# HG changeset patch # User Timo Sirainen # Date 1204505686 -7200 # Node ID 06f59be7f508f9da438f33dafc37f2a8acdf25fc # Parent fa8e8bcc85a5de01387da3d8ab86d7afb466143c Moved mbox From_-line handling to lib-mail, since it's also used by deliver. diff -r fa8e8bcc85a5 -r 06f59be7f508 src/deliver/deliver.c --- a/src/deliver/deliver.c Mon Mar 03 02:38:55 2008 +0200 +++ b/src/deliver/deliver.c Mon Mar 03 02:54:46 2008 +0200 @@ -28,7 +28,7 @@ #include "auth-client.h" #include "mail-send.h" #include "duplicate.h" -#include "mbox/mbox-from.h" +#include "mbox-from.h" #include "../master/syslog-util.h" #include "../master/syslog-util.c" /* ugly, ugly.. */ #include "deliver.h" diff -r fa8e8bcc85a5 -r 06f59be7f508 src/lib-mail/Makefile.am --- a/src/lib-mail/Makefile.am Mon Mar 03 02:38:55 2008 +0200 +++ b/src/lib-mail/Makefile.am Mon Mar 03 02:54:46 2008 +0200 @@ -6,6 +6,7 @@ libmail_a_SOURCES = \ istream-header-filter.c \ + mbox-from.c \ message-address.c \ message-date.c \ message-decoder.c \ @@ -22,6 +23,7 @@ headers = \ istream-header-filter.h \ + mbox-from.h \ mail-types.h \ message-address.h \ message-date.h \ diff -r fa8e8bcc85a5 -r 06f59be7f508 src/lib-mail/mbox-from.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-mail/mbox-from.c Mon Mar 03 02:54:46 2008 +0200 @@ -0,0 +1,293 @@ +/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "utc-mktime.h" +#include "mbox-from.h" + +#include +#include + +static const char *weekdays[] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; + +static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static int mbox_parse_month(const unsigned char *msg, struct tm *tm) +{ + int i; + + for (i = 0; i < 12; i++) { + if (i_memcasecmp(months[i], msg, 3) == 0) { + tm->tm_mon = i; + break; + } + } + + if (i == 12 && memcmp(msg, "???", 3) == 0) { + /* just a hack to parse one special mbox I have :) */ + i = 0; + } + + if (i == 12 || msg[3] != ' ') + return -1; + return 0; +} + +static int mbox_parse_year(const unsigned char *msg, struct tm *tm) +{ + if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || + !i_isdigit(msg[2]) || !i_isdigit(msg[3])) + return -1; + + tm->tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 + + (msg[2]-'0') * 10 + (msg[3]-'0') - 1900; + return 0; +} + +int mbox_from_parse(const unsigned char *msg, size_t size, + time_t *time_r, char **sender_r) +{ + const unsigned char *msg_start, *sender_end, *msg_end; + struct tm tm; + int esc, alt_stamp, timezone = 0, seen_timezone = FALSE; + time_t t; + + *time_r = (time_t)-1; + *sender_r = NULL; + + /* */ + msg_start = msg; + msg_end = msg + size; + + /* get sender */ + if (msg < msg_end && *msg == '"') { + /* "x y z"@domain - skip the quoted part */ + esc = FALSE; + msg++; + while (msg < msg_end && (*msg != '"' || esc)) { + if (*msg == '\r' || *msg == '\n') + return -1; + esc = *msg == '\\'; + msg++; + } + msg++; + } + + while (msg < msg_end && *msg != ' ') { + if (*msg == '\r' || *msg == '\n') + return -1; + msg++; + } + sender_end = msg; + while (msg < msg_end && *msg == ' ') msg++; + + /* next 24 chars should be in the date in asctime() format, eg. + "Thu Nov 9 22:33:52 2001 +0300" + + - Some put the timezone before the year + - Some use a named timezone before or after year, which we ignore + - Some don't include seconds + */ + if (msg+24 > msg_end) + return -1; + + memset(&tm, 0, sizeof(tm)); + + /* skip weekday */ + msg += 4; + + /* month */ + if (mbox_parse_month(msg, &tm) < 0) { + /* Try alternate timestamp: "Thu, 9 Nov 2002 22:33:52" */ + alt_stamp = TRUE; + msg++; + + if (!i_isdigit(msg[0])) + return -1; + tm.tm_mday = msg[0]-'0'; + msg++; + + if (i_isdigit(msg[0])) { + tm.tm_mday = tm.tm_mday*10 + msg[0]-'0'; + msg++; + } + if (msg[0] != ' ') + return -1; + msg++; + + if (mbox_parse_month(msg, &tm) < 0) + return -1; + msg += 4; + + if (mbox_parse_year(msg, &tm) < 0) + return -1; + msg += 5; + } else { + alt_stamp = FALSE; + msg += 4; + + /* day. single digit is usually preceded by extra space */ + if (msg[0] == ' ') + msg++; + if (msg[1] == ' ') { + if (!i_isdigit(msg[0])) + return -1; + tm.tm_mday = msg[0]-'0'; + msg += 2; + } else { + if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ') + return -1; + tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0'); + msg += 3; + } + } + if (tm.tm_mday == 0) + tm.tm_mday = 1; + + /* hour */ + if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':') + return -1; + tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0'); + msg += 3; + + /* minute */ + if (!i_isdigit(msg[0]) || !i_isdigit(msg[1])) + return -1; + tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0'); + msg += 2; + + /* optional second */ + if (msg[0] == ':') { + msg++; + if (!i_isdigit(msg[0]) || !i_isdigit(msg[1])) + return -1; + tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0'); + msg += 2; + + if (msg[0] == ' ') + msg++; + else if (!alt_stamp) + return -1; + } else { + if (msg[0] != ' ') + return -1; + msg++; + } + + /* optional named timezone */ + if (alt_stamp) + ; + else if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || + !i_isdigit(msg[2]) || !i_isdigit(msg[3])) { + /* skip to next space */ + while (msg < msg_end && *msg != ' ') { + if (*msg == '\r' || *msg == '\n') + return -1; + msg++; + } + if (msg+5 > msg_end) + return -1; + msg++; + } else if ((msg[0] == '-' || msg[0] == '+') && + i_isdigit(msg[1]) && i_isdigit(msg[2]) && + i_isdigit(msg[3]) && i_isdigit(msg[4]) && msg[5] == ' ') { + /* numeric timezone, use it */ + seen_timezone = TRUE; + timezone = (msg[1]-'0') * 10*60*60 + (msg[2]-'0') * 60*60 + + (msg[3]-'0') * 10 + (msg[4]-'0'); + if (msg[0] == '-') timezone = -timezone; + msg += 6; + } + + if (!alt_stamp) { + /* year */ + if (mbox_parse_year(msg, &tm) < 0) + return -1; + msg += 4; + } + + tm.tm_isdst = -1; + if (!seen_timezone && + msg[0] == ' ' && (msg[1] == '-' || msg[1] == '+') && + i_isdigit(msg[2]) && i_isdigit(msg[3]) && + i_isdigit(msg[4]) && i_isdigit(msg[5])) { + seen_timezone = TRUE; + timezone = (msg[2]-'0') * 10*60*60 + (msg[3]-'0') * 60*60 + + (msg[4]-'0') * 10 + (msg[5]-'0'); + if (msg[1] == '-') timezone = -timezone; + } + + if (seen_timezone) { + t = utc_mktime(&tm); + if (t == (time_t)-1) + return -1; + + t -= timezone; + *time_r = t; + } else { + /* assume local timezone */ + *time_r = mktime(&tm); + } + + *sender_r = i_strdup_until(msg_start, sender_end); + return 0; +} + +const char *mbox_from_create(const char *sender, time_t time) +{ + string_t *str; + struct tm *tm; + int year; + + str = t_str_new(256); + str_append(str, "From "); + str_append(str, sender); + str_append(str, " "); + + /* we could use simply asctime(), but i18n etc. may break it. + Example: "Thu Nov 29 22:33:52 2001" */ + tm = localtime(&time); + + /* week day */ + str_append(str, weekdays[tm->tm_wday]); + str_append_c(str, ' '); + + /* month */ + str_append(str, months[tm->tm_mon]); + str_append_c(str, ' '); + + /* day */ + str_append_c(str, (tm->tm_mday / 10) + '0'); + str_append_c(str, (tm->tm_mday % 10) + '0'); + str_append_c(str, ' '); + + /* hour */ + str_append_c(str, (tm->tm_hour / 10) + '0'); + str_append_c(str, (tm->tm_hour % 10) + '0'); + str_append_c(str, ':'); + + /* minute */ + str_append_c(str, (tm->tm_min / 10) + '0'); + str_append_c(str, (tm->tm_min % 10) + '0'); + str_append_c(str, ':'); + + /* second */ + str_append_c(str, (tm->tm_sec / 10) + '0'); + str_append_c(str, (tm->tm_sec % 10) + '0'); + str_append_c(str, ' '); + + /* year */ + year = tm->tm_year + 1900; + str_append_c(str, (year / 1000) + '0'); + str_append_c(str, ((year / 100) % 10) + '0'); + str_append_c(str, ((year / 10) % 10) + '0'); + str_append_c(str, (year % 10) + '0'); + + str_append_c(str, '\n'); + return str_c(str); +} diff -r fa8e8bcc85a5 -r 06f59be7f508 src/lib-mail/mbox-from.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib-mail/mbox-from.h Mon Mar 03 02:54:46 2008 +0200 @@ -0,0 +1,12 @@ +#ifndef MBOX_FROM_H +#define MBOX_FROM_H + +/* Parse time and sender from mbox-compatible From_-line. msg points to the + data after "From ". */ +int mbox_from_parse(const unsigned char *msg, size_t size, + time_t *time_r, char **sender_r); +/* Return a mbox-compatible From_-line using given sender and time. + The returned string begins with "From ". */ +const char *mbox_from_create(const char *sender, time_t time); + +#endif diff -r fa8e8bcc85a5 -r 06f59be7f508 src/lib-storage/index/mbox/Makefile.am --- a/src/lib-storage/index/mbox/Makefile.am Mon Mar 03 02:38:55 2008 +0200 +++ b/src/lib-storage/index/mbox/Makefile.am Mon Mar 03 02:54:46 2008 +0200 @@ -11,7 +11,6 @@ libstorage_mbox_a_SOURCES = \ istream-raw-mbox.c \ mbox-file.c \ - mbox-from.c \ mbox-lock.c \ mbox-mail.c \ mbox-md5.c \ @@ -26,7 +25,6 @@ headers = \ istream-raw-mbox.h \ mbox-file.h \ - mbox-from.h \ mbox-lock.h \ mbox-md5.h \ mbox-storage.h \ diff -r fa8e8bcc85a5 -r 06f59be7f508 src/lib-storage/index/mbox/mbox-from.c --- a/src/lib-storage/index/mbox/mbox-from.c Mon Mar 03 02:38:55 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,293 +0,0 @@ -/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "str.h" -#include "utc-mktime.h" -#include "mbox-from.h" - -#include -#include - -static const char *weekdays[] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" -}; - -static const char *months[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" -}; - -static int mbox_parse_month(const unsigned char *msg, struct tm *tm) -{ - int i; - - for (i = 0; i < 12; i++) { - if (i_memcasecmp(months[i], msg, 3) == 0) { - tm->tm_mon = i; - break; - } - } - - if (i == 12 && memcmp(msg, "???", 3) == 0) { - /* just a hack to parse one special mbox I have :) */ - i = 0; - } - - if (i == 12 || msg[3] != ' ') - return -1; - return 0; -} - -static int mbox_parse_year(const unsigned char *msg, struct tm *tm) -{ - if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || - !i_isdigit(msg[2]) || !i_isdigit(msg[3])) - return -1; - - tm->tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 + - (msg[2]-'0') * 10 + (msg[3]-'0') - 1900; - return 0; -} - -int mbox_from_parse(const unsigned char *msg, size_t size, - time_t *time_r, char **sender_r) -{ - const unsigned char *msg_start, *sender_end, *msg_end; - struct tm tm; - int esc, alt_stamp, timezone = 0, seen_timezone = FALSE; - time_t t; - - *time_r = (time_t)-1; - *sender_r = NULL; - - /* */ - msg_start = msg; - msg_end = msg + size; - - /* get sender */ - if (msg < msg_end && *msg == '"') { - /* "x y z"@domain - skip the quoted part */ - esc = FALSE; - msg++; - while (msg < msg_end && (*msg != '"' || esc)) { - if (*msg == '\r' || *msg == '\n') - return -1; - esc = *msg == '\\'; - msg++; - } - msg++; - } - - while (msg < msg_end && *msg != ' ') { - if (*msg == '\r' || *msg == '\n') - return -1; - msg++; - } - sender_end = msg; - while (msg < msg_end && *msg == ' ') msg++; - - /* next 24 chars should be in the date in asctime() format, eg. - "Thu Nov 9 22:33:52 2001 +0300" - - - Some put the timezone before the year - - Some use a named timezone before or after year, which we ignore - - Some don't include seconds - */ - if (msg+24 > msg_end) - return -1; - - memset(&tm, 0, sizeof(tm)); - - /* skip weekday */ - msg += 4; - - /* month */ - if (mbox_parse_month(msg, &tm) < 0) { - /* Try alternate timestamp: "Thu, 9 Nov 2002 22:33:52" */ - alt_stamp = TRUE; - msg++; - - if (!i_isdigit(msg[0])) - return -1; - tm.tm_mday = msg[0]-'0'; - msg++; - - if (i_isdigit(msg[0])) { - tm.tm_mday = tm.tm_mday*10 + msg[0]-'0'; - msg++; - } - if (msg[0] != ' ') - return -1; - msg++; - - if (mbox_parse_month(msg, &tm) < 0) - return -1; - msg += 4; - - if (mbox_parse_year(msg, &tm) < 0) - return -1; - msg += 5; - } else { - alt_stamp = FALSE; - msg += 4; - - /* day. single digit is usually preceded by extra space */ - if (msg[0] == ' ') - msg++; - if (msg[1] == ' ') { - if (!i_isdigit(msg[0])) - return -1; - tm.tm_mday = msg[0]-'0'; - msg += 2; - } else { - if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ') - return -1; - tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0'); - msg += 3; - } - } - if (tm.tm_mday == 0) - tm.tm_mday = 1; - - /* hour */ - if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':') - return -1; - tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0'); - msg += 3; - - /* minute */ - if (!i_isdigit(msg[0]) || !i_isdigit(msg[1])) - return -1; - tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0'); - msg += 2; - - /* optional second */ - if (msg[0] == ':') { - msg++; - if (!i_isdigit(msg[0]) || !i_isdigit(msg[1])) - return -1; - tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0'); - msg += 2; - - if (msg[0] == ' ') - msg++; - else if (!alt_stamp) - return -1; - } else { - if (msg[0] != ' ') - return -1; - msg++; - } - - /* optional named timezone */ - if (alt_stamp) - ; - else if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || - !i_isdigit(msg[2]) || !i_isdigit(msg[3])) { - /* skip to next space */ - while (msg < msg_end && *msg != ' ') { - if (*msg == '\r' || *msg == '\n') - return -1; - msg++; - } - if (msg+5 > msg_end) - return -1; - msg++; - } else if ((msg[0] == '-' || msg[0] == '+') && - i_isdigit(msg[1]) && i_isdigit(msg[2]) && - i_isdigit(msg[3]) && i_isdigit(msg[4]) && msg[5] == ' ') { - /* numeric timezone, use it */ - seen_timezone = TRUE; - timezone = (msg[1]-'0') * 10*60*60 + (msg[2]-'0') * 60*60 + - (msg[3]-'0') * 10 + (msg[4]-'0'); - if (msg[0] == '-') timezone = -timezone; - msg += 6; - } - - if (!alt_stamp) { - /* year */ - if (mbox_parse_year(msg, &tm) < 0) - return -1; - msg += 4; - } - - tm.tm_isdst = -1; - if (!seen_timezone && - msg[0] == ' ' && (msg[1] == '-' || msg[1] == '+') && - i_isdigit(msg[2]) && i_isdigit(msg[3]) && - i_isdigit(msg[4]) && i_isdigit(msg[5])) { - seen_timezone = TRUE; - timezone = (msg[2]-'0') * 10*60*60 + (msg[3]-'0') * 60*60 + - (msg[4]-'0') * 10 + (msg[5]-'0'); - if (msg[1] == '-') timezone = -timezone; - } - - if (seen_timezone) { - t = utc_mktime(&tm); - if (t == (time_t)-1) - return -1; - - t -= timezone; - *time_r = t; - } else { - /* assume local timezone */ - *time_r = mktime(&tm); - } - - *sender_r = i_strdup_until(msg_start, sender_end); - return 0; -} - -const char *mbox_from_create(const char *sender, time_t time) -{ - string_t *str; - struct tm *tm; - int year; - - str = t_str_new(256); - str_append(str, "From "); - str_append(str, sender); - str_append(str, " "); - - /* we could use simply asctime(), but i18n etc. may break it. - Example: "Thu Nov 29 22:33:52 2001" */ - tm = localtime(&time); - - /* week day */ - str_append(str, weekdays[tm->tm_wday]); - str_append_c(str, ' '); - - /* month */ - str_append(str, months[tm->tm_mon]); - str_append_c(str, ' '); - - /* day */ - str_append_c(str, (tm->tm_mday / 10) + '0'); - str_append_c(str, (tm->tm_mday % 10) + '0'); - str_append_c(str, ' '); - - /* hour */ - str_append_c(str, (tm->tm_hour / 10) + '0'); - str_append_c(str, (tm->tm_hour % 10) + '0'); - str_append_c(str, ':'); - - /* minute */ - str_append_c(str, (tm->tm_min / 10) + '0'); - str_append_c(str, (tm->tm_min % 10) + '0'); - str_append_c(str, ':'); - - /* second */ - str_append_c(str, (tm->tm_sec / 10) + '0'); - str_append_c(str, (tm->tm_sec % 10) + '0'); - str_append_c(str, ' '); - - /* year */ - year = tm->tm_year + 1900; - str_append_c(str, (year / 1000) + '0'); - str_append_c(str, ((year / 100) % 10) + '0'); - str_append_c(str, ((year / 10) % 10) + '0'); - str_append_c(str, (year % 10) + '0'); - - str_append_c(str, '\n'); - return str_c(str); -} diff -r fa8e8bcc85a5 -r 06f59be7f508 src/lib-storage/index/mbox/mbox-from.h --- a/src/lib-storage/index/mbox/mbox-from.h Mon Mar 03 02:38:55 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,8 +0,0 @@ -#ifndef MBOX_FROM_H -#define MBOX_FROM_H - -int mbox_from_parse(const unsigned char *msg, size_t size, - time_t *time_r, char **sender_r); -const char *mbox_from_create(const char *sender, time_t time); - -#endif