138032Speter/*
2261194Sgshapiro * Copyright (c) 1998-2001 Proofpoint, Inc. and its suppliers.
364562Sgshapiro *	All rights reserved.
438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
538032Speter * Copyright (c) 1988, 1993
638032Speter *	The Regents of the University of California.  All rights reserved.
738032Speter *
838032Speter * By using this file, you agree to the terms and conditions set
938032Speter * forth in the LICENSE file which can be found at the top level of
1038032Speter * the sendmail distribution.
1138032Speter *
1238032Speter */
1338032Speter
1464562Sgshapiro#include <sendmail.h>
1538032Speter
16266527SgshapiroSM_RCSID("@(#)$Id: arpadate.c,v 8.32 2013-11-22 20:51:55 ca Exp $")
1790792Sgshapiro
1838032Speter/*
1938032Speter**  ARPADATE -- Create date in ARPANET format
2038032Speter**
2138032Speter**	Parameters:
2238032Speter**		ud -- unix style date string.  if NULL, one is created.
2338032Speter**
2438032Speter**	Returns:
2538032Speter**		pointer to an ARPANET date field
2638032Speter**
2738032Speter**	Side Effects:
2838032Speter**		none
2938032Speter**
3038032Speter**	WARNING:
3138032Speter**		date is stored in a local buffer -- subsequent
3238032Speter**		calls will overwrite.
3338032Speter**
3438032Speter**	Bugs:
3538032Speter**		Timezone is computed from local time, rather than
3664562Sgshapiro**		from wherever (and whenever) the message was sent.
3738032Speter**		To do better is very hard.
3838032Speter**
3938032Speter**		Some sites are now inserting the timezone into the
4038032Speter**		local date.  This routine should figure out what
4138032Speter**		the format is and work appropriately.
4238032Speter*/
4338032Speter
4438032Speter#ifndef TZNAME_MAX
4538032Speter# define TZNAME_MAX	50	/* max size of timezone */
46363466Sgshapiro#endif
4738032Speter
4838032Speter/* values for TZ_TYPE */
4938032Speter#define TZ_NONE		0	/* no character timezone support */
5038032Speter#define TZ_TM_NAME	1	/* use tm->tm_name */
5138032Speter#define TZ_TM_ZONE	2	/* use tm->tm_zone */
5238032Speter#define TZ_TZNAME	3	/* use tzname[] */
5338032Speter#define TZ_TIMEZONE	4	/* use timezone() */
5438032Speter
5538032Speterchar *
5638032Speterarpadate(ud)
5738032Speter	register char *ud;
5838032Speter{
5938032Speter	register char *p;
6038032Speter	register char *q;
6138032Speter	register int off;
6238032Speter	register int i;
6338032Speter	register struct tm *lt;
6438032Speter	time_t t;
6538032Speter	struct tm gmt;
6638032Speter	char *tz;
6738032Speter	static char b[43 + TZNAME_MAX];
6838032Speter
6938032Speter	/*
7038032Speter	**  Get current time.
7138032Speter	**	This will be used if a null argument is passed and
7238032Speter	**	to resolve the timezone.
7338032Speter	*/
7438032Speter
7590792Sgshapiro	/* SM_REQUIRE(ud == NULL || strlen(ud) >= 23); */
7643730Speter	t = curtime();
7738032Speter	if (ud == NULL)
7838032Speter		ud = ctime(&t);
7938032Speter
8038032Speter	/*
8138032Speter	**  Crack the UNIX date line in a singularly unoriginal way.
8238032Speter	*/
8338032Speter
8438032Speter	q = b;
8538032Speter
8638032Speter	p = &ud[0];		/* Mon */
8738032Speter	*q++ = *p++;
8838032Speter	*q++ = *p++;
8938032Speter	*q++ = *p++;
9038032Speter	*q++ = ',';
9138032Speter	*q++ = ' ';
9238032Speter
9338032Speter	p = &ud[8];		/* 16 */
9438032Speter	if (*p == ' ')
9538032Speter		p++;
9638032Speter	else
9738032Speter		*q++ = *p++;
9838032Speter	*q++ = *p++;
9938032Speter	*q++ = ' ';
10038032Speter
10138032Speter	p = &ud[4];		/* Sep */
10238032Speter	*q++ = *p++;
10338032Speter	*q++ = *p++;
10438032Speter	*q++ = *p++;
10538032Speter	*q++ = ' ';
10638032Speter
10738032Speter	p = &ud[20];		/* 1979 */
10838032Speter	*q++ = *p++;
10938032Speter	*q++ = *p++;
11038032Speter	*q++ = *p++;
11138032Speter	*q++ = *p++;
11238032Speter	*q++ = ' ';
11338032Speter
11438032Speter	p = &ud[11];		/* 01:03:52 */
11538032Speter	for (i = 8; i > 0; i--)
11638032Speter		*q++ = *p++;
11738032Speter
11838032Speter	/*
11977349Sgshapiro	**  should really get the timezone from the time in "ud" (which
12077349Sgshapiro	**  is only different if a non-null arg was passed which is different
12177349Sgshapiro	**  from the current time), but for all practical purposes, returning
12277349Sgshapiro	**  the current local zone will do (its all that is ever needed).
12377349Sgshapiro	*/
12477349Sgshapiro
12538032Speter	gmt = *gmtime(&t);
12638032Speter	lt = localtime(&t);
12738032Speter
12838032Speter	off = (lt->tm_hour - gmt.tm_hour) * 60 + lt->tm_min - gmt.tm_min;
12938032Speter
13038032Speter	/* assume that offset isn't more than a day ... */
13138032Speter	if (lt->tm_year < gmt.tm_year)
13238032Speter		off -= 24 * 60;
13338032Speter	else if (lt->tm_year > gmt.tm_year)
13438032Speter		off += 24 * 60;
13538032Speter	else if (lt->tm_yday < gmt.tm_yday)
13638032Speter		off -= 24 * 60;
13738032Speter	else if (lt->tm_yday > gmt.tm_yday)
13838032Speter		off += 24 * 60;
13938032Speter
14038032Speter	*q++ = ' ';
14138032Speter	if (off == 0)
14238032Speter	{
14338032Speter		*q++ = 'G';
14438032Speter		*q++ = 'M';
14538032Speter		*q++ = 'T';
14638032Speter	}
14738032Speter	else
14838032Speter	{
14938032Speter		tz = NULL;
15038032Speter#if TZ_TYPE == TZ_TM_NAME
15138032Speter		tz = lt->tm_name;
152363466Sgshapiro#endif
15338032Speter#if TZ_TYPE == TZ_TM_ZONE
15438032Speter		tz = lt->tm_zone;
155363466Sgshapiro#endif
15638032Speter#if TZ_TYPE == TZ_TZNAME
15738032Speter		{
15838032Speter			extern char *tzname[];
15938032Speter
16043730Speter			if (lt->tm_isdst > 0)
16143730Speter				tz = tzname[1];
16243730Speter			else if (lt->tm_isdst == 0)
16343730Speter				tz = tzname[0];
16443730Speter			else
16543730Speter				tz = NULL;
16638032Speter		}
16764562Sgshapiro#endif /* TZ_TYPE == TZ_TZNAME */
16838032Speter#if TZ_TYPE == TZ_TIMEZONE
16938032Speter		{
17038032Speter			extern char *timezone();
17138032Speter
17238032Speter			tz = timezone(off, lt->tm_isdst);
17338032Speter		}
17464562Sgshapiro#endif /* TZ_TYPE == TZ_TIMEZONE */
17538032Speter		if (off < 0)
17638032Speter		{
17738032Speter			off = -off;
17838032Speter			*q++ = '-';
17938032Speter		}
18038032Speter		else
18138032Speter			*q++ = '+';
18238032Speter
18338032Speter		if (off >= 24*60)		/* should be impossible */
18438032Speter			off = 23*60+59;		/* if not, insert silly value */
18538032Speter
18638032Speter		*q++ = (off / 600) + '0';
18738032Speter		*q++ = (off / 60) % 10 + '0';
18838032Speter		off %= 60;
18938032Speter		*q++ = (off / 10) + '0';
19038032Speter		*q++ = (off % 10) + '0';
19138032Speter		if (tz != NULL && *tz != '\0')
19238032Speter		{
19338032Speter			*q++ = ' ';
19438032Speter			*q++ = '(';
195168515Sgshapiro			while (*tz != '\0' && q < &b[sizeof(b) - 3])
19638032Speter				*q++ = *tz++;
19738032Speter			*q++ = ')';
19838032Speter		}
19938032Speter	}
20038032Speter	*q = '\0';
20138032Speter
20264562Sgshapiro	return b;
20338032Speter}
204