-/* $Cambridge: exim/src/src/receive.c,v 1.36 2007/04/13 15:13:47 ph10 Exp $ */
+/* $Cambridge: exim/src/src/receive.c,v 1.38 2007/06/22 14:38:58 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
{
int ch_state;
register int ch;
+register int linelength = 0;
/* Handle the case when only EOF terminates the message */
if (ch == 0) body_zerocount++;
if (last_ch == '\r' && ch != '\n')
{
+ if (linelength > max_received_linelength)
+ max_received_linelength = linelength;
+ linelength = 0;
if (fputc('\n', fout) == EOF) return END_WERROR;
message_size++;
body_linecount++;
if (ch == '\r') continue;
if (fputc(ch, fout) == EOF) return END_WERROR;
- if (ch == '\n') body_linecount++;
+ if (ch == '\n')
+ {
+ if (linelength > max_received_linelength)
+ max_received_linelength = linelength;
+ linelength = 0;
+ body_linecount++;
+ }
+ else linelength++;
if (++message_size > thismessage_size_limit) return END_SIZE;
}
if (last_ch != '\n')
{
+ if (linelength > max_received_linelength)
+ max_received_linelength = linelength;
if (fputc('\n', fout) == EOF) return END_WERROR;
message_size++;
body_linecount++;
{
case 0: /* Normal state (previous char written) */
if (ch == '\n')
- { body_linecount++; ch_state = 1; }
+ {
+ body_linecount++;
+ if (linelength > max_received_linelength)
+ max_received_linelength = linelength;
+ linelength = -1;
+ ch_state = 1;
+ }
else if (ch == '\r')
{ ch_state = 2; continue; }
break;
case 1: /* After written "\n" */
if (ch == '.') { ch_state = 3; continue; }
- if (ch != '\n') ch_state = 0;
+ if (ch != '\n') ch_state = 0; else linelength = -1;
break;
case 2:
body_linecount++; /* After unwritten "\r" */
+ if (linelength > max_received_linelength)
+ max_received_linelength = linelength;
if (ch == '\n')
- { ch_state = 1; }
+ {
+ ch_state = 1;
+ linelength = -1;
+ }
else
{
if (message_size++, fputc('\n', fout) == EOF) return END_WERROR;
if (ch == '\r') continue;
ch_state = 0;
+ linelength = 0;
}
break;
if (ch == '\n') return END_DOT;
if (ch == '\r') { ch_state = 4; continue; }
message_size++;
+ linelength++;
if (fputc('.', fout) == EOF) return END_WERROR;
ch_state = 0;
break;
break;
}
+ linelength++;
if (fputc(ch, fout) == EOF) return END_WERROR;
if (++message_size > thismessage_size_limit) return END_SIZE;
}
int start, end, domain, size, sptr;
int id_resolution;
int had_zero = 0;
+int prevlines_length = 0;
register int ptr = 0;
spool_name[0] = 0;
message_size = 0;
warning_count = 0;
-received_count = 1; /* For the one we will add */
+received_count = 1; /* For the one we will add */
if (thismessage_size_limit <= 0) thismessage_size_limit = INT_MAX;
/* While reading the message, the following counts are computed. */
-message_linecount = body_linecount = body_zerocount = 0;
+message_linecount = body_linecount = body_zerocount =
+ max_received_linelength = 0;
#ifdef EXPERIMENTAL_DOMAINKEYS
/* Call into DK to set up the context. Check if DK is to be run are carried out
receive_linecount++;
message_linecount++;
+ /* Keep track of maximum line length */
+
+ if (ptr - prevlines_length > max_received_linelength)
+ max_received_linelength = ptr - prevlines_length;
+ prevlines_length = ptr + 1;
+
/* Now put in the terminating newline. There is always space for
at least two more characters. */
next->text = store_get(header_size);
ptr = 0;
had_zero = 0;
+ prevlines_length = 0;
} /* Continue, starting to read the next header */
/* At this point, we have read all the headers into a data structure in main
receive_call_bombout = TRUE;
-/* Before sending an SMTP response in a TCP/IP session, we check to see if
-there is unconsumed input (which there shouldn't be) or if the connection has
-gone away. This can be done because the end of a message is always a
-synchronization point. If the connection is still present, but there is no
-pending input, the result of a select() call will be zero. If, however, the
-connection has gone away, or if there is pending input, the result of select()
-will be non-zero. The two cases can be distinguished by trying to read the next
-input character. Of course, since TCP/IP is asynchronous, there is always a
-chance that the connection will vanish between the time of this test and the
-sending of the response, but the chance of this happening should be small.
+/* Before sending an SMTP response in a TCP/IP session, we check to see if the
+connection has gone away. This can only be done if there is no unconsumed input
+waiting in the local input buffer. We can test for this by calling
+receive_smtp_buffered(). RFC 2920 (pipelining) explicitly allows for additional
+input to be sent following the final dot, so the presence of following input is
+not an error.
+
+If the connection is still present, but there is no unread input for the
+socket, the result of a select() call will be zero. If, however, the connection
+has gone away, or if there is pending input, the result of select() will be
+non-zero. The two cases can be distinguished by trying to read the next input
+character. If we succeed, we can unread it so that it remains in the local
+buffer for handling later. If not, the connection has been lost.
-We also check for input that has already been received and is in the local
-input buffer (plain SMTP or TLS) by calling receive_smtp_buffered(). */
+Of course, since TCP/IP is asynchronous, there is always a chance that the
+connection will vanish between the time of this test and the sending of the
+response, but the chance of this happening should be small. */
-if (smtp_input && sender_host_address != NULL && !sender_host_notsocket)
+if (smtp_input && sender_host_address != NULL && !sender_host_notsocket &&
+ !receive_smtp_buffered())
{
struct timeval tv;
fd_set select_check;
tv.tv_sec = 0;
tv.tv_usec = 0;
- if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0 ||
- receive_smtp_buffered())
+ if (select(fileno(smtp_in) + 1, &select_check, NULL, NULL, &tv) != 0)
{
- uschar *msg;
- if ((RECEIVE_GETC)() == EOF)
+ int c = (RECEIVE_GETC)();
+ if (c != EOF) (RECEIVE_UNGETC)(c); else
{
- msg = US"SMTP connection lost after final dot";
- smtp_reply = US""; /* No attempt to send a response */
- }
- else
- {
- msg = US"Synchronization error (data after final dot)";
- smtp_reply = US"550 Synchronization error (data after final dot)";
- }
+ uschar *msg = US"SMTP connection lost after final dot";
+ smtp_reply = US""; /* No attempt to send a response */
+ smtp_yield = FALSE; /* Nothing more on this connection */
- /* Overwrite the log line workspace */
+ /* Re-use the log line workspace */
- sptr = 0;
- s = string_cat(s, &size, &sptr, msg, Ustrlen(msg));
- s = add_host_info_for_log(s, &size, &sptr);
- s[sptr] = 0;
- log_write(0, LOG_MAIN, "%s", s);
+ sptr = 0;
+ s = string_cat(s, &size, &sptr, msg, Ustrlen(msg));
+ s = add_host_info_for_log(s, &size, &sptr);
+ s[sptr] = 0;
+ log_write(0, LOG_MAIN, "%s", s);
- /* We now have to delete the files for this aborted message. */
+ /* Delete the files for this aborted message. */
- sprintf(CS spool_name, "%s/input/%s/%s-D", spool_directory, message_subdir,
- message_id);
- Uunlink(spool_name);
+ sprintf(CS spool_name, "%s/input/%s/%s-D", spool_directory,
+ message_subdir, message_id);
+ Uunlink(spool_name);
- sprintf(CS spool_name, "%s/input/%s/%s-H", spool_directory, message_subdir,
- message_id);
- Uunlink(spool_name);
+ sprintf(CS spool_name, "%s/input/%s/%s-H", spool_directory,
+ message_subdir, message_id);
+ Uunlink(spool_name);
- sprintf(CS spool_name, "%s/msglog/%s/%s", spool_directory, message_subdir,
- message_id);
- Uunlink(spool_name);
-
- /* Do not accept any more messages on this connection. */
+ sprintf(CS spool_name, "%s/msglog/%s/%s", spool_directory,
+ message_subdir, message_id);
+ Uunlink(spool_name);
- smtp_yield = FALSE;
- goto TIDYUP;
+ goto TIDYUP;
+ }
}
}