]>
diplodocus.org Git - nmh/blob - sbr/m_getfld.c
5647dd1568bb2b54a82d56b63f1a4c4215a4f189
1 /* m_getfld.c -- read/parse a message
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
17 Reads an Internet message (RFC 5322), or one or more messages
18 stored in a maildrop in mbox (RFC 4155) or MMDF format, from a file
19 stream. Each call to m_getfld() reads one header field, or a
20 portion of the body, in sequence.
24 gstate: opaque parse state
25 bufsz: maximum number of characters to load into buf
26 iob: input file stream
30 name: header field name (array of size NAMESZ=999)
31 buf: either a header field body or message body
32 bufsz: number of characters loaded into buf
33 (return value): message parse state on return from function
37 void m_getfld_state_destroy (m_getfld_state_t *gstate): destroys
38 the parse state pointed to by the gstate argument.
40 m_getfld_state_reset (m_getfld_state_t *gstate): resets the parse
43 void m_unknown(FILE *iob): Determines the message delimiter string
44 for the maildrop. Called by inc and scan when reading from a
49 m_getfld() retains state internally between calls in the
50 m_getfld_state_t variable. These are used for detecting the end of
51 each message when reading maildrops:
64 m_getfld_state_t gstate;
66 gstate = m_getfld_state_init(mailfp);
67 Perhaps m_getfld_track_filepos2(&gstate);
69 state = m_getfld2(&gstate, ...);
70 ...Repeat until finished with mailfp.
71 m_getfld_state_destroy (&gstate);
73 The state is retained internally by gstate. To reset its state to FLD:
74 m_getfld_state_reset (&gstate);
77 /* The following described the old implementation. The high-level
78 structure hasn't changed, but some of the details have. I'm
79 leaving this as-is, though, for posterity.
82 /* This module has a long and checkered history. First, it didn't burst
83 maildrops correctly because it considered two CTRL-A:s in a row to be
84 an inter-message delimiter. It really is four CTRL-A:s followed by a
85 newline. Unfortunately, MMDF will convert this delimiter *inside* a
86 message to a CTRL-B followed by three CTRL-A:s and a newline. This
87 caused the old version of m_getfld() to declare eom prematurely. The
88 fix was a lot slower than
90 c == '\001' && peekc (iob) == '\001'
92 but it worked, and to increase generality, MBOX style maildrops could
93 be parsed as well. Unfortunately the speed issue finally caught up with
94 us since this routine is at the very heart of MH.
96 To speed things up considerably, the routine Eom() was made an auxiliary
97 function called by the macro eom(). Unless we are bursting a maildrop,
98 the eom() macro returns false saying we aren't at the end of the
101 The next thing to do is to read the mts.conf file and initialize
102 delimiter[] and delimlen accordingly...
104 After mhl was made a built-in in msh, m_getfld() worked just fine
105 (using m_unknown() at startup). Until one day: a message which was
106 the result of a bursting was shown. Then, since the burst boundaries
107 aren't CTRL-A:s, m_getfld() would blinding plunge on past the boundary.
108 Very sad. The solution: introduce m_eomsbr(). This hook gets called
109 after the end of each line (since testing for eom involves an fseek()).
110 This worked fine, until one day: a message with no body portion arrived.
113 while (eom (c = Getc (iob), iob))
116 loop caused m_getfld() to return FMTERR. So, that logic was changed to
117 check for (*eom_action) and act accordingly.
119 This worked fine, until one day: someone didn't use four CTRL:A's as
120 their delimiters. So, the bullet got bit and we read mts.h and
121 continue to struggle on. It's not that bad though, since the only time
122 the code gets executed is when inc (or msh) calls it, and both of these
123 have already called mts_init().
125 ------------------------
126 (Written by Van Jacobson for the mh6 m_getfld, January, 1986):
128 This routine was accounting for 60% of the cpu time used by most mh
129 programs. I spent a bit of time tuning and it now accounts for <10%
130 of the time used. Like any heavily tuned routine, it's a bit
131 complex and you want to be sure you understand everything that it's
132 doing before you start hacking on it. Let me try to emphasize
133 that: every line in this atrocity depends on every other line,
134 sometimes in subtle ways. You should understand it all, in detail,
135 before trying to change any part. If you do change it, test the
136 result thoroughly (I use a hand-constructed test file that exercises
137 all the ways a header name, header body, header continuation,
138 header-body separator, body line and body eom can align themselves
139 with respect to a buffer boundary). "Minor" bugs in this routine
140 result in garbaged or lost mail.
142 If you hack on this and slow it down, I, my children and my
143 children's children will curse you.
145 This routine gets used on three different types of files: normal,
146 single msg files, "packed" unix or mmdf mailboxs (when used by inc)
147 and packed, directoried bulletin board files (when used by msh).
148 The biggest impact of different file types is in "eom" testing. The
149 code has been carefully organized to test for eom at appropriate
150 times and at no other times (since the check is quite expensive).
151 I have tried to arrange things so that the eom check need only be
152 done on entry to this routine. Since an eom can only occur after a
153 newline, this is easy to manage for header fields. For the msg
154 body, we try to efficiently search the input buffer to see if
155 contains the eom delimiter. If it does, we take up to the
156 delimiter, otherwise we take everything in the buffer. (The change
157 to the body eom/copy processing produced the most noticeable
158 performance difference, particularly for "inc" and "show".)
160 There are three qualitatively different things this routine busts
161 out of a message: field names, field text and msg bodies. Field
162 names are typically short (~8 char) and the loop that extracts them
163 might terminate on a colon, newline or max width. I considered
164 using a Vax "scanc" to locate the end of the field followed by a
165 "memmove" but the routine call overhead on a Vax is too large for this
166 to work on short names. If Berkeley ever makes "inline" part of the
167 C optimiser (so things like "scanc" turn into inline instructions) a
168 change here would be worthwhile.
170 Field text is typically 60 - 100 characters so there's (barely)
171 a win in doing a routine call to something that does a "locc"
172 followed by a "bmove". About 30% of the fields have continuations
173 (usually the 822 "received:" lines) and each continuation generates
174 another routine call. "Inline" would be a big win here, as well.
176 Messages, as of this writing, seem to come in two flavors: small
177 (~1K) and long (>2K). Most messages have 400 - 600 bytes of headers
178 so message bodies average at least a few hundred characters.
179 Assuming your system uses reasonably sized stdio buffers (1K or
180 more), this routine should be able to remove the body in large
181 (>500 byte) chunks. The makes the cost of a call to "memmove"
182 small but there is a premium on checking for the eom in packed
183 maildrops. The eom pattern is always a simple string so we can
184 construct an efficient pattern matcher for it (e.g., a Vax "matchc"
185 instruction). Some thought went into recognizing the start of
186 an eom that has been split across two buffers.
188 This routine wants to deal with large chunks of data so, rather
189 than "getc" into a local buffer, it uses stdio's buffer. If
190 you try to use it on a non-buffered file, you'll get what you
191 deserve. This routine "knows" that struct FILEs have a _ptr
192 and a _cnt to describe the current state of the buffer and
193 it knows that _filbuf ignores the _ptr & _cnt and simply fills
194 the buffer. If stdio on your system doesn't work this way, you
195 may have to make small changes in this routine.
197 This routine also "knows" that an EOF indication on a stream is
198 "sticky" (i.e., you will keep getting EOF until you reposition the
199 stream). If your system doesn't work this way it is broken and you
200 should complain to the vendor. As a consequence of the sticky
201 EOF, this routine will never return any kind of EOF status when
202 there is data in "name" or "buf").
208 static void Ungetc(m_getfld_state_t s
);
209 static int m_Eom (m_getfld_state_t
);
211 #define eom(c,s) (s->msg_style != MS_DEFAULT && \
212 ((c) == *s->msg_delim && m_Eom(s)))
217 #define MS_DEFAULT 0 /* default (one msg per file) */
218 #define MS_UNKNOWN 1 /* type not known yet */
219 #define MS_MBOX 2 /* Unix-style "from" lines */
220 #define MS_MMDF 3 /* string MMDF_DELIM */
222 /* This replaces the old approach, with its direct access to stdio
223 * internals. It uses one fread() to load a buffer that we manage.
225 * MSG_INPUT_SIZE is the size of the buffer.
226 * MAX_DELIMITER_SIZE is the maximum size of the delimiter used to
227 * separate messages in a maildrop, such as mbox "From ".
229 * Some of the tests in the test suite assume a MSG_INPUT_SIZE
232 #define MSG_INPUT_SIZE NMH_BUFSIZ
233 #define MAX_DELIMITER_SIZE 5
235 struct m_getfld_state
{
236 /* The file to read from; I/O block. Caller keeps passing it after
237 * initialisation due to historic interface so it keeps getting
238 * updated, presumably to the same value. */
241 /* Holds content of iob. */
242 char msg_buf
[2 * MSG_INPUT_SIZE
+ MAX_DELIMITER_SIZE
];
243 /* Points to the next byte to read from msg_buf. */
245 /* Points to just after the last valid byte in msg_buf. If readpos
246 * equals end then msg_buf is empty. */
249 /* Whether the caller intends to ftell(3)/fseek(3) iob's position,
250 * and thus whether m_getfld() needs to detect that and compensate. */
252 /* Position in iob given what's been consumed ready for returning to
253 * the caller. Further than this may have been read into msg_buf. */
254 off_t total_bytes_read
;
255 /* Bytes of iob consumed during this call. */
257 /* What fseeko(3) tells us iob's position is having just explicitly
258 * set it to total_bytes_read. Surely always the same? */
259 off_t last_caller_pos
;
260 /* Saved position in iob from filling msg_buf, prior to returning. */
261 off_t last_internal_pos
;
263 /* One of the MS_* macros tracking the type of iob's content and
264 * thus if it's a single email, or several with delimeters. Default
268 /* The message delimeter if iob has multiple emails, else NULL. For
269 * MS_MBOX it's the string that separates two emails, "\nFrom ",
270 * i.e. the terminating blank line of the previous email, and the
271 * starting From_ line of the next, but for MS_MMDF it's
272 * "\001\001\001\001\n" that may start or terminate an email. */
274 /* The last non-NUL char of msg_delim. */
276 /* When searching for msg_delim after an email, it's only of
277 * interest at the start of the line, i.e. when preceded by a
278 * linefeed. fdelim points to msg_delim[-1] that contains '\n' so
279 * it can be used as the needle. */
281 /* strlen(fdelim). */
283 /* The second char of msg_delim. Used when the first char has
284 * already been matched to test the rest. */
286 /* strlen(edelim). */
288 /* The relationship between all of these pointers and lengths for
289 * the two possible msg_delim values.
291 * "\0\n\nFrom \0" 9 "\0\n\001\001\001\001\n\0" 8
293 * | || s->delimend | | | s->delimend
295 * | |s->edelim s->edelimlen=5 | | s->edelim s->edelimlen=4
297 * | s->msg_delim | s->msg_delim
299 * s->fdelim s->fdelimlen=7 s->fdelim s->fdelimlen=6
302 /* Maps all the bytes of msg_delim, apart from the last two,
303 * including the NUL, onto the last position in msg_delim where they
304 * occur. Bytes not present are NULL. */
307 /* The parser's current state. Also returned to the caller, amongst
308 * other possible values, to indicate the token consumed. One of
309 * FLD, FLDPLUS, BODY, or FILEEOF. */
313 m_getfld_state_t
m_getfld_state_init(FILE *iob
)
318 s
->readpos
= s
->end
= s
->msg_buf
;
319 s
->bytes_read
= s
->total_bytes_read
= 0;
320 s
->last_caller_pos
= s
->last_internal_pos
= 0;
323 s
->msg_style
= MS_DEFAULT
;
325 s
->fdelim
= s
->delimend
= s
->edelim
= NULL
;
326 s
->fdelimlen
= s
->edelimlen
= 0;
328 s
->track_filepos
= 0;
333 /* scan() needs to force an initial state of FLD for each message. */
335 m_getfld_state_reset (m_getfld_state_t
*gstate
)
338 (*gstate
)->state
= FLD
;
342 /* If the caller interleaves ftell*()/fseek*() calls with m_getfld()
343 calls, m_getfld() must keep track of the file position. The caller
344 must use this function to inform m_getfld(). */
346 m_getfld_track_filepos (m_getfld_state_t
*gstate
, FILE *iob
)
349 *gstate
= m_getfld_state_init(iob
);
352 (*gstate
)->track_filepos
= 1;
355 /* m_getfld_track_filepos() with the existing iob. */
357 m_getfld_track_filepos2(m_getfld_state_t
*gstate
)
360 die("m_getfld_track_filepos2 without gstate");
362 m_getfld_track_filepos(gstate
, (*gstate
)->iob
);
366 m_getfld_state_destroy (m_getfld_state_t
*gstate
)
368 m_getfld_state_t s
= *gstate
;
381 Summary of file and message input buffer positions:
383 input file -------------------------------------------EOF
385 last_caller_pos last_internal_pos
388 msg_buf --------------------EOF
392 |<>|=retained characters, difference
393 between last_internal_pos and
394 first readpos value after reading
395 in new chunk in read_more()
397 When returning from m_getfld()/m_unknown():
398 1) Save the internal file position in last_internal_pos. That's the
399 m_getfld() position reference in the input file.
400 2) Set file stream position so that callers can use ftell().
402 When entering m_getfld()/m_unknown():
403 Check to see if the call had changed the file position. If so,
404 adjust the internal position reference accordingly. If not, restore
405 the internal file position from last_internal_pos.
410 enter_getfld (m_getfld_state_t
*gstate
, FILE *iob
)
417 *gstate
= m_getfld_state_init(iob
);
422 /* This is ugly and no longer necessary, but is retained just in
423 case it's needed again. The parser used to open the input file
424 multiple times, so we had to always use the FILE * that's
425 passed to m_getfld(). Now the parser inits a new
426 m_getfld_state for each file. See comment below about the
427 readpos shift code being currently unused. */
430 if (!s
->track_filepos
)
433 if ((pos
= ftello(iob
)) == -1)
434 adios("getfld's iob", "failed to get offset on entry");
435 if (pos
== 0 && s
->last_internal_pos
== 0)
438 if (s
->last_internal_pos
== 0) {
439 s
->total_bytes_read
= pos
;
443 pos_movement
= pos
- s
->last_caller_pos
; /* Can be < 0. */
444 if (pos_movement
== 0) {
445 pos
= s
->last_internal_pos
;
447 /* The current file stream position differs from the
448 last one, so caller must have called ftell/o().
449 Or, this is the first call and the file position
452 if (s
->readpos
+ pos_movement
>= s
->msg_buf
&&
453 s
->readpos
+ pos_movement
< s
->end
) {
454 /* This is currently unused. It could be used by
455 parse_mime() if it was changed to use a global
457 /* We can shift readpos and remain within the
458 bounds of msg_buf. */
459 s
->readpos
+= pos_movement
;
460 s
->total_bytes_read
+= pos_movement
;
461 pos
= s
->last_internal_pos
;
466 /* This seek skips past an integral number of
467 chunks of size MSG_INPUT_SIZE. */
468 off
= pos
/ MSG_INPUT_SIZE
* MSG_INPUT_SIZE
;
469 if (fseeko(iob
, off
, SEEK_SET
) == -1)
470 adios("getfld's iob", "failed to set offset to skip: "
471 "%" PRIdMAX
, (intmax_t)off
);
472 num_read
= fread (s
->msg_buf
, 1, MSG_INPUT_SIZE
, iob
);
473 s
->readpos
= s
->msg_buf
+ pos
% MSG_INPUT_SIZE
;
474 s
->end
= s
->msg_buf
+ num_read
;
475 s
->total_bytes_read
= pos
;
479 if (fseeko(iob
, pos
, SEEK_SET
) == -1)
480 adios("getfld's iob", "failed to set offset on entry: %" PRIdMAX
,
485 leave_getfld (m_getfld_state_t s
)
487 s
->total_bytes_read
+= s
->bytes_read
;
489 if (s
->track_filepos
) {
490 /* Save the internal file position that we use for the input buffer. */
491 if ((s
->last_internal_pos
= ftello(s
->iob
)) == -1)
492 adios("getfld's iob", "failed to get offset before seek");
494 /* Set file stream position so that callers can use ftell(). */
495 if (fseeko(s
->iob
, s
->total_bytes_read
, SEEK_SET
) == -1)
496 adios("getfld's iob", "failed to set offset: %" PRIdMAX
,
497 (intmax_t)s
->total_bytes_read
);
499 s
->last_caller_pos
= s
->total_bytes_read
;
504 read_more (m_getfld_state_t s
)
506 /* Retain at least edelimlen characters that have already been read,
507 if at least edelimlen have been read, so that we can back up to them
509 ssize_t retain
= s
->end
- s
->msg_buf
< s
->edelimlen
? 0 : s
->edelimlen
;
513 if (retain
< s
->end
- s
->readpos
)
514 retain
= s
->end
- s
->readpos
;
515 assert (retain
<= s
->readpos
- s
->msg_buf
);
517 /* Move what we want to retain at end of the buffer to the beginning. */
518 memmove (s
->msg_buf
, s
->readpos
- retain
, retain
);
521 s
->readpos
= s
->msg_buf
+ retain
;
522 num_read
= fread (s
->readpos
, 1, MSG_INPUT_SIZE
, s
->iob
);
523 s
->end
= s
->readpos
+ num_read
;
528 /* Return the next character consumed from the input, fetching more of
529 * the input for the buffer if required, or EOF on end of file. */
531 Getc (m_getfld_state_t s
)
533 if ((s
->end
- s
->readpos
< 1 && read_more (s
) == 0) ||
534 s
->readpos
>= s
->end
)
538 return (unsigned char)*s
->readpos
++;
541 /* Return the next character that Getc() would return, which may be EOF. */
543 Peek (m_getfld_state_t s
)
554 /* If there's room, undo the consumption of one character from msg_buf,
555 * rewinding so it's read next, else die. */
557 Ungetc(m_getfld_state_t s
)
559 if (s
->readpos
== s
->msg_buf
)
560 die("Ungetc() at start of message buffer.");
568 m_getfld (m_getfld_state_t
*gstate
, char name
[NAMESZ
], char *buf
, int *bufsz
,
575 enter_getfld (gstate
, iob
);
578 if ((c
= Getc(s
)) == EOF
) {
581 return s
->state
= FILEEOF
;
584 /* flush null messages */
585 while ((c
= Getc(s
)) != EOF
&& eom (c
, s
))
592 return s
->state
= FILEEOF
;
597 if (c
== '\n' || c
== '-') {
598 /* we hit the header/body separator */
599 while (c
!= '\n' && (c
= Getc(s
)) != EOF
)
602 if (c
== EOF
|| (c
= Getc(s
)) == EOF
|| eom (c
, s
)) {
603 /* flush null messages */
604 while ((c
= Getc(s
)) != EOF
&& eom (c
, s
))
610 return s
->state
= FILEEOF
;
616 * get the name of this component. take characters up
617 * to a ':', a newline or NAMESZ-1 characters, whichever
622 /* Get the field name. The first time through the loop,
623 this copies out the first character, which was loaded
624 into c prior to loop entry. Initialize n to 1 to
627 c
!= ':' && c
!= '\n' && c
!= EOF
&& n
< max
;
632 /* Check for next character, which is either the space after
633 the ':' or the first folded whitespace. */
636 if (c
== EOF
|| (next_char
= Peek (s
)) == EOF
) {
637 *bufsz
= *cp
= *buf
= 0;
638 inform("eof encountered in field \"%s\"", name
);
640 return s
->state
= FMTERR
;
644 /* If c isn't ':' here, something went wrong. Possibilities are:
645 * . hit a newline (error)
646 * . got more than namesz chars. (error)
649 /* Finished header name, fall through to FLDPLUS below. */
650 } else if (c
== '\n') {
651 /* We hit the end of the line without seeing ':' to
652 * terminate the field name. This is usually (always?)
653 * spam. But, blowing up is lame, especially when
654 * scan(1)ing a folder with such messages. Pretend such
655 * lines are the first of the body (at least mutt also
656 * handles it this way). */
658 /* See if buf can hold this line, since we were assuming
659 * we had a buffer of NAMESZ, not bufsz. */
660 /* + 1 for the newline */
661 if (*bufsz
< n
+ 1) {
662 /* No, it can't. Oh well, guess we'll blow up. */
663 *bufsz
= *cp
= *buf
= 0;
664 inform("eol encountered in field \"%s\"", name
);
668 memcpy (buf
, name
, n
- 1);
671 /* Indicate this wasn't a header field using a character
672 that can't appear in a header field. */
674 /* The last character read was '\n'. s->bytes_read
675 (and n) include that, but it was not put into the
676 name array in the for loop above. So subtract 1. */
677 *bufsz
= --s
->bytes_read
; /* == n - 1 */
679 return s
->state
= BODY
;
682 /* By design, the loop above discards the last character
683 it had read. It's in c, use it. */
685 *bufsz
= *cp
= *buf
= 0;
686 inform("field name \"%s\" exceeds %d bytes", name
,
692 /* Trim any trailing spaces from the end of name. */
693 while (isspace ((unsigned char) *--cp
) && cp
>= name
) continue;
695 /* readpos points to the first character of the field body. */
700 * get (more of) the text of a field. Take
701 * characters up to the end of this field (newline
702 * followed by non-blank) or bufsz-1 characters.
707 for (bool finished
= false; !finished
; ) {
708 while (c
!= '\n' && c
!= EOF
&& n
++ < max
) {
709 if ((c
= Getc (s
)) != EOF
)
716 /* The dest buffer is full. Need to back the read
717 pointer up by one because when m_getfld() is
718 reentered, it will read a character. Then
719 we'll jump right to the FLDPLUS handling code,
720 which will not store that character, but
721 instead move on to the next one. */
722 if (s
->readpos
> s
->msg_buf
) {
728 } else if (c
!= ' ' && c
!= '\t') {
729 /* The next character is not folded whitespace, so
730 prepare to move on to the next field. It's OK
731 if c is EOF, it will be handled on the next
732 call to m_getfld (). */
736 /* Folded header field, continues on the next line. */
739 *bufsz
= s
->bytes_read
;
746 * get the message body up to bufsz characters or the
747 * end of the message.
753 /* Back up and store the current position. */
755 c
= min(s
->end
- s
->readpos
, max
);
756 if (s
->msg_style
!= MS_DEFAULT
&& c
> 1) {
758 * packed maildrop - only take up to the (possible)
759 * start of the next message. This "matchc" should
760 * probably be a Boyer-Moore matcher for non-vaxen,
761 * particularly since we have the alignment table
762 * all built for the end-of-buffer test (next).
763 * But our vax timings indicate that the "matchc"
764 * instruction is 50% faster than a carefully coded
765 * B.M. matcher for most strings. (So much for elegant
766 * algorithms vs. brute force.) Since I (currently)
767 * run MH on a vax, we use the matchc instruction. --vj
771 if ((ep
= memmem(bp
, c
, s
->fdelim
, s
->fdelimlen
)))
772 /* Plus one to nab the '\n' that starts fdelim as
773 * that ends the previous line; it isn't part of
778 * There's no delim in the buffer but there may be
779 * a partial one at the end. If so, we want to leave
780 * it so the "eom" check on the next call picks it up.
781 * Use a modified Boyer-Moore matcher to make this
782 * check relatively cheap. The first "if" figures
783 * out what position in the pattern matches the last
784 * character in the buffer. The inner "while" matches
785 * the pattern against the buffer, backwards starting
786 * at that position. Note that unless the buffer
787 * ends with one of the characters in the pattern
788 * (excluding the first and last), we do only one test.
792 ep
= bp
+ c
- 1; /* The last byte. */
793 if ((sp
= s
->pat_map
[(unsigned char) *ep
])) {
795 /* This if() is true unless (a) the buffer is too
796 * small to contain this delimiter prefix, or
797 * (b) it contains exactly enough chars for the
799 * For case (a) obviously we aren't going to match.
800 * For case (b), if the buffer really contained exactly
801 * a delim prefix, then the m_eom call at entry
802 * should have found it. Thus it's not a delim
803 * and we know we won't get a match.
805 if (((sp
- s
->fdelim
) + 2) <= c
) {
807 /* Unfortunately although fdelim has a preceding NUL
808 * we can't use this as a sentinel in case the buffer
809 * contains a NUL in exactly the wrong place (this
810 * would cause us to run off the front of fdelim).
812 while (*--ep
== *--cp
)
815 if (cp
< s
->fdelim
) {
816 /* we matched the entire delim prefix,
817 * so only take the buffer up to there.
818 * we know ep >= bp -- check above prevents underrun
824 /* try matching one less char of delim string */
826 } while (--sp
> s
->fdelim
);
830 memcpy( buf
, bp
, c
);
831 /* Advance the current position to reflect the copy out.
832 c is less than or equal to the number of bytes remaining
833 in the read buffer, so will not overrun it. */
836 /* Subtract 1 from c because the first character was read by
837 Getc(), and therefore already accounted for in s->bytes_read. */
838 s
->bytes_read
+= c
- 1;
839 *bufsz
= s
->bytes_read
;
844 die("m_getfld() called with bogus state of %d", s
->state
);
854 /* m_getfld() with the existing iob. */
856 m_getfld2(m_getfld_state_t
*gstate
, char name
[NAMESZ
], char *buf
, int *bufsz
)
859 die("m_getfld2 without gstate");
861 return m_getfld(gstate
, name
, buf
, bufsz
, (*gstate
)->iob
);
866 m_unknown(m_getfld_state_t
*gstate
, FILE *iob
)
870 char text
[MAX_DELIMITER_SIZE
];
871 char from
[] = "From ";
876 enter_getfld (gstate
, iob
);
880 * Figure out what the message delimiter string is for this
881 * maildrop. (This used to be part of m_Eom but I didn't like
882 * the idea of an "if" statement that could only succeed on the
883 * first call to m_Eom getting executed on each call, i.e., at
884 * every newline in the message).
886 * If the first line of the maildrop is a Unix "From " line, we
887 * say the style is MBOX and eat the rest of the line. Otherwise
888 * we say the style is MMDF and look for the delimiter string
889 * specified when nmh was built (or from the mts.conf file).
892 s
->msg_style
= MS_UNKNOWN
;
894 for (i
= 0, cp
= text
; i
< sizeof text
; ++i
, ++cp
) {
895 if ((c
= Getc (s
)) == EOF
) {
902 if (i
== sizeof from
-1 && strncmp (text
, "From ", sizeof from
-1) == 0) {
903 s
->msg_style
= MS_MBOX
;
904 delimstr
= "\nFrom ";
905 while ((c
= Getc(s
)) != EOF
&& c
!= '\n')
908 /* not a Unix style maildrop */
909 s
->readpos
-= s
->bytes_read
;
911 delimstr
= MMDF_DELIM
;
912 s
->msg_style
= MS_MMDF
;
915 /* "\nFrom \0" 7 "\001\001\001\001\n\0" 6
917 * delimstr c=6 delimstr c=5
919 c
= strlen (delimstr
);
920 s
->fdelim
= mh_xmalloc (c
+ 3); /* \0, \n, delimstr, \0 */
923 s
->fdelimlen
= c
+ 1;
924 s
->msg_delim
= s
->fdelim
+1;
925 strcpy (s
->msg_delim
, delimstr
);
926 s
->edelim
= s
->msg_delim
+1;
927 s
->edelimlen
= c
- 1;
928 s
->delimend
= s
->msg_delim
+ s
->edelimlen
;
929 if (s
->edelimlen
<= 1)
930 die("maildrop delimiter must be at least 2 bytes");
933 * build a Boyer-Moore end-position map for the matcher in m_getfld.
934 * N.B. - we don't match just the first char (since it's the newline
935 * separator) or the last char (since the matchc would have found it
936 * if it was a real delim).
938 s
->pat_map
= mh_xcalloc (256, sizeof(char *));
940 for (cp
= s
->fdelim
+ 1; cp
< s
->delimend
; cp
++ )
941 s
->pat_map
[(unsigned char)*cp
] = cp
;
943 if (s
->msg_style
== MS_MMDF
) {
944 /* flush extra msg hdrs */
945 while ((c
= Getc(s
)) != EOF
&& eom (c
, s
))
955 /* m_unknown() with the existing iob. */
957 m_unknown2(m_getfld_state_t
*gstate
)
960 die("m_unknown2 without gstate");
962 m_unknown(gstate
, (*gstate
)->iob
);
967 * test for msg delimiter string
971 m_Eom (m_getfld_state_t s
)
974 char text
[MAX_DELIMITER_SIZE
];
978 for (i
= 0, cp
= text
; i
< s
->edelimlen
; ++i
, ++cp
) {
981 if ((c2
= Getc (s
)) == EOF
) {
988 if (i
!= s
->edelimlen
||
989 strncmp (text
, (char *)s
->edelim
, s
->edelimlen
)) {
990 if (i
== 0 && s
->msg_style
== MS_MBOX
) {
991 /* the final newline in the (brain damaged) unix-format
992 * maildrop is part of the delimiter - delete it.
997 if (i
<= 2 && s
->msg_style
== MS_MBOX
&&
998 i
!= s
->edelimlen
&& ! strncmp(text
, s
->fdelim
, i
)) {
999 /* If all or part of fdelim appeared at the end of the file,
1000 back up even more so that the bytes are included in the
1005 /* Did not find delimiter, so restore the read position.
1006 Note that on input, a character had already been read
1007 with Getc(). It will be unget by m_getfld () on return. */
1008 s
->readpos
-= s
->bytes_read
- adjust
;
1009 s
->bytes_read
= adjust
;
1013 if (s
->msg_style
== MS_MBOX
) {
1015 while ((c
= Getc(s
)) != EOF
&& c
!= '\n')