Commit 43ba0c68 43ba0c68726d41135916aaaf9f4dfffdb56af872 by Alain Magloire

Implemented UID fetch BODYSTRUCTURE and multiple access to mailbox via IMAP

1 parent 33825193
1 2001-05-07 Alain Magloire
2
3 Now we can have multiple access to the mailbox and the server
4 will update the mailbox and send the unsollicited responses.
5 This is implemented in imap4d/sync.c.
6
7 * imap4d/copy.c: Move the code into imap4d_copy0() to allow
8 the use of UID COPY.
9 (imaprd_copy0): New function.
10 * imap4d/fetch.c: Define a new structure command for FETCH.
11 (fetch_getcommand): New function.
12 (imap4d_fetch0): New function to allow the use of UID COPY.
13 (fetch_envelope0): New function to permit to reuse the function
14 in bodystructure.
15 (fetch_bodystructure): Implemented.
16 (fetch_bodystructure0): The implementation.
17 (bodystructure): The helper function for fetch_bodystructure.
18 * imap4d/imap4d.c (imap4d_mainloop): call imap4d_sync() in the
19 mainloop. Now use FILE *ifile.
20 * imap4d/imap4d.h: Update prototypes. Define ERR_NO_MEM and
21 ERR_NO_OFILE.
22 * imap4d/select.c (imap4d_select0): Call imap4d_sync() to update.
23 * imap4d/store.c (ima4d_store): Cal imap4d_sync_flags() to
24 update the flags in the uid_table.
25 * imap4d/uid.c: Implemented.
26 * imap4d/util.c (imap4d_readline): Use fgets() and deal
27 with literals send from the client.
28 * imap4d/sync.c: New file.
29
30 * include/mailutils/header.c: Added some new headers.
31 * mailbox/attribute.c (attribute_copy): Do a shalow copy.
32 * mailbox/file_stream.c: Check if FILE * is null in all functions.
33 * mailbox/mailbox.c (mailbox_is_updated): Should not return ENOSYS
34 but rather 1.
35
36 2001-05-07 Sam Roberts
37
38 * mailbox/parse822.c: Now allow a unix mailbox in an address.
39 * include/mailutils/parse822.h: Declare the function to parse them.
40 * doc/address.texi: Document the fact.
41 * doc/Makefile.am: Automatically build the example code from addr.c.
42 * examples/addr.c: And update the parser test.
43 * examples/Addrs.good: Update the parser test.
44
1 2001-05-03 Sam Roberts 45 2001-05-03 Sam Roberts
2 46
3 * mail/mail.c: Typo 47 * mail/mail.c: Typo
......
...@@ -23,3 +23,6 @@ EXTRA_DIST = \ ...@@ -23,3 +23,6 @@ EXTRA_DIST = \
23 url.texi \ 23 url.texi \
24 version.texi 24 version.texi
25 25
26 ex-address.texi: ../examples/addr.c
27 sed -es/{/@{/g -e s/}/@}/g < $< > $@
28
......
1 @code{#include <mailutils/mailbox.h>} 1 @code{#include <mailutils/address.h>}
2 2
3 The internet address format is defined in RFC 822. RFC 822 is in the 3 The internet address format is defined in RFC 822. RFC 822 has been
4 process of being updated, and will soon be superceeded by a new RFC 4 updated, and is now superceeded by RFC 2822, which
5 that makes some corrections and clarifications. References to RFC 822 5 makes some corrections and clarifications. References to RFC 822
6 here apply equally to the new RFC. 6 here apply equally to RFC 2822.
7 7
8 The RFC 822 format is more flexible than many people realize, here 8 The RFC 822 format is more flexible than many people realize, here
9 is a quick summary of the syntax this parser implements, see 9 is a quick summary of the syntax this parser implements, see
...@@ -16,10 +16,15 @@ mailbox = addr-spec ["(" display-name ")"] / ...@@ -16,10 +16,15 @@ mailbox = addr-spec ["(" display-name ")"] /
16 [display-name] "<" [route] addr-spec ">" 16 [display-name] "<" [route] addr-spec ">"
17 mailbox-list = mailbox ["," mailbox-list] 17 mailbox-list = mailbox ["," mailbox-list]
18 group = display-name ":" [mailbox-list] ";" 18 group = display-name ":" [mailbox-list] ";"
19 address = mailbox / group 19 address = mailbox / group / unix-mbox
20 address-list = address ["," address-list] 20 address-list = address ["," address-list]
21 @end example 21 @end example
22 22
23 unix-mbox is a non-standard extention meant to deal with the common
24 practice of using user names as addresses in mail utilities. It allows
25 addresses such as "root" to be parsed correctly. These are NOT valid
26 internet email addresses, they must be qualified before use.
27
23 Several address functions have a set of common arguments with consistent 28 Several address functions have a set of common arguments with consistent
24 semantics, these are described here to avoid repetition. 29 semantics, these are described here to avoid repetition.
25 30
...@@ -133,7 +138,8 @@ The return value is @code{0} on success and a code number on error conditions: ...@@ -133,7 +138,8 @@ The return value is @code{0} on success and a code number on error conditions:
133 @deftypefun int address_get_email (address_t *@var{addr}, size_t @var{no}, char* @var{buf}, size_t @var{len}, size_t* @var{n}) 138 @deftypefun int address_get_email (address_t *@var{addr}, size_t @var{no}, char* @var{buf}, size_t @var{len}, size_t* @var{n})
134 139
135 Acesses the email addr-spec extracted while 140 Acesses the email addr-spec extracted while
136 parsing the @var{no}th email address. 141 parsing the @var{no}th email address. This will be @code{0}
142 length for a unix-mbox.
137 143
138 The return value is @code{0} on success and a code number on error conditions: 144 The return value is @code{0} on success and a code number on error conditions:
139 @table @code 145 @table @code
...@@ -157,7 +163,8 @@ The return value is @code{0} on success and a code number on error conditions: ...@@ -157,7 +163,8 @@ The return value is @code{0} on success and a code number on error conditions:
157 @deftypefun int address_get_domain (address_t *@var{addr}, size_t @var{no}, char* @var{buf}, size_t @var{len}, size_t* @var{n}) 163 @deftypefun int address_get_domain (address_t *@var{addr}, size_t @var{no}, char* @var{buf}, size_t @var{len}, size_t* @var{n})
158 164
159 Acesses the domain of an email addr-spec extracted while 165 Acesses the domain of an email addr-spec extracted while
160 parsing the @var{no}th email address. 166 parsing the @var{no}th email address. This will be @code{0}
167 length for a unix-mbox.
161 168
162 The return value is @code{0} on success and a code number on error conditions: 169 The return value is @code{0} on success and a code number on error conditions:
163 @table @code 170 @table @code
...@@ -223,54 +230,6 @@ The return value is @code{0}. ...@@ -223,54 +230,6 @@ The return value is @code{0}.
223 230
224 @section Example 231 @section Example
225 @example 232 @example
226 #include <stdio.h> 233 @include ex-address.texi
227 #include <mailutils/address.h>
228
229 int
230 main(int argc, const char *argv[])
231 @{
232 for(argc = 1; argv[argc]; argc++)
233 @{
234 const char* str = argv[argc];
235 address_t address = NULL;
236
237 address_create(&address, str);
238
239 printf("'%s' ->\n", str);
240 @{
241 size_t no = 0;
242 size_t pcount;
243
244 address_get_count(address, &pcount);
245
246 printf(" pcount %d\n", pcount);
247
248 for(no = 1; no <= pcount; no++)
249 @{
250 char buf[BUFSIZ];
251
252 address_get_personal(address, no, buf, sizeof(buf), 0);
253
254 printf(" personal '%s'\n", buf);
255
256 address_get_local_part(address, no, buf, sizeof(buf), 0);
257
258 printf(" local_part '%s'\n", buf);
259
260 address_get_domain(address, no, buf, sizeof(buf), 0);
261
262 printf(" domain '%s'\n", buf);
263
264 address_get_email(address, no, buf, sizeof(buf), 0);
265
266 printf(" email '%s'\n", buf);
267 @}
268 @}
269
270 address_destroy(&address);
271 @}
272
273 return 0;
274 @}
275 @end example 234 @end example
276 235
......
...@@ -228,7 +228,7 @@ list-ietf-wg-apps-drums@faerber.muc.de (=?ISO-8859-1?Q?Claus_F=E4rber?=)=> pcoun ...@@ -228,7 +228,7 @@ list-ietf-wg-apps-drums@faerber.muc.de (=?ISO-8859-1?Q?Claus_F=E4rber?=)=> pcoun
228 personal <'sroberts@certicom.ca'> 228 personal <'sroberts@certicom.ca'>
229 local-part <sroberts> domain <certicom.ca> 229 local-part <sroberts> domain <certicom.ca>
230 230
231 "=?iso-8859-1?Q?Juan_Carlos_Marcos_Rodr=EDguez?=" <jcmarcos@datavoicees>=> pcount 1 231 "=?iso-8859-1?Q?Juan_Carlos_Marcos_Rodr=EDguez?=" <jcmarcos@datavoice.es>=> pcount 1
232 1 email <jcmarcos@datavoice.es> 232 1 email <jcmarcos@datavoice.es>
233 personal <=?iso-8859-1?Q?Juan_Carlos_Marcos_Rodr=EDguez?=> 233 personal <=?iso-8859-1?Q?Juan_Carlos_Marcos_Rodr=EDguez?=>
234 local-part <jcmarcos> domain <datavoice.es> 234 local-part <jcmarcos> domain <datavoice.es>
...@@ -432,17 +432,17 @@ list-ietf-wg-apps-drums@faerber.muc.de (=?ISO-8859-1?Q?Claus_F=E4rber?=)=> pcoun ...@@ -432,17 +432,17 @@ list-ietf-wg-apps-drums@faerber.muc.de (=?ISO-8859-1?Q?Claus_F=E4rber?=)=> pcoun
432 personal <=?US-ASCII?Q?gary=5Fc?=> 432 personal <=?US-ASCII?Q?gary=5Fc?=>
433 local-part <gary_c> domain <cunningham-lee.com> 433 local-part <gary_c> domain <cunningham-lee.com>
434 434
435 =?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidusnet>=> pcount 1 435 =?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidus.net>=> pcount 1
436 1 email <0@pervalidus.net> 436 1 email <0@pervalidus.net>
437 personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier> 437 personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier>
438 local-part <0> domain <pervalidus.net> 438 local-part <0> domain <pervalidus.net>
439 439
440 =?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidusnet>,=> pcount 1 440 =?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidus.net>,=> pcount 1
441 1 email <0@pervalidus.net> 441 1 email <0@pervalidus.net>
442 personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier> 442 personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier>
443 local-part <0> domain <pervalidus.net> 443 local-part <0> domain <pervalidus.net>
444 444
445 =?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E_Meunier?= <0@pervalidusnet>=> pcount 1 445 =?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E_Meunier?= <0@pervalidus.net>=> pcount 1
446 1 email <0@pervalidus.net> 446 1 email <0@pervalidus.net>
447 personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E_Meunier?=> 447 personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E_Meunier?=>
448 local-part <0> domain <pervalidus.net> 448 local-part <0> domain <pervalidus.net>
...@@ -554,14 +554,22 @@ No_Reply-To@mapquest.com=> pcount 1 ...@@ -554,14 +554,22 @@ No_Reply-To@mapquest.com=> pcount 1
554 1 email <No_Reply-To@mapquest.com> 554 1 email <No_Reply-To@mapquest.com>
555 local-part <No_Reply-To> domain <mapquest.com> 555 local-part <No_Reply-To> domain <mapquest.com>
556 556
557 OSULLIE@rte.ie, skidswam@hotmail.com, boot=> error ENOENT 557 OSULLIE@rte.ie, skidswam@hotmail.com, boot=> pcount 3
558 1 email <OSULLIE@rte.ie>
559 local-part <OSULLIE> domain <rte.ie>
560 2 email <skidswam@hotmail.com>
561 local-part <skidswam> domain <hotmail.com>
562 3 email <>
563 local-part <boot>
558 564
559 Paul Hoffman / IMC <phoffman@imc.org>=> pcount 1 565 Paul Hoffman / IMC <phoffman@imc.org>=> pcount 1
560 1 email <phoffman@imc.org> 566 1 email <phoffman@imc.org>
561 personal <Paul Hoffman / IMC> 567 personal <Paul Hoffman / IMC>
562 local-part <phoffman> domain <imc.org> 568 local-part <phoffman> domain <imc.org>
563 569
564 Sam=> error ENOENT 570 Sam=> pcount 1
571 1 email <>
572 local-part <Sam>
565 573
566 Sam Roberts <sam@cogent.ca>=> pcount 1 574 Sam Roberts <sam@cogent.ca>=> pcount 1
567 1 email <sam@cogent.ca> 575 1 email <sam@cogent.ca>
...@@ -605,7 +613,9 @@ mcaustin@eudoramail.com, aposner@usaid.gov, Kieran.O'Leary@anpost.ie,=> pcount 3 ...@@ -605,7 +613,9 @@ mcaustin@eudoramail.com, aposner@usaid.gov, Kieran.O'Leary@anpost.ie,=> pcount 3
605 613
606 rfunk@wks.uts.ohio-state.eduofflinemailer-bounce@dikke.penguin.nl=> error ENOENT 614 rfunk@wks.uts.ohio-state.eduofflinemailer-bounce@dikke.penguin.nl=> error ENOENT
607 615
608 root=> error ENOENT 616 root=> pcount 1
617 1 email <>
618 local-part <root>
609 619
610 srr <sam@localhost>=> error ENOENT 620 srr <sam@localhost>=> error ENOENT
611 621
......
...@@ -78,11 +78,15 @@ static int parse(const char* str) ...@@ -78,11 +78,15 @@ static int parse(const char* str)
78 78
79 address_get_local_part(address, no, buf, sizeof(buf), &got); 79 address_get_local_part(address, no, buf, sizeof(buf), &got);
80 80
81 if(got) printf(" local-part <%s>", buf); 81 if(got) {
82 printf(" local-part <%s>", buf);
82 83
83 address_get_domain(address, no, buf, sizeof(buf), &got); 84 address_get_domain(address, no, buf, sizeof(buf), &got);
84 85
85 if(got) printf(" domain <%s>\n", buf); 86 if(got) printf(" domain <%s>", buf);
87
88 printf("\n");
89 }
86 90
87 address_get_route(address, no, buf, sizeof(buf), &got); 91 address_get_route(address, no, buf, sizeof(buf), &got);
88 92
......
...@@ -21,34 +21,57 @@ ...@@ -21,34 +21,57 @@
21 * copy messages in argv[2] to mailbox in argv[3] 21 * copy messages in argv[2] to mailbox in argv[3]
22 */ 22 */
23 23
24 /* FIXME if the mailbox is the one selecte we should send notif. */
25 int 24 int
26 imap4d_copy (struct imap4d_command *command, char *arg) 25 imap4d_copy (struct imap4d_command *command, char *arg)
27 { 26 {
27 int rc;
28 char buffer[64];
29
30 if (! (command->states & state))
31 return util_finish (command, RESP_BAD, "Wrong state");
32
33 rc = imap4d_copy0 (arg, 0, buffer, sizeof buffer);
34 if (rc == RESP_NONE)
35 {
36 /* Reset the state ourself. */
37 int new_state = (rc == RESP_OK) ? command->success : command->failure;
38 if (new_state != STATE_NONE)
39 state = new_state;
40 return util_send ("%s %s\r\n", command->tag, buffer);
41 }
42 return util_finish (command, rc, buffer);
43 }
44
45 int
46 imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen)
47 {
28 int status; 48 int status;
29 char *msgset; 49 char *msgset;
30 char *name; 50 char *name;
31 char *mailbox_name; 51 char *mailbox_name;
32 const char *delim = "/"; 52 const char *delim = "/";
33 char *sp = NULL; 53 char *sp = NULL;
34 int *set = NULL; 54 size_t *set = NULL;
35 size_t n = 0; 55 size_t n = 0;
36 mailbox_t cmbox = NULL; 56 mailbox_t cmbox = NULL;
37 57
38 if (! (command->states & state))
39 return util_finish (command, RESP_BAD, "Wrong state");
40
41 msgset = util_getword (arg, &sp); 58 msgset = util_getword (arg, &sp);
42 name = util_getword (NULL, &sp); 59 name = util_getword (NULL, &sp);
43 60
44 util_unquote (&name); 61 util_unquote (&name);
45 if (!msgset || !name || *name == '\0') 62 if (!msgset || !name || *name == '\0')
46 return util_finish (command, RESP_BAD, "Too few args"); 63 {
64 snprintf (resp, resplen, "Too few args");
65 return RESP_BAD;
66 }
47 67
48 /* Get the message numbers in set[]. */ 68 /* Get the message numbers in set[]. */
49 status = util_msgset (msgset, &set, &n, 0); 69 status = util_msgset (msgset, &set, &n, isuid);
50 if (status != 0) 70 if (status != 0)
51 return util_finish (command, RESP_BAD, "Bogus number set"); 71 {
72 snprintf (resp, resplen, "Bogus number set");
73 return RESP_BAD;
74 }
52 75
53 if (strcasecmp (name, "INBOX") == 0) 76 if (strcasecmp (name, "INBOX") == 0)
54 { 77 {
...@@ -71,7 +94,8 @@ imap4d_copy (struct imap4d_command *command, char *arg) ...@@ -71,7 +94,8 @@ imap4d_copy (struct imap4d_command *command, char *arg)
71 for (i = 0; i < n; i++) 94 for (i = 0; i < n; i++)
72 { 95 {
73 message_t msg = NULL; 96 message_t msg = NULL;
74 mailbox_get_message (mbox, set[i], &msg); 97 size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
98 mailbox_get_message (mbox, msgno, &msg);
75 mailbox_append_message (cmbox, msg); 99 mailbox_append_message (cmbox, msg);
76 } 100 }
77 mailbox_close (cmbox); 101 mailbox_close (cmbox);
...@@ -82,16 +106,16 @@ imap4d_copy (struct imap4d_command *command, char *arg) ...@@ -82,16 +106,16 @@ imap4d_copy (struct imap4d_command *command, char *arg)
82 free (mailbox_name); 106 free (mailbox_name);
83 107
84 if (status == 0) 108 if (status == 0)
85 return util_finish (command, RESP_OK, "Completed"); 109 {
86 110 snprintf (resp, resplen, "Completed");
87 /* Since we do not call util_finish, reset the state ourself. */ 111 return RESP_OK;
88 if (command->failure != STATE_NONE) 112 }
89 state = command->failure;
90 113
91 /* Unless it is certain that the destination mailbix can not be created, 114 /* Unless it is certain that the destination mailbix can not be created,
92 the server MUST send the response code "[TRYCREATE]" as the prefix 115 the server MUST send the response code "[TRYCREATE]" as the prefix
93 of the text of the tagged NO response. This gives a hint to the 116 of the text of the tagged NO response. This gives a hint to the
94 client that it can attempt a CREATE command and retry the copy if 117 client that it can attempt a CREATE command and retry the copy if
95 the CREATE is successful. */ 118 the CREATE is successful. */
96 return util_send ("%s NO [TRYCREATE] failed\r\n", command->tag); 119 snprintf (resp, resplen, "NO [TRYCREATE] failed");
120 return RESP_NONE;
97 } 121 }
......
...@@ -32,176 +32,244 @@ ...@@ -32,176 +32,244 @@
32 ["<" number "." nz_number ">"] 32 ["<" number "." nz_number ">"]
33 */ 33 */
34 34
35 static int fetch_all __P ((struct imap4d_command *, char*)); 35 struct fetch_command;
36 static int fetch_full __P ((struct imap4d_command *, char*)); 36
37 static int fetch_fast __P ((struct imap4d_command *, char*)); 37 static int fetch_all __P ((struct fetch_command *, char*));
38 static int fetch_envelope __P ((struct imap4d_command *, char*)); 38 static int fetch_full __P ((struct fetch_command *, char*));
39 static int fetch_flags __P ((struct imap4d_command *, char*)); 39 static int fetch_fast __P ((struct fetch_command *, char*));
40 static int fetch_internaldate __P ((struct imap4d_command *, char*)); 40 static int fetch_envelope __P ((struct fetch_command *, char*));
41 static int fetch_rfc822_header __P ((struct imap4d_command *, char*)); 41 static int fetch_envelope0 __P ((message_t));
42 static int fetch_rfc822_size __P ((struct imap4d_command *, char*)); 42 static int fetch_flags __P ((struct fetch_command *, char*));
43 static int fetch_rfc822_text __P ((struct imap4d_command *, char*)); 43 static int fetch_internaldate __P ((struct fetch_command *, char*));
44 static int fetch_rfc822 __P ((struct imap4d_command *, char*)); 44 static int fetch_rfc822_header __P ((struct fetch_command *, char*));
45 static int fetch_bodystructure __P ((struct imap4d_command *, char*)); 45 static int fetch_rfc822_size __P ((struct fetch_command *, char*));
46 static int fetch_body_peek __P ((struct imap4d_command *, char*)); 46 static int fetch_rfc822_text __P ((struct fetch_command *, char*));
47 static int fetch_body __P ((struct imap4d_command *, char*)); 47 static int fetch_rfc822 __P ((struct fetch_command *, char*));
48 static int fetch_uid __P ((struct imap4d_command *, char*)); 48 static int fetch_bodystructure __P ((struct fetch_command *, char*));
49 49 static int fetch_bodystructure0 __P ((message_t, int));
50 static int fetch_operation __P ((size_t, char *, int)); 50 static int bodystructure __P ((message_t, int));
51 static int fetch_message __P ((message_t, unsigned long, unsigned long)); 51 static int fetch_body_peek __P ((struct fetch_command *, char*));
52 static int fetch_header __P ((message_t, unsigned long, unsigned long)); 52 static int fetch_body __P ((struct fetch_command *, char*));
53 static int fetch_content __P ((message_t, unsigned long, unsigned long)); 53 static int fetch_uid __P ((struct fetch_command *, char*));
54 static int fetch_io __P ((stream_t, unsigned long, unsigned long)); 54
55 static int fetch_header_fields __P ((message_t, char *, unsigned long, 55 static int fetch_operation __P ((size_t, char *, int));
56 unsigned long)); 56 static int fetch_message __P ((message_t, unsigned long, unsigned long));
57 static int fetch_header_fields_not __P ((message_t, char *, unsigned long, 57 static int fetch_header __P ((message_t, unsigned long, unsigned long));
58 unsigned long)); 58 static int fetch_content __P ((message_t, unsigned long, unsigned long));
59 static int fetch_send_address __P ((char *)); 59 static int fetch_io __P ((stream_t, unsigned long, unsigned long));
60 60 static int fetch_header_fields __P ((message_t, char *, unsigned long, unsigned long));
61 struct imap4d_command fetch_command_table [] = 61 static int fetch_header_fields_not __P ((message_t, char *, unsigned long, unsigned long));
62 static int fetch_send_address __P ((char *));
63
64 static struct fetch_command* fetch_getcommand __P ((char *, struct fetch_command[]));
65
66 struct fetch_command
67 {
68 const char *name;
69 int (*func) __P ((struct fetch_command *, char *));
70 size_t msgno;
71 } fetch_command_table [] =
62 { 72 {
63 #define F_ALL 0 73 #define F_ALL 0
64 {"ALL", fetch_all, 0, 0, 0, NULL}, 74 {"ALL", fetch_all, 0},
65 #define F_FULL 1 75 #define F_FULL 1
66 {"FULL", fetch_full, 0, 0, 0, NULL}, 76 {"FULL", fetch_full, 0},
67 #define F_FAST 2 77 #define F_FAST 2
68 {"FAST", fetch_fast, 0, 0, 0, NULL}, 78 {"FAST", fetch_fast, 0},
69 #define F_ENVELOPE 3 79 #define F_ENVELOPE 3
70 {"ENVELOPE", fetch_envelope, 0, 0, 0, NULL}, 80 {"ENVELOPE", fetch_envelope, 0},
71 #define F_FLAGS 4 81 #define F_FLAGS 4
72 {"FLAGS", fetch_flags, 0, 0, 0, NULL}, 82 {"FLAGS", fetch_flags, 0},
73 #define F_INTERNALDATE 5 83 #define F_INTERNALDATE 5
74 {"INTERNALDATE", fetch_internaldate, 0, 0, 0, NULL}, 84 {"INTERNALDATE", fetch_internaldate, 0},
75 #define F_RFC822_HEADER 6 85 #define F_RFC822_HEADER 6
76 {"RFC822.HEADER", fetch_rfc822_header, 0, 0, 0, NULL}, 86 {"RFC822.HEADER", fetch_rfc822_header, 0},
77 #define F_RFC822_SIZE 7 87 #define F_RFC822_SIZE 7
78 {"RFC822.SIZE", fetch_rfc822_size, 0, 0, 0, NULL}, 88 {"RFC822.SIZE", fetch_rfc822_size, 0},
79 #define F_RFC822_TEXT 8 89 #define F_RFC822_TEXT 8
80 {"RFC822.TEXT", fetch_rfc822_text, 0, 0, 0, NULL}, 90 {"RFC822.TEXT", fetch_rfc822_text, 0},
81 #define F_RFC822 9 91 #define F_RFC822 9
82 {"RFC822", fetch_rfc822, 0, 0, 0, NULL}, 92 {"RFC822", fetch_rfc822, 0},
83 #define F_BODYSTRUCTURE 10 93 #define F_BODYSTRUCTURE 10
84 {"BODYSTRUCTURE", fetch_bodystructure, 0, 0, 0, NULL}, 94 {"BODYSTRUCTURE", fetch_bodystructure, 0},
85 #define F_BODY_PEEK 11 95 #define F_BODY_PEEK 11
86 {"BODY.PEEK", fetch_body_peek, 0, 0, 0, NULL}, 96 {"BODY.PEEK", fetch_body_peek, 0},
87 #define F_BODY 12 97 #define F_BODY 12
88 {"BODY", fetch_body, 0, 0, 0, NULL}, 98 {"BODY", fetch_body, 0},
89 #define F_UID 13 99 #define F_UID 13
90 {"UID", fetch_uid, 0, 0, 0, NULL}, 100 {"UID", fetch_uid, 0},
91 { NULL, 0, 0, 0, 0, NULL} 101 { NULL, 0, 0}
92 }; 102 };
93 103
94 /* NOTE: the state field in the command structure is use as a place
95 holder for the message number. This save us from redifining another
96 data structure. */
97 int 104 int
98 imap4d_fetch (struct imap4d_command *command, char *arg) 105 imap4d_fetch (struct imap4d_command *command, char *arg)
99 { 106 {
100 char *sp = NULL; 107 int rc;
101 char *msgset; 108 char buffer[64];
102 int *set = NULL;
103 int i, n = 0;
104 int rc = RESP_OK;
105 int status;
106 const char *errmsg = "Completed";
107 struct imap4d_command *fcmd;
108 109
109 if (! (command->states & state)) 110 if (! (command->states & state))
110 return util_finish (command, RESP_BAD, "Wrong state"); 111 return util_finish (command, RESP_BAD, "Wrong state");
111 112
113 rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer);
114 return util_finish (command, rc, buffer);
115 }
116
117 static struct fetch_command *
118 fetch_getcommand (char *cmd, struct fetch_command command_table[])
119 {
120 size_t i, len = strlen (cmd);
121
122 for (i = 0; command_table[i].name != 0; i++)
123 {
124 if (strlen (command_table[i].name) == len &&
125 !strcasecmp (command_table[i].name, cmd))
126 return &command_table[i];
127 }
128 return NULL;
129 }
130
131 int
132 imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
133 {
134 struct fetch_command *fcmd = NULL;
135 int rc = RESP_NO;
136 char *sp = NULL;
137 char *msgset;
138 size_t *set = NULL;
139 int n = 0;
140 int i;
141 int status;
142
112 msgset = util_getword (arg, &sp); 143 msgset = util_getword (arg, &sp);
113 if (!msgset || !sp || *sp == '\0') 144 if (!msgset || !sp || *sp == '\0')
114 return util_finish (command, RESP_BAD, "Too few args"); 145 {
146 snprintf (resp, resplen, "Too few args");
147 return RESP_BAD;
148 }
115 149
116 /* Get the message numbers in set[]. */ 150 /* Get the message numbers in set[]. */
117 status = util_msgset (msgset, &set, &n, 0); 151 status = util_msgset (msgset, &set, &n, isuid);
118 if (status != 0) 152 if (status != 0)
119 return util_finish (command, RESP_BAD, "Bogus number set"); 153 {
154 snprintf (resp, resplen, "Bogus number set");
155 return RESP_BAD;
156 }
120 157
121 for (i = 0; i < n; i++) 158 for (i = 0; i < n; i++)
122 { 159 {
123 char item[32]; 160 char item[32];
124 char *items = strdup (sp); 161 char *items = strdup (sp);
125 char *p = items; 162 char *p = items;
126 util_send ("* FETCH %d (", set[i]); 163 int uid_sent = !isuid; /* Pretend we sent the uid if via fetch. */
164 util_send ("* %d FETCH (", set[i]);
127 item[0] = '\0'; 165 item[0] = '\0';
128 /* Get the fetch command names. */ 166 /* Get the fetch command names. */
129 while (*items && *items != ')') 167 while (*items && *items != ')')
130 { 168 {
131 util_token (item, sizeof (item), &items); 169 util_token (item, sizeof (item), &items);
170 if (fcmd)
171 util_send (" ");
132 /* Search in the table. */ 172 /* Search in the table. */
133 fcmd = util_getcommand (item, fetch_command_table); 173 fcmd = fetch_getcommand (item, fetch_command_table);
134 if (fcmd) 174 if (fcmd)
135 { 175 {
136 /* We use the states field to hold the msgno/uid. */ 176 fcmd->msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
137 fcmd->states = set[i]; 177 if (fcmd->msgno != 0)
138 fcmd->func (fcmd, items); 178 {
139 util_send (" "); 179 rc = fcmd->func (fcmd, items);
180 }
140 } 181 }
182 if (!uid_sent)
183 uid_sent = ((strstr (item, "UID") != NULL)
184 || (strstr (item, "uid") != NULL));
185 }
186 /* Always send the UID when fetch was done via the uid command. */
187 if (!uid_sent)
188 {
189 struct fetch_command c_uid = fetch_command_table[F_UID];
190 c_uid.msgno = set[i];
191 if (fcmd)
192 util_send (" ");
193 rc = fetch_uid (&c_uid, items);
141 } 194 }
142 free (p); 195 free (p);
143 util_send (")\r\n"); 196 util_send (")\r\n");
144 } 197 }
145 free (set); 198 free (set);
146 return util_finish (command, rc, errmsg); 199 snprintf (resp, resplen, "Completed");
200 return rc;
147 } 201 }
148 202
149 /* Combination of (FAST ENVELOPE). */ 203 /* The Fetch comand retireves data associated with a message in the
204 mailbox, The data items to be fetched can be either a single atom
205 or a parenthesized list. */
206
207 /* Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
208 or (FAST ENVELOPE) */
150 static int 209 static int
151 fetch_all (struct imap4d_command *command, char *arg) 210 fetch_all (struct fetch_command *command, char *arg)
152 { 211 {
153 struct imap4d_command c_env = fetch_command_table[F_ENVELOPE]; 212 struct fetch_command c_env = fetch_command_table[F_ENVELOPE];
154 fetch_fast (command, arg); 213 fetch_fast (command, arg);
155 util_send (" "); 214 util_send (" ");
156 c_env.states = command->states; 215 c_env.msgno = command->msgno;
157 fetch_envelope (&c_env, arg); 216 fetch_envelope (&c_env, arg);
158 return 0; 217 return RESP_OK;
159 } 218 }
160 219
161 /* Combination of (ALL BODY). */ 220 /* Combination of (ALL BODY). */
162 static int 221 static int
163 fetch_full (struct imap4d_command *command, char *arg) 222 fetch_full (struct fetch_command *command, char *arg)
164 { 223 {
165 struct imap4d_command c_body = fetch_command_table[F_BODY]; 224 struct fetch_command c_body = fetch_command_table[F_BODY];
166 fetch_all (command, arg); 225 fetch_all (command, arg);
167 util_send (" "); 226 util_send (" ");
168 c_body.states = command->states; 227 c_body.msgno = command->msgno;
169 fetch_body (&c_body, arg); 228 fetch_body (&c_body, arg);
170 return 0; 229 return RESP_OK;
171 } 230 }
172 231
173 /* Combination of (FLAGS INTERNALDATE RFC822.SIZE). */ 232 /* Combination of (FLAGS INTERNALDATE RFC822.SIZE). */
174 static int 233 static int
175 fetch_fast (struct imap4d_command *command, char *arg) 234 fetch_fast (struct fetch_command *command, char *arg)
176 { 235 {
177 struct imap4d_command c_idate = fetch_command_table[F_INTERNALDATE]; 236 struct fetch_command c_idate = fetch_command_table[F_INTERNALDATE];
178 struct imap4d_command c_rfc = fetch_command_table[F_RFC822_SIZE]; 237 struct fetch_command c_rfc = fetch_command_table[F_RFC822_SIZE];
179 struct imap4d_command c_flags = fetch_command_table[F_FLAGS]; 238 struct fetch_command c_flags = fetch_command_table[F_FLAGS];
180 c_flags.states = command->states; 239 c_flags.msgno = command->msgno;
181 fetch_flags (&c_flags, arg); 240 fetch_flags (&c_flags, arg);
182 util_send (" "); 241 util_send (" ");
183 c_idate.states = command->states; 242 c_idate.msgno = command->msgno;
184 fetch_internaldate (&c_idate, arg); 243 fetch_internaldate (&c_idate, arg);
185 util_send (" "); 244 util_send (" ");
186 c_rfc.states = command->states; 245 c_rfc.msgno = command->msgno;
187 fetch_rfc822_size (&c_rfc, arg); 246 fetch_rfc822_size (&c_rfc, arg);
188 return 0; 247 return RESP_OK;
189 } 248 }
190 249
191 /* Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, 250 /* Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To,
192 and Message-Id. */ 251 and Message-Id. */
252 static int
253 fetch_envelope (struct fetch_command *command, char *arg)
254 {
255 message_t msg = NULL;
256 int status;
257 mailbox_get_message (mbox, command->msgno, &msg);
258 util_send ("%s (", command->name);
259 status = fetch_envelope0 (msg);
260 util_send (")");
261 return status;
262 }
263
193 /* FIXME: - strings change to literals when detecting '"' */ 264 /* FIXME: - strings change to literals when detecting '"' */
194 static int 265 static int
195 fetch_envelope (struct imap4d_command *command, char *arg) 266 fetch_envelope0 (message_t msg)
196 { 267 {
197 char *buffer; 268 char *buffer = NULL;
198 char *from; 269 char *from = NULL;
199 header_t header = NULL; 270 header_t header = NULL;
200 message_t msg = NULL;
201 271
202 mailbox_get_message (mbox, command->states, &msg);
203 message_get_header (msg, &header); 272 message_get_header (msg, &header);
204 util_send ("%s(", command->name);
205 273
206 /* FIXME: Incorrect Date. */ 274 /* FIXME: Incorrect Date. */
207 header_aget_value (header, "Date", &buffer); 275 header_aget_value (header, "Date", &buffer);
...@@ -266,18 +334,18 @@ fetch_envelope (struct imap4d_command *command, char *arg) ...@@ -266,18 +334,18 @@ fetch_envelope (struct imap4d_command *command, char *arg)
266 334
267 free (buffer); 335 free (buffer);
268 free (from); 336 free (from);
269 util_send (")"); 337 return RESP_OK;
270 return 0;
271 } 338 }
272 339
273 /* The flags that are set for this message. */ 340 /* The flags that are set for this message. */
274 /* FIXME: User flags not done. */ 341 /* FIXME: User flags not done. */
275 static int 342 static int
276 fetch_flags (struct imap4d_command *command, char *arg) 343 fetch_flags (struct fetch_command *command, char *arg)
277 { 344 {
278 attribute_t attr = NULL; 345 attribute_t attr = NULL;
279 message_t msg = NULL; 346 message_t msg = NULL;
280 mailbox_get_message (mbox, command->states, &msg); 347 (void)arg;
348 mailbox_get_message (mbox, command->msgno, &msg);
281 message_get_attribute (msg, &attr); 349 message_get_attribute (msg, &attr);
282 util_send ("%s (", command->name); 350 util_send ("%s (", command->name);
283 if (attribute_is_deleted (attr)) 351 if (attribute_is_deleted (attr))
...@@ -286,23 +354,23 @@ fetch_flags (struct imap4d_command *command, char *arg) ...@@ -286,23 +354,23 @@ fetch_flags (struct imap4d_command *command, char *arg)
286 util_send (" \\Answered"); 354 util_send (" \\Answered");
287 if (attribute_is_flagged (attr)) 355 if (attribute_is_flagged (attr))
288 util_send (" \\Flagged"); 356 util_send (" \\Flagged");
289 if (attribute_is_seen (attr)) 357 if (attribute_is_seen (attr) && attribute_is_read (attr))
290 util_send (" \\Seen"); 358 util_send (" \\Seen");
291 if (attribute_is_draft (attr)) 359 if (attribute_is_draft (attr))
292 util_send (" \\Draft"); 360 util_send (" \\Draft");
293 util_send (" )"); 361 util_send (" )");
294 return 0; 362 return RESP_OK;
295 } 363 }
296 364
297 /* The internal date of the message. */ 365 /* The internal date of the message. */
298 /* FIXME: Wrong format? */ 366 /* FIXME: Wrong format? */
299 static int 367 static int
300 fetch_internaldate (struct imap4d_command *command, char *arg) 368 fetch_internaldate (struct fetch_command *command, char *arg)
301 { 369 {
302 char date[512]; 370 char date[512];
303 envelope_t env = NULL; 371 envelope_t env = NULL;
304 message_t msg = NULL; 372 message_t msg = NULL;
305 mailbox_get_message (mbox, command->states, &msg); 373 mailbox_get_message (mbox, command->msgno, &msg);
306 message_get_envelope (msg, &env); 374 message_get_envelope (msg, &env);
307 date[0] = '\0'; 375 date[0] = '\0';
308 envelope_date (env, date, sizeof (date), NULL); 376 envelope_date (env, date, sizeof (date), NULL);
...@@ -310,76 +378,80 @@ fetch_internaldate (struct imap4d_command *command, char *arg) ...@@ -310,76 +378,80 @@ fetch_internaldate (struct imap4d_command *command, char *arg)
310 if (date[strlen (date) - 1] == '\n') 378 if (date[strlen (date) - 1] == '\n')
311 date[strlen (date) - 1] = '\0'; 379 date[strlen (date) - 1] = '\0';
312 util_send (" \"%s\"", date); 380 util_send (" \"%s\"", date);
313 return 0; 381 return RESP_OK;
314 } 382 }
315 383
316 /* Equivalent to BODY.PEEK[HEADER]. */ 384 /* Equivalent to BODY.PEEK[HEADER]. */
317 static int 385 static int
318 fetch_rfc822_header (struct imap4d_command *command, char *arg) 386 fetch_rfc822_header (struct fetch_command *command, char *arg)
319 { 387 {
320 char buffer[16]; 388 char buffer[16];
321 (void)arg; 389 (void)arg;
322 util_send ("%s ", command->name); 390 util_send ("%s ", command->name);
323 strcpy (buffer, "[HEADER]"); 391 strcpy (buffer, "[HEADER]");
324 fetch_operation (command->states, buffer, 1); 392 fetch_operation (command->msgno, buffer, 1);
325 return 0; 393 return RESP_OK;
326 } 394 }
327 395
328 /* Equivalent to BODY[TEXT]. */ 396 /* Equivalent to BODY[TEXT]. */
329 /* FIXME: send a Fetch flag if the mail was not set seen ? */
330 static int 397 static int
331 fetch_rfc822_text (struct imap4d_command *command, char *arg) 398 fetch_rfc822_text (struct fetch_command *command, char *arg)
332 { 399 {
333 char buffer[16]; 400 char buffer[16];
334 attribute_t attr = NULL; 401 attribute_t attr = NULL;
335 message_t msg = NULL; 402 message_t msg = NULL;
336 mailbox_get_message (mbox, command->states, &msg); 403 (void)arg;
404 mailbox_get_message (mbox, command->msgno, &msg);
337 message_get_attribute (msg, &attr); 405 message_get_attribute (msg, &attr);
338 attribute_set_read (attr); 406 if (!attribute_is_seen (attr) && !attribute_is_read (attr))
407 {
408 util_send ("FLAGS (\\Seen) ");
409 attribute_set_seen (attr);
410 attribute_set_read (attr);
411 }
339 util_send ("%s ", command->name); 412 util_send ("%s ", command->name);
340 strcpy (buffer, "[TEXT]"); 413 strcpy (buffer, "[TEXT]");
341 fetch_operation (command->states, buffer, 1); 414 fetch_operation (command->msgno, buffer, 1);
342 return 0; 415 return RESP_OK;
343 } 416 }
344 417
345 /* The [RFC-822] size of the message. */ 418 /* The [RFC-822] size of the message. */
346 static int 419 static int
347 fetch_rfc822_size (struct imap4d_command *command, char *arg) 420 fetch_rfc822_size (struct fetch_command *command, char *arg)
348 { 421 {
349 size_t size = 0; 422 size_t size = 0;
350 size_t lines = 0; 423 size_t lines = 0;
351 message_t msg = NULL; 424 message_t msg = NULL;
352 (void)arg; 425 (void)arg;
353 mailbox_get_message (mbox, command->states, &msg); 426 mailbox_get_message (mbox, command->msgno, &msg);
354 message_size (msg, &size); 427 message_size (msg, &size);
355 message_lines (msg, &lines); 428 message_lines (msg, &lines);
356 util_send ("%s %u", command->name, size + lines); 429 util_send ("%s %u", command->name, size + lines);
357 return 0; 430 return RESP_OK;
358 } 431 }
359 432
360 /* Equivalent to BODY[]. */ 433 /* Equivalent to BODY[]. */
361 /* FIXME: send a Fetch flag if the mail was not set seen ? */
362 static int 434 static int
363 fetch_rfc822 (struct imap4d_command *command, char *arg) 435 fetch_rfc822 (struct fetch_command *command, char *arg)
364 { 436 {
365 if (*arg == '.') 437 if (*arg == '.')
366 { 438 {
367 if (strncasecmp (arg, ".SIZE", 5) == 0) 439 if (strncasecmp (arg, ".SIZE", 5) == 0)
368 { 440 {
369 struct imap4d_command c_rfc= fetch_command_table[F_RFC822_SIZE]; 441 struct fetch_command c_rfc= fetch_command_table[F_RFC822_SIZE];
370 c_rfc.states = command->states; 442 c_rfc.msgno = command->msgno;
371 fetch_rfc822_size (&c_rfc, arg); 443 fetch_rfc822_size (&c_rfc, arg);
372 } 444 }
373 else if (strncasecmp (arg, ".TEXT", 5) == 0) 445 else if (strncasecmp (arg, ".TEXT", 5) == 0)
374 { 446 {
375 struct imap4d_command c_rfc = fetch_command_table[F_RFC822_TEXT]; 447 struct fetch_command c_rfc = fetch_command_table[F_RFC822_TEXT];
376 c_rfc.states = command->states; 448 c_rfc.msgno = command->msgno;
377 fetch_rfc822_text (&c_rfc, arg); 449 fetch_rfc822_text (&c_rfc, arg);
378 } 450 }
379 else if (strncasecmp (arg, ".HEADER", 7) == 0) 451 else if (strncasecmp (arg, ".HEADER", 7) == 0)
380 { 452 {
381 struct imap4d_command c_rfc = fetch_command_table[F_RFC822_HEADER]; 453 struct fetch_command c_rfc = fetch_command_table[F_RFC822_HEADER];
382 c_rfc.states = command->states; 454 c_rfc.msgno = command->msgno;
383 fetch_rfc822_header (&c_rfc, arg); 455 fetch_rfc822_header (&c_rfc, arg);
384 } 456 }
385 } 457 }
...@@ -388,51 +460,294 @@ fetch_rfc822 (struct imap4d_command *command, char *arg) ...@@ -388,51 +460,294 @@ fetch_rfc822 (struct imap4d_command *command, char *arg)
388 char buffer[16]; 460 char buffer[16];
389 attribute_t attr = NULL; 461 attribute_t attr = NULL;
390 message_t msg = NULL; 462 message_t msg = NULL;
391 mailbox_get_message (mbox, command->states, &msg); 463 mailbox_get_message (mbox, command->msgno, &msg);
392 message_get_attribute (msg, &attr); 464 message_get_attribute (msg, &attr);
393 attribute_set_read (attr); 465 if (!attribute_is_seen (attr) && !attribute_is_read (attr))
466 {
467 util_send ("FLAGS (\\Seen) ");
468 attribute_set_seen (attr);
469 attribute_set_read (attr);
470 }
394 util_send ("%s ", command->name); 471 util_send ("%s ", command->name);
395 strcpy (buffer, "[]"); 472 strcpy (buffer, "[]");
396 fetch_operation (command->states, buffer, 1); 473 fetch_operation (command->msgno, buffer, 1);
397 } 474 }
398 return 0; 475 return RESP_OK;
399 } 476 }
400 477
401 /* The unique identifier for the message. */ 478 /* The unique identifier for the message. */
402 static int 479 static int
403 fetch_uid (struct imap4d_command *command, char *arg) 480 fetch_uid (struct fetch_command *command, char *arg)
404 { 481 {
405 size_t uid = 0; 482 size_t uid = 0;
406 message_t msg = NULL; 483 message_t msg = NULL;
407 mailbox_get_message (mbox, command->states, &msg); 484 (void)arg;
485 mailbox_get_message (mbox, command->msgno, &msg);
408 message_get_uid (msg, &uid); 486 message_get_uid (msg, &uid);
409 util_send ("%s %d", command->name, uid); 487 util_send ("%s %d", command->name, uid);
410 return 0; 488 return RESP_OK;
411 } 489 }
412 490
413 /* FIXME: not implemeted. */
414 static int 491 static int
415 fetch_bodystructure (struct imap4d_command *command, char *arg) 492 fetch_bodystructure (struct fetch_command *command, char *arg)
416 { 493 {
417 util_send ("%s ()", command->name); 494 message_t message = NULL;
418 return 0; 495 (void)arg;
496 util_send ("%s (", command->name);
497 mailbox_get_message (mbox, command->msgno, &message);
498 fetch_bodystructure0 (message, 1);
499 util_send (")");
500 return RESP_OK;
501 }
502
503 static int
504 fetch_bodystructure0 (message_t message, int extension)
505 {
506 size_t nparts = 1;
507 size_t i;
508 int is_multipart = 0;
509 message_is_multipart (message, &is_multipart);
510 if (is_multipart)
511 {
512 message_get_num_parts (message, &nparts);
513 for (i = 1; i <= nparts; i++)
514 {
515 message_t msg = NULL;
516 message_get_part (message, i, &msg);
517 util_send ("(");
518 fetch_bodystructure0 (msg, extension);
519 util_send (")");
520 } /* for () */
521 /* The extension data for multipart. */
522 if (extension)
523 {
524 header_t header = NULL;
525 char *buffer = NULL;
526 char *sp = NULL;
527 char *s;
528 /* The subtype. */
529 message_get_header (message, &header);
530 header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
531 s = strtok_r (buffer, " \t\r\n;", &sp);
532 s = strchr (buffer, '/');
533 if (s)
534 {
535 s++;
536 util_send (" \"%s\"", s);
537 }
538 else
539 util_send (" NIL");
540 /* Content-type parameter list. */
541 util_send (" (");
542 {
543 while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
544 {
545 char *p = strchr (s, '=');
546 if (p)
547 *p++ = '\0';
548 util_send ("\"%s\"", s);
549 util_send (" \"%s\"", (p) ? p : "NIL");
550 }
551 }
552 free (buffer);
553 /* Content-Disposition. */
554 header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
555 if (*buffer)
556 {
557 util_send (" (");
558 while ((s = strtok_r (buffer, " \t\r\n;", &sp)))
559 {
560 char *p = strchr (s, '=');
561 if (p)
562 *p++ = '\0';
563 util_send ("\"%s\"", s);
564 util_send (" \"%s\"", (p) ? p : "NIL");
565 }
566 }
567 else
568 util_send (" NIL");
569 free (buffer);
570 /* Content-Language. */
571 header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
572 if (*buffer)
573 util_send (" \"%s\"", buffer);
574 else
575 util_send (" NIL");
576 } /* extension */
577 }
578 else
579 bodystructure (message, extension);
580 return RESP_OK;
581 }
582
583 static int
584 bodystructure (message_t msg, int extension)
585 {
586 header_t header = NULL;
587 char *sp = NULL;
588 char *buffer = NULL;
589 char *s;
590 size_t blines = 0;
591 int message_rfc822 = 0;
592 int text_plain = 0;
593
594 message_get_header (msg, &header);
595
596 /* MIME: */
597 header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
598 s = strtok_r (buffer, " \t\r\n;", &sp);
599 /* MIME media type and subtype */
600 if (s)
601 {
602 char *p = strchr (s, '/');
603 if (strcasecmp (s, "MESSAGE/RFC822") == 0)
604 message_rfc822 = 1;
605 if (strcasecmp (s, "TEXT/PLAIN") == 0)
606 text_plain = 1;
607 if (p)
608 *p++ = '\0';
609 util_send ("\"%s\"", s);
610 util_send (" \"%s\"", (p) ? p : "NIL");
611 }
612 else
613 {
614 /* Default? */
615 util_send ("TEXT");
616 util_send (" PLAIN");
617 }
618 /* Content-type parameter list. */
619 util_send (" (");
620 {
621 int have_charset = 0;
622 while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
623 {
624 char *p = strchr (s, '=');
625 if (p)
626 *p++ = '\0';
627 util_send ("\"%s\"", s);
628 util_send (" \"%s\"", (p) ? p : "NIL");
629 if (strcasecmp (s, "charset") == 0)
630 have_charset = 1;
631 }
632 /* Default. */
633 if (!have_charset)
634 {
635 util_send ("\"CHARSET\"");
636 util_send (" \"US-ASCII\"");
637 }
638 }
639 util_send (")");
640 free (buffer);
641
642 /* Content-ID. */
643 header_aget_value (header, MU_HEADER_CONTENT_ID, &buffer);
644 if (*buffer)
645 util_send (" \"%s\"", buffer);
646 else
647 util_send (" NIL");
648 free (buffer);
649
650 /* Content-Description. */
651 header_aget_value (header, MU_HEADER_CONTENT_DESCRIPTION, &buffer);
652 if (*buffer)
653 util_send (" \"%s\"", buffer);
654 else
655 util_send (" NIL");
656 free (buffer);
657
658 /* Content-Transfer-Encoding. */
659 header_aget_value (header, MU_HEADER_CONTENT_TRANSFER_ENCODING, &buffer);
660 util_send (" \"%s\"", (*buffer) ? buffer : "7bit");
661 free (buffer);
662
663 /* Body size RFC822 format. */
664 {
665 size_t size = 0;
666 body_t body = NULL;
667 message_get_body (msg, &body);
668 body_size (body, &size);
669 body_lines (body, &blines);
670 util_send (" %d", size + blines);
671 }
672
673 /* If the mime type was text. */
674 if (text_plain)
675 {
676 /* Add the line number of the body. */
677 util_send (" %d", blines);
678 }
679 else if (message_rfc822)
680 {
681 size_t lines = 0;
682 /* Add envelope structure */
683 util_send ("(");
684 fetch_envelope0 (msg);
685 util_send (")");
686 /* Add body structure */
687 util_send ("(");
688 bodystructure (msg, 1);
689 util_send (")");
690 /* size in text lines of the encapsulated message. */
691 message_lines (msg, &lines);
692 util_send (" %d", lines);
693 }
694
695 if (extension)
696 {
697 /* Content-MD5. */
698 header_aget_value (header, MU_HEADER_CONTENT_MD5, &buffer);
699 if (*buffer)
700 util_send (" \"%s\"", buffer);
701 else
702 util_send (" NIL");
703 free (buffer);
704 /* Content-Disposition. */
705 header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
706 if (*buffer)
707 {
708 util_send (" (");
709 while ((s = strtok_r (buffer, " \t\r\n;", &sp)))
710 {
711 char *p = strchr (s, '=');
712 if (p)
713 *p++ = '\0';
714 util_send ("\"%s\"", s);
715 util_send (" \"%s\"", (p) ? p : "NIL");
716 }
717 }
718 else
719 util_send (" NIL");
720 free (buffer);
721 /* Content-Language. */
722 header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
723 if (*buffer)
724 util_send (" \"%s\"", buffer);
725 else
726 util_send (" NIL");
727 free (buffer);
728 }
729 return RESP_OK;
419 } 730 }
420 731
421 /* An alternate form of BODY that does not implicitly set the \Seen flag. */ 732 /* An alternate form of BODY that does not implicitly set the \Seen flag. */
422 /* FIXME: send notificaton if seen attribute is set? */
423 static int 733 static int
424 fetch_body (struct imap4d_command *command, char *arg) 734 fetch_body (struct fetch_command *command, char *arg)
425 { 735 {
426 struct imap4d_command c_body_p = fetch_command_table[F_BODY_PEEK]; 736 struct fetch_command c_body_p = fetch_command_table[F_BODY_PEEK];
427 c_body_p.states = command->states; 737 c_body_p.msgno = command->msgno;
428 /* It's BODY set the message as seen */ 738 /* It's BODY set the message as seen */
429 if (*arg == '[') 739 if (*arg == '[')
430 { 740 {
431 message_t msg = NULL; 741 message_t msg = NULL;
432 attribute_t attr = NULL; 742 attribute_t attr = NULL;
433 mailbox_get_message (mbox, command->states, &msg); 743 mailbox_get_message (mbox, command->msgno, &msg);
434 message_get_attribute (msg, &attr); 744 message_get_attribute (msg, &attr);
435 attribute_set_seen (attr); 745 if (!attribute_is_seen (attr) && !attribute_is_read (attr))
746 {
747 util_send ("FLAGS (\\Seen) ");
748 attribute_set_seen (attr);
749 attribute_set_read (attr);
750 }
436 } 751 }
437 else if (strncasecmp (arg,".PEEK", 5) == 0) 752 else if (strncasecmp (arg,".PEEK", 5) == 0)
438 { 753 {
...@@ -443,22 +758,23 @@ fetch_body (struct imap4d_command *command, char *arg) ...@@ -443,22 +758,23 @@ fetch_body (struct imap4d_command *command, char *arg)
443 } 758 }
444 else if (*arg != '[' && *arg != '.') 759 else if (*arg != '[' && *arg != '.')
445 { 760 {
446 struct imap4d_command c_bs = fetch_command_table[F_BODYSTRUCTURE]; 761 message_t message = NULL;
447 c_bs.states = command->states; 762 mailbox_get_message (mbox, command->msgno, &message);
448 /* FIXME: Call body structure without the extension. */ 763 /* Call body structure without the extension. */
449 /* return fetch_bodystructure (&c_bs, arg); */ 764 util_send ("%s (", command->name);
450 util_send (" ()"); 765 fetch_bodystructure0 (message, 0);
451 return 0; 766 util_send (")");
767 return RESP_OK;
452 } 768 }
453 return fetch_body_peek (&c_body_p, arg); 769 return fetch_body_peek (&c_body_p, arg);
454 } 770 }
455 771
456 static int 772 static int
457 fetch_body_peek (struct imap4d_command *command, char *arg) 773 fetch_body_peek (struct fetch_command *command, char *arg)
458 { 774 {
459 util_send ("%s ", command->name); 775 util_send ("%s ", command->name);
460 fetch_operation (command->states, arg, 0); 776 fetch_operation (command->msgno, arg, 0);
461 return 0; 777 return RESP_OK;
462 } 778 }
463 779
464 static int 780 static int
...@@ -498,7 +814,7 @@ fetch_operation (size_t msgno, char *arg, int silent) ...@@ -498,7 +814,7 @@ fetch_operation (size_t msgno, char *arg, int silent)
498 if (status != 0) 814 if (status != 0)
499 { 815 {
500 util_send ("\"\""); 816 util_send ("\"\"");
501 return 0; 817 return RESP_OK;
502 } 818 }
503 } 819 }
504 820
...@@ -537,7 +853,7 @@ fetch_operation (size_t msgno, char *arg, int silent) ...@@ -537,7 +853,7 @@ fetch_operation (size_t msgno, char *arg, int silent)
537 } 853 }
538 else 854 else
539 util_send ("\"\""); 855 util_send ("\"\"");
540 return 0; 856 return RESP_OK;
541 } 857 }
542 858
543 static int 859 static int
...@@ -595,7 +911,7 @@ fetch_io (stream_t stream, unsigned long start, unsigned long end) ...@@ -595,7 +911,7 @@ fetch_io (stream_t stream, unsigned long start, unsigned long end)
595 if (start == ULONG_MAX) 911 if (start == ULONG_MAX)
596 { 912 {
597 start = 0; 913 start = 0;
598 util_send ("{%u}\r\n", end); 914 util_send (" {%u}\r\n", end);
599 } 915 }
600 else 916 else
601 util_send ("<%lu> {%u}\r\n", start , end); 917 util_send ("<%lu> {%u}\r\n", start , end);
...@@ -613,7 +929,7 @@ fetch_io (stream_t stream, unsigned long start, unsigned long end) ...@@ -613,7 +929,7 @@ fetch_io (stream_t stream, unsigned long start, unsigned long end)
613 } 929 }
614 util_send ("%s", buffer); 930 util_send ("%s", buffer);
615 } 931 }
616 return 0; 932 return RESP_OK;
617 } 933 }
618 934
619 static int 935 static int
...@@ -630,7 +946,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start, ...@@ -630,7 +946,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
630 946
631 status = memory_stream_create (&stream); 947 status = memory_stream_create (&stream);
632 if (status != 0) 948 if (status != 0)
633 util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */ 949 util_quit (ERR_NO_MEM);
634 950
635 /* Save the fields in an array. */ 951 /* Save the fields in an array. */
636 { 952 {
...@@ -641,7 +957,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start, ...@@ -641,7 +957,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
641 { 957 {
642 array = realloc (array, (array_len + 1) * sizeof (*array)); 958 array = realloc (array, (array_len + 1) * sizeof (*array));
643 if (!array) 959 if (!array)
644 util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */ 960 util_quit (ERR_NO_MEM);
645 array[array_len] = field; 961 array[array_len] = field;
646 } 962 }
647 } 963 }
...@@ -668,7 +984,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start, ...@@ -668,7 +984,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
668 if (status != 0) 984 if (status != 0)
669 { 985 {
670 free (array); 986 free (array);
671 util_quit (1); /* FIXME: send a "* BYE" to the client. */ 987 util_quit (ERR_NO_MEM);
672 } 988 }
673 } 989 }
674 } 990 }
...@@ -694,7 +1010,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start, ...@@ -694,7 +1010,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
694 fetch_io (stream, start, end); 1010 fetch_io (stream, start, end);
695 if (array) 1011 if (array)
696 free (array); 1012 free (array);
697 return 0; 1013 return RESP_OK;
698 } 1014 }
699 1015
700 static int 1016 static int
...@@ -711,7 +1027,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start, ...@@ -711,7 +1027,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
711 1027
712 status = memory_stream_create (&stream); 1028 status = memory_stream_create (&stream);
713 if (status) 1029 if (status)
714 util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */ 1030 util_quit (ERR_NO_MEM);
715 1031
716 /* Save the field we want to ignore. */ 1032 /* Save the field we want to ignore. */
717 { 1033 {
...@@ -722,7 +1038,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start, ...@@ -722,7 +1038,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
722 { 1038 {
723 array = realloc (array, (array_len + 1) * sizeof (*array)); 1039 array = realloc (array, (array_len + 1) * sizeof (*array));
724 if (!array) 1040 if (!array)
725 util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */ 1041 util_quit (ERR_NO_MEM);
726 array[array_len] = field; 1042 array[array_len] = field;
727 } 1043 }
728 } 1044 }
...@@ -777,7 +1093,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start, ...@@ -777,7 +1093,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
777 if (status != 0) 1093 if (status != 0)
778 { 1094 {
779 free (array); 1095 free (array);
780 util_quit (1); /* FIXME: send a "* BYE" to the client. */ 1096 util_quit (ERR_NO_MEM);
781 } 1097 }
782 } 1098 }
783 } 1099 }
...@@ -802,7 +1118,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start, ...@@ -802,7 +1118,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
802 fetch_io (stream, start, end); 1118 fetch_io (stream, start, end);
803 if (array) 1119 if (array)
804 free (array); 1120 free (array);
805 return 0; 1121 return RESP_OK;
806 } 1122 }
807 1123
808 /* FIXME: The address is limit by a buffer of 128, no good. We should 1124 /* FIXME: The address is limit by a buffer of 128, no good. We should
...@@ -816,7 +1132,7 @@ fetch_send_address (char *addr) ...@@ -816,7 +1132,7 @@ fetch_send_address (char *addr)
816 if (*addr == '\0') 1132 if (*addr == '\0')
817 { 1133 {
818 util_send ("NIL"); 1134 util_send ("NIL");
819 return 0; 1135 return RESP_OK;
820 } 1136 }
821 1137
822 address_create (&address, addr); 1138 address_create (&address, addr);
...@@ -874,5 +1190,5 @@ fetch_send_address (char *addr) ...@@ -874,5 +1190,5 @@ fetch_send_address (char *addr)
874 util_send (")"); 1190 util_send (")");
875 } 1191 }
876 util_send (")"); 1192 util_send (")");
877 return 0; 1193 return RESP_OK;
878 } 1194 }
......
...@@ -17,14 +17,13 @@ ...@@ -17,14 +17,13 @@
17 17
18 #include "imap4d.h" 18 #include "imap4d.h"
19 19
20 int *ifile;
21 FILE *ofile; 20 FILE *ofile;
22 unsigned int timeout = 1800; /* RFC2060: 30 minutes, if enable. */ 21 unsigned int timeout = 1800; /* RFC2060: 30 minutes, if enable. */
23 mailbox_t mbox; 22 mailbox_t mbox;
24 char *homedir; 23 char *homedir;
25 int state = STATE_NONAUTH; 24 int state = STATE_NONAUTH;
26 25
27 static int imap4_mainloop __P ((int, int)); 26 static int imap4d_mainloop __P ((int, int));
28 27
29 int 28 int
30 main (int argc, char **argv) 29 main (int argc, char **argv)
...@@ -39,18 +38,19 @@ main (int argc, char **argv) ...@@ -39,18 +38,19 @@ main (int argc, char **argv)
39 list_append (bookie, path_record); 38 list_append (bookie, path_record);
40 } 39 }
41 /* FIXME: Incomplete, make it work for standalone, see pop3d. */ 40 /* FIXME: Incomplete, make it work for standalone, see pop3d. */
42 imap4_mainloop (fileno (stdin), fileno (stdout)); 41 imap4d_mainloop (fileno (stdin), fileno (stdout));
43 return 0; 42 return 0;
44 } 43 }
45 44
46 static int 45 static int
47 imap4_mainloop (int infile, int outfile) 46 imap4d_mainloop (int infile, int outfile)
48 { 47 {
49 const char *remote_host = ""; 48 const char *remote_host = "";
50 49 FILE *ifile;
50 ifile = fdopen (infile, "r");
51 ofile = fdopen (outfile, "w"); 51 ofile = fdopen (outfile, "w");
52 if (ofile == NULL) 52 if (!ofile || !ifile)
53 util_quit (1); 53 util_quit (ERR_NO_OFILE);
54 54
55 /* FIXME: Retreive hostname with getpeername() and log. */ 55 /* FIXME: Retreive hostname with getpeername() and log. */
56 syslog (LOG_INFO, "Incoming connection from %s", remote_host); 56 syslog (LOG_INFO, "Incoming connection from %s", remote_host);
...@@ -61,9 +61,11 @@ imap4_mainloop (int infile, int outfile) ...@@ -61,9 +61,11 @@ imap4_mainloop (int infile, int outfile)
61 61
62 while (1) 62 while (1)
63 { 63 {
64 char *cmd = imap4d_readline (infile); 64 char *cmd = imap4d_readline (ifile);
65 /* check for updates */ 65 /* check for updates */
66 imap4d_sync ();
66 util_do_command (cmd); 67 util_do_command (cmd);
68 imap4d_sync ();
67 free (cmd); 69 free (cmd);
68 fflush (ofile); 70 fflush (ofile);
69 } 71 }
......
...@@ -99,12 +99,17 @@ struct imap4d_command ...@@ -99,12 +99,17 @@ struct imap4d_command
99 #define STATE_ALL (STATE_NONE | STATE_NONAUTH | STATE_AUTH | STATE_SEL \ 99 #define STATE_ALL (STATE_NONE | STATE_NONAUTH | STATE_AUTH | STATE_SEL \
100 | STATE_LOGOUT) 100 | STATE_LOGOUT)
101 101
102 /* Response code. */
102 #define RESP_OK 0 103 #define RESP_OK 0
103 #define RESP_BAD 1 104 #define RESP_BAD 1
104 #define RESP_NO 2 105 #define RESP_NO 2
105 #define RESP_BYE 3 106 #define RESP_BYE 3
106 #define RESP_NONE 4 107 #define RESP_NONE 4
107 108
109 /* Error values. */
110 #define ERR_NO_MEM 1
111 #define ERR_NO_OFILE 2
112
108 extern struct imap4d_command imap4d_command_table[]; 113 extern struct imap4d_command imap4d_command_table[];
109 extern FILE *ofile; 114 extern FILE *ofile;
110 extern unsigned int timeout; 115 extern unsigned int timeout;
...@@ -135,10 +140,18 @@ extern int imap4d_close __P ((struct imap4d_command *, char *)); ...@@ -135,10 +140,18 @@ extern int imap4d_close __P ((struct imap4d_command *, char *));
135 extern int imap4d_expunge __P ((struct imap4d_command *, char *)); 140 extern int imap4d_expunge __P ((struct imap4d_command *, char *));
136 extern int imap4d_search __P ((struct imap4d_command *, char *)); 141 extern int imap4d_search __P ((struct imap4d_command *, char *));
137 extern int imap4d_fetch __P ((struct imap4d_command *, char *)); 142 extern int imap4d_fetch __P ((struct imap4d_command *, char *));
143 extern int imap4d_fetch0 __P ((char *, int, char *, size_t));
138 extern int imap4d_store __P ((struct imap4d_command *, char *)); 144 extern int imap4d_store __P ((struct imap4d_command *, char *));
145 extern int imap4d_store0 __P ((char *, int, char *, size_t));
139 extern int imap4d_copy __P ((struct imap4d_command *, char *)); 146 extern int imap4d_copy __P ((struct imap4d_command *, char *));
147 extern int imap4d_copy0 __P ((char *, int, char *, size_t));
140 extern int imap4d_uid __P ((struct imap4d_command *, char *)); 148 extern int imap4d_uid __P ((struct imap4d_command *, char *));
141 149
150 /* Synchronisation on simultenous access. */
151 extern int imap4d_sync __P ((void));
152 extern int imap4d_sync_flags __P ((size_t));
153 extern size_t uid_to_msgno __P ((size_t));
154
142 /* Helper functions. */ 155 /* Helper functions. */
143 extern int util_out __P ((int, const char *, ...)); 156 extern int util_out __P ((int, const char *, ...));
144 extern int util_send __P ((const char *, ...)); 157 extern int util_send __P ((const char *, ...));
...@@ -146,14 +159,14 @@ extern int util_start __P ((char *)); ...@@ -146,14 +159,14 @@ extern int util_start __P ((char *));
146 extern int util_finish __P ((struct imap4d_command *, int, const char *, ...)); 159 extern int util_finish __P ((struct imap4d_command *, int, const char *, ...));
147 extern int util_getstate __P ((void)); 160 extern int util_getstate __P ((void));
148 extern int util_do_command __P ((char *)); 161 extern int util_do_command __P ((char *));
149 extern char *imap4d_readline __P ((int)); 162 extern char *imap4d_readline __P ((FILE*));
150 extern void util_quit __P ((int)); 163 extern void util_quit __P ((int));
151 extern char *util_getword __P ((char *, char **)); 164 extern char *util_getword __P ((char *, char **));
152 extern int util_token __P ((char *, size_t, char **)); 165 extern int util_token __P ((char *, size_t, char **));
153 extern void util_unquote __P ((char **)); 166 extern void util_unquote __P ((char **));
154 extern char *util_tilde_expansion __P ((const char *, const char *)); 167 extern char *util_tilde_expansion __P ((const char *, const char *));
155 extern char *util_getfullpath __P ((char *, const char *)); 168 extern char *util_getfullpath __P ((char *, const char *));
156 extern int util_msgset __P ((char *, int **, int *, int)); 169 extern int util_msgset __P ((char *, size_t **, int *, int));
157 extern int util_upper __P ((char *)); 170 extern int util_upper __P ((char *));
158 extern struct imap4d_command *util_getcommand __P ((char *, 171 extern struct imap4d_command *util_getcommand __P ((char *,
159 struct imap4d_command [])); 172 struct imap4d_command []));
......
...@@ -97,6 +97,7 @@ imap4d_login (struct imap4d_command *command, char *arg) ...@@ -97,6 +97,7 @@ imap4d_login (struct imap4d_command *command, char *arg)
97 return util_finish (command, RESP_NO, "Too many args"); 97 return util_finish (command, RESP_NO, "Too many args");
98 98
99 pw = getpwnam (arg); 99 pw = getpwnam (arg);
100
100 #ifndef USE_LIBPAM 101 #ifndef USE_LIBPAM
101 if (pw == NULL || pw->pw_uid < 1) 102 if (pw == NULL || pw->pw_uid < 1)
102 return util_finish (command, RESP_NO, "User name or passwd rejected"); 103 return util_finish (command, RESP_NO, "User name or passwd rejected");
...@@ -105,7 +106,7 @@ imap4d_login (struct imap4d_command *command, char *arg) ...@@ -105,7 +106,7 @@ imap4d_login (struct imap4d_command *command, char *arg)
105 #ifdef HAVE_SHADOW_H 106 #ifdef HAVE_SHADOW_H
106 struct spwd *spw; 107 struct spwd *spw;
107 spw = getspnam (arg); 108 spw = getspnam (arg);
108 if (spw == NULL || strcmp (spw->sp_pwdp, crypt (pass, spw->sp_pwdp))) 109 if (spw == NULL || strcmp (spw->sp_pwdp, (char *)crypt (pass, spw->sp_pwdp)))
109 #endif /* HAVE_SHADOW_H */ 110 #endif /* HAVE_SHADOW_H */
110 return util_finish (command, RESP_NO, "User name or passwd rejected"); 111 return util_finish (command, RESP_NO, "User name or passwd rejected");
111 } 112 }
......
...@@ -50,6 +50,8 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags) ...@@ -50,6 +50,8 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
50 { 50 {
51 mailbox_close (mbox); 51 mailbox_close (mbox);
52 mailbox_destroy (&mbox); 52 mailbox_destroy (&mbox);
53 /* Destroy the old uid table. */
54 imap4d_sync ();
53 } 55 }
54 56
55 if (strcasecmp (mailbox_name, "INBOX") == 0) 57 if (strcasecmp (mailbox_name, "INBOX") == 0)
...@@ -63,7 +65,7 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags) ...@@ -63,7 +65,7 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
63 && mailbox_open (mbox, flags) == 0) 65 && mailbox_open (mbox, flags) == 0)
64 { 66 {
65 const char *mflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft"; 67 const char *mflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
66 const char *pflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft"; 68 const char *pflags = "\\Answered \\Deleted \\Seen";
67 unsigned long uidvalidity = 0; 69 unsigned long uidvalidity = 0;
68 size_t count = 0, recent = 0, unseen = 0, uidnext = 0; 70 size_t count = 0, recent = 0, unseen = 0, uidnext = 0;
69 71
...@@ -83,10 +85,13 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags) ...@@ -83,10 +85,13 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
83 /* FIXME: 85 /* FIXME:
84 - '\*' can be supported if we use the attribute_set userflag() 86 - '\*' can be supported if we use the attribute_set userflag()
85 - Answered is still not set in the mailbox code. */ 87 - Answered is still not set in the mailbox code. */
86 util_out (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags", pflags); 88 if (flags == MU_STREAM_READ)
89 util_out (RESP_OK, "[PERMANENTFLAGS ()] No Permanent flags");
90 else
91 util_out (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags", pflags);
87 /* Need to set the state explicitely for select. */ 92 /* Need to set the state explicitely for select. */
88 state = STATE_SEL; 93 state = STATE_SEL;
89 return util_send ("%s OK [%s] %s Complete\r\n", command->tag, 94 return util_send ("%s OK [%s] %s Completed\r\n", command->tag,
90 (MU_STREAM_READ == flags) ? 95 (MU_STREAM_READ == flags) ?
91 "READ-ONLY" : "READ-WRITE", command->name); 96 "READ-ONLY" : "READ-WRITE", command->name);
92 } 97 }
......
...@@ -144,7 +144,7 @@ status_unseen (mailbox_t smbox) ...@@ -144,7 +144,7 @@ status_unseen (mailbox_t smbox)
144 attribute_t attr = NULL; 144 attribute_t attr = NULL;
145 mailbox_get_message (smbox, i, &msg); 145 mailbox_get_message (smbox, i, &msg);
146 message_get_attribute (msg, &attr); 146 message_get_attribute (msg, &attr);
147 if (!attribute_is_seen (attr)) 147 if (!attribute_is_seen (attr) && !attribute_is_read (attr))
148 unseen++; 148 unseen++;
149 } 149 }
150 util_send ("UNSEEN %d", unseen); 150 util_send ("UNSEEN %d", unseen);
......
...@@ -25,23 +25,36 @@ static int get_attribute_type __P ((const char *, int *)); ...@@ -25,23 +25,36 @@ static int get_attribute_type __P ((const char *, int *));
25 int 25 int
26 imap4d_store (struct imap4d_command *command, char *arg) 26 imap4d_store (struct imap4d_command *command, char *arg)
27 { 27 {
28 int rc;
29 char buffer[64];
30
31 if (! (command->states & state))
32 return util_finish (command, RESP_BAD, "Wrong state");
33
34 rc = imap4d_store0 (arg, 0, buffer, sizeof buffer);
35 return util_finish (command, rc, buffer);
36 }
37
38 int
39 imap4d_store0 (char *arg, int isuid, char *resp, size_t resplen)
40 {
28 char *msgset; 41 char *msgset;
29 char *data; 42 char *data;
30 char *sp = NULL; 43 char *sp = NULL;
31 int status; 44 int status;
32 int ack = 0; 45 int ack = 0;
33 size_t i, n = 0; 46 size_t i, n = 0;
34 int *set = NULL; 47 size_t *set = NULL;
35 enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how; 48 enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how;
36 49
37 if (! (command->states & state))
38 return util_finish (command, RESP_BAD, "Wrong state");
39
40 msgset = util_getword (arg, &sp); 50 msgset = util_getword (arg, &sp);
41 data = util_getword (NULL, &sp); 51 data = util_getword (NULL, &sp);
42 52
43 if (!msgset || !data || !sp || *sp == '\0') 53 if (!msgset || !data || !sp || *sp == '\0')
44 return util_finish (command, RESP_BAD, "Too few args"); 54 {
55 snprintf (resp, resplen, "Too few args");
56 return RESP_BAD;
57 }
45 58
46 /* The parsing of the data-item is a little slugish. */ 59 /* The parsing of the data-item is a little slugish. */
47 if (strcasecmp (data, "FLAGS") == 0) 60 if (strcasecmp (data, "FLAGS") == 0)
...@@ -75,12 +88,18 @@ imap4d_store (struct imap4d_command *command, char *arg) ...@@ -75,12 +88,18 @@ imap4d_store (struct imap4d_command *command, char *arg)
75 how = STORE_UNSET; 88 how = STORE_UNSET;
76 } 89 }
77 else 90 else
78 return util_finish (command, RESP_BAD, "Bogus data item"); 91 {
92 snprintf (resp, resplen, "Bogus data item");
93 return RESP_BAD;
94 }
79 95
80 /* Get the message numbers in set[]. */ 96 /* Get the message numbers in set[]. */
81 status = util_msgset (msgset, &set, &n, 0); 97 status = util_msgset (msgset, &set, &n, isuid);
82 if (status != 0) 98 if (status != 0)
83 return util_finish (command, RESP_BAD, "Bogus number set"); 99 {
100 snprintf (resp, resplen, "Bogus number set");
101 return RESP_BAD;
102 }
84 103
85 for (i = 0; i < n; i++) 104 for (i = 0; i < n; i++)
86 { 105 {
...@@ -89,8 +108,10 @@ imap4d_store (struct imap4d_command *command, char *arg) ...@@ -89,8 +108,10 @@ imap4d_store (struct imap4d_command *command, char *arg)
89 char *items = strdup (sp); /* Don't use the orignal list. */ 108 char *items = strdup (sp); /* Don't use the orignal list. */
90 char *flags = strdup (""); 109 char *flags = strdup ("");
91 int first = 1; 110 int first = 1;
111 size_t msgno;
92 112
93 mailbox_get_message (mbox, set[i], &msg); 113 msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
114 mailbox_get_message (mbox, msgno, &msg);
94 message_get_attribute (msg, &attr); 115 message_get_attribute (msg, &attr);
95 116
96 /* Get the fetch command names. */ 117 /* Get the fetch command names. */
...@@ -124,9 +145,12 @@ imap4d_store (struct imap4d_command *command, char *arg) ...@@ -124,9 +145,12 @@ imap4d_store (struct imap4d_command *command, char *arg)
124 util_out (RESP_NONE, "%d FETCH FLAGS (%s)", set[i], flags); 145 util_out (RESP_NONE, "%d FETCH FLAGS (%s)", set[i], flags);
125 free (items); 146 free (items);
126 free (flags); 147 free (flags);
148 /* Update the flags of uid table. */
149 imap4d_sync_flags (set[i]);
127 } 150 }
128 free (set); 151 free (set);
129 return util_finish (command, RESP_OK, "Completed"); 152 snprintf (resp, resplen, "Completed");
153 return RESP_OK;
130 } 154 }
131 155
132 static int 156 static int
......
1 /* GNU mailutils - a suite of utilities for electronic mail
2 Copyright (C) 1999, 2001 Free Software Foundation, Inc.
3
4 This program 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 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include "imap4d.h"
19
20 /*
21
22 */
23 struct _uid_table
24 {
25 size_t uid;
26 size_t msgno;
27 int notify;
28 attribute_t attr;
29 };
30
31 static struct _uid_table *uid_table;
32 static size_t uid_table_count;
33
34 static void
35 add_flag (char **pbuf, const char *f)
36 {
37 char *abuf = *pbuf;
38 abuf = realloc (abuf, strlen (abuf) + strlen (f) + 2);
39 if (abuf == NULL)
40 util_quit (ERR_NO_MEM);
41 if (*abuf)
42 strcat (abuf, " ");
43 strcat (abuf, "\\Seen");
44 *pbuf = abuf;
45 }
46
47 static void
48 notify_flag (size_t msgno, attribute_t oattr)
49 {
50 message_t msg = NULL;
51 attribute_t nattr = NULL;
52 int status ;
53 mailbox_get_message (mbox, msgno, &msg);
54 message_get_attribute (msg, &nattr);
55 status = attribute_is_equal (oattr, nattr);
56 //if (!attribute_is_equal (oattr, nattr))
57 if (status == 0)
58 {
59 char *abuf = malloc (1);;
60 if (!abuf)
61 util_quit (ERR_NO_MEM);
62 *abuf = '\0';
63 if (attribute_is_seen (nattr) && attribute_is_read (nattr))
64 if (!attribute_is_seen (oattr) && !attribute_is_read (oattr))
65 {
66 attribute_set_seen (oattr);
67 attribute_set_read (oattr);
68 add_flag (&abuf, "\\Seen");
69 }
70 if (attribute_is_answered (nattr))
71 if (!attribute_is_answered (oattr))
72 {
73 attribute_set_answered (oattr);
74 add_flag (&abuf, "\\Answered");
75 }
76 if (attribute_is_flagged (nattr))
77 if (!attribute_is_flagged (oattr))
78 {
79 attribute_set_flagged (oattr);
80 add_flag (&abuf, "\\Flagged");
81 }
82 if (attribute_is_deleted (nattr))
83 if (!attribute_is_deleted (oattr))
84 {
85 attribute_set_deleted (oattr);
86 add_flag (&abuf, "\\Deleted");
87 }
88 if (attribute_is_draft (nattr))
89 if (!attribute_is_draft (oattr))
90 {
91 attribute_set_draft (oattr);
92 add_flag (&abuf, "\\Draft");
93 }
94 if (attribute_is_recent (nattr))
95 if (!attribute_is_recent (oattr))
96 {
97 attribute_set_recent (oattr);
98 add_flag (&abuf, "\\Recent");
99 }
100 if (*abuf)
101 util_out (RESP_NONE, "%d FETCH FLAGS (%s)", msgno, abuf);
102 free (abuf);
103 }
104 }
105
106 static void
107 notify_deleted (void)
108 {
109 if (uid_table)
110 {
111 size_t i;
112 for (i = 0; i < uid_table_count; i++)
113 {
114 if (!(uid_table[i].notify))
115 {
116 util_out (RESP_NONE, "%d EXPUNGE", uid_table[i].msgno);
117 uid_table[i].notify = 1;
118 }
119 }
120 }
121 }
122
123
124 static int
125 notify_uid (size_t uid)
126 {
127 if (uid_table)
128 {
129 size_t i;
130 for (i = 0; i < uid_table_count; i++)
131 {
132 if (uid_table[i].uid == uid)
133 {
134 notify_flag (uid_table[i].msgno, uid_table[i].attr);
135 uid_table[i].notify = 1;
136 return 1;
137 }
138 }
139 }
140 return 0;
141 }
142
143 static void
144 notify (void)
145 {
146 if (uid_table)
147 {
148 size_t total = 0;
149 size_t i;
150 size_t recent = 0;
151 mailbox_messages_count (mbox, &total);
152 for (i = 1; i <= total; i++)
153 {
154 message_t msg = NULL;
155 size_t uid = 0;
156 mailbox_get_message (mbox, i, &msg);
157 message_get_uid (msg, &uid);
158 if (!notify_uid (uid))
159 recent++;
160 }
161 util_out (RESP_NONE, "%d EXISTS", total);
162 if (recent)
163 util_out (RESP_NONE, "%d RECENT", recent);
164 notify_deleted ();
165 }
166 }
167
168 static void
169 free_uids (void)
170 {
171 if (uid_table)
172 {
173 size_t i;
174 for (i = 0; i < uid_table_count; i++)
175 attribute_destroy (&(uid_table[i].attr), NULL);
176 free (uid_table);
177 uid_table = NULL;
178 uid_table_count = 0;
179 }
180 }
181
182 static void
183 reset_uids (void)
184 {
185 size_t total = 0;
186 size_t i;
187
188 notify ();
189 free_uids ();
190
191 mailbox_messages_count (mbox, &total);
192 for (i = 1; i <= total; i++)
193 {
194 message_t msg = NULL;
195 attribute_t attr = NULL;
196 size_t uid = 0;
197 uid_table = realloc (uid_table, sizeof (*uid_table) *
198 (uid_table_count + 1));
199 if (!uid_table)
200 util_quit (ERR_NO_MEM);
201 mailbox_get_message (mbox, i, &msg);
202 message_get_attribute (msg, &attr);
203 message_get_uid (msg, &uid);
204 uid_table[uid_table_count].uid = uid;
205 uid_table[uid_table_count].msgno = i;
206 uid_table[uid_table_count].notify = 0;
207 attribute_create (&(uid_table[uid_table_count].attr), NULL);
208 attribute_copy (uid_table[uid_table_count].attr, attr);
209 uid_table_count++;
210 }
211 }
212
213 size_t
214 uid_to_msgno (size_t uid)
215 {
216 size_t i;
217 for (i = 0; i < uid_table_count; i++)
218 if (uid_table[i].uid == uid)
219 return uid_table[i].msgno;
220 return 0;
221 }
222
223 int
224 imap4d_sync_flags (size_t msgno)
225 {
226 size_t i;
227 for (i = 0; i < uid_table_count; i++)
228 if (uid_table[i].msgno == msgno)
229 {
230 message_t msg = NULL;
231 attribute_t attr = NULL;
232 mailbox_get_message (mbox, msgno, &msg);
233 message_get_attribute (msg, &attr);
234 attribute_copy (uid_table[i].attr, attr);
235 break;
236 }
237 return 0;
238 }
239
240 int
241 imap4d_sync (void)
242 {
243 /* if mbox --> NULL, it means to free all the ressources.
244 it may be because of close or before select/examine a new mailbox. */
245 if (mbox == NULL)
246 free_uids ();
247 else if (uid_table == NULL || !mailbox_is_updated (mbox))
248 reset_uids ();
249 return 0;
250 }
...@@ -25,7 +25,33 @@ ...@@ -25,7 +25,33 @@
25 int 25 int
26 imap4d_uid (struct imap4d_command *command, char *arg) 26 imap4d_uid (struct imap4d_command *command, char *arg)
27 { 27 {
28 char *cmd;
29 char *sp = NULL;
30 int rc = RESP_NO;
31 char buffer[64];
32
28 if (! (command->states & state)) 33 if (! (command->states & state))
29 return util_finish (command, RESP_BAD, "Wrong state"); 34 return util_finish (command, RESP_BAD, "Wrong state");
30 return util_finish (command, RESP_NO, "Not supported"); 35
36 cmd = util_getword (arg, &sp);
37 if (!cmd)
38 util_finish (command, RESP_BAD, "Too few args");
39 if (strcasecmp (cmd, "FETCH") == 0)
40 {
41 rc = imap4d_fetch0 (sp, 1, buffer, sizeof buffer);
42 }
43 else if (strcasecmp (cmd, "COPY") == 0)
44 {
45 rc = imap4d_copy0 (sp, 1, buffer, sizeof buffer);
46 }
47 else if (strcasecmp (cmd, "STORE") == 0)
48 {
49 rc = imap4d_store0 (sp, 1, buffer, sizeof buffer);
50 }
51 else
52 {
53 snprintf (buffer, sizeof buffer, "Error uknown uid command");
54 rc = RESP_BAD;
55 }
56 return util_finish (command, rc, "%s %s", cmd, buffer);
31 } 57 }
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
18 #include "imap4d.h" 18 #include "imap4d.h"
19 #include <ctype.h> 19 #include <ctype.h>
20 20
21 static int add2set __P ((int **, int *, unsigned long, size_t)); 21 static int add2set __P ((size_t **, int *, unsigned long, size_t));
22 static const char *sc2string __P ((int)); 22 static const char *sc2string __P ((int));
23 23
24 /* Get the next space/CR/NL separated word, some words are between double 24 /* Get the next space/CR/NL separated word, some words are between double
...@@ -67,7 +67,8 @@ util_token (char *buf, size_t len, char **ptr) ...@@ -67,7 +67,8 @@ util_token (char *buf, size_t len, char **ptr)
67 if (**ptr == ' ' || **ptr == '.' 67 if (**ptr == ' ' || **ptr == '.'
68 || **ptr == '(' || **ptr == ')' 68 || **ptr == '(' || **ptr == ')'
69 || **ptr == '[' || **ptr == ']' 69 || **ptr == '[' || **ptr == ']'
70 || **ptr == '<' || **ptr == '>') 70 || **ptr == '<' || **ptr == '>'
71 || **ptr == '\r' || **ptr == '\n')
71 { 72 {
72 /* Advance. */ 73 /* Advance. */
73 if (start == (*ptr)) 74 if (start == (*ptr))
...@@ -172,7 +173,7 @@ util_getfullpath (char *name, const char *delim) ...@@ -172,7 +173,7 @@ util_getfullpath (char *name, const char *delim)
172 FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10> 173 FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10>
173 will not generate an error. */ 174 will not generate an error. */
174 int 175 int
175 util_msgset (char *s, int **set, int *n, int isuid) 176 util_msgset (char *s, size_t **set, int *n, int isuid)
176 { 177 {
177 unsigned long val = 0; 178 unsigned long val = 0;
178 unsigned long low = 0; 179 unsigned long low = 0;
...@@ -340,93 +341,79 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...) ...@@ -340,93 +341,79 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
340 return status; 341 return status;
341 } 342 }
342 343
343 #if 0 344 /* Clients are allowed to send literal string to the servers. this
344 /* Need a replacement for readline that can support literals. */ 345 mean that it can me everywhere where a string is allowed.
346 A literal is a sequence of zero or more octets (including CR and LF)
347 prefix-quoted with an octet count in the form of an open brace ("{"),
348 the number of octets, close brace ("}"), and CRLF.
349 */
345 char * 350 char *
346 imap4d_readline (FILE *fp) 351 imap4d_readline (FILE *fp)
347 { 352 {
348 char buffer[512]; 353 char buffer[512];
349 char *line;
350 size_t len; 354 size_t len;
355 long number = 0;
356 size_t total = 0;
357 char *line = malloc (1);
351 358
352 alarm (timeout);
353 line = fgets (buffer, sizeof (buffer), fp);
354 alarm (0);
355 if (!line) 359 if (!line)
356 util_quit (1); 360 util_quit (ERR_NO_MEM);
357 line = strdup (buffer); 361
358 len = strlen (buffer); 362 line[0] = '\0'; /* start with a empty string. */
359 if (len > 2) 363 do
360 { 364 {
361 len--; /* C arrays are 0-based. */ 365 alarm (timeout);
362 if (line[len] == '\n' && line[len - 1] == '}') 366 if (fgets (buffer, sizeof (buffer), fp) == NULL)
367 util_quit (0); /* Logout. */
368 alarm (0);
369
370 len = strlen (buffer);
371 /* If we were in a litteral substract. We have to do it since the CR
372 is part of the count in a literal. */
373 if (number)
374 number -= len;
375
376 /* Remove CR. */
377 if (len > 2 && buffer[len - 1] == '\n')
363 { 378 {
364 while (len && line[len] != '{') len--; 379 if (buffer[len - 2] == '\r')
365 if (line [len] == '{')
366 { 380 {
367 char *sp = NULL; 381 buffer[len - 2] = '\n';
368 long number = strtoul (line + len + 1, &sp, 10); 382 buffer[len - 1] = '\0';
369 if (*sp != '+')
370 util_send ("+ GO AHEAD\r\n");
371 line[len] = '\0';
372 while (number > 0)
373 {
374 char *literal = imap4d_readline (fd);
375 size_t n = strlen (literal);
376 line = realloc (line, strlen (line) + n + 1);
377 strcat (line, literal);
378 number -= n;
379 free (literal);
380 }
381 } 383 }
382 } 384 }
383 }
384 return line;
385 }
386 #endif
387 385
388 char * 386 line = realloc (line, total + len + 1);
389 imap4d_readline (int fd) 387 if (!line)
390 { 388 util_quit (ERR_NO_MEM);
391 fd_set rfds; 389 strcat (line, buffer);
392 struct timeval tv;
393 char buf[512], *ret = NULL;
394 int nread;
395 int total = 0;
396 int available;
397
398 FD_ZERO (&rfds);
399 FD_SET (fd, &rfds);
400 tv.tv_sec = timeout;
401 tv.tv_usec = 0;
402 390
403 do 391 total = strlen (line);
404 {
405 if (timeout)
406 {
407 available = select (fd + 1, &rfds, NULL, NULL, &tv);
408 if (!available)
409 util_quit (1);
410 }
411 nread = read (fd, buf, sizeof (buf) - 1);
412 if (nread < 1)
413 util_quit (1);
414 392
415 buf[nread] = '\0'; 393 /* Check if the client try to send a literal and we are not already
416 394 retrieving a litera. */
417 ret = realloc (ret, (total + nread + 1) * sizeof (char)); 395 if (number <= 0 && len > 2)
418 if (ret == NULL) 396 {
419 util_quit (1); 397 size_t n = total - 1; /* C arrays are 0-based. */
420 memcpy (ret + total, buf, nread + 1); 398 if (line[n] == '\n' && line[n - 1] == '}')
421 total += nread; 399 {
400 while (n && line[n] != '{') n--;
401 if (line [n] == '{')
402 {
403 char *sp = NULL;
404 /* Truncate where the literal number was. */
405 line[n] = '\0';
406 number = strtoul (line + n + 1, &sp, 10);
407 /* Client can ask for non synchronise literal,
408 if a '+' is append to the octet count. */
409 if (*sp != '+')
410 util_send ("+ GO AHEAD\r\n");
411 }
412 }
413 }
422 } 414 }
423 while (memchr (buf, '\n', nread) == NULL); 415 while (number > 0);
424 416 return line;
425 /* Nuke CR'\r' */
426 for (nread = total; nread > 0; nread--)
427 if (ret[nread] == '\r' || ret[nread] == '\n')
428 ret[nread] = '\0';
429 return ret;
430 } 417 }
431 418
432 int 419 int
...@@ -435,6 +422,7 @@ util_do_command (char *prompt) ...@@ -435,6 +422,7 @@ util_do_command (char *prompt)
435 char *sp = NULL, *tag, *cmd; 422 char *sp = NULL, *tag, *cmd;
436 struct imap4d_command *command; 423 struct imap4d_command *command;
437 static struct imap4d_command nullcommand; 424 static struct imap4d_command nullcommand;
425 size_t len;
438 426
439 tag = util_getword (prompt, &sp); 427 tag = util_getword (prompt, &sp);
440 cmd = util_getword (NULL, &sp); 428 cmd = util_getword (NULL, &sp);
...@@ -462,6 +450,9 @@ util_do_command (char *prompt) ...@@ -462,6 +450,9 @@ util_do_command (char *prompt)
462 } 450 }
463 451
464 command->tag = tag; 452 command->tag = tag;
453 len = strlen (sp);
454 if (len && sp[len - 1] == '\n')
455 sp[len - 1] = '\0';
465 return command->func (command, sp); 456 return command->func (command, sp);
466 } 457 }
467 458
...@@ -487,8 +478,17 @@ util_start (char *tag) ...@@ -487,8 +478,17 @@ util_start (char *tag)
487 void 478 void
488 util_quit (int err) 479 util_quit (int err)
489 { 480 {
490 if (err) 481 switch (err)
491 util_out (RESP_BYE, "Server terminating"); 482 {
483 case ERR_NO_OFILE:
484 /*util_out (RESP_BYE, "Server terminating dead socket."); */
485 break;
486 case ERR_NO_MEM:
487 util_out (RESP_BYE, "Server terminating no more ressources.");
488 break;
489 default:
490 util_out (RESP_BYE, "Server terminating");
491 }
492 exit (err); 492 exit (err);
493 } 493 }
494 494
...@@ -535,7 +535,7 @@ sc2string (int rc) ...@@ -535,7 +535,7 @@ sc2string (int rc)
535 } 535 }
536 536
537 static int 537 static int
538 add2set (int **set, int *n, unsigned long val, size_t max) 538 add2set (size_t **set, int *n, unsigned long val, size_t max)
539 { 539 {
540 int *tmp; 540 int *tmp;
541 if (val == 0 || val > max 541 if (val == 0 || val > max
......
...@@ -34,39 +34,43 @@ ...@@ -34,39 +34,43 @@
34 extern "C" { 34 extern "C" {
35 #endif 35 #endif
36 36
37 #define MU_HEADER_UNIX_FROM "From " 37 #define MU_HEADER_UNIX_FROM "From "
38 #define MU_HEADER_RETURN_PATH "Return-Path" 38 #define MU_HEADER_RETURN_PATH "Return-Path"
39 #define MU_HEADER_RECEIVED "Received" 39 #define MU_HEADER_RECEIVED "Received"
40 #define MU_HEADER_DATE "Date" 40 #define MU_HEADER_DATE "Date"
41 #define MU_HEADER_FROM "From" 41 #define MU_HEADER_FROM "From"
42 #define MU_HEADER_SENDER "Sender" 42 #define MU_HEADER_SENDER "Sender"
43 #define MU_HEADER_RESENT_FROM "Resent-From" 43 #define MU_HEADER_RESENT_FROM "Resent-From"
44 #define MU_HEADER_SUBJECT "Subject" 44 #define MU_HEADER_SUBJECT "Subject"
45 #define MU_HEADER_SENDER "Sender" 45 #define MU_HEADER_SENDER "Sender"
46 #define MU_HEADER_RESENT_SENDER "Resent-SENDER" 46 #define MU_HEADER_RESENT_SENDER "Resent-SENDER"
47 #define MU_HEADER_TO "To" 47 #define MU_HEADER_TO "To"
48 #define MU_HEADER_RESENT_TO "Resent-To" 48 #define MU_HEADER_RESENT_TO "Resent-To"
49 #define MU_HEADER_CC "Cc" 49 #define MU_HEADER_CC "Cc"
50 #define MU_HEADER_RESENT_CC "Resent-Cc" 50 #define MU_HEADER_RESENT_CC "Resent-Cc"
51 #define MU_HEADER_BCC "Bcc" 51 #define MU_HEADER_BCC "Bcc"
52 #define MU_HEADER_RESENT_BCC "Resent-Bcc" 52 #define MU_HEADER_RESENT_BCC "Resent-Bcc"
53 #define MU_HEADER_REPLY_TO "Reply-To" 53 #define MU_HEADER_REPLY_TO "Reply-To"
54 #define MU_HEADER_RESENT_REPLY_TO "Resent-Reply-To" 54 #define MU_HEADER_RESENT_REPLY_TO "Resent-Reply-To"
55 #define MU_HEADER_MESSAGE_ID "Message-ID" 55 #define MU_HEADER_MESSAGE_ID "Message-ID"
56 #define MU_HEADER_RESENT_MESSAGE_ID "Resent-Message-ID" 56 #define MU_HEADER_RESENT_MESSAGE_ID "Resent-Message-ID"
57 #define MU_HEADER_IN_REPLY_TO "In-Reply-To" 57 #define MU_HEADER_IN_REPLY_TO "In-Reply-To"
58 #define MU_HEADER_REFERENCE "Reference" 58 #define MU_HEADER_REFERENCE "Reference"
59 #define MU_HEADER_ENCRYPTED "Encrypted" 59 #define MU_HEADER_ENCRYPTED "Encrypted"
60 #define MU_HEADER_PRECEDENCE "Precedence" 60 #define MU_HEADER_PRECEDENCE "Precedence"
61 #define MU_HEADER_STATUS "Status" 61 #define MU_HEADER_STATUS "Status"
62 #define MU_HEADER_CONTENT_LENGTH "Content-Length" 62 #define MU_HEADER_CONTENT_LENGTH "Content-Length"
63 #define MU_HEADER_CONTENT_LANGUAGE "Content-Language" 63 #define MU_HEADER_CONTENT_LANGUAGE "Content-Language"
64 #define MU_HEADER_CONTENT_ENCODING "Content-transfer-encoding" 64 #define MU_HEADER_CONTENT_TRANSFER_ENCODING "Content-transfer-encoding"
65 #define MU_HEADER_CONTENT_TYPE "Content-Type" 65 #define MU_HEADER_CONTENT_ID "Content-ID"
66 #define MU_HEADER_MIME_VERSION "MIME-Version" 66 #define MU_HEADER_CONTENT_TYPE "Content-Type"
67 #define MU_HEADER_X_UIDL "X-UIDL" 67 #define MU_HEADER_CONTENT_DESCRIPTION "Content-Description"
68 #define MU_HEADER_X_UID "X-UID" 68 #define MU_HEADER_CONTENT_DISPOSITION "Content-Disposition"
69 #define MU_HEADER_X_IMAPBASE "X-IMAPbase" 69 #define MU_HEADER_CONTENT_MD5 "Content-MD5"
70 #define MU_HEADER_MIME_VERSION "MIME-Version"
71 #define MU_HEADER_X_UIDL "X-UIDL"
72 #define MU_HEADER_X_UID "X-UID"
73 #define MU_HEADER_X_IMAPBASE "X-IMAPbase"
70 74
71 /* Mime support header attribute */ 75 /* Mime support header attribute */
72 76
......
...@@ -78,6 +78,7 @@ extern int parse822_address __P ((const char** p, const char* e, address_ ...@@ -78,6 +78,7 @@ extern int parse822_address __P ((const char** p, const char* e, address_
78 extern int parse822_route_addr __P ((const char** p, const char* e, address_t* a)); 78 extern int parse822_route_addr __P ((const char** p, const char* e, address_t* a));
79 extern int parse822_route __P ((const char** p, const char* e, char** route)); 79 extern int parse822_route __P ((const char** p, const char* e, char** route));
80 extern int parse822_addr_spec __P ((const char** p, const char* e, address_t* a)); 80 extern int parse822_addr_spec __P ((const char** p, const char* e, address_t* a));
81 extern int parse822_unix_mbox __P ((const char** p, const char* e, address_t* a));
81 extern int parse822_local_part __P ((const char** p, const char* e, char** local_part)); 82 extern int parse822_local_part __P ((const char** p, const char* e, char** local_part));
82 extern int parse822_domain __P ((const char** p, const char* e, char** domain)); 83 extern int parse822_domain __P ((const char** p, const char* e, char** domain));
83 extern int parse822_sub_domain __P ((const char** p, const char* e, char** sub_domain)); 84 extern int parse822_sub_domain __P ((const char** p, const char* e, char** sub_domain));
......
...@@ -441,7 +441,9 @@ attribute_copy (attribute_t dest, attribute_t src) ...@@ -441,7 +441,9 @@ attribute_copy (attribute_t dest, attribute_t src)
441 { 441 {
442 if (dest == NULL || src == NULL) 442 if (dest == NULL || src == NULL)
443 return EINVAL; 443 return EINVAL;
444 memcpy (dest, src, sizeof (*dest)); 444 /* Can not be a deep copy. */
445 /* memcpy (dest, src, sizeof (*dest)); */
446 dest->flags = src->flags;
445 return 0; 447 return 0;
446 } 448 }
447 449
......
...@@ -55,6 +55,13 @@ _file_read (stream_t stream, char *optr, size_t osize, ...@@ -55,6 +55,13 @@ _file_read (stream_t stream, char *optr, size_t osize,
55 size_t n; 55 size_t n;
56 int err = 0; 56 int err = 0;
57 57
58 if (!fs->file)
59 {
60 if (nbytes)
61 *nbytes = 0;
62 return 0;
63 }
64
58 if (fs->offset != offset) 65 if (fs->offset != offset)
59 { 66 {
60 if (fseek (fs->file, offset, SEEK_SET) != 0) 67 if (fseek (fs->file, offset, SEEK_SET) != 0)
...@@ -84,6 +91,13 @@ _file_readline (stream_t stream, char *optr, size_t osize, ...@@ -84,6 +91,13 @@ _file_readline (stream_t stream, char *optr, size_t osize,
84 size_t n = 0; 91 size_t n = 0;
85 int err = 0; 92 int err = 0;
86 93
94 if (!fs->file)
95 {
96 if (nbytes)
97 *nbytes = 0;
98 return 0;
99 }
100
87 if (fs->offset != offset) 101 if (fs->offset != offset)
88 { 102 {
89 if (fseek (fs->file, offset, SEEK_SET) != 0) 103 if (fseek (fs->file, offset, SEEK_SET) != 0)
...@@ -117,6 +131,13 @@ _file_write (stream_t stream, const char *iptr, size_t isize, ...@@ -117,6 +131,13 @@ _file_write (stream_t stream, const char *iptr, size_t isize,
117 size_t n; 131 size_t n;
118 int err = 0; 132 int err = 0;
119 133
134 if (!fs->file)
135 {
136 if (nbytes)
137 *nbytes = 0;
138 return 0;
139 }
140
120 if (fs->offset != offset) 141 if (fs->offset != offset)
121 { 142 {
122 if (fseek (fs->file, offset, SEEK_SET) != 0) 143 if (fseek (fs->file, offset, SEEK_SET) != 0)
...@@ -144,7 +165,7 @@ static int ...@@ -144,7 +165,7 @@ static int
144 _file_truncate (stream_t stream, off_t len) 165 _file_truncate (stream_t stream, off_t len)
145 { 166 {
146 struct _file_stream *fs = stream_get_owner (stream); 167 struct _file_stream *fs = stream_get_owner (stream);
147 if (ftruncate (fileno(fs->file), len) != 0) 168 if (fs->file && ftruncate (fileno(fs->file), len) != 0)
148 return errno; 169 return errno;
149 return 0; 170 return 0;
150 } 171 }
...@@ -154,6 +175,12 @@ _file_size (stream_t stream, off_t *psize) ...@@ -154,6 +175,12 @@ _file_size (stream_t stream, off_t *psize)
154 { 175 {
155 struct _file_stream *fs = stream_get_owner (stream); 176 struct _file_stream *fs = stream_get_owner (stream);
156 struct stat stbuf; 177 struct stat stbuf;
178 if (!fs->file)
179 {
180 if (psize)
181 *psize = 0;
182 return 0;
183 }
157 fflush (fs->file); 184 fflush (fs->file);
158 if (fstat(fileno(fs->file), &stbuf) == -1) 185 if (fstat(fileno(fs->file), &stbuf) == -1)
159 return errno; 186 return errno;
...@@ -166,16 +193,24 @@ static int ...@@ -166,16 +193,24 @@ static int
166 _file_flush (stream_t stream) 193 _file_flush (stream_t stream)
167 { 194 {
168 struct _file_stream *fs = stream_get_owner (stream); 195 struct _file_stream *fs = stream_get_owner (stream);
169 return fflush (fs->file); 196 if (fs->file)
197 return fflush (fs->file);
198 return 0;
170 } 199 }
171 200
172 static int 201 static int
173 _file_get_fd (stream_t stream, int *pfd) 202 _file_get_fd (stream_t stream, int *pfd)
174 { 203 {
175 struct _file_stream *fs = stream_get_owner (stream); 204 struct _file_stream *fs = stream_get_owner (stream);
205 int status = 0;
176 if (pfd) 206 if (pfd)
177 *pfd = fileno (fs->file); 207 {
178 return 0; 208 if (fs->file)
209 *pfd = fileno (fs->file);
210 else
211 status = EINVAL;
212 }
213 return status;
179 } 214 }
180 215
181 static int 216 static int
......
...@@ -261,7 +261,7 @@ int ...@@ -261,7 +261,7 @@ int
261 mailbox_is_updated (mailbox_t mbox) 261 mailbox_is_updated (mailbox_t mbox)
262 { 262 {
263 if (mbox == NULL || mbox->_is_updated == NULL) 263 if (mbox == NULL || mbox->_is_updated == NULL)
264 return ENOSYS; 264 return 1;
265 return mbox->_is_updated (mbox); 265 return mbox->_is_updated (mbox);
266 } 266 }
267 267
......
...@@ -18,20 +18,9 @@ ...@@ -18,20 +18,9 @@
18 /* 18 /*
19 Things to consider: 19 Things to consider:
20 20
21 - A group should create an address node for a group, accessable
22 with address_get_personal(). Perhaps an is_group() would be
23 useful? Test that a zero-length phrase is rejected! So these
24 are invalid:
25 : a@b ;
26 "" : ;
27
28 - When parsing phrase, should I ignore non-ascii, or replace with a 21 - When parsing phrase, should I ignore non-ascii, or replace with a
29 '?' character? Right now parsing fails. 22 '?' character? Right now parsing fails.
30 23
31 - Make domain optional in addr-spec, for parsing address lists
32 provided to local mail utilities, but NOT in the addr-spec of a
33 route-addr.
34
35 - Are comments allowed in domain-literals? 24 - Are comments allowed in domain-literals?
36 25
37 - Need a way to mark the *end* of a group. Maybe add a field to _address, 26 - Need a way to mark the *end* of a group. Maybe add a field to _address,
...@@ -53,14 +42,12 @@ Things to consider: ...@@ -53,14 +42,12 @@ Things to consider:
53 gets one address, or just say it is or it isn't in RFC format? 42 gets one address, or just say it is or it isn't in RFC format?
54 Right now we're strict, we'll see how it goes. 43 Right now we're strict, we'll see how it goes.
55 44
56 - parse field names and bodies?
57 - parse dates? 45 - parse dates?
58 - parse Received: field? 46 - parse Received: field?
59 47
60 - test for memory leaks on malloc failure 48 - test for memory leaks on malloc failure
61 - fix the realloc, try a struct _string { char* b, size_t sz }; 49 - fix the realloc, try a struct _string { char* b, size_t sz };
62 50 - get example addresses from rfc2822, and from the perl code.
63 - get example mail from drums, and from the perl code.
64 */ 51 */
65 52
66 #ifdef HAVE_CONFIG_H 53 #ifdef HAVE_CONFIG_H
...@@ -610,12 +597,15 @@ int parse822_address_list(address_t* a, const char* s) ...@@ -610,12 +597,15 @@ int parse822_address_list(address_t* a, const char* s)
610 597
611 int parse822_address(const char** p, const char* e, address_t* a) 598 int parse822_address(const char** p, const char* e, address_t* a)
612 { 599 {
613 /* address = mailbox / group */ 600 /* address = mailbox / group / unix-mbox */
614 601
615 int rc; 602 int rc;
616 603
617 if((rc = parse822_mail_box(p, e, a)) == EPARSE) 604 if((rc = parse822_mail_box(p, e, a)) == EPARSE) {
618 rc = parse822_group(p, e, a); 605 if((rc = parse822_group(p, e, a)) == EPARSE) {
606 rc = parse822_unix_mbox(p, e, a);
607 }
608 }
619 609
620 return rc; 610 return rc;
621 } 611 }
...@@ -690,7 +680,9 @@ int parse822_group(const char** p, const char* e, address_t* a) ...@@ -690,7 +680,9 @@ int parse822_group(const char** p, const char* e, address_t* a)
690 680
691 int parse822_mail_box(const char** p, const char* e, address_t* a) 681 int parse822_mail_box(const char** p, const char* e, address_t* a)
692 { 682 {
693 /* mailbox = addr-spec [ "(" comment ")" ] / [phrase] route-addr 683 /* mailbox =
684 * addr-spec [ "(" comment ")" ] /
685 * [phrase] route-addr
694 * 686 *
695 * Note: we parse the ancient comment on the right since 687 * Note: we parse the ancient comment on the right since
696 * it's such "common practice". :-( 688 * it's such "common practice". :-(
...@@ -717,10 +709,6 @@ int parse822_mail_box(const char** p, const char* e, address_t* a) ...@@ -717,10 +709,6 @@ int parse822_mail_box(const char** p, const char* e, address_t* a)
717 709
718 return rc; 710 return rc;
719 } 711 }
720 if(rc != EPARSE) {
721 *p = save;
722 return rc;
723 }
724 712
725 /* -> phrase route-addr */ 713 /* -> phrase route-addr */
726 { 714 {
...@@ -732,17 +720,23 @@ int parse822_mail_box(const char** p, const char* e, address_t* a) ...@@ -732,17 +720,23 @@ int parse822_mail_box(const char** p, const char* e, address_t* a)
732 return rc; 720 return rc;
733 } 721 }
734 722
735 if((rc = parse822_route_addr(p, e, a))) { 723 if((rc = parse822_route_addr(p, e, a)) == EOK) {
724 /* add the phrase */
725 (*a)->personal = phrase;
726
727 return EOK;
728 } else if(rc != EPARSE) {
729 /* some internal error, fail out */
736 *p = save; 730 *p = save;
737 str_free(&phrase); 731 str_free(&phrase);
738 return rc; 732 return rc;
739 } 733 }
734 *p = save;
740 735
741 /* add the phrase */ 736 return rc;
742 (*a)->personal = phrase;
743 } 737 }
744 738
745 return EOK; 739 return rc;
746 } 740 }
747 741
748 int parse822_route_addr(const char** p, const char* e, address_t* a) 742 int parse822_route_addr(const char** p, const char* e, address_t* a)
...@@ -874,6 +868,29 @@ int parse822_addr_spec(const char** p, const char* e, address_t* a) ...@@ -874,6 +868,29 @@ int parse822_addr_spec(const char** p, const char* e, address_t* a)
874 return rc; 868 return rc;
875 } 869 }
876 870
871 int parse822_unix_mbox(const char** p, const char* e, address_t* a)
872 {
873 /* unix-mbox = atom */
874
875 const char* save = *p;
876 char* mbox = 0;
877 int rc;
878
879 parse822_skip_comments(p, e);
880
881 rc = parse822_atom(p, e, &mbox);
882
883 if(!rc) {
884 rc = fill_mb(a, 0, 0, mbox, 0);
885 }
886
887 if(rc) {
888 *p = save;
889 str_free(&mbox);
890 }
891 return rc;
892 }
893
877 int parse822_local_part(const char** p, const char* e, char** local_part) 894 int parse822_local_part(const char** p, const char* e, char** local_part)
878 { 895 {
879 /* local-part = word *("." word) 896 /* local-part = word *("." word)
......