- * The "full" delimiter string for a packed maildrop consists
- * of a newline followed by the actual delimiter. E.g., the
- * full string for a Unix maildrop would be: "\n\nFrom ".
- * "Fdelim" points to the start of the full string and is used
- * in the BODY case of the main routine to search the buffer for
- * a possible eom. Msg_delim points to the first character of
- * the actual delim. string (i.e., fdelim+1). Edelim
- * points to the 2nd character of actual delimiter string. It
- * is used in m_Eom because the first character of the string
- * has been read and matched before m_Eom is called.
- */
-static char *msg_delim = "";
-static unsigned char *fdelim;
-static unsigned char *delimend;
-static int fdelimlen;
-static unsigned char *edelim;
-static int edelimlen;
-
-static int (*eom_action)(int) = NULL;
-
-/* This replaces the old approach, which included direct access to
- stdio internals. It uses one fread() to load a buffer that we
- manage.
- MSG_INPUT_SIZE is the size of the buffer.
- MAX_DELIMITER_SIZE is the maximum size of the delimiter used to
- separate messages in a maildrop, such as mbox "\nFrom ". */
-#define MSG_INPUT_SIZE 8192
-#define MAX_DELIMITER_SIZE 32
-static struct m_getfld_buffer {
- unsigned char msg_buf[2 * MSG_INPUT_SIZE + MAX_DELIMITER_SIZE];
- unsigned char *readpos;
- unsigned char *end; /* One past, like C++, the last character read in. */
-} m;
+ Summary of file and message input buffer positions:
+
+ input file -------------------------------------------EOF
+ | |
+ last_caller_pos last_internal_pos
+
+
+ msg_buf --------------------EOF
+ | | |
+ msg_buf readpos end
+
+ |<>|=retained characters, difference
+ between last_internal_pos and
+ first readpos value after reading
+ in new chunk in read_more()
+
+ When returning from m_getfld()/m_unknown():
+ 1) Save the internal file position in last_internal_pos. That's the
+ m_getfld() position reference in the input file.
+ 2) Set file stream position so that callers can use ftell().
+
+ When entering m_getfld()/m_unknown():
+ Check to see if the call had changed the file position. If so,
+ adjust the internal position reference accordingly. If not, restore
+ the internal file position from last_internal_pos.
+*/
+
+
+static void
+enter_getfld (m_getfld_state_t *gstate, FILE *iob) {
+ m_getfld_state_t s;
+ off_t pos = ftello (iob);
+
+ if (! *gstate) {
+ m_getfld_state_init (gstate, iob);
+ }
+ s = *gstate;
+ s->bytes_read = 0;
+
+ /* This is ugly and no longer necessary, but is retained just in
+ case it's needed again. The parser used to open the input file
+ multiple times, so we had to always use the FILE * that's
+ passed to m_getfld(). Now the parser inits a new
+ m_getfld_state for each file. See comment below about the
+ readpos shift code being currently unused. */
+ s->iob = iob;
+
+ if (s->track_filepos && (pos != 0 || s->last_internal_pos != 0)) {
+ if (s->last_internal_pos == 0) {
+ s->total_bytes_read = pos;
+ } else {
+ off_t pos_movement = pos - s->last_caller_pos; /* Can be < 0. */
+
+ if (pos_movement == 0) {
+ pos = s->last_internal_pos;
+ } else {
+ /* The current file stream position differs from the
+ last one, so caller must have called ftell/o().
+ Or, this is the first call and the file position
+ was not at 0. */
+
+ if (s->readpos + pos_movement >= s->msg_buf &&
+ s->readpos + pos_movement < s->end) {
+ /* This is currently unused. It could be used by
+ parse_mime() if it was changed to use a global
+ m_getfld_state. */
+ /* We can shift readpos and remain within the
+ bounds of msg_buf. */
+ s->readpos += pos_movement;
+ s->total_bytes_read += pos_movement;
+ pos = s->last_internal_pos;
+ } else {
+ size_t num_read;
+
+ /* This seek skips past an integral number of
+ chunks of size MSG_INPUT_SIZE. */
+ fseeko (iob, pos/MSG_INPUT_SIZE * MSG_INPUT_SIZE, SEEK_SET);
+ num_read = fread (s->msg_buf, 1, MSG_INPUT_SIZE, iob);
+ s->readpos = s->msg_buf + pos % MSG_INPUT_SIZE;
+ s->end = s->msg_buf + num_read;
+ s->total_bytes_read = pos;
+ }
+ }
+
+ fseeko (iob, pos, SEEK_SET);
+ }
+ }
+}