Commit efe54c6d efe54c6d45fc25459febc395e57588eb46580bee by Alain Magloire

Finally took time to put the code in from Jakob first draft, in

an email excerpt:
states is the valid states for a command (eg. LOGIN is only valid in
non-authenticated state, SELECT is valid in authenticated or
selected). success is the state to enter when the command completes
successfully (STATE_NONE means no change) and failure is the state to
enter when the command fails.

The fetch code is getting close to completion! ye!
1 parent a912fe08
2001-04-18 Alain Magloire
Finally took time to put the code in from Jakob first draft, in
an email excerpt:
states is the valid states for a command (eg. LOGIN is only valid in
non-authenticated state, SELECT is valid in authenticated or
selected). success is the state to enter when the command completes
successfully (STATE_NONE means no change) and failure is the state to
enter when the command fails.
* imap4d/*.c: All the commands check there state.
* imap4d/fetch.c: Cleanup the fetch code, and broke
the fetch_operation() routine in multiple routines.
(fetch_message): New function.
(fetch_header): Likewised
(fetch_content): Likewised
(fetch_io): Likewised
(fetch_header_fields): Likewised
(fetch_header_fields_not): Likewised
(fetch_send_address): Likewised
* mailbox/header.c: Some functions were usefull while
programming the imap server, put them here.
(header_aget_value): New function.
(header_aget_field_name): New function.
(header_aget_field_value): New function.
* mailbox/memory_stream.c: New file, implemented a
malloc() buffer that you can access via the stream interface.
* mailbox/file_stream.c: Remove spurious checks.
* mailbox/mapfile_stream.c: Remove spurious checks.
(_mapfile_read): check if there is no newline left.
2001-04-16 Alain Magloire
To get things to compile on Solaris, change configure to check
......
......@@ -72,16 +72,20 @@ MIME-Version
@end deftypefun
@deftypefun int header_get_value (header_t @var{hdr}, const char *fn, char *fv, size_t len, size_t *n)
@deftypefun int header_get_value (header_t @var{hdr}, const char *@var{fn}, char *@var{fv}, size_t @var{len}, size_t *@var{n})
Value of field-name @var{fn} is returned in buffer @var{fv} of size @var{len}.
The number of bytes written is put in @var{n}.
@end deftypefun
@deftypefun int header_aget_value (header_t @var{hdr}, const char *@var{fn}, char **@var{fv})
The value is allocated.
@end deftypefun
@deftypefun int header_get_stream (header_t @var{hdr}, stream_t *@var{pstream})
@end deftypefun
@deftypefun int header_size (header_t @var{hdr}, size_t *@var{size})
@deftypefun int header_set_size (header_t @var{hdr}, size_t *@var{size})
@end deftypefun
@deftypefun int header_lines (header_t @var{hdr}, size_t *@var{lpines})
@deftypefun int header_set_lines (header_t @var{hdr}, size_t *@var{lpines})
@end deftypefun
......
......@@ -24,5 +24,7 @@
int
imap4d_append (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not implemented");
}
......
......@@ -24,5 +24,7 @@
int
imap4d_authenticate (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Command not supported");
}
......
......@@ -20,6 +20,8 @@
int
imap4d_capability (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
util_out (RESP_NONE, "CAPABILITY IMAP4rev1");
return util_finish (command, RESP_OK, "Completed");
}
......
......@@ -26,5 +26,7 @@
int
imap4d_check (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_OK, "Completed");
}
......
......@@ -25,14 +25,11 @@ imap4d_close (struct imap4d_command *command, char *arg)
{
/* FIXME: Check args. */
/* FIXME: Check state and if they selected. */
/* FIXME: state = AUTHENTICATE. */
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
/* FIXME: Check and report errors. */
mailbox_expunge (mbox);
mailbox_close (mbox);
mailbox_destroy (&mbox);
/* FIXME: state = Not selected. */
return util_finish (command, RESP_OK, "Completed");
}
......
......@@ -19,29 +19,29 @@
struct imap4d_command imap4d_command_table [] =
{
{ "CAPABILITY", imap4d_capability, STATE_ALL, STATE_NONE, STATE_NONE },
{ "NOOP", imap4d_noop, STATE_ALL, STATE_NONE, STATE_NONE },
{ "LOGOUT", imap4d_logout, STATE_ALL, STATE_LOGOUT, STATE_NONE },
{ "AUTHENTICATE", imap4d_authenticate, STATE_NONAUTH, STATE_NONE, STATE_AUTH },
{ "LOGIN", imap4d_login, STATE_NONAUTH, STATE_NONE, STATE_AUTH },
{ "SELECT", imap4d_select, STATE_AUTH | STATE_SEL, STATE_AUTH, STATE_SEL },
{ "EXAMINE", imap4d_examine, STATE_AUTH | STATE_SEL, STATE_AUTH, STATE_SEL },
{ "CREATE", imap4d_create, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "DELETE", imap4d_delete, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "RENAME", imap4d_rename, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "SUBSCRIBE", imap4d_subscribe, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "UNSUBSCRIBE", imap4d_unsubscribe, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "LIST", imap4d_list, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "LSUB", imap4d_lsub, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "STATUS", imap4d_status, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "APPEND", imap4d_append, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE },
{ "CHECK", imap4d_check, STATE_SEL, STATE_NONE, STATE_NONE },
{ "CLOSE", imap4d_close, STATE_SEL, STATE_AUTH, STATE_AUTH },
{ "EXPUNGE", imap4d_expunge, STATE_SEL, STATE_NONE, STATE_NONE },
{ "SEARCH", imap4d_search, STATE_SEL, STATE_NONE, STATE_NONE },
{ "FETCH", imap4d_fetch, STATE_SEL, STATE_NONE, STATE_NONE },
{ "STORE", imap4d_store, STATE_SEL, STATE_NONE, STATE_NONE },
{ "COPY", imap4d_copy, STATE_SEL, STATE_NONE, STATE_NONE },
{ "UID", imap4d_uid, STATE_SEL, STATE_NONE, STATE_NONE },
{ 0, 0, 0}
{ "CAPABILITY", imap4d_capability, STATE_ALL, STATE_NONE, STATE_NONE, NULL },
{ "NOOP", imap4d_noop, STATE_ALL, STATE_NONE, STATE_NONE, NULL },
{ "LOGOUT", imap4d_logout, STATE_ALL, STATE_LOGOUT, STATE_NONE, NULL },
{ "AUTHENTICATE", imap4d_authenticate, STATE_NONAUTH, STATE_NONE, STATE_AUTH, NULL },
{ "LOGIN", imap4d_login, STATE_NONAUTH, STATE_NONE, STATE_AUTH, NULL },
{ "SELECT", imap4d_select, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_SEL, NULL },
{ "EXAMINE", imap4d_examine, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_SEL, NULL },
{ "CREATE", imap4d_create, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "DELETE", imap4d_delete, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "RENAME", imap4d_rename, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "SUBSCRIBE", imap4d_subscribe, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "UNSUBSCRIBE", imap4d_unsubscribe, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "LIST", imap4d_list, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "LSUB", imap4d_lsub, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "STATUS", imap4d_status, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "APPEND", imap4d_append, STATE_AUTH | STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "CHECK", imap4d_check, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "CLOSE", imap4d_close, STATE_SEL, STATE_AUTH, STATE_AUTH, NULL },
{ "EXPUNGE", imap4d_expunge, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "SEARCH", imap4d_search, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "FETCH", imap4d_fetch, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "STORE", imap4d_store, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "COPY", imap4d_copy, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ "UID", imap4d_uid, STATE_SEL, STATE_NONE, STATE_NONE, NULL },
{ NULL, 0, 0, 0, 0, NULL }
};
......
......@@ -24,5 +24,7 @@
int
imap4d_copy (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Command not supported");
}
......
......@@ -24,5 +24,7 @@
int
imap4d_create (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Command not supported");
}
......
......@@ -24,5 +24,7 @@
int
imap4d_delete (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Command not supported");;
}
......
......@@ -24,5 +24,7 @@
int
imap4d_examine (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return imap4d_select0 (command, arg, MU_STREAM_READ);
}
......
......@@ -25,11 +25,12 @@ int
imap4d_expunge (struct imap4d_command *command, char *arg)
{
char *sp = NULL;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
if (util_getword (arg, &sp))
return util_finish (command, RESP_NO, "Too many args");
/* FIXME: Check state, check for errors. */
/* FIXME: check for errors. */
mailbox_expunge (mbox);
return util_finish (command, RESP_OK, "Completed");
}
......
......@@ -16,6 +16,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "imap4d.h"
#include <ctype.h>
/* This will suck, too.
Alain: Yes it does. */
......@@ -31,59 +32,68 @@
["<" number "." nz_number ">"]
*/
static int fetch_all (struct imap4d_command *, char*);
static int fetch_full (struct imap4d_command *, char*);
static int fetch_fast (struct imap4d_command *, char*);
static int fetch_envelope (struct imap4d_command *, char*);
static int fetch_flags (struct imap4d_command *, char*);
static int fetch_internaldate (struct imap4d_command *, char*);
static int fetch_rfc822_header (struct imap4d_command *, char*);
static int fetch_rfc822_size (struct imap4d_command *, char*);
static int fetch_rfc822_text (struct imap4d_command *, char*);
static int fetch_rfc822 (struct imap4d_command *, char*);
static int fetch_bodystructure (struct imap4d_command *, char*);
static int fetch_body_peek (struct imap4d_command *, char*);
static int fetch_body (struct imap4d_command *, char*);
static int fetch_uid (struct imap4d_command *, char*);
static int fetch_send_address (char *addr);
static int fetch_operation (size_t, char *, int);
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 [] =
{
#define F_ALL 0
{"ALL", fetch_all},
{"ALL", fetch_all, 0, 0, 0, NULL},
#define F_FULL 1
{"FULL", fetch_full},
{"FULL", fetch_full, 0, 0, 0, NULL},
#define F_FAST 2
{"FAST", fetch_fast},
{"FAST", fetch_fast, 0, 0, 0, NULL},
#define F_ENVELOPE 3
{"ENVELOPE", fetch_envelope},
{"ENVELOPE", fetch_envelope, 0, 0, 0, NULL},
#define F_FLAGS 4
{"FLAGS", fetch_flags},
{"FLAGS", fetch_flags, 0, 0, 0, NULL},
#define F_INTERNALDATE 5
{"INTERNALDATE", fetch_internaldate},
{"INTERNALDATE", fetch_internaldate, 0, 0, 0, NULL},
#define F_RFC822_HEADER 6
{"RFC822.HEADER", fetch_rfc822_header},
{"RFC822.HEADER", fetch_rfc822_header, 0, 0, 0, NULL},
#define F_RFC822_SIZE 7
{"RFC822.SIZE", fetch_rfc822_size},
{"RFC822.SIZE", fetch_rfc822_size, 0, 0, 0, NULL},
#define F_RFC822_TEXT 8
{"RFC822.TEXT", fetch_rfc822_text},
{"RFC822.TEXT", fetch_rfc822_text, 0, 0, 0, NULL},
#define F_RFC822 9
{"RFC822", fetch_rfc822},
{"RFC822", fetch_rfc822, 0, 0, 0, NULL},
#define F_BODYSTRUCTURE 10
{"BODYSTRUCTURE", fetch_bodystructure},
{"BODYSTRUCTURE", fetch_bodystructure, 0, 0, 0, NULL},
#define F_BODY_PEEK 11
{"BODY.PEEK", fetch_body_peek},
{"BODY.PEEK", fetch_body_peek, 0, 0, 0, NULL},
#define F_BODY 12
{"BODY", fetch_body},
{"BODY", fetch_body, 0, 0, 0, NULL},
#define F_UID 13
{"UID", fetch_uid},
{ 0, 0},
{"UID", fetch_uid, 0, 0, 0, NULL},
{ NULL, 0, 0, 0, 0, NULL}
};
/* NOTE: the states field in the command structure is use to as a place
holder for the message number. */
/* 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)
{
......@@ -97,6 +107,9 @@ imap4d_fetch (struct imap4d_command *command, char *arg)
struct imap4d_command *fcmd;
char item[32];
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
msgset = util_getword (arg, &sp);
if (!msgset)
return util_finish (command, RESP_BAD, "Too few args");
......@@ -169,71 +182,14 @@ fetch_fast (struct imap4d_command *command, char *arg)
return 0;
}
static int
fetch_send_address (char *addr)
{
address_t address;
size_t i, count = 0;
if (*addr == '\0')
{
util_send ("NIL");
return 0;
}
address_create (&address, addr);
address_get_count (address, &count);
util_send ("(", count);
for (i = 1; i <= count; i++)
{
char buf[128];
char *at;
size_t len = 0;
util_send ("(");
*buf = '\0';
address_get_personal (address, 1, buf, sizeof (buf), NULL);
if (*buf == '\0')
util_send ("NIL ");
else
util_send ("\"%s\" ", buf);
/* FIXME: Source route. */
util_send ("NIL ", buf);
*buf = '\0';
address_get_email (address, 1, buf, sizeof (buf), &len);
if (*buf == '\0')
strcpy (buf, "NIL");
at = memchr (buf, '@', len);
if (at)
{
*at = '\0';
at++;
util_send ("\"%s\" \"%s\"", buf, at);
}
else
util_send ("\"%s\" NIL", buf);
util_send (")");
}
util_send (")");
return 0;
}
/* Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To,
and Message-Id. */
/* FIXME, FIXME:
- incorrect DATE
- address not the correct format
- strings change to literals when detecting '"'
*/
/* FIXME: - strings change to literals when detecting '"' */
static int
fetch_envelope (struct imap4d_command *command, char *arg)
{
char buffer[512];
char from[128];
char *buffer;
char *from;
header_t header = NULL;
message_t msg = NULL;
......@@ -242,68 +198,68 @@ fetch_envelope (struct imap4d_command *command, char *arg)
util_send ("%s(", command->name);
/* FIXME: Incorrect Date. */
*buffer = '\0';
header_get_value (header, "Date", buffer, sizeof (buffer), NULL);
header_aget_value (header, "Date", &buffer);
if (*buffer == '\0')
util_send ("NIL");
else
util_send ("\"%s\"", buffer);
free (buffer);
util_send (" ");
/* Subject. */
*buffer = '\0';
header_get_value (header, "Subject", buffer, sizeof (buffer), NULL);
header_aget_value (header, "Subject", &buffer);
if (*buffer == '\0')
util_send ("NIL");
else
util_send ("\"%s\"", buffer);
free (buffer);
util_send (" ");
/* From. */
*from = '\0';
header_get_value (header, "From", from, sizeof (from), NULL);
header_aget_value (header, "From", &from);
fetch_send_address (from);
util_send (" ");
/* Note that the server MUST default the reply-to and sender fields from
the from field; a client is not expected to know to do this. */
*buffer = '\0';
header_get_value (header, "Sender", buffer, sizeof (buffer), NULL);
the From field; a client is not expected to know to do this. */
header_aget_value (header, "Sender", &buffer);
fetch_send_address ((*buffer == '\0') ? from : buffer);
free (buffer);
util_send (" ");
*buffer = '\0';
header_get_value (header, "Reply-to", buffer, sizeof (buffer), NULL);
header_aget_value (header, "Reply-to", &buffer);
fetch_send_address ((*buffer == '\0') ? from : buffer);
free (buffer);
util_send (" ");
*buffer = '\0';
header_get_value (header, "To", buffer, sizeof (buffer), NULL);
header_aget_value (header, "To", &buffer);
fetch_send_address (buffer);
free (buffer);
util_send (" ");
*buffer = '\0';
header_get_value (header, "Cc", buffer, sizeof (buffer), NULL);
header_aget_value (header, "Cc", &buffer);
fetch_send_address (buffer);
free (buffer);
util_send (" ");
*buffer = '\0';
header_get_value (header, "Bcc", buffer, sizeof (buffer), NULL);
header_aget_value (header, "Bcc", &buffer);
fetch_send_address (buffer);
free (buffer);
util_send (" ");
*buffer = '\0';
header_get_value (header, "In-Reply-To", buffer, sizeof (buffer), NULL);
header_aget_value (header, "In-Reply-To", &buffer);
fetch_send_address (buffer);
free (buffer);
util_send (" ");
*buffer = '\0';
header_get_value (header, "Message-ID", buffer, sizeof (buffer), NULL);
header_aget_value (header, "Message-ID", &buffer);
if (*buffer == '\0')
util_send ("NIL");
else
util_send ("\"%s\"", buffer);
free (buffer);
free (from);
util_send (")");
return 0;
}
......@@ -320,8 +276,10 @@ fetch_flags (struct imap4d_command *command, char *arg)
util_send ("%s (", command->name);
if (attribute_is_deleted (attr))
util_send (" \\Deleted");
if (attribute_is_read (attr))
util_send (" \\Read");
if (attribute_is_answered (attr))
util_send (" \\Answered");
if (attribute_is_flagged (attr))
util_send (" \\Flagged");
if (attribute_is_seen (attr))
util_send (" \\Seen");
if (attribute_is_draft (attr))
......@@ -354,6 +312,7 @@ static int
fetch_rfc822_header (struct imap4d_command *command, char *arg)
{
char buffer[16];
(void)arg;
util_send ("%s ", command->name);
strcpy (buffer, "[HEADER]");
fetch_operation (command->states, buffer, 1);
......@@ -384,6 +343,7 @@ fetch_rfc822_size (struct imap4d_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);
message_size (msg, &size);
message_lines (msg, &lines);
......@@ -453,37 +413,28 @@ fetch_bodystructure (struct imap4d_command *command, char *arg)
}
/* An alternate form of BODY that does not implicitly set the \Seen flag. */
static int
fetch_body_peek (struct imap4d_command *command, char *arg)
{
struct imap4d_command c_body = fetch_command_table[F_BODY];
c_body.states = command->states;
return fetch_body (&c_body, arg);
}
/* FIXME: send notificaton if seen attribute is set? */
/* FIXME: partial offset not done. */
/* FIXME: HEADER.FIELDS not done. */
/* FIXME: HEADER.FIELDS.NOT not done. */
static int
fetch_body (struct imap4d_command *command, char *arg)
{
struct imap4d_command c_body_p = fetch_command_table[F_BODY_PEEK];
util_send ("%s ", command->name);
if (strncasecmp (arg, ".PEEK", 5) == 0)
c_body_p.states = command->states;
/* It's BODY set the message as seen */
if (*arg == '[')
{
arg += strlen (".PEEK");
}
else if (*arg == '[')
{
attribute_t attr = NULL;
message_t msg = NULL;
attribute_t attr = NULL;
mailbox_get_message (mbox, command->states, &msg);
message_get_attribute (msg, &attr);
attribute_set_seen (attr);
}
else if (strncasecmp (arg,".PEEK", 5) == 0)
{
/* Move pass the .peek */
arg += strlen (".PEEK");
while (isspace ((unsigned)*arg))
arg++;
}
else if (*arg != '[' && *arg != '.')
{
struct imap4d_command c_bs = fetch_command_table[F_BODYSTRUCTURE];
......@@ -493,19 +444,22 @@ fetch_body (struct imap4d_command *command, char *arg)
util_send (" ()");
return 0;
}
return fetch_body_peek (&c_body_p, arg);
}
static int
fetch_body_peek (struct imap4d_command *command, char *arg)
{
util_send ("%s ", command->name);
fetch_operation (command->states, arg, 0);
return 0;
}
/* FIXME: "\n" -->"\r\n" is not handle right still it will not be as messy. */
/* FIXME: Code bloat move some stuff in routines, to be reuse. */
/* FIXME: partial fetch <x.y> still not handle. */
static int
fetch_operation (size_t msgno, char *arg, int silent)
{
off_t offset = 0;
size_t limit = -1; /* No limit. */
unsigned long start = ULONG_MAX;
unsigned long end = ULONG_MAX; /* No limit. */
message_t msg = NULL;
char *partial = strchr (arg, '<');
......@@ -516,267 +470,388 @@ fetch_operation (size_t msgno, char *arg, int silent)
draconian check. */
*partial = '\0';
partial++;
offset = strtoul (partial, &partial, 10);
start = strtoul (partial, &partial, 10);
if (*partial == '.')
{
partial++;
limit = strtoul (partial, NULL, 10);
end = strtoul (partial, NULL, 10);
}
partial = alloca (64);
snprintf (partial, 64, "<%lu>", (unsigned long)offset);
}
else
partial = (char *)"";
mailbox_get_message (mbox, msgno, &msg);
if (strncasecmp (arg, "[]", 2) == 0)
/* Retreive the sub message. */
for (arg++; isdigit ((unsigned)*arg) || *arg == '.'; arg++)
{
stream_t stream = NULL;
char buffer[512];
size_t size = 0, lines = 0, n = 0;
off_t off = 0;
message_get_stream (msg, &stream);
message_size (msg, &size);
message_lines (msg, &lines);
if (!silent)
util_send ("%s", arg);
util_send ("%s {%u}\r\n", partial, size + lines);
while (stream_readline (stream, buffer, sizeof (buffer), off, &n) == 0
&& n > 0)
unsigned long j = strtoul (arg, &arg, 10);
int status;
/* Technicaly I should check errno too. */
if (j == 0 || j == ULONG_MAX)
break;
status = message_get_part (msg, j, &msg);
if (status != 0)
{
/* Nuke the trainline newline. */
if (buffer[n - 1] == '\n')
buffer[n - 1] = '\0';
util_send ("%s\r\n", buffer);
off += n;
util_send ("\"\"");
return 0;
}
}
else if (strncasecmp (arg, "[HEADER]", 8) == 0
|| strncasecmp (arg, "[MIME]", 6) == 0)
/* Choose the right fetch attribute. */
if (*arg == ']')
{
if (!silent)
util_send ("[]");
fetch_message (msg, start, end);
}
else if (strncasecmp (arg, "HEADER]", 7) == 0
|| strncasecmp (arg, "MIME]", 5) == 0)
{
header_t header = NULL;
stream_t stream = NULL;
char buffer[512];
size_t size = 0, lines = 0, n = 0;
off_t off = 0;
message_get_header (msg, &header);
header_size (header, &size);
header_lines (header, &lines);
if (!silent)
{
util_upper (arg);
util_send ("%s", arg);
util_send ("[%s", arg);
}
util_send ("%s {%u}\r\n", partial, size + lines);
header_get_stream (header, &stream);
while (stream_readline (stream, buffer, sizeof (buffer), off, &n) == 0
&& n > 0)
fetch_header (msg, start, end);
}
else if (strncasecmp (arg, "TEXT]", 5) == 0)
{
if (!silent)
util_send ("[TEXT]");
return fetch_content (msg, start, end);
}
else if (strncasecmp (arg, "HEADER.FIELDS.NOT", 17) == 0)
{
arg += 17;
fetch_header_fields_not (msg, arg, start, end);
}
else if (strncasecmp (arg, "HEADER.FIELDS", 13) == 0)
{
arg += 13;
fetch_header_fields (msg, arg, start, end);
}
else
util_send ("\"\"");
return 0;
}
static int
fetch_message (message_t msg, unsigned long start, unsigned long end)
{
stream_t stream = NULL;
size_t size = 0, lines = 0;
message_get_stream (msg, &stream);
message_size (msg, &size);
message_lines (msg, &lines);
if ((size + lines) < end || end == ULONG_MAX)
end = size + lines;
return fetch_io (stream, start, end);
}
static int
fetch_header (message_t msg, unsigned long start, unsigned long end)
{
header_t header = NULL;
stream_t stream = NULL;
size_t size = 0, lines = 0;
message_get_header (msg, &header);
header_size (header, &size);
header_lines (header, &lines);
if ((size + lines) < end || end == ULONG_MAX)
end = size + lines;
header_get_stream (header, &stream);
return fetch_io (stream, start, end);
}
static int
fetch_content (message_t msg, unsigned long start, unsigned long end)
{
body_t body = NULL;
stream_t stream = NULL;
size_t size = 0, lines = 0;
message_get_body (msg, &body);
body_size (body, &size);
body_lines (body, &lines);
if ((size + lines) < end || end == ULONG_MAX)
end = size + lines;
body_get_stream (body, &stream);
return fetch_io (stream, start, end);
}
static int
fetch_io (stream_t stream, unsigned long start, unsigned long end)
{
stream_t rfc = NULL;
char buffer[1024];
size_t n = 0;
size_t total = 0;
filter_create (&rfc, stream, "rfc822", MU_FILTER_ENCODE, MU_STREAM_READ);
if (start == ULONG_MAX)
{
start = 0;
util_send ("{%u}\r\n", end);
}
else
util_send ("<%lu> {%u}\r\n", start , end);
while (start < end &&
stream_read (rfc, buffer, sizeof (buffer), start, &n) == 0
&& n > 0)
{
start += n;
total += n;
if (total > end)
{
/* Nuke the trainline newline. */
if (buffer[n - 1] == '\n')
buffer[n - 1] = '\0';
util_send ("%s\r\n", buffer);
off += n;
size_t diff = n - (total - end);
buffer[diff] = '\0';
}
util_send ("%s", buffer);
}
else if (strncasecmp (arg, "[HEADER.FIELDS.NOT", 18) == 0)
{
char **array = NULL;
size_t array_len = 0;
char *buffer = NULL;
size_t total = 0;
return 0;
}
arg += 18;
static int
fetch_header_fields (message_t msg, char *arg, unsigned long start,
unsigned long end)
{
char *buffer = NULL;
char **array = NULL;
size_t array_len = 0;
size_t off = 0;
size_t lines = 0;
stream_t stream = NULL;
int status;
/* Save the field we want to ignore. */
status = memory_stream_create (&stream);
if (status != 0)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
/* Save the fields in an array. */
{
char *field;
char *sp = NULL;
for (;(field = strtok_r (arg, " ()]\r\n", &sp));
arg = NULL, array_len++)
{
char *field;
char *sp = NULL;
for (;(field = strtok_r (arg, " ()]\r\n", &sp));
arg = NULL, array_len++)
array = realloc (array, (array_len + 1) * sizeof (*array));
if (!array)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
array[array_len] = field;
}
}
/* Get the header values. */
{
size_t j;
header_t header = NULL;
message_get_header (msg, &header);
for (j = 0; j < array_len; j++)
{
char *value;
size_t n = 0;
header_aget_value (header, array[j], &value);
if (*value == '\0')
continue;
n = asprintf (&buffer, "%s: %s\n", array[j], value);
status = stream_write (stream, buffer, n, off, &n);
off += n;
lines++;
free (value);
free (buffer);
buffer = NULL;
if (status != 0)
{
array = realloc (array, (array_len + 1) * sizeof (*array));
if (!array)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
array[array_len] = field;
free (array);
util_quit (1); /* FIXME: send a "* BYE" to the client. */
}
}
}
/* Headers are always sent with the NL separator. */
stream_write (stream, "\n", 1, off, NULL);
off++;
lines++;
/* Send the command back. */
util_send ("[HEADER.FIELDS");
{
size_t j;
for (j = 0; j < array_len; j++)
{
util_upper (array[j]);
util_send (" \"%s\"", array[j]);
}
util_send ("]");
}
if ((off + lines) < end || end == ULONG_MAX)
end = off + lines;
fetch_io (stream, start, end);
if (array)
free (array);
return 0;
}
/* Build the buffer. */
static int
fetch_header_fields_not (message_t msg, char *arg, unsigned long start,
unsigned long end)
{
char **array = NULL;
size_t array_len = 0;
char *buffer = NULL;
size_t off = 0;
size_t lines = 0;
stream_t stream = NULL;
int status;
status = memory_stream_create (&stream);
if (status)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
/* Save the field we want to ignore. */
{
char *field;
char *sp = NULL;
for (;(field = strtok_r (arg, " ()]\r\n", &sp));
arg = NULL, array_len++)
{
size_t i;
header_t header = NULL;
size_t count = 0;
message_get_header (msg, &header);
header_get_field_count (header, &count);
for (i = 1; i <= count; i++)
{
char *name;
char *value ;
size_t ototal;
size_t name_len = 0;
size_t value_len = 0;
size_t ignore = 0;
/* Get the field name. */
header_get_field_name (header, i, NULL, 0, &name_len);
if (name_len == 0)
continue;
name = calloc (name_len + 1, sizeof (*name));
if (!name)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
header_get_field_name (header, i, name, name_len + 1, NULL);
array = realloc (array, (array_len + 1) * sizeof (*array));
if (!array)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
array[array_len] = field;
}
}
/* Build the memory buffer. */
{
size_t i;
header_t header = NULL;
size_t count = 0;
message_get_header (msg, &header);
header_get_field_count (header, &count);
for (i = 1; i <= count; i++)
{
char *name;
char *value ;
size_t n = 0;
size_t ignore = 0;
/* Get the field name. */
status = header_aget_field_name (header, i, &name);
if (status != 0 || *name == '\0')
continue;
/* Should we ignore the field? */
/* Should we ignore the field? */
{
size_t j;
for (j = 0; j < array_len; j++)
{
size_t j;
for (j = 0; j < array_len; j++)
if (strcasecmp (array[j], name) == 0)
{
if (strcasecmp (array[j], name) == 0)
{
ignore = 1;
break;
}
}
if (ignore)
{
free (name);
continue;
ignore = 1;
break;
}
}
if (ignore)
{
free (name);
continue;
}
}
/* Fet the field value. */
header_get_field_value (header, i, NULL, 0, &value_len);
value = calloc (value_len + 1, sizeof (*value));
if (!value)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
header_get_field_value (header, i, value, value_len + 1, NULL);
/* Save the field. */
ototal = name_len + value_len + 4; /* 4 for ": \r\n" */
buffer = realloc (buffer, (ototal + total + 1) * sizeof (*buffer));
if (!buffer)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
snprintf (buffer + total, ototal + 1, "%s: %s\r\n", name, value);
free (value);
free (name);
total += ototal;
header_aget_field_value (header, i, &value);
/* Save the field. */
n = asprintf (&buffer, "%s: %s\n", name, value);
status = stream_write (stream, buffer, n, off, &n);
off += n;
lines++;
free (value);
free (name);
free (buffer);
buffer = NULL;
if (status != 0)
{
free (array);
util_quit (1); /* FIXME: send a "* BYE" to the client. */
}
}
util_send ("[HEADER.FIELDS.NOT");
}
/* Headers are always sent with a NL separator. */
stream_write (stream, "\n", 1, off, NULL);
off++;
lines++;
util_send ("[HEADER.FIELDS.NOT");
{
size_t j;
for (j = 0; j < array_len; j++)
{
size_t j;
for (j = 0; j < array_len; j++)
{
util_upper (array[j]);
util_send (" \"%s\"", array[j]);
}
util_upper (array[j]);
util_send (" \"%s\"", array[j]);
}
util_send ("]%s {%u}\r\n", partial, total + 2);
util_send ("%s\r\n", (buffer) ? buffer : "");
if (buffer)
free (buffer);
if (array)
free (array);
}
else if (strncasecmp (arg, "[HEADER.FIELDS", 14) == 0)
util_send ("]");
}
if ((off + lines) < end || end == ULONG_MAX)
end = off + lines;
fetch_io (stream, start, end);
if (array)
free (array);
return 0;
}
static int
fetch_send_address (char *addr)
{
address_t address;
size_t i, count = 0;
if (*addr == '\0')
{
char *buffer = NULL;
char **array = NULL;
size_t array_len = 0;
size_t total = 0;
util_send ("NIL");
return 0;
}
arg += 14;
address_create (&address, addr);
address_get_count (address, &count);
/* Save the field. */
{
char *field;
char *sp = NULL;
for (;(field = strtok_r (arg, " ()]\r\n", &sp));
arg = NULL, array_len++)
{
array = realloc (array, (array_len + 1) * sizeof (*array));
if (!array)
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
array[array_len] = field;
}
}
util_send ("(", count);
for (i = 1; i <= count; i++)
{
char buf[128];
{
size_t j;
header_t header = NULL;
util_send ("(");
message_get_header (msg, &header);
*buf = '\0';
address_get_personal (address, 1, buf, sizeof (buf), NULL);
if (*buf == '\0')
util_send ("NIL ");
else
util_send ("\"%s\" ", buf);
for (j = 0; j < array_len; j++)
{
size_t ototal;
char *value;
size_t val_len = 0;
*buf = '\0';
address_get_route (address, 1, buf, sizeof (buf), NULL);
if (*buf == '\0')
util_send ("NIL ");
else
util_send ("\"%s\" ", buf);
util_send ("NIL ", buf);
header_get_value (header, array[j], NULL, 0, &val_len);
if (val_len == 0)
continue;
value = calloc (val_len + 1, sizeof (*value));
if (!value)
util_quit (1); /* FIXME: send a "* BYE" to the client. */
header_get_value (header, array[j], value, val_len + 1, NULL);
ototal = strlen (array[j]) + val_len + 4; /* 4 for ": \r\n" */
buffer = realloc (buffer, (ototal + total + 1) * sizeof (*buffer));
if (!buffer)
util_quit (1); /* FIXME: send a "* BYE" to the client. */
snprintf (buffer + total, ototal + 1, "%s: %s\r\n",
array[j], value);
free (value);
total += ototal;
}
}
*buf = '\0';
address_get_local_part (address, 1, buf, sizeof (buf), NULL);
if (*buf == '\0')
util_send ("NIL ");
else
util_send ("\"%s\" ", buf);
util_send ("[HEADER.FIELDS");
{
size_t j;
for (j = 0; j < array_len; j++)
{
util_upper (array[j]);
util_send (" \"%s\"", array[j]);
}
}
util_send ("]%s {%u}\r\n", partial, total + 2);
if (total)
util_send ("%s", buffer);
util_send ("\r\n");
if (buffer)
free (buffer);
if (array)
free (array);
}
else if (strncasecmp (arg, "[TEXT]", 6) == 0)
{
body_t body = NULL;
stream_t stream = NULL;
char buffer[512];
size_t size = 0, lines = 0, n = 0;
off_t off = 0;
message_get_body (msg, &body);
body_size (body, &size);
body_lines (body, &lines);
if (!silent)
util_send ("[TEXT]");
util_send ("%s {%u}\r\n", partial, size + lines);
body_get_stream (body, &stream);
while (stream_readline (stream, buffer, sizeof (buffer), off, &n) == 0
&& n > 0)
{
/* Nuke the trainline newline. */
if (buffer[n - 1] == '\n')
buffer[n - 1] = '\0';
util_send ("%s\r\n", buffer);
off += n;
}
*buf = '\0';
address_get_domain (address, 1, buf, sizeof (buf), NULL);
if (*buf == '\0')
util_send ("NIL ");
else
util_send ("\"%s\" ", buf);
util_send (")");
}
/* else util_send (" Not supported"); */
util_send (")");
return 0;
}
......
......@@ -21,6 +21,7 @@ int *ifile;
FILE *ofile;
unsigned int timeout = 1800; /* RFC2060: 30 minutes, if enable. */
mailbox_t mbox;
int state = STATE_NONAUTH;
static int imap4_mainloop __P ((int, int));
......
......@@ -62,6 +62,8 @@
#include <mailutils/body.h>
#include <mailutils/address.h>
#include <mailutils/registrar.h>
#include <mailutils/filter.h>
#include <mailutils/stream.h>
#ifdef __cplusplus
extern "C" {
......@@ -80,17 +82,17 @@ struct imap4d_command
const char *name;
int (*func) __P ((struct imap4d_command *, char *));
int states;
int success;
int failure;
int success;
char *tag;
};
/* Global variables and constants*/
#define STATE_NONE (1 << 0)
#define STATE_NONAUTH (1 << 1)
#define STATE_AUTH (1 << 2)
#define STATE_SEL (1 << 3)
#define STATE_LOGOUT (1 << 4)
#define STATE_NONE (0)
#define STATE_NONAUTH (1 << 0)
#define STATE_AUTH (1 << 1)
#define STATE_SEL (1 << 2)
#define STATE_LOGOUT (1 << 3)
#define STATE_ALL (STATE_NONE | STATE_NONAUTH | STATE_AUTH | STATE_SEL \
| STATE_LOGOUT)
......@@ -105,7 +107,7 @@ extern struct imap4d_command imap4d_command_table[];
extern FILE *ofile;
extern unsigned int timeout;
extern mailbox_t mbox;
extern unsigned int state;
extern int state;
/* Imap4 commands */
int imap4d_capability __P ((struct imap4d_command *, char *));
......
......@@ -24,5 +24,7 @@
int
imap4d_list (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not supported");
}
......
......@@ -86,6 +86,8 @@ imap4d_login (struct imap4d_command *command, char *arg)
int pamerror;
#endif /* !USE_LIBPAM */
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
username = util_getword (arg, &sp);
pass = util_getword (NULL, &sp);
......
......@@ -25,6 +25,8 @@ int
imap4d_logout (struct imap4d_command *command, char *arg)
{
char *sp = NULL;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
if (util_getword (arg, &sp))
return util_finish (command, RESP_BAD, "Too many args");
util_out (RESP_BYE, "Logging out");
......
......@@ -24,5 +24,7 @@
int
imap4d_lsub (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not supported");
}
......
......@@ -22,6 +22,8 @@ int
imap4d_noop (struct imap4d_command *command, char *arg)
{
char *sp = NULL;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
if (util_getword (arg, &sp))
return util_finish (command, RESP_BAD, "Too many args");
return util_finish (command, RESP_OK, "Completed");
......
......@@ -24,5 +24,7 @@
int
imap4d_rename (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not Supported");
}
......
......@@ -26,5 +26,7 @@
int
imap4d_search (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not supported");
}
......
......@@ -22,6 +22,8 @@
int
imap4d_select (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return imap4d_select0 (command, arg, MU_STREAM_RDWR);
}
......@@ -61,6 +63,7 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
unsigned long uidvalidity = 0;
size_t count = 0, recent = 0, unseen = 0, uidnext = 0;
state = STATE_SEL;
mailbox_uidvalidity (mbox, &uidvalidity);
mailbox_uidnext (mbox, &uidnext);
mailbox_messages_count (mbox, &count);
......
......@@ -27,6 +27,8 @@ imap4d_status (struct imap4d_command *command, char *arg)
char *sp = NULL;
char *mailbox_name;
char *data;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
mailbox_name = util_getword (arg, &sp);
data = util_getword (NULL, &sp);
if (!mailbox_name || !data)
......
......@@ -24,5 +24,7 @@
int
imap4d_store (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not supported");
}
......
......@@ -24,5 +24,7 @@
int
imap4d_subscribe (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not supported");
}
......
......@@ -25,5 +25,7 @@
int
imap4d_uid (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not supported");
}
......
......@@ -24,5 +24,7 @@
int
imap4d_unsubscribe (struct imap4d_command *command, char *arg)
{
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Not supported");
}
......
......@@ -207,6 +207,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
{
char *buf = NULL;
const char *resp;
int new_state;
va_list ap;
va_start (ap, format);
......@@ -216,6 +217,9 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
resp = sc2string (rc);
fprintf (ofile, "%s %s%s %s\r\n", command->tag, resp, command->name, buf);
free (buf);
new_state = (rc == RESP_OK) ? command->success : command->failure;
if (new_state != STATE_NONE)
state = new_state;
return 0;
}
......
......@@ -74,56 +74,70 @@ extern "C" {
struct _header;
typedef struct _header * header_t;
extern int header_create __P ((header_t *, const char *,
size_t, void *));
extern void header_destroy __P ((header_t *, void *));
extern void *header_get_owner __P ((header_t));
extern int header_create __P ((header_t *, const char *,
size_t, void *));
extern void header_destroy __P ((header_t *, void *));
extern void *header_get_owner __P ((header_t));
extern int header_is_modified __P ((header_t));
extern int header_clear_modified __P ((header_t));
extern int header_is_modified __P ((header_t));
extern int header_clear_modified __P ((header_t));
extern int header_get_property __P ((header_t, property_t *));
extern int header_set_property __P ((header_t, property_t, void *));
extern int header_get_property __P ((header_t, property_t *));
extern int header_set_property __P ((header_t, property_t, void *));
extern int header_set_value __P ((header_t, const char *,
extern int header_set_value __P ((header_t, const char *,
const char *, int));
extern int header_set_set_value __P ((header_t, int (*_set_value)
__P ((header_t, const char *,
const char *, int)), void *));
extern int header_get_value __P ((header_t, const char *, char *,
size_t, size_t *));
extern int header_set_get_value __P ((header_t, int (*_get_value)
__P ((header_t, const char *, char *,
size_t, size_t *)), void *));
extern int header_set_get_fvalue __P ((header_t, int (*_get_value)
__P ((header_t, const char *, char *,
size_t, size_t *)), void *));
extern int header_get_field_count __P ((header_t, size_t *));
extern int header_get_field_value __P ((header_t, size_t, char *,
size_t, size_t *));
extern int header_get_field_name __P ((header_t, size_t, char *,
size_t, size_t *));
extern int header_get_stream __P ((header_t, stream_t *));
extern int header_set_stream __P ((header_t, stream_t, void *));
extern int header_size __P ((header_t, size_t *));
extern int header_set_size __P ((header_t, int (*_size)
__P ((header_t, size_t *)), void *));
extern int header_lines __P ((header_t, size_t *));
extern int header_set_lines __P ((header_t,
int (*_lines) __P ((header_t,
size_t *)),
void *));
extern int header_set_fill __P ((header_t,
int (*_fill) __P ((header_t, char *,
size_t, off_t,
extern int header_set_set_value __P ((header_t,
int (*_set_value) __P ((header_t,
const char *,
const char *,
int)),
void *));
extern int header_get_value __P ((header_t, const char *, char *,
size_t, size_t *));
extern int header_aget_value __P ((header_t, const char *, char **));
extern int header_set_get_value __P ((header_t,
int (*_get_value) __P ((header_t,
const char *,
char *,
size_t,
size_t *)),
void *));
extern int header_set_get_fvalue __P ((header_t,
int (*_get_value) __P ((header_t,
const char *,
char *,
size_t,
size_t *)),
void *));
extern int header_get_field_count __P ((header_t, size_t *));
extern int header_get_field_value __P ((header_t, size_t, char *,
size_t, size_t *));
extern int header_aget_field_value __P ((header_t, size_t, char **));
extern int header_get_field_name __P ((header_t, size_t, char *,
size_t, size_t *));
extern int header_aget_field_name __P ((header_t, size_t, char **));
extern int header_get_stream __P ((header_t, stream_t *));
extern int header_set_stream __P ((header_t, stream_t, void *));
extern int header_size __P ((header_t, size_t *));
extern int header_set_size __P ((header_t, int (*_size)
__P ((header_t, size_t *)), void *));
extern int header_lines __P ((header_t, size_t *));
extern int header_set_lines __P ((header_t,
int (*_lines) __P ((header_t,
size_t *)),
void *));
extern int header_set_fill __P ((header_t,
int (*_fill) __P ((header_t, char *,
size_t, off_t,
size_t *)),
void *owner));
void *owner));
#ifdef __cplusplus
}
#endif
......
......@@ -119,11 +119,12 @@ extern int stream_get_state __P ((stream_t, int *pstate));
/* Misc. */
extern int file_stream_create __P ((stream_t *stream));
extern int mapfile_stream_create __P ((stream_t *stream));
extern int memory_stream_create __P ((stream_t *stream));
extern int tcp_stream_create __P ((stream_t *stream));
extern int encoder_stream_create __P ((stream_t *stream, stream_t iostream,
const char *encoding));
extern int decoder_stream_create __P ((stream_t *stream, stream_t iostream,
const char *encoding));
extern int tcp_stream_create __P ((stream_t *stream));
#ifdef __cplusplus
}
......
......@@ -41,6 +41,7 @@ mbx_imap.c \
mbx_mbox.c \
mbx_pop.c \
message.c \
memory_stream.c \
mime.c \
misc.c \
monitor.c \
......
......@@ -41,8 +41,7 @@ static void
_file_destroy (stream_t stream)
{
struct _file_stream *fs = stream_get_owner (stream);
if (fs && fs->file)
if (fs->file)
fclose (fs->file);
free (fs);
}
......@@ -55,9 +54,6 @@ _file_read (stream_t stream, char *optr, size_t osize,
size_t n;
int err = 0;
if (fs == NULL)
return EINVAL;
if (fs->offset != offset)
{
if (fseek (fs->file, offset, SEEK_SET) != 0)
......@@ -87,9 +83,6 @@ _file_readline (stream_t stream, char *optr, size_t osize,
size_t n = 0;
int err = 0;
if (fs == NULL)
return EINVAL;
if (fs->offset != offset)
{
if (fseek (fs->file, offset, SEEK_SET) != 0)
......@@ -123,9 +116,6 @@ _file_write (stream_t stream, const char *iptr, size_t isize,
size_t n;
int err = 0;
if (fs == NULL)
return EINVAL;
if (fs->offset != offset)
{
if (fseek (fs->file, offset, SEEK_SET) != 0)
......@@ -153,9 +143,6 @@ static int
_file_truncate (stream_t stream, off_t len)
{
struct _file_stream *fs = stream_get_owner (stream);
if (fs == NULL)
return EINVAL;
if (ftruncate (fileno(fs->file), len) != 0)
return errno;
return 0;
......@@ -166,9 +153,6 @@ _file_size (stream_t stream, off_t *psize)
{
struct _file_stream *fs = stream_get_owner (stream);
struct stat stbuf;
if (fs == NULL)
return EINVAL;
fflush (fs->file);
if (fstat(fileno(fs->file), &stbuf) == -1)
return errno;
......@@ -181,9 +165,6 @@ static int
_file_flush (stream_t stream)
{
struct _file_stream *fs = stream_get_owner (stream);
if (fs == NULL)
return EINVAL;
return fflush (fs->file);
}
......@@ -191,9 +172,6 @@ static int
_file_get_fd (stream_t stream, int *pfd)
{
struct _file_stream *fs = stream_get_owner (stream);
if (fs == NULL)
return EINVAL;
if (pfd)
*pfd = fileno (fs->file);
return 0;
......@@ -204,9 +182,6 @@ _file_close (stream_t stream)
{
struct _file_stream *fs = stream_get_owner (stream);
int err = 0;
if (fs == NULL)
return EINVAL;
if (fs->file)
{
if (fclose (fs->file) != 0)
......@@ -226,9 +201,6 @@ _file_open (stream_t stream, const char *filename, int port, int flags)
(void)port; /* Ignored. */
if (fs == NULL)
return EINVAL;
if (fs->file)
{
fclose (fs->file);
......
......@@ -189,7 +189,7 @@ rfc822_read0 (filter_t filter, char *buffer, size_t buflen,
rfc822->residue = 0;
}
buffer += nread;
} while (buflen > 0 || !isreadline);
} while (buflen > 0 && !isreadline);
if (isreadline)
*buffer = '\0';
......
......@@ -495,6 +495,25 @@ header_get_value (header_t header, const char *name, char *buffer,
}
int
header_aget_value (header_t header, const char *name, char **pvalue)
{
char *value;
size_t n = 0;
int status = header_get_value (header, name, NULL, 0, &n);
if (status == 0)
{
value = calloc (n + 1, 1);
if (value == NULL)
return ENOMEM;
header_get_value (header, name, value, n + 1, NULL);
*pvalue = value;
}
else
*pvalue = strdup ("");
return 0;
}
int
header_get_field_count (header_t header, size_t *pcount)
{
if (header == NULL)
......@@ -553,6 +572,25 @@ header_get_field_name (header_t header, size_t num, char *buf,
}
int
header_aget_field_name (header_t header, size_t num, char **pvalue)
{
char *value;
size_t n = 0;
int status = header_get_field_name (header, num, NULL, 0, &n);
if (status == 0)
{
value = calloc (n + 1, 1);
if (value == NULL)
return ENOMEM;
header_get_field_name (header, num, value, n + 1, NULL);
*pvalue = value;
}
else
*pvalue = strdup ("");
return 0;
}
int
header_get_field_value (header_t header, size_t num, char *buf,
size_t buflen, size_t *nwritten)
{
......@@ -588,6 +626,25 @@ header_get_field_value (header_t header, size_t num, char *buf,
}
int
header_aget_field_value (header_t header, size_t num, char **pvalue)
{
char *value;
size_t n = 0;
int status = header_get_field_value (header, num, NULL, 0, &n);
if (status == 0)
{
value = calloc (n + 1, 1);
if (value == NULL)
return ENOMEM;
header_get_field_value (header, num, value, n + 1, NULL);
*pvalue = value;
}
else
*pvalue = strdup ("");
return status;
}
int
header_set_lines (header_t header, int (*_lines)
(header_t, size_t *), void *owner)
{
......
......@@ -48,7 +48,7 @@ _mapfile_destroy (stream_t stream)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs && mfs->ptr != MAP_FAILED)
if (mfs->ptr != MAP_FAILED)
{
munmap (mfs->ptr, mfs->size);
close (mfs->fd);
......@@ -61,21 +61,17 @@ _mapfile_read (stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
size_t n;
size_t n = 0;
if (mfs == NULL || mfs->ptr == MAP_FAILED)
if (mfs->ptr == MAP_FAILED)
return EINVAL;
if (offset >= (off_t)mfs->size)
if (offset < (off_t)mfs->size)
{
if (nbytes)
*nbytes = 0;
return 0;
n = ((offset + osize) > mfs->size) ? mfs->size - offset : osize;
memcpy (optr, mfs->ptr + offset, n);
}
n = ((offset + osize) > mfs->size) ? mfs->size - offset : osize;
memcpy (optr, mfs->ptr + offset, n);
if (nbytes)
*nbytes = n;
return 0;
......@@ -89,24 +85,21 @@ _mapfile_readline (stream_t stream, char *optr, size_t osize,
char *nl;
size_t n = 0;
if (mfs == NULL || mfs->ptr == MAP_FAILED)
if (mfs->ptr == MAP_FAILED)
return EINVAL;
/* Save space for the null byte. */
osize--;
if (offset >= (off_t)mfs->size)
if (offset < (off_t)mfs->size)
{
if (nbytes)
*nbytes = 0;
return 0;
/* Save space for the null byte. */
osize--;
nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset);
n = (nl) ? nl - (mfs->ptr + offset) + 1 : mfs->size - offset;
n = (n > osize) ? osize : n;
memcpy (optr, mfs->ptr + offset, n);
optr[n] = '\0';
}
nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset);
n = nl - (mfs->ptr + offset) + 1;
n = (n > osize) ? osize : n;
memcpy (optr, mfs->ptr + offset, n);
if (nbytes)
*nbytes = n;
optr[n] = '\0';
return 0;
}
......@@ -116,7 +109,7 @@ _mapfile_write (stream_t stream, const char *iptr, size_t isize,
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL || mfs->ptr == MAP_FAILED)
if (mfs->ptr == MAP_FAILED)
return EINVAL;
if (! (mfs->flags & PROT_WRITE))
......@@ -155,7 +148,7 @@ static int
_mapfile_truncate (stream_t stream, off_t len)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL || mfs->ptr == MAP_FAILED)
if (mfs->ptr == MAP_FAILED)
return EINVAL;
/* Remap. */
if (munmap (mfs->ptr, mfs->size) != 0)
......@@ -185,7 +178,7 @@ _mapfile_size (stream_t stream, off_t *psize)
struct stat stbuf;
int err = 0;
if (mfs == NULL || mfs->ptr == MAP_FAILED)
if (mfs->ptr == MAP_FAILED)
return EINVAL;
msync (mfs->ptr, mfs->size, MS_SYNC);
if (fstat(mfs->fd, &stbuf) != 0)
......@@ -220,8 +213,6 @@ static int
_mapfile_flush (stream_t stream)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL)
return EINVAL;
return msync (mfs->ptr, mfs->size, MS_SYNC);
}
......@@ -229,8 +220,6 @@ static int
_mapfile_get_fd (stream_t stream, int *pfd)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL)
return EINVAL;
if (pfd)
*pfd = mfs->fd;
return 0;
......@@ -241,7 +230,7 @@ _mapfile_close (stream_t stream)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
int err = 0;
if (mfs && mfs->ptr != MAP_FAILED)
if (mfs->ptr != MAP_FAILED)
{
if (munmap (mfs->ptr, mfs->size) != 0)
err = errno;
......@@ -262,9 +251,6 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags)
(void)port; /* Ignored. */
if (mfs == NULL)
return EINVAL;
/* Close any previous file. */
if (mfs->ptr != MAP_FAILED)
{
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 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 Library 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 Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <mailutils/stream.h>
struct _memory_stream
{
char *ptr;
size_t size;
};
static void
_memory_destroy (stream_t stream)
{
struct _memory_stream *mfs = stream_get_owner (stream);
if (mfs && mfs->ptr != NULL)
free (mfs->ptr);
free (mfs);
}
static int
_memory_read (stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
{
struct _memory_stream *mfs = stream_get_owner (stream);
size_t n = 0;
if (mfs->ptr != NULL && (offset <= (off_t)mfs->size))
{
n = ((offset + osize) > mfs->size) ? mfs->size - offset : osize;
memcpy (optr, mfs->ptr + offset, n);
}
if (nbytes)
*nbytes = n;
return 0;
}
static int
_memory_readline (stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
{
struct _memory_stream *mfs = stream_get_owner (stream);
char *nl;
size_t n = 0;
if (mfs->ptr && (offset < (off_t)mfs->size))
{
/* Save space for the null byte. */
osize--;
nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset);
n = (nl) ? nl - (mfs->ptr + offset) + 1 : mfs->size - offset;
n = (n > osize) ? osize : n;
memcpy (optr, mfs->ptr + offset, n);
optr[n] = '\0';
}
if (nbytes)
*nbytes = n;
return 0;
}
static int
_memory_write (stream_t stream, const char *iptr, size_t isize,
off_t offset, size_t *nbytes)
{
struct _memory_stream *mfs = stream_get_owner (stream);
/* Bigger we have to realloc. */
if (mfs->size < (offset + isize))
{
char *tmp = realloc (mfs->ptr, offset + isize);
if (tmp == NULL)
return ENOMEM;
mfs->ptr = tmp;
mfs->size = offset + isize;
}
memcpy (mfs->ptr + offset, iptr, isize);
if (nbytes)
*nbytes = isize;
return 0;
}
static int
_memory_truncate (stream_t stream, off_t len)
{
struct _memory_stream *mfs = stream_get_owner (stream);
if (len == 0)
{
free (mfs->ptr);
mfs->ptr = NULL;
}
else
{
char *tmp = realloc (mfs, len);
if (tmp == NULL)
return ENOMEM;
mfs->ptr = tmp;
}
mfs->size = len;
return 0;
}
static int
_memory_size (stream_t stream, off_t *psize)
{
struct _memory_stream *mfs = stream_get_owner (stream);
if (psize)
*psize = mfs->size;
return 0;
}
static int
_memory_close (stream_t stream)
{
struct _memory_stream *mfs = stream_get_owner (stream);
if (mfs->ptr)
{
free (mfs->ptr);
mfs->ptr = NULL;
mfs->size = 0;
}
return 0;
}
static int
_memory_open (stream_t stream, const char *filename, int port, int flags)
{
struct _memory_stream *mfs = stream_get_owner (stream);
(void)port; /* Ignored. */
(void)filename; /* Ignored. */
(void)flags; /* Ignored. */
/* Close any previous file. */
if (mfs->ptr)
{
free (mfs->ptr);
mfs->ptr = NULL;
mfs->size = 0;
}
stream_set_flags (stream, flags |MU_STREAM_NO_CHECK);
return 0;
}
int
memory_stream_create (stream_t *stream)
{
struct _memory_stream *mfs;
int ret;
if (stream == NULL)
return EINVAL;
mfs = calloc (1, sizeof (*mfs));
if (mfs == NULL)
return ENOMEM;
mfs->ptr = NULL;
mfs->size = 0;
ret = stream_create (stream, MU_STREAM_NO_CHECK, mfs);
if (ret != 0)
{
free (mfs);
return ret;
}
stream_set_open (*stream, _memory_open, mfs);
stream_set_close (*stream, _memory_close, mfs);
stream_set_read (*stream, _memory_read, mfs);
stream_set_readline (*stream, _memory_readline, mfs);
stream_set_write (*stream, _memory_write, mfs);
stream_set_truncate (*stream, _memory_truncate, mfs);
stream_set_size (*stream, _memory_size, mfs);
stream_set_destroy (*stream, _memory_destroy, mfs);
return 0;
}