Merge from vendor branch GROFF:
[dragonfly.git] / contrib / sendmail-8.13.4 / sendmail / arpadate.c
1 /*
2  * Copyright (c) 1998-2001 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13
14 #include <sendmail.h>
15
16 SM_RCSID("@(#)$Id: arpadate.c,v 8.30 2001/09/11 04:05:12 gshapiro Exp $")
17
18 /*
19 **  ARPADATE -- Create date in ARPANET format
20 **
21 **      Parameters:
22 **              ud -- unix style date string.  if NULL, one is created.
23 **
24 **      Returns:
25 **              pointer to an ARPANET date field
26 **
27 **      Side Effects:
28 **              none
29 **
30 **      WARNING:
31 **              date is stored in a local buffer -- subsequent
32 **              calls will overwrite.
33 **
34 **      Bugs:
35 **              Timezone is computed from local time, rather than
36 **              from wherever (and whenever) the message was sent.
37 **              To do better is very hard.
38 **
39 **              Some sites are now inserting the timezone into the
40 **              local date.  This routine should figure out what
41 **              the format is and work appropriately.
42 */
43
44 #ifndef TZNAME_MAX
45 # define TZNAME_MAX     50      /* max size of timezone */
46 #endif /* ! TZNAME_MAX */
47
48 /* values for TZ_TYPE */
49 #define TZ_NONE         0       /* no character timezone support */
50 #define TZ_TM_NAME      1       /* use tm->tm_name */
51 #define TZ_TM_ZONE      2       /* use tm->tm_zone */
52 #define TZ_TZNAME       3       /* use tzname[] */
53 #define TZ_TIMEZONE     4       /* use timezone() */
54
55 char *
56 arpadate(ud)
57         register char *ud;
58 {
59         register char *p;
60         register char *q;
61         register int off;
62         register int i;
63         register struct tm *lt;
64         time_t t;
65         struct tm gmt;
66         char *tz;
67         static char b[43 + TZNAME_MAX];
68
69         /*
70         **  Get current time.
71         **      This will be used if a null argument is passed and
72         **      to resolve the timezone.
73         */
74
75         /* SM_REQUIRE(ud == NULL || strlen(ud) >= 23); */
76         t = curtime();
77         if (ud == NULL)
78                 ud = ctime(&t);
79
80         /*
81         **  Crack the UNIX date line in a singularly unoriginal way.
82         */
83
84         q = b;
85
86         p = &ud[0];             /* Mon */
87         *q++ = *p++;
88         *q++ = *p++;
89         *q++ = *p++;
90         *q++ = ',';
91         *q++ = ' ';
92
93         p = &ud[8];             /* 16 */
94         if (*p == ' ')
95                 p++;
96         else
97                 *q++ = *p++;
98         *q++ = *p++;
99         *q++ = ' ';
100
101         p = &ud[4];             /* Sep */
102         *q++ = *p++;
103         *q++ = *p++;
104         *q++ = *p++;
105         *q++ = ' ';
106
107         p = &ud[20];            /* 1979 */
108         *q++ = *p++;
109         *q++ = *p++;
110         *q++ = *p++;
111         *q++ = *p++;
112         *q++ = ' ';
113
114         p = &ud[11];            /* 01:03:52 */
115         for (i = 8; i > 0; i--)
116                 *q++ = *p++;
117
118         /*
119         **  should really get the timezone from the time in "ud" (which
120         **  is only different if a non-null arg was passed which is different
121         **  from the current time), but for all practical purposes, returning
122         **  the current local zone will do (its all that is ever needed).
123         */
124
125         gmt = *gmtime(&t);
126         lt = localtime(&t);
127
128         off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min;
129
130         /* assume that offset isn't more than a day ... */
131         if (lt->tm_year < gmt.tm_year)
132                 off -= 24 * 60;
133         else if (lt->tm_year > gmt.tm_year)
134                 off += 24 * 60;
135         else if (lt->tm_yday < gmt.tm_yday)
136                 off -= 24 * 60;
137         else if (lt->tm_yday > gmt.tm_yday)
138                 off += 24 * 60;
139
140         *q++ = ' ';
141         if (off == 0)
142         {
143                 *q++ = 'G';
144                 *q++ = 'M';
145                 *q++ = 'T';
146         }
147         else
148         {
149                 tz = NULL;
150 #if TZ_TYPE == TZ_TM_NAME
151                 tz = lt->tm_name;
152 #endif /* TZ_TYPE == TZ_TM_NAME */
153 #if TZ_TYPE == TZ_TM_ZONE
154                 tz = lt->tm_zone;
155 #endif /* TZ_TYPE == TZ_TM_ZONE */
156 #if TZ_TYPE == TZ_TZNAME
157                 {
158                         extern char *tzname[];
159
160                         if (lt->tm_isdst > 0)
161                                 tz = tzname[1];
162                         else if (lt->tm_isdst == 0)
163                                 tz = tzname[0];
164                         else
165                                 tz = NULL;
166                 }
167 #endif /* TZ_TYPE == TZ_TZNAME */
168 #if TZ_TYPE == TZ_TIMEZONE
169                 {
170                         extern char *timezone();
171
172                         tz = timezone(off, lt->tm_isdst);
173                 }
174 #endif /* TZ_TYPE == TZ_TIMEZONE */
175                 if (off < 0)
176                 {
177                         off = -off;
178                         *q++ = '-';
179                 }
180                 else
181                         *q++ = '+';
182
183                 if (off >= 24*60)               /* should be impossible */
184                         off = 23*60+59;         /* if not, insert silly value */
185
186                 *q++ = (off / 600) + '0';
187                 *q++ = (off / 60) % 10 + '0';
188                 off %= 60;
189                 *q++ = (off / 10) + '0';
190                 *q++ = (off % 10) + '0';
191                 if (tz != NULL && *tz != '\0')
192                 {
193                         *q++ = ' ';
194                         *q++ = '(';
195                         while (*tz != '\0' && q < &b[sizeof b - 3])
196                                 *q++ = *tz++;
197                         *q++ = ')';
198                 }
199         }
200         *q = '\0';
201
202         return b;
203 }