#include "args.h"
/*
 * Copyright (c) 1986, 2014 by The Trustees of Columbia University in
 * the City of New York.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  + Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *  + Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 *  + Neither the name of Columbia University nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 */

#ifndef lint
static const char *rcsid = "$Header: /usr/local/src/mm/mm-0.94/mm/RCS/dates.c,v 1.6 2005/05/31 18:35:34 beebe Exp beebe $";
#endif

/*
 * dates.c - miscellaneous routines to manipulate date/time formats
 */

#include "mm.h"
#if BSD
#include <sys/timeb.h>			/* XXX use gettimeofday */
#endif

char *cdate ARGS((time_t it));
char *ctad ARGS((time_t it));
char *daytime ARGS((time_t it));
char *fdate ARGS((time_t it));
char *hdate ARGS((time_t it));
char *rfctime ARGS((time_t it));
time_t itime ARGS((struct tm *t));

#if defined(__NeXT__)
extern void ftime ARGS((struct timeb *tp_));
extern char *timezone ARGS((int zone, int dst));
#endif

#if defined(HAVE_GNU_LINUX)
extern char *timezone ARGS((int zone, int dst));
#endif

#if SYSV
extern char *tzname[2];
#endif

static int dayspermonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

static const char *month_names[] = {
    "January", "February", "March", "April", "May", "June", "July",
    "August", "September", "October", "November", "December"
};
static const char *day_names[] = {
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
    "Saturday"
};

int minutes_west;			/* offset from gmt; set in init.c */

#define dysize(y) \
    ((((((y) % 4) == 0 && (((y) % 100)) != 0) || ((y) % 400) == 0)) ? 366 : 365)

time_t
#if HAVE_STDC
itime(struct tm *t)
             				/* as returned by localtime(3) */
#else /* K&R style */
itime(t)
struct tm *t;				/* as returned by localtime(3) */
#endif /* HAVE_STDC */
{
    int i;
    unsigned long x = 0;
    int year = t->tm_year + 1900;

    int dst = (t->tm_isdst ? 1 : 0);	/* how much to subtract for dst */

    /* count days in previous years back to 1970 */
    for (i = (year - 1); i >= 1970; i--)
	x += dysize(i);

    /* add in days in previous months for this year */
    for (i = t->tm_mon; i > 0; i--)
	x += dayspermonth[i-1];

    /* include Feb 29th if it has occurred this year */
    if ((dysize(year) == 366) && (t->tm_mon >= 2))
	x++;

    x += t->tm_mday - 1;		/* add days this month */

    x = (24*x) + t->tm_hour - dst;	/* convert and add hours */
    x = (60*x) + t->tm_min + minutes_west; /* add minutes, convert to gmt */
    x = (60*x) + t->tm_sec;		/* seconds */
    return (time_t) x;
}

/*
 * 1 Jan 70
 */
char *
#if HAVE_STDC
cdate(time_t it)
#else /* K&R style */
cdate(it)
time_t it;
#endif /* HAVE_STDC */
{
    struct tm *t;
    static char str[16];

    t = localtime(&it);
    sprintf(str, "%d %3.3s %d", t->tm_mday, month_names[t->tm_mon],
	    (t->tm_year < 100) ? t->tm_year : t->tm_year + 1900);
    return (char *) str;
}

/*
 * ctad - convert internal time to ascii
 *
 * Similar to ctime, but the output format is "11 Oct 86 12:42am"
 * Returns current time if the argument is zero.
 */

char *
#if HAVE_STDC
ctad(time_t it)
#else /* K&R style */
ctad(it)
time_t it;
#endif /* HAVE_STDC */
{
    struct tm *t;
    static char str[32];

    if (it == 0)
	(void) time (&it);

    t = localtime(&it);
    sprintf(str,"%d %3.3s %d %d:%02d%s",
	    t->tm_mday, month_names[t->tm_mon],
	    (t->tm_year < 100) ? t->tm_year : t->tm_year + 1900,
	    (((t->tm_hour % 12) == 0) ? 12 : (t->tm_hour % 12)),
	    t->tm_min, ((t->tm_hour < 12) ? "am" : "pm"));
    return (char *) str;
}

