whether the headers (which is all that is read) were terminated by '.' or
not. */
+typedef struct {
+ pid_t pid;
+ struct timeval tv;
+} message_id_data_t;
+
+message_id_data_t
+get_message_id_data(void)
+{
+/* The last part of the message id consists of 4 BaseX digits. It is
+constructed from the tv_us value of gettimeofday() and localhost_number.
+The usable time resolution depends on the X from BaseX (62 or only 36
+(on a case-ignorant OS)) and the usage of localhost_number */
+
+ static int cnt;
+ static int id_resolution;
+ static message_id_data_t id;
+
+
+ /* first time call, nothing to wait, but initialize or
+ internal data */
+ if (!id_resolution)
+ {
+ /* best resolution is 500 ticks, worst is 10000.
+ one tick is 1/1_000_000 second */
+ id_resolution = host_number_string
+ ? (BASE_62 == 62) ? 5000 : 10000
+ : (BASE_62 == 62) ? 500 : 1000;
+ id.pid = getpid();
+ gettimeofday(&id.tv, NULL);
+ }
+
+ /* next message id, ensure uniqness */
+ else
+ {
+ exim_wait_tick(&id.tv, id_resolution);
+ gettimeofday(&id.tv, NULL);
+ }
+
+ id.tv.tv_usec = (id.tv.tv_usec/id_resolution) * id_resolution;
+ if (host_number_string) id.tv.tv_usec += host_number * 1000000/id_resolution;
+
+ return id;
+}
+
+void
+build_message_id_string(uschar **string, const message_id_data_t *data)
+{
+ Ustrncpy(*string, string_base62((long int)data->tv.tv_sec), 6);
+ (*string)[6] = '-';
+ Ustrncpy(*string + 7, string_base62((long int)data->pid), 6);
+
+/* Deal with the case where the host number is set. The value of the number was
+checked when it was read, to ensure it isn't too big. The timing granularity is
+left in id_resolution so that an appropriate wait can be done after receiving
+the message, if necessary (we hope it won't be). */
+
+ sprintf(CS(*string + MESSAGE_ID_LENGTH - 3), "-%2s",
+ string_base62((long int)data->tv.tv_usec) + 4);
+}
+
BOOL
receive_msg(BOOL extract_recip)
{
errors_sender_rc : EXIT_FAILURE;
int header_size = 256;
int start, end, domain, size, sptr;
-int id_resolution;
int had_zero = 0;
int prevlines_length = 0;
uschar *errmsg, *s;
struct stat statbuf;
+message_id_data_t message_id_data;
+
/* Final message to give to SMTP caller, and messages from ACLs */
uschar *smtp_reply = NULL;
ids, and fractions of a second are required. See the comments that precede the
message id creation below. */
-(void)gettimeofday(&message_id_tv, NULL);
+message_id_data = get_message_id_data();
/* For other uses of the received time we can operate with granularity of one
second, and for that we use the global variable received_time. This is for
things like ultimate message timeouts. */
-received_time = message_id_tv.tv_sec;
+received_time = message_id_data.tv.tv_sec;
/* If SMTP input, set the special handler for timeouts. The alarm() calls
happen in the smtp_getc() function when it refills its buffer. */
must also be changed to reflect the correct string length. Then, of course,
other programs that rely on the message id format will need updating too. */
-Ustrncpy(message_id, string_base62((long int)(message_id_tv.tv_sec)), 6);
-message_id[6] = '-';
-Ustrncpy(message_id + 7, string_base62((long int)getpid()), 6);
-
-/* Deal with the case where the host number is set. The value of the number was
-checked when it was read, to ensure it isn't too big. The timing granularity is
-left in id_resolution so that an appropriate wait can be done after receiving
-the message, if necessary (we hope it won't be). */
-
-if (host_number_string != NULL)
- {
- id_resolution = (BASE_62 == 62)? 5000 : 10000;
- sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
- string_base62((long int)(
- host_number * (1000000/id_resolution) +
- message_id_tv.tv_usec/id_resolution)) + 4);
- }
-
-/* Host number not set: final field is just the fractional time at an
-appropriate resolution. */
-
-else
- {
- id_resolution = (BASE_62 == 62)? 500 : 1000;
- sprintf(CS(message_id + MESSAGE_ID_LENGTH - 3), "-%2s",
- string_base62((long int)(message_id_tv.tv_usec/id_resolution)) + 4);
- }
+build_message_id_string(&message_id, &message_id_data);
/* Add the current message id onto the current process info string if
it will fit. */
receive_messagecount++;
-/* In SMTP sessions we may receive several in one connection. After each one,
-we wait for the clock to tick at the level of message-id granularity. This is
-so that the combination of time+pid is unique, even on systems where the pid
-can be re-used within our time interval. We can't shorten the interval without
-re-designing the message-id. See comments above where the message id is
-created. This is Something For The Future. */
-
-message_id_tv.tv_usec = (message_id_tv.tv_usec/id_resolution) * id_resolution;
-exim_wait_tick(&message_id_tv, id_resolution);
-
/* Add data size to written header size. We do not count the initial file name
that is in the file, but we do add one extra for the notional blank line that
precedes the data. This total differs from message_size in that it include the
header_list = header_last = NULL;
+/* In SMTP sessions we may receive several in one connection. After each one,
+we wait for the clock to tick at the level of message-id granularity. This is
+so that the combination of time+pid is unique, even on systems where the pid
+can be re-used within our time interval. We can't shorten the interval without
+re-designing the message-id. See comments above where the message id is
+created. This is Something For The Future. */
+
return yield; /* TRUE if more messages (SMTP only) */
}