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 }
......
...@@ -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)
......