diff options
author | Alain Magloire <alainm@gnu.org> | 2001-05-07 04:36:40 +0000 |
---|---|---|
committer | Alain Magloire <alainm@gnu.org> | 2001-05-07 04:36:40 +0000 |
commit | 43ba0c68726d41135916aaaf9f4dfffdb56af872 (patch) | |
tree | b629eebf2462a65f3481a8f344a8ebcdf7c55ef3 | |
parent | 33825193d58de51f0d9fbe261180159d1f623d8f (diff) | |
download | mailutils-43ba0c68726d41135916aaaf9f4dfffdb56af872.tar.gz mailutils-43ba0c68726d41135916aaaf9f4dfffdb56af872.tar.bz2 |
Implemented UID fetch BODYSTRUCTURE and multiple access to mailbox via IMAP
-rw-r--r-- | ChangeLog | 44 | ||||
-rw-r--r-- | doc/Makefile.am | 3 | ||||
-rw-r--r-- | doc/address.texi | 73 | ||||
-rw-r--r-- | examples/Addrs.good | 24 | ||||
-rw-r--r-- | examples/addr.c | 10 | ||||
-rw-r--r-- | imap4d/copy.c | 54 | ||||
-rw-r--r-- | imap4d/fetch.c | 626 | ||||
-rw-r--r-- | imap4d/imap4d.c | 18 | ||||
-rw-r--r-- | imap4d/imap4d.h | 17 | ||||
-rw-r--r-- | imap4d/login.c | 3 | ||||
-rw-r--r-- | imap4d/select.c | 11 | ||||
-rw-r--r-- | imap4d/status.c | 2 | ||||
-rw-r--r-- | imap4d/store.c | 44 | ||||
-rw-r--r-- | imap4d/sync.c | 250 | ||||
-rw-r--r-- | imap4d/uid.c | 28 | ||||
-rw-r--r-- | imap4d/util.c | 154 | ||||
-rw-r--r-- | include/mailutils/header.h | 70 | ||||
-rw-r--r-- | include/mailutils/parse822.h | 1 | ||||
-rw-r--r-- | mailbox/attribute.c | 4 | ||||
-rw-r--r-- | mailbox/file_stream.c | 43 | ||||
-rw-r--r-- | mailbox/mailbox.c | 2 | ||||
-rw-r--r-- | mailbox/parse822.c | 69 |
22 files changed, 1145 insertions, 405 deletions
@@ -1,3 +1,47 @@ +2001-05-07 Alain Magloire + + Now we can have multiple access to the mailbox and the server + will update the mailbox and send the unsollicited responses. + This is implemented in imap4d/sync.c. + + * imap4d/copy.c: Move the code into imap4d_copy0() to allow + the use of UID COPY. + (imaprd_copy0): New function. + * imap4d/fetch.c: Define a new structure command for FETCH. + (fetch_getcommand): New function. + (imap4d_fetch0): New function to allow the use of UID COPY. + (fetch_envelope0): New function to permit to reuse the function + in bodystructure. + (fetch_bodystructure): Implemented. + (fetch_bodystructure0): The implementation. + (bodystructure): The helper function for fetch_bodystructure. + * imap4d/imap4d.c (imap4d_mainloop): call imap4d_sync() in the + mainloop. Now use FILE *ifile. + * imap4d/imap4d.h: Update prototypes. Define ERR_NO_MEM and + ERR_NO_OFILE. + * imap4d/select.c (imap4d_select0): Call imap4d_sync() to update. + * imap4d/store.c (ima4d_store): Cal imap4d_sync_flags() to + update the flags in the uid_table. + * imap4d/uid.c: Implemented. + * imap4d/util.c (imap4d_readline): Use fgets() and deal + with literals send from the client. + * imap4d/sync.c: New file. + + * include/mailutils/header.c: Added some new headers. + * mailbox/attribute.c (attribute_copy): Do a shalow copy. + * mailbox/file_stream.c: Check if FILE * is null in all functions. + * mailbox/mailbox.c (mailbox_is_updated): Should not return ENOSYS + but rather 1. + +2001-05-07 Sam Roberts + + * mailbox/parse822.c: Now allow a unix mailbox in an address. + * include/mailutils/parse822.h: Declare the function to parse them. + * doc/address.texi: Document the fact. + * doc/Makefile.am: Automatically build the example code from addr.c. + * examples/addr.c: And update the parser test. + * examples/Addrs.good: Update the parser test. + 2001-05-03 Sam Roberts * mail/mail.c: Typo diff --git a/doc/Makefile.am b/doc/Makefile.am index 92aca963d..0607918ff 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -23,3 +23,6 @@ EXTRA_DIST = \ url.texi \ version.texi +ex-address.texi: ../examples/addr.c + sed -es/{/@{/g -e s/}/@}/g < $< > $@ + diff --git a/doc/address.texi b/doc/address.texi index 2a5b8398b..23ec93ee7 100644 --- a/doc/address.texi +++ b/doc/address.texi @@ -1,9 +1,9 @@ -@code{#include <mailutils/mailbox.h>} +@code{#include <mailutils/address.h>} -The internet address format is defined in RFC 822. RFC 822 is in the -process of being updated, and will soon be superceeded by a new RFC -that makes some corrections and clarifications. References to RFC 822 -here apply equally to the new RFC. +The internet address format is defined in RFC 822. RFC 822 has been +updated, and is now superceeded by RFC 2822, which +makes some corrections and clarifications. References to RFC 822 +here apply equally to RFC 2822. The RFC 822 format is more flexible than many people realize, here is a quick summary of the syntax this parser implements, see @@ -16,10 +16,15 @@ mailbox = addr-spec ["(" display-name ")"] / [display-name] "<" [route] addr-spec ">" mailbox-list = mailbox ["," mailbox-list] group = display-name ":" [mailbox-list] ";" -address = mailbox / group +address = mailbox / group / unix-mbox address-list = address ["," address-list] @end example +unix-mbox is a non-standard extention meant to deal with the common +practice of using user names as addresses in mail utilities. It allows +addresses such as "root" to be parsed correctly. These are NOT valid +internet email addresses, they must be qualified before use. + Several address functions have a set of common arguments with consistent semantics, these are described here to avoid repetition. @@ -133,7 +138,8 @@ The return value is @code{0} on success and a code number on error conditions: @deftypefun int address_get_email (address_t *@var{addr}, size_t @var{no}, char* @var{buf}, size_t @var{len}, size_t* @var{n}) Acesses the email addr-spec extracted while -parsing the @var{no}th email address. +parsing the @var{no}th email address. This will be @code{0} +length for a unix-mbox. The return value is @code{0} on success and a code number on error conditions: @table @code @@ -157,7 +163,8 @@ The return value is @code{0} on success and a code number on error conditions: @deftypefun int address_get_domain (address_t *@var{addr}, size_t @var{no}, char* @var{buf}, size_t @var{len}, size_t* @var{n}) Acesses the domain of an email addr-spec extracted while -parsing the @var{no}th email address. +parsing the @var{no}th email address. This will be @code{0} +length for a unix-mbox. The return value is @code{0} on success and a code number on error conditions: @table @code @@ -223,54 +230,6 @@ The return value is @code{0}. @section Example @example -#include <stdio.h> -#include <mailutils/address.h> - -int -main(int argc, const char *argv[]) -@{ - for(argc = 1; argv[argc]; argc++) - @{ - const char* str = argv[argc]; - address_t address = NULL; - - address_create(&address, str); - - printf("'%s' ->\n", str); - @{ - size_t no = 0; - size_t pcount; - - address_get_count(address, &pcount); - - printf(" pcount %d\n", pcount); - - for(no = 1; no <= pcount; no++) - @{ - char buf[BUFSIZ]; - - address_get_personal(address, no, buf, sizeof(buf), 0); - - printf(" personal '%s'\n", buf); - - address_get_local_part(address, no, buf, sizeof(buf), 0); - - printf(" local_part '%s'\n", buf); - - address_get_domain(address, no, buf, sizeof(buf), 0); - - printf(" domain '%s'\n", buf); - - address_get_email(address, no, buf, sizeof(buf), 0); - - printf(" email '%s'\n", buf); - @} - @} - - address_destroy(&address); - @} - - return 0; -@} +@include ex-address.texi @end example diff --git a/examples/Addrs.good b/examples/Addrs.good index e15b45e42..17536398e 100644 --- a/examples/Addrs.good +++ b/examples/Addrs.good @@ -228,7 +228,7 @@ list-ietf-wg-apps-drums@faerber.muc.de (=?ISO-8859-1?Q?Claus_F=E4rber?=)=> pcoun personal <'sroberts@certicom.ca'> local-part <sroberts> domain <certicom.ca> -"=?iso-8859-1?Q?Juan_Carlos_Marcos_Rodr=EDguez?=" <jcmarcos@datavoicees>=> pcount 1 +"=?iso-8859-1?Q?Juan_Carlos_Marcos_Rodr=EDguez?=" <jcmarcos@datavoice.es>=> pcount 1 1 email <jcmarcos@datavoice.es> personal <=?iso-8859-1?Q?Juan_Carlos_Marcos_Rodr=EDguez?=> 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 personal <=?US-ASCII?Q?gary=5Fc?=> local-part <gary_c> domain <cunningham-lee.com> -=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidusnet>=> pcount 1 +=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidus.net>=> pcount 1 1 email <0@pervalidus.net> personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier> local-part <0> domain <pervalidus.net> -=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidusnet>,=> pcount 1 +=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier <0@pervalidus.net>,=> pcount 1 1 email <0@pervalidus.net> personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E?= Meunier> local-part <0> domain <pervalidus.net> -=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E_Meunier?= <0@pervalidusnet>=> pcount 1 +=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E_Meunier?= <0@pervalidus.net>=> pcount 1 1 email <0@pervalidus.net> personal <=?iso-8859-1?Q?Fr=E9d=E9ric_L_=2E_W_=2E_Meunier?=> local-part <0> domain <pervalidus.net> @@ -554,14 +554,22 @@ No_Reply-To@mapquest.com=> pcount 1 1 email <No_Reply-To@mapquest.com> local-part <No_Reply-To> domain <mapquest.com> -OSULLIE@rte.ie, skidswam@hotmail.com, boot=> error ENOENT +OSULLIE@rte.ie, skidswam@hotmail.com, boot=> pcount 3 +1 email <OSULLIE@rte.ie> + local-part <OSULLIE> domain <rte.ie> +2 email <skidswam@hotmail.com> + local-part <skidswam> domain <hotmail.com> +3 email <> + local-part <boot> Paul Hoffman / IMC <phoffman@imc.org>=> pcount 1 1 email <phoffman@imc.org> personal <Paul Hoffman / IMC> local-part <phoffman> domain <imc.org> -Sam=> error ENOENT +Sam=> pcount 1 +1 email <> + local-part <Sam> Sam Roberts <sam@cogent.ca>=> pcount 1 1 email <sam@cogent.ca> @@ -605,7 +613,9 @@ mcaustin@eudoramail.com, aposner@usaid.gov, Kieran.O'Leary@anpost.ie,=> pcount 3 rfunk@wks.uts.ohio-state.eduofflinemailer-bounce@dikke.penguin.nl=> error ENOENT -root=> error ENOENT +root=> pcount 1 +1 email <> + local-part <root> srr <sam@localhost>=> error ENOENT diff --git a/examples/addr.c b/examples/addr.c index 5f495a052..e32b60766 100644 --- a/examples/addr.c +++ b/examples/addr.c @@ -78,11 +78,15 @@ static int parse(const char* str) address_get_local_part(address, no, buf, sizeof(buf), &got); - if(got) printf(" local-part <%s>", buf); + if(got) { + printf(" local-part <%s>", buf); - address_get_domain(address, no, buf, sizeof(buf), &got); + address_get_domain(address, no, buf, sizeof(buf), &got); - if(got) printf(" domain <%s>\n", buf); + if(got) printf(" domain <%s>", buf); + + printf("\n"); + } address_get_route(address, no, buf, sizeof(buf), &got); diff --git a/imap4d/copy.c b/imap4d/copy.c index 2c688921d..56e9fc90a 100644 --- a/imap4d/copy.c +++ b/imap4d/copy.c @@ -21,34 +21,57 @@ * copy messages in argv[2] to mailbox in argv[3] */ -/* FIXME if the mailbox is the one selecte we should send notif. */ int imap4d_copy (struct imap4d_command *command, char *arg) { + int rc; + char buffer[64]; + + if (! (command->states & state)) + return util_finish (command, RESP_BAD, "Wrong state"); + + rc = imap4d_copy0 (arg, 0, buffer, sizeof buffer); + if (rc == RESP_NONE) + { + /* Reset the state ourself. */ + int new_state = (rc == RESP_OK) ? command->success : command->failure; + if (new_state != STATE_NONE) + state = new_state; + return util_send ("%s %s\r\n", command->tag, buffer); + } + return util_finish (command, rc, buffer); +} + +int +imap4d_copy0 (char *arg, int isuid, char *resp, size_t resplen) +{ int status; char *msgset; char *name; char *mailbox_name; const char *delim = "/"; char *sp = NULL; - int *set = NULL; + size_t *set = NULL; size_t n = 0; mailbox_t cmbox = NULL; - if (! (command->states & state)) - return util_finish (command, RESP_BAD, "Wrong state"); - msgset = util_getword (arg, &sp); name = util_getword (NULL, &sp); util_unquote (&name); if (!msgset || !name || *name == '\0') - return util_finish (command, RESP_BAD, "Too few args"); + { + snprintf (resp, resplen, "Too few args"); + return RESP_BAD; + } /* Get the message numbers in set[]. */ - status = util_msgset (msgset, &set, &n, 0); + status = util_msgset (msgset, &set, &n, isuid); if (status != 0) - return util_finish (command, RESP_BAD, "Bogus number set"); + { + snprintf (resp, resplen, "Bogus number set"); + return RESP_BAD; + } if (strcasecmp (name, "INBOX") == 0) { @@ -71,7 +94,8 @@ imap4d_copy (struct imap4d_command *command, char *arg) for (i = 0; i < n; i++) { message_t msg = NULL; - mailbox_get_message (mbox, set[i], &msg); + size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; + mailbox_get_message (mbox, msgno, &msg); mailbox_append_message (cmbox, msg); } mailbox_close (cmbox); @@ -82,16 +106,16 @@ imap4d_copy (struct imap4d_command *command, char *arg) free (mailbox_name); if (status == 0) - return util_finish (command, RESP_OK, "Completed"); - - /* Since we do not call util_finish, reset the state ourself. */ - if (command->failure != STATE_NONE) - state = command->failure; + { + snprintf (resp, resplen, "Completed"); + return RESP_OK; + } /* Unless it is certain that the destination mailbix can not be created, the server MUST send the response code "[TRYCREATE]" as the prefix of the text of the tagged NO response. This gives a hint to the client that it can attempt a CREATE command and retry the copy if the CREATE is successful. */ - return util_send ("%s NO [TRYCREATE] failed\r\n", command->tag); + snprintf (resp, resplen, "NO [TRYCREATE] failed"); + return RESP_NONE; } diff --git a/imap4d/fetch.c b/imap4d/fetch.c index bfca9aabd..c648369e0 100644 --- a/imap4d/fetch.c +++ b/imap4d/fetch.c @@ -32,176 +32,244 @@ ["<" number "." nz_number ">"] */ -static int fetch_all __P ((struct imap4d_command *, char*)); -static int fetch_full __P ((struct imap4d_command *, char*)); -static int fetch_fast __P ((struct imap4d_command *, char*)); -static int fetch_envelope __P ((struct imap4d_command *, char*)); -static int fetch_flags __P ((struct imap4d_command *, char*)); -static int fetch_internaldate __P ((struct imap4d_command *, char*)); -static int fetch_rfc822_header __P ((struct imap4d_command *, char*)); -static int fetch_rfc822_size __P ((struct imap4d_command *, char*)); -static int fetch_rfc822_text __P ((struct imap4d_command *, char*)); -static int fetch_rfc822 __P ((struct imap4d_command *, char*)); -static int fetch_bodystructure __P ((struct imap4d_command *, char*)); -static int fetch_body_peek __P ((struct imap4d_command *, char*)); -static int fetch_body __P ((struct imap4d_command *, char*)); -static int fetch_uid __P ((struct imap4d_command *, char*)); - -static int fetch_operation __P ((size_t, char *, int)); -static int fetch_message __P ((message_t, unsigned long, unsigned long)); -static int fetch_header __P ((message_t, unsigned long, unsigned long)); -static int fetch_content __P ((message_t, unsigned long, unsigned long)); -static int fetch_io __P ((stream_t, unsigned long, unsigned long)); -static int fetch_header_fields __P ((message_t, char *, unsigned long, - unsigned long)); -static int fetch_header_fields_not __P ((message_t, char *, unsigned long, - unsigned long)); -static int fetch_send_address __P ((char *)); - -struct imap4d_command fetch_command_table [] = +struct fetch_command; + +static int fetch_all __P ((struct fetch_command *, char*)); +static int fetch_full __P ((struct fetch_command *, char*)); +static int fetch_fast __P ((struct fetch_command *, char*)); +static int fetch_envelope __P ((struct fetch_command *, char*)); +static int fetch_envelope0 __P ((message_t)); +static int fetch_flags __P ((struct fetch_command *, char*)); +static int fetch_internaldate __P ((struct fetch_command *, char*)); +static int fetch_rfc822_header __P ((struct fetch_command *, char*)); +static int fetch_rfc822_size __P ((struct fetch_command *, char*)); +static int fetch_rfc822_text __P ((struct fetch_command *, char*)); +static int fetch_rfc822 __P ((struct fetch_command *, char*)); +static int fetch_bodystructure __P ((struct fetch_command *, char*)); +static int fetch_bodystructure0 __P ((message_t, int)); +static int bodystructure __P ((message_t, int)); +static int fetch_body_peek __P ((struct fetch_command *, char*)); +static int fetch_body __P ((struct fetch_command *, char*)); +static int fetch_uid __P ((struct fetch_command *, char*)); + +static int fetch_operation __P ((size_t, char *, int)); +static int fetch_message __P ((message_t, unsigned long, unsigned long)); +static int fetch_header __P ((message_t, unsigned long, unsigned long)); +static int fetch_content __P ((message_t, unsigned long, unsigned long)); +static int fetch_io __P ((stream_t, unsigned long, unsigned long)); +static int fetch_header_fields __P ((message_t, char *, unsigned long, unsigned long)); +static int fetch_header_fields_not __P ((message_t, char *, unsigned long, unsigned long)); +static int fetch_send_address __P ((char *)); + +static struct fetch_command* fetch_getcommand __P ((char *, struct fetch_command[])); + +struct fetch_command +{ + const char *name; + int (*func) __P ((struct fetch_command *, char *)); + size_t msgno; +} fetch_command_table [] = { #define F_ALL 0 - {"ALL", fetch_all, 0, 0, 0, NULL}, + {"ALL", fetch_all, 0}, #define F_FULL 1 - {"FULL", fetch_full, 0, 0, 0, NULL}, + {"FULL", fetch_full, 0}, #define F_FAST 2 - {"FAST", fetch_fast, 0, 0, 0, NULL}, + {"FAST", fetch_fast, 0}, #define F_ENVELOPE 3 - {"ENVELOPE", fetch_envelope, 0, 0, 0, NULL}, + {"ENVELOPE", fetch_envelope, 0}, #define F_FLAGS 4 - {"FLAGS", fetch_flags, 0, 0, 0, NULL}, + {"FLAGS", fetch_flags, 0}, #define F_INTERNALDATE 5 - {"INTERNALDATE", fetch_internaldate, 0, 0, 0, NULL}, + {"INTERNALDATE", fetch_internaldate, 0}, #define F_RFC822_HEADER 6 - {"RFC822.HEADER", fetch_rfc822_header, 0, 0, 0, NULL}, + {"RFC822.HEADER", fetch_rfc822_header, 0}, #define F_RFC822_SIZE 7 - {"RFC822.SIZE", fetch_rfc822_size, 0, 0, 0, NULL}, + {"RFC822.SIZE", fetch_rfc822_size, 0}, #define F_RFC822_TEXT 8 - {"RFC822.TEXT", fetch_rfc822_text, 0, 0, 0, NULL}, + {"RFC822.TEXT", fetch_rfc822_text, 0}, #define F_RFC822 9 - {"RFC822", fetch_rfc822, 0, 0, 0, NULL}, + {"RFC822", fetch_rfc822, 0}, #define F_BODYSTRUCTURE 10 - {"BODYSTRUCTURE", fetch_bodystructure, 0, 0, 0, NULL}, + {"BODYSTRUCTURE", fetch_bodystructure, 0}, #define F_BODY_PEEK 11 - {"BODY.PEEK", fetch_body_peek, 0, 0, 0, NULL}, + {"BODY.PEEK", fetch_body_peek, 0}, #define F_BODY 12 - {"BODY", fetch_body, 0, 0, 0, NULL}, + {"BODY", fetch_body, 0}, #define F_UID 13 - {"UID", fetch_uid, 0, 0, 0, NULL}, - { NULL, 0, 0, 0, 0, NULL} + {"UID", fetch_uid, 0}, + { NULL, 0, 0} }; -/* NOTE: the state field in the command structure is use as a place - holder for the message number. This save us from redifining another - data structure. */ int imap4d_fetch (struct imap4d_command *command, char *arg) { - char *sp = NULL; - char *msgset; - int *set = NULL; - int i, n = 0; - int rc = RESP_OK; - int status; - const char *errmsg = "Completed"; - struct imap4d_command *fcmd; + int rc; + char buffer[64]; if (! (command->states & state)) return util_finish (command, RESP_BAD, "Wrong state"); + rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer); + return util_finish (command, rc, buffer); +} + +static struct fetch_command * +fetch_getcommand (char *cmd, struct fetch_command command_table[]) +{ + size_t i, len = strlen (cmd); + + for (i = 0; command_table[i].name != 0; i++) + { + if (strlen (command_table[i].name) == len && + !strcasecmp (command_table[i].name, cmd)) + return &command_table[i]; + } + return NULL; +} + +int +imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen) +{ + struct fetch_command *fcmd = NULL; + int rc = RESP_NO; + char *sp = NULL; + char *msgset; + size_t *set = NULL; + int n = 0; + int i; + int status; + msgset = util_getword (arg, &sp); if (!msgset || !sp || *sp == '\0') - return util_finish (command, RESP_BAD, "Too few args"); + { + snprintf (resp, resplen, "Too few args"); + return RESP_BAD; + } /* Get the message numbers in set[]. */ - status = util_msgset (msgset, &set, &n, 0); + status = util_msgset (msgset, &set, &n, isuid); if (status != 0) - return util_finish (command, RESP_BAD, "Bogus number set"); + { + snprintf (resp, resplen, "Bogus number set"); + return RESP_BAD; + } for (i = 0; i < n; i++) { char item[32]; char *items = strdup (sp); char *p = items; - util_send ("* FETCH %d (", set[i]); + int uid_sent = !isuid; /* Pretend we sent the uid if via fetch. */ + util_send ("* %d FETCH (", set[i]); item[0] = '\0'; /* Get the fetch command names. */ while (*items && *items != ')') { util_token (item, sizeof (item), &items); + if (fcmd) + util_send (" "); /* Search in the table. */ - fcmd = util_getcommand (item, fetch_command_table); + fcmd = fetch_getcommand (item, fetch_command_table); if (fcmd) { - /* We use the states field to hold the msgno/uid. */ - fcmd->states = set[i]; - fcmd->func (fcmd, items); - util_send (" "); + fcmd->msgno = (isuid) ? uid_to_msgno (set[i]) : set[i]; + if (fcmd->msgno != 0) + { + rc = fcmd->func (fcmd, items); + } } + if (!uid_sent) + uid_sent = ((strstr (item, "UID") != NULL) + || (strstr (item, "uid") != NULL)); + } + /* Always send the UID when fetch was done via the uid command. */ + if (!uid_sent) + { + struct fetch_command c_uid = fetch_command_table[F_UID]; + c_uid.msgno = set[i]; + if (fcmd) + util_send (" "); + rc = fetch_uid (&c_uid, items); } free (p); util_send (")\r\n"); } free (set); - return util_finish (command, rc, errmsg); + snprintf (resp, resplen, "Completed"); + return rc; } -/* Combination of (FAST ENVELOPE). */ +/* The Fetch comand retireves data associated with a message in the + mailbox, The data items to be fetched can be either a single atom + or a parenthesized list. */ + +/* Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE) + or (FAST ENVELOPE) */ static int -fetch_all (struct imap4d_command *command, char *arg) +fetch_all (struct fetch_command *command, char *arg) { - struct imap4d_command c_env = fetch_command_table[F_ENVELOPE]; + struct fetch_command c_env = fetch_command_table[F_ENVELOPE]; fetch_fast (command, arg); util_send (" "); - c_env.states = command->states; + c_env.msgno = command->msgno; fetch_envelope (&c_env, arg); - return 0; + return RESP_OK; } /* Combination of (ALL BODY). */ static int -fetch_full (struct imap4d_command *command, char *arg) +fetch_full (struct fetch_command *command, char *arg) { - struct imap4d_command c_body = fetch_command_table[F_BODY]; + struct fetch_command c_body = fetch_command_table[F_BODY]; fetch_all (command, arg); util_send (" "); - c_body.states = command->states; + c_body.msgno = command->msgno; fetch_body (&c_body, arg); - return 0; + return RESP_OK; } /* Combination of (FLAGS INTERNALDATE RFC822.SIZE). */ static int -fetch_fast (struct imap4d_command *command, char *arg) +fetch_fast (struct fetch_command *command, char *arg) { - struct imap4d_command c_idate = fetch_command_table[F_INTERNALDATE]; - struct imap4d_command c_rfc = fetch_command_table[F_RFC822_SIZE]; - struct imap4d_command c_flags = fetch_command_table[F_FLAGS]; - c_flags.states = command->states; + struct fetch_command c_idate = fetch_command_table[F_INTERNALDATE]; + struct fetch_command c_rfc = fetch_command_table[F_RFC822_SIZE]; + struct fetch_command c_flags = fetch_command_table[F_FLAGS]; + c_flags.msgno = command->msgno; fetch_flags (&c_flags, arg); util_send (" "); - c_idate.states = command->states; + c_idate.msgno = command->msgno; fetch_internaldate (&c_idate, arg); util_send (" "); - c_rfc.states = command->states; + c_rfc.msgno = command->msgno; fetch_rfc822_size (&c_rfc, arg); - return 0; + return RESP_OK; } /* Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, and Message-Id. */ +static int +fetch_envelope (struct fetch_command *command, char *arg) +{ + message_t msg = NULL; + int status; + mailbox_get_message (mbox, command->msgno, &msg); + util_send ("%s (", command->name); + status = fetch_envelope0 (msg); + util_send (")"); + return status; +} + /* FIXME: - strings change to literals when detecting '"' */ static int -fetch_envelope (struct imap4d_command *command, char *arg) +fetch_envelope0 (message_t msg) { - char *buffer; - char *from; + char *buffer = NULL; + char *from = NULL; header_t header = NULL; - message_t msg = NULL; - mailbox_get_message (mbox, command->states, &msg); message_get_header (msg, &header); - util_send ("%s(", command->name); /* FIXME: Incorrect Date. */ header_aget_value (header, "Date", &buffer); @@ -266,18 +334,18 @@ fetch_envelope (struct imap4d_command *command, char *arg) free (buffer); free (from); - util_send (")"); - return 0; + return RESP_OK; } /* The flags that are set for this message. */ /* FIXME: User flags not done. */ static int -fetch_flags (struct imap4d_command *command, char *arg) +fetch_flags (struct fetch_command *command, char *arg) { attribute_t attr = NULL; message_t msg = NULL; - mailbox_get_message (mbox, command->states, &msg); + (void)arg; + mailbox_get_message (mbox, command->msgno, &msg); message_get_attribute (msg, &attr); util_send ("%s (", command->name); if (attribute_is_deleted (attr)) @@ -286,23 +354,23 @@ fetch_flags (struct imap4d_command *command, char *arg) util_send (" \\Answered"); if (attribute_is_flagged (attr)) util_send (" \\Flagged"); - if (attribute_is_seen (attr)) + if (attribute_is_seen (attr) && attribute_is_read (attr)) util_send (" \\Seen"); if (attribute_is_draft (attr)) util_send (" \\Draft"); util_send (" )"); - return 0; + return RESP_OK; } /* The internal date of the message. */ /* FIXME: Wrong format? */ static int -fetch_internaldate (struct imap4d_command *command, char *arg) +fetch_internaldate (struct fetch_command *command, char *arg) { char date[512]; envelope_t env = NULL; message_t msg = NULL; - mailbox_get_message (mbox, command->states, &msg); + mailbox_get_message (mbox, command->msgno, &msg); message_get_envelope (msg, &env); date[0] = '\0'; envelope_date (env, date, sizeof (date), NULL); @@ -310,76 +378,80 @@ fetch_internaldate (struct imap4d_command *command, char *arg) if (date[strlen (date) - 1] == '\n') date[strlen (date) - 1] = '\0'; util_send (" \"%s\"", date); - return 0; + return RESP_OK; } /* Equivalent to BODY.PEEK[HEADER]. */ static int -fetch_rfc822_header (struct imap4d_command *command, char *arg) +fetch_rfc822_header (struct fetch_command *command, char *arg) { char buffer[16]; (void)arg; util_send ("%s ", command->name); strcpy (buffer, "[HEADER]"); - fetch_operation (command->states, buffer, 1); - return 0; + fetch_operation (command->msgno, buffer, 1); + return RESP_OK; } /* Equivalent to BODY[TEXT]. */ -/* FIXME: send a Fetch flag if the mail was not set seen ? */ static int -fetch_rfc822_text (struct imap4d_command *command, char *arg) +fetch_rfc822_text (struct fetch_command *command, char *arg) { char buffer[16]; attribute_t attr = NULL; message_t msg = NULL; - mailbox_get_message (mbox, command->states, &msg); + (void)arg; + mailbox_get_message (mbox, command->msgno, &msg); message_get_attribute (msg, &attr); - attribute_set_read (attr); + if (!attribute_is_seen (attr) && !attribute_is_read (attr)) + { + util_send ("FLAGS (\\Seen) "); + attribute_set_seen (attr); + attribute_set_read (attr); + } util_send ("%s ", command->name); strcpy (buffer, "[TEXT]"); - fetch_operation (command->states, buffer, 1); - return 0; + fetch_operation (command->msgno, buffer, 1); + return RESP_OK; } /* The [RFC-822] size of the message. */ static int -fetch_rfc822_size (struct imap4d_command *command, char *arg) +fetch_rfc822_size (struct fetch_command *command, char *arg) { size_t size = 0; size_t lines = 0; message_t msg = NULL; (void)arg; - mailbox_get_message (mbox, command->states, &msg); + mailbox_get_message (mbox, command->msgno, &msg); message_size (msg, &size); message_lines (msg, &lines); util_send ("%s %u", command->name, size + lines); - return 0; + return RESP_OK; } /* Equivalent to BODY[]. */ -/* FIXME: send a Fetch flag if the mail was not set seen ? */ static int -fetch_rfc822 (struct imap4d_command *command, char *arg) +fetch_rfc822 (struct fetch_command *command, char *arg) { if (*arg == '.') { if (strncasecmp (arg, ".SIZE", 5) == 0) { - struct imap4d_command c_rfc= fetch_command_table[F_RFC822_SIZE]; - c_rfc.states = command->states; + struct fetch_command c_rfc= fetch_command_table[F_RFC822_SIZE]; + c_rfc.msgno = command->msgno; fetch_rfc822_size (&c_rfc, arg); } else if (strncasecmp (arg, ".TEXT", 5) == 0) { - struct imap4d_command c_rfc = fetch_command_table[F_RFC822_TEXT]; - c_rfc.states = command->states; + struct fetch_command c_rfc = fetch_command_table[F_RFC822_TEXT]; + |