/*
* Copyright (c) 1998-2001, 2003 Sendmail, Inc. and its suppliers.
* All rights reserved.
* Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#include "sm/generic.h"
SM_RCSID("@(#)$Id: arpadate.c,v 1.7 2006/10/06 02:51:35 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/time.h"
#include "sm/str.h"
/*
** ARPADATE -- Create date in RFC 2822 format
**
** Parameters:
** when -- time_t
** udate -- (pointer to) str for RFC2822 date field (output)
**
** Returns:
** pointer to an RFC 2822 date field
*/
#define MIN_per_HOUR 60 /* minutes in an hour */
#define MIN_per_DAY (24 * MIN_per_HOUR) /* minutes in a day */
#define SEC_per_MIN 60 /* seconds in a minute */
sm_ret_T
arpadate(time_t *when, sm_str_P udate)
{
char *p;
int off, i;
#if MTA_USE_PTHREADS
struct tm tm;
#endif
struct tm gmt;
struct tm *lt;
sm_ret_T ret;
char *ud, ct[26]; /* ctime_r(3) */
#define APPCHAR(ch) \
do \
{ \
if ((ret = sm_str_put(udate, (uchar) (ch))) != SM_SUCCESS) \
return ret; \
} while (0)
#define APPCHARP \
do \
{ \
APPCHAR(*p); \
p++; \
} while (0)
/*
** Get current time.
** This will be used if a null argument is passed and
** to resolve the timezone.
*/
SM_REQUIRE(when != NULL);
#if HAVE_CTIME_R
# if SM_CTIME_R_API == 2
(void) ctime_r(when, ct);
# elif SM_CTIME_R_API == 3
(void) ctime_r(when, ct, sizeof(ct));
# else
OOPS: unknown ctime_r() API
# endif
ud = ct;
#else /* HAVE_CTIME_R */
OOPS: missing ctime_r()
write a replacement function in librepl/
#endif /* HAVE_CTIME_R */
/*
** Crack the UNIX date line in a singularly unoriginal way.
*/
p = &ud[0]; /* weekday (%a) */
APPCHARP;
APPCHARP;
APPCHARP;
APPCHAR(',');
APPCHAR(' ');
p = &ud[8]; /* day of month (%e) */
APPCHARP; /* might be blank */
APPCHARP;
APPCHAR(' ');
p = &ud[4]; /* month (%b) */
APPCHARP;
APPCHARP;
APPCHARP;
APPCHAR(' ');
p = &ud[20]; /* year (%G) */
APPCHARP;
APPCHARP;
APPCHARP;
APPCHARP;
APPCHAR(' ');
p = &ud[11]; /* HH:MM:SS */
for (i = 8; i > 0; i--)
APPCHARP;
/*
** Should really get the timezone from the time in "ud" (which
** is only different if a non-null arg was passed which is different
** from the current time), but for all practical purposes, returning
** the current local zone will do (it's all that is ever needed).
*/
gmt = *gmtime(when);
#if MTA_USE_PTHREADS
lt = localtime_r(when, &tm);
#else /* MTA_USE_PTHREADS */
lt = localtime(when);
#endif /* MTA_USE_PTHREADS */
off = (lt->tm_hour - gmt.tm_hour) * MIN_per_HOUR + lt->tm_min - gmt.tm_min;
/* assume that offset isn't more than a day ... */
if (lt->tm_year < gmt.tm_year)
off -= MIN_per_DAY;
else if (lt->tm_year > gmt.tm_year)
off += MIN_per_DAY;
else if (lt->tm_yday < gmt.tm_yday)
off -= MIN_per_DAY;
else if (lt->tm_yday > gmt.tm_yday)
off += MIN_per_DAY;
/* seconds can be 0 - 60 now */
if (lt->tm_sec <= gmt.tm_sec - SEC_per_MIN)
off -= 1;
else if (lt->tm_sec >= gmt.tm_sec + SEC_per_MIN)
off += 1;
APPCHAR(' ');
if (off == 0)
{
APPCHAR('+');
APPCHAR('0');
APPCHAR('0');
APPCHAR('0');
APPCHAR('0');
}
else
{
if (off < 0)
{
off = -off;
APPCHAR('-');
}
else
APPCHAR('+');
if (off >= 24*60) /* should be impossible */
off = 23*60+59; /* if not, insert silly value */
APPCHAR((off / 600) + '0');
APPCHAR((off / 60) % 10 + '0');
off %= 60;
APPCHAR((off / 10) + '0');
APPCHAR((off % 10) + '0');
}
/* APPCHAR('\0'); */
return SM_SUCCESS;
}
syntax highlighted by Code2HTML, v. 0.9.1