/* $Id$ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "fdm.h"
int tzlookup(const char *, int *);
char *
rfc822time(time_t t, char *buf, size_t len)
{
struct tm *tm;
size_t n;
tm = localtime(&t);
if ((n = strftime(buf, len, "%a, %d %b %Y %H:%M:%S %z", tm)) == 0)
return (NULL);
if (n == len)
return (NULL);
return (buf);
}
/*
* Some mailers, notably AOL's, use the timezone string instead of an offset
* from UTC. A limited set of these are permitted by RFC822, but it is still
* highly annoying: others can appear, and since there are duplicate
* abbreviations it cannot be converted with absolute certainty. As it is only
* a few clients do this anyway, don't even try particularly hard, just try to
* look it up using tzset, which catches the few most common abbreviations.
*/
int
tzlookup(const char *tz, int *off)
{
char *saved_tz;
struct tm *tm;
time_t t;
saved_tz = getenv("TZ");
if (saved_tz != NULL)
saved_tz = xstrdup(saved_tz);
/* Set the new timezone. */
if (setenv("TZ", tz, 1) != 0)
goto error;
tzset();
/* Get the time at epoch + one year. */
t = TIME_YEAR;
tm = localtime(&t);
/* And work out the timezone. */
if (strcmp(tz, tm->tm_zone) != 0)
goto error;
*off = tm->tm_gmtoff;
/* Restore the old timezone. */
if (saved_tz != NULL) {
if (setenv("TZ", saved_tz, 1) != 0)
goto error;
xfree(saved_tz);
} else
unsetenv("TZ");
tzset();
return (0);
error:
if (saved_tz != NULL)
xfree(saved_tz);
return (-1);
}
int
mailtime(struct mail *m, time_t *tim)
{
char *s, *ptr, *endptr, *hdr;
const char *errstr;
size_t len;
struct tm tm;
int tz;
hdr = find_header(m, "date", &len, 1);
if (hdr == NULL || len == 0)
return (-1);
/* Make a copy of the header. */
s = xmalloc(len + 1);
strlcpy(s, hdr, len + 1);
/* Skip spaces. */
ptr = s;
while (*ptr != '\0' && isspace((u_char) *ptr))
ptr++;
/* Parse the date. */
memset(&tm, 0, sizeof tm);
endptr = strptime(ptr, "%a, %d %b %Y %H:%M:%S", &tm);
if (endptr == NULL)
endptr = strptime(ptr, "%d %b %Y %H:%M:%S", &tm);
if (endptr == NULL)
goto invalid;
*tim = mktime(&tm);
/* Skip spaces. */
while (*endptr != '\0' && isspace((u_char) *endptr))
endptr++;
/* Terminate the timezone. */
ptr = endptr;
while (*ptr != '\0' && !isspace((u_char) *ptr))
ptr++;
*ptr = '\0';
tz = strtonum(endptr, -2359, 2359, &errstr);
if (errstr != NULL) {
/* Try it using tzset. */
if (tzlookup(endptr, &tz) != 0)
goto invalid;
}
*tim -= (tz / 100) * TIME_HOUR + (tz % 100) * TIME_MINUTE;
if (*tim < 0)
goto invalid;
xfree(s);
return (0);
invalid:
xfree(s);
return (-1);
}