Improvements to local interface IP addr detection. Fixes: #802
[users/jgh/exim.git] / src / src / tod.c
1 /* $Cambridge: exim/src/src/tod.c,v 1.4 2007/01/08 10:50:18 ph10 Exp $ */
2
3 /*************************************************
4 *     Exim - an Internet mail transport agent    *
5 *************************************************/
6
7 /* Copyright (c) University of Cambridge 1995 - 2007 */
8 /* See the file NOTICE for conditions of use and distribution. */
9
10 /* A function for returning the time of day in various formats */
11
12
13 #include "exim.h"
14
15 /* #define TESTING_LOG_DATESTAMP */
16
17
18 static uschar timebuf[sizeof("www, dd-mmm-yyyy hh:mm:ss +zzzz")];
19
20
21 /*************************************************
22 *                Return timestamp                *
23 *************************************************/
24
25 /* The log timestamp format is dd-mmm-yy so as to be non-confusing on both
26 sides of the Atlantic. We calculate an explicit numerical offset from GMT for
27 the full datestamp and BSD inbox datestamp. Note that on some systems
28 localtime() and gmtime() re-use the same store, so we must save the local time
29 values before calling gmtime(). If timestamps_utc is set, don't use
30 localtime(); all times are then in UTC (with offset +0000).
31
32 There are also some contortions to get the day of the month without
33 a leading zero for the full stamp, since Ustrftime() doesn't provide this
34 option.
35
36 Argument:  type of timestamp required:
37              tod_bsdin          BSD inbox format
38              tod_epoch          Unix epoch format
39              tod_full           full date and time
40              tod_log            log file data line format,
41                                   with zone if log_timezone is TRUE
42              tod_log_bare       always without zone
43              tod_log_datestamp  for log file names when datestamped
44              tod_log_zone       always with zone
45              tod_mbx            MBX inbox format
46              tod_zone           just the timezone offset
47              tod_zulu           time in 8601 zulu format
48
49 Returns:   pointer to fixed buffer containing the timestamp
50 */
51
52 uschar *
53 tod_stamp(int type)
54 {
55 time_t now = time(NULL);
56 struct tm *t;
57
58 /* Vary log type according to timezone requirement */
59
60 if (type == tod_log) type = log_timezone? tod_log_zone : tod_log_bare;
61
62 /* Styles that don't need local time */
63
64 else if (type == tod_epoch)
65   {
66   (void) sprintf(CS timebuf, "%d", (int)now);  /* Unix epoch format */
67   return timebuf;
68   }
69
70 else if (type == tod_zulu)
71   {
72   t = gmtime(&now);
73   (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d%02dZ",
74     1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min,
75     t->tm_sec);
76   return timebuf;
77   }
78
79 /* Convert to local time or UTC */
80
81 t = timestamps_utc? gmtime(&now) : localtime(&now);
82
83 switch(type)
84   {
85   case tod_log_bare:          /* Format used in logging without timezone */
86   (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d",
87     1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday,
88     t->tm_hour, t->tm_min, t->tm_sec);
89   break;
90
91   /* Format used as suffix of log file name when 'log_datestamp' is active. For
92   testing purposes, it changes the file every second. */
93
94   case tod_log_datestamp:
95   #ifdef TESTING_LOG_DATESTAMP
96   (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d",
97     1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min);
98   #else
99   (void) sprintf(CS timebuf, "%04d%02d%02d",
100     1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday);
101   #endif
102   break;
103
104   /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976
105   ("UUCP Mail Interchange Format Standard") but only by example, not by
106   explicit definition. The examples show no timezone offsets, and some MUAs
107   appear to be sensitive to this, so Exim has been changed to remove the
108   timezone offsets that originally appeared. */
109
110   case tod_bsdin:
111     {
112     int len = Ustrftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", t);
113     Ustrftime(timebuf + len, sizeof(timebuf) - len, " %Y", t);
114     }
115   break;
116
117   /* Other types require the GMT offset to be calculated, or just set up in the
118   case of UTC timestamping. We need to take a copy of the local time first. */
119
120   default:
121     {
122     int diff_hour, diff_min;
123     struct tm local;
124     memcpy(&local, t, sizeof(struct tm));
125
126     if (timestamps_utc)
127       {
128       diff_hour = diff_min = 0;
129       }
130     else
131       {
132       struct tm *gmt = gmtime(&now);
133       diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
134       if (local.tm_year != gmt->tm_year)
135         diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440;
136       else if (local.tm_yday != gmt->tm_yday)
137         diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440;
138       diff_hour = diff_min/60;
139       diff_min  = abs(diff_min - diff_hour*60);
140       }
141
142     switch(type)
143       {
144       case tod_log_zone:          /* Format used in logging with timezone */
145       (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+03d%02d",
146         1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
147         local.tm_hour, local.tm_min, local.tm_sec,
148         diff_hour, diff_min);
149       break;
150
151       case tod_zone:              /* Just the timezone offset */
152       (void) sprintf(CS timebuf, "%+03d%02d", diff_hour, diff_min);
153       break;
154
155       /* tod_mbx: format used in MBX mailboxes - subtly different to tod_full */
156
157       #ifdef SUPPORT_MBX
158       case tod_mbx:
159         {
160         int len;
161         (void) sprintf(CS timebuf, "%02d-", local.tm_mday);
162         len = Ustrlen(timebuf);
163         len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b-%Y %H:%M:%S",
164           &local);
165         (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
166         }
167       break;
168       #endif
169
170       /* tod_full: format used in Received: headers (use as default just in case
171       called with a junk type value) */
172
173       default:
174         {
175         int len = Ustrftime(timebuf, sizeof(timebuf), "%a, ", &local);
176         (void) sprintf(CS timebuf + len, "%02d ", local.tm_mday);
177         len += Ustrlen(timebuf + len);
178         len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b %Y %H:%M:%S",
179           &local);
180         (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
181         }
182       break;
183       }
184     }
185   break;
186   }
187
188 return timebuf;
189 }
190
191 /* End of tod.c */