imap4d: CLOSE should not send EXPUNGE responses. Fix error checking in STORE.
* imap4d/imap4d.h (silent_expunge): New global. * imap4d/sync.c (silent_expunge): New variable. (action): Suppress EXPUNGE responses if silent_expunge is set. * imap4d/close.c (imap4d_close0): Set silent_expunge before calling mu_mailbox_flush. * imap4d/tests/close-expunge.at: New test. * imap4d/tests/testsuite.at: Include close-expunge.at. * imap4d/tests/Makefile.am (TESTSUITE_AT): Add close-expunge.at. * imap4d/fetch.c (fetch_thunk): Emit BAD response if failed to parse message set. * imap4d/store.c (store_thunk): Emit BAD response if failed to parse flags.
Showing
8 changed files
with
74 additions
and
13 deletions
... | @@ -30,9 +30,11 @@ imap4d_close0 (struct imap4d_command *command, imap4d_tokbuf_t tok, | ... | @@ -30,9 +30,11 @@ imap4d_close0 (struct imap4d_command *command, imap4d_tokbuf_t tok, |
30 | mu_mailbox_get_flags (mbox, &flags); | 30 | mu_mailbox_get_flags (mbox, &flags); |
31 | if (flags & MU_STREAM_WRITE) | 31 | if (flags & MU_STREAM_WRITE) |
32 | { | 32 | { |
33 | silent_expunge = expunge; | ||
33 | imap4d_enter_critical (); | 34 | imap4d_enter_critical (); |
34 | status = mu_mailbox_flush (mbox, expunge); | 35 | status = mu_mailbox_flush (mbox, expunge); |
35 | imap4d_leave_critical (); | 36 | imap4d_leave_critical (); |
37 | silent_expunge = 0; | ||
36 | if (status) | 38 | if (status) |
37 | { | 39 | { |
38 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_flush", NULL, status); | 40 | mu_diag_funcall (MU_DIAG_ERROR, "mu_mailbox_flush", NULL, status); |
... | @@ -69,9 +71,11 @@ imap4d_close0 (struct imap4d_command *command, imap4d_tokbuf_t tok, | ... | @@ -69,9 +71,11 @@ imap4d_close0 (struct imap4d_command *command, imap4d_tokbuf_t tok, |
69 | NO - close failure: no mailbox selected | 71 | NO - close failure: no mailbox selected |
70 | BAD - command unknown or arguments invalid | 72 | BAD - command unknown or arguments invalid |
71 | 73 | ||
72 | The CLOSE command permanently removes from the currently selected | 74 | The CLOSE command permanently removes all messages that have the |
73 | mailbox all messages that have the \\Deleted flag set, and returns | 75 | \Deleted flag set from the currently selected mailbox, and returns |
74 | to authenticated state from selected state. */ | 76 | to the authenticated state from the selected state. No untagged |
77 | EXPUNGE responses are sent. */ | ||
78 | |||
75 | int | 79 | int |
76 | imap4d_close (struct imap4d_command *command, imap4d_tokbuf_t tok) | 80 | imap4d_close (struct imap4d_command *command, imap4d_tokbuf_t tok) |
77 | { | 81 | { | ... | ... |
... | @@ -1778,13 +1778,10 @@ fetch_thunk (imap4d_parsebuf_t pb) | ... | @@ -1778,13 +1778,10 @@ fetch_thunk (imap4d_parsebuf_t pb) |
1778 | FIXME: This code also causes imap4d to silently ignore erroneous | 1778 | FIXME: This code also causes imap4d to silently ignore erroneous |
1779 | msgset specifications (e.g. FETCH foobar (FLAGS)), which should | 1779 | msgset specifications (e.g. FETCH foobar (FLAGS)), which should |
1780 | be fixed. */ | 1780 | be fixed. */ |
1781 | |||
1782 | pb->err_text = "Completed"; | ||
1783 | return RESP_OK; | 1781 | return RESP_OK; |
1784 | 1782 | ||
1785 | default: | 1783 | default: |
1786 | pb->err_text = "Failed to parse message set"; | 1784 | imap4d_parsebuf_exit (pb, "Failed to parse message set"); |
1787 | return RESP_NO; | ||
1788 | } | 1785 | } |
1789 | 1786 | ||
1790 | /* Compile the expression */ | 1787 | /* Compile the expression */ | ... | ... |
... | @@ -205,6 +205,7 @@ extern char **imap4d_argv; | ... | @@ -205,6 +205,7 @@ extern char **imap4d_argv; |
205 | extern jmp_buf child_jmp; | 205 | extern jmp_buf child_jmp; |
206 | 206 | ||
207 | extern int test_mode; | 207 | extern int test_mode; |
208 | extern int silent_expunge; | ||
208 | 209 | ||
209 | /* Input functions */ | 210 | /* Input functions */ |
210 | extern mu_stream_t iostream; | 211 | extern mu_stream_t iostream; | ... | ... |
... | @@ -79,12 +79,10 @@ store_thunk (imap4d_parsebuf_t p) | ... | @@ -79,12 +79,10 @@ store_thunk (imap4d_parsebuf_t p) |
79 | case EINVAL: | 79 | case EINVAL: |
80 | /* See RFC 3501, section 6.4.8, and a comment to the equivalent code | 80 | /* See RFC 3501, section 6.4.8, and a comment to the equivalent code |
81 | in fetch.c */ | 81 | in fetch.c */ |
82 | p->err_text = "Completed"; | ||
83 | return RESP_OK; | 82 | return RESP_OK; |
84 | 83 | ||
85 | default: | 84 | default: |
86 | p->err_text = "Failed to parse message set"; | 85 | imap4d_parsebuf_exit (p, "Failed to parse message set"); |
87 | return RESP_NO; | ||
88 | } | 86 | } |
89 | 87 | ||
90 | if (p->token[0] != '(') | 88 | if (p->token[0] != '(') |
... | @@ -94,7 +92,9 @@ store_thunk (imap4d_parsebuf_t p) | ... | @@ -94,7 +92,9 @@ store_thunk (imap4d_parsebuf_t p) |
94 | do | 92 | do |
95 | { | 93 | { |
96 | int t; | 94 | int t; |
97 | if (!util_attribute_to_type (p->token, &t)) | 95 | if (util_attribute_to_type (p->token, &t)) |
96 | imap4d_parsebuf_exit (p, "Failed to parse flags"); | ||
97 | else | ||
98 | pclos->type |= t; | 98 | pclos->type |= t; |
99 | } | 99 | } |
100 | while (imap4d_parsebuf_next (p, 1) && p->token[0] != ')'); | 100 | while (imap4d_parsebuf_next (p, 1) && p->token[0] != ')'); |
... | @@ -173,9 +173,9 @@ int | ... | @@ -173,9 +173,9 @@ int |
173 | imap4d_store (struct imap4d_command *command, imap4d_tokbuf_t tok) | 173 | imap4d_store (struct imap4d_command *command, imap4d_tokbuf_t tok) |
174 | { | 174 | { |
175 | int rc; | 175 | int rc; |
176 | char *err_text; | 176 | char *err_text = NULL; |
177 | 177 | ||
178 | rc = imap4d_store0 (tok, 0, &err_text); | 178 | rc = imap4d_store0 (tok, 0, &err_text); |
179 | return io_completion_response (command, rc, "%s", err_text); | 179 | return io_completion_response (command, rc, "%s", err_text ? err_text : ""); |
180 | } | 180 | } |
181 | 181 | ... | ... |
... | @@ -136,7 +136,11 @@ imap4d_sync_flags (size_t msgno) | ... | @@ -136,7 +136,11 @@ imap4d_sync_flags (size_t msgno) |
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | int silent_expunge; | ||
140 | /* When true, non-tagged EXPUNGE responses are suppressed. */ | ||
141 | |||
139 | static int mailbox_corrupt; | 142 | static int mailbox_corrupt; |
143 | /* When true, mailbox has been altered by another party. */ | ||
140 | 144 | ||
141 | static int | 145 | static int |
142 | action (mu_observer_t observer, size_t type, void *data, void *action_data) | 146 | action (mu_observer_t observer, size_t type, void *data, void *action_data) |
... | @@ -158,6 +162,7 @@ action (mu_observer_t observer, size_t type, void *data, void *action_data) | ... | @@ -158,6 +162,7 @@ action (mu_observer_t observer, size_t type, void *data, void *action_data) |
158 | immediately decremented by 1, and this decrement is reflected in | 162 | immediately decremented by 1, and this decrement is reflected in |
159 | message sequence numbers in subsequent responses (including other | 163 | message sequence numbers in subsequent responses (including other |
160 | untagged EXPUNGE responses). */ | 164 | untagged EXPUNGE responses). */ |
165 | if (!silent_expunge) | ||
161 | { | 166 | { |
162 | size_t *exp = data; | 167 | size_t *exp = data; |
163 | io_untagged_response (RESP_NONE, "%lu EXPUNGED", | 168 | io_untagged_response (RESP_NONE, "%lu EXPUNGED", | ... | ... |
imap4d/tests/close-expunge.at
0 → 100644
1 | # This file is part of GNU Mailutils. -*- Autotest -*- | ||
2 | # Copyright (C) 2011 Free Software Foundation, Inc. | ||
3 | # | ||
4 | # GNU Mailutils is free software; you can redistribute it and/or | ||
5 | # modify it under the terms of the GNU General Public License as | ||
6 | # published by the Free Software Foundation; either version 3, or (at | ||
7 | # your option) any later version. | ||
8 | # | ||
9 | # GNU Mailutils is distributed in the hope that it will be useful, but | ||
10 | # WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | # General Public License for more details. | ||
13 | # | ||
14 | # You should have received a copy of the GNU General Public License | ||
15 | # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. | ||
16 | |||
17 | AT_SETUP([Close with expunge]) | ||
18 | AT_KEYWORDS([close close-expunge]) | ||
19 | |||
20 | # According to RFC3501, CLOSE command should not send untagged EXPUNGE | ||
21 | # responses even if expunge actually took place. | ||
22 | |||
23 | IMAP4D_CHECK([ | ||
24 | MUT_MBCOPY($abs_top_srcdir/testsuite/spool/search.mbox,temp) | ||
25 | sed 's/^\(Status: .*\)/\1D/' temp > INBOX | ||
26 | ], | ||
27 | [1 SELECT INBOX | ||
28 | 2 CLOSE | ||
29 | 3 EXAMINE INBOX | ||
30 | X LOGOUT | ||
31 | ], | ||
32 | [* PREAUTH IMAP4rev1 Test mode | ||
33 | * 8 EXISTS | ||
34 | * 5 RECENT | ||
35 | * OK [[UIDNEXT 9]] Predicted next uid | ||
36 | * OK [[UNSEEN 4]] first unseen messsage | ||
37 | * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) | ||
38 | * OK [[PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft)]] Permanent flags | ||
39 | 1 OK [[READ-WRITE]] SELECT Completed | ||
40 | 2 OK CLOSE Completed | ||
41 | * 5 EXISTS | ||
42 | * 0 RECENT | ||
43 | * OK [[UIDNEXT 9]] Predicted next uid | ||
44 | * OK [[UNSEEN 1]] first unseen messsage | ||
45 | * FLAGS (\Answered \Flagged \Deleted \Seen \Draft) | ||
46 | * OK [[PERMANENTFLAGS ()]] No permanent flags | ||
47 | 3 OK [[READ-ONLY]] EXAMINE Completed | ||
48 | * BYE Session terminating. | ||
49 | X OK LOGOUT Completed | ||
50 | ]) | ||
51 | |||
52 | AT_CLEANUP |
... | @@ -70,6 +70,7 @@ m4_include([select.at]) | ... | @@ -70,6 +70,7 @@ m4_include([select.at]) |
70 | m4_include([examine.at]) | 70 | m4_include([examine.at]) |
71 | m4_include([status.at]) | 71 | m4_include([status.at]) |
72 | m4_include([expunge.at]) | 72 | m4_include([expunge.at]) |
73 | m4_include([close-expunge.at]) | ||
73 | m4_include([create01.at]) | 74 | m4_include([create01.at]) |
74 | m4_include([create02.at]) | 75 | m4_include([create02.at]) |
75 | 76 | ... | ... |
-
Please register or sign in to post a comment