11556Srgrimes/* 21556Srgrimes * Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers. 31556Srgrimes * All rights reserved. 41556Srgrimes * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 51556Srgrimes * Copyright (c) 1988, 1993 61556Srgrimes * The Regents of the University of California. All rights reserved. 71556Srgrimes * 81556Srgrimes * By using this file, you agree to the terms and conditions set 91556Srgrimes * forth in the LICENSE file which can be found at the top level of 101556Srgrimes * the sendmail distribution. 111556Srgrimes * 121556Srgrimes */ 131556Srgrimes 141556Srgrimes#include <sendmail.h> 151556Srgrimes 161556SrgrimesSM_RCSID("@(#)$Id: arpadate.c,v 8.32 2013-11-22 20:51:55 ca Exp $") 171556Srgrimes 181556Srgrimes/* 191556Srgrimes** ARPADATE -- Create date in ARPANET format 201556Srgrimes** 211556Srgrimes** Parameters: 221556Srgrimes** ud -- unix style date string. if NULL, one is created. 231556Srgrimes** 241556Srgrimes** Returns: 251556Srgrimes** pointer to an ARPANET date field 261556Srgrimes** 271556Srgrimes** Side Effects: 281556Srgrimes** none 291556Srgrimes** 301556Srgrimes** WARNING: 311556Srgrimes** date is stored in a local buffer -- subsequent 321556Srgrimes** calls will overwrite. 331556Srgrimes** 3436150Scharnier** Bugs: 3536150Scharnier** Timezone is computed from local time, rather than 3636150Scharnier** from wherever (and whenever) the message was sent. 371556Srgrimes** To do better is very hard. 3899110Sobrien** 3999110Sobrien** Some sites are now inserting the timezone into the 401556Srgrimes** local date. This routine should figure out what 4117987Speter** the format is and work appropriately. 4217987Speter*/ 4317987Speter 4417987Speter#ifndef TZNAME_MAX 4517987Speter# define TZNAME_MAX 50 /* max size of timezone */ 4617987Speter#endif /* ! TZNAME_MAX */ 4717987Speter 4817987Speter/* values for TZ_TYPE */ 4919281Sache#define TZ_NONE 0 /* no character timezone support */ 5038887Stegge#define TZ_TM_NAME 1 /* use tm->tm_name */ 51108286Stjr#define TZ_TM_ZONE 2 /* use tm->tm_zone */ 5217987Speter#define TZ_TZNAME 3 /* use tzname[] */ 531556Srgrimes#define TZ_TIMEZONE 4 /* use timezone() */ 541556Srgrimes 551556Srgrimeschar * 561556Srgrimesarpadate(ud) 571556Srgrimes register char *ud; 581556Srgrimes{ 591556Srgrimes register char *p; 601556Srgrimes register char *q; 611556Srgrimes register int off; 621556Srgrimes register int i; 631556Srgrimes register struct tm *lt; 641556Srgrimes time_t t; 651556Srgrimes struct tm gmt; 661556Srgrimes char *tz; 671556Srgrimes static char b[43 + TZNAME_MAX]; 681556Srgrimes 691556Srgrimes /* 701556Srgrimes ** Get current time. 711556Srgrimes ** This will be used if a null argument is passed and 721556Srgrimes ** to resolve the timezone. 7317987Speter */ 7417987Speter 751556Srgrimes /* SM_REQUIRE(ud == NULL || strlen(ud) >= 23); */ 761556Srgrimes t = curtime(); 771556Srgrimes if (ud == NULL) 781556Srgrimes ud = ctime(&t); 791556Srgrimes 801556Srgrimes /* 811556Srgrimes ** Crack the UNIX date line in a singularly unoriginal way. 821556Srgrimes */ 831556Srgrimes 841556Srgrimes q = b; 851556Srgrimes 861556Srgrimes p = &ud[0]; /* Mon */ 871556Srgrimes *q++ = *p++; 881556Srgrimes *q++ = *p++; 89117261Sdds *q++ = *p++; 90117261Sdds *q++ = ','; 91117261Sdds *q++ = ' '; 92117261Sdds 93117261Sdds p = &ud[8]; /* 16 */ 941556Srgrimes if (*p == ' ') 9590111Simp p++; 9690111Simp else 9790111Simp *q++ = *p++; 9890111Simp *q++ = *p++; 9990111Simp *q++ = ' '; 10090111Simp 10190111Simp p = &ud[4]; /* Sep */ 10290111Simp *q++ = *p++; 103155301Sschweikh *q++ = *p++; 10490111Simp *q++ = *p++; 10590111Simp *q++ = ' '; 10690111Simp 10790111Simp p = &ud[20]; /* 1979 */ 10890111Simp *q++ = *p++; 10990111Simp *q++ = *p++; 11090111Simp *q++ = *p++; 11190111Simp *q++ = *p++; 11290111Simp *q++ = ' '; 1131556Srgrimes 11490111Simp p = &ud[11]; /* 01:03:52 */ 115118374Sache for (i = 8; i > 0; i--) 11619281Sache *q++ = *p++; 11719281Sache 11819281Sache /* 11919281Sache ** should really get the timezone from the time in "ud" (which 12019281Sache ** is only different if a non-null arg was passed which is different 121118374Sache ** from the current time), but for all practical purposes, returning 12219281Sache ** the current local zone will do (its all that is ever needed). 12319281Sache */ 1241556Srgrimes 1251556Srgrimes gmt = *gmtime(&t); 12690111Simp lt = localtime(&t); 12790111Simp 1281556Srgrimes off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min; 1291556Srgrimes 1301556Srgrimes /* assume that offset isn't more than a day ... */ 13190111Simp if (lt->tm_year < gmt.tm_year) 13290111Simp off -= 24 * 60; 1331556Srgrimes else if (lt->tm_year > gmt.tm_year) 1341556Srgrimes off += 24 * 60; 13539137Stegge else if (lt->tm_yday < gmt.tm_yday) 1361556Srgrimes off -= 24 * 60; 1371556Srgrimes else if (lt->tm_yday > gmt.tm_yday) 1381556Srgrimes off += 24 * 60; 1391556Srgrimes 1401556Srgrimes *q++ = ' '; 1411556Srgrimes if (off == 0) 1421556Srgrimes { 1431556Srgrimes *q++ = 'G'; 1441556Srgrimes *q++ = 'M'; 1451556Srgrimes *q++ = 'T'; 1461556Srgrimes } 14790111Simp else 14817987Speter { 1491556Srgrimes tz = NULL; 1501556Srgrimes#if TZ_TYPE == TZ_TM_NAME 1511556Srgrimes tz = lt->tm_name; 1521556Srgrimes#endif /* TZ_TYPE == TZ_TM_NAME */ 1531556Srgrimes#if TZ_TYPE == TZ_TM_ZONE 1541556Srgrimes tz = lt->tm_zone; 1551556Srgrimes#endif /* TZ_TYPE == TZ_TM_ZONE */ 1561556Srgrimes#if TZ_TYPE == TZ_TZNAME 1571556Srgrimes { 1581556Srgrimes extern char *tzname[]; 1591556Srgrimes 1601556Srgrimes if (lt->tm_isdst > 0) 1611556Srgrimes tz = tzname[1]; 1621556Srgrimes else if (lt->tm_isdst == 0) 1631556Srgrimes tz = tzname[0]; 1641556Srgrimes else 1651556Srgrimes tz = NULL; 1661556Srgrimes } 1671556Srgrimes#endif /* TZ_TYPE == TZ_TZNAME */ 1681556Srgrimes#if TZ_TYPE == TZ_TIMEZONE 1691556Srgrimes { 1701556Srgrimes extern char *timezone(); 1711556Srgrimes 1721556Srgrimes tz = timezone(off, lt->tm_isdst); 1731556Srgrimes } 1741556Srgrimes#endif /* TZ_TYPE == TZ_TIMEZONE */ 1751556Srgrimes if (off < 0) 1761556Srgrimes { 1771556Srgrimes off = -off; 1781556Srgrimes *q++ = '-'; 1791556Srgrimes } 1801556Srgrimes else 1811556Srgrimes *q++ = '+'; 1821556Srgrimes 1831556Srgrimes if (off >= 24*60) /* should be impossible */ 1841556Srgrimes off = 23*60+59; /* if not, insert silly value */ 1851556Srgrimes 1861556Srgrimes *q++ = (off / 600) + '0'; 1871556Srgrimes *q++ = (off / 60) % 10 + '0'; 1881556Srgrimes off %= 60; 1891556Srgrimes *q++ = (off / 10) + '0'; 1901556Srgrimes *q++ = (off % 10) + '0'; 1911556Srgrimes if (tz != NULL && *tz != '\0') 1921556Srgrimes { 1931556Srgrimes *q++ = ' '; 1941556Srgrimes *q++ = '('; 1951556Srgrimes while (*tz != '\0' && q < &b[sizeof(b) - 3]) 1961556Srgrimes *q++ = *tz++; 1971556Srgrimes *q++ = ')'; 1981556Srgrimes } 1991556Srgrimes } 2001556Srgrimes *q = '\0'; 2011556Srgrimes 2021556Srgrimes return b; 20390111Simp} 20417987Speter