Commit 5e5b68fd 5e5b68fd028495f7076a576df26962bbdf51ac63 by Sergey Poznyakoff

imap4d: fix returned INTERNALDATE and date searches.

INTERNALDATE now includes a meaningful timezone information (it
used to return +0000).

Date searches disregard the time and timezone of the INTERNALDATE
or Date: header, as mandated by RFC 3501.

* libmailutils/base/date.c (mu_parse_ctime_date_time): In the absence
of TZ in ctime strings, return local time zone.

* imap4d/io.c (imap4d_tokbuf_getline): Kill trailing whitespace.

* imap4d/util.c (adjust_tm): New function.
(util_parse_internal_date)
(util_parse_822_date)
(util_parse_ctime_date): Take three arguments, the third one controlling
what information to return. All uses updated.
* imap4d/fetch.c (_frt_internaldate): Return meaningful timezone.
If all else fails, use local TZ.
* imap4d/imap4d.h (datetime_parse_mode): New enum.
(util_parse_internal_date)
(util_parse_822_date)
(util_parse_ctime_date): Change signature.
* imap4d/search.c (parse_simple_key)
(_header_date,cond_before,cond_on,cond_since): Use datetime_date_only mode.

* testsuite/spool/search.mbox: New file.
* testsuite/spool/DISTFILES: Add search.mbox
* imap4d/testsuite/lib/imap4d.exp (imap4d_start): New option -mbox.
* imap4d/testsuite/imap4d/search.exp: Rewrite.

