Implemented UID fetch BODYSTRUCTURE and multiple access to mailbox via IMAP
Showing
22 changed files
with
674 additions
and
250 deletions
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 | ... | ... |
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 | } | ... | ... |
This diff is collapsed.
Click to expand it.
... | @@ -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 | ... | ... |
imap4d/sync.c
0 → 100644
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) | ... | ... |
-
Please register or sign in to post a comment