message-date.c revision ba3dc5075c0851302032edefb9015207c3b57cd4
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "lib.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "str.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen#include "utc-offset.h"
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen#include "utc-mktime.h"
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen#include "rfc822-parser.h"
419be6cd72f6e11705576bbba683b29c32eaa762Timo Sirainen#include "message-date.h"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen#include <ctype.h>
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen
c4390dad33b03dd51ba2a475f550347c86ebdb9aTimo Sirainen/* RFC specifies ':' as the only allowed separator,
dd3ccdbb29dad006f7781ea138a5ba39727963c4Timo Sirainen but be forgiving also for some broken ones */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen#define IS_TIME_SEP(c) \
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen ((c) == ':' || (c) == '.')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstruct message_date_parser_context {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen struct rfc822_parser_context parser;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen string_t *str;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen};
458acd7b39c84bae0d18c36ff9ddff9a49b4ae4aTimo Sirainen
78a5b3e697af5db96fe0dffed600b0d6370bb8e5Timo Sirainenstatic const char *month_names[] = {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen "Jan", "Feb", "Mar", "Apr", "May", "Jun",
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen};
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic const char *weekday_names[] = {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen};
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic int parse_timezone(const unsigned char *str, size_t len)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen{
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen int offset;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen char chr;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen if (len == 5 && (*str == '+' || *str == '-')) {
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen /* numeric offset */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (!i_isdigit(str[1]) || !i_isdigit(str[2]) ||
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen !i_isdigit(str[3]) || !i_isdigit(str[4]))
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return FALSE;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen offset = ((str[1]-'0') * 10 + (str[2]-'0')) * 60 +
89502bb187e8285b2a155559894ca80374ac3ae7Timo Sirainen (str[3]-'0') * 10 + (str[4]-'0');
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return *str == '+' ? offset : -offset;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (len == 1) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* military zone - handle them the correct way, not as
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen RFC822 says. RFC2822 though suggests that they'd be
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen considered as unspecified.. */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen chr = i_toupper(*str);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (chr < 'J')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return (*str-'A'+1) * 60;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (chr == 'J')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return 0;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (chr <= 'M')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return (*str-'A') * 60;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (chr < 'Z')
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return ('M'-*str) * 60;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return 0;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (len == 2 && i_toupper(str[0]) == 'U' && i_toupper(str[1]) == 'T') {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* UT - Universal Time */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen return 0;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen }
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (len == 3) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* GMT | [ECMP][DS]T */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (str[2] != 'T')
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen switch (i_toupper(*str)) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen case 'E':
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen offset = -5 * 60;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen break;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen case 'C':
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen offset = -6 * 60;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen break;
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen case 'M':
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen offset = -7 * 60;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen break;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen case 'P':
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen offset = -8 * 60;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen break;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen default:
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* GMT and others */
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen return 0;
ad5130b3afda4cf30e6272d96d818f84d3ae4e55Timo Sirainen }
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (i_toupper(str[1]) == 'D')
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return offset + 60;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (i_toupper(str[1]) == 'S')
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return offset;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen }
ad5130b3afda4cf30e6272d96d818f84d3ae4e55Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return 0;
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainenstatic int next_token(struct message_date_parser_context *ctx,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const unsigned char **value, size_t *value_len)
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen{
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen int ret;
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen str_truncate(ctx->str, 0);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = ctx->parser.data == ctx->parser.end ? 0 :
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen rfc822_parse_atom(&ctx->parser, ctx->str);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen *value = str_data(ctx->str);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen *value_len = str_len(ctx->str);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen return ret < 0 ? -1 : *value_len > 0;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen}
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenstatic bool
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenmessage_date_parser_tokens(struct message_date_parser_context *ctx,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen time_t *timestamp_r, int *timezone_offset_r)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct tm tm;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const unsigned char *value;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen size_t i, len;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen int ret;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* [weekday_name "," ] dd month_name [yy]yy hh:mi[:ss] timezone */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen memset(&tm, 0, sizeof(tm));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen rfc822_skip_lwsp(&ctx->parser);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* skip the optional weekday */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (next_token(ctx, &value, &len) <= 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (len == 3) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (*ctx->parser.data != ',')
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen ctx->parser.data++;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen rfc822_skip_lwsp(&ctx->parser);
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (next_token(ctx, &value, &len) <= 0)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen return FALSE;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen }
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen /* dd */
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen if (len < 1 || len > 2 || !i_isdigit(value[0]))
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen return FALSE;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen tm.tm_mday = value[0]-'0';
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen if (len == 2) {
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen if (!i_isdigit(value[1]))
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen return FALSE;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen tm.tm_mday = (tm.tm_mday * 10) + (value[1]-'0');
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen }
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* month name */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (next_token(ctx, &value, &len) <= 0 || len < 3)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen for (i = 0; i < 12; i++) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (i_memcasecmp(month_names[i], value, 3) == 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm.tm_mon = i;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen break;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (i == 12)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* [yy]yy */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (next_token(ctx, &value, &len) <= 0 || (len != 2 && len != 4))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen for (i = 0; i < len; i++) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (!i_isdigit(value[i]))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm.tm_year = tm.tm_year * 10 + (value[i]-'0');
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (len == 2) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* two digit year, assume 1970+ */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (tm.tm_year < 70)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm.tm_year += 100;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } else {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (tm.tm_year < 1900)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm.tm_year -= 1900;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen }
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* hh, allow also single digit */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (next_token(ctx, &value, &len) <= 0 ||
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen len < 1 || len > 2 || !i_isdigit(value[0]))
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return FALSE;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen tm.tm_hour = value[0]-'0';
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (len == 2) {
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (!i_isdigit(value[1]))
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return FALSE;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen tm.tm_hour = tm.tm_hour * 10 + (value[1]-'0');
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen }
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* :mm (may be the last token) */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen if (!IS_TIME_SEP(*ctx->parser.data))
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return FALSE;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ctx->parser.data++;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen rfc822_skip_lwsp(&ctx->parser);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (next_token(ctx, &value, &len) < 0 || len != 2 ||
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen !i_isdigit(value[0]) || !i_isdigit(value[1]))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen tm.tm_min = (value[0]-'0') * 10 + (value[1]-'0');
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* [:ss] */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (ctx->parser.data != ctx->parser.end &&
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen IS_TIME_SEP(*ctx->parser.data)) {
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen ctx->parser.data++;
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen rfc822_skip_lwsp(&ctx->parser);
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen if (next_token(ctx, &value, &len) <= 0 || len != 2 ||
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen !i_isdigit(value[0]) || !i_isdigit(value[1]))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm.tm_sec = (value[0]-'0') * 10 + (value[1]-'0');
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if ((ret = next_token(ctx, &value, &len)) < 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (ret == 0) {
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen /* missing timezone */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen *timezone_offset_r = 0;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } else {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* timezone. invalid timezones are treated as GMT, because
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen we may not know all the possible timezones that are used
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen and it's better to give at least a mostly correct reply.
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen FIXME: perhaps some different strict version of this
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen function would be useful? */
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen *timezone_offset_r = parse_timezone(value, len);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm.tm_isdst = -1;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen *timestamp_r = utc_mktime(&tm);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (*timestamp_r == (time_t)-1)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen *timestamp_r -= *timezone_offset_r * 60;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen return TRUE;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen}
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenbool message_date_parse(const unsigned char *data, size_t size,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen time_t *timestamp_r, int *timezone_offset_r)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen bool success;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen T_BEGIN {
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen struct message_date_parser_context ctx;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen rfc822_parser_init(&ctx.parser, data, size, NULL);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen ctx.str = t_str_new(128);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen success = message_date_parser_tokens(&ctx, timestamp_r,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen timezone_offset_r);
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen } T_END;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen return success;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenconst char *message_date_create(time_t timestamp)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen{
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct tm *tm;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen int offset;
98720d3b830e8ec762e9bdde94a71c0ef184595dTimo Sirainen bool negative;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen tm = localtime(&timestamp);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen offset = utc_offset(tm, timestamp);
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen if (offset >= 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen negative = FALSE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen else {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen negative = TRUE;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen offset = -offset;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen }
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen return t_strdup_printf("%s, %02d %s %04d %02d:%02d:%02d %c%02d%02d",
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen weekday_names[tm->tm_wday],
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm->tm_mday,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen month_names[tm->tm_mon],
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm->tm_year+1900,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen tm->tm_hour, tm->tm_min, tm->tm_sec,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen negative ? '-' : '+', offset / 60, offset % 60);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen}
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen