Commit 9b414014 9b414014de10e4c543030b072a79d2de26fd239b by Sam Roberts

Moved some generically useful date/time handling functions to mutil.c,

fixed problems with portability of timezone information in struct tm, and
moved created a new structure to hold timezone information, since struct
tm doesn't do so reliably.
1 parent bd9d296b
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MAILUTILS_MUTIL_H
#define _MAILUTILS_MUTIL_H
/*
Collection of useful utility routines that are worth sharing,
but don't have a natural home somewhere else.
*/
#include <time.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
struct mu_timezone
{
int utc_offset;
/* Seconds east of UTC. */
const char *tz_name;
/* Nickname for this timezone, if known. It is always considered
* to be a pointer to static string, so will never be freed. */
};
typedef struct mu_timezone mu_timezone;
extern int mu_parse_imap_date_time __P ((const char **p, struct tm * tm,
mu_timezone * tz));
extern int mu_parse_ctime_date_time __P ((const char **p, struct tm * tm,
mu_timezone * tz));
extern time_t mu_utc_offset __P ((void));
extern time_t mu_tm2time __P ((struct tm * timeptr, mu_timezone * tz));
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_MUTIL_H */
......@@ -44,7 +44,7 @@ memory_stream.c \
mime.c \
misc.c \
monitor.c \
mu_mktime.c \
mutil.c \
muerror.c \
observer.c \
parse822.c \
......
......@@ -30,12 +30,11 @@
#include <mailutils/address.h>
#include <mailutils/error.h>
#include <mailutils/mutil.h>
#include <mailbox0.h>
#include <registrar0.h>
#include <imap0.h>
extern time_t mu_mktime __P((struct tm *timeptr, int tz));
/* Functions to overload the mailbox_t API. */
static void mailbox_imap_destroy __P ((mailbox_t));
static int mailbox_imap_open __P ((mailbox_t, int));
......@@ -91,13 +90,6 @@ static int imap_get_message0 __P ((msg_imap_t, message_t *));
static int message_operation __P ((f_imap_t, msg_imap_t, char *, size_t, size_t *));
static void free_subparts __P ((msg_imap_t));
static const char *MONTHS[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/* Initialize the concrete object mailbox_t by overloading the function of the
structure. */
int
......@@ -1232,67 +1224,6 @@ imap_envelope_sender (envelope_t envelope, char *buffer, size_t buflen,
return status;
}
int
imap_parse_date_time (const char **p, struct tm *tm, int *tz)
{
int year, mon, day, hour, min, sec;
char zone[6] = "+0000"; /* ( "+" / "-" ) hhmm */
char month[5] = "";
int hh = 0;
int mm = 0;
int sign = 1;
int scanned = 0, scanned3;
int i;
day = mon = year = hour = min = sec = 0;
memset (tm, 0, sizeof (*tm));
switch (sscanf (*p,
"%2d-%3s-%4d%n %2d:%2d:%2d %5s%n",
&day, month, &year, &scanned3, &hour, &min, &sec, zone,
&scanned))
{
case 3:
scanned = scanned3;
break;
case 7:
break;
default:
return -1;
}
tm->tm_sec = sec;
tm->tm_min = min;
tm->tm_hour = hour;
tm->tm_mday = day;
for (i = 0; i < 12; i++)
{
if (strncasecmp (month, MONTHS[i], 3) == 0)
{
mon = i;
break;
}
}
tm->tm_mon = mon;
tm->tm_year = (year > 1900) ? year - 1900 : year;
tm->tm_yday = 0; /* unknown. */
tm->tm_wday = 0; /* unknown. */
tm->tm_isdst = -1; /* unknown. */
hh = (zone[1] - '0') * 10 + (zone[2] - '0');
mm = (zone[3] - '0') * 10 + (zone[4] - '0');
sign = (zone[0] == '-') ? -1 : +1;
if (tz)
*tz = sign * (hh * 60 * 60 + mm * 60);
*p += scanned;
return 0;
}
static int
imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
size_t *plen)
......@@ -1302,7 +1233,7 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
m_imap_t m_imap = msg_imap->m_imap;
f_imap_t f_imap = m_imap->f_imap;
struct tm tm;
int tz;
mu_timezone tz;
time_t now;
char datebuf[] = "mm-dd-yyyy hh:mm:ss +0000";
const char* date = datebuf;
......@@ -1326,10 +1257,10 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
if (status != 0)
return status;
if (imap_parse_date_time(datep, &tm, &tz) != 0)
if (mu_parse_imap_date_time(datep, &tm, &tz) != 0)
now = (time_t)-1;
else
now = mu_mktime (&tm, tz);
now = mu_tm2time (&tm, &tz);
/* if the time was unparseable, or mktime() didn't like what we
parsed, use the calendar time. */
......
/* Copyright (C) 2001 Free Software Foundation, Inc.
A wrapper for mktime function allowing to specify the timezone.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <time.h>
#include <mailutils/mutil.h>
/* Convert struct tm into time_t, taking into account timezone offset.
mktime() always treats tm as if it was localtime, so convert it
to UTC, then adjust by the tm's real timezone, if it is known.
*/
time_t
mu_tm2time (struct tm *timeptr, mu_timezone* tz)
{
int offset = tz ? tz->utc_offset : 0;
return mktime(timeptr) - mu_utc_offset() + offset;
}
/* Convert time 0 at UTC to our localtime, that tells us the offset
of our current timezone from UTC. */
time_t mu_utc_offset(void)
{
time_t t = 0;
struct tm* tm = gmtime(&t);
return mktime(tm);
}
static const char *months[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL
};
static const char *wdays[] =
{
"Mon", "Teu", "Wed", "Thr", "Fri", "Sat", "Sun", NULL
};
int
mu_parse_imap_date_time (const char **p, struct tm *tm, mu_timezone *tz)
{
int year, mon, day, hour, min, sec;
char zone[6] = "+0000"; /* ( "+" / "-" ) hhmm */
char month[5] = "";
int hh = 0;
int mm = 0;
int sign = 1;
int scanned = 0, scanned3;
int i;
int tzoffset;
day = mon = year = hour = min = sec = 0;
memset (tm, 0, sizeof (*tm));
switch (sscanf (*p,
"%2d-%3s-%4d%n %2d:%2d:%2d %5s%n",
&day, month, &year, &scanned3, &hour, &min, &sec, zone,
&scanned))
{
case 3:
scanned = scanned3;
break;
case 7:
break;
default:
return -1;
}
tm->tm_sec = sec;
tm->tm_min = min;
tm->tm_hour = hour;
tm->tm_mday = day;
for (i = 0; i < 12; i++)
{
if (strncasecmp (month, months[i], 3) == 0)
{
mon = i;
break;
}
}
tm->tm_mon = mon;
tm->tm_year = (year > 1900) ? year - 1900 : year;
tm->tm_yday = 0; /* unknown. */
tm->tm_wday = 0; /* unknown. */
#if HAVE_TM_ISDST
tm->tm_isdst = -1; /* unknown. */
#endif
hh = (zone[1] - '0') * 10 + (zone[2] - '0');
mm = (zone[3] - '0') * 10 + (zone[4] - '0');
sign = (zone[0] == '-') ? -1 : +1;
tzoffset = sign * (hh * 60 * 60 + mm * 60);
#if HAVE_TM_GMTOFFSET
tm->tm_gmtoffset = tzoffset;
#endif
if (tz)
{
tz->utc_offset = tzoffset;
tz->tz_name = NULL;
}
*p += scanned;
return 0;
}
/* "ctime" format is: Thu Jul 01 15:58:27 1999, with no trailing \n. */
int
mu_parse_ctime_date_time (const char **p, struct tm *tm, mu_timezone * tz)
{
int wday = 0;
int year = 0;
int mon = 0;
int day = 0;
int hour = 0;
int min = 0;
int sec = 0;
int n = 0;
int i;
char weekday[5] = "";
char month[5] = "";
if (sscanf (*p, "%3s %3s %2d %2d:%2d:%2d %d%n\n",
weekday, month, &day, &hour, &min, &sec, &year, &n) != 7)
return -1;
*p += n;
for (i = 0; i < 7; i++)
{
if (strncasecmp (weekday, wdays[i], 3) == 0)
{
wday = i;
break;
}
}
for (i = 0; i < 12; i++)
{
if (strncasecmp (month, months[i], 3) == 0)
{
mon = i;
break;
}
}
if (tm)
{
memset (tm, 0, sizeof (struct tm));
tm->tm_sec = sec;
tm->tm_min = min;
tm->tm_hour = hour;
tm->tm_mday = day;
tm->tm_wday = wday;
tm->tm_mon = mon;
tm->tm_year = (year > 1900) ? year - 1900 : year;
#ifdef HAVE_TM_ISDST
tm->tm_isdst = -1; /* unknown. */
#endif
}
/* ctime has no timezone information, set tz to UTC if they ask. */
if (tz)
memset (tz, 0, sizeof (struct mu_timezone));
return 0;
}
......@@ -1431,7 +1431,7 @@ struct tm
};
#endif
int parse822_date_time(const char** p, const char* e, struct tm* tm)
int parse822_date_time(const char** p, const char* e, struct tm* tm, struct mu_timezone* tz)
{
/* date-time = [ day "," ] date time */
......@@ -1448,7 +1448,7 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm)
int min = 0;
int sec = 0;
int tz = 0;
int tzoffset = 0;
const char* tzname = 0;
if((rc = parse822_day(p, e, &wday))) {
......@@ -1468,7 +1468,7 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm)
*p = save;
return rc;
}
if((rc = parse822_time(p, e, &hour, &min, &sec, &tz, &tzname))) {
if((rc = parse822_time(p, e, &hour, &min, &sec, &tzoffset, &tzname))) {
*p = save;
return rc;
}
......@@ -1486,9 +1486,21 @@ int parse822_date_time(const char** p, const char* e, struct tm* tm)
tm->tm_min = min;
tm->tm_sec = sec;
#ifdef HAVE_TM_ISDST
tm->tm_isdst = -1; /* unknown whether it's dst or not */
tm->tm_gmtoff = tz;
#endif
#ifdef HAVE_TM_GMTOFF
tm->tm_gmtoff = tzoffset;
#endif
#ifdef HAVE_TM_ZONE
tm->tm_zone = tzname;
#endif
}
if(tz)
{
tz->utc_offset = tzoffset;
tz->tz_name = tzname;
}
return EOK;
......