Commit 43ba0c68 43ba0c68726d41135916aaaf9f4dfffdb56af872 by Alain Magloire

Implemented UID fetch BODYSTRUCTURE and multiple access to mailbox via IMAP

1 parent 33825193
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
......
......@@ -23,3 +23,6 @@ EXTRA_DIST = \
url.texi \
version.texi
ex-address.texi: ../examples/addr.c
sed -es/{/@{/g -e s/}/@}/g < $< > $@
......
@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
......
......@@ -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
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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);
}
......
......@@ -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 []));
......
......@@ -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");
}
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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
......
/* 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;
}
......@@ -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);
}
......
......@@ -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
......
......@@ -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 */
......
......@@ -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));
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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)
......