* imap4d/testsuite/imap4d/create.exp: Account for TZ part in internaldate
strings, which may vary.
* imap4d/testsuite/imap4d/fetch.exp: Likewise.
* imap4d/testsuite/imap4d/list.exp: List the new mailbox.
1 parent e759db27
......@@ -79,7 +79,7 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
message is set to the current date and time by default. */
if (date_time)
{
if (util_parse_internal_date (date_time, &t))
if (util_parse_internal_date (date_time, &t, datetime_default))
{
*err_text = "Invalid date/time format";
return 1;
......
......@@ -862,19 +862,34 @@ _frt_internaldate (struct fetch_function_closure *ffc,
struct tm tm, *tmp = NULL;
mu_timezone tz;
char datebuf[sizeof ("13-Jul-2002 00:00:00")];
int tzoff;
int tzh = 0, tzm = 0;
mu_message_get_envelope (frt->msg, &env);
if (mu_envelope_sget_date (env, &date) == 0
&& mu_parse_ctime_date_time (&date, &tm, &tz) == 0)
{
tmp = &tm;
tzoff = tz.utc_offset;
}
else
{
time_t t = time (NULL);
time_t t;
struct timeval stv;
struct timezone stz;
gettimeofday(&stv, &stz);
t = stv.tv_sec;
tzoff = - stz.tz_minuteswest;
tmp = localtime (&t);
}
tzh = tzoff / 3600;
if (tzoff < 0)
tzoff = - tzoff;
tzm = tzoff % 3600;
mu_strftime (datebuf, sizeof (datebuf), "%d-%b-%Y %H:%M:%S", tmp);
io_sendf ("%s", ffc->name);
io_sendf (" \"%s +0000\"", datebuf);
io_sendf (" \"%s %+03d%02d\"", datebuf, tzh, tzm);
return 0;
}
......
......@@ -367,9 +367,20 @@ extern char *util_getfullpath (const char *, const char *);
extern int util_msgset (char *, size_t **, int *, int);
extern struct imap4d_command *util_getcommand (char *,
struct imap4d_command []);
extern int util_parse_internal_date (char *date, time_t *timep);
extern int util_parse_822_date (const char *date, time_t *timep);
extern int util_parse_ctime_date (const char *date, time_t *timep);
enum datetime_parse_mode /* how to parse date/time strings */
{
datetime_default, /* default mode */
datetime_date_only, /* return only date part, ignore time and TZ */
datetime_time_only /* return only time and TZ, ignore date */
};
extern int util_parse_internal_date (char *date, time_t *timep,
enum datetime_parse_mode flag);
extern int util_parse_822_date (const char *date, time_t *timep,
enum datetime_parse_mode flag);
extern int util_parse_ctime_date (const char *date, time_t *timep,
enum datetime_parse_mode flag);
extern char *util_strcasestr (const char *haystack, const char *needle);
extern char *util_localname (void);
......
......@@ -548,6 +548,8 @@ imap4d_tokbuf_getline (struct imap4d_tokbuf *tok)
tok->buffer[--tok->level] = 0;
if (tok->buffer[tok->level - 1] == '\r')
tok->buffer[--tok->level] = 0;
while (tok->level > 0 && mu_isblank (tok->buffer[tok->level-1]))
tok->buffer[--tok->level] = 0;
return level;
}
......
......@@ -670,7 +670,8 @@ parse_simple_key (struct parsebuf *pb)
break;
case 'd': /* date */
if (util_parse_internal_date (pb->token, &time))
if (util_parse_internal_date (pb->token, &time,
datetime_date_only))
{
pb->err_mesg = "Bad date format";
return NULL;
......@@ -801,7 +802,7 @@ _header_date (struct parsebuf *pb, time_t *timep)
mu_message_get_header (pb->msg, &header);
if (mu_header_sget_value (header, "Date", &hval) == 0
&& util_parse_822_date (hval, timep))
&& util_parse_822_date (hval, timep, datetime_date_only))
return 0;
return 1;
}
......@@ -893,7 +894,7 @@ cond_before (struct parsebuf *pb, struct search_node *node, struct value *arg,
retval->v.number = 0;
else
{
util_parse_ctime_date (date, &mesg_time);
util_parse_ctime_date (date, &mesg_time, datetime_date_only);
retval->v.number = mesg_time < t;
}
}
......@@ -980,7 +981,7 @@ cond_on (struct parsebuf *pb, struct search_node *node, struct value *arg,
retval->v.number = 0;
else
{
util_parse_ctime_date (date, &mesg_time);
util_parse_ctime_date (date, &mesg_time, datetime_date_only);
retval->v.number = t <= mesg_time && mesg_time <= t + 86400;
}
}
......@@ -1038,7 +1039,7 @@ cond_since (struct parsebuf *pb, struct search_node *node, struct value *arg,
retval->v.number = 0;
else
{
util_parse_ctime_date (date, &mesg_time);
util_parse_ctime_date (date, &mesg_time, datetime_date_only);
retval->v.number = mesg_time >= t;
}
}
......
......@@ -63,7 +63,7 @@ imap4d_test "SELECT en/to/tre"\
"OK \[READ-WRITE\] SELECT Completed"
imap4d_test "FETCH 1 ALL"\
"1 FETCH (FLAGS (\\Recent) INTERNALDATE \"25-Aug-2002 16:00:00 +0000\" RFC822.SIZE 285 ENVELOPE (\"Mon, 7 Feb 1994 21:52:25 -0800 (PST)\" \"afternoon meeting again\" ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\")) ((NIL NIL \"mooch\" \"owatagu.siam.edu\")) NIL NIL NIL \"<B27397-0200000@Blurdybloop.COM>\"))"\
-re {1 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"25-Aug-2002 16:00:00 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 285 ENVELOPE \(\"Mon, 7 Feb 1994 21:52:25 -0800 \(PST\)\" \"afternoon meeting again\" \(\(\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\"\)\) \(\(\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\"\)\) \(\(\"Fred Foobar\" NIL \"foobar\" \"Blurdybloop.COM\"\)\) \(\(NIL NIL \"mooch\" \"owatagu.siam.edu\"\)\) NIL NIL NIL \"<B27397-0200000@Blurdybloop.COM>\"\)\)}\
"OK"
......
......@@ -47,7 +47,7 @@ imap4d_test "FETCH 3 (FLAGS)"\
# INTERNALDATE The internal date of the message.
imap4d_test "FETCH 3 INTERNALDATE"\
"3 FETCH (INTERNALDATE \"13-Jul-2002 00:43:18 +0000\")"\
-re {3 FETCH \(INTERNALDATE \"13-Jul-2002 00:43:18 [+-][0-9][0-9][0-9][0-9]\"\)} \
"OK"
# UID The unique identifier for the message.
......@@ -56,7 +56,7 @@ imap4d_test "FETCH 3 UID"\
"OK"
imap4d_test "FETCH 3 (FLAGS INTERNALDATE UID)"\
"3 FETCH (FLAGS (\\Recent) INTERNALDATE \"13-Jul-2002 00:43:18 +0000\" UID 3)"\
-re {3 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"13-Jul-2002 00:43:18 [+-][0-9][0-9][0-9][0-9]\" UID 3\)}\
"OK"
# ENVELOPE The envelope structure of the message. This is
......@@ -76,11 +76,11 @@ imap4d_test "FETCH 1:* ENVELOPE"\
# RFC822.SIZE ENVELOPE)
imap4d_test "FETCH 1:\* ALL"\
"1 FETCH (FLAGS (\\Recent) INTERNALDATE \"28-Dec-2001 22:18:09 +0000\" RFC822.SIZE 1298 ENVELOPE (\"Fri, 28 Dec 2001 22:18:08 +0200\" \"Jabberwocky\" ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) ((\"Bar\" NIL \"bar\" \"dontmailme.org\")) NIL NIL NIL \"<200112282018.fBSKI8N04906@nonexistent.net>\"))"\
"2 FETCH (FLAGS (\\Recent) INTERNALDATE \"28-Dec-2001 23:28:09 +0000\" RFC822.SIZE 547 ENVELOPE (\"Fri, 28 Dec 2001 23:28:08 +0200\" \"Re: Jabberwocky\" ((\"Bar\" NIL \"bar\" \"dontmailme.org\")) ((\"Bar\" NIL \"bar\" \"dontmailme.org\")) ((\"Bar\" NIL \"bar\" \"dontmailme.org\")) ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) NIL NIL NIL \"<200112232808.fERKR9N16790@dontmailme.org>\"))"\
"3 FETCH (FLAGS (\\Recent) INTERNALDATE \"13-Jul-2002 00:43:18 +0000\" RFC822.SIZE 1611 ENVELOPE (\"Sat, 13 Jul 2002 00:43:18 +0300\" \"Simple MIME\" ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) NIL NIL NIL \"<200207122143.g6CLhIb05086@example.net>\"))"\
"4 FETCH (FLAGS (\\Recent) INTERNALDATE \"13-Jul-2002 00:50:58 +0000\" RFC822.SIZE 3483 ENVELOPE (\"Sat, 13 Jul 2002 00:50:58 +0300\" \"Nested MIME\" ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) NIL NIL NIL \"<200207122150.g6CLowb05126@example.net>\"))"\
"5 FETCH (FLAGS (\\Recent) INTERNALDATE \"13-Jul-2002 00:43:18 +0000\" RFC822.SIZE 884 ENVELOPE (\"Sat, 13 Jul 2002 00:43:18 +0300\" \"Empty MIME Parts\" ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) NIL NIL NIL \"<200207122143.g6CLhIb05086@example.net>\"))"\
-re {1 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"28-Dec-2001 22:18:09 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 1298 ENVELOPE \(\"Fri, 28 Dec 2001 22:18:08 \+0200\" \"Jabberwocky\" \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) \(\(\"Bar\" NIL \"bar\" \"dontmailme.org\"\)\) NIL NIL NIL \"<200112282018.fBSKI8N04906@nonexistent.net>\"\)\)}\
-re {2 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"28-Dec-2001 23:28:09 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 547 ENVELOPE \(\"Fri, 28 Dec 2001 23:28:08 \+0200\" \"Re: Jabberwocky\" \(\(\"Bar\" NIL \"bar\" \"dontmailme.org\"\)\) \(\(\"Bar\" NIL \"bar\" \"dontmailme.org\"\)\) \(\(\"Bar\" NIL \"bar\" \"dontmailme.org\"\)\) \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) NIL NIL NIL \"<200112232808.fERKR9N16790@dontmailme.org>\"\)\)}\
-re {3 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"13-Jul-2002 00:43:18 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 1611 ENVELOPE \(\"Sat, 13 Jul 2002 00:43:18 \+0300\" \"Simple MIME\" \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) NIL NIL NIL \"<200207122143.g6CLhIb05086@example.net>\"\)\)}\
-re {4 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"13-Jul-2002 00:50:58 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 3483 ENVELOPE \(\"Sat, 13 Jul 2002 00:50:58 \+0300\" \"Nested MIME\" \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) NIL NIL NIL \"<200207122150.g6CLowb05126@example.net>\"\)\)}\
-re {5 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"13-Jul-2002 00:43:18 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 884 ENVELOPE \(\"Sat, 13 Jul 2002 00:43:18 \+0300\" \"Empty MIME Parts\" \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) NIL NIL NIL \"<200207122143.g6CLhIb05086@example.net>\"\)\)}\
"OK"
# BODYSTRUCTURE The [MIME-IMB] body structure of the message. This
......@@ -508,14 +508,14 @@ imap4d_test "FETCH 2 RFC822.TEXT"\
# RFC822.SIZE)
imap4d_test "FETCH 1 FAST" \
"1 FETCH (FLAGS (\\Seen \\Recent) INTERNALDATE \"28-Dec-2001 22:18:09 +0000\" RFC822.SIZE 1298)"\
-re {1 FETCH \(FLAGS \(\\Seen \\Recent\) INTERNALDATE \"28-Dec-2001 22:18:09 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 1298\)}\
"OK"
# FULL Macro equivalent to: (FLAGS INTERNALDATE
# RFC822.SIZE ENVELOPE BODY)
imap4d_test "FETCH 4 FULL"\
"4 FETCH (FLAGS (\\Recent) INTERNALDATE \"13-Jul-2002 00:50:58 +0000\" RFC822.SIZE 3483 ENVELOPE (\"Sat, 13 Jul 2002 00:50:58 +0300\" \"Nested MIME\" ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\")) ((\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\")) NIL NIL NIL \"<200207122150.g6CLowb05126@example.net>\") BODY ((\"text\" \"plain\" (\"name\" \"msg.21\" \"charset\" \"us-ascii\") \"<5122.1026510654.2@example.net>\" \"Father William Part I\" \"7BIT\" 351 10)((\"application\" \"octet-stream\" (\"name\" \"msg.22\") \"<5122.1026510654.4@example.net>\" \"Father William Part II\" \"base64\" 486)((\"application\" \"octet-stream\" (\"name\" \"msg.23\") \"<5122.1026510654.6@example.net>\" \"Father William Part III\" \"base64\" 490)(\"application\" \"octet-stream\" (\"name\" \"msg.24\") \"<5122.1026510654.7@example.net>\" \"Father William Part IV\" \"base64\" 502) \"mixed\" NIL NIL NIL) \"mixed\" NIL NIL NIL) \"mixed\" NIL NIL NIL))"\
-re {4 FETCH \(FLAGS \(\\Recent\) INTERNALDATE \"13-Jul-2002 00:50:58 [+-][0-9][0-9][0-9][0-9]\" RFC822.SIZE 3483 ENVELOPE \(\"Sat, 13 Jul 2002 00:50:58 \+0300\" \"Nested MIME\" \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Sergey Poznyakoff\" NIL \"gray\" \"example.net\"\)\) \(\(\"Foo Bar\" NIL \"foobar\" \"nonexistent.net\"\)\) NIL NIL NIL \"<200207122150.g6CLowb05126@example.net>\"\) BODY \(\(\"text\" \"plain\" \(\"name\" \"msg.21\" \"charset\" \"us-ascii\"\) \"<5122.1026510654.2@example.net>\" \"Father William Part I\" \"7BIT\" 351 10\)\(\(\"application\" \"octet-stream\" \(\"name\" \"msg.22\"\) \"<5122.1026510654.4@example.net>\" \"Father William Part II\" \"base64\" 486\)\(\(\"application\" \"octet-stream\" \(\"name\" \"msg.23\"\) \"<5122.1026510654.6@example.net>\" \"Father William Part III\" \"base64\" 490\)\(\"application\" \"octet-stream\" \(\"name\" \"msg.24\"\) \"<5122.1026510654.7@example.net>\" \"Father William Part IV\" \"base64\" 502\) \"mixed\" NIL NIL NIL\) \"mixed\" NIL NIL NIL\) \"mixed\" NIL NIL NIL\)\)}\
"OK"
imap4d_stop
......
......@@ -22,6 +22,7 @@ imap4d_auth "user!passwd" "guessme"
imap4d_test -sort "LIST \"~\" \"*\""\
"LIST (\\NoInferiors) \"/\" ~/mbox1"\
"LIST (\\NoInferiors) \"/\" ~/mbox"\
"LIST (\\NoInferiors) \"/\" ~/search.mbox"\
"LIST (\\NoInferiors) \"/\" ~/sieve.mbox"\
"LIST (\\NoInferiors) \"/\" ~/teaparty.mbox"\
"LIST (\\NoInferiors) \"/\" ~/bigto.mbox"\
......@@ -31,6 +32,7 @@ imap4d_test -sort "LIST \"~\" \"*\""\
imap4d_test -sort "LIST \"~\" \"%\""\
"LIST (\\NoInferiors) \"/\" ~/mbox1"\
"LIST (\\NoInferiors) \"/\" ~/mbox"\
"LIST (\\NoInferiors) \"/\" ~/search.mbox"\
"LIST (\\NoInferiors) \"/\" ~/sieve.mbox"\
"LIST (\\NoInferiors) \"/\" ~/teaparty.mbox"\
"LIST (\\NoInferiors) \"/\" ~/bigto.mbox"\
......@@ -41,6 +43,7 @@ imap4d_test -sort "LIST \"\" \"*\""\
"LIST (\\NoInferiors) NIL INBOX"\
"LIST (\\NoInferiors) \"/\" mbox1"\
"LIST (\\NoInferiors) \"/\" mbox"\
"LIST (\\NoInferiors) \"/\" search.mbox"\
"LIST (\\NoInferiors) \"/\" sieve.mbox"\
"LIST (\\NoInferiors) \"/\" teaparty.mbox"\
"LIST (\\NoInferiors) \"/\" bigto.mbox"\
......@@ -60,6 +63,7 @@ imap4d_test -sort "LIST \"$MU_DATA_DIR\" \"*\""\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/relational.mbox" \
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/mbox1"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/mbox"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/search.mbox"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/sieve.mbox"\
"LIST (\\NoInferiors) \"/\" $MU_DATA_DIR/spool/teaparty.mbox"\
"LIST (\\NoSelect) \"/\" $MU_DATA_DIR/folder"\
......
......@@ -30,15 +30,15 @@
# contains a listing of message sequence numbers corresponding to
# those messages that match the searching criteria.
imap4d_start
imap4d_start -mbox "search.mbox"
imap4d_auth "user!passwd" "guessme"
imap4d_test "SELECT INBOX"\
"95 EXISTS"\
"95 RECENT"\
"8 EXISTS"\
"5 RECENT"\
-re {OK \[UIDVALIDITY [0-9]+\] UID valididy status}\
"OK \[UIDNEXT 96\] Predicted next uid"\
"OK \[UNSEEN 1\] first unseen messsage "\
"OK \[UIDNEXT 9\] Predicted next uid"\
"OK \[UNSEEN 4\] first unseen messsage "\
"FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)"\
"OK \[PERMANENTFLAGS (\\Answered \\Deleted \\Seen)\] Permanent flags"\
"OK \[READ-WRITE\] SELECT Completed"
......@@ -48,14 +48,14 @@ imap4d_test "SELECT INBOX"\
# number set
imap4d_test "SEARCH 1:*" \
"SEARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95" \
"SEARCH 1 2 3 4 5 6 7 8" \
"OK"
# ALL All messages in the mailbox; the default initial
# key for ANDing.
imap4d_test "SEARCH ALL" \
"SEARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95" \
"SEARCH 1 2 3 4 5 6 7 8" \
"OK"
# NEW Messages that have the \Recent flag set but not the
......@@ -64,39 +64,39 @@ imap4d_test "SEARCH ALL" \
# All messages are still new
imap4d_test "SEARCH NEW" \
"SEARCH 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95" \
"SEARCH 4 5 6 7 8" \
"OK"
# FROM <string> Messages that contain the specified string in the
# envelope structure's FROM field.
imap4d_test "SEARCH FROM alice" \
"SEARCH 2 4 6 8 10 12 14 20 25 27 29 33 36 38 40 43 45 47 51 53 55 57 59 63 66 68 70 72 74 76 78 80 82 85 87 90 93 95" \
imap4d_test "SEARCH FROM corrector" \
"SEARCH 2 4 8" \
"OK"
imap4d_test "SEARCH FROM hare" \
"SEARCH 1 3 5 7 9 11 13 16 22 24 35 42 58 62 71" \
imap4d_test "SEARCH FROM lexi@example.net" \
"SEARCH 1 3 5 6 7" \
"OK"
# LARGER <n> Messages with an [RFC-822] size larger than the
# specified number of octets.
imap4d_test "SEARCH LARGER 512" \
"SEARCH 41 46" \
"SEARCH 3 4" \
"OK"
# SMALLER <n> Messages with an [RFC-822] size smaller than the
# specified number of octets.
imap4d_test "SEARCH SMALLER 300" \
"SEARCH 12 20 35" \
imap4d_test "SEARCH SMALLER 400" \
"SEARCH 7 8" \
"OK"
# SUBJECT <string> Messages that contain the specified string in the
# envelope structure's SUBJECT field.
imap4d_test "SEARCH SUBJECT \"watch\"" \
"SEARCH 19 20 21 22 23 24 25 26 27 28 29"\
imap4d_test "SEARCH SUBJECT \"Alliance\"" \
"SEARCH 6"\
"OK"
# HEADER <field-name> <string>
......@@ -105,75 +105,65 @@ imap4d_test "SEARCH SUBJECT \"watch\"" \
# contains the specified string in the [RFC-822]
# field-body.
imap4d_test "SEARCH HEADER Message-Id \"<200207292200.3303@wonder.land>\"" \
imap4d_test "SEARCH HEADER Message-Id \"<200207291200.3303@example.org>\"" \
"SEARCH 3" \
"OK"
# CC <string> Messages that contain the specified string in the
# envelope structure's CC field.
imap4d_test "SEARCH CC dormouse" \
"SEARCH 60" \
imap4d_test "SEARCH CC Corrector" \
"SEARCH 6" \
"OK"
# TO <string> Messages that contain the specified string in the
# envelope structure's TO field.
imap4d_test "SEARCH TO hare"\
"SEARCH 2 4 6 8 10 12 14 21 23 42 59 72" \
imap4d_test "SEARCH TO editor+recheck"\
"SEARCH 7" \
"OK"
# SENTBEFORE <date>
# Messages whose [RFC-822] Date: header is earlier
# than the specified date.
imap4d_test "SEARCH SENTBEFORE \"29-Jul-2002 22:00:02 +0100\"" \
"SEARCH 1"\
imap4d_test "SEARCH SENTBEFORE \"30-Jul-2002\"" \
"SEARCH 1 2"\
"OK"
# SENTSINCE <date>
# Messages whose [RFC-822] Date: header is within or
# later than the specified date.
imap4d_test "SEARCH SENTSINCE \"29-Jul-2002 22:01:32 +0100\""\
"SEARCH 92 93 94 95"\
"OK"
imap4d_test "SEARCH SENTSINCE \"29-Jul-2002 23:01:32 +0200\""\
"SEARCH 92 93 94 95"\
imap4d_test "SEARCH SENTSINCE \"31-Jul-2002\""\
"SEARCH 5 6 7 8"\
"OK"
# BEFORE <date> Messages whose internal date is earlier than the
# specified date.
imap4d_test "SEARCH BEFORE \"29-Jul-2002 22:00:09 +0000\""\
imap4d_test "SEARCH BEFORE \"30-Jul-2002\""\
"SEARCH 1"\
"OK"
# SINCE <date> Messages whose internal date is within or later
# than the specified date.
imap4d_test "SEARCH SINCE \"29-Jul-2002 22:01:36 +0000\""\
"SEARCH 89 90 91 92 93 94 95"\
"OK"
imap4d_test "STORE 3,5,89 +FLAGS (\\Answered)"\
"3 FETCH (FLAGS (\\Answered \\Recent))"\
"5 FETCH (FLAGS (\\Answered \\Recent))"\
"89 FETCH (FLAGS (\\Answered \\Recent))"\
imap4d_test "SEARCH SINCE \"30-Jul-2002\""\
"SEARCH 2 3 4 5 6 7 8"\
"OK"
# ANSWERED Messages with the \Answered flag set.
imap4d_test "SEARCH ANSWERED"\
"SEARCH 3 5 89"\
"SEARCH 2 3"\
"OK"
# TEXT <string> Messages that contain the specified string in the
# header or body of the message.
imap4d_test "SEARCH TEXT wine"\
"SEARCH 1 2"\
imap4d_test "SEARCH TEXT person"\
"SEARCH 2 5 8"\
"OK"
## Boolean operations
......@@ -181,33 +171,33 @@ imap4d_test "SEARCH TEXT wine"\
# When multiple keys are specified, the result is the intersection
# (AND function) of all the messages that match those keys.
imap4d_test "SEARCH TEXT wine FROM alice"\
imap4d_test "SEARCH TEXT person FROM corrector"\
"SEARCH 2"\
"OK"
imap4d_test "SEARCH SENTSINCE \"30-Jul-2002\" SENTBEFORE \"31-Jul-2002\"" \
"SEARCH 3 4" \
"OK"
# OR <search-key1> <search-key2>
# Messages that match either search key.
imap4d_test "SEARCH OR FROM alice ANSWERED"\
"SEARCH 2 3 4 5 6 8 10 12 14 20 25 27 29 33 36 38 40 43 45 47 51 53 55 57 59 63 66 68 70 72 74 76 78 80 82 85 87 89 90 93 95"\
imap4d_test "SEARCH OR FROM corrector ANSWERED"\
"SEARCH 2 3 4 8" \
"OK"
## Check precedence
imap4d_test "SEARCH (OR FROM alice ANSWERED) SENTSINCE \"29-Jul-2002 22:00:33 +0100\""\
"SEARCH 33 36 38 40 43 45 47 51 53 55 57 59 63 66 68 70 72 74 76 78 80 82 85 87 89 90 93 95" \
"OK"
imap4d_test "SEARCH (OR FROM alice ANSWERED) SENTSINCE \"29-Jul-2002 22:00:33 +0100\" SENTBEFORE \"29-Jul-2002 22:00:56 +0100\""\
"SEARCH 33 36 38 40 43 45 47 51 53 55"\
imap4d_test "SEARCH (OR FROM corrector ANSWERED) SENTSINCE \"30-Jul-2002\""\
"SEARCH 3 4 8" \
"OK"
imap4d_test "SEARCH OR FROM alice ANSWERED SENTSINCE \"29-Jul-2002 22:00:33 +0100\" SENTBEFORE \"29-Jul-2002 22:00:56 +0100\""\
"SEARCH 33 36 38 40 43 45 47 51 53 55"\
imap4d_test "SEARCH OR FROM corrector ANSWERED SENTSINCE \"30-Jul-2002\""\
"SEARCH 3 4 8" \
"OK"
imap4d_test "SEARCH OR FROM alice (ANSWERED SENTSINCE \"29-Jul-2002 22:00:33 +0100\" SENTBEFORE \"29-Jul-2002 22:00:56 +0100\")"\
"SEARCH 2 4 6 8 10 12 14 20 25 27 29 33 36 38 40 43 45 47 51 53 55 57 59 63 66 68 70 72 74 76 78 80 82 85 87 90 93 95"\
imap4d_test "SEARCH OR FROM corrector (ANSWERED SENTSINCE \"30-Jul-2002\")"\
"SEARCH 2 3 4 8" \
"OK"
imap4d_stop
......
......@@ -107,10 +107,15 @@ proc imap4d_start {args} {
verbose "Starting imap4d"
set reuse_spool 0
set mbox "teaparty.mbox"
for {set i 0} {$i < [llength $args]} {incr i} {
set a [lindex $args $i]
if {"$a" == "-reuse-spool"} {
set reuse_spool 1
} elseif {"$a" == "-mbox"} {
set mbox [lindex $args [expr $i + 1]]
incr i
} else {
break;
}
......@@ -118,7 +123,7 @@ proc imap4d_start {args} {
if {$reuse_spool == 0} {
mu_prepare_spools
mu_copy_file $MU_SPOOL_DIR/teaparty.mbox $MU_SPOOL_DIR/INBOX
mu_copy_file $MU_SPOOL_DIR/$mbox $MU_SPOOL_DIR/INBOX
}
return [default_imap4d_start [concat [lrange $args $i end]]]
}
......
......@@ -335,8 +335,40 @@ add2set (size_t ** set, int *n, unsigned long val)
return 0;
}
static void
adjust_tm (struct tm *tm, mu_timezone *tz, enum datetime_parse_mode flag)
{
switch (flag)
{
case datetime_default:
break;
case datetime_date_only:
tm->tm_sec = 0;
tm->tm_min = 0;
tm->tm_hour = 0;
#if HAVE_STRUCT_TM_TM_ISDST
tm->tm_isdst = 0;
#endif
#if HAVE_STRUCT_TM_TM_GMTOFF
tm->tm_gmtoff = 0;
#endif
tz->utc_offset = 0;
tz->tz_name = NULL;
break;
case datetime_time_only:
tm->tm_mon = 0;
tm->tm_year = 0;
tm->tm_yday = 0;
tm->tm_wday = 0;
tm->tm_mday = 0;
break;
}
}
int
util_parse_internal_date (char *date, time_t * timep)
util_parse_internal_date (char *date, time_t *timep,
enum datetime_parse_mode flag)
{
struct tm tm;
mu_timezone tz;
......@@ -346,6 +378,8 @@ util_parse_internal_date (char *date, time_t * timep)
if (mu_parse_imap_date_time ((const char **) datep, &tm, &tz))
return 1;
adjust_tm (&tm, &tz, flag);
time = mu_tm2time (&tm, &tz);
if (time == (time_t) - 1)
return 2;
......@@ -355,7 +389,8 @@ util_parse_internal_date (char *date, time_t * timep)
}
int
util_parse_822_date (const char *date, time_t * timep)
util_parse_822_date (const char *date, time_t *timep,
enum datetime_parse_mode flag)
{
struct tm tm;
mu_timezone tz;
......@@ -363,6 +398,7 @@ util_parse_822_date (const char *date, time_t * timep)
if (mu_parse822_date_time (&p, date + strlen (date), &tm, &tz) == 0)
{
adjust_tm (&tm, &tz, flag);
*timep = mu_tm2time (&tm, &tz);
return 0;
}
......@@ -370,13 +406,15 @@ util_parse_822_date (const char *date, time_t * timep)
}
int
util_parse_ctime_date (const char *date, time_t * timep)
util_parse_ctime_date (const char *date, time_t *timep,
enum datetime_parse_mode flag)
{
struct tm tm;
mu_timezone tz;
if (mu_parse_ctime_date_time (&date, &tm, &tz) == 0)
{
adjust_tm (&tm, &tz, flag);
*timep = mu_tm2time (&tm, &tz);
return 0;
}
......
......@@ -182,7 +182,7 @@ mu_parse_imap_date_time (const char **p, struct tm *tm, mu_timezone *tz)
/* "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)
mu_parse_ctime_date_time (const char **p, struct tm *tm, mu_timezone *tz)
{
int wday = 0;
int year = 0;
......@@ -236,9 +236,12 @@ mu_parse_ctime_date_time (const char **p, struct tm *tm, mu_timezone * tz)
#endif
}
/* ctime has no timezone information, set tz to UTC if they ask. */
/* ctime has no timezone information, set tz to local TZ if they ask. */
if (tz)
memset (tz, 0, sizeof (struct mu_timezone));
{
tz->utc_offset = mu_utc_offset ();
tz->tz_name = NULL;
}
return 0;
}
......
......@@ -45,7 +45,7 @@ proc mu_copy_file {src dst} {
set output [open $dst w]
set arg "$"
for {gets $input line} {![eof $input]} {gets $input line} {
puts $output [subst -nobackslashes $line]
puts $output [subst -nobackslashes -nocommands $line]
}
close $input
close $output
......
bigto.mbox
mbox1
mbox
search.mbox
sieve.mbox
relational.mbox
teaparty.mbox
......
From lexi@example.net Mon Jul 29 22:00:08 2002
Received: (from lexi@example.com)
by example.org id 3301
for editor@example.org; Mon, 29 Jul 2002 22:00:06 +0100
Date: Mon, 29 Jul 2002 22:00:01 +0100
From: Lexicographer <lexi@example.com>
To: Editor <editor@example.org>
Subject: Abasement
Status: OR
ABASEMENT, n. A decent and customary mental attitude in the presence
of wealth of power. Peculiarly appropriate in an employee when
addressing an employer.
From correct@example.net Tue Jul 30 00:00:00 2002
Received: (from correct@example.com)
by example.org id 3302
for editor@example.org Tue, Jul 30 00:00:00 2002 +0100
Date: Mon, 29 Jul 2002 22:00:02 +0100
From: Corrector <correct@example.com>
To: Editor <editor@example.org>
Subject: Aboriginies
Status: ORA
ABORIGINIES, n. Persons of little worth found cumbering the soil of a
newly discovered country. They soon cease to cumber; they fertilize.
From lexi@example.net Tue Jul 30 12:00:10 2002
Received: (from lexi@example.com)
by example.org id 3303
for editor@example.org Tue, 30 Jul 2002 12:00:08 +0100
Date: Tue, 30 Jul 2002 12:00:03 +0100
From: Lexicographer <lexi@example.com>
To: Editor <editor@example.org>
Message-Id: "<200207291200.3303@example.org>"
Subject: Abnormal
Status: ORA
ABNORMAL, adj. Not conforming to standard. In matters of thought and
conduct, to be independent is to be abnormal, to be abnormal is to be
detested. Wherefore the lexicographer adviseth a striving toward the
straiter [sic] resemblance of the Average Man than he hath to himself.
Whoso attaineth thereto shall have peace, the prospect of death and
the hope of Hell.
From corrector@example.net Tue Jul 30 12:00:11 2002
Received: (from correct@example.com)
by example.org id 3304
for editor@example.org Tue, 30 Jul 2002 12:00:09 +0100
Date: Tue, 30 Jul 2002 12:00:04 +0100
From: Corrector <corrector@example.com>
To: Editor <editor@example.org>
Subject: Occident
OCCIDENT, n. The part of the world lying west (or east) of the
Orient. It is largely inhabited by Christians, a powerful subtribe of
the Hypocrites, whose principal industries are murder and cheating,
which they are pleased to call "war" and "commerce." These, also, are
the principal industries of the Orient.
From lexi@example.net Wed Jul 31 02:00:12 2002
Received: (from lexi@example.com)
by example.org id 3305
for corrector@example.org Wed, 31 Jul 2002 02:00:10 +0100
Date: Wed, 31 Jul 2002 02:00:05 +0100
From: Lexicographer <lexi@example.com>
To: Corrector <correct@example.org>
Subject: Acquaintance
ACQUAINTANCE, n. A person whom we know well enough to borrow from,
but not well enough to lend to. A degree of friendship called slight
when its object is poor or obscure, and intimate when he is rich or
famous.
From lexi@example.net Thu Aug 01 10:00:13 2002
Received: (from lexi@example.com)
by example.org id 3306
for editor@example.org Thu, 01 Aug 2002 10:00:11 +0100
Date: Thu, 01 Aug 2002 22:00:06 +0100
From: Lexicographer <lexi@example.com>
To: Editor <editor@example.org>
Cc: Corrector <correct@example.org>
Subject: Alliance
ALLIANCE, n. In international politics, the union of two thieves who
have their hands so deeply inserted in each other's pockets that they
cannot separately plunder a third.
From lexi@example.net Fri Aug 02 11:00:14 2002
Received: (from lexi@example.com)
by example.org id 3307
for editor@example.org Fri, 02 Aug 2002 11:00:12 +0100
Date: Fri, 02 Aug 2002 11:00:07 +0100
From: Lexicographer <lexi@example.com>
To: Editor <editor+recheck@example.org>
Subject: White
WHITE, adj. and n. Black.
From correct@example.net Fri Aug 02 12:00:15 2002
Received: (from correct@example.com)
by example.org id 3308
for editor@example.org Fri, 02 Aug 2002 12:00:13 +0100
Date: Fri, 02 Aug 2002 12:00:08 +0100
From: Corrector <correct@example.com>
To: Editor <editor@example.org>
Subject: Telephone
TELEPHONE, n. An invention of the devil which abrogates some of the
advantages of making a disagreeable person keep his distance.