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");
}
......
......@@ -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;
}
......
......@@ -87,24 +87,38 @@ extern int header_set_property __P ((header_t, property_t, void *));
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_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_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 *));
......
......@@ -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,20 +61,16 @@ _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);
}
if (nbytes)
*nbytes = n;
......@@ -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;
if (offset < (off_t)mfs->size)
{
/* Save space for the null byte. */
osize--;
if (offset >= (off_t)mfs->size)
{
if (nbytes)
*nbytes = 0;
return 0;
}
nl = memchr (mfs->ptr + offset, '\n', mfs->size - offset);
n = nl - (mfs->ptr + offset) + 1;
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;
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;
}