summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog44
-rw-r--r--doc/Makefile.am3
-rw-r--r--doc/address.texi73
-rw-r--r--examples/Addrs.good24
-rw-r--r--examples/addr.c10
-rw-r--r--imap4d/copy.c54
-rw-r--r--imap4d/fetch.c626
-rw-r--r--imap4d/imap4d.c18
-rw-r--r--imap4d/imap4d.h17
-rw-r--r--imap4d/login.c3
-rw-r--r--imap4d/select.c11
-rw-r--r--imap4d/status.c2
-rw-r--r--imap4d/store.c44
-rw-r--r--imap4d/sync.c250
-rw-r--r--imap4d/uid.c28
-rw-r--r--imap4d/util.c154
-rw-r--r--include/mailutils/header.h70
-rw-r--r--include/mailutils/parse822.h1
-rw-r--r--mailbox/attribute.c4
-rw-r--r--mailbox/file_stream.c43
-rw-r--r--mailbox/mailbox.c2
-rw-r--r--mailbox/parse822.c69
22 files changed, 1145 insertions, 405 deletions
diff --git a/ChangeLog b/ChangeLog
index b4eec651b..4e6f69bc8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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];
+ c_rfc.msgno = command->msgno;
fetch_rfc822_text (&c_rfc, arg);
}
else if (strncasecmp (arg, ".HEADER", 7) == 0)
{
- struct imap4d_command c_rfc = fetch_command_table[F_RFC822_HEADER];
- c_rfc.states = command->states;
+ struct fetch_command c_rfc = fetch_command_table[F_RFC822_HEADER];
+ c_rfc.msgno = command->msgno;
fetch_rfc822_header (&c_rfc, arg);
}
}
@@ -388,51 +460,294 @@ fetch_rfc822 (struct imap4d_command *command, char *arg)
char buffer[16];
attribute_t attr = NULL;
message_t msg = NULL;
- mailbox_get_message (mbox, command->states, &msg);
+ 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, "[]");
- fetch_operation (command->states, buffer, 1);
+ fetch_operation (command->msgno, buffer, 1);
}
- return 0;
+ return RESP_OK;
}
/* The unique identifier for the message. */
static int
-fetch_uid (struct imap4d_command *command, char *arg)
+fetch_uid (struct fetch_command *command, char *arg)
{
size_t uid = 0;
message_t msg = NULL;
- mailbox_get_message (mbox, command->states, &msg);
+ (void)arg;
+ mailbox_get_message (mbox, command->msgno, &msg);
message_get_uid (msg, &uid);
util_send ("%s %d", command->name, uid);
- return 0;
+ return RESP_OK;
}
-/* FIXME: not implemeted. */
static int
-fetch_bodystructure (struct imap4d_command *command, char *arg)
+fetch_bodystructure (struct fetch_command *command, char *arg)
{
- util_send ("%s ()", command->name);
- return 0;
+ message_t message = NULL;
+ (void)arg;
+ util_send ("%s (", command->name);
+ mailbox_get_message (mbox, command->msgno, &message);
+ fetch_bodystructure0 (message, 1);
+ util_send (")");
+ return RESP_OK;
+}
+
+static int
+fetch_bodystructure0 (message_t message, int extension)
+{
+ size_t nparts = 1;
+ size_t i;
+ int is_multipart = 0;
+ message_is_multipart (message, &is_multipart);
+ if (is_multipart)
+ {
+ message_get_num_parts (message, &nparts);
+ for (i = 1; i <= nparts; i++)
+ {
+ message_t msg = NULL;
+ message_get_part (message, i, &msg);
+ util_send ("(");
+ fetch_bodystructure0 (msg, extension);
+ util_send (")");
+ } /* for () */
+ /* The extension data for multipart. */
+ if (extension)
+ {
+ header_t header = NULL;
+ char *buffer = NULL;
+ char *sp = NULL;
+ char *s;
+ /* The subtype. */
+ message_get_header (message, &header);
+ header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
+ s = strtok_r (buffer, " \t\r\n;", &sp);
+ s = strchr (buffer, '/');
+ if (s)
+ {
+ s++;
+ util_send (" \"%s\"", s);
+ }
+ else
+ util_send (" NIL");
+ /* Content-type parameter list. */
+ util_send (" (");
+ {
+ while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
+ {
+ char *p = strchr (s, '=');
+ if (p)
+ *p++ = '\0';
+ util_send ("\"%s\"", s);
+ util_send (" \"%s\"", (p) ? p : "NIL");
+ }
+ }
+ free (buffer);
+ /* Content-Disposition. */
+ header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
+ if (*buffer)
+ {
+ util_send (" (");
+ while ((s = strtok_r (buffer, " \t\r\n;", &sp)))
+ {
+ char *p = strchr (s, '=');
+ if (p)
+ *p++ = '\0';
+ util_send ("\"%s\"", s);
+ util_send (" \"%s\"", (p) ? p : "NIL");
+ }
+ }
+ else
+ util_send (" NIL");
+ free (buffer);
+ /* Content-Language. */
+ header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
+ if (*buffer)
+ util_send (" \"%s\"", buffer);
+ else
+ util_send (" NIL");
+ } /* extension */
+ }
+ else
+ bodystructure (message, extension);
+ return RESP_OK;
+}
+
+static int
+bodystructure (message_t msg, int extension)
+{
+ header_t header = NULL;
+ char *sp = NULL;
+ char *buffer = NULL;
+ char *s;
+ size_t blines = 0;
+ int message_rfc822 = 0;
+ int text_plain = 0;
+
+ message_get_header (msg, &header);
+
+ /* MIME: */
+ header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
+ s = strtok_r (buffer, " \t\r\n;", &sp);
+ /* MIME media type and subtype */
+ if (s)
+ {
+ char *p = strchr (s, '/');
+ if (strcasecmp (s, "MESSAGE/RFC822") == 0)
+ message_rfc822 = 1;
+ if (strcasecmp (s, "TEXT/PLAIN") == 0)
+ text_plain = 1;
+ if (p)
+ *p++ = '\0';
+ util_send ("\"%s\"", s);
+ util_send (" \"%s\"", (p) ? p : "NIL");
+ }
+ else
+ {
+ /* Default? */
+ util_send ("TEXT");
+ util_send (" PLAIN");
+ }
+ /* Content-type parameter list. */
+ util_send (" (");
+ {
+ int have_charset = 0;
+ while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
+ {
+ char *p = strchr (s, '=');
+ if (p)
+ *p++ = '\0';
+ util_send ("\"%s\"", s);
+ util_send (" \"%s\"", (p) ? p : "NIL");
+ if (strcasecmp (s, "charset") == 0)
+ have_charset = 1;
+ }
+ /* Default. */
+ if (!have_charset)
+ {
+ util_send ("\"CHARSET\"");
+ util_send (" \"US-ASCII\"");
+ }
+ }
+ util_send (")");
+ free (buffer);
+
+ /* Content-ID. */
+ header_aget_value (header, MU_HEADER_CONTENT_ID, &buffer);
+ if (*buffer)
+ util_send (" \"%s\"", buffer);
+ else
+ util_send (" NIL");
+ free (buffer);
+
+ /* Content-Description. */
+ header_aget_value (header, MU_HEADER_CONTENT_DESCRIPTION, &buffer);
+ if (*buffer)
+ util_send (" \"%s\"", buffer);
+ else
+ util_send (" NIL");
+ free (buffer);
+
+ /* Content-Transfer-Encoding. */
+ header_aget_value (header, MU_HEADER_CONTENT_TRANSFER_ENCODING, &buffer);
+ util_send (" \"%s\"", (*buffer) ? buffer : "7bit");
+ free (buffer);
+
+ /* Body size RFC822 format. */
+ {
+ size_t size = 0;
+ body_t body = NULL;
+ message_get_body (msg, &body);
+ body_size (body, &size);
+ body_lines (body, &blines);
+ util_send (" %d", size + blines);
+ }
+
+ /* If the mime type was text. */
+ if (text_plain)
+ {
+ /* Add the line number of the body. */
+ util_send (" %d", blines);
+ }
+ else if (message_rfc822)
+ {
+ size_t lines = 0;
+ /* Add envelope structure */
+ util_send ("(");
+ fetch_envelope0 (msg);
+ util_send (")");
+ /* Add body structure */
+ util_send ("(");
+ bodystructure (msg, 1);
+ util_send (")");
+ /* size in text lines of the encapsulated message. */
+ message_lines (msg, &lines);
+ util_send (" %d", lines);
+ }
+
+ if (extension)
+ {
+ /* Content-MD5. */
+ header_aget_value (header, MU_HEADER_CONTENT_MD5, &buffer);
+ if (*buffer)
+ util_send (" \"%s\"", buffer);
+ else
+ util_send (" NIL");
+ free (buffer);
+ /* Content-Disposition. */
+ header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
+ if (*buffer)
+ {
+ util_send (" (");
+ while ((s = strtok_r (buffer, " \t\r\n;", &sp)))
+ {
+ char *p = strchr (s, '=');
+ if (p)
+ *p++ = '\0';
+ util_send ("\"%s\"", s);
+ util_send (" \"%s\"", (p) ? p : "NIL");
+ }
+ }
+ else
+ util_send (" NIL");
+ free (buffer);
+ /* Content-Language. */
+ header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
+ if (*buffer)
+ util_send (" \"%s\"", buffer);
+ else
+ util_send (" NIL");
+ free (buffer);
+ }
+ return RESP_OK;
}
/* An alternate form of BODY that does not implicitly set the \Seen flag. */
-/* FIXME: send notificaton if seen attribute is set? */
static int
-fetch_body (struct imap4d_command *command, char *arg)
+fetch_body (struct fetch_command *command, char *arg)
{
- struct imap4d_command c_body_p = fetch_command_table[F_BODY_PEEK];
- c_body_p.states = command->states;
+ struct fetch_command c_body_p = fetch_command_table[F_BODY_PEEK];
+ c_body_p.msgno = command->msgno;
/* It's BODY set the message as seen */
if (*arg == '[')
{
message_t msg = NULL;
attribute_t attr = NULL;
- mailbox_get_message (mbox, command->states, &msg);
+ mailbox_get_message (mbox, command->msgno, &msg);
message_get_attribute (msg, &attr);
- attribute_set_seen (attr);
+ if (!attribute_is_seen (attr) && !attribute_is_read (attr))
+ {
+ util_send ("FLAGS (\\Seen) ");
+ attribute_set_seen (attr);
+ attribute_set_read (attr);
+ }
}
else if (strncasecmp (arg,".PEEK", 5) == 0)
{
@@ -443,22 +758,23 @@ fetch_body (struct imap4d_command *command, char *arg)
}
else if (*arg != '[' && *arg != '.')
{
- struct imap4d_command c_bs = fetch_command_table[F_BODYSTRUCTURE];
- c_bs.states = command->states;
- /* FIXME: Call body structure without the extension. */
- /* return fetch_bodystructure (&c_bs, arg); */
- util_send (" ()");
- return 0;
+ message_t message = NULL;
+ mailbox_get_message (mbox, command->msgno, &message);
+ /* Call body structure without the extension. */
+ util_send ("%s (", command->name);
+ fetch_bodystructure0 (message, 0);
+ util_send (")");
+ return RESP_OK;
}
return fetch_body_peek (&c_body_p, arg);
}
static int
-fetch_body_peek (struct imap4d_command *command, char *arg)
+fetch_body_peek (struct fetch_command *command, char *arg)
{
util_send ("%s ", command->name);
- fetch_operation (command->states, arg, 0);
- return 0;
+ fetch_operation (command->msgno, arg, 0);
+ return RESP_OK;
}
static int
@@ -498,7 +814,7 @@ fetch_operation (size_t msgno, char *arg, int silent)
if (status != 0)
{
util_send ("\"\"");
- return 0;
+ return RESP_OK;
}
}
@@ -537,7 +853,7 @@ fetch_operation (size_t msgno, char *arg, int silent)
}
else
util_send ("\"\"");
- return 0;
+ return RESP_OK;
}
static int
@@ -595,7 +911,7 @@ fetch_io (stream_t stream, unsigned long start, unsigned long end)
if (start == ULONG_MAX)
{
start = 0;
- util_send ("{%u}\r\n", end);
+ util_send (" {%u}\r\n", end);
}
else
util_send ("<%lu> {%u}\r\n", start , end);
@@ -613,7 +929,7 @@ fetch_io (stream_t stream, unsigned long start, unsigned long end)
}
util_send ("%s", buffer);
}
- return 0;
+ return RESP_OK;
}
static int
@@ -630,7 +946,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
status = memory_stream_create (&stream);
if (status != 0)
- util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
+ util_quit (ERR_NO_MEM);
/* Save the fields in an array. */
{
@@ -641,7 +957,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
{
array = realloc (array, (array_len + 1) * sizeof (*array));
if (!array)
- util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
+ util_quit (ERR_NO_MEM);
array[array_len] = field;
}
}
@@ -668,7 +984,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
if (status != 0)
{
free (array);
- util_quit (1); /* FIXME: send a "* BYE" to the client. */
+ util_quit (ERR_NO_MEM);
}
}
}
@@ -694,7 +1010,7 @@ fetch_header_fields (message_t msg, char *arg, unsigned long start,
fetch_io (stream, start, end);
if (array)
free (array);
- return 0;
+ return RESP_OK;
}
static int
@@ -711,7 +1027,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
status = memory_stream_create (&stream);
if (status)
- util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
+ util_quit (ERR_NO_MEM);
/* Save the field we want to ignore. */
{
@@ -722,7 +1038,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
{
array = realloc (array, (array_len + 1) * sizeof (*array));
if (!array)
- util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
+ util_quit (ERR_NO_MEM);
array[array_len] = field;
}
}
@@ -777,7 +1093,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
if (status != 0)
{
free (array);
- util_quit (1); /* FIXME: send a "* BYE" to the client. */
+ util_quit (ERR_NO_MEM);
}
}
}
@@ -802,7 +1118,7 @@ fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
fetch_io (stream, start, end);
if (array)
free (array);
- return 0;
+ return RESP_OK;
}
/* FIXME: The address is limit by a buffer of 128, no good. We should
@@ -816,7 +1132,7 @@ fetch_send_address (char *addr)
if (*addr == '\0')
{
util_send ("NIL");
- return 0;
+ return RESP_OK;
}
address_create (&address, addr);
@@ -874,5 +1190,5 @@ fetch_send_address (char *addr)
util_send (")");
}
util_send (")");
- return 0;
+ return RESP_OK;
}
diff --git a/imap4d/imap4d.c b/imap4d/imap4d.c
index 67a2931d6..4f3da79a1 100644
--- a/imap4d/imap4d.c
+++ b/imap4d/imap4d.c
@@ -17,14 +17,13 @@
#include "imap4d.h"
-int *ifile;
FILE *ofile;
unsigned int timeout = 1800; /* RFC2060: 30 minutes, if enable. */
mailbox_t mbox;
char *homedir;
int state = STATE_NONAUTH;
-static int imap4_mainloop __P ((int, int));
+static int imap4d_mainloop __P ((int, int));
int
main (int argc, char **argv)
@@ -39,18 +38,19 @@ main (int argc, char **argv)
list_append (bookie, path_record);
}
/* FIXME: Incomplete, make it work for standalone, see pop3d. */
- imap4_mainloop (fileno (stdin), fileno (stdout));
+ imap4d_mainloop (fileno (stdin), fileno (stdout));
return 0;
}
static int
-imap4_mainloop (int infile, int outfile)
+imap4d_mainloop (int infile, int outfile)
{
const char *remote_host = "";
-
+ FILE *ifile;
+ ifile = fdopen (infile, "r");
ofile = fdopen (outfile, "w");
- if (ofile == NULL)
- util_quit (1);
+ if (!ofile || !ifile)
+ util_quit (ERR_NO_OFILE);
/* FIXME: Retreive hostname with getpeername() and log. */
syslog (LOG_INFO, "Incoming connection from %s", remote_host);
@@ -61,9 +61,11 @@ imap4_mainloop (int infile, int outfile)
while (1)
{
- char *cmd = imap4d_readline (infile);
+ char *cmd = imap4d_readline (ifile);
/* check for updates */
+ imap4d_sync ();
util_do_command (cmd);
+ imap4d_sync ();
free (cmd);
fflush (ofile);
}
diff --git a/imap4d/imap4d.h b/imap4d/imap4d.h
index 4b4235423..1d346e8fa 100644
--- a/imap4d/imap4d.h
+++ b/imap4d/imap4d.h
@@ -99,12 +99,17 @@ struct imap4d_command
#define STATE_ALL (STATE_NONE | STATE_NONAUTH | STATE_AUTH | STATE_SEL \
| STATE_LOGOUT)
+/* Response code. */
#define RESP_OK 0
#define RESP_BAD 1
#define RESP_NO 2
#define RESP_BYE 3
#define RESP_NONE 4
+/* Error values. */
+#define ERR_NO_MEM 1
+#define ERR_NO_OFILE 2
+
extern struct imap4d_command imap4d_command_table[];
extern FILE *ofile;
extern unsigned int timeout;
@@ -135,10 +140,18 @@ extern int imap4d_close __P ((struct imap4d_command *, char *));
extern int imap4d_expunge __P ((struct imap4d_command *, char *));
extern int imap4d_search __P ((struct imap4d_command *, char *));
extern int imap4d_fetch __P ((struct imap4d_command *, char *));
+extern int imap4d_fetch0 __P ((char *, int, char *, size_t));
extern int imap4d_store __P ((struct imap4d_command *, char *));
+extern int imap4d_store0 __P ((char *, int, char *, size_t));
extern int imap4d_copy __P ((struct imap4d_command *, char *));
+extern int imap4d_copy0 __P ((char *, int, char *, size_t));
extern int imap4d_uid __P ((struct imap4d_command *, char *));
+/* Synchronisation on simultenous access. */
+extern int imap4d_sync __P ((void));
+extern int imap4d_sync_flags __P ((size_t));
+extern size_t uid_to_msgno __P ((size_t));
+
/* Helper functions. */
extern int util_out __P ((int, const char *, ...));
extern int util_send __P ((const char *, ...));
@@ -146,14 +159,14 @@ extern int util_start __P ((char *));
extern int util_finish __P ((struct imap4d_command *, int, const char *, ...));
extern int util_getstate __P ((void));
extern int util_do_command __P ((char *));
-extern char *imap4d_readline __P ((int));
+extern char *imap4d_readline __P ((FILE*));
extern void util_quit __P ((int));
extern char *util_getword __P ((char *, char **));
extern int util_token __P ((char *, size_t, char **));
extern void util_unquote __P ((char **));
extern char *util_tilde_expansion __P ((const char *, const char *));
extern char *util_getfullpath __P ((char *, const char *));
-extern int util_msgset __P ((char *, int **, int *, int));
+extern int util_msgset __P ((char *, size_t **, int *, int));
extern int util_upper __P ((char *));
extern struct imap4d_command *util_getcommand __P ((char *,
struct imap4d_command []));
diff --git a/imap4d/login.c b/imap4d/login.c
index df1ca76b6..7e1d15274 100644
--- a/imap4d/login.c
+++ b/imap4d/login.c
@@ -97,6 +97,7 @@ imap4d_login (struct imap4d_command *command, char *arg)
return util_finish (command, RESP_NO, "Too many args");
pw = getpwnam (arg);
+
#ifndef USE_LIBPAM
if (pw == NULL || pw->pw_uid < 1)
return util_finish (command, RESP_NO, "User name or passwd rejected");
@@ -105,7 +106,7 @@ imap4d_login (struct imap4d_command *command, char *arg)
#ifdef HAVE_SHADOW_H
struct spwd *spw;
spw = getspnam (arg);
- if (spw == NULL || strcmp (spw->sp_pwdp, crypt (pass, spw->sp_pwdp)))
+ if (spw == NULL || strcmp (spw->sp_pwdp, (char *)crypt (pass, spw->sp_pwdp)))
#endif /* HAVE_SHADOW_H */
return util_finish (command, RESP_NO, "User name or passwd rejected");
}
diff --git a/imap4d/select.c b/imap4d/select.c
index d62835a96..389841d37 100644
--- a/imap4d/select.c
+++ b/imap4d/select.c
@@ -50,6 +50,8 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
{
mailbox_close (mbox);
mailbox_destroy (&mbox);
+ /* Destroy the old uid table. */
+ imap4d_sync ();
}
if (strcasecmp (mailbox_name, "INBOX") == 0)
@@ -63,7 +65,7 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
&& mailbox_open (mbox, flags) == 0)
{
const char *mflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
- const char *pflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
+ const char *pflags = "\\Answered \\Deleted \\Seen";
unsigned long uidvalidity = 0;
size_t count = 0, recent = 0, unseen = 0, uidnext = 0;
@@ -83,10 +85,13 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
/* FIXME:
- '\*' can be supported if we use the attribute_set userflag()
- Answered is still not set in the mailbox code. */
- util_out (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags", pflags);
+ if (flags == MU_STREAM_READ)
+ util_out (RESP_OK, "[PERMANENTFLAGS ()] No Permanent flags");
+ else
+ util_out (RESP_OK, "[PERMANENTFLAGS (%s)] Permanent flags", pflags);
/* Need to set the state explicitely for select. */
state = STATE_SEL;
- return util_send ("%s OK [%s] %s Complete\r\n", command->tag,
+ return util_send ("%s OK [%s] %s Completed\r\n", command->tag,
(MU_STREAM_READ == flags) ?
"READ-ONLY" : "READ-WRITE", command->name);
}
diff --git a/imap4d/status.c b/imap4d/status.c
index f242e01f9..20b590909 100644
--- a/imap4d/status.c
+++ b/imap4d/status.c
@@ -144,7 +144,7 @@ status_unseen (mailbox_t smbox)
attribute_t attr = NULL;
mailbox_get_message (smbox, i, &msg);
message_get_attribute (msg, &attr);
- if (!attribute_is_seen (attr))
+ if (!attribute_is_seen (attr) && !attribute_is_read (attr))
unseen++;
}
util_send ("UNSEEN %d", unseen);
diff --git a/imap4d/store.c b/imap4d/store.c
index 5199e3127..fba9fa57c 100644
--- a/imap4d/store.c
+++ b/imap4d/store.c
@@ -25,23 +25,36 @@ static int get_attribute_type __P ((const char *, int *));
int
imap4d_store (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_store0 (arg, 0, buffer, sizeof buffer);
+ return util_finish (command, rc, buffer);
+}
+
+int
+imap4d_store0 (char *arg, int isuid, char *resp, size_t resplen)
+{
char *msgset;
char *data;
char *sp = NULL;
int status;
int ack = 0;
size_t i, n = 0;
- int *set = NULL;
+ size_t *set = NULL;
enum value_type { STORE_SET, STORE_ADD, STORE_UNSET } how;
- if (! (command->states & state))
- return util_finish (command, RESP_BAD, "Wrong state");
-
msgset = util_getword (arg, &sp);
data = util_getword (NULL, &sp);
if (!msgset || !data || !sp || *sp == '\0')
- return util_finish (command, RESP_BAD, "Too few args");
+ {
+ snprintf (resp, resplen, "Too few args");
+ return RESP_BAD;
+ }
/* The parsing of the data-item is a little slugish. */
if (strcasecmp (data, "FLAGS") == 0)
@@ -75,12 +88,18 @@ imap4d_store (struct imap4d_command *command, char *arg)
how = STORE_UNSET;
}
else
- return util_finish (command, RESP_BAD, "Bogus data item");
+ {
+ snprintf (resp, resplen, "Bogus data item");
+ 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++)
{
@@ -89,8 +108,10 @@ imap4d_store (struct imap4d_command *command, char *arg)
char *items = strdup (sp); /* Don't use the orignal list. */
char *flags = strdup ("");
int first = 1;
+ size_t msgno;
- mailbox_get_message (mbox, set[i], &msg);
+ msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
+ mailbox_get_message (mbox, msgno, &msg);
message_get_attribute (msg, &attr);
/* Get the fetch command names. */
@@ -124,9 +145,12 @@ imap4d_store (struct imap4d_command *command, char *arg)
util_out (RESP_NONE, "%d FETCH FLAGS (%s)", set[i], flags);
free (items);
free (flags);
+ /* Update the flags of uid table. */
+ imap4d_sync_flags (set[i]);
}
free (set);
- return util_finish (command, RESP_OK, "Completed");
+ snprintf (resp, resplen, "Completed");
+ return RESP_OK;
}
static int
diff --git a/imap4d/sync.c b/imap4d/sync.c
new file mode 100644
index 000000000..6224d11b1
--- /dev/null
+++ b/imap4d/sync.c
@@ -0,0 +1,250 @@
+/* GNU mailutils - a suite of utilities for electronic mail
+ Copyright (C) 1999, 2001 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "imap4d.h"
+
+/*
+
+ */
+struct _uid_table
+{
+ size_t uid;
+ size_t msgno;
+ int notify;
+ attribute_t attr;
+};
+
+static struct _uid_table *uid_table;
+static size_t uid_table_count;
+
+static void
+add_flag (char **pbuf, const char *f)
+{
+ char *abuf = *pbuf;
+ abuf = realloc (abuf, strlen (abuf) + strlen (f) + 2);
+ if (abuf == NULL)
+ util_quit (ERR_NO_MEM);
+ if (*abuf)
+ strcat (abuf, " ");
+ strcat (abuf, "\\Seen");
+ *pbuf = abuf;
+}
+
+static void
+notify_flag (size_t msgno, attribute_t oattr)
+{
+ message_t msg = NULL;
+ attribute_t nattr = NULL;
+ int status ;
+ mailbox_get_message (mbox, msgno, &msg);
+ message_get_attribute (msg, &nattr);
+ status = attribute_is_equal (oattr, nattr);
+ //if (!attribute_is_equal (oattr, nattr))
+ if (status == 0)
+ {
+ char *abuf = malloc (1);;
+ if (!abuf)
+ util_quit (ERR_NO_MEM);
+ *abuf = '\0';
+ if (attribute_is_seen (nattr) && attribute_is_read (nattr))
+ if (!attribute_is_seen (oattr) && !attribute_is_read (oattr))
+ {
+ attribute_set_seen (oattr);
+ attribute_set_read (oattr);
+ add_flag (&abuf, "\\Seen");
+ }
+ if (attribute_is_answered (nattr))
+ if (!attribute_is_answered (oattr))
+ {
+ attribute_set_answered (oattr);
+ add_flag (&abuf, "\\Answered");
+ }
+ if (attribute_is_flagged (nattr))
+ if (!attribute_is_flagged (oattr))
+ {
+ attribute_set_flagged (oattr);
+ add_flag (&abuf, "\\Flagged");
+ }
+ if (attribute_is_deleted (nattr))
+ if (!attribute_is_deleted (oattr))
+ {
+ attribute_set_deleted (oattr);
+ add_flag (&abuf, "\\Deleted");
+ }
+ if (attribute_is_draft (nattr))
+ if (!attribute_is_draft (oattr))
+ {
+ attribute_set_draft (oattr);
+ add_flag (&abuf, "\\Draft");
+ }
+ if (attribute_is_recent (nattr))
+ if (!attribute_is_recent (oattr))
+ {
+ attribute_set_recent (oattr);
+ add_flag (&abuf, "\\Recent");
+ }
+ if (*abuf)
+ util_out (RESP_NONE, "%d FETCH FLAGS (%s)", msgno, abuf);
+ free (abuf);
+ }
+}
+
+static void
+notify_deleted (void)
+{
+ if (uid_table)
+ {
+ size_t i;
+ for (i = 0; i < uid_table_count; i++)
+ {
+ if (!(uid_table[i].notify))
+ {
+ util_out (RESP_NONE, "%d EXPUNGE", uid_table[i].msgno);
+ uid_table[i].notify = 1;
+ }
+ }
+ }
+}
+
+
+static int
+notify_uid (size_t uid)
+{
+ if (uid_table)
+ {
+ size_t i;
+ for (i = 0; i < uid_table_count; i++)
+ {
+ if (uid_table[i].uid == uid)
+ {
+ notify_flag (uid_table[i].msgno, uid_table[i].attr);
+ uid_table[i].notify = 1;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static void
+notify (void)
+{
+ if (uid_table)
+ {
+ size_t total = 0;
+ size_t i;
+ size_t recent = 0;
+ mailbox_messages_count (mbox, &total);
+ for (i = 1; i <= total; i++)
+ {
+ message_t msg = NULL;
+ size_t uid = 0;
+ mailbox_get_message (mbox, i, &msg);
+ message_get_uid (msg, &uid);
+ if (!notify_uid (uid))
+ recent++;
+ }
+ util_out (RESP_NONE, "%d EXISTS", total);
+ if (recent)
+ util_out (RESP_NONE, "%d RECENT", recent);
+ notify_deleted ();
+ }
+}
+
+static void
+free_uids (void)
+{
+ if (uid_table)
+ {
+ size_t i;
+ for (i = 0; i < uid_table_count; i++)
+ attribute_destroy (&(uid_table[i].attr), NULL);
+ free (uid_table);
+ uid_table = NULL;
+ uid_table_count = 0;
+ }
+}
+
+static void
+reset_uids (void)
+{
+ size_t total = 0;
+ size_t i;
+
+ notify ();
+ free_uids ();
+
+ mailbox_messages_count (mbox, &total);
+ for (i = 1; i <= total; i++)
+ {
+ message_t msg = NULL;
+ attribute_t attr = NULL;
+ size_t uid = 0;
+ uid_table = realloc (uid_table, sizeof (*uid_table) *
+ (uid_table_count + 1));
+ if (!uid_table)
+ util_quit (ERR_NO_MEM);
+ mailbox_get_message (mbox, i, &msg);
+ message_get_attribute (msg, &attr);
+ message_get_uid (msg, &uid);
+ uid_table[uid_table_count].uid = uid;
+ uid_table[uid_table_count].msgno = i;
+ uid_table[uid_table_count].notify = 0;
+ attribute_create (&(uid_table[uid_table_count].attr), NULL);
+ attribute_copy (uid_table[uid_table_count].attr, attr);
+ uid_table_count++;
+ }
+}
+
+size_t
+uid_to_msgno (size_t uid)
+{
+ size_t i;
+ for (i = 0; i < uid_table_count; i++)
+ if (uid_table[i].uid == uid)
+ return uid_table[i].msgno;
+ return 0;
+}
+
+int
+imap4d_sync_flags (size_t msgno)
+{
+ size_t i;
+ for (i = 0; i < uid_table_count; i++)
+ if (uid_table[i].msgno == msgno)
+ {
+ message_t msg = NULL;
+ attribute_t attr = NULL;
+ mailbox_get_message (mbox, msgno, &msg);
+ message_get_attribute (msg, &attr);
+ attribute_copy (uid_table[i].attr, attr);
+ break;
+ }
+ return 0;
+}
+
+int
+imap4d_sync (void)
+{
+ /* if mbox --> NULL, it means to free all the ressources.
+ it may be because of close or before select/examine a new mailbox. */
+ if (mbox == NULL)
+ free_uids ();
+ else if (uid_table == NULL || !mailbox_is_updated (mbox))
+ reset_uids ();
+ return 0;
+}
diff --git a/imap4d/uid.c b/imap4d/uid.c
index d716b77a4..af6e18ea1 100644
--- a/imap4d/uid.c
+++ b/imap4d/uid.c
@@ -25,7 +25,33 @@
int
imap4d_uid (struct imap4d_command *command, char *arg)
{
+ char *cmd;
+ char *sp = NULL;
+ int rc = RESP_NO;
+ char buffer[64];
+
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
- return util_finish (command, RESP_NO, "Not supported");
+
+ cmd = util_getword (arg, &sp);
+ if (!cmd)
+ util_finish (command, RESP_BAD, "Too few args");
+ if (strcasecmp (cmd, "FETCH") == 0)
+ {
+ rc = imap4d_fetch0 (sp, 1, buffer, sizeof buffer);
+ }
+ else if (strcasecmp (cmd, "COPY") == 0)
+ {
+ rc = imap4d_copy0 (sp, 1, buffer, sizeof buffer);
+ }
+ else if (strcasecmp (cmd, "STORE") == 0)
+ {
+ rc = imap4d_store0 (sp, 1, buffer, sizeof buffer);
+ }
+ else
+ {
+ snprintf (buffer, sizeof buffer, "Error uknown uid command");
+ rc = RESP_BAD;
+ }
+ return util_finish (command, rc, "%s %s", cmd, buffer);
}
diff --git a/imap4d/util.c b/imap4d/util.c
index 34a922d0d..99bf09de3 100644
--- a/imap4d/util.c
+++ b/imap4d/util.c
@@ -18,7 +18,7 @@
#include "imap4d.h"
#include <ctype.h>
-static int add2set __P ((int **, int *, unsigned long, size_t));
+static int add2set __P ((size_t **, int *, unsigned long, size_t));
static const char *sc2string __P ((int));
/* 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)
if (**ptr == ' ' || **ptr == '.'
|| **ptr == '(' || **ptr == ')'
|| **ptr == '[' || **ptr == ']'
- || **ptr == '<' || **ptr == '>')
+ || **ptr == '<' || **ptr == '>'
+ || **ptr == '\r' || **ptr == '\n')
{
/* Advance. */
if (start == (*ptr))
@@ -172,7 +173,7 @@ util_getfullpath (char *name, const char *delim)
FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10>
will not generate an error. */
int
-util_msgset (char *s, int **set, int *n, int isuid)
+util_msgset (char *s, size_t **set, int *n, int isuid)
{
unsigned long val = 0;
unsigned long low = 0;
@@ -340,93 +341,79 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
return status;
}
-#if 0
-/* Need a replacement for readline that can support literals. */
+/* Clients are allowed to send literal string to the servers. this
+ mean that it can me everywhere where a string is allowed.
+ A literal is a sequence of zero or more octets (including CR and LF)
+ prefix-quoted with an octet count in the form of an open brace ("{"),
+ the number of octets, close brace ("}"), and CRLF.
+ */
char *
imap4d_readline (FILE *fp)
{
char buffer[512];
- char *line;
size_t len;
+ long number = 0;
+ size_t total = 0;
+ char *line = malloc (1);
- alarm (timeout);
- line = fgets (buffer, sizeof (buffer), fp);
- alarm (0);
if (!line)
- util_quit (1);
- line = strdup (buffer);
- len = strlen (buffer);
- if (len > 2)
+ util_quit (ERR_NO_MEM);
+
+ line[0] = '\0'; /* start with a empty string. */
+ do
{
- len--; /* C arrays are 0-based. */
- if (line[len] == '\n' && line[len - 1] == '}')
+ alarm (timeout);
+ if (fgets (buffer, sizeof (buffer), fp) == NULL)
+ util_quit (0); /* Logout. */
+ alarm (0);
+
+ len = strlen (buffer);
+ /* If we were in a litteral substract. We have to do it since the CR
+ is part of the count in a literal. */
+ if (number)
+ number -= len;
+
+ /* Remove CR. */
+ if (len > 2 && buffer[len - 1] == '\n')
{
- while (len && line[len] != '{') len--;
- if (line [len] == '{')
+ if (buffer[len - 2] == '\r')
{
- char *sp = NULL;
- long number = strtoul (line + len + 1, &sp, 10);
- if (*sp != '+')
- util_send ("+ GO AHEAD\r\n");
- line[len] = '\0';
- while (number > 0)
- {
- char *literal = imap4d_readline (fd);
- size_t n = strlen (literal);
- line = realloc (line, strlen (line) + n + 1);
- strcat (line, literal);
- number -= n;
- free (literal);
- }
+ buffer[len - 2] = '\n';
+ buffer[len - 1] = '\0';
}
}
- }
- return line;
-}
-#endif
-char *
-imap4d_readline (int fd)
-{
- fd_set rfds;
- struct timeval tv;
- char buf[512], *ret = NULL;
- int nread;
- int total = 0;
- int available;
-
- FD_ZERO (&rfds);
- FD_SET (fd, &rfds);
- tv.tv_sec = timeout;
- tv.tv_usec = 0;
+ line = realloc (line, total + len + 1);
+ if (!line)
+ util_quit (ERR_NO_MEM);
+ strcat (line, buffer);
- do
- {
- if (timeout)
- {
- available = select (fd + 1, &rfds, NULL, NULL, &tv);
- if (!available)
- util_quit (1);
- }
- nread = read (fd, buf, sizeof (buf) - 1);
- if (nread < 1)
- util_quit (1);
+ total = strlen (line);
- buf[nread] = '\0';
-
- ret = realloc (ret, (total + nread + 1) * sizeof (char));
- if (ret == NULL)
- util_quit (1);
- memcpy (ret + total, buf, nread + 1);
- total += nread;
+ /* Check if the client try to send a literal and we are not already
+ retrieving a litera. */
+ if (number <= 0 && len > 2)
+ {
+ size_t n = total - 1; /* C arrays are 0-based. */
+ if (line[n] == '\n' && line[n - 1] == '}')
+ {
+ while (n && line[n] != '{') n--;
+ if (line [n] == '{')
+ {
+ char *sp = NULL;
+ /* Truncate where the literal number was. */
+ line[n] = '\0';
+ number = strtoul (line + n + 1, &sp, 10);
+ /* Client can ask for non synchronise literal,
+ if a '+' is append to the octet count. */
+ if (*sp != '+')
+ util_send ("+ GO AHEAD\r\n");
+ }
+ }
+ }
}
- while (memchr (buf, '\n', nread) == NULL);
-
- /* Nuke CR'\r' */
- for (nread = total; nread > 0; nread--)
- if (ret[nread] == '\r' || ret[nread] == '\n')
- ret[nread] = '\0';
- return ret;
+ while (number > 0);
+ return line;
}
int
@@ -435,6 +422,7 @@ util_do_command (char *prompt)
char *sp = NULL, *tag, *cmd;
struct imap4d_command *command;
static struct imap4d_command nullcommand;
+ size_t len;
tag = util_getword (prompt, &sp);
cmd = util_getword (NULL, &sp);
@@ -462,6 +450,9 @@ util_do_command (char *prompt)
}
command->tag = tag;
+ len = strlen (sp);
+ if (len && sp[len - 1] == '\n')
+ sp[len - 1] = '\0';
return command->func (command, sp);
}
@@ -487,8 +478,17 @@ util_start (char *tag)
void
util_quit (int err)
{
- if (err)
- util_out (RESP_BYE, "Server terminating");
+ switch (err)
+ {
+ case ERR_NO_OFILE:
+ /*util_out (RESP_BYE, "Server terminating dead socket."); */
+ break;
+ case ERR_NO_MEM:
+ util_out (RESP_BYE, "Server terminating no more ressources.");
+ break;
+ default:
+ util_out (RESP_BYE, "Server terminating");
+ }
exit (err);
}
@@ -535,7 +535,7 @@ sc2string (int rc)
}
static int
-add2set (int **set, int *n, unsigned long val, size_t max)
+add2set (size_t **set, int *n, unsigned long val, size_t max)
{
int *tmp;
if (val == 0 || val > max
diff --git a/include/mailutils/header.h b/include/mailutils/header.h
index e498958e1..41691effa 100644
--- a/include/mailutils/header.h
+++ b/include/mailutils/header.h
@@ -34,39 +34,43 @@
extern "C" {
#endif
-#define MU_HEADER_UNIX_FROM "From "
-#define MU_HEADER_RETURN_PATH "Return-Path"
-#define MU_HEADER_RECEIVED "Received"
-#define MU_HEADER_DATE "Date"
-#define MU_HEADER_FROM "From"
-#define MU_HEADER_SENDER "Sender"
-#define MU_HEADER_RESENT_FROM "Resent-From"
-#define MU_HEADER_SUBJECT "Subject"
-#define MU_HEADER_SENDER "Sender"
-#define MU_HEADER_RESENT_SENDER "Resent-SENDER"
-#define MU_HEADER_TO "To"
-#define MU_HEADER_RESENT_TO "Resent-To"
-#define MU_HEADER_CC "Cc"
-#define MU_HEADER_RESENT_CC "Resent-Cc"
-#define MU_HEADER_BCC "Bcc"
-#define MU_HEADER_RESENT_BCC "Resent-Bcc"
-#define MU_HEADER_REPLY_TO "Reply-To"
-#define MU_HEADER_RESENT_REPLY_TO "Resent-Reply-To"
-#define MU_HEADER_MESSAGE_ID "Message-ID"
-#define MU_HEADER_RESENT_MESSAGE_ID "Resent-Message-ID"
-#define MU_HEADER_IN_REPLY_TO "In-Reply-To"
-#define MU_HEADER_REFERENCE "Reference"
-#define MU_HEADER_ENCRYPTED "Encrypted"
-#define MU_HEADER_PRECEDENCE "Precedence"
-#define MU_HEADER_STATUS "Status"
-#define MU_HEADER_CONTENT_LENGTH "Content-Length"
-#define MU_HEADER_CONTENT_LANGUAGE "Content-Language"
-#define MU_HEADER_CONTENT_ENCODING "Content-transfer-encoding"
-#define MU_HEADER_CONTENT_TYPE "Content-Type"
-#define MU_HEADER_MIME_VERSION "MIME-Version"
-#define MU_HEADER_X_UIDL "X-UIDL"
-#define MU_HEADER_X_UID "X-UID"
-#define MU_HEADER_X_IMAPBASE "X-IMAPbase"
+#define MU_HEADER_UNIX_FROM "From "
+#define MU_HEADER_RETURN_PATH "Return-Path"
+#define MU_HEADER_RECEIVED "Received"
+#define MU_HEADER_DATE "Date"
+#define MU_HEADER_FROM "From"
+#define MU_HEADER_SENDER "Sender"
+#define MU_HEADER_RESENT_FROM "Resent-From"
+#define MU_HEADER_SUBJECT "Subject"
+#define MU_HEADER_SENDER "Sender"
+#define MU_HEADER_RESENT_SENDER "Resent-SENDER"
+#define MU_HEADER_TO "To"
+#define MU_HEADER_RESENT_TO "Resent-To"
+#define MU_HEADER_CC "Cc"
+#define MU_HEADER_RESENT_CC "Resent-Cc"
+#define MU_HEADER_BCC "Bcc"
+#define MU_HEADER_RESENT_BCC "Resent-Bcc"
+#define MU_HEADER_REPLY_TO "Reply-To"
+#define MU_HEADER_RESENT_REPLY_TO "Resent-Reply-To"
+#define MU_HEADER_MESSAGE_ID "Message-ID"
+#define MU_HEADER_RESENT_MESSAGE_ID "Resent-Message-ID"
+#define MU_HEADER_IN_REPLY_TO "In-Reply-To"
+#define MU_HEADER_REFERENCE "Reference"
+#define MU_HEADER_ENCRYPTED "Encrypted"
+#define MU_HEADER_PRECEDENCE "Precedence"
+#define MU_HEADER_STATUS "Status"
+#define MU_HEADER_CONTENT_LENGTH "Content-Length"
+#define MU_HEADER_CONTENT_LANGUAGE "Content-Language"
+#define MU_HEADER_CONTENT_TRANSFER_ENCODING "Content-transfer-encoding"
+#define MU_HEADER_CONTENT_ID "Content-ID"
+#define MU_HEADER_CONTENT_TYPE "Content-Type"
+#define MU_HEADER_CONTENT_DESCRIPTION "Content-Description"
+#define MU_HEADER_CONTENT_DISPOSITION "Content-Disposition"
+#define MU_HEADER_CONTENT_MD5 "Content-MD5"
+#define MU_HEADER_MIME_VERSION "MIME-Version"
+#define MU_HEADER_X_UIDL "X-UIDL"
+#define MU_HEADER_X_UID "X-UID"
+#define MU_HEADER_X_IMAPBASE "X-IMAPbase"
/* Mime support header attribute */
diff --git a/include/mailutils/parse822.h b/include/mailutils/parse822.h
index 0f93df399..97a49c4c9 100644
--- a/include/mailutils/parse822.h
+++ b/include/mailutils/parse822.h
@@ -78,6 +78,7 @@ extern int parse822_address __P ((const char** p, const char* e, address_
extern int parse822_route_addr __P ((const char** p, const char* e, address_t* a));
extern int parse822_route __P ((const char** p, const char* e, char** route));
extern int parse822_addr_spec __P ((const char** p, const char* e, address_t* a));
+extern int parse822_unix_mbox __P ((const char** p, const char* e, address_t* a));
extern int parse822_local_part __P ((const char** p, const char* e, char** local_part));
extern int parse822_domain __P ((const char** p, const char* e, char** domain));
extern int parse822_sub_domain __P ((const char** p, const char* e, char** sub_domain));
diff --git a/mailbox/attribute.c b/mailbox/attribute.c
index db1af6fc0..ae481a86c 100644
--- a/mailbox/attribute.c
+++ b/mailbox/attribute.c
@@ -441,7 +441,9 @@ attribute_copy (attribute_t dest, attribute_t src)
{
if (dest == NULL || src == NULL)
return EINVAL;
- memcpy (dest, src, sizeof (*dest));
+ /* Can not be a deep copy. */
+ /* memcpy (dest, src, sizeof (*dest)); */
+ dest->flags = src->flags;
return 0;
}
diff --git a/mailbox/file_stream.c b/mailbox/file_stream.c
index 13a582a4e..f474a9df5 100644
--- a/mailbox/file_stream.c
+++ b/mailbox/file_stream.c
@@ -55,6 +55,13 @@ _file_read (stream_t stream, char *optr, size_t osize,
size_t n;
int err = 0;
+ if (!fs->file)
+ {
+ if (nbytes)
+ *nbytes = 0;
+ return 0;
+ }
+
if (fs->offset != offset)
{
if (fseek (fs->file, offset, SEEK_SET) != 0)
@@ -84,6 +91,13 @@ _file_readline (stream_t stream, char *optr, size_t osize,
size_t n = 0;
int err = 0;
+ if (!fs->file)
+ {
+ if (nbytes)
+ *nbytes = 0;
+ return 0;
+ }
+
if (fs->offset != offset)
{
if (fseek (fs->file, offset, SEEK_SET) != 0)
@@ -117,6 +131,13 @@ _file_write (stream_t stream, const char *iptr, size_t isize,
size_t n;
int err = 0;
+ if (!fs->file)
+ {
+ if (nbytes)
+ *nbytes = 0;
+ return 0;
+ }
+
if (fs->offset != offset)
{
if (fseek (fs->file, offset, SEEK_SET) != 0)
@@ -144,7 +165,7 @@ static int
_file_truncate (stream_t stream, off_t len)
{
struct _file_stream *fs = stream_get_owner (stream);
- if (ftruncate (fileno(fs->file), len) != 0)
+ if (fs->file && ftruncate (fileno(fs->file), len) != 0)
return errno;
return 0;
}
@@ -154,6 +175,12 @@ _file_size (stream_t stream, off_t *psize)
{
struct _file_stream *fs = stream_get_owner (stream);
struct stat stbuf;
+ if (!fs->file)
+ {
+ if (psize)
+ *psize = 0;
+ return 0;
+ }
fflush (fs->file);
if (fstat(fileno(fs->file), &stbuf) == -1)
return errno;
@@ -166,16 +193,24 @@ static int
_file_flush (stream_t stream)
{
struct _file_stream *fs = stream_get_owner (stream);
- return fflush (fs->file);
+ if (fs->file)
+ return fflush (fs->file);
+ return 0;
}
static int
_file_get_fd (stream_t stream, int *pfd)
{
struct _file_stream *fs = stream_get_owner (stream);
+ int status = 0;
if (pfd)
- *pfd = fileno (fs->file);
- return 0;
+ {
+ if (fs->file)
+ *pfd = fileno (fs->file);
+ else
+ status = EINVAL;
+ }
+ return status;
}
static int
diff --git a/mailbox/mailbox.c b/mailbox/mailbox.c
index 30ec25a21..84fa7977d 100644
--- a/mailbox/mailbox.c
+++ b/mailbox/mailbox.c
@@ -261,7 +261,7 @@ int
mailbox_is_updated (mailbox_t mbox)
{
if (mbox == NULL || mbox->_is_updated == NULL)
- return ENOSYS;
+ return 1;
return mbox->_is_updated (mbox);
}
diff --git a/mailbox/parse822.c b/mailbox/parse822.c
index 66c7f739c..668fb608d 100644
--- a/mailbox/parse822.c
+++ b/mailbox/parse822.c
@@ -18,20 +18,9 @@
/*
Things to consider:
- - A group should create an address node for a group, accessable
- with address_get_personal(). Perhaps an is_group() would be
- useful? Test that a zero-length phrase is rejected! So these
- are invalid:
- : a@b ;
- "" : ;
-
- When parsing phrase, should I ignore non-ascii, or replace with a
'?' character? Right now parsing fails.
- - Make domain optional in addr-spec, for parsing address lists
- provided to local mail utilities, but NOT in the addr-spec of a
- route-addr.
-
- Are comments allowed in domain-literals?
- Need a way to mark the *end* of a group. Maybe add a field to _address,
@@ -53,14 +42,12 @@ Things to consider:
gets one address, or just say it is or it isn't in RFC format?
Right now we're strict, we'll see how it goes.
- - parse field names and bodies?
- parse dates?
- parse Received: field?
- test for memory leaks on malloc failure
- fix the realloc, try a struct _string { char* b, size_t sz };
-
- - get example mail from drums, and from the perl code.
+ - get example addresses from rfc2822, and from the perl code.
*/
#ifdef HAVE_CONFIG_H
@@ -610,12 +597,15 @@ int parse822_address_list(address_t* a, const char* s)
int parse822_address(const char** p, const char* e, address_t* a)
{
- /* address = mailbox / group */
+ /* address = mailbox / group / unix-mbox */
int rc;
- if((rc = parse822_mail_box(p, e, a)) == EPARSE)
- rc = parse822_group(p, e, a);
+ if((rc = parse822_mail_box(p, e, a)) == EPARSE) {
+ if((rc = parse822_group(p, e, a)) == EPARSE) {
+ rc = parse822_unix_mbox(p, e, a);
+ }
+ }
return rc;
}
@@ -690,7 +680,9 @@ int parse822_group(const char** p, const char* e, address_t* a)
int parse822_mail_box(const char** p, const char* e, address_t* a)
{
- /* mailbox = addr-spec [ "(" comment ")" ] / [phrase] route-addr
+ /* mailbox =
+ * addr-spec [ "(" comment ")" ] /
+ * [phrase] route-addr
*
* Note: we parse the ancient comment on the right since
* it's such "common practice". :-(
@@ -717,10 +709,6 @@ int parse822_mail_box(const char** p, const char* e, address_t* a)
return rc;
}
- if(rc != EPARSE) {
- *p = save;
- return rc;
- }
/* -> phrase route-addr */
{
@@ -732,17 +720,23 @@ int parse822_mail_box(const char** p, const char* e, address_t* a)
return rc;
}
- if((rc = parse822_route_addr(p, e, a))) {
+ if((rc = parse822_route_addr(p, e, a)) == EOK) {
+ /* add the phrase */
+ (*a)->personal = phrase;
+
+ return EOK;
+ } else if(rc != EPARSE) {
+ /* some internal error, fail out */
*p = save;
str_free(&phrase);
return rc;
}
+ *p = save;
- /* add the phrase */
- (*a)->personal = phrase;
+ return rc;
}
- return EOK;
+ return rc;
}
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)
return rc;
}
+int parse822_unix_mbox(const char** p, const char* e, address_t* a)
+{
+ /* unix-mbox = atom */
+
+ const char* save = *p;
+ char* mbox = 0;
+ int rc;
+
+ parse822_skip_comments(p, e);
+
+ rc = parse822_atom(p, e, &mbox);
+
+ if(!rc) {
+ rc = fill_mb(a, 0, 0, mbox, 0);
+ }
+
+ if(rc) {
+ *p = save;
+ str_free(&mbox);
+ }
+ return rc;
+}
+
int parse822_local_part(const char** p, const char* e, char** local_part)
{
/* local-part = word *("." word)

Return to:

Send suggestions and report system problems to the System administrator.