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 {
134 time(&t); 97 time(&t);
135 } 98
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);
...@@ -159,3 +125,86 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text) ...@@ -159,3 +125,86 @@ imap4d_append0 (mu_mailbox_t mbox, int flags, char *text)
159 } 125 }
160 126
161 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
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;
102 108
103 auth_type = util_getword (arg, &sp); 109 if (imap4d_tokbuf_argc (tok) != 3)
104 util_unquote (&auth_type); 110 return util_finish (command, RESP_BAD, "Invalid arguments");
105 if (!auth_type) 111
106 return util_finish (command, RESP_BAD, "Too few arguments"); 112 auth_type = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
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,17 +20,28 @@ ...@@ -19,17 +20,28 @@
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;
32 41
42 if (imap4d_tokbuf_argc (tok) != 2)
43 return util_finish (command, RESP_BAD, "Invalid arguments");
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)
35 { 47 {
......
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;
42
43 if (imap4d_tokbuf_argc (tok) != 4)
44 return util_finish (command, RESP_BAD, "Invalid arguments");
45
46 rc = imap4d_copy0 (tok, 0, &text);
30 47
31 rc = imap4d_copy0 (arg, 0, buffer, sizeof buffer);
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 */
52 size_t *section_part; /* Section-part */
53 size_t nset; /* Number of elements in section_part */
54 int peek;
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 };
129 60
130 rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer);
131 return util_finish (command, rc, "%s", buffer);
132 }
133 61
134 /* Where the real implementation is. It is here since UID command also 62 static int
135 calls FETCH. */ 63 fetch_send_address (const char *addr)
136 int
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
148 msgset = util_getword (arg, &sp);
149 if (!msgset || !sp || *sp == '\0')
150 {
151 snprintf (resp, resplen, "Too few args");
152 return RESP_BAD;
153 }
154 67
155 /* Get the message numbers in set[]. */ 68 /* Short circuit. */
156 status = util_msgset (msgset, &set, &n, isuid); 69 if (addr == NULL || *addr == '\0')
157 if (status != 0)
158 { 70 {
159 snprintf (resp, resplen, "Bogus number set"); 71 util_send ("NIL");
160 return RESP_BAD; 72 return RESP_OK;
161 } 73 }
162 74
163 /* Prepare status code. It will be replaced if an error occurs in the 75 mu_address_create (&address, addr);
164 loop below */ 76 mu_address_get_count (address, &count);
165 snprintf (resp, resplen, "Completed");
166
167 for (i = 0; i < n && rc == RESP_OK; i++)
168 {
169 size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
170 mu_message_t msg = NULL;
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 77
179 fcmd = NULL; 78 /* We failed: can't parse. */
180 util_send ("* %s FETCH (", mu_umaxtostr (0, msgno)); 79 if (count == 0)
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 { 80 {
221 snprintf (resp, resplen, 81 util_send ("NIL");
222 "Bogus message set: message number out of range"); 82 return RESP_OK;
223 rc = RESP_BAD;
224 break;
225 }
226 } 83 }
227 free (set);
228 return rc;
229 }
230 84
231 /* ALL: 85 util_send ("(");
232 Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) 86 for (i = 1; i <= count; i++)
233 Combination of FAST and ENVELOPE. */ 87 {
234 static int 88 const char *str;
235 fetch_all (struct fetch_command *command, char **arg) 89 int is_group = 0;
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 90
245 /* FULL: 91 util_send ("(");
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 92
259 /* FAST: 93 mu_address_sget_personal (address, i, &str);
260 Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE) 94 util_send_qstring (str);
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 (" "); 95 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 96
292 /* FLAGS: The flags that are set for this message. */ 97 mu_address_sget_route (address, i, &str);
293 /* FIXME: User flags not done. If enable change the PERMANENTFLAGS in SELECT */ 98 util_send_qstring (str);
294 void
295 fetch_flags0 (const char *prefix, mu_message_t msg, int isuid)
296 {
297 mu_attribute_t attr = NULL;
298 99
299 mu_message_get_attribute (msg, &attr);
300 if (isuid)
301 {
302 struct fetch_command *fcmd = &fetch_command_table[F_UID];
303 fcmd->msg = msg;
304 fetch_uid (fcmd, NULL);
305 util_send (" "); 100 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
339 time ::= 2digit ":" 2digit ":" 2digit
340 ;; Hours minutes seconds
341
342 zone ::= ("+" / "-") 4digit
343 ;; Signed four-digit value of hhmm representing
344 ;; hours and minutes west of Greenwich (that is,
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 101
358 mu_message_get_envelope (command->msg, &env); 102 mu_address_is_group (address, i, &is_group);
359 if (mu_envelope_sget_date (env, &date) == 0 103 str = NULL;
360 && mu_parse_ctime_date_time (&date, &tm, &tz) == 0) 104 if (is_group)
361 tmp = &tm; 105 mu_address_sget_personal (address, i, &str);
362 else 106 else
363 { 107 mu_address_sget_local_part (address, i, &str);
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
373 /*
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
383 strcpy (buffer, ".PEEK[HEADER]");
384 return fetch_body (command, &p);
385 }
386
387 /* RFC822.TEXT:
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
396 strcpy (buffer, "[TEXT]");
397 return fetch_body (command, &p);
398 }
399
400 /* The [RFC-822] size of the message. */
401 static int
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 108
413 /* RFC822: 109 util_send_qstring (str);
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 }
452 return RESP_OK;
453 }
454 110
455 /* UID: The unique identifier for the message. */ 111 util_send (" ");
456 static int
457 fetch_uid (struct fetch_command *command, char **arg MU_ARG_UNUSED)
458 {
459 size_t uid = 0;
460 112
461 mu_message_get_uid (command->msg, &uid); 113 mu_address_sget_domain (address, i, &str);
462 util_send ("%s %s", command->name, mu_umaxtostr (0, uid)); 114 util_send_qstring (str);
463 return RESP_OK;
464 }
465 115
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 (")"); 116 util_send (")");
476 return RESP_OK;
477 }
478
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 } 117 }
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 (")"); 118 util_send (")");
517 return RESP_OK; 119 return RESP_OK;
518 }
519 util_send ("%s", command->name);
520 return fetch_operation (command->msg, arg,
521 strcasecmp (command->name, "BODY"));
522 } 120 }
523 121
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,7 +139,7 @@ fetch_send_header_value (mu_header_t header, const char *name, ...@@ -543,7 +139,7 @@ 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, 142 fetch_send_header_address (mu_header_t header, const char *name,
547 const char *defval, int space) 143 const char *defval, int space)
548 { 144 {
549 char *buffer; 145 char *buffer;
...@@ -552,146 +148,47 @@ fetch_send_header_list (mu_header_t header, const char *name, ...@@ -552,146 +148,47 @@ fetch_send_header_list (mu_header_t header, const char *name,
552 util_send (" "); 148 util_send (" ");
553 if (mu_header_aget_value (header, name, &buffer) == 0) 149 if (mu_header_aget_value (header, name, &buffer) == 0)
554 { 150 {
555 send_parameter_list (buffer); 151 fetch_send_address (buffer);
556 free (buffer); 152 free (buffer);
557 } 153 }
558 else if (defval)
559 send_parameter_list (defval);
560 else 154 else
561 util_send ("NIL"); 155 fetch_send_address (defval);
562 } 156 }
563 157
158 /* Send parameter list for the bodystructure. */
564 static void 159 static void
565 fetch_send_header_address (mu_header_t header, const char *name, 160 send_parameter_list (const char *buffer)
566 const char *defval, int space)
567 { 161 {
568 char *buffer; 162 int argc = 0;
163 char **argv;
569 164
570 if (space) 165 if (!buffer)
571 util_send (" ");
572 if (mu_header_aget_value (header, name, &buffer) == 0)
573 { 166 {
574 fetch_send_address (buffer); 167 util_send ("NIL");
575 free (buffer); 168 return;
576 } 169 }
577 else
578 fetch_send_address (defval);
579 }
580
581 /* ENVELOPE:
582 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
584 fields as necessary. The fields are presented in the order:
585 Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, Message-ID.
586 Any field of an envelope or address structure that is not applicable is
587 presented as NIL. Note that the server MUST default the reply-to and sender
588 fields from the from field. The date, subject, in-reply-to, and message-id
589 fields are strings. The from, sender, reply-to, to, cc, and bcc fields
590 are parenthesized lists of address structures. */
591 static int
592 fetch_envelope0 (mu_message_t msg)
593 {
594 char *from = NULL;
595 mu_header_t header = NULL;
596
597 mu_message_get_header (msg, &header);
598
599 fetch_send_header_value (header, "Date", NULL, 0);
600 fetch_send_header_value (header, "Subject", NULL, 1);
601
602 /* From: */
603 mu_header_aget_value (header, "From", &from);
604 util_send (" ");
605 fetch_send_address (from);
606
607 fetch_send_header_address (header, "Sender", from, 1);
608 fetch_send_header_address (header, "Reply-to", from, 1);
609 fetch_send_header_address (header, "To", NULL, 1);
610 fetch_send_header_address (header, "Cc", NULL, 1);
611 fetch_send_header_address (header, "Bcc", NULL, 1);
612 fetch_send_header_value (header, "In-Reply-To", NULL, 1);
613 fetch_send_header_value (header, "Message-ID", NULL, 1);
614
615 free (from);
616 return RESP_OK;
617 }
618
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 170
638 body language: 171 mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
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 172
648 mu_message_is_multipart (message, &is_multipart); 173 if (argc == 0)
649 if (is_multipart) 174 util_send ("NIL");
175 else
650 { 176 {
651 char *buffer = NULL; 177 char *p;
652 mu_header_t header = NULL;
653
654 mu_message_get_num_parts (message, &nparts);
655 178
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 ("("); 179 util_send ("(");
662 fetch_bodystructure0 (msg, extension);
663 util_send (")");
664 } /* for () */
665
666 mu_message_get_header (message, &header);
667 180
181 p = argv[0];
182 util_send_qstring (p);
668 183
669 /* The subtype. */ 184 if (argc > 1)
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 { 185 {
687 int space = 0; 186 int i, space = 0;
688 char *lvalue = NULL; 187 char *lvalue = NULL;
689 188
690 util_send (" ("); 189 util_send ("(");
691 for (i = 1; i < argc; i++) 190 for (i = 1; i < argc; i++)
692 { 191 {
693 /* body parameter parenthesized list:
694 Content-type parameter list. */
695 if (lvalue) 192 if (lvalue)
696 { 193 {
697 if (space) 194 if (space)
...@@ -711,7 +208,6 @@ fetch_bodystructure0 (mu_message_t message, int extension) ...@@ -711,7 +208,6 @@ fetch_bodystructure0 (mu_message_t message, int extension)
711 { 208 {
712 char *p = argv[i]; 209 char *p = argv[i];
713 util_send (" "); 210 util_send (" ");
714 util_unquote (&p);
715 util_send_qstring (p); 211 util_send_qstring (p);
716 } 212 }
717 break; 213 break;
...@@ -730,22 +226,65 @@ fetch_bodystructure0 (mu_message_t message, int extension) ...@@ -730,22 +226,65 @@ fetch_bodystructure0 (mu_message_t message, int extension)
730 } 226 }
731 else 227 else
732 util_send (" NIL"); 228 util_send (" NIL");
229 util_send (")");
230 }
733 mu_argcv_free (argc, argv); 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);
734 free (buffer); 245 free (buffer);
735 } 246 }
247 else if (defval)
248 send_parameter_list (defval);
736 else 249 else
737 /* No content-type header */ 250 util_send ("NIL");
738 util_send (" NIL"); 251 }
739 252
740 /* body disposition: Content-Disposition. */ 253 /* ENVELOPE:
741 fetch_send_header_list (header, MU_HEADER_CONTENT_DISPOSITION, 254 The envelope structure of the message. This is computed by the server by
742 NULL, 1); 255 parsing the [RFC-822] header into the component parts, defaulting various
743 /* body language: Content-Language. */ 256 fields as necessary. The fields are presented in the order:
744 fetch_send_header_list (header, MU_HEADER_CONTENT_LANGUAGE, 257 Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, Message-ID.
745 NULL, 1); 258 Any field of an envelope or address structure that is not applicable is
746 } 259 presented as NIL. Note that the server MUST default the reply-to and sender
747 else 260 fields from the from field. The date, subject, in-reply-to, and message-id
748 bodystructure (message, extension); 261 fields are strings. The from, sender, reply-to, to, cc, and bcc fields
262 are parenthesized lists of address structures. */
263 static int
264 fetch_envelope0 (mu_message_t msg)
265 {
266 char *from = NULL;
267 mu_header_t header = NULL;
268
269 mu_message_get_header (msg, &header);
270
271 fetch_send_header_value (header, "Date", NULL, 0);
272 fetch_send_header_value (header, "Subject", NULL, 1);
273
274 /* From: */
275 mu_header_aget_value (header, "From", &from);
276 util_send (" ");
277 fetch_send_address (from);
278
279 fetch_send_header_address (header, "Sender", from, 1);
280 fetch_send_header_address (header, "Reply-to", from, 1);
281 fetch_send_header_address (header, "To", NULL, 1);
282 fetch_send_header_address (header, "Cc", NULL, 1);
283 fetch_send_header_address (header, "Bcc", NULL, 1);
284 fetch_send_header_value (header, "In-Reply-To", NULL, 1);
285 fetch_send_header_value (header, "Message-ID", NULL, 1);
286
287 free (from);
749 return RESP_OK; 288 return RESP_OK;
750 } 289 }
751 290
...@@ -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
496 /* The beef BODYSTRUCTURE.
497 A parenthesized list that describes the [MIME-IMB] body structure of a
498 message. Multiple parts are indicated by parenthesis nesting. Instead of
499 a body type as the first element of the parenthesized list there is a nested
500 body. The second element of the parenthesized list is the multipart
501 subtype (mixed, digest, parallel, alternative, etc.).
502
503 The extension data of a multipart body part are in the following order:
504 body parameter parenthesized list:
505 A parenthesized list of attribute/value pairs [e.g. ("foo" "bar" "baz"
506 "rag") where "bar" is the value of "foo" and "rag" is the value of
507 "baz"] as defined in [MIME-IMB].
508
509 body disposition:
510 A parenthesized list, consisting of a disposition type string followed by a
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].
514
515 body language:
516 A string or parenthesized list giving the body language value as defined
517 in [LANGUAGE-TAGS]. */
958 static int 518 static int
959 fetch_operation (mu_message_t msg, char **arg, int silent) 519 fetch_bodystructure0 (mu_message_t message, int extension)
960 { 520 {
961 unsigned long start = ULONG_MAX; /* No starting offset. */ 521 size_t nparts = 1;
962 unsigned long end = ULONG_MAX; /* No limit. */ 522 size_t i;
963 char *section; /* Hold the section number string. */ 523 int is_multipart = 0;
964 char *partial = strchr (*arg, '<');
965 int rc;
966 524
967 /* Check for section specific offset. */ 525 mu_message_is_multipart (message, &is_multipart);
968 if (partial) 526 if (is_multipart)
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 { 527 {
977 partial++; 528 char *buffer = NULL;
978 end = strtoul (partial, NULL, 10); 529 mu_header_t header = NULL;
979 }
980 }
981 530
982 /* Pass the first bracket '[' */ 531 mu_message_get_num_parts (message, &nparts);
983 (*arg)++;
984 section = *arg;
985 532
986 /* Retreive the section message. */ 533 /* Get all the sub messages. */
987 while (isdigit ((unsigned)**arg)) 534 for (i = 1; i <= nparts; i++)
988 { 535 {
989 unsigned long j = strtoul (*arg, arg, 10); 536 mu_message_t msg = NULL;
990 int status; 537 mu_message_get_part (message, i, &msg);
538 util_send ("(");
539 fetch_bodystructure0 (msg, extension);
540 util_send (")");
541 } /* for () */
991 542
992 /* Wrong section message number bail out. */ 543 mu_message_get_header (message, &header);
993 if (j == 0 || j == ULONG_MAX) /* Technical: I should check errno too. */
994 break;
995 544
996 /* If the section message did not exist bail out here. */
997 status = mu_message_get_part (msg, j, &msg);
998 if (status != 0)
999 {
1000 util_send (" \"\"");
1001 return RESP_OK;
1002 }
1003 if (**arg == '.')
1004 (*arg)++;
1005 else
1006 break;
1007 }
1008 545
1009 /* Did we have a section message? */ 546 /* The subtype. */
1010 if (((*arg) - section) > 0) 547 if (mu_header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer) == 0)
1011 { 548 {
1012 char *p = section; 549 int argc = 0;
1013 section = calloc ((*arg) - p + 1, 1); 550 char **argv;
1014 if (section) 551 char *s;
1015 memcpy (section, p, (*arg) - p);
1016 }
1017 else
1018 section = calloc (1, 1);
1019 552
1020 rc = RESP_OK; 553 mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv);
1021 554
1022 /* Choose the right fetch attribute. */ 555 s = strchr (argv[0], '/');
1023 if (*section == '\0' && **arg == ']') 556 if (s)
1024 { 557 s++;
1025 if (!silent) 558 util_send (" ");
1026 util_send ("[]"); 559 util_send_qstring (s);
1027 (*arg)++; 560
1028 rc = fetch_message (msg, start, end); 561 /* The extension data for multipart. */
1029 } 562 if (extension)
1030 else if (strncasecmp (*arg, "HEADER]", 7) == 0)
1031 {
1032 if (!silent)
1033 {
1034 /* NOTE: We violate the RFC here: Header cannot take a prefix for
1035 section messages it only referes to the RFC822 header .. ok
1036 see it as an extension. But according to IMAP4 we should
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 { 563 {
1048 if (*section) 564 int space = 0;
1049 util_send ("[%sMIME]", section); 565 char *lvalue = NULL;
1050 else 566
1051 util_send ("[%s", *arg); 567 util_send (" (");
1052 } 568 for (i = 1; i < argc; i++)
1053 (*arg) += 5;
1054 rc = fetch_header (msg, start, end);
1055 }
1056 else if (strncasecmp (*arg, "HEADER.FIELDS.NOT", 17) == 0)
1057 { 569 {
1058 /* NOTE: we should flag an error if section is not empty: accept 570 /* body parameter parenthesized list:
1059 as an extension for now. */ 571 Content-type parameter list. */
1060 if (*section) 572 if (lvalue)
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 { 573 {
1069 /* NOTE: we should flag an error if section is not empty: accept 574 if (space)
1070 as an extension for now. */ 575 util_send (" ");
1071 if (*section) 576 util_send_qstring (lvalue);
1072 util_send ("[%s", section); 577 lvalue = NULL;
1073 else 578 space = 1;
1074 util_send ("[");
1075 (*arg) += 13;
1076 rc = fetch_header_fields (msg, arg, start, end);
1077 } 579 }
1078 580
1079 else if (strncasecmp (*arg, "TEXT]", 5) == 0) 581 switch (argv[i][0])
1080 { 582 {
1081 if (!silent) 583 case ';':
584 continue;
585
586 case '=':
587 if (++i < argc)
1082 { 588 {
1083 if (*section) 589 char *p = argv[i];
1084 util_send ("[%sTEXT]", section); 590 util_send (" ");
1085 else 591 util_send_qstring (p);
1086 util_send ("[TEXT]"); 592 }
593 break;
594
595 default:
596 lvalue = argv[i];
1087 } 597 }
1088 (*arg) += 5;
1089 rc = fetch_body_content (msg, start, end);
1090 } 598 }
1091 else if (**arg == ']') 599 if (lvalue)
1092 { 600 {
1093 if (!silent) 601 if (space)
1094 util_send ("[%s]", section); 602 util_send (" ");
1095 (*arg)++; 603 util_send_qstring (lvalue);
1096 rc = fetch_body_content (msg, start, end); 604 }
605 util_send (")");
1097 } 606 }
1098 else 607 else
1099 { 608 util_send (" NIL");
1100 util_send (" \"\"");/*FIXME: ERROR Message!*/ 609 mu_argcv_free (argc, argv);
1101 rc = RESP_BAD; 610 free (buffer);
1102 } 611 }
1103 free (section); 612 else
1104 return rc; 613 /* No content-type header */
614 util_send (" NIL");
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);
622 }
623 else
624 bodystructure (message, extension);
625 return RESP_OK;
1105 } 626 }
1106 627
1107 static int 628 static void
1108 fetch_message (mu_message_t msg, unsigned long start, unsigned long end) 629 set_seen (struct fetch_function_closure *ffc,
630 struct fetch_runtime_closure *frt)
1109 { 631 {
1110 mu_stream_t stream = NULL; 632 if (!ffc->peek)
1111 size_t size = 0, lines = 0; 633 {
1112 mu_message_get_stream (msg, &stream); 634 mu_attribute_t attr = NULL;
1113 mu_message_size (msg, &size); 635 mu_message_get_attribute (frt->msg, &attr);
1114 mu_message_lines (msg, &lines); 636 if (!mu_attribute_is_read (attr))
1115 return fetch_io (stream, start, end, size + lines); 637 {
638 util_send ("FLAGS (\\Seen) ");
639 mu_attribute_set_read (attr);
640 }
641 }
1116 } 642 }
1117 643
1118 static int 644 static mu_message_t
1119 fetch_header (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)
1120 { 647 {
1121 mu_header_t header = NULL; 648 mu_message_t msg = frt->msg;
1122 mu_stream_t stream = NULL; 649 size_t i;
1123 size_t size = 0, lines = 0; 650
1124 mu_message_get_header (msg, &header); 651 for (i = 0; i < ffc->nset; i++)
1125 mu_header_size (header, &size); 652 if (mu_message_get_part (msg, ffc->section_part[i], &msg))
1126 mu_header_lines (header, &lines); 653 return NULL;
1127 mu_header_get_stream (header, &stream); 654 return msg;
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,13 +681,13 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, ...@@ -1151,13 +681,13 @@ 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 {
...@@ -1165,11 +695,12 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end, ...@@ -1165,11 +695,12 @@ fetch_io (mu_stream_t stream, unsigned long start, unsigned long end,
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 745
1257 n = asprintf (&buffer, "%s: %s\n", array[j], value); 746 mu_message_get_uid (frt->msg, &uid);
1258 status = mu_stream_write (stream, buffer, n, off, &n); 747 util_send ("%s %s", ffc->name, mu_umaxtostr (0, uid));
1259 off += n; 748 return RESP_OK;
1260 /* count the lines. */ 749 }
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 750
1281 /* Send the command back. The first braket was already sent. */ 751 static int
1282 util_send ("HEADER.FIELDS"); 752 _frt_envelope (struct fetch_function_closure *ffc,
1283 { 753 struct fetch_runtime_closure *frt)
1284 size_t j; 754 {
1285 util_send (" ("); 755 util_send ("%s (", ffc->name);
1286 for (j = 0; j < array_len; j++) 756 fetch_envelope0 (frt->msg);
1287 {
1288 util_upper (array[j]);
1289 if (j)
1290 util_send (" ");
1291 util_send_qstring (array[j]);
1292 }
1293 util_send (")"); 757 util_send (")");
1294 util_send ("]");
1295 }
1296
1297 fetch_io (stream, start, end, off + lines);
1298 if (array)
1299 free (array);
1300 return RESP_OK; 758 return RESP_OK;
1301 } 759 }
1302 760
1303 static int 761 static int
1304 fetch_header_fields_not (mu_message_t msg, char **arg, unsigned long start, 762 _frt_flags (struct fetch_function_closure *ffc,
1305 unsigned long end) 763 struct fetch_runtime_closure *frt)
1306 { 764 {
1307 char **array = NULL; 765 mu_attribute_t attr = NULL;
1308 size_t array_len = 0;
1309 char *buffer = NULL;
1310 size_t off = 0;
1311 size_t lines = 0;
1312 mu_stream_t stream = NULL;
1313 int status;
1314 766
1315 status = mu_memory_stream_create (&stream, 0, 0); 767 mu_message_get_attribute (frt->msg, &attr);
1316 if (status) 768 util_send ("%s (", ffc->name);
1317 imap4d_bye (ERR_NO_MEM); 769 util_print_flags (attr);
770 util_send (")");
771 return 0;
772 }
1318 773
1319 /* Save the field we want to ignore. */ 774 /* INTERNALDATE The internal date of the message.
1320 { 775 Format:
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 776
1334 for (;(field = strtok_r (f, " ()\r\n", &sp)); f = NULL, array_len++) 777 date_time ::= <"> date_day_fixed "-" date_month "-" date_year
1335 { 778 SPACE time SPACE zone <">
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 779
1343 /* Build the memory buffer. */ 780 date_day ::= 1*2digit
1344 { 781 ;; Day of month
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 782
1357 /* Get the field name. */ 783 date_day_fixed ::= (SPACE digit) / 2digit
1358 status = mu_header_aget_field_name (header, i, &name); 784 ;; Fixed-format version of date_day
1359 if (*name == '\0')
1360 {
1361 free (name);
1362 continue;
1363 }
1364 785
1365 /* Should we ignore the field? */ 786 date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
1366 { 787 "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
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 788
1383 if (mu_header_aget_field_value (header, i, &value) == 0) 789 date_text ::= date_day "-" date_month "-" date_year
1384 {
1385 char *nl;
1386 790
1387 /* Save the field. */ 791 date_year ::= 4digit
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 792
1395 free (value); 793 time ::= 2digit ":" 2digit ":" 2digit
1396 } 794 ;; Hours minutes seconds
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 795
1412 util_send ("HEADER.FIELDS.NOT"); 796 zone ::= ("+" / "-") 4digit
1413 { 797 ;; Signed four-digit value of hhmm representing
1414 size_t j; 798 ;; hours and minutes west of Greenwich (that is,
1415 util_send (" ("); 799 ;; (the amount that the given time differs from
1416 for (j = 0; j < array_len; j++) 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")];
812
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
1417 { 818 {
1418 util_upper (array[j]); 819 time_t t = time (NULL);
1419 if (j) 820 tmp = localtime (&t);
1420 util_send (" ");
1421 util_send_qstring (array[j]);
1422 }
1423 util_send (")");
1424 util_send ("]");
1425 } 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 }
1426 827
1427 fetch_io (stream, start, end, off + lines); 828 static int
1428 if (array) 829 _frt_bodystructure (struct fetch_function_closure *ffc,
1429 free (array); 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 (")");
1430 return RESP_OK; 835 return RESP_OK;
1431 } 836 }
1432 837
1433 static int 838 static int
1434 fetch_send_address (const char *addr) 839 _frt_bodystructure0 (struct fetch_function_closure *ffc,
840 struct fetch_runtime_closure *frt)
1435 { 841 {
1436 mu_address_t address; 842 util_send ("%s (", ffc->name);
1437 size_t i, count = 0; 843 fetch_bodystructure0 (frt->msg, 0);
844 util_send (")");
845 return RESP_OK;
846 }
1438 847
1439 /* Short circuit. */ 848 /* BODY[] */
1440 if (addr == NULL || *addr == '\0') 849 static int
850 _frt_body (struct fetch_function_closure *ffc,
851 struct fetch_runtime_closure *frt)
852 {
853 mu_message_t msg;
854 mu_stream_t stream = NULL;
855 size_t size = 0, lines = 0;
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)
1441 { 864 {
1442 util_send ("NIL"); 865 util_send (" \"\"");
1443 return RESP_OK; 866 return RESP_OK;
1444 } 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 }
1445 873
1446 mu_address_create (&address, addr); 874 static int
1447 mu_address_get_count (address, &count); 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;
1448 882
1449 /* We failed: can't parse. */ 883 set_seen (ffc, frt);
1450 if (count == 0) 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)
1451 { 890 {
1452 util_send ("NIL"); 891 util_send (" \"\"");
1453 return RESP_OK; 892 return RESP_OK;
1454 } 893 }
1455 894
1456 util_send ("("); 895 mu_message_get_body (msg, &body);
1457 for (i = 1; i <= count; i++) 896 mu_body_size (body, &size);
1458 { 897 mu_body_lines (body, &lines);
1459 const char *str; 898 mu_body_get_stream (body, &stream);
1460 int is_group = 0; 899 return fetch_io (stream, ffc->start, ffc->size, size + lines);
1461 900 }
1462 util_send ("(");
1463 901
1464 mu_address_sget_personal (address, i, &str); 902 static int
1465 util_send_qstring (str); 903 _frt_size (struct fetch_function_closure *ffc,
1466 util_send (" "); 904 struct fetch_runtime_closure *frt)
905 {
906 size_t size = 0;
907 size_t lines = 0;
1467 908
1468 mu_address_sget_route (address, i, &str); 909 mu_message_size (frt->msg, &size);
1469 util_send_qstring (str); 910 mu_message_lines (frt->msg, &lines);
911 util_send ("%s %u", ffc->name, size + lines);
912 return RESP_OK;
913 }
1470 914
1471 util_send (" "); 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;
1472 924
1473 mu_address_is_group (address, i, &is_group); 925 set_seen (ffc, frt);
1474 str = NULL; 926 if (ffc->name)
1475 if (is_group) 927 util_send ("%s", ffc->name);
1476 mu_address_sget_personal (address, i, &str);
1477 else 928 else
1478 mu_address_sget_local_part (address, i, &str); 929 fetch_send_section_part (ffc, "BODY[", suffix);
1479 930
1480 util_send_qstring (str); 931 msg = fetch_get_part (ffc, frt);
932 if (!msg)
933 {
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 }
1481 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)
1482 util_send (" "); 963 util_send (" ");
964 else
965 *pf = 1;
966 util_send ("\"%s\"", (char*) item);
967 return 0;
968 }
1483 969
1484 mu_address_sget_domain (address, i, &str); 970 static int
1485 util_send_qstring (str); 971 count_nl (const char *str)
972 {
973 int n = 0;
974 for (;(str = strchr (str, '\n')); str++)
975 n++;
976 return n;
977 }
1486 978
1487 util_send (")"); 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;
1488 } 1006 }
1489 util_send (")"); 1007
1008 /* Collect headers: */
1009 if (mu_message_get_header (msg, &header)
1010 || mu_header_get_iterator (header, &itr))
1011 {
1012 util_send (" \"\"");
1490 return RESP_OK; 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;
1026
1027 mu_iterator_current_kv (itr, (const void **)&hf, (void **)&hv);
1028 status = mu_list_locate (ffc->headers, (void *)hf, (void**) &item) == 0;
1029 if (ffc->not)
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;
1491 } 1050 }
1492 1051
1493 /* Send parameter list for the bodystructure. */ 1052
1494 static void 1053 static void
1495 send_parameter_list (const char *buffer) 1054 ffc_init (struct fetch_function_closure *ffc)
1496 { 1055 {
1497 int argc = 0; 1056 memset(ffc, 0, sizeof *ffc);
1498 char **argv; 1057 ffc->start = 0;
1058 ffc->size = (size_t) -1;
1059 }
1499 1060
1500 if (!buffer) 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] == ')')
1501 { 1198 {
1502 util_send ("NIL"); 1199 /* Equivalent to BODY[]. */
1503 return; 1200 ffc.fun = _frt_body;
1504 } 1201 }
1202 else if (p->token[0] == '.')
1203 {
1204 parsebuf_next (p, 1);
1205 if (strcasecmp (p->token, "HEADER") == 0)
1206 {
1207 /* RFC822.HEADER
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). */
1505 1213
1506 mu_argcv_get (buffer, " \t\r\n;=", NULL, &argc, &argv); 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 }
1507 1241
1508 if (argc == 0) 1242 static int
1509 util_send ("NIL"); 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] == '.')
1292 {
1293 parsebuf_next (p, 1);
1294 if (strcasecmp (p->token, "NOT") == 0)
1295 {
1296 ffc->not = 1;
1297 parsebuf_next (p, 1);
1298 }
1299 else
1300 parsebuf_exit (p, "Expected NOT");
1301 }
1302 parse_header_list (p, ffc);
1303 }
1510 else 1304 else
1305 ffc->fun = _frt_header;
1306 }
1307 else if (strcasecmp (p->token, "TEXT") == 0)
1511 { 1308 {
1512 char *p; 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 }
1513 1321
1514 util_send ("("); 1322 static size_t
1323 parsebuf_get_number (struct parsebuf *p)
1324 {
1325 char *cp;
1326 unsigned n = strtoul (p->token, &cp, 10);
1515 1327
1516 p = argv[0]; 1328 if (*cp)
1517 util_send_qstring (p); 1329 parsebuf_exit (p, "Syntax error: expected number");
1330 return n;
1331 }
1518 1332
1519 if (argc > 1) 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 (;;)
1520 { 1345 {
1521 int i, space = 0; 1346 char *cp;
1522 char *lvalue = NULL; 1347 size_t n = parsebuf_get_number (p);
1348 if (ncur == nmax)
1349 {
1350 if (nmax == 0)
1351 {
1352 nmax = 16;
1353 parts = calloc (nmax, sizeof (parts[0]));
1354 }
1355 else
1356 {
1357 nmax *= 2;
1358 parts = realloc (parts, nmax * sizeof (parts[0]));
1359 }
1360 if (!parts)
1361 imap4d_bye (ERR_NO_MEM);
1362 }
1363 parts[ncur++] = n;
1523 1364
1524 util_send ("("); 1365 parsebuf_next (p, 1);
1525 for (i = 1; i < argc; i++) 1366 if (p->token[0] == '.'
1367 && (cp = parsebuf_peek (p)) && isascii (*cp) && isdigit (cp[0]))
1368 parsebuf_next (p, 1);
1369 else
1370 break;
1371 }
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))
1526 { 1390 {
1527 if (lvalue) 1391 if (p->token[0] == ']')
1392 /* OK */;
1393 else if (isascii (p->token[0]) && isdigit (p->token[0]))
1528 { 1394 {
1529 if (space) 1395 parse_section_part (p, ffc);
1530 util_send (" "); 1396 if (p->token[0] == '.')
1531 util_send_qstring (lvalue); 1397 {
1532 lvalue = NULL; 1398 parsebuf_next (p, 1);
1533 space = 1; 1399 parse_section_text (p, ffc, 1);
1400 }
1534 } 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 }
1535 1410
1536 switch (argv[i][0]) 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)
1537 { 1436 {
1538 case ';': 1437 parse_substring (p, &ffc);
1539 continue; 1438 ffc.peek = peek;
1439 append_ffc (p, &ffc);
1440 return 0;
1441 }
1442 return 1;
1443 }
1540 1444
1541 case '=': 1445 static void
1542 if (++i < argc) 1446 parse_body_peek (struct parsebuf *p)
1447 {
1448 parsebuf_next (p, 1);
1449 if (strcasecmp (p->token, "PEEK") == 0)
1543 { 1450 {
1544 char *p = argv[i]; 1451 parsebuf_next (p, 1);
1545 util_send (" "); 1452 if (parse_body_args (p, 1))
1546 util_unquote (&p); 1453 parsebuf_exit (p, "Syntax error");
1547 util_send_qstring (p);
1548 } 1454 }
1549 break; 1455 else
1456 parsebuf_exit (p, "Syntax error: expected PEEK");
1457 }
1550 1458
1551 default: 1459 /* "BODY" ["STRUCTURE"] /
1552 lvalue = argv[i]; 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);
1553 } 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);
1554 } 1499 }
1555 if (lvalue) 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] == '(')
1556 { 1521 {
1557 if (space) 1522 parsebuf_next (p, 1);
1558 util_send (" "); 1523 parse_fetch_att_list (p);
1559 util_send_qstring (lvalue); 1524 if (p->token[0] != ')')
1525 parsebuf_exit (p, "Missing closing parenthesis");
1560 } 1526 }
1561 util_send (")"); 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");
1562 } 1542 }
1563 else 1543 else
1564 util_send (" NIL"); 1544 {
1565 util_send (")"); 1545 parse_fetch_att (p);
1546 if (p->token)
1547 parsebuf_exit (p, "Too many arguments");
1566 } 1548 }
1567 mu_argcv_free (argc, argv);
1568 } 1549 }
1569 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);
1651 }
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;
...@@ -192,47 +195,62 @@ extern int imap4d_transcript; ...@@ -192,47 +195,62 @@ extern int imap4d_transcript;
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
194 197
195 /* Imap4 commands */ 198 /* Input functions */
196 extern int imap4d_append (struct imap4d_command *, char *); 199 imap4d_tokbuf_t imap4d_tokbuf_init (void);
197 extern int imap4d_append0 (mu_mailbox_t mbox, int flags, char *text); 200 void imap4d_tokbuf_destroy (imap4d_tokbuf_t *tok);
198 extern int imap4d_authenticate (struct imap4d_command *, char *); 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
213
214 /* Imap4 commands */
215 extern int imap4d_append (struct imap4d_command *, imap4d_tokbuf_t);
216 extern int imap4d_authenticate (struct imap4d_command *, imap4d_tokbuf_t);
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)
139 return util_finish (command, RESP_BAD, "Too few arguments");
140 150
141 /* Remove the double quotes. */ 151 ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
142 util_unquote (&ref); 152 wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
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
34 /* Remove the double quotes. */
35 util_unquote (&username);
36 util_unquote (&pass);
37 45
38 if (username == NULL || *username == '\0' || pass == NULL) 46 username = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
39 return util_finish (command, RESP_NO, "Too few args"); 47 pass = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
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)
39 return util_finish (command, RESP_BAD, "Too few arguments");
40 45
41 /* Remove the double quotes. */ 46 ref = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
42 util_unquote (&ref); 47 wcard = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
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)
39 return util_finish (command, RESP_BAD, "Too few arguments");
40
41 util_unquote (&newname);
42 util_unquote (&oldname);
43 50
44 if (*newname == '\0' || *oldname == '\0') 51 oldname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
45 return util_finish (command, RESP_BAD, "Too few arguments"); 52 newname = imap4d_tokbuf_getarg (tok, IMAP4_ARG_2);
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 '(':
371 case ')':
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 }
394 if (req && rc == 0)
395 pb->err_mesg = "Unexpected end of statement"; 376 pb->err_mesg = "Unexpected end of statement";
396 return rc; 377 return 0;
378 }
379 pb->token = imap4d_tokbuf_getarg (pb->tok, pb->arg++);
380 return 1;
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
...@@ -587,8 +572,10 @@ parse_equiv_key (struct parsebuf *pb) ...@@ -587,8 +572,10 @@ parse_equiv_key (struct parsebuf *pb)
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
...@@ -53,10 +53,21 @@ status_get_handler (const char *name) ...@@ -53,10 +53,21 @@ status_get_handler (const char *name)
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 102
91 if (*sp == '(') 103 if (item[0] == '(')
92 sp++; 104 {
93 else 105 if (imap4d_tokbuf_getarg (tok, argc - 1)[0] != ')')
94 *sp = 0; 106 return util_finish (command, RESP_BAD, "Invalid arguments");
107 argc--;
108 i++;
109 }
95 110
96 /* Get the status item names. */ 111 for (; i < argc; i++)
97 while (*sp && *sp != ')')
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 30
31 rc = imap4d_store0 (arg, 0, buffer, sizeof buffer); 31 rc = imap4d_store0 (tok, 0, &err_text);
32 return util_finish (command, rc, "%s", buffer); 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 }
50
51 static char *
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;
70 struct parsebuf pb;
71 char *data;
72 int type = 0;
47 73
48 msgset = util_getword (arg, &sp); 74 pb.tok = tok;
49 data = util_getword (NULL, &sp); 75 pb.arg = IMAP4_ARG_1;
50 76 pb.err_text = NULL;
51 if (!msgset || !data || !sp || *sp == '\0') 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 }
56 83
57 /* The parsing of the data-item is a little slugish. */ 84 msgset = parsebuf_next (&pb, 1);
58 if (strcasecmp (data, "FLAGS") == 0) 85 data = parsebuf_next (&pb, 1);
59 { 86
60 ack = 1; 87 if (*data == '+')
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; 94 how = STORE_UNSET;
95 data++;
72 } 96 }
73 else if (strcasecmp (data, "FLAGS.SILENT") == 0) 97 else
74 {
75 ack = 0;
76 how = STORE_SET; 98 how = STORE_SET;
77 } 99
78 else if (strcasecmp (data, "+FLAGS.SILENT") == 0) 100 if (strcasecmp (data, "FLAGS"))
101 parsebuf_exit (&pb, "Bogus data item");
102 data = parsebuf_next (&pb, 1);
103
104 if (*data == '.')
79 { 105 {
80 ack = 0; 106 data = parsebuf_next (&pb, 1);
81 how = STORE_ADD; 107 if (strcasecmp (data, "SILENT") == 0)
82 }
83 else if (strcasecmp (data, "-FLAGS.SILENT") == 0)
84 { 108 {
85 ack = 0; 109 ack = 0;
86 how = STORE_UNSET; 110 parsebuf_next (&pb, 1);
87 } 111 }
88 else 112 else
89 { 113 parsebuf_exit (&pb, "Bogus data suffix");
90 snprintf (resp, resplen, "Bogus data item");
91 return RESP_BAD;
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;
108 size_t msgno;
109 char *p = items;
110 138
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] = "";
122 util_token (item, sizeof (item), &items);
123 if (!util_attribute_to_type (item, &type))
124 {
125 if (how == STORE_ADD )
126 mu_attribute_set_flags (attr, type); 147 mu_attribute_set_flags (attr, type);
127 else if (how == STORE_UNSET ) 148 break;
149
150 case STORE_UNSET:
128 mu_attribute_unset_flags (attr, type); 151 mu_attribute_unset_flags (attr, type);
129 else if (how == STORE_SET ) 152 break;
130 { 153
131 if (first) 154 case STORE_SET:
132 { 155 mu_attribute_unset_flags (attr, 0xffffffff); /* FIXME */
133 mu_attribute_set_flags (attr, 0);
134 first = 0;
135 }
136 mu_attribute_set_flags (attr, type); 156 mu_attribute_set_flags (attr, type);
137 } 157 }
138 mu_attribute_set_flags (attr, MU_ATTRIBUTE_MODIFIED);
139 }
140 }
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";
32
33 if (imap4d_tokbuf_argc (tok) < 3)
34 return util_finish (command, RESP_BAD, "Invalid arguments");
35
36 cmd = imap4d_tokbuf_getarg (tok, IMAP4_ARG_1);
33 37
34 cmd = util_getword (arg, &sp);
35 if (!cmd)
36 util_finish (command, RESP_BAD, "Too few args");
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 }
......