/*
 * fdate - convert internal date/time to message separator format used
 * in mail files
 *
 * 01-Jan-70 00:00:00-GMT
 */

char *
#if HAVE_STDC
fdate (time_t it)
#else /* K&R style */
fdate (it)
time_t it;
#endif /* HAVE_STDC */
{
    struct tm *t;
    static char str[32];

    t = gmtime (&it);
    sprintf (str, "%2d-%3.3s-%d %2d:%02d:%02d-GMT",
		 t->tm_mday, month_names[t->tm_mon],
#if 0
		 (t->tm_year < 100) ? t->tm_year : t->tm_year + 1900,
#else
		 t->tm_year + 1900,	/* always use 4-digit year */
#endif
		 t->tm_hour, t->tm_min, t->tm_sec);
    return (char *) str;
}

/*
 * hdate - convert internal date to ascii
 *
 * return a date string for use in displaying headers in the form
 * nn-mmm
 */

char *
#if HAVE_STDC
hdate (time_t it)
#else /* K&R style */
hdate (it)
time_t it;
#endif /* HAVE_STDC */
{
    struct tm *t;
    static char str[32];

    t = localtime(&it);
    /* %2.0d works.  it should be %2.2d, but that comes out as "07" */
    sprintf(str,"%2.0d-%3.3s",
	    t->tm_mday, month_names[t->tm_mon]);
    return (char *) str;
}


/*
 * More verbose version of ctad; format is "Thursday, 31 July 1986 11:20PM"
 *
 * If the argument is zero, the current date is returned.
 */
char *
#if HAVE_STDC
daytime(time_t it)
#else /* K&R style */
daytime(it)
time_t it;
#endif /* HAVE_STDC */
{
    struct tm *t;
    static char str[64];

    if (it == 0)
	(void) time (&it);

    t = localtime(&it);
    sprintf(str,"%s, %d %s %d %d:%02d%s",
	    day_names[t->tm_wday],
	    t->tm_mday, month_names[t->tm_mon], t->tm_year + 1900,
	    (((t->tm_hour % 12) == 0) ? 12 : (t->tm_hour % 12)),
	    t->tm_min, ((t->tm_hour < 12) ? "AM" : "PM"));
    return (char *) str;
}


/*
 * rfc822-acceptable date, like:
 * Thu, 1 Jan 70 00:00:00 GMT
 * Apparently this routine is used only to construct the Resent-Date:.
 * New messages arrive with their dates already filled in (correctly).
 * Fixed 8 Jan 2006 to write the full year.
 */
char *
#if HAVE_STDC
rfctime(time_t it)
#else /* K&R style */
rfctime(it)
time_t it;
#endif /* HAVE_STDC */
{
    struct tm *t;
    static char str[64];
#if BSD
    struct timeb tb;
#endif

    if (it == 0)
	(void) time (&it);

    t = localtime(&it);
#if BSD && !defined(HAVE_NEW_BSD)
    ftime (&tb);
#endif
#if SYSV || defined(HAVE_NEW_BSD)
    asctime(t);
#endif
    sprintf(str,"%3.3s, %d %3.3s %d %d:%02d:%02d %s",
	    day_names[t->tm_wday],
#ifdef COMMENT
	    t->tm_mday, month_names[t->tm_mon], t->tm_year /*+ 1900*/,
#else  /* fdc 8 Jan 2006 */
	    t->tm_mday, month_names[t->tm_mon], t->tm_year + 1900,
#endif	/* COMMENT */
	    t->tm_hour, t->tm_min, t->tm_sec,
#if BSD && !defined(__solaris) && !defined(_IBMR2) && !defined(__osf__) && !defined(HAVE_NEW_BSD) && !defined(HAVE_GNU_LINUX)
	    timezone(tb.timezone, t->tm_isdst)
#else
#if SYSV || defined(__solaris) || defined(_IBMR2) || defined(__osf__) || defined(HAVE_NEW_BSD) || defined(HAVE_GNU_LINUX)
	    tzname[t->tm_isdst ? 1 : 0]
#endif
#endif
	    );
    return (char *) str;
}
