Commit 927c27f8 927c27f8e4bc2c8ae5699addfbcd833d8fec6e08 by Sergey Poznyakoff

Fix input operations and RFC-compliance in imap4d.

* imap4d/util.c (util_getword, util_getitem, util_token)
(util_unquote): Remove.
(imap4d_readline): Rewrite to reduce memory reallocation.  Add
support for non-synchronizing literals (RFC 2088).
(imap4d_readline_ex): Remove.
(util_do_command): Rewrite using new imap4d_readline.
(util_parse_internal_date0): Remove.
(imap4d_tokbuf_init, imap4d_tokbuf_destroy, imap4d_tokbuf_argc)
(imap4d_tokbuf_getarg, util_isdelim)
(imap4d_tokbuf_from_string): New functions.
* imap4d/append.c, imap4d/auth_gss.c, imap4d/authenticate.c,
imap4d/check.c, imap4d/close.c, imap4d/commands.c, imap4d/copy.c,
imap4d/create.c, imap4d/delete.c, imap4d/examine.c,
imap4d/imap4d.h, imap4d/list.c, imap4d/login.c, imap4d/logout.c,
imap4d/lsub.c, imap4d/expunge.c, imap4d/idle.c, imap4d/noop.c,
imap4d/rename.c, imap4d/search.c, imap4d/select.c,
imap4d/starttls.c, imap4d/status.c, imap4d/store.c,
imap4d/subscribe.c, imap4d/uid.c, imap4d/unsubscribe.c,
imap4d/version.c: Rewrite using new imap4d_readline.
* imap4d/namespace.c: Use new imap4d_readline.  Ensure that
each reported prefix ends with a hierarchy delimiter.
* imap4d/imap4d.c (imap4d_mainloop): Use new imap4d_readline.
* imap4d/fetch.c: Rewrite parser from scratch.
* imap4d/capability.c (imap4d_capability_init): Report LITERAL+
capability.

