Commit | Line | Data |
---|---|---|
059ec3d9 PH |
1 | /* $Cambridge: exim/src/src/tod.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */ |
2 | ||
3 | /************************************************* | |
4 | * Exim - an Internet mail transport agent * | |
5 | *************************************************/ | |
6 | ||
7 | /* Copyright (c) University of Cambridge 1995 - 2004 */ | |
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 */ |