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