* imap4d/testsuite/imap4d/anystate.exp: Account for the LITERAL+
capability.
* imap4d/testsuite/imap4d/append.exp: Fix APPEND arguments (imap4d
requires exactly three arguments, as per RFC3501.
Fix octet count in literals returned by fetch (previous versions
failed to include the trailing CRLF).
* imap4d/testsuite/imap4d/create.exp: Likewise.
* imap4d/testsuite/imap4d/fetch.exp: Fix FETCH arguments (previous
versions incorrectly accepted header-list without parentheses.
Fix result of FETCH 4 BODY[2.2.1]: it returns entire part, in the
contrast to previous versions, which treated it as
BODY[2.2.1.TEXT].

* maidag/mailtmp.c (mail_tmp_finish): Ensure /dev/null is treated
as mailbox.
1 parent 7317a04a
1 2008-08-11 Sergey Poznyakoff <gray@gnu.org.ua>
2
3 Fix input operations and RFC-compliance in imap4d.
4
5 * imap4d/util.c (util_getword, util_getitem, util_token)
6 (util_unquote): Remove.
7 (imap4d_readline): Rewrite to reduce memory reallocation. Add
8 support for non-synchronizing literals (RFC 2088).
9 (imap4d_readline_ex): Remove.
10 (util_do_command): Rewrite using new imap4d_readline.
11 (util_parse_internal_date0): Remove.
12 (imap4d_tokbuf_init, imap4d_tokbuf_destroy, imap4d_tokbuf_argc)
13 (imap4d_tokbuf_getarg, util_isdelim)
14 (imap4d_tokbuf_from_string): New functions.
15 * imap4d/append.c, imap4d/auth_gss.c, imap4d/authenticate.c,
16 imap4d/check.c, imap4d/close.c, imap4d/commands.c, imap4d/copy.c,
17 imap4d/create.c, imap4d/delete.c, imap4d/examine.c,
18 imap4d/imap4d.h, imap4d/list.c, imap4d/login.c, imap4d/logout.c,
19 imap4d/lsub.c, imap4d/expunge.c, imap4d/idle.c, imap4d/noop.c,
20 imap4d/rename.c, imap4d/search.c, imap4d/select.c,
21 imap4d/starttls.c, imap4d/status.c, imap4d/store.c,
22 imap4d/subscribe.c, imap4d/uid.c, imap4d/unsubscribe.c,
23 imap4d/version.c: Rewrite using new imap4d_readline.
24 * imap4d/namespace.c: Use new imap4d_readline. Ensure that
25 each reported prefix ends with a hierarchy delimiter.
26 * imap4d/imap4d.c (imap4d_mainloop): Use new imap4d_readline.
27 * imap4d/fetch.c: Rewrite parser from scratch.
28 * imap4d/capability.c (imap4d_capability_init): Report LITERAL+
29 capability.
30
31 * imap4d/testsuite/imap4d/anystate.exp: Account for the LITERAL+
32 capability.
33 * imap4d/testsuite/imap4d/append.exp: Fix APPEND arguments (imap4d
34 requires exactly three arguments, as per RFC3501.
35 Fix octet count in literals returned by fetch (previous versions
36 failed to include the trailing CRLF).
37 * imap4d/testsuite/imap4d/create.exp: Likewise.
38 * imap4d/testsuite/imap4d/fetch.exp: Fix FETCH arguments (previous
39 versions incorrectly accepted header-list without parentheses.
40 Fix result of FETCH 4 BODY[2.2.1]: it returns entire part, in the
41 contrast to previous versions, which treated it as
42 BODY[2.2.1.TEXT].
43
44 * maidag/mailtmp.c (mail_tmp_finish): Ensure /dev/null is treated
45 as mailbox.
46
1 2008-08-08 Sergey Poznyakoff <gray@gnu.org.ua> 47 2008-08-08 Sergey Poznyakoff <gray@gnu.org.ua>
2 48
3 Fix imap appends for AMD mailboxes. 49 Fix imap appends for AMD mailboxes.
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2006, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2006, 2007,
3 2008 Free Software Foundation, Inc.
3 4
4 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -18,49 +19,6 @@ ...@@ -18,49 +19,6 @@
18 19
19 #include "imap4d.h" 20 #include "imap4d.h"
20 21
21 /* APPEND mbox [(flags)] [date_time] message_literal */
22 int
23 imap4d_append (struct imap4d_command *command, char *arg)
24 {
25 char *sp;
26 char *mboxname;
27 int flags = 0;
28 mu_mailbox_t dest_mbox = NULL;
29 int status;
30
31 mboxname = util_getword (arg, &sp);
32 if (!mboxname)
33 return util_finish (command, RESP_BAD, "Too few arguments");
34
35 util_unquote (&mboxname);
36
37 if (*sp == '(' && util_parse_attributes (sp+1, &sp, &flags))
38 return util_finish (command, RESP_BAD, "Missing closing parenthesis");
39
40 mboxname = namespace_getfullpath (mboxname, "/");
41 if (!mboxname)
42 return util_finish (command, RESP_NO, "Couldn't open mailbox");
43
44 status = mu_mailbox_create_default (&dest_mbox, mboxname);
45 if (status == 0)
46 {
47 /* It SHOULD NOT automatifcllly create the mailbox. */
48 status = mu_mailbox_open (dest_mbox, MU_STREAM_RDWR);
49 if (status == 0)
50 {
51 status = imap4d_append0 (dest_mbox, flags, sp);
52 mu_mailbox_close (dest_mbox);
53 }
54 mu_mailbox_destroy (&dest_mbox);
55 }
56
57 free (mboxname);
58 if (status == 0)
59 return util_finish (command, RESP_OK, "Completed");
60
61 return util_finish (command, RESP_NO, "[TRYCREATE] failed");
62 }
63
64 static int 22 static int
65 _append_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite) 23 _append_date (mu_envelope_t envelope, char *buf, size_t len, size_t *pnwrite)
66 { 24 {
...@@ -93,12 +51,18 @@ _append_size (mu_message_t msg, size_t *psize) ...@@ -93,12 +51,18 @@ _append_size (mu_message_t msg, size_t *psize)
93 mu_stream_t str; 51 mu_stream_t str;
94 int status = mu_message_get_stream (msg, &str); 52 int status = mu_message_get_stream (msg, &str);
95 if (status == 0) 53 if (status == 0)
96 status = mu_stream_size (str, psize); 54 {
55 mu_off_t size;
56 status = mu_stream_size (str, &size);
57 if (status == 0 && psize)
58 *psize = size;
59 }
97 return status; 60 return status;
98 } 61 }
99 62
100 int 63 int
101 imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) 64 imap4d_append0 (mu_mailbox_t mbox, int flags, char *date_time, char *text,
65 char **err_text)
102 { 66 {
103 mu_stream_t stream; 67 mu_stream_t stream;
104 int rc = 0; 68 int rc = 0;
...@@ -118,23 +82,25 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) ...@@ -118,23 +82,25 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text)
118 return 1; 82 return 1;
119 } 83 }
120 84
121 while (*text && isspace (*text))
122 text++;
123
124 /* If a date_time is specified, the internal date SHOULD be set in the 85 /* If a date_time is specified, the internal date SHOULD be set in the
125 resulting message; otherwise, the internal date of the resulting 86 resulting message; otherwise, the internal date of the resulting
126 message is set to the current date and time by default. */ 87 message is set to the current date and time by default. */
127 if (util_parse_internal_date0 (text, &t, &text) == 0) 88 if (date_time)
128 { 89 {
129 while (*text && isspace(*text)) 90 if (util_parse_internal_date (date_time, &t))
130 text++; 91 {
92 *err_text = "Invalid date/time format";
93 return 1;
94 }
131 } 95 }
132 else 96 else
133 { 97 time(&t);
134 time(&t); 98
135 }
136 tm = gmtime(&t); 99 tm = gmtime(&t);
137 100
101 while (*text && isspace (*text))
102 text++;
103
138 mu_stream_write (stream, text, strlen (text), len, &len); 104 mu_stream_write (stream, text, strlen (text), len, &len);
139 mu_message_set_stream (msg, stream, &tm); 105 mu_message_set_stream (msg, stream, &tm);
140 mu_message_set_size (msg, _append_size, &tm); 106 mu_message_set_size (msg, _append_size, &tm);
...@@ -158,4 +124,87 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) ...@@ -158,4 +124,87 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text)
158 return rc; 124 return rc;
159 } 125 }
160 126
127
128 /* APPEND mbox [(flags)] [date_time] message_literal */
129 int
130 imap4d_append (struct imap4d_command *command, imap4d_tokbuf_t tok)
131 {
132 int i;
133 char *mboxname;
134 int flags = 0;
135 mu_mailbox_t dest_mbox = NULL;
136 int status;
137 int argc = imap4d_tokbuf_argc (tok);
138 char *date_time;
139 char *msg_text;
140 char *err_text = "[TRYCREATE] failed";
141
142 if (argc < 4)
143 return util_finish (command, RESP_BAD, "Too few arguments");
144
145 mboxname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
146 if (!mboxname)
147 return util_finish (command, RESP_BAD, "Too few arguments");
148
149 i = IMAP4_ARG_2;
150 if (imap4d_tokbuf_getarg (tok, i)[0] == '(')
151 {
152 while (++i < argc)
153 {
154 int type;
155 char *arg = imap4d_tokbuf_getarg (tok, i);
156
157 if (!util_attribute_to_type (arg, &type))
158 flags |= type;
159 else if (arg[0] == ')')
160 break;
161 }
162 if (i == argc)
163 return util_finish (command, RESP_BAD, "Missing closing parenthesis");
164 i++;
165 }
166
167 switch (argc - i)
168 {
169 case 2:
170 /* Date/time is present */
171 date_time = imap4d_tokbuf_getarg (tok, i);
172 i++;
173 break;
174
175 case 1:
176 date_time = NULL;
177 break;
178
179 default:
180 return util_finish (command, RESP_BAD, "Too many arguments");
181 }
182
183 msg_text = imap4d_tokbuf_getarg (tok, i);
184
185 mboxname = namespace_getfullpath (mboxname, "/");
186 if (!mboxname)
187 return util_finish (command, RESP_NO, "Couldn't open mailbox");
188
189 status = mu_mailbox_create_default (&dest_mbox, mboxname);
190 if (status == 0)
191 {
192 /* It SHOULD NOT automatically create the mailbox. */
193 status = mu_mailbox_open (dest_mbox, MU_STREAM_RDWR);
194 if (status == 0)
195 {
196 status = imap4d_append0 (dest_mbox, flags, date_time, msg_text,
197 &err_text);
198 mu_mailbox_close (dest_mbox);
199 }
200 mu_mailbox_destroy (&dest_mbox);
201 }
202
203 free (mboxname);
204 if (status == 0)
205 return util_finish (command, RESP_OK, "Completed");
206
207 return util_finish (command, RESP_NO, err_text);
208 }
209
161 210
......
...@@ -119,7 +119,9 @@ auth_gssapi (struct imap4d_command *command, ...@@ -119,7 +119,9 @@ auth_gssapi (struct imap4d_command *command,
119 gss_ctx_id_t context; 119 gss_ctx_id_t context;
120 gss_cred_id_t cred_handle, server_creds; 120 gss_cred_id_t cred_handle, server_creds;
121 gss_OID mech_type; 121 gss_OID mech_type;
122 char *token_str; 122 char *token_str = NULL;
123 size_t token_size = 0;
124 size_t token_len;
123 unsigned char *tmp = NULL; 125 unsigned char *tmp = NULL;
124 size_t size; 126 size_t size;
125 gss_name_t server_name; 127 gss_name_t server_name;
...@@ -168,11 +170,10 @@ auth_gssapi (struct imap4d_command *command, ...@@ -168,11 +170,10 @@ auth_gssapi (struct imap4d_command *command,
168 170
169 for (;;) 171 for (;;)
170 { 172 {
171 token_str = imap4d_readline_ex (); 173 imap4d_getline (&token_str, &token_size, &token_len);
172 util_base64_decode (token_str, strlen (token_str), &tmp, &size); 174 util_base64_decode (token_str, token_len, &tmp, &size);
173 tokbuf.value = tmp; 175 tokbuf.value = tmp;
174 tokbuf.length = size; 176 tokbuf.length = size;
175 free (token_str);
176 177
177 maj_stat = gss_accept_sec_context (&min_stat, 178 maj_stat = gss_accept_sec_context (&min_stat,
178 &context, 179 &context,
...@@ -202,6 +203,7 @@ auth_gssapi (struct imap4d_command *command, ...@@ -202,6 +203,7 @@ auth_gssapi (struct imap4d_command *command,
202 display_status ("accept context", maj_stat, min_stat); 203 display_status ("accept context", maj_stat, min_stat);
203 maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf); 204 maj_stat = gss_delete_sec_context (&min_stat, &context, &outbuf);
204 gss_release_buffer (&min_stat, &outbuf); 205 gss_release_buffer (&min_stat, &outbuf);
206 free (token_str);
205 return RESP_NO; 207 return RESP_NO;
206 } 208 }
207 209
...@@ -211,8 +213,7 @@ auth_gssapi (struct imap4d_command *command, ...@@ -211,8 +213,7 @@ auth_gssapi (struct imap4d_command *command,
211 util_send ("+ %*.*s\r\n", size, size, tmp); 213 util_send ("+ %*.*s\r\n", size, size, tmp);
212 free (tmp); 214 free (tmp);
213 gss_release_buffer (&min_stat, &outbuf); 215 gss_release_buffer (&min_stat, &outbuf);
214 token_str = imap4d_readline_ex (); 216 imap4d_getline (&token_str, &token_size, &token_len);
215 free (token_str);
216 } 217 }
217 218
218 /* Construct security-level data */ 219 /* Construct security-level data */
...@@ -224,6 +225,7 @@ auth_gssapi (struct imap4d_command *command, ...@@ -224,6 +225,7 @@ auth_gssapi (struct imap4d_command *command,
224 if (maj_stat != GSS_S_COMPLETE) 225 if (maj_stat != GSS_S_COMPLETE)
225 { 226 {
226 display_status ("wrap", maj_stat, min_stat); 227 display_status ("wrap", maj_stat, min_stat);
228 free (token_str);
227 return RESP_NO; 229 return RESP_NO;
228 } 230 }
229 231
...@@ -231,8 +233,8 @@ auth_gssapi (struct imap4d_command *command, ...@@ -231,8 +233,8 @@ auth_gssapi (struct imap4d_command *command,
231 util_send ("+ %*.*s\r\n", size, size, tmp); 233 util_send ("+ %*.*s\r\n", size, size, tmp);
232 free (tmp); 234 free (tmp);
233 235
234 token_str = imap4d_readline_ex (); 236 imap4d_getline (&token_str, &token_size, &token_len);
235 util_base64_decode (token_str, strlen (token_str), 237 util_base64_decode (token_str, token_len,
236 (unsigned char **) &tokbuf.value, &tokbuf.length); 238 (unsigned char **) &tokbuf.value, &tokbuf.length);
237 free (token_str); 239 free (token_str);
238 240
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2006, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2006, 2007,
3 2008 Free Software Foundation, Inc.
3 4
4 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -93,24 +94,30 @@ imap4d_auth_capability () ...@@ -93,24 +94,30 @@ imap4d_auth_capability ()
93 mu_list_do (imap_auth_list, _auth_capa, NULL); 94 mu_list_do (imap_auth_list, _auth_capa, NULL);
94 } 95 }
95 96
97 /*
98 6.2.1. AUTHENTICATE Command
99
100 Arguments: authentication mechanism name
101 */
102
96 int 103 int
97 imap4d_authenticate (struct imap4d_command *command, char *arg) 104 imap4d_authenticate (struct imap4d_command *command, imap4d_tokbuf_t tok)
98 { 105 {
99 char *sp = NULL;
100 char *auth_type; 106 char *auth_type;
101 struct auth_data adata; 107 struct auth_data adata;
108
109 if (imap4d_tokbuf_argc (tok) != 3)
110 return util_finish (command, RESP_BAD, "Invalid arguments");
102 111
103 auth_type = util_getword (arg, &sp); 112 auth_type = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
104 util_unquote (&auth_type);
105 if (!auth_type)
106 return util_finish (command, RESP_BAD, "Too few arguments");
107 113
108 if (tls_required) 114 if (tls_required)
109 return util_finish (command, RESP_NO, "Command disabled: Use STARTTLS first"); 115 return util_finish (command, RESP_NO,
116 "Command disabled: Use STARTTLS first");
110 117
111 adata.command = command; 118 adata.command = command;
112 adata.auth_type = auth_type; 119 adata.auth_type = auth_type;
113 adata.arg = sp; 120 adata.arg = NULL;
114 adata.username = NULL; 121 adata.username = NULL;
115 122
116 if (mu_list_do (imap_auth_list, _auth_try, &adata) == 0) 123 if (mu_list_do (imap_auth_list, _auth_try, &adata) == 0)
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2003, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2003, 2005, 2007,
3 2008 Free Software Foundation, Inc.
3 4
4 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -50,6 +51,7 @@ imap4d_capability_init () ...@@ -50,6 +51,7 @@ imap4d_capability_init ()
50 "IMAP4rev1", 51 "IMAP4rev1",
51 "NAMESPACE", 52 "NAMESPACE",
52 "IDLE", 53 "IDLE",
54 "LITERAL+",
53 "X-VERSION", 55 "X-VERSION",
54 NULL 56 NULL
55 }; 57 };
...@@ -67,8 +69,11 @@ print_capa (void *item, void *data) ...@@ -67,8 +69,11 @@ print_capa (void *item, void *data)
67 } 69 }
68 70
69 int 71 int
70 imap4d_capability (struct imap4d_command *command, char *arg MU_ARG_UNUSED) 72 imap4d_capability (struct imap4d_command *command, imap4d_tokbuf_t tok)
71 { 73 {
74 if (imap4d_tokbuf_argc (tok) != 2)
75 return util_finish (command, RESP_BAD, "Invalid arguments");
76
72 util_send ("* CAPABILITY"); 77 util_send ("* CAPABILITY");
73 78
74 mu_list_do (capa_list, print_capa, NULL); 79 mu_list_do (capa_list, print_capa, NULL);
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,13 +19,20 @@ ...@@ -19,13 +19,20 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 * Do we need to do anything here? 22 6.4.1. CHECK Command
23 * FIXME: This is like noop we need to notify the client of 23
24 * new mails etc ... and do housekeeping. 24 Arguments: none
25 */ 25
26 Responses: no specific responses for this command
27
28 Result: OK - check completed
29 BAD - command unknown or arguments invalid
30 */
26 31
27 int 32 int
28 imap4d_check (struct imap4d_command *command, char *arg MU_ARG_UNUSED) 33 imap4d_check (struct imap4d_command *command, imap4d_tokbuf_t tok)
29 { 34 {
35 if (imap4d_tokbuf_argc (tok) != 2)
36 return util_finish (command, RESP_BAD, "Invalid arguments");
30 return util_finish (command, RESP_OK, "Completed"); 37 return util_finish (command, RESP_OK, "Completed");
31 } 38 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2004, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2004, 2005, 2007,
3 2008 Free Software Foundation, Inc.
3 4
4 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -19,16 +20,27 @@ ...@@ -19,16 +20,27 @@
19 #include "imap4d.h" 20 #include "imap4d.h"
20 21
21 /* 22 /*
22 */ 23 6.4.2. CLOSE Command
23 24
24 /* The CLOSE command permanently removes from the currently selected 25 Arguments: none
26
27 Responses: no specific responses for this command
28
29 Result: OK - close completed, now in authenticated state
30 NO - close failure: no mailbox selected
31 BAD - command unknown or arguments invalid
32
33 The CLOSE command permanently removes from the currently selected
25 mailbox all messages that have the \\Deleted flag set, and returns 34 mailbox all messages that have the \\Deleted flag set, and returns
26 to authenticated state from selected state. */ 35 to authenticated state from selected state. */
27 int 36 int
28 imap4d_close (struct imap4d_command *command, char *arg MU_ARG_UNUSED) 37 imap4d_close (struct imap4d_command *command, imap4d_tokbuf_t tok)
29 { 38 {
30 const char *msg = NULL; 39 const char *msg = NULL;
31 int status, flags; 40 int status, flags;
41
42 if (imap4d_tokbuf_argc (tok) != 2)
43 return util_finish (command, RESP_BAD, "Invalid arguments");
32 44
33 mu_mailbox_get_flags (mbox, &flags); 45 mu_mailbox_get_flags (mbox, &flags);
34 if ((flags & MU_STREAM_READ) == 0) 46 if ((flags & MU_STREAM_READ) == 0)
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2003, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2003, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,55 +19,69 @@ ...@@ -19,55 +19,69 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 * copy messages in argv[2] to mailbox in argv[3] 22 6.4.7. COPY Command
23
24 Arguments: message set
25 mailbox name
26
27 Responses: no specific responses for this command
28
29 Result: OK - copy completed
30 NO - copy error: can't copy those messages or to that
31 name
32 BAD - command unknown or arguments invalid
33
34 copy messages in argv[2] to mailbox in argv[3]
23 */ 35 */
24 36
25 int 37 int
26 imap4d_copy (struct imap4d_command *command, char *arg) 38 imap4d_copy (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 39 {
28 int rc; 40 int rc;
29 char buffer[64]; 41 char *text;
30 42
31 rc = imap4d_copy0 (arg, 0, buffer, sizeof buffer); 43 if (imap4d_tokbuf_argc (tok) != 4)
44 return util_finish (command, RESP_BAD, "Invalid arguments");
45
46 rc = imap4d_copy0 (tok, 0, &text);
47
32 if (rc == RESP_NONE) 48 if (rc == RESP_NONE)
33 { 49 {
34 /* Reset the state ourself. */ 50 /* Reset the state ourself. */
35 int new_state = (rc == RESP_OK) ? command->success : command->failure; 51 int new_state = (rc == RESP_OK) ? command->success : command->failure;
36 if (new_state != STATE_NONE) 52 if (new_state != STATE_NONE)
37 state = new_state; 53 state = new_state;
38 return util_send ("%s %s\r\n", command->tag, buffer); 54 return util_send ("%s %s\r\n", command->tag, text);
39 } 55 }
40 return util_finish (command, rc, "%s", buffer); 56 return util_finish (command, rc, "%s", text);
41 } 57 }
42 58
43 int 59 int
44 imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) 60 imap4d_copy0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
45 { 61 {
46 int status; 62 int status;
47 char *msgset; 63 char *msgset;
48 char *name; 64 char *name;
49 char *mailbox_name; 65 char *mailbox_name;
50 const char *delim = "/"; 66 const char *delim = "/";
51 char *sp = NULL;
52 size_t *set = NULL; 67 size_t *set = NULL;
53 int n = 0; 68 int n = 0;
54 mu_mailbox_t cmbox = NULL; 69 mu_mailbox_t cmbox = NULL;
70 int arg = IMAP4_ARG_1 + !!isuid;
55 71
56 msgset = util_getword (arg, &sp); 72 if (imap4d_tokbuf_argc (tok) != arg + 2)
57 name = util_getword (NULL, &sp);
58
59 util_unquote (&name);
60 if (!msgset || !name || *name == '\0')
61 { 73 {
62 snprintf (resp, resplen, "Too few args"); 74 *err_text = "Invalid arguments";
63 return RESP_BAD; 75 return 1;
64 } 76 }
65 77
78 msgset = imap4d_tokbuf_getarg (tok, arg);
79 name = imap4d_tokbuf_getarg (tok, arg + 1);
66 /* Get the message numbers in set[]. */ 80 /* Get the message numbers in set[]. */
67 status = util_msgset (msgset, &set, &n, isuid); 81 status = util_msgset (msgset, &set, &n, isuid);
68 if (status != 0) 82 if (status != 0)
69 { 83 {
70 snprintf (resp, resplen, "Bogus number set"); 84 *err_text = "Bogus number set";
71 return RESP_BAD; 85 return RESP_BAD;
72 } 86 }
73 87
...@@ -75,7 +89,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -75,7 +89,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen)
75 89
76 if (!mailbox_name) 90 if (!mailbox_name)
77 { 91 {
78 snprintf (resp, resplen, "NO Create failed."); 92 *err_text = "NO Create failed.";
79 return RESP_NO; 93 return RESP_NO;
80 } 94 }
81 95
...@@ -105,7 +119,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -105,7 +119,7 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen)
105 119
106 if (status == 0) 120 if (status == 0)
107 { 121 {
108 snprintf (resp, resplen, "Completed"); 122 *err_text = "Completed";
109 return RESP_OK; 123 return RESP_OK;
110 } 124 }
111 125
...@@ -114,6 +128,6 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) ...@@ -114,6 +128,6 @@ imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen)
114 of the text of the tagged NO response. This gives a hint to the 128 of the text of the tagged NO response. This gives a hint to the
115 client that it can attempt a CREATE command and retry the copy if 129 client that it can attempt a CREATE command and retry the copy if
116 the CREATE is successful. */ 130 the CREATE is successful. */
117 snprintf (resp, resplen, "NO [TRYCREATE] failed"); 131 *err_text = "NO [TRYCREATE] failed";
118 return RESP_NONE; 132 return RESP_NONE;
119 } 133 }
......
...@@ -63,25 +63,34 @@ mkdir_p (char *name, int delim) ...@@ -63,25 +63,34 @@ mkdir_p (char *name, int delim)
63 return 0; 63 return 0;
64 } 64 }
65 65
66 /*
67 6.3.3. CREATE Command
68
69 Arguments: mailbox name
70
71 Responses: no specific responses for this command
72
73 Result: OK - create completed
74 NO - create failure: can't create mailbox with that name
75 BAD - command unknown or arguments invalid
76 */
66 /* FIXME: How do we do this ??????: 77 /* FIXME: How do we do this ??????:
67 IF a new mailbox is created with the same name as a mailbox which was 78 IF a new mailbox is created with the same name as a mailbox which was
68 deleted, its unique identifiers MUST be greater than any unique identifiers 79 deleted, its unique identifiers MUST be greater than any unique identifiers
69 used in the previous incarnation of the mailbox. */ 80 used in the previous incarnation of the mailbox. */
70 int 81 int
71 imap4d_create (struct imap4d_command *command, char *arg) 82 imap4d_create (struct imap4d_command *command, imap4d_tokbuf_t tok)
72 { 83 {
73 char *name; 84 char *name;
74 char *sp = NULL;
75 const char *delim = "/"; 85 const char *delim = "/";
76 int isdir = 0; 86 int isdir = 0;
77 int rc = RESP_OK; 87 int rc = RESP_OK;
78 const char *msg = "Completed"; 88 const char *msg = "Completed";
79 89
80 name = util_getword (arg, &sp); 90 if (imap4d_tokbuf_argc (tok) != 3)
81 if (!name) 91 return util_finish (command, RESP_BAD, "Invalid arguments");
82 return util_finish (command, RESP_BAD, "Too few arguments");
83 92
84 util_unquote (&name); 93 name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
85 94
86 if (*name == '\0') 95 if (*name == '\0')
87 return util_finish (command, RESP_BAD, "Too few arguments"); 96 return util_finish (command, RESP_BAD, "Too few arguments");
...@@ -152,6 +161,5 @@ imap4d_create (struct imap4d_command *command, char *arg) ...@@ -152,6 +161,5 @@ imap4d_create (struct imap4d_command *command, char *arg)
152 msg = "already exists"; 161 msg = "already exists";
153 } 162 }
154 163
155 free (name);
156 return util_finish (command, rc, msg); 164 return util_finish (command, rc, msg);
157 } 165 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,20 +19,27 @@ ...@@ -19,20 +19,27 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 * 22 6.3.4. DELETE Command
23 */
24 23
24 Arguments: mailbox name
25
26 Responses: no specific responses for this command
27
28 Result: OK - delete completed
29 NO - delete failure: can't delete mailbox with that name
30 BAD - command unknown or arguments invalid
31 */
25 int 32 int
26 imap4d_delete (struct imap4d_command *command, char *arg) 33 imap4d_delete (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 34 {
28 char *sp = NULL;
29 int rc = RESP_OK; 35 int rc = RESP_OK;
30 const char *msg = "Completed"; 36 const char *msg = "Completed";
31 const char *delim = "/"; 37 const char *delim = "/";
32 char *name; 38 char *name;
33 39
34 name = util_getword (arg, &sp); 40 if (imap4d_tokbuf_argc (tok) != 3)
35 util_unquote (&name); 41 return util_finish (command, RESP_BAD, "Invalid arguments");
42 name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
36 if (!name || *name == '\0') 43 if (!name || *name == '\0')
37 return util_finish (command, RESP_BAD, "Too few arguments"); 44 return util_finish (command, RESP_BAD, "Too few arguments");
38 45
...@@ -51,6 +58,5 @@ imap4d_delete (struct imap4d_command *command, char *arg) ...@@ -51,6 +58,5 @@ imap4d_delete (struct imap4d_command *command, char *arg)
51 rc = RESP_NO; 58 rc = RESP_NO;
52 msg = "Cannot remove"; 59 msg = "Cannot remove";
53 } 60 }
54 free (name);
55 return util_finish (command, rc, msg); 61 return util_finish (command, rc, msg);
56 } 62 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,11 +19,23 @@ ...@@ -19,11 +19,23 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 * copy things from select.c 22 6.3.2. EXAMINE Command
23 */
24 23
24 Arguments: mailbox name
25
26 Responses: REQUIRED untagged responses: FLAGS, EXISTS, RECENT
27 OPTIONAL OK untagged responses: UNSEEN, PERMANENTFLAGS
28
29 Result: OK - examine completed, now in selected state
30 NO - examine failure, now in authenticated state: no
31 such mailbox, can't access mailbox
32 BAD - command unknown or arguments invalid
33 */
25 int 34 int
26 imap4d_examine (struct imap4d_command *command, char *arg) 35 imap4d_examine (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 36 {
28 return imap4d_select0 (command, arg, MU_STREAM_READ); 37 if (imap4d_tokbuf_argc (tok) != 3)
38 return util_finish (command, RESP_BAD, "Invalid arguments");
39 return imap4d_select0 (command, imap4d_tokbuf_getarg (tok, IMAP4_ARG_1),
40 MU_STREAM_READ);
29 } 41 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,16 +19,23 @@ ...@@ -19,16 +19,23 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 * 22 6.4.3. EXPUNGE Command
23 */ 23
24 Arguments: none
25
26 Responses: untagged responses: EXPUNGE
27
28 Result: OK - expunge completed
29 NO - expunge failure: can't expunge (e.g. permission
30 denied)
31 BAD - command unknown or arguments invalid
32 */
24 33
25 int 34 int
26 imap4d_expunge (struct imap4d_command *command, char *arg) 35 imap4d_expunge (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 36 {
28 char *sp = NULL; 37 if (imap4d_tokbuf_argc (tok) != 2)
29 38 return util_finish (command, RESP_BAD, "Invalid arguments");
30 if (util_getword (arg, &sp))
31 return util_finish (command, RESP_NO, "Too many args");
32 39
33 /* FIXME: check for errors. */ 40 /* FIXME: check for errors. */
34 mu_mailbox_expunge (mbox); 41 mu_mailbox_expunge (mbox);
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2006, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2006, 2007,
3 2008 Free Software Foundation, Inc.
3 4
4 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -20,9 +21,6 @@ ...@@ -20,9 +21,6 @@
20 #include <ctype.h> 21 #include <ctype.h>
21 #include <mailutils/argcv.h> 22 #include <mailutils/argcv.h>
22 23
23 /* This will suck, too.
24 Alain: Yes it does. */
25
26 /* Taken from RFC2060 24 /* Taken from RFC2060
27 fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" / 25 fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" /
28 "FAST" / fetch_att / "(" 1#fetch_att ")") 26 "FAST" / fetch_att / "(" 1#fetch_att ")")
...@@ -34,495 +32,93 @@ ...@@ -34,495 +32,93 @@
34 ["<" number "." nz_number ">"] 32 ["<" number "." nz_number ">"]
35 */ 33 */
36 34
37 struct fetch_command; 35 struct fetch_runtime_closure
38
39 static int fetch_all (struct fetch_command *, char**);
40 static int fetch_full (struct fetch_command *, char**);
41 static int fetch_fast (struct fetch_command *, char**);
42 static int fetch_envelope (struct fetch_command *, char**);
43 static int fetch_flags (struct fetch_command *, char**);
44 static int fetch_internaldate (struct fetch_command *, char**);
45 static int fetch_rfc822_header (struct fetch_command *, char**);
46 static int fetch_rfc822_size (struct fetch_command *, char**);
47 static int fetch_rfc822_text (struct fetch_command *, char**);
48 static int fetch_rfc822 (struct fetch_command *, char**);
49 static int fetch_bodystructure (struct fetch_command *, char**);
50 static int fetch_body (struct fetch_command *, char**);
51 static int fetch_uid (struct fetch_command *, char**);
52
53 /* Helper functions. */
54 static int fetch_envelope0 (mu_message_t);
55 static int fetch_bodystructure0 (mu_message_t, int);
56 static int bodystructure (mu_message_t, int);
57 static void send_parameter_list (const char *);
58 static int fetch_operation (mu_message_t, char **, int);
59 static int fetch_message (mu_message_t, unsigned long, unsigned long);
60 static int fetch_header (mu_message_t, unsigned long, unsigned long);
61 static int fetch_body_content (mu_message_t, unsigned long, unsigned long);
62 static int fetch_io (mu_stream_t, unsigned long, unsigned long, unsigned long);
63 static int fetch_header_fields (mu_message_t, char **, unsigned long, unsigned long);
64 static int fetch_header_fields_not (mu_message_t, char **, unsigned long, unsigned long);
65 static int fetch_send_address (const char *);
66
67 static struct fetch_command* fetch_getcommand (char *, struct fetch_command*);
68
69 struct fetch_command
70 { 36 {
71 const char *name; 37 int eltno;
72 int (*func) (struct fetch_command *, char **); 38 size_t msgno;
73 mu_message_t msg; 39 mu_message_t msg;
74 } fetch_command_table [] = 40 char *err_text;
75 {
76 #define F_ALL 0
77 {"ALL", fetch_all, 0},
78 #define F_FULL 1
79 {"FULL", fetch_full, 0},
80 #define F_FAST 2
81 {"FAST", fetch_fast, 0},
82 #define F_ENVELOPE 3
83 {"ENVELOPE", fetch_envelope, 0},
84 #define F_FLAGS 4
85 {"FLAGS", fetch_flags, 0},
86 #define F_INTERNALDATE 5
87 {"INTERNALDATE", fetch_internaldate, 0},
88 #define F_RFC822_HEADER 6
89 {"RFC822.HEADER", fetch_rfc822_header, 0},
90 #define F_RFC822_SIZE 7
91 {"RFC822.SIZE", fetch_rfc822_size, 0},
92 #define F_RFC822_TEXT 8
93 {"RFC822.TEXT", fetch_rfc822_text, 0},
94 #define F_RFC822 9
95 {"RFC822", fetch_rfc822, 0},
96 #define F_BODYSTRUCTURE 10
97 {"BODYSTRUCTURE", fetch_bodystructure, 0},
98 #define F_BODY 11
99 {"BODY", fetch_body, 0},
100 #define F_UID 12
101 {"UID", fetch_uid, 0},
102 { NULL, 0, 0}
103 }; 41 };
104 42
105 /* Go through the fetch array sub command and returns the the structure. */ 43 struct fetch_function_closure;
106
107 static struct fetch_command *
108 fetch_getcommand (char *cmd, struct fetch_command *command_table)
109 {
110 size_t i, len = strlen (cmd);
111 44
112 for (i = 0; command_table[i].name != 0; i++) 45 typedef int (*fetch_function_t) (struct fetch_function_closure *,
113 { 46 struct fetch_runtime_closure *);
114 if (strlen (command_table[i].name) == len &&
115 !strcasecmp (command_table[i].name, cmd))
116 return &command_table[i];
117 }
118 return NULL;
119 }
120 47
121 /* The FETCH command retrieves data associated with a message in the 48 struct fetch_function_closure
122 mailbox. The data items to be fetched can be either a single atom
123 or a parenthesized list. */
124 int
125 imap4d_fetch (struct imap4d_command *command, char *arg)
126 { 49 {
127 int rc; 50 fetch_function_t fun; /* Handler function */
128 char buffer[64]; 51 const char *name; /* Response tag */
129 52 size_t *section_part; /* Section-part */
130 rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer); 53 size_t nset; /* Number of elements in section_part */
131 return util_finish (command, rc, "%s", buffer); 54 int peek;
132 } 55 int not; /* Negate header set */
56 mu_list_t headers; /* Headers */
57 size_t start; /* Substring start */
58 size_t size; /* Substring length */
59 };
133 60
134 /* Where the real implementation is. It is here since UID command also 61
135 calls FETCH. */ 62 static int
136 int 63 fetch_send_address (const char *addr)
137 imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
138 { 64 {
139 struct fetch_command *fcmd = NULL; 65 mu_address_t address;
140 int rc = RESP_OK; 66 size_t i, count = 0;
141 char *sp = NULL;
142 char *msgset;
143 size_t *set = NULL;
144 int n = 0;
145 int i;
146 int status;
147 67
148 msgset = util_getword (arg, &sp); 68 /* Short circuit. */
149 if (!msgset || !sp || *sp == '\0') 69 if (addr == NULL || *addr == '\0')
150 { 70 {
151 snprintf (resp, resplen, "Too few args"); 71 util_send ("NIL");
152 return RESP_BAD; 72 return RESP_OK;
153 } 73 }
154 74
155 /* Get the message numbers in set[]. */ 75 mu_address_create (&address, addr);
156 status = util_msgset (msgset, &set, &n, isuid); 76 mu_address_get_count (address, &count);
157 if (status != 0)
158 {
159 snprintf (resp, resplen, "Bogus number set");
160 return RESP_BAD;
161 }
162 77
163 /* Prepare status code. It will be replaced if an error occurs in the 78 /* We failed: can't parse. */
164 loop below */ 79 if (count == 0)
165 snprintf (resp, resplen, "Completed");
166
167 for (i = 0; i < n && rc == RESP_OK; i++)
168 { 80 {
169 size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; 81 util_send ("NIL");
170 mu_message_t msg = NULL; 82 return RESP_OK;
171
172 if (msgno && mu_mailbox_get_message (mbox, msgno, &msg) == 0)
173 {
174 char item[32];
175 char *items = strdup (sp);
176 char *p = items;
177 int space = 0;
178
179 fcmd = NULL;
180 util_send ("* %s FETCH (", mu_umaxtostr (0, msgno));
181 item[0] = '\0';
182 /* Server implementations MUST implicitly
183 include the UID message data item as part of any FETCH
184 response caused by a UID command, regardless of whether
185 a UID was specified as a message data item to the FETCH. */
186 if (isuid)
187 {
188 fcmd = &fetch_command_table[F_UID];
189 fcmd->msg = msg;
190 rc = fetch_uid (fcmd, &items);
191 }
192 /* Get the fetch command names. */
193 while (*items && *items != ')')
194 {
195 util_token (item, sizeof (item), &items);
196 /* Do not send the UID again. */
197 if (isuid && strcasecmp (item, "UID") == 0)
198 continue;
199 if (fcmd)
200 space = 1;
201 /* Search in the table. */
202 fcmd = fetch_getcommand (item, fetch_command_table);
203 if (fcmd)
204 {
205 if (space)
206 {
207 util_send (" ");
208 space = 0;
209 }
210 fcmd->msg = msg;
211 rc = fcmd->func (fcmd, &items);
212 }
213 }
214 util_send (")\r\n");
215 free (p);
216 }
217 else if (!isuid)
218 /* According to RFC 3501, "A non-existent unique identifier is
219 ignored without any error message generated." */
220 {
221 snprintf (resp, resplen,
222 "Bogus message set: message number out of range");
223 rc = RESP_BAD;
224 break;
225 }
226 } 83 }
227 free (set);
228 return rc;
229 }
230
231 /* ALL:
232 Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
233 Combination of FAST and ENVELOPE. */
234 static int
235 fetch_all (struct fetch_command *command, char **arg)
236 {
237 struct fetch_command c_env = fetch_command_table[F_ENVELOPE];
238 fetch_fast (command, arg);
239 util_send (" ");
240 c_env.msg = command->msg;
241 fetch_envelope (&c_env, arg);
242 return RESP_OK;
243 }
244
245 /* FULL:
246 Macro equivalent to: (FLAGS INTERNALDATE
247 RFC822.SIZE ENVELOPE BODY).
248 Combination of (ALL BODY). */
249 static int
250 fetch_full (struct fetch_command *command, char **arg)
251 {
252 struct fetch_command c_body = fetch_command_table[F_BODY];
253 fetch_all (command, arg);
254 util_send (" ");
255 c_body.msg = command->msg;
256 return fetch_body (&c_body, arg);
257 }
258
259 /* FAST:
260 Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)
261 Combination of (FLAGS INTERNALDATE RFC822.SIZE). */
262 static int
263 fetch_fast (struct fetch_command *command, char **arg)
264 {
265 struct fetch_command c_idate = fetch_command_table[F_INTERNALDATE];
266 struct fetch_command c_rfc = fetch_command_table[F_RFC822_SIZE];
267 struct fetch_command c_flags = fetch_command_table[F_FLAGS];
268 c_flags.msg = command->msg;
269 fetch_flags (&c_flags, arg);
270 util_send (" ");
271 c_idate.msg = command->msg;
272 fetch_internaldate (&c_idate, arg);
273 util_send (" ");
274 c_rfc.msg = command->msg;
275 fetch_rfc822_size (&c_rfc, arg);
276 return RESP_OK;
277 }
278
279 /* ENVELOPE:
280 Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To,
281 and Message-Id. */
282 static int
283 fetch_envelope (struct fetch_command *command, char **arg MU_ARG_UNUSED)
284 {
285 int status;
286 util_send ("%s (", command->name);
287 status = fetch_envelope0 (command->msg);
288 util_send (")");
289 return status;
290 }
291
292 /* FLAGS: The flags that are set for this message. */
293 /* FIXME: User flags not done. If enable change the PERMANENTFLAGS in SELECT */
294 void
295 fetch_flags0 (const char *prefix, mu_message_t msg, int isuid)
296 {
297 mu_attribute_t attr = NULL;
298 84
299 mu_message_get_attribute (msg, &attr); 85 util_send ("(");
300 if (isuid) 86 for (i = 1; i <= count; i++)
301 { 87 {
302 struct fetch_command *fcmd = &fetch_command_table[F_UID]; 88 const char *str;
303 fcmd->msg = msg; 89 int is_group = 0;
304 fetch_uid (fcmd, NULL);
305 util_send (" ");
306 }
307 util_send ("%s (", prefix);
308 util_print_flags(attr);
309 util_send (")");
310 }
311
312 static int
313 fetch_flags (struct fetch_command *command, char **arg)
314 {
315 fetch_flags0 (command->name, command->msg, 0);
316 return RESP_OK;
317 }
318
319
320 /* INTERNALDATE The internal date of the message.
321 Format:
322
323 date_time ::= <"> date_day_fixed "-" date_month "-" date_year
324 SPACE time SPACE zone <">
325
326 date_day ::= 1*2digit
327 ;; Day of month
328
329 date_day_fixed ::= (SPACE digit) / 2digit
330 ;; Fixed-format version of date_day
331
332 date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
333 "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
334
335 date_text ::= date_day "-" date_month "-" date_year
336
337 date_year ::= 4digit
338 90
339 time ::= 2digit ":" 2digit ":" 2digit 91 util_send ("(");
340 ;; Hours minutes seconds
341 92
342 zone ::= ("+" / "-") 4digit 93 mu_address_sget_personal (address, i, &str);
343 ;; Signed four-digit value of hhmm representing 94 util_send_qstring (str);
344 ;; hours and minutes west of Greenwich (that is, 95 util_send (" ");
345 ;; (the amount that the given time differs from
346 ;; Universal Time). Subtracting the timezone
347 ;; from the given time will give the UT form.
348 ;; The Universal Time zone is "+0000". */
349 static int
350 fetch_internaldate (struct fetch_command *command, char **arg MU_ARG_UNUSED)
351 {
352 const char *date;
353 mu_envelope_t env = NULL;
354 struct tm tm, *tmp = NULL;
355 mu_timezone tz;
356 char datebuf[sizeof ("13-Jul-2002 00:00:00")];
357 96
358 mu_message_get_envelope (command->msg, &env); 97 mu_address_sget_route (address, i, &str);
359 if (mu_envelope_sget_date (env, &date) == 0 98 util_send_qstring (str);
360 && mu_parse_ctime_date_time (&date, &tm, &tz) == 0)
361 tmp = &tm;
362 else
363 {
364 time_t t = time (NULL);
365 tmp = localtime (&t);
366 }
367 mu_strftime (datebuf, sizeof (datebuf), "%d-%b-%Y %H:%M:%S", tmp);
368 util_send ("%s", command->name);
369 util_send (" \"%s +0000\"", datebuf);
370 return RESP_OK;
371 }
372 99
373 /* 100 util_send (" ");
374 RFC822.HEADER:
375 Functionally equivalent to BODY.PEEK[HEADER], differing in the syntax of
376 the resulting untagged FETCH data (RFC822.HEADER is returned). */
377 static int
378 fetch_rfc822_header (struct fetch_command *command, char **arg MU_ARG_UNUSED)
379 {
380 char buffer[32];
381 char *p = buffer;
382 101
383 strcpy (buffer, ".PEEK[HEADER]"); 102 mu_address_is_group (address, i, &is_group);
384 return fetch_body (command, &p); 103 str = NULL;
385 } 104 if (is_group)
105 mu_address_sget_personal (address, i, &str);
106 else
107 mu_address_sget_local_part (address, i, &str);
386 108
387 /* RFC822.TEXT: 109 util_send_qstring (str);
388 Functionally equivalent to BODY[TEXT], differing in the syntax of the
389 resulting untagged FETCH data (RFC822.TEXT is returned). */
390 static int
391 fetch_rfc822_text (struct fetch_command *command, char **arg MU_ARG_UNUSED)
392 {
393 char buffer[16];
394 char *p = buffer;
395 110
396 strcpy (buffer, "[TEXT]"); 111 util_send (" ");
397 return fetch_body (command, &p);
398 }
399 112
400 /* The [RFC-822] size of the message. */ 113 mu_address_sget_domain (address, i, &str);
401 static int 114 util_send_qstring (str);
402 fetch_rfc822_size (struct fetch_command *command, char **arg MU_ARG_UNUSED)
403 {
404 size_t size = 0;
405 size_t lines = 0;
406
407 mu_message_size (command->msg, &size);
408 mu_message_lines (command->msg, &lines);
409 util_send ("%s %u", command->name, size + lines);
410 return RESP_OK;
411 }
412 115
413 /* RFC822: 116 util_send (")");
414 Functionally equivalent to BODY[], differing in the syntax of the
415 resulting untagged FETCH data (RFC822 is returned). */
416 static int
417 fetch_rfc822 (struct fetch_command *command, char **arg)
418 {
419 if (**arg == '.')
420 {
421 /* We have to catch the other RFC822.XXX commands here. This is because
422 util_token() in imap4d_fetch0 will return the RFC822 token only. */
423 if (strncasecmp (*arg, ".SIZE", 5) == 0)
424 {
425 struct fetch_command c_rfc= fetch_command_table[F_RFC822_SIZE];
426 c_rfc.msg = command->msg;
427 (*arg) += 5;
428 fetch_rfc822_size (&c_rfc, arg);
429 }
430 else if (strncasecmp (*arg, ".TEXT", 5) == 0)
431 {
432 struct fetch_command c_rfc = fetch_command_table[F_RFC822_TEXT];
433 c_rfc.msg = command->msg;
434 (*arg) += 5;
435 fetch_rfc822_text (&c_rfc, arg);
436 }
437 else if (strncasecmp (*arg, ".HEADER", 7) == 0)
438 {
439 struct fetch_command c_rfc = fetch_command_table[F_RFC822_HEADER];
440 c_rfc.msg = command->msg;
441 (*arg) += 7;
442 fetch_rfc822_header (&c_rfc, arg);
443 }
444 }
445 else
446 {
447 char buffer[16];
448 char *p = buffer;
449 strcpy (buffer, "[]");
450 fetch_body (command, &p);
451 } 117 }
452 return RESP_OK;
453 }
454
455 /* UID: The unique identifier for the message. */
456 static int
457 fetch_uid (struct fetch_command *command, char **arg MU_ARG_UNUSED)
458 {
459 size_t uid = 0;
460
461 mu_message_get_uid (command->msg, &uid);
462 util_send ("%s %s", command->name, mu_umaxtostr (0, uid));
463 return RESP_OK;
464 }
465
466 /* BODYSTRUCTURE:
467 The [MIME-IMB] body structure of the message. This is computed by the
468 server by parsing the [MIME-IMB] header fields in the [RFC-822] header and
469 [MIME-IMB] headers. */
470 static int
471 fetch_bodystructure (struct fetch_command *command, char **arg MU_ARG_UNUSED)
472 {
473 util_send ("%s (", command->name);
474 fetch_bodystructure0 (command->msg, 1); /* 1 means with extension data. */
475 util_send (")"); 118 util_send (")");
476 return RESP_OK; 119 return RESP_OK;
477 } 120 }
478 121
479 /* BODY: Non-extensible form of BODYSTRUCTURE.
480 BODY[<section>]<<partial>> :
481 The text of a particular body section. The section specification is a set
482 of zero or more part specifiers delimited by periods. A part specifier
483 is either a part number or one of the following: HEADER, HEADER.FIELDS,
484 HEADER.FIELDS.NOT, MIME, and TEXT. An empty section specification refers
485 to the entire message, including the header.
486
487 Note: for body section, the \Seen flag is implicitly set;
488 if this causes the flags to change they SHOULD be
489 included as part of the FETCH responses. */
490 static int
491 fetch_body (struct fetch_command *command, char **arg)
492 {
493 /* It's body section, set the message as seen */
494 if (**arg == '[')
495 {
496 mu_attribute_t attr = NULL;
497 mu_message_get_attribute (command->msg, &attr);
498 if (!mu_attribute_is_read (attr))
499 {
500 util_send ("FLAGS (\\Seen) ");
501 mu_attribute_set_read (attr);
502 }
503 }
504 else if (strncasecmp (*arg,".PEEK", 5) == 0)
505 {
506 /* Move pass the .peek */
507 (*arg) += 5;
508 while (isspace ((unsigned)**arg))
509 (*arg)++;
510 }
511 else if (**arg != '[' && **arg != '.')
512 {
513 /* Call body structure without the extension. */
514 util_send ("%s (", command->name);
515 fetch_bodystructure0 (command->msg, 0);
516 util_send (")");
517 return RESP_OK;
518 }
519 util_send ("%s", command->name);
520 return fetch_operation (command->msg, arg,
521 strcasecmp (command->name, "BODY"));
522 }
523
524 /* Helper Functions: Where the Beef is. */
525
526 static void 122 static void
527 fetch_send_header_value (mu_header_t header, const char *name, 123 fetch_send_header_value (mu_header_t header, const char *name,
528 const char *defval, int space) 124 const char *defval, int space)
...@@ -543,25 +139,6 @@ fetch_send_header_value (mu_header_t header, const char *name, ...@@ -543,25 +139,6 @@ fetch_send_header_value (mu_header_t header, const char *name,
543 } 139 }
544 140
545 static void 141 static void
546 fetch_send_header_list (mu_header_t header, const char *name,
547 const char *defval, int space)
548 {
549 char *buffer;
550
551 if (space)
552 util_send (" ");
553 if (mu_header_aget_value (header, name, &buffer) == 0)
554 {
555 send_parameter_list (buffer);
556 free (buffer);
557 }
558 else if (defval)
559 send_parameter_list (defval);
560 else
561 util_send ("NIL");
562 }
563
564 static void
565 fetch_send_header_address (mu_header_t header, const char *name, 142 fetch_send_header_address (mu_header_t header, const char *name,
566 const char *defval, int space) 143 const char *defval, int space)
567 { 144 {
...@@ -578,6 +155,101 @@ fetch_send_header_address (mu_header_t header, const char *name, ...@@ -578,6 +155,101 @@ fetch_send_header_address (mu_header_t header, const char *name,
578 fetch_send_address (defval); 155 fetch_send_address (defval);
579 } 156 }
580 157
158 /* Send parameter list for the bodystructure. */
159 static void
160 send_parameter_list (const char *buffer)
161 {
162 int argc = 0;
163 char **argv;
164
165 if (!buffer)
166 {
167 util_send ("NIL");
168 return;
169 }
170
171 mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
172
173 if (argc == 0)
174 util_send ("NIL");
175 else
176 {
177 char *p;
178
179 util_send ("(");
180
181 p = argv[0];
182 util_send_qstring (p);
183
184 if (argc > 1)
185 {
186 int i, space = 0;
187 char *lvalue = NULL;
188
189 util_send ("(");
190 for (i = 1; i < argc; i++)
191 {
192 if (lvalue)
193 {
194 if (space)
195 util_send (" ");
196 util_send_qstring (lvalue);
197 lvalue = NULL;
198 space = 1;
199 }
200
201 switch (argv[i][0])
202 {
203 case ';':
204 continue;
205
206 case '=':
207 if (++i < argc)
208 {
209 char *p = argv[i];
210 util_send (" ");
211 util_send_qstring (p);
212 }
213 break;
214
215 default:
216 lvalue = argv[i];
217 }
218 }
219 if (lvalue)
220 {
221 if (space)
222 util_send (" ");
223 util_send_qstring (lvalue);
224 }
225 util_send (")");
226 }
227 else
228 util_send (" NIL");
229 util_send (")");
230 }
231 mu_argcv_free (argc, argv);
232 }
233
234 static void
235 fetch_send_header_list (mu_header_t header, const char *name,
236 const char *defval, int space)
237 {
238 char *buffer;
239
240 if (space)
241 util_send (" ");
242 if (mu_header_aget_value (header, name, &buffer) == 0)
243 {
244 send_parameter_list (buffer);
245 free (buffer);
246 }
247 else if (defval)
248 send_parameter_list (defval);
249 else
250 util_send ("NIL");
251 }
252
581 /* ENVELOPE: 253 /* ENVELOPE:
582 The envelope structure of the message. This is computed by the server by 254 The envelope structure of the message. This is computed by the server by
583 parsing the [RFC-822] header into the component parts, defaulting various 255 parsing the [RFC-822] header into the component parts, defaulting various
...@@ -616,139 +288,6 @@ fetch_envelope0 (mu_message_t msg) ...@@ -616,139 +288,6 @@ fetch_envelope0 (mu_message_t msg)
616 return RESP_OK; 288 return RESP_OK;
617 } 289 }
618 290
619 /* The beef BODYSTRUCTURE.
620 A parenthesized list that describes the [MIME-IMB] body structure of a
621 message. Multiple parts are indicated by parenthesis nesting. Instead of
622 a body type as the first element of the parenthesized list there is a nested
623 body. The second element of the parenthesized list is the multipart
624 subtype (mixed, digest, parallel, alternative, etc.).
625
626 The extension data of a multipart body part are in the following order:
627 body parameter parenthesized list:
628 A parenthesized list of attribute/value pairs [e.g. ("foo" "bar" "baz"
629 "rag") where "bar" is the value of "foo" and "rag" is the value of
630 "baz"] as defined in [MIME-IMB].
631
632 body disposition:
633 A parenthesized list, consisting of a disposition type string followed by a
634 parenthesized list of disposition attribute/value pairs. The disposition
635 type and attribute names will be defined in a future standards-track
636 revision to [DISPOSITION].
637
638 body language:
639 A string or parenthesized list giving the body language value as defined
640 in [LANGUAGE-TAGS]. */
641 static int
642 fetch_bodystructure0 (mu_message_t message, int extension)
643 {
644 size_t nparts = 1;
645 size_t i;
646 int is_multipart = 0;
647
648 mu_message_is_multipart (message, &is_multipart);
649 if (is_multipart)
650 {
651 char *buffer = NULL;
652 mu_header_t header = NULL;
653
654 mu_message_get_num_parts (message, &nparts);
655
656 /* Get all the sub messages. */
657 for (i = 1; i <= nparts; i++)
658 {
659 mu_message_t msg = NULL;
660 mu_message_get_part (message, i, &msg);
661 util_send ("(");
662 fetch_bodystructure0 (msg, extension);
663 util_send (")");
664 } /* for () */
665
666 mu_message_get_header (message, &header);
667
668
669 /* The subtype. */
670 if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
671 {
672 int argc = 0;
673 char **argv;
674 char *s;
675
676 mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
677
678 s = strchr (argv[0], '/');
679 if (s)
680 s++;
681 util_send (" ");
682 util_send_qstring (s);
683
684 /* The extension data for multipart. */
685 if (extension)
686 {
687 int space = 0;
688 char *lvalue = NULL;
689
690 util_send (" (");
691 for (i = 1; i < argc; i++)
692 {
693 /* body parameter parenthesized list:
694 Content-type parameter list. */
695 if (lvalue)
696 {
697 if (space)
698 util_send (" ");
699 util_send_qstring (lvalue);
700 lvalue = NULL;
701 space = 1;
702 }
703
704 switch (argv[i][0])
705 {
706 case ';':
707 continue;
708
709 case '=':
710 if (++i < argc)
711 {
712 char *p = argv[i];
713 util_send (" ");
714 util_unquote (&p);
715 util_send_qstring (p);
716 }
717 break;
718
719 default:
720 lvalue = argv[i];
721 }
722 }
723 if (lvalue)
724 {
725 if (space)
726 util_send (" ");
727 util_send_qstring (lvalue);
728 }
729 util_send (")");
730 }
731 else
732 util_send (" NIL");
733 mu_argcv_free (argc, argv);
734 free (buffer);
735 }
736 else
737 /* No content-type header */
738 util_send (" NIL");
739
740 /* body disposition: Content-Disposition. */
741 fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION,
742 NULL, 1);
743 /* body language: Content-Language. */
744 fetch_send_header_list (header, MU_HEADER_CONTENT_LANGUAGE,
745 NULL, 1);
746 }
747 else
748 bodystructure (message, extension);
749 return RESP_OK;
750 }
751
752 /* The basic fields of a non-multipart body part are in the following order: 291 /* The basic fields of a non-multipart body part are in the following order:
753 body type: 292 body type:
754 A string giving the content media type name as defined in [MIME-IMB]. 293 A string giving the content media type name as defined in [MIME-IMB].
...@@ -857,7 +396,6 @@ bodystructure (mu_message_t msg, int extension) ...@@ -857,7 +396,6 @@ bodystructure (mu_message_t msg, int extension)
857 { 396 {
858 char *p = argv[i]; 397 char *p = argv[i];
859 util_send (" "); 398 util_send (" ");
860 util_unquote (&p);
861 util_send_qstring (p); 399 util_send_qstring (p);
862 } 400 }
863 break; 401 break;
...@@ -955,195 +493,187 @@ bodystructure (mu_message_t msg, int extension) ...@@ -955,195 +493,187 @@ bodystructure (mu_message_t msg, int extension)
955 return RESP_OK; 493 return RESP_OK;
956 } 494 }
957 495
958 static int 496 /* The beef BODYSTRUCTURE.
959 fetch_operation (mu_message_t msg, char **arg, int silent) 497 A parenthesized list that describes the [MIME-IMB] body structure of a
960 { 498 message. Multiple parts are indicated by parenthesis nesting. Instead of
961 unsigned long start = ULONG_MAX; /* No starting offset. */ 499 a body type as the first element of the parenthesized list there is a nested
962 unsigned long end = ULONG_MAX; /* No limit. */ 500 body. The second element of the parenthesized list is the multipart
963 char *section; /* Hold the section number string. */ 501 subtype (mixed, digest, parallel, alternative, etc.).
964 char *partial = strchr (*arg, '<');
965 int rc;
966
967 /* Check for section specific offset. */
968 if (partial)
969 {
970 /* NOTE: should this should be move in imap4d_fetch() and have a more
971 draconian check? */
972 *partial = '\0';
973 partial++;
974 start = strtoul (partial, &partial, 10);
975 if (*partial == '.')
976 {
977 partial++;
978 end = strtoul (partial, NULL, 10);
979 }
980 }
981
982 /* Pass the first bracket '[' */
983 (*arg)++;
984 section = *arg;
985 502
986 /* Retreive the section message. */ 503 The extension data of a multipart body part are in the following order:
987 while (isdigit ((unsigned)**arg)) 504 body parameter parenthesized list:
988 { 505 A parenthesized list of attribute/value pairs [e.g. ("foo" "bar" "baz"
989 unsigned long j = strtoul (*arg, arg, 10); 506 "rag") where "bar" is the value of "foo" and "rag" is the value of
990 int status; 507 "baz"] as defined in [MIME-IMB].
991 508
992 /* Wrong section message number bail out. */ 509 body disposition:
993 if (j == 0 || j == ULONG_MAX) /* Technical: I should check errno too. */ 510 A parenthesized list, consisting of a disposition type string followed by a
994 break; 511 parenthesized list of disposition attribute/value pairs. The disposition
512 type and attribute names will be defined in a future standards-track
513 revision to [DISPOSITION].
995 514
996 /* If the section message did not exist bail out here. */ 515 body language:
997 status = mu_message_get_part (msg, j, &msg); 516 A string or parenthesized list giving the body language value as defined
998 if (status != 0) 517 in [LANGUAGE-TAGS]. */
999 { 518 static int
1000 util_send (" \"\""); 519 fetch_bodystructure0 (mu_message_t message, int extension)
1001 return RESP_OK; 520 {
1002 } 521 size_t nparts = 1;
1003 if (**arg == '.') 522 size_t i;
1004 (*arg)++; 523 int is_multipart = 0;
1005 else
1006 break;
1007 }
1008 524
1009 /* Did we have a section message? */ 525 mu_message_is_multipart (message, &is_multipart);
1010 if (((*arg) - section) > 0) 526 if (is_multipart)
1011 { 527 {
1012 char *p = section; 528 char *buffer = NULL;
1013 section = calloc ((*arg) - p + 1, 1); 529 mu_header_t header = NULL;
1014 if (section)
1015 memcpy (section, p, (*arg) - p);
1016 }
1017 else
1018 section = calloc (1, 1);
1019 530
1020 rc = RESP_OK; 531 mu_message_get_num_parts (message, &nparts);
1021 532
1022 /* Choose the right fetch attribute. */ 533 /* Get all the sub messages. */
1023 if (*section == '\0' && **arg == ']') 534 for (i = 1; i <= nparts; i++)
1024 { 535 {
1025 if (!silent) 536 mu_message_t msg = NULL;
1026 util_send ("[]"); 537 mu_message_get_part (message, i, &msg);
1027 (*arg)++; 538 util_send ("(");
1028 rc = fetch_message (msg, start, end); 539 fetch_bodystructure0 (msg, extension);
1029 } 540 util_send (")");
1030 else if (strncasecmp (*arg, "HEADER]", 7) == 0) 541 } /* for () */
1031 { 542
1032 if (!silent) 543 mu_message_get_header (message, &header);
1033 { 544
1034 /* NOTE: We violate the RFC here: Header cannot take a prefix for 545
1035 section messages it only referes to the RFC822 header .. ok 546 /* The subtype. */
1036 see it as an extension. But according to IMAP4 we should 547 if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
1037 have send an empty string: util_send (" \"\"");
1038 */
1039 util_send ("[%sHEADER]", section);
1040 }
1041 (*arg) += 7;
1042 rc = fetch_header (msg, start, end);
1043 }
1044 else if (strncasecmp (*arg, "MIME]", 5) == 0)
1045 {
1046 if (!silent)
1047 { 548 {
1048 if (*section) 549 int argc = 0;
1049 util_send ("[%sMIME]", section); 550 char **argv;
551 char *s;
552
553 mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
554
555 s = strchr (argv[0], '/');
556 if (s)
557 s++;
558 util_send (" ");
559 util_send_qstring (s);
560
561 /* The extension data for multipart. */
562 if (extension)
563 {
564 int space = 0;
565 char *lvalue = NULL;
566
567 util_send (" (");
568 for (i = 1; i < argc; i++)
569 {
570 /* body parameter parenthesized list:
571 Content-type parameter list. */
572 if (lvalue)
573 {
574 if (space)
575 util_send (" ");
576 util_send_qstring (lvalue);
577 lvalue = NULL;
578 space = 1;
579 }
580
581 switch (argv[i][0])
582 {
583 case ';':
584 continue;
585
586 case '=':
587 if (++i < argc)
588 {
589 char *p = argv[i];
590 util_send (" ");
591 util_send_qstring (p);
592 }
593 break;
594
595 default:
596 lvalue = argv[i];
597 }
598 }
599 if (lvalue)
600 {
601 if (space)
602 util_send (" ");
603 util_send_qstring (lvalue);
604 }
605 util_send (")");
606 }
1050 else 607 else
1051 util_send ("[%s", *arg); 608 util_send (" NIL");
609 mu_argcv_free (argc, argv);
610 free (buffer);
1052 } 611 }
1053 (*arg) += 5;
1054 rc = fetch_header (msg, start, end);
1055 }
1056 else if (strncasecmp (*arg, "HEADER.FIELDS.NOT", 17) == 0)
1057 {
1058 /* NOTE: we should flag an error if section is not empty: accept
1059 as an extension for now. */
1060 if (*section)
1061 util_send ("[%s", section);
1062 else
1063 util_send ("[");
1064 (*arg) += 17;
1065 rc = fetch_header_fields_not (msg, arg, start, end);
1066 }
1067 else if (strncasecmp (*arg, "HEADER.FIELDS", 13) == 0)
1068 {
1069 /* NOTE: we should flag an error if section is not empty: accept
1070 as an extension for now. */
1071 if (*section)
1072 util_send ("[%s", section);
1073 else 612 else
1074 util_send ("["); 613 /* No content-type header */
1075 (*arg) += 13; 614 util_send (" NIL");
1076 rc = fetch_header_fields (msg, arg, start, end); 615
616 /* body disposition: Content-Disposition. */
617 fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION,
618 NULL, 1);
619 /* body language: Content-Language. */
620 fetch_send_header_list (header, MU_HEADER_CONTENT_LANGUAGE,
621 NULL, 1);
1077 } 622 }
623 else
624 bodystructure (message, extension);
625 return RESP_OK;
626 }
1078 627
1079 else if (strncasecmp (*arg, "TEXT]", 5) == 0) 628 static void
629 set_seen (struct fetch_function_closure *ffc,
630 struct fetch_runtime_closure *frt)
631 {
632 if (!ffc->peek)
1080 { 633 {
1081 if (!silent) 634 mu_attribute_t attr = NULL;
635 mu_message_get_attribute (frt->msg, &attr);
636 if (!mu_attribute_is_read (attr))
1082 { 637 {
1083 if (*section) 638 util_send ("FLAGS (\\Seen) ");
1084 util_send ("[%sTEXT]", section); 639 mu_attribute_set_read (attr);
1085 else
1086 util_send ("[TEXT]");
1087 } 640 }
1088 (*arg) += 5;
1089 rc = fetch_body_content (msg, start, end);
1090 }
1091 else if (**arg == ']')
1092 {
1093 if (!silent)
1094 util_send ("[%s]", section);
1095 (*arg)++;
1096 rc = fetch_body_content (msg, start, end);
1097 }
1098 else
1099 {
1100 util_send (" \"\"");/*FIXME: ERROR Message!*/
1101 rc = RESP_BAD;
1102 } 641 }
1103 free (section);
1104 return rc;
1105 } 642 }
1106 643
1107 static int 644 static mu_message_t
1108 fetch_message (mu_message_t msg, unsigned long start, unsigned long end) 645 fetch_get_part (struct fetch_function_closure *ffc,
646 struct fetch_runtime_closure *frt)
1109 { 647 {
1110 mu_stream_t stream = NULL; 648 mu_message_t msg = frt->msg;
1111 size_t size = 0, lines = 0; 649 size_t i;
1112 mu_message_get_stream (msg, &stream);
1113 mu_message_size (msg, &size);
1114 mu_message_lines (msg, &lines);
1115 return fetch_io (stream, start, end, size + lines);
1116 }
1117 650
1118 static int 651 for (i = 0; i < ffc->nset; i++)
1119 fetch_header (mu_message_t msg, unsigned long start, unsigned long end) 652 if (mu_message_get_part (msg, ffc->section_part[i], &msg))
1120 { 653 return NULL;
1121 mu_header_t header = NULL; 654 return msg;
1122 mu_stream_t stream = NULL;
1123 size_t size = 0, lines = 0;
1124 mu_message_get_header (msg, &header);
1125 mu_header_size (header, &size);
1126 mu_header_lines (header, &lines);
1127 mu_header_get_stream (header, &stream);
1128 return fetch_io (stream, start, end, size + lines);
1129 } 655 }
1130 656
1131 static int 657 static void
1132 fetch_body_content (mu_message_t msg, unsigned long start, unsigned long end) 658 fetch_send_section_part (struct fetch_function_closure *ffc,
659 const char *prefix, const char *suffix)
1133 { 660 {
1134 mu_body_t body = NULL; 661 int i;
1135 mu_stream_t stream = NULL; 662
1136 size_t size = 0, lines = 0; 663 util_send ("%s", prefix);
1137 mu_message_get_body (msg, &body); 664 for (i = 0; i < ffc->nset; i++)
1138 mu_body_size (body, &size); 665 {
1139 mu_body_lines (body, &lines); 666 if (i)
1140 mu_body_get_stream (body, &stream); 667 util_send (".");
1141 return fetch_io (stream, start, end, size + lines); 668 util_send ("%lu", (unsigned long) ffc->section_part[i]);
669 }
670 if (i && suffix[0] != ']')
671 util_send (".");
672 util_send ("%s", suffix);
1142 } 673 }
1143 674
1144 static int 675 static int
1145 fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, 676 fetch_io (mu_stream_t stream, size_t start, size_t size, size_t max)
1146 unsigned long max)
1147 { 677 {
1148 mu_stream_t rfc = NULL; 678 mu_stream_t rfc = NULL;
1149 size_t n = 0; 679 size_t n = 0;
...@@ -1151,25 +681,26 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, ...@@ -1151,25 +681,26 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end,
1151 681
1152 mu_filter_create (&rfc, stream, "rfc822", MU_FILTER_ENCODE, MU_STREAM_READ); 682 mu_filter_create (&rfc, stream, "rfc822", MU_FILTER_ENCODE, MU_STREAM_READ);
1153 683
1154 if (start == ULONG_MAX || end == ULONG_MAX) 684 if (start == 0 && size == (size_t) -1)
1155 { 685 {
1156 char buffer[512]; 686 char buffer[512];
1157 offset = 0; 687 offset = 0;
1158 if (max) 688 if (max)
1159 { 689 {
1160 util_send (" {%lu}\r\n", max); 690 util_send (" {%lu}\r\n", (unsigned long) max);
1161 while (mu_stream_read (rfc, buffer, sizeof (buffer) - 1, offset, 691 while (mu_stream_read (rfc, buffer, sizeof (buffer) - 1, offset,
1162 &n) == 0 && n > 0) 692 &n) == 0 && n > 0)
1163 { 693 {
1164 buffer[n] = '\0'; 694 buffer[n] = '\0';
1165 util_send ("%s", buffer); 695 util_send ("%s", buffer);
1166 offset += n; 696 offset += n;
1167 } 697 }
698 /* FIXME: Make sure exactly max bytes were sent */
1168 } 699 }
1169 else 700 else
1170 util_send (" \"\""); 701 util_send (" \"\"");
1171 } 702 }
1172 else if (end + 2 < end) /* Check for integer overflow */ 703 else if (size + 2 < size) /* Check for integer overflow */
1173 { 704 {
1174 return RESP_BAD; 705 return RESP_BAD;
1175 } 706 }
...@@ -1178,393 +709,944 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, ...@@ -1178,393 +709,944 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end,
1178 char *buffer, *p; 709 char *buffer, *p;
1179 size_t total = 0; 710 size_t total = 0;
1180 offset = start; 711 offset = start;
1181 p = buffer = calloc (end + 2, 1); 712 p = buffer = malloc (size + 1);
1182 while (end > 0 713 if (!p)
1183 && mu_stream_read (rfc, buffer, end + 1, offset, &n) == 0 && n > 0) 714 imap4d_bye (ERR_NO_MEM);
715
716 while (total < size
717 && mu_stream_read (rfc, p, size - total + 1, offset, &n) == 0
718 && n > 0)
1184 { 719 {
1185 offset += n; 720 offset += n;
1186 total += n; 721 total += n;
1187 end -= n; 722 p += n;
1188 buffer += n;
1189 } 723 }
1190 /* Make sure we null terminate. */ 724 *p = 0;
1191 *buffer = '\0'; 725 util_send ("<%lu>", (unsigned long) start);
1192 util_send ("<%lu>", start);
1193 if (total) 726 if (total)
1194 { 727 {
1195 util_send (" {%s}\r\n", mu_umaxtostr (0, total)); 728 util_send (" {%lu}\r\n", (unsigned long) total);
1196 util_send ("%s", p); 729 util_send ("%s", buffer);
1197 } 730 }
1198 else 731 else
1199 util_send (" \"\""); 732 util_send (" \"\"");
1200 free (p); 733 free (buffer);
1201 } 734 }
1202 return RESP_OK; 735 return RESP_OK;
1203 } 736 }
1204 737
738
739 /* Runtime functions */
1205 static int 740 static int
1206 fetch_header_fields (mu_message_t msg, char **arg, unsigned long start, 741 _frt_uid (struct fetch_function_closure *ffc,
1207 unsigned long end) 742 struct fetch_runtime_closure *frt)
1208 { 743 {
1209 char *buffer = NULL; 744 size_t uid = 0;
1210 char **array = NULL;
1211 size_t array_len = 0;
1212 size_t off = 0;
1213 size_t lines = 0;
1214 mu_stream_t stream = NULL;
1215 int status;
1216
1217 status = mu_memory_stream_create (&stream, 0, 0);
1218 if (status != 0)
1219 imap4d_bye (ERR_NO_MEM);
1220
1221 /* Save the fields in an array. */
1222 {
1223 char *field;
1224 char *sp = NULL;
1225 char *f = *arg;
1226 /* Find the end of the header.field tag. */
1227 field = strchr (f, ']');
1228 if (field)
1229 {
1230 *field++ = '\0';
1231 *arg = field;
1232 }
1233 else
1234 *arg += strlen (*arg);
1235
1236 for (;(field = util_getitem (f, " ()]\r\n", &sp)); f = NULL, array_len++)
1237 {
1238 array = realloc (array, (array_len + 1) * sizeof (*array));
1239 if (!array)
1240 imap4d_bye (ERR_NO_MEM);
1241 array[array_len] = field;
1242 }
1243 }
1244
1245 /* Get the header values. */
1246 {
1247 size_t j;
1248 mu_header_t header = NULL;
1249 mu_message_get_header (msg, &header);
1250 for (j = 0; j < array_len; j++)
1251 {
1252 char *value = NULL;
1253 size_t n = 0;
1254 if (mu_header_aget_value (header, array[j], &value))
1255 continue;
1256
1257 n = asprintf (&buffer, "%s: %s\n", array[j], value);
1258 status = mu_stream_write (stream, buffer, n, off, &n);
1259 off += n;
1260 /* count the lines. */
1261 {
1262 char *nl = buffer;
1263 for (;(nl = strchr (nl, '\n')); nl++)
1264 lines++;
1265 }
1266 free (value);
1267 free (buffer);
1268 buffer = NULL;
1269 if (status != 0)
1270 {
1271 free (array);
1272 imap4d_bye (ERR_NO_MEM);
1273 }
1274 }
1275 }
1276 /* Headers are always sent with the NL separator. */
1277 mu_stream_write (stream, "\n", 1, off, NULL);
1278 off++;
1279 lines++;
1280
1281 /* Send the command back. The first braket was already sent. */
1282 util_send ("HEADER.FIELDS");
1283 {
1284 size_t j;
1285 util_send (" (");
1286 for (j = 0; j < array_len; j++)
1287 {
1288 util_upper (array[j]);
1289 if (j)
1290 util_send (" ");
1291 util_send_qstring (array[j]);
1292 }
1293 util_send (")");
1294 util_send ("]");
1295 }
1296 745
1297 fetch_io (stream, start, end, off + lines); 746 mu_message_get_uid (frt->msg, &uid);
1298 if (array) 747 util_send ("%s %s", ffc->name, mu_umaxtostr (0, uid));
1299 free (array);
1300 return RESP_OK; 748 return RESP_OK;
1301 } 749 }
1302 750
1303 static int 751 static int
1304 fetch_header_fields_not (mu_message_t msg, char **arg, unsigned long start, 752 _frt_envelope (struct fetch_function_closure *ffc,
1305 unsigned long end) 753 struct fetch_runtime_closure *frt)
1306 { 754 {
1307 char **array = NULL; 755 util_send ("%s (", ffc->name);
1308 size_t array_len = 0; 756 fetch_envelope0 (frt->msg);
1309 char *buffer = NULL; 757 util_send (")");
1310 size_t off = 0;
1311 size_t lines = 0;
1312 mu_stream_t stream = NULL;
1313 int status;
1314
1315 status = mu_memory_stream_create (&stream, 0, 0);
1316 if (status)
1317 imap4d_bye (ERR_NO_MEM);
1318
1319 /* Save the field we want to ignore. */
1320 {
1321 char *field;
1322 char *sp = NULL;
1323 char *f = *arg;
1324 /* Find the end of the header.field.no tag. */
1325 field = strchr (f, ']');
1326 if (field)
1327 {
1328 *field++ = '\0';
1329 *arg = field;
1330 }
1331 else
1332 *arg += strlen (*arg);
1333
1334 for (;(field = strtok_r (f, " ()\r\n", &sp)); f = NULL, array_len++)
1335 {
1336 array = realloc (array, (array_len + 1) * sizeof (*array));
1337 if (!array)
1338 imap4d_bye (ERR_NO_MEM);
1339 array[array_len] = field;
1340 }
1341 }
1342
1343 /* Build the memory buffer. */
1344 {
1345 size_t i;
1346 mu_header_t header = NULL;
1347 size_t count = 0;
1348 mu_message_get_header (msg, &header);
1349 mu_header_get_field_count (header, &count);
1350 for (i = 1; i <= count; i++)
1351 {
1352 char *name = NULL;
1353 char *value ;
1354 size_t n = 0;
1355 size_t ignore = 0;
1356
1357 /* Get the field name. */
1358 status = mu_header_aget_field_name (header, i, &name);
1359 if (*name == '\0')
1360 {
1361 free (name);
1362 continue;
1363 }
1364
1365 /* Should we ignore the field? */
1366 {
1367 size_t j;
1368 for (j = 0; j < array_len; j++)
1369 {
1370 if (strcasecmp (array[j], name) == 0)
1371 {
1372 ignore = 1;
1373 break;
1374 }
1375 }
1376 if (ignore)
1377 {
1378 free (name);
1379 continue;
1380 }
1381 }
1382
1383 if (mu_header_aget_field_value (header, i, &value) == 0)
1384 {
1385 char *nl;
1386
1387 /* Save the field. */
1388 n = asprintf (&buffer, "%s: %s\n", name, value);
1389 status = mu_stream_write (stream, buffer, n, off, &n);
1390 off += n;
1391 /* count the lines. */
1392 for (nl = buffer;(nl = strchr (nl, '\n')); nl++)
1393 lines++;
1394
1395 free (value);
1396 }
1397 free (name);
1398 free (buffer);
1399 buffer = NULL;
1400 if (status != 0)
1401 {
1402 free (array);
1403 imap4d_bye (ERR_NO_MEM);
1404 }
1405 }
1406 }
1407 /* Headers are always sent with a NL separator. */
1408 mu_stream_write (stream, "\n", 1, off, NULL);
1409 off++;
1410 lines++;
1411
1412 util_send ("HEADER.FIELDS.NOT");
1413 {
1414 size_t j;
1415 util_send (" (");
1416 for (j = 0; j < array_len; j++)
1417 {
1418 util_upper (array[j]);
1419 if (j)
1420 util_send (" ");
1421 util_send_qstring (array[j]);
1422 }
1423 util_send (")");
1424 util_send ("]");
1425 }
1426
1427 fetch_io (stream, start, end, off + lines);
1428 if (array)
1429 free (array);
1430 return RESP_OK; 758 return RESP_OK;
1431 } 759 }
1432 760
1433 static int 761 static int
1434 fetch_send_address (const char *addr) 762 _frt_flags (struct fetch_function_closure *ffc,
763 struct fetch_runtime_closure *frt)
1435 { 764 {
1436 mu_address_t address; 765 mu_attribute_t attr = NULL;
1437 size_t i, count = 0;
1438 766
1439 /* Short circuit. */ 767 mu_message_get_attribute (frt->msg, &attr);
1440 if (addr == NULL || *addr == '\0') 768 util_send ("%s (", ffc->name);
1441 { 769 util_print_flags (attr);
1442 util_send ("NIL"); 770 util_send (")");
1443 return RESP_OK; 771 return 0;
1444 } 772 }
1445 773
1446 mu_address_create (&address, addr); 774 /* INTERNALDATE The internal date of the message.
1447 mu_address_get_count (address, &count); 775 Format:
1448 776
1449 /* We failed: can't parse. */ 777 date_time ::= <"> date_day_fixed "-" date_month "-" date_year
1450 if (count == 0) 778 SPACE time SPACE zone <">
1451 {
1452 util_send ("NIL");
1453 return RESP_OK;
1454 }
1455 779
1456 util_send ("("); 780 date_day ::= 1*2digit
1457 for (i = 1; i <= count; i++) 781 ;; Day of month
1458 {
1459 const char *str;
1460 int is_group = 0;
1461 782
1462 util_send ("("); 783 date_day_fixed ::= (SPACE digit) / 2digit
784 ;; Fixed-format version of date_day
1463 785
1464 mu_address_sget_personal (address, i, &str); 786 date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
1465 util_send_qstring (str); 787 "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
1466 util_send (" ");
1467 788
1468 mu_address_sget_route (address, i, &str); 789 date_text ::= date_day "-" date_month "-" date_year
1469 util_send_qstring (str);
1470 790
1471 util_send (" "); 791 date_year ::= 4digit
1472 792
1473 mu_address_is_group (address, i, &is_group); 793 time ::= 2digit ":" 2digit ":" 2digit
1474 str = NULL; 794 ;; Hours minutes seconds
1475 if (is_group)
1476 mu_address_sget_personal (address, i, &str);
1477 else
1478 mu_address_sget_local_part (address, i, &str);
1479 795
1480 util_send_qstring (str); 796 zone ::= ("+" / "-") 4digit
797 ;; Signed four-digit value of hhmm representing
798 ;; hours and minutes west of Greenwich (that is,
799 ;; (the amount that the given time differs from
800 ;; Universal Time). Subtracting the timezone
801 ;; from the given time will give the UT form.
802 ;; The Universal Time zone is "+0000". */
803 static int
804 _frt_internaldate (struct fetch_function_closure *ffc,
805 struct fetch_runtime_closure *frt)
806 {
807 const char *date;
808 mu_envelope_t env = NULL;
809 struct tm tm, *tmp = NULL;
810 mu_timezone tz;
811 char datebuf[sizeof ("13-Jul-2002 00:00:00")];
1481 812
1482 util_send (" "); 813 mu_message_get_envelope (frt->msg, &env);
814 if (mu_envelope_sget_date (env, &date) == 0
815 && mu_parse_ctime_date_time (&date, &tm, &tz) == 0)
816 tmp = &tm;
817 else
818 {
819 time_t t = time (NULL);
820 tmp = localtime (&t);
821 }
822 mu_strftime (datebuf, sizeof (datebuf), "%d-%b-%Y %H:%M:%S", tmp);
823 util_send ("%s", ffc->name);
824 util_send (" \"%s +0000\"", datebuf);
825 return 0;
826 }
1483 827
1484 mu_address_sget_domain (address, i, &str); 828 static int
1485 util_send_qstring (str); 829 _frt_bodystructure (struct fetch_function_closure *ffc,
830 struct fetch_runtime_closure *frt)
831 {
832 util_send ("%s (", ffc->name);
833 fetch_bodystructure0 (frt->msg, 1); /* 1 means with extension data. */
834 util_send (")");
835 return RESP_OK;
836 }
1486 837
1487 util_send (")"); 838 static int
1488 } 839 _frt_bodystructure0 (struct fetch_function_closure *ffc,
840 struct fetch_runtime_closure *frt)
841 {
842 util_send ("%s (", ffc->name);
843 fetch_bodystructure0 (frt->msg, 0);
1489 util_send (")"); 844 util_send (")");
1490 return RESP_OK; 845 return RESP_OK;
1491 } 846 }
1492 847
1493 /* Send parameter list for the bodystructure. */ 848 /* BODY[] */
1494 static void 849 static int
1495 send_parameter_list (const char *buffer) 850 _frt_body (struct fetch_function_closure *ffc,
851 struct fetch_runtime_closure *frt)
1496 { 852 {
1497 int argc = 0; 853 mu_message_t msg;
1498 char **argv; 854 mu_stream_t stream = NULL;
1499 855 size_t size = 0, lines = 0;
1500 if (!buffer) 856
857 set_seen (ffc, frt);
858 if (ffc->name)
859 util_send ("%s", ffc->name);
860 else
861 fetch_send_section_part (ffc, "BODY[", "]");
862 msg = fetch_get_part (ffc, frt);
863 if (!msg)
1501 { 864 {
1502 util_send ("NIL"); 865 util_send (" \"\"");
1503 return; 866 return RESP_OK;
1504 } 867 }
868 mu_message_get_stream (msg, &stream);
869 mu_message_size (msg, &size);
870 mu_message_lines (msg, &lines);
871 return fetch_io (stream, ffc->start, ffc->size, size + lines);
872 }
1505 873
1506 mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv); 874 static int
875 _frt_body_text (struct fetch_function_closure *ffc,
876 struct fetch_runtime_closure *frt)
877 {
878 mu_message_t msg;
879 mu_body_t body = NULL;
880 mu_stream_t stream = NULL;
881 size_t size = 0, lines = 0;
882
883 set_seen (ffc, frt);
884 if (ffc->name)
885 util_send ("%s", ffc->name);
886 else
887 fetch_send_section_part (ffc, "BODY[", "TEXT]");
888 msg = fetch_get_part (ffc, frt);
889 if (!msg)
890 {
891 util_send (" \"\"");
892 return RESP_OK;
893 }
894
895 mu_message_get_body (msg, &body);
896 mu_body_size (body, &size);
897 mu_body_lines (body, &lines);
898 mu_body_get_stream (body, &stream);
899 return fetch_io (stream, ffc->start, ffc->size, size + lines);
900 }
901
902 static int
903 _frt_size (struct fetch_function_closure *ffc,
904 struct fetch_runtime_closure *frt)
905 {
906 size_t size = 0;
907 size_t lines = 0;
1507 908
1508 if (argc == 0) 909 mu_message_size (frt->msg, &size);
1509 util_send ("NIL"); 910 mu_message_lines (frt->msg, &lines);
911 util_send ("%s %u", ffc->name, size + lines);
912 return RESP_OK;
913 }
914
915 static int
916 _frt_header0 (struct fetch_function_closure *ffc,
917 struct fetch_runtime_closure *frt,
918 const char *suffix)
919 {
920 mu_message_t msg;
921 mu_header_t header = NULL;
922 mu_stream_t stream = NULL;
923 size_t size = 0, lines = 0;
924
925 set_seen (ffc, frt);
926 if (ffc->name)
927 util_send ("%s", ffc->name);
1510 else 928 else
929 fetch_send_section_part (ffc, "BODY[", suffix);
930
931 msg = fetch_get_part (ffc, frt);
932 if (!msg)
1511 { 933 {
1512 char *p; 934 util_send (" \"\"");
935 return RESP_OK;
936 }
937 mu_message_get_header (msg, &header);
938 mu_header_size (header, &size);
939 mu_header_lines (header, &lines);
940 mu_header_get_stream (header, &stream);
941 return fetch_io (stream, ffc->start, ffc->size, size + lines);
942 }
943
944 static int
945 _frt_header (struct fetch_function_closure *ffc,
946 struct fetch_runtime_closure *frt)
947 {
948 return _frt_header0 (ffc, frt, "HEADER]");
949 }
950
951 static int
952 _frt_mime (struct fetch_function_closure *ffc,
953 struct fetch_runtime_closure *frt)
954 {
955 return _frt_header0 (ffc, frt, "MIME]");
956 }
957
958 static int
959 _send_header_name (void *item, void *data)
960 {
961 int *pf = data;
962 if (*pf)
963 util_send (" ");
964 else
965 *pf = 1;
966 util_send ("\"%s\"", (char*) item);
967 return 0;
968 }
969
970 static int
971 count_nl (const char *str)
972 {
973 int n = 0;
974 for (;(str = strchr (str, '\n')); str++)
975 n++;
976 return n;
977 }
978
979 static int
980 _frt_header_fields (struct fetch_function_closure *ffc,
981 struct fetch_runtime_closure *frt)
982 {
983 int status;
984 mu_message_t msg;
985 mu_off_t size = 0;
986 size_t lines = 0;
987 mu_stream_t stream;
988 mu_header_t header;
989 mu_iterator_t itr;
990
991 set_seen (ffc, frt);
992
993 fetch_send_section_part (ffc, "BODY[", "HEADER.FIELDS");
994 if (ffc->not)
995 util_send (".NOT");
996 util_send (" (");
997 status = 0;
998 mu_list_do (ffc->headers, _send_header_name, &status);
999 util_send (")]");
1000
1001 msg = fetch_get_part (ffc, frt);
1002 if (!msg)
1003 {
1004 util_send (" \"\"");
1005 return RESP_OK;
1006 }
1007
1008 /* Collect headers: */
1009 if (mu_message_get_header (msg, &header)
1010 || mu_header_get_iterator (header, &itr))
1011 {
1012 util_send (" \"\"");
1013 return RESP_OK;
1014 }
1015
1016 status = mu_memory_stream_create (&stream, NULL, MU_STREAM_NO_CHECK);
1017 if (status != 0)
1018 imap4d_bye (ERR_NO_MEM);
1019
1020 for (mu_iterator_first (itr);
1021 !mu_iterator_is_done (itr); mu_iterator_next (itr))
1022 {
1023 const char *hf;
1024 char *hv;
1025 const char *item;
1513 1026
1514 util_send ("("); 1027 mu_iterator_current_kv (itr, (const void **)&hf, (void **)&hv);
1515 1028 status = mu_list_locate (ffc->headers, (void *)hf, (void**) &item) == 0;
1516 p = argv[0]; 1029 if (ffc->not)
1517 util_send_qstring (p); 1030 {
1031 status = !status;
1032 item = hf;
1033 }
1034
1035 if (status)
1036 {
1037 mu_stream_sequential_printf (stream, "%s: %s\n", item, hv);
1038 lines += 1 + count_nl (hv);
1039 }
1040 }
1041 mu_stream_sequential_write (stream, "\n", 1);
1042 lines++;
1043
1044 /* Output collected data */
1045 mu_stream_size (stream, &size);
1046 status = fetch_io (stream, ffc->start, ffc->size, size + lines);
1047 mu_stream_destroy (&stream, NULL);
1048
1049 return status;
1050 }
1518 1051
1519 if (argc > 1) 1052
1053 static void
1054 ffc_init (struct fetch_function_closure *ffc)
1055 {
1056 memset(ffc, 0, sizeof *ffc);
1057 ffc->start = 0;
1058 ffc->size = (size_t) -1;
1059 }
1060
1061 static void
1062 _free_ffc (void *item)
1063 {
1064 struct fetch_function_closure *ffc = item;
1065 mu_list_destroy (&ffc->headers);
1066 free (ffc);
1067 }
1068
1069 static int
1070 _do_fetch (void *item, void *data)
1071 {
1072 struct fetch_function_closure *ffc = item;
1073 struct fetch_runtime_closure *frt = data;
1074 if (frt->eltno++)
1075 util_send (" ");
1076 return ffc->fun (ffc, frt);
1077 }
1078
1079 struct parsebuf
1080 {
1081 imap4d_tokbuf_t tok;
1082 int arg;
1083 char *token;
1084 int isuid;
1085 mu_list_t fnlist;
1086 jmp_buf errjmp;
1087 char *err_text;
1088 };
1089
1090 static void
1091 parsebuf_exit (struct parsebuf *p, char *text)
1092 {
1093 p->err_text = text;
1094 longjmp (p->errjmp, 1);
1095 }
1096
1097 static char *
1098 parsebuf_peek (struct parsebuf *p)
1099 {
1100 return imap4d_tokbuf_getarg (p->tok, p->arg);
1101 }
1102
1103 static char *
1104 parsebuf_next (struct parsebuf *p, int req)
1105 {
1106 p->token = imap4d_tokbuf_getarg (p->tok, p->arg++);
1107 if (!p->token && req)
1108 parsebuf_exit (p, "Too few arguments");
1109 return p->token;
1110 }
1111
1112 static void
1113 append_ffc (struct parsebuf *p, struct fetch_function_closure *ffc)
1114 {
1115 struct fetch_function_closure *new_ffc = malloc (sizeof (*new_ffc));
1116 if (!new_ffc)
1117 imap4d_bye (ERR_NO_MEM);
1118 *new_ffc = *ffc;
1119 mu_list_append (p->fnlist, new_ffc);
1120 }
1121
1122 static void
1123 append_simple_function (struct parsebuf *p, const char *name,
1124 fetch_function_t fun)
1125 {
1126 struct fetch_function_closure ffc;
1127 ffc_init (&ffc);
1128 ffc.fun = fun;
1129 ffc.name = name;
1130 append_ffc (p, &ffc);
1131 }
1132
1133
1134 static struct fetch_macro
1135 {
1136 char *macro;
1137 char *exp;
1138 } fetch_macro_tab[] = {
1139 { "ALL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE" },
1140 { "FULL", "FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY" },
1141 { "FAST", "FLAGS INTERNALDATE RFC822.SIZE" },
1142 { NULL }
1143 };
1144
1145 static char *
1146 find_macro (const char *name)
1147 {
1148 int i;
1149 for (i = 0; fetch_macro_tab[i].macro; i++)
1150 if (strcasecmp (fetch_macro_tab[i].macro, name) == 0)
1151 return fetch_macro_tab[i].exp;
1152 return NULL;
1153 }
1154
1155
1156 struct fetch_att_tab
1157 {
1158 char *name;
1159 fetch_function_t fun;
1160 };
1161
1162 static struct fetch_att_tab fetch_att_tab[] = {
1163 { "ENVELOPE", _frt_envelope },
1164 { "FLAGS", _frt_flags },
1165 { "INTERNALDATE", _frt_internaldate },
1166 { "UID", _frt_uid },
1167 { NULL }
1168 };
1169
1170 static struct fetch_att_tab *
1171 find_fetch_att_tab (char *name)
1172 {
1173 struct fetch_att_tab *p;
1174 for (p = fetch_att_tab; p->name; p++)
1175 if (strcasecmp (p->name, name) == 0)
1176 return p;
1177 return NULL;
1178 }
1179
1180 /*
1181 fetch-att = "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
1182 "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
1183 "BODY" ["STRUCTURE"] / "UID" /
1184 "BODY" section ["<" number "." nz-number ">"] /
1185 "BODY.PEEK" section ["<" number "." nz-number ">"]
1186
1187 */
1188
1189 /* "RFC822" [".HEADER" / ".SIZE" / ".TEXT"] */
1190 static void
1191 parse_fetch_rfc822 (struct parsebuf *p)
1192 {
1193 struct fetch_function_closure ffc;
1194 ffc_init (&ffc);
1195 ffc.name = "RFC822";
1196 parsebuf_next (p, 0);
1197 if (p->token == NULL || p->token[0] == ')')
1198 {
1199 /* Equivalent to BODY[]. */
1200 ffc.fun = _frt_body;
1201 }
1202 else if (p->token[0] == '.')
1203 {
1204 parsebuf_next (p, 1);
1205 if (strcasecmp (p->token, "HEADER") == 0)
1520 { 1206 {
1521 int i, space = 0; 1207 /* RFC822.HEADER
1522 char *lvalue = NULL; 1208 Equivalent to BODY[HEADER]. Note that this did not result in
1209 \Seen being set, because RFC822.HEADER response data occurs as
1210 a result of a FETCH of RFC822.HEADER. BODY[HEADER] response
1211 data occurs as a result of a FETCH of BODY[HEADER] (which sets
1212 \Seen) or BODY.PEEK[HEADER] (which does not set \Seen). */
1213
1214 ffc.name = "RFC822.HEADER";
1215 ffc.fun = _frt_header;
1216 ffc.peek = 1;
1217 parsebuf_next (p, 0);
1218 }
1219 else if (strcasecmp (p->token, "SIZE") == 0)
1220 {
1221 /* A number expressing the [RFC-2822] size of the message. */
1222 ffc.name = "RFC822.SIZE";
1223 ffc.fun = _frt_size;
1224 parsebuf_next (p, 0);
1225 }
1226 else if (strcasecmp (p->token, "TEXT") == 0)
1227 {
1228 /* RFC822.TEXT
1229 Equivalent to BODY[TEXT]. */
1230 ffc.name = "RFC822.TEXT";
1231 ffc.fun = _frt_body_text;
1232 parsebuf_next (p, 0);
1233 }
1234 else
1235 parsebuf_exit (p, "Syntax error after RFC822.");
1236 }
1237 else
1238 parsebuf_exit (p, "Syntax error after RFC822");
1239 append_ffc (p, &ffc);
1240 }
1523 1241
1524 util_send ("("); 1242 static int
1525 for (i = 1; i < argc; i++) 1243 _header_cmp (const void *a, const void *b)
1244 {
1245 return strcasecmp ((char*)a, (char*)b);
1246 }
1247
1248 /*
1249 header-fld-name = astring
1250
1251 header-list = "(" header-fld-name *(SP header-fld-name) ")"
1252 */
1253 static void
1254 parse_header_list (struct parsebuf *p, struct fetch_function_closure *ffc)
1255 {
1256 if (p->token[0] != '(')
1257 parsebuf_exit (p, "Syntax error: expected (");
1258 mu_list_create (&ffc->headers);
1259 mu_list_set_comparator (ffc->headers, _header_cmp);
1260 for (parsebuf_next (p, 1); p->token[0] != ')'; parsebuf_next (p, 1))
1261 {
1262 if (util_isdelim (p->token))
1263 parsebuf_exit (p, "Syntax error: unexpected delimiter");
1264 mu_list_append (ffc->headers, p->token);
1265 }
1266 parsebuf_next (p, 1);
1267 }
1268
1269 /*
1270 section-msgtext = "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list /
1271 "TEXT"
1272 ; top-level or MESSAGE/RFC822 part
1273 section-text = section-msgtext / "MIME"
1274 ; text other than actual body part (headers, etc.)
1275 */
1276 static int
1277 parse_section_text (struct parsebuf *p, struct fetch_function_closure *ffc,
1278 int allow_mime)
1279 {
1280 if (strcasecmp (p->token, "HEADER") == 0)
1281 {
1282 /* "HEADER" / "HEADER.FIELDS" [".NOT"] SP header-list */
1283 parsebuf_next (p, 1);
1284 if (p->token[0] == '.')
1285 {
1286 parsebuf_next (p, 1);
1287 if (strcasecmp (p->token, "FIELDS"))
1288 parsebuf_exit (p, "Expected FIELDS");
1289 ffc->fun = _frt_header_fields;
1290 parsebuf_next (p, 1);
1291 if (p->token[0] == '.')
1526 { 1292 {
1527 if (lvalue) 1293 parsebuf_next (p, 1);
1294 if (strcasecmp (p->token, "NOT") == 0)
1528 { 1295 {
1529 if (space) 1296 ffc->not = 1;
1530 util_send (" "); 1297 parsebuf_next (p, 1);
1531 util_send_qstring (lvalue);
1532 lvalue = NULL;
1533 space = 1;
1534 }
1535
1536 switch (argv[i][0])
1537 {
1538 case ';':
1539 continue;
1540
1541 case '=':
1542 if (++i < argc)
1543 {
1544 char *p = argv[i];
1545 util_send (" ");
1546 util_unquote (&p);
1547 util_send_qstring (p);
1548 }
1549 break;
1550
1551 default:
1552 lvalue = argv[i];
1553 } 1298 }
1299 else
1300 parsebuf_exit (p, "Expected NOT");
1554 } 1301 }
1555 if (lvalue) 1302 parse_header_list (p, ffc);
1303 }
1304 else
1305 ffc->fun = _frt_header;
1306 }
1307 else if (strcasecmp (p->token, "TEXT") == 0)
1308 {
1309 parsebuf_next (p, 1);
1310 ffc->fun = _frt_body_text;
1311 }
1312 else if (allow_mime && strcasecmp (p->token, "MIME") == 0)
1313 {
1314 parsebuf_next (p, 1);
1315 ffc->fun = _frt_mime;
1316 }
1317 else
1318 return 1;
1319 return 0;
1320 }
1321
1322 static size_t
1323 parsebuf_get_number (struct parsebuf *p)
1324 {
1325 char *cp;
1326 unsigned n = strtoul (p->token, &cp, 10);
1327
1328 if (*cp)
1329 parsebuf_exit (p, "Syntax error: expected number");
1330 return n;
1331 }
1332
1333 /*
1334 section-part = nz-number *("." nz-number)
1335 ; body part nesting
1336 */
1337 static void
1338 parse_section_part (struct parsebuf *p, struct fetch_function_closure *ffc)
1339 {
1340 size_t *parts;
1341 size_t nmax = 0;
1342 size_t ncur = 0;
1343
1344 for (;;)
1345 {
1346 char *cp;
1347 size_t n = parsebuf_get_number (p);
1348 if (ncur == nmax)
1349 {
1350 if (nmax == 0)
1556 { 1351 {
1557 if (space) 1352 nmax = 16;
1558 util_send (" "); 1353 parts = calloc (nmax, sizeof (parts[0]));
1559 util_send_qstring (lvalue);
1560 } 1354 }
1561 util_send (")"); 1355 else
1356 {
1357 nmax *= 2;
1358 parts = realloc (parts, nmax * sizeof (parts[0]));
1359 }
1360 if (!parts)
1361 imap4d_bye (ERR_NO_MEM);
1562 } 1362 }
1363 parts[ncur++] = n;
1364
1365 parsebuf_next (p, 1);
1366 if (p->token[0] == '.'
1367 && (cp = parsebuf_peek (p)) && isascii (*cp) && isdigit (cp[0]))
1368 parsebuf_next (p, 1);
1563 else 1369 else
1564 util_send (" NIL"); 1370 break;
1565 util_send (")");
1566 } 1371 }
1567 mu_argcv_free (argc, argv); 1372 ffc->section_part = parts;
1373 ffc->nset = ncur;
1374 }
1375
1376 /*
1377 section = "[" [section-spec] "]"
1378 section-spec = section-msgtext / (section-part ["." section-text])
1379 */
1380 static int
1381 parse_section (struct parsebuf *p, struct fetch_function_closure *ffc)
1382 {
1383 if (p->token[0] != '[')
1384 return 1;
1385 ffc_init (ffc);
1386 ffc->name = NULL;
1387 ffc->fun = _frt_body;
1388 parsebuf_next (p, 1);
1389 if (parse_section_text (p, ffc, 0))
1390 {
1391 if (p->token[0] == ']')
1392 /* OK */;
1393 else if (isascii (p->token[0]) && isdigit (p->token[0]))
1394 {
1395 parse_section_part (p, ffc);
1396 if (p->token[0] == '.')
1397 {
1398 parsebuf_next (p, 1);
1399 parse_section_text (p, ffc, 1);
1400 }
1401 }
1402 else
1403 parsebuf_exit (p, "Syntax error");
1404 }
1405 if (p->token[0] != ']')
1406 parsebuf_exit (p, "Syntax error: missing ]");
1407 parsebuf_next (p, 0);
1408 return 0;
1409 }
1410
1411 static void
1412 parse_substring (struct parsebuf *p, struct fetch_function_closure *ffc)
1413 {
1414 if (p->token && p->token[0] == '<')
1415 {
1416 parsebuf_next (p, 1);
1417 ffc->start = parsebuf_get_number (p);
1418 parsebuf_next (p, 1);
1419 if (p->token[0] != '.')
1420 parsebuf_exit (p, "Syntax error: expected .");
1421 parsebuf_next (p, 1);
1422 ffc->size = parsebuf_get_number (p);
1423 parsebuf_next (p, 1);
1424 if (p->token[0] != '>')
1425 parsebuf_exit (p, "Syntax error: expected >");
1426 parsebuf_next (p, 0);
1427 }
1428 }
1429
1430 /* section ["<" number "." nz-number ">"] */
1431 static int
1432 parse_body_args (struct parsebuf *p, int peek)
1433 {
1434 struct fetch_function_closure ffc;
1435 if (parse_section (p, &ffc) == 0)
1436 {
1437 parse_substring (p, &ffc);
1438 ffc.peek = peek;
1439 append_ffc (p, &ffc);
1440 return 0;
1441 }
1442 return 1;
1443 }
1444
1445 static void
1446 parse_body_peek (struct parsebuf *p)
1447 {
1448 parsebuf_next (p, 1);
1449 if (strcasecmp (p->token, "PEEK") == 0)
1450 {
1451 parsebuf_next (p, 1);
1452 if (parse_body_args (p, 1))
1453 parsebuf_exit (p, "Syntax error");
1454 }
1455 else
1456 parsebuf_exit (p, "Syntax error: expected PEEK");
1457 }
1458
1459 /* "BODY" ["STRUCTURE"] /
1460 "BODY" section ["<" number "." nz-number ">"] /
1461 "BODY.PEEK" section ["<" number "." nz-number ">"] */
1462 static void
1463 parse_fetch_body (struct parsebuf *p)
1464 {
1465 if (parsebuf_next (p, 0) == NULL || p->token[0] == ')')
1466 append_simple_function (p, "BODY", _frt_bodystructure0);
1467 else if (p->token[0] == '.')
1468 parse_body_peek (p);
1469 else if (strcasecmp (p->token, "STRUCTURE") == 0)
1470 {
1471 /* For compatibility with previous versions */
1472 append_simple_function (p, "BODYSTRUCTURE", _frt_bodystructure);
1473 parsebuf_next (p, 0);
1474 }
1475 else if (parse_body_args (p, 0))
1476 parsebuf_exit (p, "Syntax error");
1477 }
1478
1479 static int
1480 parse_fetch_att (struct parsebuf *p)
1481 {
1482 struct fetch_att_tab *ent;
1483
1484 ent = find_fetch_att_tab (p->token);
1485 if (ent)
1486 {
1487 if (!(ent->fun == _frt_uid && p->isuid))
1488 append_simple_function (p, ent->name, ent->fun);
1489 parsebuf_next (p, 0);
1490 }
1491 else if (strcasecmp (p->token, "RFC822") == 0)
1492 parse_fetch_rfc822 (p);
1493 else if (strcasecmp (p->token, "BODY") == 0)
1494 parse_fetch_body (p);
1495 else if (strcasecmp (p->token, "BODYSTRUCTURE") == 0)
1496 {
1497 append_simple_function (p, "BODYSTRUCTURE", _frt_bodystructure);
1498 parsebuf_next (p, 0);
1499 }
1500 else
1501 return 1;
1502 return 0;
1503 }
1504
1505 /* fetch-att *(SP fetch-att) */
1506 static void
1507 parse_fetch_att_list (struct parsebuf *p)
1508 {
1509 while (p->token && parse_fetch_att (p) == 0)
1510 ;
1511 }
1512
1513 /* "ALL" / "FULL" / "FAST" / fetch-att / "(" */
1514 static void
1515 parse_macro (struct parsebuf *p)
1516 {
1517 char *exp;
1518
1519 parsebuf_next (p, 1);
1520 if (p->token[0] == '(')
1521 {
1522 parsebuf_next (p, 1);
1523 parse_fetch_att_list (p);
1524 if (p->token[0] != ')')
1525 parsebuf_exit (p, "Missing closing parenthesis");
1526 }
1527 else if ((exp = find_macro (p->token)))
1528 {
1529 imap4d_tokbuf_t save_tok = p->tok;
1530 int save_arg = p->arg;
1531 p->tok = imap4d_tokbuf_from_string (exp);
1532 p->arg = 0;
1533 parsebuf_next (p, 1);
1534 parse_fetch_att_list (p);
1535 imap4d_tokbuf_destroy (&p->tok);
1536
1537 p->arg = save_arg;
1538 p->tok = save_tok;
1539
1540 if (parsebuf_peek (p))
1541 parsebuf_exit (p, "Too many arguments");
1542 }
1543 else
1544 {
1545 parse_fetch_att (p);
1546 if (p->token)
1547 parsebuf_exit (p, "Too many arguments");
1548 }
1549 }
1550
1551 /* Where the real implementation is. It is here since UID command also
1552 calls FETCH. */
1553 int
1554 imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
1555 {
1556 int rc = RESP_OK;
1557 char *msgset;
1558 size_t *set = NULL;
1559 int n = 0;
1560 int i;
1561 int status;
1562 struct fetch_runtime_closure frc;
1563 struct parsebuf pb;
1564
1565 if (imap4d_tokbuf_argc (tok) - (IMAP4_ARG_1 + isuid) < 2)
1566 {
1567 *err_text = "Invalid arguments";
1568 return 1;
1569 }
1570
1571 pb.tok = tok;
1572 pb.arg = IMAP4_ARG_1 + isuid;
1573 pb.isuid = isuid;
1574 pb.err_text = "Syntax error";
1575 mu_list_create (&pb.fnlist);
1576 mu_list_set_destroy_item (pb.fnlist, _free_ffc);
1577 if (setjmp (pb.errjmp))
1578 {
1579 *err_text = pb.err_text;
1580 mu_list_destroy (&pb.fnlist);
1581 return RESP_BAD;
1582 }
1583
1584 msgset = parsebuf_next (&pb, 1);
1585
1586 /* Get the message numbers in set[]. */
1587 status = util_msgset (msgset, &set, &n, isuid);
1588 if (status != 0)
1589 {
1590 *err_text = "Bogus number set";
1591 return RESP_BAD;
1592 }
1593
1594 /* Compile the expression */
1595
1596 /* Server implementations MUST implicitly
1597 include the UID message data item as part of any FETCH
1598 response caused by a UID command, regardless of whether
1599 a UID was specified as a message data item to the FETCH. */
1600 if (isuid)
1601 append_simple_function (&pb, "UID", _frt_uid);
1602
1603 parse_macro (&pb);
1604
1605 /* Prepare status code. It will be replaced if an error occurs in the
1606 loop below */
1607 frc.err_text = "Completed";
1608
1609 for (i = 0; i < n && rc == RESP_OK; i++)
1610 {
1611 frc.msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
1612
1613 if (frc.msgno && mu_mailbox_get_message (mbox, frc.msgno, &frc.msg) == 0)
1614 {
1615 util_send ("* %lu FETCH (", (unsigned long) frc.msgno);
1616 frc.eltno = 0;
1617 rc = mu_list_do (pb.fnlist, _do_fetch, &frc);
1618 util_send (")\r\n");
1619 }
1620 }
1621
1622 mu_list_destroy (&pb.fnlist);
1623 free (set);
1624 return rc;
1625 }
1626
1627 /*
1628 6.4.5. FETCH Command
1629
1630 Arguments: message set
1631 message data item names
1632
1633 Responses: untagged responses: FETCH
1634
1635 Result: OK - fetch completed
1636 NO - fetch error: can't fetch that data
1637 BAD - command unknown or arguments invalid
1638 */
1639
1640 /* The FETCH command retrieves data associated with a message in the
1641 mailbox. The data items to be fetched can be either a single atom
1642 or a parenthesized list. */
1643 int
1644 imap4d_fetch (struct imap4d_command *command, imap4d_tokbuf_t tok)
1645 {
1646 int rc;
1647 char *err_text = "Completed";
1648
1649 rc = imap4d_fetch0 (tok, 0, &err_text);
1650 return util_finish (command, rc, "%s", err_text);
1568 } 1651 }
1569
1570 1652
......
...@@ -19,13 +19,12 @@ ...@@ -19,13 +19,12 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 int 21 int
22 imap4d_idle (struct imap4d_command *command, char *arg) 22 imap4d_idle (struct imap4d_command *command, imap4d_tokbuf_t tok)
23 { 23 {
24 char *sp;
25 time_t start; 24 time_t start;
26 25
27 if (util_getword (arg, &sp)) 26 if (imap4d_tokbuf_argc (tok) != 2)
28 return util_finish (command, RESP_BAD, "Too many args"); 27 return util_finish (command, RESP_BAD, "Invalid arguments");
29 28
30 if (util_wait_input (0) == -1) 29 if (util_wait_input (0) == -1)
31 return util_finish (command, RESP_NO, "Cannot idle"); 30 return util_finish (command, RESP_NO, "Cannot idle");
...@@ -38,15 +37,10 @@ imap4d_idle (struct imap4d_command *command, char *arg) ...@@ -38,15 +37,10 @@ imap4d_idle (struct imap4d_command *command, char *arg)
38 { 37 {
39 if (util_wait_input (5)) 38 if (util_wait_input (5))
40 { 39 {
41 int rc; 40 imap4d_readline (tok);
42 char *p; 41 if (imap4d_tokbuf_argc (tok) == 1
43 char *cmd = imap4d_readline (); 42 && strcasecmp (imap4d_tokbuf_getarg (tok, IMAP4_ARG_TAG),
44 43 "done") == 0)
45 p = util_getword (cmd, &sp);
46 rc = strcasecmp (p, "done") == 0;
47
48 free (cmd);
49 if (rc)
50 break; 44 break;
51 } 45 }
52 else if (time (NULL) - start > idle_timeout) 46 else if (time (NULL) - start > idle_timeout)
......
...@@ -370,6 +370,7 @@ get_client_address (int fd, struct sockaddr_in *pcs) ...@@ -370,6 +370,7 @@ get_client_address (int fd, struct sockaddr_in *pcs)
370 static int 370 static int
371 imap4d_mainloop (int fd, FILE *infile, FILE *outfile) 371 imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
372 { 372 {
373 imap4d_tokbuf_t tokp;
373 char *text; 374 char *text;
374 int debug_mode = isatty (fd); 375 int debug_mode = isatty (fd);
375 static int sigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP, SIGPIPE, 376 static int sigtab[] = { SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGSTOP, SIGPIPE,
...@@ -400,14 +401,14 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile) ...@@ -400,14 +401,14 @@ imap4d_mainloop (int fd, FILE *infile, FILE *outfile)
400 util_out ((state == STATE_AUTH) ? RESP_PREAUTH : RESP_OK, "%s", text); 401 util_out ((state == STATE_AUTH) ? RESP_PREAUTH : RESP_OK, "%s", text);
401 util_flush_output (); 402 util_flush_output ();
402 403
404 tokp = imap4d_tokbuf_init ();
403 while (1) 405 while (1)
404 { 406 {
405 char *cmd = imap4d_readline (); 407 imap4d_readline (tokp);
406 /* check for updates */ 408 /* check for updates */
407 imap4d_sync (); 409 imap4d_sync ();
408 util_do_command (cmd); 410 util_do_command (tokp);
409 imap4d_sync (); 411 imap4d_sync ();
410 free (cmd);
411 util_flush_output (); 412 util_flush_output ();
412 } 413 }
413 414
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
41 #include <stdlib.h> 41 #include <stdlib.h>
42 #include <unistd.h> 42 #include <unistd.h>
43 #include <string.h> 43 #include <string.h>
44 #include <setjmp.h>
44 #include <sys/wait.h> 45 #include <sys/wait.h>
45 #include <sys/types.h> 46 #include <sys/types.h>
46 #include <syslog.h> 47 #include <syslog.h>
...@@ -108,10 +109,12 @@ ...@@ -108,10 +109,12 @@
108 extern "C" { 109 extern "C" {
109 #endif 110 #endif
110 111
112 typedef struct imap4d_tokbuf *imap4d_tokbuf_t;
113
111 struct imap4d_command 114 struct imap4d_command
112 { 115 {
113 const char *name; 116 const char *name;
114 int (*func) (struct imap4d_command *, char *); 117 int (*func) (struct imap4d_command *, imap4d_tokbuf_t);
115 int states; 118 int states;
116 int failure; 119 int failure;
117 int success; 120 int success;
...@@ -191,48 +194,63 @@ extern int imap4d_transcript; ...@@ -191,48 +194,63 @@ extern int imap4d_transcript;
191 #ifndef HAVE_STRTOK_R 194 #ifndef HAVE_STRTOK_R
192 extern char *strtok_r (char *s, const char *delim, char **save_ptr); 195 extern char *strtok_r (char *s, const char *delim, char **save_ptr);
193 #endif 196 #endif
197
198 /* Input functions */
199 imap4d_tokbuf_t imap4d_tokbuf_init (void);
200 void imap4d_tokbuf_destroy (imap4d_tokbuf_t *tok);
201 int imap4d_tokbuf_argc (imap4d_tokbuf_t tok);
202 char *imap4d_tokbuf_getarg (imap4d_tokbuf_t tok, int n);
203 void imap4d_readline (imap4d_tokbuf_t tok);
204 struct imap4d_tokbuf *imap4d_tokbuf_from_string (char *str);
205 int imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes);
206
207 #define IMAP4_ARG_TAG 0
208 #define IMAP4_ARG_COMMAND 1
209 #define IMAP4_ARG_1 2
210 #define IMAP4_ARG_2 3
211 #define IMAP4_ARG_3 4
212 #define IMAP4_ARG_4 5
194 213
195 /* Imap4 commands */ 214 /* Imap4 commands */
196 extern int imap4d_append (struct imap4d_command *, char *); 215 extern int imap4d_append (struct imap4d_command *, imap4d_tokbuf_t);
197 extern int imap4d_append0 (mu_mailbox_t mbox, int flags, char *text); 216 extern int imap4d_authenticate (struct imap4d_command *, imap4d_tokbuf_t);
198 extern int imap4d_authenticate (struct imap4d_command *, char *);
199 extern void imap4d_auth_capability (void); 217 extern void imap4d_auth_capability (void);
200 extern int imap4d_capability (struct imap4d_command *, char *); 218 extern int imap4d_capability (struct imap4d_command *, imap4d_tokbuf_t);
201 extern int imap4d_check (struct imap4d_command *, char *); 219 extern int imap4d_check (struct imap4d_command *, imap4d_tokbuf_t);
202 extern int imap4d_close (struct imap4d_command *, char *); 220 extern int imap4d_close (struct imap4d_command *, imap4d_tokbuf_t);
203 extern int imap4d_copy (struct imap4d_command *, char *); 221 extern int imap4d_copy (struct imap4d_command *, imap4d_tokbuf_t);
204 extern int imap4d_copy0 (char *, int, char *, size_t); 222 extern int imap4d_copy0 (imap4d_tokbuf_t, int isuid, char **err_text);
205 extern int imap4d_create (struct imap4d_command *, char *); 223 extern int imap4d_create (struct imap4d_command *, imap4d_tokbuf_t);
206 extern int imap4d_delete (struct imap4d_command *, char *); 224 extern int imap4d_delete (struct imap4d_command *, imap4d_tokbuf_t);
207 extern int imap4d_examine (struct imap4d_command *, char *); 225 extern int imap4d_examine (struct imap4d_command *, imap4d_tokbuf_t);
208 extern int imap4d_expunge (struct imap4d_command *, char *); 226 extern int imap4d_expunge (struct imap4d_command *, imap4d_tokbuf_t);
209 extern int imap4d_fetch (struct imap4d_command *, char *); 227 extern int imap4d_fetch (struct imap4d_command *, imap4d_tokbuf_t);
210 extern int imap4d_fetch0 (char *, int, char *, size_t); 228 extern int imap4d_fetch0 (imap4d_tokbuf_t tok, int isuid, char **err_text);
211 extern int imap4d_list (struct imap4d_command *, char *); 229 extern int imap4d_list (struct imap4d_command *, imap4d_tokbuf_t);
212 extern int imap4d_lsub (struct imap4d_command *, char *); 230 extern int imap4d_lsub (struct imap4d_command *, imap4d_tokbuf_t);
213 extern int imap4d_login (struct imap4d_command *, char *); 231 extern int imap4d_login (struct imap4d_command *, imap4d_tokbuf_t);
214 extern int imap4d_logout (struct imap4d_command *, char *); 232 extern int imap4d_logout (struct imap4d_command *, imap4d_tokbuf_t);
215 extern int imap4d_noop (struct imap4d_command *, char *); 233 extern int imap4d_noop (struct imap4d_command *, imap4d_tokbuf_t);
216 extern int imap4d_rename (struct imap4d_command *, char *); 234 extern int imap4d_rename (struct imap4d_command *, imap4d_tokbuf_t);
217 extern int imap4d_preauth_setup (int fd); 235 extern int imap4d_preauth_setup (int fd);
218 extern int imap4d_search (struct imap4d_command *, char *); 236 extern int imap4d_search (struct imap4d_command *, imap4d_tokbuf_t);
219 extern int imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize); 237 extern int imap4d_search0 (imap4d_tokbuf_t, int isuid, char **repyptr);
220 extern int imap4d_select (struct imap4d_command *, char *); 238 extern int imap4d_select (struct imap4d_command *, imap4d_tokbuf_t);
221 extern int imap4d_select0 (struct imap4d_command *, char *, int); 239 extern int imap4d_select0 (struct imap4d_command *, char *, int);
222 extern int imap4d_select_status (void); 240 extern int imap4d_select_status (void);
223 #ifdef WITH_TLS 241 #ifdef WITH_TLS
224 extern int imap4d_starttls (struct imap4d_command *, char *); 242 extern int imap4d_starttls (struct imap4d_command *, imap4d_tokbuf_t);
225 extern void starttls_init (void); 243 extern void starttls_init (void);
226 #endif /* WITH_TLS */ 244 #endif /* WITH_TLS */
227 extern int imap4d_status (struct imap4d_command *, char *); 245 extern int imap4d_status (struct imap4d_command *, imap4d_tokbuf_t);
228 extern int imap4d_store (struct imap4d_command *, char *); 246 extern int imap4d_store (struct imap4d_command *, imap4d_tokbuf_t);
229 extern int imap4d_store0 (char *, int, char *, size_t); 247 extern int imap4d_store0 (imap4d_tokbuf_t, int, char **);
230 extern int imap4d_subscribe (struct imap4d_command *, char *); 248 extern int imap4d_subscribe (struct imap4d_command *, imap4d_tokbuf_t);
231 extern int imap4d_uid (struct imap4d_command *, char *); 249 extern int imap4d_uid (struct imap4d_command *, imap4d_tokbuf_t);
232 extern int imap4d_unsubscribe (struct imap4d_command *, char *); 250 extern int imap4d_unsubscribe (struct imap4d_command *, imap4d_tokbuf_t);
233 extern int imap4d_namespace (struct imap4d_command *, char *); 251 extern int imap4d_namespace (struct imap4d_command *, imap4d_tokbuf_t);
234 extern int imap4d_version (struct imap4d_command *, char *); 252 extern int imap4d_version (struct imap4d_command *, imap4d_tokbuf_t);
235 extern int imap4d_idle (struct imap4d_command *, char *); 253 extern int imap4d_idle (struct imap4d_command *, imap4d_tokbuf_t);
236 254
237 extern int imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid); 255 extern int imap4d_check_home_dir (const char *dir, uid_t uid, gid_t gid);
238 256
...@@ -274,25 +292,17 @@ extern int util_start (char *); ...@@ -274,25 +292,17 @@ extern int util_start (char *);
274 extern int util_finish (struct imap4d_command *, int, const char *, ...) 292 extern int util_finish (struct imap4d_command *, int, const char *, ...)
275 MU_PRINTFLIKE(3,4); 293 MU_PRINTFLIKE(3,4);
276 extern int util_getstate (void); 294 extern int util_getstate (void);
277 extern int util_do_command (char *); 295 extern int util_do_command (imap4d_tokbuf_t);
278 extern char *imap4d_readline (void);
279 extern char *imap4d_readline_ex (void);
280 extern char *util_getword (char *, char **);
281 extern char *util_getitem (char *, const char *, char **);
282 extern int util_token (char *, size_t, char **);
283 extern void util_unquote (char **);
284 extern char *util_tilde_expansion (const char *, const char *); 296 extern char *util_tilde_expansion (const char *, const char *);
285 extern char *util_getfullpath (char *, const char *); 297 extern char *util_getfullpath (char *, const char *);
286 extern int util_msgset (char *, size_t **, int *, int); 298 extern int util_msgset (char *, size_t **, int *, int);
287 extern int util_upper (char *); 299 extern int util_upper (char *);
288 extern struct imap4d_command *util_getcommand (char *, 300 extern struct imap4d_command *util_getcommand (char *,
289 struct imap4d_command []); 301 struct imap4d_command []);
290 extern int util_parse_internal_date0 (char *date, time_t *timep, char **endp);
291 extern int util_parse_internal_date (char *date, time_t *timep); 302 extern int util_parse_internal_date (char *date, time_t *timep);
292 extern int util_parse_822_date (const char *date, time_t *timep); 303 extern int util_parse_822_date (const char *date, time_t *timep);
293 extern int util_parse_ctime_date (const char *date, time_t *timep); 304 extern int util_parse_ctime_date (const char *date, time_t *timep);
294 extern char *util_strcasestr (const char *haystack, const char *needle); 305 extern char *util_strcasestr (const char *haystack, const char *needle);
295 extern int util_parse_attributes (char *items, char **save, int *flags);
296 306
297 extern int util_base64_encode (const unsigned char *input, 307 extern int util_base64_encode (const unsigned char *input,
298 size_t input_len, 308 size_t input_len,
...@@ -330,6 +340,7 @@ void util_bye (void); ...@@ -330,6 +340,7 @@ void util_bye (void);
330 void util_atexit (void (*fp) (void)); 340 void util_atexit (void (*fp) (void));
331 void util_chdir (const char *homedir); 341 void util_chdir (const char *homedir);
332 int is_atom (const char *s); 342 int is_atom (const char *s);
343 int util_isdelim (const char *str);
333 344
334 #ifdef WITH_TLS 345 #ifdef WITH_TLS
335 int imap4d_init_tls_server (void); 346 int imap4d_init_tls_server (void);
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2005, 2006, 2 Copyright (C) 1999, 2001, 2002, 2005, 2006,
3 2007 Free Software Foundation, Inc. 3 2007, 2008 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -106,6 +106,19 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) ...@@ -106,6 +106,19 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
106 } 106 }
107 107
108 /* 108 /*
109 6.3.8. LIST Command
110
111 Arguments: reference name
112 mailbox name with possible wildcards
113
114 Responses: untagged responses: LIST
115
116 Result: OK - list completed
117 NO - list failure: can't list that reference or name
118 BAD - command unknown or arguments invalid
119 */
120
121 /*
109 1- IMAP4 insists: the reference argument present in the 122 1- IMAP4 insists: the reference argument present in the
110 interpreted form SHOULD prefix the interpreted form. It SHOULD 123 interpreted form SHOULD prefix the interpreted form. It SHOULD
111 also be in the same form as the reference name argument. This 124 also be in the same form as the reference name argument. This
...@@ -126,21 +139,17 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data) ...@@ -126,21 +139,17 @@ list_fun (mu_folder_t folder, struct mu_list_response *resp, void *data)
126 but it does not match the hierarchy delimiter. */ 139 but it does not match the hierarchy delimiter. */
127 140
128 int 141 int
129 imap4d_list (struct imap4d_command *command, char *arg) 142 imap4d_list (struct imap4d_command *command, imap4d_tokbuf_t tok)
130 { 143 {
131 char *sp = NULL;
132 char *ref; 144 char *ref;
133 char *wcard; 145 char *wcard;
134 const char *delim = "/"; 146 const char *delim = "/";
135 147
136 ref = util_getword (arg, &sp); 148 if (imap4d_tokbuf_argc (tok) != 4)
137 wcard = util_getword (NULL, &sp); 149 return util_finish (command, RESP_BAD, "Invalid arguments");
138 if (!ref || !wcard) 150
139 return util_finish (command, RESP_BAD, "Too few arguments"); 151 ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
140 152 wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
141 /* Remove the double quotes. */
142 util_unquote (&ref);
143 util_unquote (&wcard);
144 153
145 /* If wildcard is empty, it is a special case: we have to 154 /* If wildcard is empty, it is a special case: we have to
146 return the hierarchy. */ 155 return the hierarchy. */
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2006, 2 Copyright (C) 1999, 2001, 2002, 2006,
3 2007 Free Software Foundation, Inc. 3 2007, 2008 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -19,26 +19,32 @@ ...@@ -19,26 +19,32 @@
19 19
20 #include "imap4d.h" 20 #include "imap4d.h"
21 21
22 /*
23 6.2.2. LOGIN Command
24
25 Arguments: user name
26 password
27
28 Responses: no specific responses for this command
29
30 Result: OK - login completed, now in authenticated state
31 NO - login failure: user name or password rejected
32 BAD - command unknown or arguments invalid
33 */
22 int 34 int
23 imap4d_login (struct imap4d_command *command, char *arg) 35 imap4d_login (struct imap4d_command *command, imap4d_tokbuf_t tok)
24 { 36 {
25 char *sp = NULL, *username, *pass; 37 char *username, *pass;
26 int rc; 38 int rc;
27 39
28 if (login_disabled || tls_required) 40 if (login_disabled || tls_required)
29 return util_finish (command, RESP_NO, "Command disabled"); 41 return util_finish (command, RESP_NO, "Command disabled");
30 42
31 username = util_getword (arg, &sp); 43 if (imap4d_tokbuf_argc (tok) != 4)
32 pass = util_getword (NULL, &sp); 44 return util_finish (command, RESP_BAD, "Invalid arguments");
33 45
34 /* Remove the double quotes. */ 46 username = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
35 util_unquote (&username); 47 pass = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
36 util_unquote (&pass);
37
38 if (username == NULL || *username == '\0' || pass == NULL)
39 return util_finish (command, RESP_NO, "Too few args");
40 else if (util_getword (NULL, &sp))
41 return util_finish (command, RESP_NO, "Too many args");
42 48
43 auth_data = mu_get_auth_by_name (username); 49 auth_data = mu_get_auth_by_name (username);
44 50
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,15 +19,21 @@ ...@@ -19,15 +19,21 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 * This needs to properly close the mailbox 22 6.1.3. LOGOUT Command
23 */ 23
24 Arguments: none
25
26 Responses: REQUIRED untagged response: BYE
27
28 Result: OK - logout completed
29 BAD - command unknown or arguments invalid
30 */
24 31
25 int 32 int
26 imap4d_logout (struct imap4d_command *command, char *arg) 33 imap4d_logout (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 34 {
28 char *sp = NULL; 35 if (imap4d_tokbuf_argc (tok) != 2)
29 if (util_getword (arg, &sp)) 36 return util_finish (command, RESP_BAD, "Invalid arguments");
30 return util_finish (command, RESP_BAD, "Too many args");
31 imap4d_bye0 (OK, command); 37 imap4d_bye0 (OK, command);
32 return 0; 38 return 0;
33 } 39 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,13 +19,20 @@ ...@@ -19,13 +19,20 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 * 22 6.3.9. LSUB Command
23 */
24 23
24 Arguments: reference name
25 mailbox name with possible wildcards
26
27 Responses: untagged responses: LSUB
28
29 Result: OK - lsub completed
30 NO - lsub failure: can't list that reference or name
31 BAD - command unknown or arguments invalid
32 */
25 int 33 int
26 imap4d_lsub (struct imap4d_command *command, char *arg) 34 imap4d_lsub (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 35 {
28 char *sp;
29 char *ref; 36 char *ref;
30 char *wcard; 37 char *wcard;
31 char *file = NULL; 38 char *file = NULL;
...@@ -33,14 +40,11 @@ imap4d_lsub (struct imap4d_command *command, char *arg) ...@@ -33,14 +40,11 @@ imap4d_lsub (struct imap4d_command *command, char *arg)
33 const char *delim = "/"; 40 const char *delim = "/";
34 FILE *fp; 41 FILE *fp;
35 42
36 ref = util_getword (arg, &sp); 43 if (imap4d_tokbuf_argc (tok) != 4)
37 wcard = util_getword (NULL, &sp); 44 return util_finish (command, RESP_BAD, "Invalid arguments");
38 if (!ref || !wcard) 45
39 return util_finish (command, RESP_BAD, "Too few arguments"); 46 ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
40 47 wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
41 /* Remove the double quotes. */
42 util_unquote (&ref);
43 util_unquote (&wcard);
44 48
45 asprintf (&pattern, "%s%s", ref, wcard); 49 asprintf (&pattern, "%s%s", ref, wcard);
46 if (!pattern) 50 if (!pattern)
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -89,8 +89,9 @@ print_namespace (int n) ...@@ -89,8 +89,9 @@ print_namespace (int n)
89 util_send ("("); 89 util_send ("(");
90 for (i = 0; i < namespace[n].subdir_c; i++) 90 for (i = 0; i < namespace[n].subdir_c; i++)
91 { 91 {
92 util_send ("(\"%s\" \"/\")", 92 char *dir = printable_pathname (namespace[n].subdir_v[i]);
93 printable_pathname (namespace[n].subdir_v[i])); 93 char *suf = (dir[0] && dir[strlen (dir) - 1] != '/') ? "/" : "";
94 util_send ("(\"%s%s\" \"/\")", dir, suf);
94 } 95 }
95 util_send (")"); 96 util_send (")");
96 } 97 }
...@@ -114,11 +115,27 @@ namespace_enumerate_all (nsfp_t f, void *closure) ...@@ -114,11 +115,27 @@ namespace_enumerate_all (nsfp_t f, void *closure)
114 || namespace_enumerate (NS_SHARED, f, closure); 115 || namespace_enumerate (NS_SHARED, f, closure);
115 } 116 }
116 117
118 /*
119 5. NAMESPACE Command
120
121 Arguments: none
122
123 Response: an untagged NAMESPACE response that contains the prefix
124 and hierarchy delimiter to the server's Personal
125 Namespace(s), Other Users' Namespace(s), and Shared
126 Namespace(s) that the server wishes to expose. The
127 response will contain a NIL for any namespace class
128 that is not available. Namespace_Response_Extensions
129 MAY be included in the response.
130 Namespace_Response_Extensions which are not on the IETF
131 standards track, MUST be prefixed with an "X-".
132 */
133
117 int 134 int
118 imap4d_namespace (struct imap4d_command *command, char *arg) 135 imap4d_namespace (struct imap4d_command *command, imap4d_tokbuf_t tok)
119 { 136 {
120 if (*arg) 137 if (imap4d_tokbuf_argc (tok) != 2)
121 return util_finish (command, RESP_BAD, "Too many arguments"); 138 return util_finish (command, RESP_BAD, "Invalid arguments");
122 139
123 util_send ("* NAMESPACE "); 140 util_send ("* NAMESPACE ");
124 141
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,13 +19,10 @@ ...@@ -19,13 +19,10 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 int 21 int
22 imap4d_noop (struct imap4d_command *command, char *arg) 22 imap4d_noop (struct imap4d_command *command, imap4d_tokbuf_t tok)
23 { 23 {
24 char *sp = NULL; 24 if (imap4d_tokbuf_argc (tok) != 2)
25 25 return util_finish (command, RESP_BAD, "Invalid arguments");
26 if (util_getword (arg, &sp))
27 return util_finish (command, RESP_BAD, "Too many args");
28
29 imap4d_sync (); 26 imap4d_sync ();
30 return util_finish (command, RESP_OK, "Completed"); 27 return util_finish (command, RESP_OK, "Completed");
31 } 28 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,30 +19,37 @@ ...@@ -19,30 +19,37 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 6.3.5. RENAME Command
23
24 Arguments: existing mailbox name
25 new mailbox name
26
27 Responses: no specific responses for this command
28
29 Result: OK - rename completed
30 NO - rename failure: can't rename mailbox with that name,
31 can't rename to mailbox with that name
32 BAD - command unknown or arguments invalid
33 */
34 /*
22 FIXME: Renaming a mailbox we must change the UIDVALIDITY 35 FIXME: Renaming a mailbox we must change the UIDVALIDITY
23 of the mailbox. */ 36 of the mailbox. */
24 37
25 int 38 int
26 imap4d_rename (struct imap4d_command *command, char *arg) 39 imap4d_rename (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 40 {
28 char *oldname; 41 char *oldname;
29 char *newname; 42 char *newname;
30 char *sp = NULL;
31 int rc = RESP_OK; 43 int rc = RESP_OK;
32 const char *msg = "Completed"; 44 const char *msg = "Completed";
33 struct stat newst; 45 struct stat newst;
34 const char *delim = "/"; 46 const char *delim = "/";
35 47
36 oldname = util_getword (arg, &sp); 48 if (imap4d_tokbuf_argc (tok) != 4)
37 newname = util_getword (NULL, &sp); 49 return util_finish (command, RESP_BAD, "Invalid arguments");
38 if (!newname || !oldname) 50
39 return util_finish (command, RESP_BAD, "Too few arguments"); 51 oldname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
40 52 newname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
41 util_unquote (&newname);
42 util_unquote (&oldname);
43
44 if (*newname == '\0' || *oldname == '\0')
45 return util_finish (command, RESP_BAD, "Too few arguments");
46 53
47 if (strcasecmp (newname, "INBOX") == 0) 54 if (strcasecmp (newname, "INBOX") == 0)
48 return util_finish (command, RESP_NO, "Name Inbox is reservered"); 55 return util_finish (command, RESP_NO, "Name Inbox is reservered");
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2002, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2002, 2005, 2007,
3 2008 Free Software Foundation, Inc.
3 4
4 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -223,11 +224,9 @@ struct mem_chain ...@@ -223,11 +224,9 @@ struct mem_chain
223 /* Parse buffer structure */ 224 /* Parse buffer structure */
224 struct parsebuf 225 struct parsebuf
225 { 226 {
226 char *token; /* Current token. Either points to tokbuf 227 imap4d_tokbuf_t tok; /* Token buffer */
227 or is allocated within `alloc' chain */ 228 int arg; /* Argument number */
228 char tokbuf[MAXTOKEN+1]; /* Token buffer for short tokens */ 229 char *token; /* Current token */
229
230 char *arg; /* Rest of command line to be parsed */
231 int isuid; /* UIDs instead of msgnos are required */ 230 int isuid; /* UIDs instead of msgnos are required */
232 char *err_mesg; /* Error message if a parse error occured */ 231 char *err_mesg; /* Error message if a parse error occured */
233 struct mem_chain *alloc; /* Chain of objects allocated during parsing */ 232 struct mem_chain *alloc; /* Chain of objects allocated during parsing */
...@@ -249,30 +248,45 @@ static int parse_gettoken (struct parsebuf *pb, int req); ...@@ -249,30 +248,45 @@ static int parse_gettoken (struct parsebuf *pb, int req);
249 static int search_run (struct parsebuf *pb); 248 static int search_run (struct parsebuf *pb);
250 static void do_search (struct parsebuf *pb); 249 static void do_search (struct parsebuf *pb);
251 250
251 /*
252 6.4.4. SEARCH Command
253
254 Arguments: OPTIONAL [CHARSET] specification
255 searching criteria (one or more)
256
257 Responses: REQUIRED untagged response: SEARCH
258
259 Result: OK - search completed
260 NO - search error: can't search that [CHARSET] or
261 criteria
262 BAD - command unknown or arguments invalid
263 */
264
252 int 265 int
253 imap4d_search (struct imap4d_command *command, char *arg) 266 imap4d_search (struct imap4d_command *command, imap4d_tokbuf_t tok)
254 { 267 {
255 int rc; 268 int rc;
256 char buffer[64]; 269 char *err_text= "";
257 270
258 rc = imap4d_search0 (arg, 0, buffer, sizeof buffer); 271 rc = imap4d_search0 (tok, 0, &err_text);
259 return util_finish (command, rc, "%s", buffer); 272 return util_finish (command, rc, "%s", err_text);
260 } 273 }
261 274
262 int 275 int
263 imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) 276 imap4d_search0 (imap4d_tokbuf_t tok, int isuid, char **err_text)
264 { 277 {
265 struct parsebuf parsebuf; 278 struct parsebuf parsebuf;
266 279
267 memset (&parsebuf, 0, sizeof(parsebuf)); 280 memset (&parsebuf, 0, sizeof(parsebuf));
268 parsebuf.arg = arg; 281 parsebuf.tok = tok;
282 parsebuf.arg = IMAP4_ARG_1 + !!isuid;
269 parsebuf.err_mesg = NULL; 283 parsebuf.err_mesg = NULL;
270 parsebuf.alloc = NULL; 284 parsebuf.alloc = NULL;
271 parsebuf.isuid = isuid; 285 parsebuf.isuid = isuid;
272 286
273 if (!parse_gettoken (&parsebuf, 0)) 287 if (!parse_gettoken (&parsebuf, 0))
274 { 288 {
275 snprintf (replybuf, replysize, "Too few args"); 289 *err_text = "Too few args";
276 return RESP_BAD; 290 return RESP_BAD;
277 } 291 }
278 292
...@@ -280,20 +294,20 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) ...@@ -280,20 +294,20 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize)
280 { 294 {
281 if (!parse_gettoken (&parsebuf, 0)) 295 if (!parse_gettoken (&parsebuf, 0))
282 { 296 {
283 snprintf (replybuf, replysize, "Too few args"); 297 *err_text = "Too few args";
284 return RESP_BAD; 298 return RESP_BAD;
285 } 299 }
286 300
287 /* Currently only ASCII is supported */ 301 /* Currently only ASCII is supported */
288 if (strcasecmp (parsebuf.token, "US-ASCII")) 302 if (strcasecmp (parsebuf.token, "US-ASCII"))
289 { 303 {
290 snprintf (replybuf, replysize, "Charset not supported"); 304 *err_text = "Charset not supported";
291 return RESP_NO; 305 return RESP_NO;
292 } 306 }
293 307
294 if (!parse_gettoken (&parsebuf, 0)) 308 if (!parse_gettoken (&parsebuf, 0))
295 { 309 {
296 snprintf (replybuf, replysize, "Too few args"); 310 *err_text = "Too few args";
297 return RESP_BAD; 311 return RESP_BAD;
298 } 312 }
299 313
...@@ -304,16 +318,14 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) ...@@ -304,16 +318,14 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize)
304 if (!parsebuf.tree) 318 if (!parsebuf.tree)
305 { 319 {
306 parse_free_mem (&parsebuf); 320 parse_free_mem (&parsebuf);
307 snprintf (replybuf, replysize, "%s (near %s)", 321 *err_text = "Parse error";
308 parsebuf.err_mesg,
309 *parsebuf.arg ? parsebuf.arg : "end");
310 return RESP_BAD; 322 return RESP_BAD;
311 } 323 }
312 324
313 if (parsebuf.token[0] != 0) 325 if (parsebuf.token)
314 { 326 {
315 parse_free_mem (&parsebuf); 327 parse_free_mem (&parsebuf);
316 snprintf (replybuf, replysize, "Junk at the end of statement"); 328 *err_text = "Junk at the end of statement";
317 return RESP_BAD; 329 return RESP_BAD;
318 } 330 }
319 331
...@@ -322,7 +334,7 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize) ...@@ -322,7 +334,7 @@ imap4d_search0 (char *arg, int isuid, char *replybuf, size_t replysize)
322 334
323 parse_free_mem (&parsebuf); 335 parse_free_mem (&parsebuf);
324 336
325 snprintf (replybuf, replysize, "Completed"); 337 *err_text = "Completed";
326 return RESP_OK; 338 return RESP_OK;
327 } 339 }
328 340
...@@ -359,41 +371,13 @@ do_search (struct parsebuf *pb) ...@@ -359,41 +371,13 @@ do_search (struct parsebuf *pb)
359 int 371 int
360 parse_gettoken (struct parsebuf *pb, int req) 372 parse_gettoken (struct parsebuf *pb, int req)
361 { 373 {
362 int rc; 374 if (req && pb->arg >= imap4d_tokbuf_argc (pb->tok))
363 char *s;
364
365 pb->token = pb->tokbuf;
366 while (*pb->arg && *pb->arg == ' ')
367 pb->arg++;
368 switch (*pb->arg)
369 { 375 {
370 case '(': 376 pb->err_mesg = "Unexpected end of statement";
371 case ')': 377 return 0;
372 pb->token[0] = *pb->arg++;
373 pb->token[1] = 0;
374 rc = 1;
375 break;
376 case '"':
377 s = ++pb->arg;
378 while (*pb->arg && *pb->arg != '"')
379 pb->arg++;
380 rc = pb->arg - s;
381 if (*pb->arg)
382 pb->arg++;
383
384 if (rc >= sizeof(pb->tokbuf))
385 pb->token = parse_alloc (pb, rc+1);
386 memcpy (pb->token, s, rc);
387 pb->token[rc] = 0;
388 break;
389
390 default:
391 rc = util_token (pb->token, sizeof(pb->tokbuf), &pb->arg);
392 break;
393 } 378 }
394 if (req && rc == 0) 379 pb->token = imap4d_tokbuf_getarg (pb->tok, pb->arg++);
395 pb->err_mesg = "Unexpected end of statement"; 380 return 1;
396 return rc;
397 } 381 }
398 382
399 /* Memory handling */ 383 /* Memory handling */
...@@ -468,7 +452,7 @@ parse_search_key_list (struct parsebuf *pb) ...@@ -468,7 +452,7 @@ parse_search_key_list (struct parsebuf *pb)
468 { 452 {
469 struct search_node *leftarg = NULL; 453 struct search_node *leftarg = NULL;
470 454
471 while (pb->token[0] && pb->token[0] != ')') 455 while (pb->token && pb->token[0] != ')')
472 { 456 {
473 struct search_node *rightarg = parse_search_key (pb); 457 struct search_node *rightarg = parse_search_key (pb);
474 if (!rightarg) 458 if (!rightarg)
...@@ -563,8 +547,8 @@ parse_equiv_key (struct parsebuf *pb) ...@@ -563,8 +547,8 @@ parse_equiv_key (struct parsebuf *pb)
563 { 547 {
564 struct search_node *node; 548 struct search_node *node;
565 struct cond_equiv *condp; 549 struct cond_equiv *condp;
566 char *arg; 550 int save_arg;
567 char *save_arg; 551 imap4d_tokbuf_t save_tok;
568 552
569 for (condp = equiv_list; condp->name && strcasecmp (condp->name, pb->token); 553 for (condp = equiv_list; condp->name && strcasecmp (condp->name, pb->token);
570 condp++) 554 condp++)
...@@ -574,8 +558,9 @@ parse_equiv_key (struct parsebuf *pb) ...@@ -574,8 +558,9 @@ parse_equiv_key (struct parsebuf *pb)
574 return parse_simple_key (pb); 558 return parse_simple_key (pb);
575 559
576 save_arg = pb->arg; 560 save_arg = pb->arg;
577 arg = parse_strdup (pb, condp->equiv); 561 save_tok = pb->tok;
578 pb->arg = arg; 562 pb->tok = imap4d_tokbuf_from_string (condp->equiv);
563 pb->arg = 0;
579 564
580 parse_gettoken (pb, 0); 565 parse_gettoken (pb, 0);
581 566
...@@ -584,11 +569,13 @@ parse_equiv_key (struct parsebuf *pb) ...@@ -584,11 +569,13 @@ parse_equiv_key (struct parsebuf *pb)
584 { 569 {
585 /* shouldn't happen? */ 570 /* shouldn't happen? */
586 mu_diag_output (MU_DIAG_CRIT, _("%s:%d: INTERNAL ERROR (please report)"), 571 mu_diag_output (MU_DIAG_CRIT, _("%s:%d: INTERNAL ERROR (please report)"),
587 __FILE__, __LINE__); 572 __FILE__, __LINE__);
588 abort (); 573 abort ();
589 } 574 }
575 imap4d_tokbuf_destroy (&pb->tok);
590 576
591 pb->arg = save_arg; 577 pb->arg = save_arg;
578 pb->tok = save_tok;
592 parse_gettoken (pb, 0); 579 parse_gettoken (pb, 0);
593 return node; 580 return node;
594 } 581 }
...@@ -658,7 +645,7 @@ parse_simple_key (struct parsebuf *pb) ...@@ -658,7 +645,7 @@ parse_simple_key (struct parsebuf *pb)
658 return NULL; 645 return NULL;
659 } 646 }
660 647
661 if (!pb->token[0]) 648 if (!pb->token)
662 { 649 {
663 pb->err_mesg = "Not enough arguments for criterion"; 650 pb->err_mesg = "Not enough arguments for criterion";
664 return NULL; 651 return NULL;
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2003, 2005, 2006, 2 Copyright (C) 1999, 2001, 2003, 2005, 2006,
3 2007 Free Software Foundation, Inc. 3 2007, 2008 Free Software Foundation, Inc.
4 4
5 GNU Mailutils is free software; you can redistribute it and/or modify 5 GNU Mailutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
...@@ -24,25 +24,22 @@ static int select_flags; ...@@ -24,25 +24,22 @@ static int select_flags;
24 /* select ::= "SELECT" SPACE mailbox */ 24 /* select ::= "SELECT" SPACE mailbox */
25 25
26 int 26 int
27 imap4d_select (struct imap4d_command *command, char *arg) 27 imap4d_select (struct imap4d_command *command, imap4d_tokbuf_t tok)
28 { 28 {
29 return imap4d_select0 (command, arg, MU_STREAM_RDWR); 29 if (imap4d_tokbuf_argc (tok) != 3)
30 return util_finish (command, RESP_BAD, "Invalid arguments");
31 return imap4d_select0 (command, imap4d_tokbuf_getarg (tok, IMAP4_ARG_1),
32 MU_STREAM_RDWR);
30 } 33 }
31 34
32 /* This code is share with EXAMINE. */ 35 /* This code is share with EXAMINE. */
33 int 36 int
34 imap4d_select0 (struct imap4d_command *command, char *arg, int flags) 37 imap4d_select0 (struct imap4d_command *command, char *mailbox_name, int flags)
35 { 38 {
36 char *mailbox_name, *sp = NULL;
37 int status; 39 int status;
38 40
39 /* FIXME: Check state. */ 41 /* FIXME: Check state. */
40 42
41 mailbox_name = util_getword (arg, &sp);
42 util_unquote (&mailbox_name);
43 if (mailbox_name == NULL || *mailbox_name == '\0')
44 return util_finish (command, RESP_BAD, "Too few arguments");
45
46 /* Even if a mailbox is selected, a SELECT EXAMINE or LOGOUT 43 /* Even if a mailbox is selected, a SELECT EXAMINE or LOGOUT
47 command MAY be issued without previously issuing a CLOSE command. 44 command MAY be issued without previously issuing a CLOSE command.
48 The SELECT, EXAMINE, and LOGUT commands implictly close the 45 The SELECT, EXAMINE, and LOGUT commands implictly close the
......
...@@ -23,17 +23,26 @@ ...@@ -23,17 +23,26 @@
23 static int tls_available; 23 static int tls_available;
24 static int tls_done; 24 static int tls_done;
25 25
26 /*
27 6.2.1. STARTTLS Command
28
29 Arguments: none
30
31 Responses: no specific response for this command
32
33 Result: OK - starttls completed, begin TLS negotiation
34 BAD - command unknown or arguments invalid
35 */
26 int 36 int
27 imap4d_starttls (struct imap4d_command *command, char *arg) 37 imap4d_starttls (struct imap4d_command *command, imap4d_tokbuf_t tok)
28 { 38 {
29 int status; 39 int status;
30 char *sp = NULL;
31 40
32 if (!tls_available || tls_done) 41 if (!tls_available || tls_done)
33 return util_finish (command, RESP_BAD, "Invalid command"); 42 return util_finish (command, RESP_BAD, "Invalid command");
34 43
35 if (util_getword (arg, &sp)) 44 if (imap4d_tokbuf_argc (tok) != 2)
36 return util_finish (command, RESP_BAD, "Too many args"); 45 return util_finish (command, RESP_BAD, "Invalid arguments");
37 46
38 util_atexit (mu_deinit_tls_libs); 47 util_atexit (mu_deinit_tls_libs);
39 48
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -52,11 +52,22 @@ status_get_handler (const char *name) ...@@ -52,11 +52,22 @@ status_get_handler (const char *name)
52 return p->fun; 52 return p->fun;
53 return NULL; 53 return NULL;
54 } 54 }
55 55
56 /*
57 6.3.10. STATUS Command
58
59 Arguments: mailbox name
60 status data item names
61
62 Responses: untagged responses: STATUS
63
64 Result: OK - status completed
65 NO - status failure: no status for that name
66 BAD - command unknown or arguments invalid
67 */
56 int 68 int
57 imap4d_status (struct imap4d_command *command, char *arg) 69 imap4d_status (struct imap4d_command *command, imap4d_tokbuf_t tok)
58 { 70 {
59 char *sp = NULL;
60 char *name; 71 char *name;
61 char *mailbox_name; 72 char *mailbox_name;
62 const char *delim = "/"; 73 const char *delim = "/";
...@@ -64,11 +75,12 @@ imap4d_status (struct imap4d_command *command, char *arg) ...@@ -64,11 +75,12 @@ imap4d_status (struct imap4d_command *command, char *arg)
64 int status; 75 int status;
65 int count = 0; 76 int count = 0;
66 char *err_msg = NULL; 77 char *err_msg = NULL;
78 int argc = imap4d_tokbuf_argc (tok);
79
80 if (argc < 4)
81 return util_finish (command, RESP_BAD, "Invalid arguments");
67 82
68 name = util_getword (arg, &sp); 83 name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
69 util_unquote (&name);
70 if (!name || *name == '\0' || !sp || *sp == '\0')
71 return util_finish (command, RESP_BAD, "Too few args");
72 84
73 mailbox_name = namespace_getfullpath (name, delim); 85 mailbox_name = namespace_getfullpath (name, delim);
74 86
...@@ -85,20 +97,22 @@ imap4d_status (struct imap4d_command *command, char *arg) ...@@ -85,20 +97,22 @@ imap4d_status (struct imap4d_command *command, char *arg)
85 status = mu_mailbox_open (smbox, MU_STREAM_READ); 97 status = mu_mailbox_open (smbox, MU_STREAM_READ);
86 if (status == 0) 98 if (status == 0)
87 { 99 {
88 char item[32]; 100 int i = IMAP4_ARG_2;
89 item[0] = '\0'; 101 char *item = imap4d_tokbuf_getarg (tok, i);
90
91 if (*sp == '(')
92 sp++;
93 else
94 *sp = 0;
95 102
96 /* Get the status item names. */ 103 if (item[0] == '(')
97 while (*sp && *sp != ')') 104 {
105 if (imap4d_tokbuf_getarg (tok, argc - 1)[0] != ')')
106 return util_finish (command, RESP_BAD, "Invalid arguments");
107 argc--;
108 i++;
109 }
110
111 for (; i < argc; i++)
98 { 112 {
99 status_funcp fun; 113 status_funcp fun;
100 114
101 util_token (item, sizeof (item), &sp); 115 item = imap4d_tokbuf_getarg (tok, i);
102 fun = status_get_handler (item); 116 fun = status_get_handler (item);
103 if (!fun) 117 if (!fun)
104 { 118 {
...@@ -112,6 +126,8 @@ imap4d_status (struct imap4d_command *command, char *arg) ...@@ -112,6 +126,8 @@ imap4d_status (struct imap4d_command *command, char *arg)
112 if (!fun (smbox)) 126 if (!fun (smbox))
113 util_send (" "); 127 util_send (" ");
114 } 128 }
129
130
115 if (count > 0) 131 if (count > 0)
116 util_send (")\r\n"); 132 util_send (")\r\n");
117 mu_mailbox_close (smbox); 133 mu_mailbox_close (smbox);
...@@ -193,5 +209,4 @@ status_unseen (mu_mailbox_t smbox) ...@@ -193,5 +209,4 @@ status_unseen (mu_mailbox_t smbox)
193 } 209 }
194 util_send ("UNSEEN %d", unseen); 210 util_send ("UNSEEN %d", unseen);
195 return 0; 211 return 0;
196
197 } 212 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2005, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2005, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -23,134 +23,155 @@ ...@@ -23,134 +23,155 @@
23 */ 23 */
24 24
25 int 25 int
26 imap4d_store (struct imap4d_command *command, char *arg) 26 imap4d_store (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 27 {
28 int rc; 28 int rc;
29 char buffer[64]; 29 char *err_text;
30
31 rc = imap4d_store0 (tok, 0, &err_text);
32 return util_finish (command, rc, "%s", err_text);
33 }
34
35 struct parsebuf
36 {
37 char *token;
38 imap4d_tokbuf_t tok;
39 int arg;
40 jmp_buf errjmp;
41 char *err_text;
42 };
43
44 static void
45 parsebuf_exit (struct parsebuf *p, char *text)
46 {
47 p->err_text = text;
48 longjmp (p->errjmp, 1);
49 }
30 50
31 rc = imap4d_store0 (arg, 0, buffer, sizeof buffer); 51 static char *
32 return util_finish (command, rc, "%s", buffer); 52 parsebuf_next (struct parsebuf *p, int req)
53 {
54 p->token = imap4d_tokbuf_getarg (p->tok, p->arg++);
55 if (!p->token && req)
56 parsebuf_exit (p, "Too few arguments");
57 return p->token;
33 } 58 }
34 59
35 int 60 int
36 imap4d_store0 (char *arg, int isuid, char *resp, size_t resplen) 61 imap4d_store0 (imap4d_tokbuf_t tok, int isuid, char **ptext)
37 { 62 {
38 char *msgset; 63 char *msgset;
39 char *data;
40 char *sp = NULL;
41 int status; 64 int status;
42 int ack = 0; 65 int ack = 1;
43 size_t i; 66 size_t i;
44 int n = 0; 67 int n = 0;
45 size_t *set = NULL; 68 size_t *set = NULL;
46 enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how; 69 enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how;
47 70 struct parsebuf pb;
48 msgset = util_getword (arg, &sp); 71 char *data;
49 data = util_getword (NULL, &sp); 72 int type = 0;
50 73
51 if (!msgset || !data || !sp || *sp == '\0') 74 pb.tok = tok;
75 pb.arg = IMAP4_ARG_1;
76 pb.err_text = NULL;
77 if (setjmp (pb.errjmp))
52 { 78 {
53 snprintf (resp, resplen, "Too few args"); 79 *ptext = pb.err_text;
80 free (set);
54 return RESP_BAD; 81 return RESP_BAD;
55 } 82 }
83
84 msgset = parsebuf_next (&pb, 1);
85 data = parsebuf_next (&pb, 1);
56 86
57 /* The parsing of the data-item is a little slugish. */ 87 if (*data == '+')
58 if (strcasecmp (data, "FLAGS") == 0)
59 {
60 ack = 1;
61 how = STORE_SET;
62 }
63 else if (strcasecmp (data, "+FLAGS") == 0)
64 { 88 {
65 ack = 1;
66 how = STORE_ADD; 89 how = STORE_ADD;
90 data++;
67 } 91 }
68 else if (strcasecmp (data, "-FLAGS") == 0) 92 else if (*data == '-')
69 { 93 {
70 ack = 1;
71 how = STORE_UNSET;
72 }
73 else if (strcasecmp (data, "FLAGS.SILENT") == 0)
74 {
75 ack = 0;
76 how = STORE_SET;
77 }
78 else if (strcasecmp (data, "+FLAGS.SILENT") == 0)
79 {
80 ack = 0;
81 how = STORE_ADD;
82 }
83 else if (strcasecmp (data, "-FLAGS.SILENT") == 0)
84 {
85 ack = 0;
86 how = STORE_UNSET; 94 how = STORE_UNSET;
95 data++;
87 } 96 }
88 else 97 else
98 how = STORE_SET;
99
100 if (strcasecmp (data, "FLAGS"))
101 parsebuf_exit (&pb, "Bogus data item");
102 data = parsebuf_next (&pb, 1);
103
104 if (*data == '.')
89 { 105 {
90 snprintf (resp, resplen, "Bogus data item"); 106 data = parsebuf_next (&pb, 1);
91 return RESP_BAD; 107 if (strcasecmp (data, "SILENT") == 0)
108 {
109 ack = 0;
110 parsebuf_next (&pb, 1);
111 }
112 else
113 parsebuf_exit (&pb, "Bogus data suffix");
92 } 114 }
93 115
94 /* Get the message numbers in set[]. */ 116 /* Get the message numbers in set[]. */
95 status = util_msgset (msgset, &set, &n, isuid); 117 status = util_msgset (msgset, &set, &n, isuid);
96 if (status != 0) 118 if (status != 0)
119 parsebuf_exit (&pb, "Bogus number set");
120
121 if (pb.token[0] != '(')
122 parsebuf_exit (&pb, "Syntax error");
123 parsebuf_next (&pb, 1);
124
125 do
97 { 126 {
98 snprintf (resp, resplen, "Bogus number set"); 127 int t;
99 return RESP_BAD; 128 if (!util_attribute_to_type (pb.token, &t))
129 type |= t;
100 } 130 }
131 while (parsebuf_next (&pb, 1) && pb.token[0] != ')');
101 132
102 for (i = 0; i < n; i++) 133 for (i = 0; i < n; i++)
103 { 134 {
104 mu_message_t msg = NULL; 135 mu_message_t msg = NULL;
105 mu_attribute_t attr = NULL; 136 mu_attribute_t attr = NULL;
106 char *items = strdup (sp); /* Don't use the orignal list. */ 137 size_t msgno = isuid ? uid_to_msgno (set[i]) : set[i];
107 int first = 1; 138
108 size_t msgno;
109 char *p = items;
110
111 msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
112 if (msgno) 139 if (msgno)
113 { 140 {
114 mu_mailbox_get_message (mbox, msgno, &msg); 141 mu_mailbox_get_message (mbox, msgno, &msg);
115 mu_message_get_attribute (msg, &attr); 142 mu_message_get_attribute (msg, &attr);
116 143
117 /* Get the fetch command names. */ 144 switch (how)
118 while (*items && *items != ')')
119 { 145 {
120 int type = 0; 146 case STORE_ADD:
121 char item[64] = ""; 147 mu_attribute_set_flags (attr, type);
122 util_token (item, sizeof (item), &items); 148 break;
123 if (!util_attribute_to_type (item, &type)) 149
124 { 150 case STORE_UNSET:
125 if (how == STORE_ADD ) 151 mu_attribute_unset_flags (attr, type);
126 mu_attribute_set_flags (attr, type); 152 break;
127 else if (how == STORE_UNSET ) 153
128 mu_attribute_unset_flags (attr, type); 154 case STORE_SET:
129 else if (how == STORE_SET ) 155 mu_attribute_unset_flags (attr, 0xffffffff); /* FIXME */
130 { 156 mu_attribute_set_flags (attr, type);
131 if (first)
132 {
133 mu_attribute_set_flags (attr, 0);
134 first = 0;
135 }
136 mu_attribute_set_flags (attr, type);
137 }
138 mu_attribute_set_flags (attr, MU_ATTRIBUTE_MODIFIED);
139 }
140 } 157 }
141 } 158 }
159
142 if (ack) 160 if (ack)
143 { 161 {
144 util_send ("* %d FETCH (", msgno); 162 util_send ("* %d FETCH (", msgno);
145 fetch_flags0 ("FLAGS", msg, isuid); 163
146 util_send (")\r\n"); 164 if (isuid)
165 util_send ("UID %lu ", (unsigned long) msgno);
166 util_send ("FLAGS (");
167 util_print_flags (attr);
168 util_send ("))\r\n");
147 } 169 }
148 free (p);
149 /* Update the flags of uid table. */ 170 /* Update the flags of uid table. */
150 imap4d_sync_flags (set[i]); 171 imap4d_sync_flags (set[i]);
151 } 172 }
152 free (set); 173 free (set);
153 snprintf (resp, resplen, "Completed"); 174 *ptext = "Completed";
154 return RESP_OK; 175 return RESP_OK;
155 } 176 }
156 177
......
...@@ -19,21 +19,27 @@ ...@@ -19,21 +19,27 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 /* 21 /*
22 FIXME: We need to lock the file to prevent simultaneous access. 22 6.3.6. SUBSCRIBE Command
23 */
24 23
24 Arguments: mailbox
25
26 Responses: no specific responses for this command
27
28 Result: OK - subscribe completed
29 NO - subscribe failure: can't subscribe to that name
30 BAD - command unknown or arguments invalid
31 */
25 int 32 int
26 imap4d_subscribe (struct imap4d_command *command, char *arg) 33 imap4d_subscribe (struct imap4d_command *command, imap4d_tokbuf_t tok)
27 { 34 {
28 char *sp = NULL;
29 char *name; 35 char *name;
30 char *file; 36 char *file;
31 FILE *fp; 37 FILE *fp;
32 38
33 name = util_getword (arg, &sp); 39 if (imap4d_tokbuf_argc (tok) != 3)
34 util_unquote (&name); 40 return util_finish (command, RESP_BAD, "Invalid arguments");
35 if (!name || *name == '\0') 41
36 return util_finish (command, RESP_BAD, "Too few arguments"); 42 name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
37 43
38 asprintf (&file, "%s/.mailboxlist", homedir); 44 asprintf (&file, "%s/.mailboxlist", homedir);
39 fp = fopen (file, "a"); 45 fp = fopen (file, "a");
......
1 # -*- tcl -*- 1 # -*- tcl -*-
2 # This file is part of Mailutils testsuite. 2 # This file is part of Mailutils testsuite.
3 # Copyright (C) 2002, 2007 Free Software Foundation 3 # Copyright (C) 2002, 2007, 2008 Free Software Foundation
4 # 4 #
5 # This program is free software; you can redistribute it and/or modify 5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by 6 # it under the terms of the GNU General Public License as published by
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
20 imap4d_start 20 imap4d_start
21 21
22 imap4d_test "CAPABILITY" \ 22 imap4d_test "CAPABILITY" \
23 "CAPABILITY IMAP4rev1 NAMESPACE IDLE X-VERSION" \ 23 "CAPABILITY IMAP4rev1 NAMESPACE IDLE LITERAL+ X-VERSION" \
24 "OK" 24 "OK"
25 imap4d_test "NOOP" 25 imap4d_test "NOOP"
26 26
......
...@@ -48,7 +48,7 @@ Hello Joe, do you think we can meet at 3:30 tomorrow? ...@@ -48,7 +48,7 @@ Hello Joe, do you think we can meet at 3:30 tomorrow?
48 48
49 " 49 "
50 50
51 imap4d_test -long "APPEND mbox 25-Aug-2002 18:00:00 +0200"\ 51 imap4d_test -long "APPEND mbox \"25-Aug-2002 18:00:00 +0200\""\
52 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) 52 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
53 From: Fred Foobar <foobar@Blurdybloop.COM> 53 From: Fred Foobar <foobar@Blurdybloop.COM>
54 Subject: afternoon meeting again 54 Subject: afternoon meeting again
...@@ -72,7 +72,7 @@ imap4d_test "SELECT mbox"\ ...@@ -72,7 +72,7 @@ imap4d_test "SELECT mbox"\
72 "OK" 72 "OK"
73 73
74 imap4d_test "FETCH 2:3 BODY\[\]"\ 74 imap4d_test "FETCH 2:3 BODY\[\]"\
75 "2 FETCH (FLAGS (\\Seen) BODY\[\] {310}"\ 75 "2 FETCH (FLAGS (\\Seen) BODY\[\] {312}"\
76 -literal\ 76 -literal\
77 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\ 77 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\
78 "From: Fred Foobar <foobar@Blurdybloop.COM>"\ 78 "From: Fred Foobar <foobar@Blurdybloop.COM>"\
...@@ -83,9 +83,10 @@ imap4d_test "FETCH 2:3 BODY\[\]"\ ...@@ -83,9 +83,10 @@ imap4d_test "FETCH 2:3 BODY\[\]"\
83 "Content-Type: TEXT/PLAIN; CHARSET=US-ASCII"\ 83 "Content-Type: TEXT/PLAIN; CHARSET=US-ASCII"\
84 ""\ 84 ""\
85 "Hello Joe, do you think we can meet at 3:30 tomorrow?"\ 85 "Hello Joe, do you think we can meet at 3:30 tomorrow?"\
86 ""\
86 ")"\ 87 ")"\
87 -noliteral\ 88 -noliteral\
88 "3 FETCH (FLAGS (\\Seen) BODY\[\] {283}"\ 89 "3 FETCH (FLAGS (\\Seen) BODY\[\] {285}"\
89 -literal\ 90 -literal\
90 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\ 91 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)"\
91 "From: Fred Foobar <foobar@Blurdybloop.COM>"\ 92 "From: Fred Foobar <foobar@Blurdybloop.COM>"\
......
...@@ -37,7 +37,7 @@ imap4d_test "CREATE flat" ...@@ -37,7 +37,7 @@ imap4d_test "CREATE flat"
37 37
38 imap4d_test "CREATE en/to/tre" 38 imap4d_test "CREATE en/to/tre"
39 39
40 imap4d_test -long "APPEND en/to/tre 25-Aug-2002 18:00:00 +0200"\ 40 imap4d_test -long "APPEND en/to/tre \"25-Aug-2002 18:00:00 +0200\""\
41 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST) 41 "Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
42 From: Fred Foobar <foobar@Blurdybloop.COM> 42 From: Fred Foobar <foobar@Blurdybloop.COM>
43 Subject: afternoon meeting again 43 Subject: afternoon meeting again
...@@ -65,7 +65,7 @@ imap4d_test "SELECT en/to/tre"\ ...@@ -65,7 +65,7 @@ imap4d_test "SELECT en/to/tre"\
65 "OK \[READ-WRITE\] SELECT Completed" 65 "OK \[READ-WRITE\] SELECT Completed"
66 66
67 imap4d_test "FETCH 1 ALL"\ 67 imap4d_test "FETCH 1 ALL"\
68 "1 FETCH (FLAGS (\\Recent) INTERNALDATE \"25-Aug-2002 16:00:00 +0000\" RFC822.SIZE 283 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>\"))"\ 68 "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>\"))"\
69 "OK" 69 "OK"
70 70
71 71
......
...@@ -165,7 +165,7 @@ imap4d_test "FETCH 1 BODY\[HEADER\]"\ ...@@ -165,7 +165,7 @@ imap4d_test "FETCH 1 BODY\[HEADER\]"\
165 # The subset returned by HEADER.FIELDS contains only those header fields 165 # The subset returned by HEADER.FIELDS contains only those header fields
166 # with a field-name that matches one of the names in the list; 166 # with a field-name that matches one of the names in the list;
167 167
168 imap4d_test "FETCH 1 BODY\[HEADER.FIELDS FROM TO SUBJECT\]"\ 168 imap4d_test "FETCH 1 BODY\[HEADER.FIELDS (FROM TO SUBJECT)\]"\
169 "1 FETCH (BODY\[HEADER.FIELDS (\"FROM\" \"TO\" \"SUBJECT\")\] {94}"\ 169 "1 FETCH (BODY\[HEADER.FIELDS (\"FROM\" \"TO\" \"SUBJECT\")\] {94}"\
170 -literal\ 170 -literal\
171 "FROM: Foo Bar <foobar@nonexistent.net>"\ 171 "FROM: Foo Bar <foobar@nonexistent.net>"\
...@@ -178,7 +178,7 @@ imap4d_test "FETCH 1 BODY\[HEADER.FIELDS FROM TO SUBJECT\]"\ ...@@ -178,7 +178,7 @@ imap4d_test "FETCH 1 BODY\[HEADER.FIELDS FROM TO SUBJECT\]"\
178 # similarly, the subset returned by HEADER.FIELDS.NOT contains only 178 # similarly, the subset returned by HEADER.FIELDS.NOT contains only
179 # the header fields with a non-matching field-name. 179 # the header fields with a non-matching field-name.
180 180
181 imap4d_test "FETCH 1 BODY\[HEADER.FIELDS.NOT FROM TO SUBJECT\]"\ 181 imap4d_test "FETCH 1 BODY\[HEADER.FIELDS.NOT (FROM TO SUBJECT)\]"\
182 "1 FETCH (BODY\[HEADER.FIELDS.NOT (\"FROM\" \"TO\" \"SUBJECT\")\] {235}"\ 182 "1 FETCH (BODY\[HEADER.FIELDS.NOT (\"FROM\" \"TO\" \"SUBJECT\")\] {235}"\
183 -literal\ 183 -literal\
184 "Received: (from foobar@nonexistent.net) "\ 184 "Received: (from foobar@nonexistent.net) "\
...@@ -330,8 +330,13 @@ imap4d_test "FETCH 3 BODY\[1.MIME\]"\ ...@@ -330,8 +330,13 @@ imap4d_test "FETCH 3 BODY\[1.MIME\]"\
330 "OK" 330 "OK"
331 331
332 imap4d_test "FETCH 4 BODY\[2.2.1\]"\ 332 imap4d_test "FETCH 4 BODY\[2.2.1\]"\
333 "4 FETCH (FLAGS (\\Seen) BODY\[2.2.1\] {490}"\ 333 "4 FETCH (FLAGS (\\Seen) BODY\[2.2.1\] {680}"\
334 -literal\ 334 -literal\
335 "Content-Type: application/octet-stream; name=\"msg.23\""\
336 "Content-ID: <5122.1026510654.6@Mirddin.farlep.net>"\
337 "Content-Description: Father William Part III"\
338 "Content-Transfer-Encoding: base64"\
339 ""\
335 "YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhbmQgeW91ciBqYXdzIGFyZSB0b28gd2Vh"\ 340 "YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhbmQgeW91ciBqYXdzIGFyZSB0b28gd2Vh"\
336 "awpGb3IgYW55dGhpbmcgdG91Z2hlciB0aGFuIHN1ZXQ7CllldCB5b3UgZmluaXNoZWQgdGhlIGdv"\ 341 "awpGb3IgYW55dGhpbmcgdG91Z2hlciB0aGFuIHN1ZXQ7CllldCB5b3UgZmluaXNoZWQgdGhlIGdv"\
337 "b3NlLCB3aXRoIHRoZSBib25lcyBhbmQgdGhlIGJlYWstLQpQcmF5IGhvdyBkaWQgeW91IG1hbmFn"\ 342 "b3NlLCB3aXRoIHRoZSBib25lcyBhbmQgdGhlIGJlYWstLQpQcmF5IGhvdyBkaWQgeW91IG1hbmFn"\
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -24,36 +24,29 @@ ...@@ -24,36 +24,29 @@
24 */ 24 */
25 25
26 int 26 int
27 imap4d_uid (struct imap4d_command *command, char *arg) 27 imap4d_uid (struct imap4d_command *command, imap4d_tokbuf_t tok)
28 { 28 {
29 char *cmd; 29 char *cmd;
30 char *sp = NULL;
31 int rc = RESP_NO; 30 int rc = RESP_NO;
32 char buffer[64]; 31 char *err_text = "Completed";
33 32
34 cmd = util_getword (arg, &sp); 33 if (imap4d_tokbuf_argc (tok) < 3)
35 if (!cmd) 34 return util_finish (command, RESP_BAD, "Invalid arguments");
36 util_finish (command, RESP_BAD, "Too few args"); 35
36 cmd = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
37
37 if (strcasecmp (cmd, "FETCH") == 0) 38 if (strcasecmp (cmd, "FETCH") == 0)
38 { 39 rc = imap4d_fetch0 (tok, 1, &err_text);
39 rc = imap4d_fetch0 (sp, 1, buffer, sizeof buffer);
40 }
41 else if (strcasecmp (cmd, "COPY") == 0) 40 else if (strcasecmp (cmd, "COPY") == 0)
42 { 41 rc = imap4d_copy0 (tok, 1, &err_text);
43 rc = imap4d_copy0 (sp, 1, buffer, sizeof buffer);
44 }
45 else if (strcasecmp (cmd, "STORE") == 0) 42 else if (strcasecmp (cmd, "STORE") == 0)
46 { 43 rc = imap4d_store0 (tok, 1, &err_text);
47 rc = imap4d_store0 (sp, 1, buffer, sizeof buffer);
48 }
49 else if (strcasecmp (cmd, "SEARCH") == 0) 44 else if (strcasecmp (cmd, "SEARCH") == 0)
50 { 45 rc = imap4d_search0 (tok, 1, &err_text);
51 rc = imap4d_search0 (sp, 1, buffer, sizeof buffer);
52 }
53 else 46 else
54 { 47 {
55 snprintf (buffer, sizeof buffer, "Error uknown uid command"); 48 err_text = "Uknown uid command";
56 rc = RESP_BAD; 49 rc = RESP_BAD;
57 } 50 }
58 return util_finish (command, rc, "%s %s", cmd, buffer); 51 return util_finish (command, rc, "%s %s", cmd, err_text);
59 } 52 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -71,19 +71,34 @@ unsubscribe (struct scan_data *data, char *name) ...@@ -71,19 +71,34 @@ unsubscribe (struct scan_data *data, char *name)
71 return 0; 71 return 0;
72 } 72 }
73 73
74 /*
75 6.3.7. UNSUBSCRIBE Command
76
77 Arguments: mailbox name
78
79 Responses: no specific responses for this command
80
81 Result: OK - unsubscribe completed
82 NO - unsubscribe failure: can't unsubscribe that name
83 BAD - command unknown or arguments invalid
84
85 The UNSUBSCRIBE command removes the specified mailbox name from
86 the server's set of "active" or "subscribed" mailboxes as returned
87 by the LSUB command. This command returns a tagged OK response
88 only if the unsubscription is successful.
89 */
74 int 90 int
75 imap4d_unsubscribe (struct imap4d_command *command, char *arg) 91 imap4d_unsubscribe (struct imap4d_command *command, imap4d_tokbuf_t tok)
76 { 92 {
77 char *sp = NULL;
78 char *name; 93 char *name;
79 char *file; 94 char *file;
80 struct scan_data sd; 95 struct scan_data sd;
81 int rc; 96 int rc;
82 97
83 name = util_getword (arg, &sp); 98 if (imap4d_tokbuf_argc (tok) != 3)
84 util_unquote (&name); 99 return util_finish (command, RESP_BAD, "Invalid arguments");
85 if (!name || *name == '\0') 100
86 return util_finish (command, RESP_BAD, "Too few arguments"); 101 name = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
87 102
88 asprintf (&file, "%s/.mailboxlist", homedir); 103 asprintf (&file, "%s/.mailboxlist", homedir);
89 sd.result = 0; 104 sd.result = 0;
......
...@@ -25,92 +25,6 @@ static mu_stream_t ostream; ...@@ -25,92 +25,6 @@ static mu_stream_t ostream;
25 static int add2set (size_t **, int *, unsigned long); 25 static int add2set (size_t **, int *, unsigned long);
26 static const char *sc2string (int); 26 static const char *sc2string (int);
27 27
28 /* Get the next space/CR/NL separated word, some words are between double
29 quotes, strtok() cannot handle it. */
30 char *
31 util_getword (char *s, char **save)
32 {
33 return util_getitem (s, " \r\n", save);
34 }
35
36 /* Take care of words between double quotes. */
37 char *
38 util_getitem (char *s, const char *delim, char **save)
39 {
40 {
41 char *p;
42 if ((p = s) || (p = *save))
43 {
44 while (isspace ((unsigned) *p))
45 p++;
46 if (*p == '"')
47 {
48 s = p;
49 p++;
50 while (*p && *p != '"')
51 p++;
52 if (*p == '"')
53 p++;
54 *save = (*p) ? p + 1 : p;
55 *p = '\0';
56 return s;
57 }
58 }
59 }
60 return strtok_r (s, delim, save);
61 }
62
63 /* Stop at the first char that represents an IMAP4 special character. */
64 int
65 util_token (char *buf, size_t len, char **ptr)
66 {
67 char *start = *ptr;
68 size_t i;
69 /* Skip leading space. */
70 while (**ptr && **ptr == ' ')
71 (*ptr)++;
72
73 /* Break the string by token, i.e when we reconize IMAP special
74 atoms we stop and send it. */
75 for (i = 1; **ptr && i < len; (*ptr)++, buf++, i++)
76 {
77 if (**ptr == ' ' || **ptr == '.'
78 || **ptr == '(' || **ptr == ')'
79 || **ptr == '[' || **ptr == ']'
80 || **ptr == '<' || **ptr == '>' || **ptr == '\r' || **ptr == '\n')
81 {
82 /* Advance. */
83 if (start == (*ptr))
84 (*ptr)++;
85 break;
86 }
87 *buf = **ptr;
88 }
89 *buf = '\0';
90 /* Skip trailing space. */
91 while (**ptr && **ptr == ' ')
92 (*ptr)++;
93 return *ptr - start;
94 }
95
96 /* Remove the surrounding double quotes. */
97 /* FIXME: Check if the quote was escaped and ignore it. */
98 void
99 util_unquote (char **ptr)
100 {
101 char *s = *ptr;
102 size_t len;
103 if (s && *s == '"' && (len = strlen (s)) > 1 && s[len - 1] == '"')
104 {
105 char *p = ++s;
106 while (*p && *p != '"')
107 p++;
108 if (*p == '"')
109 *p = '\0';
110 }
111 *ptr = s;
112 }
113
114 /* NOTE: Allocates Memory. */ 28 /* NOTE: Allocates Memory. */
115 /* Expand: ~ --> /home/user and to ~guest --> /home/guest. */ 29 /* Expand: ~ --> /home/user and to ~guest --> /home/guest. */
116 char * 30 char *
...@@ -266,8 +180,8 @@ util_msgset (char *s, size_t ** set, int *n, int isuid) ...@@ -266,8 +180,8 @@ util_msgset (char *s, size_t ** set, int *n, int isuid)
266 s++; 180 s++;
267 break; 181 break;
268 182
269 /* As a convenience. '*' is provided to refer to the highest message 183 /* As a convenience. '*' is provided to refer to the highest
270 number int the mailbox: 184 message number int the mailbox:
271 5:* --> 5 6 7 8 185 5:* --> 5 6 7 8
272 */ 186 */
273 case '*': 187 case '*':
...@@ -479,143 +393,30 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...) ...@@ -479,143 +393,30 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
479 return status; 393 return status;
480 } 394 }
481 395
482 /* Clients are allowed to send literal string to the servers. this
483 means that it can occur everywhere where a string is allowed.
484 A literal is a sequence of zero or more octets (including CR and LF)
485 prefix-quoted with an octet count in the form of an open brace ("{"),
486 the number of octets, close brace ("}"), and CRLF.
487 */
488 char *
489 imap4d_readline (void)
490 {
491 char buffer[512];
492 size_t len;
493 long number = 0;
494 size_t total = 0;
495 char *line = malloc (1);
496
497 if (!line)
498 imap4d_bye (ERR_NO_MEM);
499
500 line[0] = '\0'; /* start with a empty string. */
501 do
502 {
503 size_t sz;
504 int rc;
505
506 alarm (idle_timeout);
507 rc = mu_stream_sequential_readline (istream, buffer, sizeof (buffer), &sz);
508 if (sz == 0)
509 {
510 mu_diag_output (MU_DIAG_INFO, _("Unexpected eof on input"));
511 imap4d_bye (ERR_NO_OFILE);
512 }
513 else if (rc)
514 {
515 const char *p;
516 if (mu_stream_strerror (istream, &p))
517 p = strerror (errno);
518
519 mu_diag_output (MU_DIAG_INFO, _("Error reading from input file: %s"), p);
520 imap4d_bye (ERR_NO_OFILE);
521 }
522 alarm (0);
523
524 len = strlen (buffer);
525 /* If we were in a litteral substract. We have to do it here since the CR
526 is part of the count in a literal. */
527 if (number)
528 number -= len;
529
530 /* Remove CR. */
531 if (len > 1 && buffer[len - 1] == '\n')
532 {
533 if (buffer[len - 2] == '\r')
534 {
535 buffer[len - 2] = '\n';
536 buffer[len - 1] = '\0';
537 }
538 }
539 line = realloc (line, total + len + 1);
540 if (!line)
541 imap4d_bye (ERR_NO_MEM);
542 strcat (line, buffer);
543
544 total = strlen (line);
545
546 /* I observe some client requesting long FETCH operations since, I did
547 not see any limit in the command length in the RFC, catch things
548 here. */
549 /* Check that we do have a terminated NL line and we are not retrieving
550 a literal. If we don't continue the read. */
551 if (number <= 0 && total && line[total - 1] != '\n')
552 continue;
553
554 /* Check if the client try to send a literal and make sure we are not
555 already retrieving a literal. */
556 if (number <= 0 && len > 2)
557 {
558 size_t n = total - 1; /* C arrays are 0-based. */
559 /* A literal is this "{number}\n". The CR is already strip. */
560 if (line[n] == '\n' && line[n - 1] == '}')
561 {
562 /* Search for the matching bracket. */
563 while (n && line[n] != '{')
564 n--;
565 if (line[n] == '{')
566 {
567 char *sp = NULL;
568 /* Truncate where the literal number was. */
569 line[n] = '\0';
570 number = strtoul (line + n + 1, &sp, 10);
571 /* Client can ask for non synchronise literal,
572 if a '+' is append to the octet count. */
573 if (*sp != '+')
574 util_send ("+ GO AHEAD\r\n");
575 }
576 }
577 }
578 }
579 while (number > 0 || (total && line[total - 1] != '\n'));
580 if (imap4d_transcript)
581 mu_diag_output (MU_DIAG_DEBUG, "recv: %s", line);
582 return line;
583 }
584
585 char *
586 imap4d_readline_ex (void)
587 {
588 int len;
589 char *s = imap4d_readline ();
590
591 if (s && (len = strlen (s)) > 0 && s[len - 1] == '\n')
592 s[len - 1] = 0;
593 return s;
594 }
595
596 int 396 int
597 util_do_command (char *prompt) 397 util_do_command (imap4d_tokbuf_t tok)
598 { 398 {
599 char *sp = NULL, *tag, *cmd; 399 char *tag, *cmd;
600 struct imap4d_command *command; 400 struct imap4d_command *command;
601 static struct imap4d_command nullcommand; 401 static struct imap4d_command nullcommand;
602 size_t len; 402 int argc = imap4d_tokbuf_argc (tok);
603 403
604 tag = util_getword (prompt, &sp); 404 if (argc == 0)
605 cmd = util_getword (NULL, &sp);
606 if (!tag)
607 { 405 {
608 nullcommand.name = ""; 406 nullcommand.name = "";
609 nullcommand.tag = (char *) "*"; 407 nullcommand.tag = (char *) "*";
610 return util_finish (&nullcommand, RESP_BAD, "Null command"); 408 return util_finish (&nullcommand, RESP_BAD, "Null command");
611 } 409 }
612 else if (!cmd) 410 else if (argc == 1)
613 { 411 {
614 nullcommand.name = ""; 412 nullcommand.name = "";
615 nullcommand.tag = tag; 413 nullcommand.tag = tag;
616 return util_finish (&nullcommand, RESP_BAD, "Missing arguments"); 414 return util_finish (&nullcommand, RESP_BAD, "Missing command");
617 } 415 }
618 416
417 tag = imap4d_tokbuf_getarg (tok, 0);
418 cmd = imap4d_tokbuf_getarg (tok, 1);
419
619 command = util_getcommand (cmd, imap4d_command_table); 420 command = util_getcommand (cmd, imap4d_command_table);
620 if (command == NULL) 421 if (command == NULL)
621 { 422 {
...@@ -629,10 +430,7 @@ util_do_command (char *prompt) ...@@ -629,10 +430,7 @@ util_do_command (char *prompt)
629 if (command->states && (command->states & state) == 0) 430 if (command->states && (command->states & state) == 0)
630 return util_finish (command, RESP_BAD, "Wrong state"); 431 return util_finish (command, RESP_BAD, "Wrong state");
631 432
632 len = strlen (sp); 433 return command->func (command, tok);
633 if (len && sp[len - 1] == '\n')
634 sp[len - 1] = '\0';
635 return command->func (command, sp);
636 } 434 }
637 435
638 int 436 int
...@@ -702,7 +500,7 @@ add2set (size_t ** set, int *n, unsigned long val) ...@@ -702,7 +500,7 @@ add2set (size_t ** set, int *n, unsigned long val)
702 } 500 }
703 501
704 int 502 int
705 util_parse_internal_date0 (char *date, time_t * timep, char **endp) 503 util_parse_internal_date (char *date, time_t * timep)
706 { 504 {
707 struct tm tm; 505 struct tm tm;
708 mu_timezone tz; 506 mu_timezone tz;
...@@ -717,19 +515,10 @@ util_parse_internal_date0 (char *date, time_t * timep, char **endp) ...@@ -717,19 +515,10 @@ util_parse_internal_date0 (char *date, time_t * timep, char **endp)
717 return 2; 515 return 2;
718 516
719 *timep = time; 517 *timep = time;
720 if (endp)
721 *endp = *datep;
722 return 0; 518 return 0;
723 } 519 }
724 520
725 int 521 int
726 util_parse_internal_date (char *date, time_t * timep)
727 {
728 return util_parse_internal_date0 (date, timep, NULL);
729 }
730
731
732 int
733 util_parse_822_date (const char *date, time_t * timep) 522 util_parse_822_date (const char *date, time_t * timep)
734 { 523 {
735 struct tm tm; 524 struct tm tm;
...@@ -875,35 +664,6 @@ util_attribute_matches_flag (mu_attribute_t attr, const char *item) ...@@ -875,35 +664,6 @@ util_attribute_matches_flag (mu_attribute_t attr, const char *item)
875 return flags & mask; 664 return flags & mask;
876 } 665 }
877 666
878
879 int
880 util_parse_attributes (char *items, char **save, int *flags)
881 {
882 int rc = 0;
883
884 *flags = 0;
885 while (*items)
886 {
887 int type = 0;
888 char item[64] = "";
889
890 util_token (item, sizeof (item), &items);
891 if (!util_attribute_to_type (item, &type))
892 *flags |= type;
893 /*FIXME: else? */
894
895 if (*items == ')')
896 {
897 items++;
898 rc = 0;
899 break;
900 }
901 }
902
903 *save = items;
904 return rc;
905 }
906
907 int 667 int
908 util_base64_encode (const unsigned char *input, size_t input_len, 668 util_base64_encode (const unsigned char *input, size_t input_len,
909 unsigned char **output, size_t * output_len) 669 unsigned char **output, size_t * output_len)
...@@ -1324,3 +1084,327 @@ is_atom (const char *s) ...@@ -1324,3 +1084,327 @@ is_atom (const char *s)
1324 return 1; 1084 return 1;
1325 } 1085 }
1326 1086
1087
1088 static size_t
1089 remove_cr (char *line, size_t len)
1090 {
1091 char *prev = NULL;
1092 size_t rlen = len;
1093 char *p;
1094 while ((p = memchr (line, '\r', len)))
1095 {
1096 if (prev)
1097 {
1098 memmove (prev, line, p - line);
1099 prev += p - line;
1100 }
1101 else
1102 prev = p;
1103 rlen--;
1104 len -= p - line + 1;
1105 line = p + 1;
1106 }
1107 if (prev)
1108 memmove (prev, line, len);
1109 return rlen;
1110 }
1111
1112 static size_t
1113 unquote (char *line, size_t len)
1114 {
1115 char *prev = NULL;
1116 size_t rlen = len;
1117 char *p;
1118 int off = 0;
1119 while ((p = memchr (line + off, '\\', len - off)))
1120 {
1121 if (p[1] == '\\' || p[1] == '"')
1122 {
1123 if (prev)
1124 {
1125 memmove (prev, line, p - line);
1126 prev += p - line;
1127 }
1128 else
1129 prev = p;
1130 off = p[1] == '\\';
1131 rlen--;
1132 len -= p - line + 1;
1133 line = p + 1;
1134 }
1135 }
1136 if (prev)
1137 memmove (prev, line, len);
1138 return rlen;
1139 }
1140
1141 struct imap4d_tokbuf {
1142 char *buffer;
1143 size_t size;
1144 size_t level;
1145 int argc;
1146 int argmax;
1147 size_t *argp;
1148 };
1149
1150 struct imap4d_tokbuf *
1151 imap4d_tokbuf_init ()
1152 {
1153 struct imap4d_tokbuf *tok = malloc (sizeof (tok[0]));
1154 if (!tok)
1155 imap4d_bye (ERR_NO_MEM);
1156 memset (tok, 0, sizeof (*tok));
1157 return tok;
1158 }
1159
1160 void
1161 imap4d_tokbuf_destroy (struct imap4d_tokbuf **ptok)
1162 {
1163 struct imap4d_tokbuf *tok = *ptok;
1164 free (tok->buffer);
1165 free (tok->argp);
1166 free (tok);
1167 *ptok = NULL;
1168 }
1169
1170 int
1171 imap4d_tokbuf_argc (struct imap4d_tokbuf *tok)
1172 {
1173 return tok->argc;
1174 }
1175
1176 char *
1177 imap4d_tokbuf_getarg (struct imap4d_tokbuf *tok, int n)
1178 {
1179 if (n < tok->argc)
1180 return tok->buffer + tok->argp[n];
1181 return NULL;
1182 }
1183
1184 static void
1185 imap4d_tokbuf_unquote (struct imap4d_tokbuf *tok, size_t *poff, size_t *plen)
1186 {
1187 char *buf = tok->buffer + *poff;
1188 if (buf[0] == '"' && buf[*plen - 1] == '"')
1189 {
1190 ++*poff;
1191 *plen = unquote (buf + 1, *plen - 1);
1192 }
1193 }
1194
1195 static void
1196 imap4d_tokbuf_expand (struct imap4d_tokbuf *tok, size_t size)
1197 {
1198 if (tok->size - tok->level < size)
1199 {
1200 tok->size = tok->level + size;
1201 tok->buffer = realloc (tok->buffer, tok->size);
1202 if (!tok->buffer)
1203 imap4d_bye (ERR_NO_MEM);
1204 }
1205 }
1206
1207 #define ISDELIM(c) (strchr (".()[]<>", (c)) != NULL)
1208 #define ISWS(c) (c == ' ' || c == '\t')
1209
1210 int
1211 util_isdelim (const char *str)
1212 {
1213 return str[1] == 0 && ISDELIM (str[0]);
1214 }
1215
1216 static size_t
1217 insert_nul (struct imap4d_tokbuf *tok, size_t off)
1218 {
1219 imap4d_tokbuf_expand (tok, 1);
1220 if (off < tok->level)
1221 {
1222 memmove (tok->buffer + off + 1, tok->buffer + off, tok->level - off);
1223 tok->level++;
1224 }
1225 tok->buffer[off] = 0;
1226 return off + 1;
1227 }
1228
1229 static size_t
1230 gettok (struct imap4d_tokbuf *tok, size_t off)
1231 {
1232 char *buf = tok->buffer;
1233
1234 while (off < tok->level && ISWS (buf[off]))
1235 off++;
1236
1237 if (tok->argc == tok->argmax)
1238 {
1239 if (tok->argmax == 0)
1240 tok->argmax = 16;
1241 else
1242 tok->argmax *= 2;
1243 tok->argp = realloc(tok->argp, tok->argmax * sizeof (tok->argp[0]));
1244 if (!tok->argp)
1245 imap4d_bye (ERR_NO_MEM);
1246 }
1247
1248 if (buf[off] == '"')
1249 {
1250 char *start = buf + off + 1;
1251 char *p = NULL;
1252
1253 while (*start && (p = strchr (start, '"')))
1254 {
1255 if (p == start || p[-1] != '\\')
1256 break;
1257 start = p + 1;
1258 }
1259
1260 if (p)
1261 {
1262 size_t len;
1263 off++;
1264 len = unquote(buf + off, p - (buf + off));
1265 buf[off + len] = 0;
1266 tok->argp[tok->argc++] = off;
1267 return p - buf + 1;
1268 }
1269 }
1270
1271 tok->argp[tok->argc++] = off;
1272 if (ISDELIM (buf[off]))
1273 return insert_nul (tok, off + 1);
1274
1275 while (off < tok->level && !ISWS (buf[off]))
1276 {
1277 if (ISDELIM (buf[off]))
1278 return insert_nul (tok, off);
1279 off++;
1280 }
1281 buf[off++] = 0;
1282
1283 return off;
1284 }
1285
1286 static void
1287 imap4d_tokbuf_tokenize (struct imap4d_tokbuf *tok, size_t off)
1288 {
1289 while (off < tok->level)
1290 off = gettok (tok, off);
1291 }
1292
1293 static void
1294 check_input_err (int rc, size_t sz)
1295 {
1296 if (rc)
1297 {
1298 const char *p;
1299 if (mu_stream_strerror (istream, &p))
1300 p = mu_strerror (rc);
1301
1302 mu_diag_output (MU_DIAG_INFO,
1303 _("Error reading from input file: %s"), p);
1304 imap4d_bye (ERR_NO_OFILE);
1305 }
1306 else if (sz == 0)
1307 {
1308 mu_diag_output (MU_DIAG_INFO, _("Unexpected eof on input"));
1309 imap4d_bye (ERR_NO_OFILE);
1310 }
1311 }
1312
1313 static size_t
1314 imap4d_tokbuf_getline (struct imap4d_tokbuf *tok)
1315 {
1316 char buffer[512];
1317 size_t level = tok->level;
1318
1319 do
1320 {
1321 size_t len;
1322 int rc;
1323
1324 rc = mu_stream_sequential_readline (istream,
1325 buffer, sizeof (buffer), &len);
1326 check_input_err (rc, len);
1327 imap4d_tokbuf_expand (tok, len);
1328
1329 memcpy (tok->buffer + tok->level, buffer, len);
1330 tok->level += len;
1331 }
1332 while (tok->level && tok->buffer[tok->level - 1] != '\n');
1333 tok->buffer[--tok->level] = 0;
1334 if (tok->buffer[tok->level - 1] == '\r')
1335 tok->buffer[--tok->level] = 0;
1336 return level;
1337 }
1338
1339 void
1340 imap4d_readline (struct imap4d_tokbuf *tok)
1341 {
1342 tok->argc = 0;
1343 for (;;)
1344 {
1345 char *last_arg;
1346 size_t off = imap4d_tokbuf_getline (tok);
1347 imap4d_tokbuf_tokenize (tok, off);
1348 last_arg = tok->buffer + tok->argp[tok->argc - 1];
1349 if (last_arg[0] == '{' && last_arg[strlen(last_arg)-1] == '}')
1350 {
1351 int rc;
1352 unsigned long number;
1353 char *sp = NULL;
1354 char *buf;
1355 size_t len;
1356
1357 number = strtoul (last_arg + 1, &sp, 10);
1358 /* Client can ask for non-synchronised literal,
1359 if a '+' is appended to the octet count. */
1360 if (*sp == '}')
1361 util_send ("+ GO AHEAD\r\n");
1362 else if (*sp != '+')
1363 break;
1364 imap4d_tokbuf_expand (tok, number + 1);
1365 off = tok->level;
1366 buf = tok->buffer + off;
1367 rc = mu_stream_sequential_read (istream, buf, number, &len);
1368 check_input_err (rc, len);
1369 len = remove_cr (buf, len);
1370 imap4d_tokbuf_unquote (tok, &off, &len);
1371 tok->level += len;
1372 tok->buffer[tok->level++] = 0;
1373 tok->argp[tok->argc - 1] = off;
1374 if (buf[len-1] != '\n')
1375 continue;
1376 }
1377 break;
1378 }
1379 }
1380
1381 struct imap4d_tokbuf *
1382 imap4d_tokbuf_from_string (char *str)
1383 {
1384 struct imap4d_tokbuf *tok = imap4d_tokbuf_init ();
1385 tok->buffer = strdup (str);
1386 if (!tok->buffer)
1387 imap4d_bye (ERR_NO_MEM);
1388 tok->level = strlen (str);
1389 tok->size = tok->level + 1;
1390 imap4d_tokbuf_tokenize (tok, 0);
1391 return tok;
1392 }
1393
1394 int
1395 imap4d_getline (char **pbuf, size_t *psize, size_t *pnbytes)
1396 {
1397 size_t len;
1398 int rc = mu_stream_sequential_getline (istream, pbuf, psize, &len);
1399 if (rc == 0)
1400 {
1401 char *s = *pbuf;
1402 if (s && len > 0 && s[len - 1] == '\n')
1403 s[--len] = 0;
1404 if (s && len > 0 && s[len - 1] == '\r')
1405 s[--len] = 0;
1406 if (pnbytes)
1407 *pnbytes = len;
1408 }
1409 return rc;
1410 }
......
1 /* GNU Mailutils -- a suite of utilities for electronic mail 1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2001, 2007, 2008 Free Software Foundation, Inc.
3 3
4 GNU Mailutils is free software; you can redistribute it and/or modify 4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
...@@ -19,8 +19,10 @@ ...@@ -19,8 +19,10 @@
19 #include "imap4d.h" 19 #include "imap4d.h"
20 20
21 int 21 int
22 imap4d_version (struct imap4d_command *command, char *arg) 22 imap4d_version (struct imap4d_command *command, imap4d_tokbuf_t tok)
23 { 23 {
24 if (imap4d_tokbuf_argc (tok) != 2)
25 return util_finish (command, RESP_BAD, "Invalid arguments");
24 util_send ("* %s GNU %s\r\n", command->name, program_version); 26 util_send ("* %s GNU %s\r\n", command->name, program_version);
25 return util_finish (command, RESP_OK, "Completed"); 27 return util_finish (command, RESP_OK, "Completed");
26 } 28 }
......
...@@ -145,7 +145,7 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox) ...@@ -145,7 +145,7 @@ mail_tmp_finish (struct mail_tmp *mtmp, mu_mailbox_t *mbox)
145 } 145 }
146 146
147 mu_stream_flush (mtmp->stream); 147 mu_stream_flush (mtmp->stream);
148 if ((status = mu_mailbox_create (mbox, "/dev/null")) 148 if ((status = mu_mailbox_create (mbox, "mbox:/dev/null"))
149 || (status = mu_mailbox_open (*mbox, MU_STREAM_READ)) 149 || (status = mu_mailbox_open (*mbox, MU_STREAM_READ))
150 || (status = mu_mailbox_set_stream (*mbox, mtmp->stream))) 150 || (status = mu_mailbox_set_stream (*mbox, mtmp->stream)))
151 { 151 {
......
...@@ -51,7 +51,7 @@ _memory_destroy (mu_stream_t stream) ...@@ -51,7 +51,7 @@ _memory_destroy (mu_stream_t stream)
51 struct _memory_stream *mfs = mu_stream_get_owner (stream); 51 struct _memory_stream *mfs = mu_stream_get_owner (stream);
52 if (mfs && mfs->ptr != NULL) 52 if (mfs && mfs->ptr != NULL)
53 free (mfs->ptr); 53 free (mfs->ptr);
54 if(mfs->filename) 54 if (mfs->filename)
55 free (mfs->filename); 55 free (mfs->filename);
56 free (mfs); 56 free (mfs);
57 } 57 }
......