Commit 4e0913bf 4e0913bf210cabf46e36866617158ef96ca90a91 by Alain Magloire

The big change: For getting the header we use "TOP # 0" but since TOP is an

optionnal command, we fallback to RETR and ignore the body part.  This ugly
and wastefull and it made the code unnecessary complexe.  But fortunately
I do not know of any POP server that does not have TOP. It's a mess.
The other stuff was little cleanups.
1 parent 526e7396
The current maintainer Alain Magloire <alainm@rcsm.ece.mcgill.ca>
The current maintainer Alain Magloire <alainm@gnu.org>
Brian Edmond <briane@qnx.com>
Dave Inglis <dinglis@qnx.com>
Jakob Kaivo <jkaivo@ndn.net>
Jeff Bailey <jbailey@gnu.org>
Sean 'Shaleh' Perry <shaleh@debian.org>
......
2000--5-19 Sean 'Shaleh' Perry <shaleh@debian.org>
2000-09-01 Alain Magloire
*
2000-5-19 Sean 'Shaleh' Perry <shaleh@debian.org>
* libmailbox/mh.c: fleshed out mh_open() some more
......
......@@ -47,13 +47,11 @@ extern int body_get_filename __P ((body_t, char *, size_t, size_t *));
extern int body_set_filename __P ((body_t, const char*));
extern int body_size __P ((body_t, size_t*));
extern int body_set_size __P ((body_t,
int (*_size) __P ((body_t, size_t*)),
void *owner));
extern int body_set_size __P ((body_t, int (*_size)
__P ((body_t, size_t*)), void *owner));
extern int body_lines __P ((body_t, size_t *));
extern int body_set_lines __P ((body_t,
int (*_lines) __P ((body_t, size_t*)),
void *owner));
extern int body_set_lines __P ((body_t, int (*_lines)
__P ((body_t, size_t*)), void *owner));
#ifdef _cplusplus
}
......
......@@ -70,24 +70,29 @@ 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 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_get_stream __P ((header_t, stream_t *));
extern int header_size __P ((header_t, size_t *));
extern int header_lines __P ((header_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_get_stream __P ((header_t, stream_t *));
extern int header_set_stream __P ((header_t, stream_t, 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_set_get_value __P ((header_t, int (*_get_value)
__P ((header_t, const char *,
char *, size_t, size_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 *));
#ifdef _cplusplus
}
......
......@@ -45,49 +45,59 @@ typedef struct _message *message_t;
* header_t, body_t, and its attribute_t.
*/
extern int message_create __P ((message_t *, void *owner));
extern void message_destroy __P ((message_t *, void *owner));
extern int message_get_header __P ((message_t, header_t *));
extern int message_set_header __P ((message_t, header_t, void *owner));
extern int message_get_body __P ((message_t, body_t *));
extern int message_set_body __P ((message_t, body_t, void *owner));
extern int message_get_stream __P ((message_t, stream_t *));
extern int message_is_mime __P ((message_t));
extern int message_size __P ((message_t, size_t *));
extern int message_lines __P ((message_t, size_t *));
extern int message_from __P ((message_t, char *, size_t, size_t *));
extern int message_set_from __P ((message_t,
int (*_from) __P ((message_t, char *,
size_t, size_t *)),
void *owner));
extern int message_received __P ((message_t, char *, size_t, size_t *));
extern int message_set_received __P ((message_t, int (*_received)
__P ((message_t, char *, size_t,
size_t *)), void *owner));
extern int message_get_attribute __P ((message_t, attribute_t *));
extern int message_set_attribute __P ((message_t, attribute_t, void *owner));
extern int message_get_num_parts __P ((message_t, size_t *nparts));
extern int message_set_get_num_parts __P ((message_t, int (*_getNum_parts)
__P ((message_t, size_t *)),
void *owner));
extern int message_get_part __P ((message_t, size_t part, message_t *msg));
extern int message_set_get_part __P ((message_t, int (*_get_part)
__P ((message_t, size_t, message_t *)),
void *owner));
extern int message_get_uidl __P ((message_t, char *buffer, size_t, size_t *));
extern int message_set_uidl __P ((message_t, int (*_get_uidl)
__P ((message_t, char *, size_t, size_t *)),
void *owner));
extern int message_create __P ((message_t *, void *owner));
extern void message_destroy __P ((message_t *, void *owner));
extern int message_get_header __P ((message_t, header_t *));
extern int message_set_header __P ((message_t, header_t, void *owner));
extern int message_get_body __P ((message_t, body_t *));
extern int message_set_body __P ((message_t, body_t, void *owner));
extern int message_get_stream __P ((message_t, stream_t *));
extern int message_set_stream __P ((message_t, stream_t, void *owner));
extern int message_is_multipart __P ((message_t, int *));
extern int message_set_is_multipart __P ((message_t, int (*_is_multipart)
__P ((message_t, int *)), void *));
extern int message_size __P ((message_t, size_t *));
extern int message_set_size __P ((message_t, int (*_size)
__P ((message_t, size_t *)),
void *owner));
extern int message_lines __P ((message_t, size_t *));
extern int message_set_lines __P ((message_t, int (*_lines)
__P ((message_t, size_t *)),
void *owner));
extern int message_from __P ((message_t, char *, size_t, size_t *));
extern int message_set_from __P ((message_t, int (*_from)
__P ((message_t, char *, size_t,
size_t *)), void *owner));
extern int message_received __P ((message_t, char *, size_t, size_t *));
extern int message_set_received __P ((message_t, int (*_received)
__P ((message_t, char *, size_t,
size_t *)), void *owner));
extern int message_get_attribute __P ((message_t, attribute_t *));
extern int message_set_attribute __P ((message_t, attribute_t, void *));
extern int message_get_num_parts __P ((message_t, size_t *nparts));
extern int message_set_get_num_parts __P ((message_t, int (*_get_num_parts)
__P ((message_t, size_t *)),
void *owner));
extern int message_get_part __P ((message_t, size_t, message_t *));
extern int message_set_get_part __P ((message_t, int (*_get_part)
__P ((message_t, size_t,
message_t *)), void *owner));
extern int message_get_uidl __P ((message_t, char *, size_t, size_t *));
extern int message_set_uidl __P ((message_t, int (*_get_uidl)
__P ((message_t, char *, size_t,
size_t *)), void *owner));
/* events */
#define MU_EVT_MSG_DESTROY 32
......
......@@ -198,7 +198,8 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
if (header == NULL || fn == NULL || fv == NULL)
return EINVAL;
if (header->_set_value != NULL)
/* Overload. */
if (header->_set_value)
return header->_set_value (header, fn, fv, replace);
/* Try to fill out the buffer, if we know how. */
......@@ -268,7 +269,8 @@ header_get_value (header_t header, const char *name, char *buffer,
if (header == NULL || name == NULL)
return EINVAL;
if (header->_get_value != NULL)
/* Overload. */
if (header->_get_value)
return header->_get_value (header, name, buffer, buflen, pn);
/* Try to fill out the buffer, if we know how. */
......@@ -320,27 +322,36 @@ header_get_value (header_t header, const char *name, char *buffer,
if (pn)
*pn = total;
/* Check if they provided a hook. */
if (total == 0)
{
err = ENOENT;
if (header->_get_value != NULL)
err = header->_get_value (header, name, buffer, buflen, pn);
/* Success. Cache it locally. */
if (err == 0)
header_set_value (header, name, buffer, 0);
}
err = ENOENT;
return err;
}
int
header_set_lines (header_t header, int (*_lines)
(header_t, size_t *), void *owner)
{
if (header == NULL)
return EINVAL;
if (header->owner != owner)
return EACCES;
header->_lines = _lines;
return 0;
}
int
header_lines (header_t header, size_t *plines)
{
int n;
size_t lines = 0;
if (header == NULL)
if (header == NULL || plines == NULL)
return EINVAL;
/* Overload. */
if (header->_lines)
return header->_lines (header, plines);
/* Try to fill out the buffer, if we know how. */
if (header->blurb == NULL)
{
......@@ -360,11 +371,27 @@ header_lines (header_t header, size_t *plines)
}
int
header_size (header_t header, size_t *pnum)
header_set_size (header_t header, int (*_size)
(header_t, size_t *), void *owner)
{
if (header == NULL)
return EINVAL;
if (header->owner != owner)
return EACCES;
header->_size = _size;
return 0;
}
int
header_size (header_t header, size_t *psize)
{
if (header == NULL)
return EINVAL;
/* Overload. */
if (header->_size)
return header->_size (header, psize);
/* Try to fill out the buffer, if we know how. */
if (header->blurb == NULL)
{
......@@ -373,8 +400,8 @@ header_size (header_t header, size_t *pnum)
return err;
}
if (pnum)
*pnum = header->blurb_len;
if (psize)
*psize = header->blurb_len;
return 0;
}
......
......@@ -43,6 +43,9 @@ mailbox_create (mailbox_t *pmbox, const char *name, int id)
struct mailbox_registrar *mreg;
url_t url = NULL;
if (pmbox == NULL)
return EINVAL;
url_create (&url, name);
/* 1st guest: if an ID is specify, shortcut */
......@@ -151,6 +154,14 @@ mailbox_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
return mbox->_scan (mbox, msgno, pcount);
}
int
mailbox_size (mailbox_t mbox, off_t *psize)
{
if (mbox == NULL || mbox->_size == NULL)
return 0;
return mbox->_size (mbox, psize);
}
/* locking */
int
mailbox_set_locker (mailbox_t mbox, locker_t locker)
......
......@@ -32,14 +32,20 @@
#include <header0.h>
#include <attribute0.h>
/* Advance declarations. */
struct _pop_data;
struct _pop_message;
struct _bio;
typedef struct _pop_data * pop_data_t;
typedef struct _pop_message * pop_message_t;
typedef struct _bio *bio_t;
/* The different possible states of a Pop client, it maps to the POP3 commands.
Note that POP3 is not reentrant. It is only one channel. */
/* The different possible states of a Pop client, Note that POP3 is not
reentrant. It is only one channel. */
enum pop_state
{
/* The initialisation of POP_NO_STATE is redundant but it is here for
info purposes meaning 0 is the starting state. */
POP_NO_STATE = 0,
POP_NO_STATE = 0, POP_STATE_DONE,
POP_OPEN_CONNECTION,
POP_GREETINGS,
POP_APOP_TX, POP_APOP_ACK,
......@@ -54,8 +60,6 @@ enum pop_state
POP_TOP_TX, POP_TOP_ACK, POP_TOP_RX,
POP_UIDL_TX, POP_UIDL_ACK,
POP_USER_TX, POP_USER_ACK,
POP_CLOSE_CONNECTION /* I do not think a shutdown of a connection will
block. More for the symmetry. */
};
/* Those two are exportable funtions i.e. they are visible/call when you
......@@ -82,13 +86,17 @@ static int pop_is_updated (mailbox_t);
/* The implementation of message_t */
static int pop_size (mailbox_t, off_t *);
static int pop_readstream (stream_t, char *, size_t, off_t, size_t *);
static int pop_top (stream_t, char *, size_t, off_t, size_t *);
static int pop_read_header (stream_t, char *, size_t, off_t, size_t *);
static int pop_read_body (stream_t, char *, size_t, off_t, size_t *);
static int pop_read_message (stream_t, char *, size_t, off_t, size_t *);
static int pop_retr (pop_message_t, char *, size_t, off_t, size_t *);
static int pop_get_fd (stream_t, int *);
static int pop_get_flags (attribute_t, int *);
static int pop_body_size (body_t, size_t *);
static int pop_body_lines (body_t body, size_t *plines);
static int pop_header_read (stream_t, char *, size_t, off_t, size_t *);
static int pop_uidl (message_t, char *, size_t, size_t *);
static int fill_buffer (bio_t bio, char *buffer, size_t buflen);
/* According to the rfc:
RFC 2449 POP3 Extension Mechanism November 1998
......@@ -130,7 +138,6 @@ struct _bio
char *ptr;
char *nl;
};
typedef struct _bio *bio_t;
static int bio_create (bio_t *, stream_t);
static void bio_destroy (bio_t *);
......@@ -138,12 +145,6 @@ static int bio_readline (bio_t);
static int bio_read (bio_t);
static int bio_write (bio_t);
/* Advance declarations. */
struct _pop_data;
struct _pop_message;
typedef struct _pop_data * pop_data_t;
typedef struct _pop_message * pop_message_t;
/* This structure holds the info when for a pop_get_message() the
pop_message_t type will serve as the owner of the message_t and contains
......@@ -156,6 +157,8 @@ typedef struct _pop_message * pop_message_t;
struct _pop_message
{
int inbody;
int skip_header;
int skip_body;
size_t body_size;
size_t body_lines;
size_t num;
......@@ -215,7 +218,7 @@ pop_create (mailbox_t *pmbox, const char *name)
size_t name_len;
/* Sanity check. */
if (pmbox == NULL || name == NULL || *name == '\0')
if (name == NULL || *name == '\0')
return EINVAL;
name_len = strlen (name);
......@@ -394,7 +397,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
static int
pop_open (mailbox_t mbox, int flags)
{
pop_data_t mpd;
pop_data_t mpd = mbox->data;
int status;
bio_t bio;
void *func = (void *)pop_open;
......@@ -402,7 +405,7 @@ pop_open (mailbox_t mbox, int flags)
long port;
/* Sanity checks. */
if (mbox == NULL || mbox->url == NULL || (mpd = mbox->data) == NULL)
if (mbox->url == NULL || mpd == NULL)
return EINVAL;
/* Fetch the pop server name and the port in the url_t. */
......@@ -549,13 +552,13 @@ pop_open (mailbox_t mbox, int flags)
static int
pop_close (mailbox_t mbox)
{
pop_data_t mpd;
pop_data_t mpd = mbox->data;
void *func = (void *)pop_close;
int status;
bio_t bio;
size_t i;
if (mbox == NULL || (mpd = mbox->data) == NULL)
if (mpd == NULL)
return EINVAL;
if (mpd->func && mpd->func != func)
......@@ -623,13 +626,13 @@ pop_close (mailbox_t mbox)
static int
pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
pop_data_t mpd;
pop_data_t mpd = mbox->data;
int status;
pop_message_t mpm;
size_t i;
/* Sanity. */
if (mbox == NULL || pmsg == NULL || (mpd = mbox->data) == NULL)
if (pmsg == NULL || mpd == NULL)
return EINVAL;
/* See if we have already this message. */
......@@ -655,12 +658,15 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
/* Create the message. */
{
message_t msg;
status = message_create (&msg, mpm);
if (status != 0)
stream_t is;
if ((status = message_create (&msg, mpm)) != 0
|| (status = stream_create (&is, MU_STREAM_READ, mpm)) != 0)
{
free (mpm);
return status;
}
stream_set_read (is, pop_read_message, mpm);
message_set_stream (msg, is, mpm);
/* The message. */
mpm->message = msg;
}
......@@ -676,7 +682,8 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
free (mpm);
return status;
}
stream_set_read (stream, pop_header_read, mpm);
//stream_set_read (stream, pop_read_header, mpm);
stream_set_read (stream, pop_top, mpm);
stream_set_fd (stream, pop_get_fd, mpm);
stream_set_flags (stream, MU_STREAM_READ, mpm);
header_set_stream (header, stream, mpm);
......@@ -701,21 +708,14 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
stream_t stream;
body_t body;
status = body_create (&body, mpm);
if (status != 0)
{
message_destroy (&(mpm->message), mpm);
free (mpm);
return status;
}
status = stream_create (&stream, MU_STREAM_READ, mpm);
if (status != 0)
if ((status = body_create (&body, mpm)) != 0
|| (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0)
{
message_destroy (&(mpm->message), mpm);
free (mpm);
return status;
}
stream_set_read (stream, pop_readstream, mpm);
stream_set_read (stream, pop_read_body, mpm);
stream_set_fd (stream, pop_get_fd, mpm);
stream_set_flags (stream, mpd->flags, mpm);
body_set_size (body, pop_body_size, mpm);
......@@ -750,12 +750,12 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
static int
pop_messages_count (mailbox_t mbox, size_t *pcount)
{
pop_data_t mpd;
pop_data_t mpd = mbox->data;
int status;
void *func = (void *)pop_messages_count;
bio_t bio;
if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL)
if (mpd == NULL)
return EINVAL;
if (pop_is_updated (mbox))
......@@ -817,8 +817,8 @@ pop_messages_count (mailbox_t mbox, size_t *pcount)
static int
pop_is_updated (mailbox_t mbox)
{
pop_data_t mpd;
if ((mpd = (pop_data_t)mbox->data) == NULL)
pop_data_t mpd = mbox->data;
if (mpd == NULL)
return 0;
return mpd->is_updated;
}
......@@ -826,11 +826,11 @@ pop_is_updated (mailbox_t mbox)
static int
pop_num_deleted (mailbox_t mbox, size_t *pnum)
{
pop_data_t mpd;
pop_data_t mpd = mbox->data;
size_t i, total;
attribute_t attr;
if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL)
if (mpd == NULL)
return EINVAL;
for (i = total = 0; i < mpd->messages_count; i++)
......@@ -867,14 +867,14 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
static int
pop_expunge (mailbox_t mbox)
{
pop_data_t mpd;
pop_data_t mpd = mbox->data;
size_t i;
attribute_t attr;
bio_t bio;
int status;
void *func = (void *)pop_expunge;
if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL)
if (mpd == NULL)
return EINVAL;
/* Busy ? */
......@@ -958,10 +958,10 @@ pop_expunge (mailbox_t mbox)
static int
pop_size (mailbox_t mbox, off_t *psize)
{
pop_data_t mpd;
pop_data_t mpd = mbox->data;
int status = 0;
if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL)
if (mpd == NULL)
return EINVAL;
if (! pop_is_updated (mbox))
......@@ -974,8 +974,8 @@ pop_size (mailbox_t mbox, off_t *psize)
static int
pop_body_size (body_t body, size_t *psize)
{
pop_message_t mpm;
if (body == NULL || (mpm = body->owner) == NULL)
pop_message_t mpm = body->owner;
if (mpm == NULL)
return EINVAL;
if (psize)
*psize = mpm->body_size;
......@@ -985,8 +985,8 @@ pop_body_size (body_t body, size_t *psize)
static int
pop_body_lines (body_t body, size_t *plines)
{
pop_message_t mpm;
if (body == NULL || (mpm = body->owner) == NULL)
pop_message_t mpm = body->owner;
if (mpm == NULL)
return EINVAL;
if (plines)
*plines = mpm->body_lines;
......@@ -996,12 +996,12 @@ pop_body_lines (body_t body, size_t *plines)
static int
pop_get_flags (attribute_t attr, int *pflags)
{
pop_message_t mpm;
pop_message_t mpm = attr->owner;
char hdr_status[64];
header_t header = NULL;
int err;
if (attr == NULL || (mpm = attr->owner) == NULL)
if (mpm == NULL)
return EINVAL;
hdr_status[0] = '\0';
message_get_header (mpm->message, &header);
......@@ -1015,8 +1015,8 @@ pop_get_flags (attribute_t attr, int *pflags)
static int
pop_get_fd (stream_t stream, int *pfd)
{
pop_message_t mpm;
if (stream == NULL || (mpm = stream->owner) == NULL)
pop_message_t mpm = stream->owner;
if (mpm == NULL)
return EINVAL;
if (mpm->mpd->bio)
return stream_get_fd (mpm->mpd->bio->stream, pfd);
......@@ -1026,7 +1026,7 @@ pop_get_fd (stream_t stream, int *pfd)
static int
pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
{
pop_message_t mpm;
pop_message_t mpm = msg->owner;
pop_data_t mpd;
bio_t bio;
int status = 0;
......@@ -1035,7 +1035,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
/* According to the RFC uidl's are no longer then 70 chars. */
char uniq[128];
if (msg == NULL || (mpm = msg->owner) == NULL)
if (mpm == NULL)
return EINVAL;
mpd = mpm->mpd;
......@@ -1099,19 +1099,20 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
}
static int
pop_header_read (stream_t is, char *buffer, size_t buflen,
pop_top (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread)
{
pop_message_t mpm;
pop_message_t mpm = is->owner;
pop_data_t mpd;
bio_t bio;
size_t nread = 0;
int status = 0;
void *func = (void *)pop_header_read;
void *func = (void *)pop_top;
if (is == NULL || (mpm = is->owner) == NULL)
if (mpm == NULL)
return EINVAL;
/* We do not carry the offset(for pop), should be doc somewhere. */
(void)offset;
mpd = mpm->mpd;
bio = mpd->bio;
......@@ -1147,9 +1148,12 @@ pop_header_read (stream_t is, char *buffer, size_t buflen,
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
{
fprintf (stderr, "TOP not implmented\n");
CLEAR_STATE (mpd);
return ENOSYS;
/* fprintf (stderr, "TOP not implmented\n"); */
/* Fall back to RETR call. */
mpd->state = POP_NO_STATE;
mpm->skip_header = 0;
mpm->skip_body = 1;
return pop_retr (mpm, buffer, buflen, offset, pnread);
}
mpd->state = POP_TOP_RX;
bio->current = bio->nl;
......@@ -1185,8 +1189,10 @@ pop_header_read (stream_t is, char *buffer, size_t buflen,
}
break;
default:
/* fprintf (stderr, "pop_header_blurb unknown state\n"); */
break;
/* Probabaly TOP was not supported so we fall back to RETR. */
mpm->skip_header = 0;
mpm->skip_body = 1;
return pop_retr (mpm, buffer, buflen, offset, pnread);
} /* switch (state) */
if (nread == 0)
......@@ -1199,41 +1205,114 @@ pop_header_read (stream_t is, char *buffer, size_t buflen,
}
static int
pop_readstream (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread)
pop_read_header (stream_t is, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
pop_message_t mpm = is->owner;
pop_data_t mpd;
void *func = (void *)pop_read_header;
if (mpm == NULL)
return EINVAL;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
mpm->skip_header = 0;
mpm->skip_body = 1;
return pop_retr (mpm, buffer, buflen, offset, pnread);
}
static int
pop_read_body (stream_t is, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
pop_message_t mpm = is->owner;
pop_data_t mpd;
void *func = (void *)pop_read_body;
if (mpm == NULL)
return EINVAL;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
mpm->skip_header = 1;
mpm->skip_body = 0;
return pop_retr (mpm, buffer, buflen, offset, pnread);
}
static int
pop_read_message (stream_t is, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
pop_message_t mpm = is->owner;
pop_data_t mpd;
void *func = (void *)pop_read_message;
if (mpm == NULL)
return EINVAL;
mpd = mpm->mpd;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
mpm->skip_header = mpm->skip_body = 0;
return pop_retr (mpm, buffer, buflen, offset, pnread);
}
static int
fill_buffer (bio_t bio, char *buffer, size_t buflen)
{
int nleft, n, nread = 0;
n = bio->nl - bio->current;
nleft = buflen - n;
/* We got more then requested. */
if (nleft <= 0)
{
memcpy (buffer, bio->current, buflen);
bio->current += buflen;
nread = buflen;
}
else
{
/* Drain the buffer. */
memcpy (buffer, bio->current, n);
bio->current += n;
nread = n;
}
return nread;
}
static int
pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
pop_message_t mpm;
pop_data_t mpd;
size_t nread = 0;
bio_t bio;
int status = 0;
void *func = (void *)pop_readstream;
(void)offset;
if (is == NULL || (mpm = is->owner) == NULL)
return EINVAL;
if (pnread)
*pnread = nread;
/* Take care of the obvious. */
if (buffer == NULL || buflen == 0)
{
if (pnread)
*pnread = nread;
return 0;
}
return 0;
mpd = mpm->mpd;
bio = mpd->bio;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
switch (mpd->state)
{
case POP_NO_STATE:
mpm->body_lines = mpm->body_size = 0;
bio->len = sprintf (bio->buffer, "RETR %d\r\n", mpm->num);
bio->ptr = bio->buffer;
mpd->state = POP_RETR_TX;
case POP_RETR_TX:
......@@ -1251,14 +1330,33 @@ pop_readstream (stream_t is, char *buffer, size_t buflen,
CLEAR_STATE (mpd);
return EACCES;
}
bio->current = bio->nl;
mpd->state = POP_RETR_RX_HDR;
case POP_RETR_RX_HDR:
/* Skip the header. */
while (!mpm->inbody)
{
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
/* Do we need to fill up. */
if (bio->current >= bio->nl)
{
bio->current = bio->buffer;
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
}
if (mpm->skip_header == 0)
{
nread = fill_buffer (bio, buffer, buflen);
if (pnread)
*pnread += nread;
buflen -= nread ;
if (buflen > 0)
buffer += nread;
else
return 0;
}
else
bio->current = bio->nl;
if (bio->buffer[0] == '\n')
{
mpm->inbody = 1;
......@@ -1266,50 +1364,58 @@ pop_readstream (stream_t is, char *buffer, size_t buflen,
}
}
/* Skip the newline. */
bio_readline (bio);
bio->current = bio->current;
//bio_readline (bio);
mpd->state = POP_RETR_RX_BODY;
case POP_RETR_RX_BODY:
/* Start taking the body. */
{
int nleft, n;
/* Do we need to fill up. */
if (bio->current >= bio->nl)
{
bio->current = bio->buffer;
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
}
n = bio->nl - bio->current;
nleft = buflen - n;
/* We got more then requested. */
if (nleft <= 0)
{
memcpy (buffer, bio->current, buflen);
bio->current += buflen;
nread = buflen;
}
else
while (mpm->inbody)
{
/* Drain the buffer. */
memcpy (buffer, bio->current, n);
bio->current += n;
nread = n;
/* Do we need to fill up. */
if (bio->current >= bio->nl)
{
bio->current = bio->buffer;
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
mpm->body_lines++;
}
if (mpm->skip_body == 0)
{
nread = fill_buffer (bio, buffer, buflen);
mpm->body_size += nread;
if (pnread)
*pnread += nread;
buflen -= nread ;
if (buflen > 0)
buffer += nread;
else
return 0;
}
else
{
mpm->body_size += (bio->nl - bio->current);
bio->current = bio->nl;
}
if (bio->buffer[0] == '\0')
{
mpm->inbody = 0;
break;
}
}
break;
}
mpd->state = POP_STATE_DONE;
return 0;
case POP_STATE_DONE:
/* A convenient break, this is here so we can return 0 read on next
call meaning we're done. */
default:
/* fprintf (stderr, "pop_readstream unknow state\n"); */
/* fprintf (stderr, "pop_retr unknow state\n"); */
break;
} /* Switch state. */
if (nread == 0)
{
CLEAR_STATE (mpd);
}
if (pnread)
*pnread = nread;
CLEAR_STATE (mpd);
mpm->skip_header = mpm->skip_body = 0;
return 0;
}
......
......@@ -23,6 +23,7 @@
#include <url0.h>
#include <stream0.h>
#include <body0.h>
#include <header0.h>
#include <attribute0.h>
#include <mailutils/header.h>
#include <mailutils/auth.h>
......@@ -103,13 +104,20 @@ typedef struct _unix_data
size_t umessages_count;
size_t messages_count;
stream_t stream;
char *dirname;
char *basename;
#ifdef HAVE_PTHREAD_H
pthread_mutex_t mutex;
#endif
off_t size;
/* The variables below are use to hold the state when appending messages. */
enum unix_state
{
UNIX_NO_STATE=0, UNIX_STATE_FROM, UNIX_STATE_DATE, UNIX_STATE_APPEND
} state ;
char *from;
char *date;
off_t off;
} *unix_data_t;
static int unix_open (mailbox_t mbox, int flag);
......@@ -134,6 +142,8 @@ static int unix_set_flags (attribute_t, int);
static int unix_unset_flags (attribute_t, int);
static int unix_readstream (stream_t is, char *buffer, size_t buflen,
off_t off, size_t *pnread);
static int unix_header_size (header_t header, size_t *psize);
static int unix_header_lines (header_t header, size_t *plines);
static int unix_body_size (body_t body, size_t *psize);
static int unix_body_lines (body_t body, size_t *plines);
static int unix_msg_from (message_t msg, char *buf, size_t len,
......@@ -155,7 +165,6 @@ unix_create (mailbox_t *pmbox, const char *name)
{
mailbox_t mbox;
unix_data_t mud;
const char *sep;
size_t name_len;
/* Sanity check. */
......@@ -169,18 +178,18 @@ unix_create (mailbox_t *pmbox, const char *name)
#define SEPARATOR '/'
/* Skip the url scheme. */
if (name_len > UNIX_SCHEME_LEN &&
(name[0] == 'u' || name[0] == 'U') &&
(name[1] == 'n' || name[1] == 'N') &&
(name[2] == 'i' || name[2] == 'i') &&
(name[3] == 'x' || name[3] == 'x' ) &&
name[4] == ':')
if (name_len > UNIX_SCHEME_LEN
&& (name[0] == 'u' || name[0] == 'U')
&& (name[1] == 'n' || name[1] == 'N')
&& (name[2] == 'i' || name[2] == 'i')
&& (name[3] == 'x' || name[3] == 'x' )
&& name[4] == ':')
{
name += UNIX_SCHEME_LEN;
name_len -= UNIX_SCHEME_LEN;
}
/* Allocate memory for mbox. */
/* Allocate memory for mbox (mailbox_t). */
mbox = calloc (1, sizeof (*mbox));
if (mbox == NULL)
return ENOMEM;
......@@ -193,7 +202,14 @@ unix_create (mailbox_t *pmbox, const char *name)
return ENOMEM;
}
/* Copy the name. */
/* Copy the name.
We do not do any further interpretation after the scheme "unix:"
Because for example on distributed system like QnX4 a file name is
//390/etc/passwd. So the best approach is to let the OS handle it
for example if we receive: "unix:///var/mail/alain" the mailbox name
will be "///var/mail/alain" we let open() do the right thing.
So it will let things like this "unix://390/var/mail/alain" where
"//390/var/mail/alain" _is_ the filename, pass correctely. */
mbox->name = calloc (name_len + 1, sizeof (char));
if (mbox->name == NULL)
{
......@@ -202,50 +218,6 @@ unix_create (mailbox_t *pmbox, const char *name)
}
memcpy (mbox->name, name, name_len);
/* Save the basename and dirname. We split the name, but this should
probably be supported via "maildir:" or the mailbox mgr. */
sep = strrchr (name, SEPARATOR);
if (sep)
{
/* Split it into two. */
mud->dirname = calloc ((sep - name) + 1, sizeof (char));
if (mud->dirname == NULL)
{
unix_destroy (&mbox);
return ENOMEM;
}
memcpy (mud->dirname, name, sep - name);
++sep;
mud->basename = calloc (name_len - (sep - name) + 1, sizeof (char));
if (mud->basename == NULL)
{
unix_destroy (&mbox);
return ENOMEM;
}
memcpy (mud->basename, sep, name_len - (sep - name));
}
else
{
/* Use the relative directory ".". */
/* FIXME: should we call getcwd () instead ? */
mud->dirname = calloc (2 , sizeof (char));
if (mud->dirname == NULL)
{
unix_destroy (&mbox);
return ENOMEM;
}
mud->dirname[0] = '.';
mud->basename = calloc (name_len + 1, sizeof (char));
if (mud->basename == NULL)
{
unix_destroy (&mbox);
return ENOMEM;
}
memcpy (mud->basename, name, name_len);
}
#ifdef HAVE_PHTREAD_H
/* Mutex when accessing the structure fields. */
/* FIXME: should we use rdwr locks instead ?? */
......@@ -270,8 +242,8 @@ unix_create (mailbox_t *pmbox, const char *name)
mbox->_size = unix_size;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_create (%s/%s)\n",
mud->dirname, mud->basename);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_create(%s)\n",
mbox->name);
(*pmbox) = mbox;
return 0; /* okdoke */
......@@ -289,10 +261,7 @@ unix_destroy (mailbox_t *pmbox)
size_t i;
unix_data_t mud = mbox->data;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
"unix_destroy (%s/%s)\n",
mud->dirname, mud->basename);
free (mud->dirname);
free (mud->basename);
"unix_destroy (%s/%s)\n", mbox->name);
for (i = 0; i < mud->umessages_count; i++)
{
unix_message_t mum = mud->umessages[i];
......@@ -331,11 +300,10 @@ unix_destroy (mailbox_t *pmbox)
static int
unix_open (mailbox_t mbox, int flags)
{
unix_data_t mud;
unix_data_t mud = mbox->data;
int status = 0;
if (mbox == NULL ||
(mud = (unix_data_t)mbox->data) == NULL)
if (mud == NULL)
return EINVAL;
/* Authentication prologues. */
......@@ -384,10 +352,10 @@ unix_open (mailbox_t mbox, int flags)
static int
unix_close (mailbox_t mbox)
{
unix_data_t mud;
unix_data_t mud = mbox->data;
size_t i;
if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL)
if (mud == NULL)
return EINVAL;
/* Make sure we do not hold any lock for that file. */
......@@ -428,13 +396,15 @@ unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
/* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
browsers and delete files in one. My views is that we should scream
bloody murder and hunt them with a machette. */
bloody murder and hunt them with a machette. But for now just play dumb,
but maybe the best approach is to pack our things and leave .i.e exit(). */
static int
unix_is_updated (mailbox_t mbox)
{
off_t size;
unix_data_t mud;
if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
unix_data_t mud = mbox->data;
if (mud == NULL)
return EINVAL;
if (stream_size (mbox->stream, &size) != 0)
return 0;
......@@ -444,10 +414,10 @@ unix_is_updated (mailbox_t mbox)
static int
unix_num_deleted (mailbox_t mbox, size_t *pnum)
{
unix_data_t mud;
unix_data_t mud = mbox->data;
unix_message_t mum;
size_t i, total;
if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
if (mud == NULL)
return EINVAL;
for (i = total = 0; i < mud->messages_count; i++)
{
......@@ -462,15 +432,14 @@ unix_num_deleted (mailbox_t mbox, size_t *pnum)
}
/* FIXME: the use of tmpfile() on some system can lead to race condition, We
should use a safer approach. We take a very naive approach for this, it
involves unfortunately two copies. */
should use a safer approach. */
static FILE *
unix_tmpfile (mailbox_t mbox, char **pbox)
{
const char *tmpdir;
int fd;
FILE *fp;
unix_data_t mud = (unix_data_t)mbox->data;
const char *basename;
/* P_tmpdir should be define in <stdio.h>. */
#ifndef P_tmpdir
......@@ -478,11 +447,16 @@ unix_tmpfile (mailbox_t mbox, char **pbox)
#endif
tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir;
*pbox = calloc (1, strlen (tmpdir) + strlen ("MBOX_") +
strlen (mud->basename) + 1);
basename = strrchr (mbox->name, '/');
if (basename)
basename++;
else
basename = mbox->name;
*pbox = calloc (strlen (tmpdir) + strlen ("MBOX_") +
strlen (basename) + 1, sizeof (char));
if (*pbox == NULL)
return NULL;
sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", mud->basename);
sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", basename);
/* FIXME: I don't think this is the righ approach, creating an anonymous
file would be better ? no trace left behind. */
......@@ -508,10 +482,21 @@ unix_tmpfile (mailbox_t mbox, char **pbox)
return fp;
}
/* For the expunge bits we took a very cautionnary approach, meaning
we create temporary file in the tmpdir copy all the file not mark deleted,
and skip the deleted ones, truncate the real mailbox to the desired size
and overwrite with the tmp mailbox. The approach to do everyting
in core is tempting but require to much memory, it is not rare now
a day to have 30 Megs mailbox, also there is danger for filesystems
with quotas, or some program may not respect the advisory lock and
decide to append a new message while your expunging etc ...
The real downside to the approach we take is that when things go wrong
the temporary file bay be left in /tmp, which is not all that bad
because at least have something to recuparate when failure. */
static int
unix_expunge (mailbox_t mbox)
{
unix_data_t mud;
unix_data_t mud = mbox->data;
unix_message_t mum;
int status = 0;
sigset_t sigset;
......@@ -523,7 +508,7 @@ unix_expunge (mailbox_t mbox)
char buffer [BUFSIZ];
char *tmpmbox = NULL;
if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL)
if (mud == NULL)
return EINVAL;
/* Noop. */
......@@ -569,7 +554,11 @@ unix_expunge (mailbox_t mbox)
/* Create a tempory file. */
tempfile = unix_tmpfile (mbox, &tmpmbox);
if (tempfile == NULL)
return errno;
{
fprintf (stderr, "Failed to create temporary file when expunging.\n");
free (tmpmbox);
return errno;
}
/* Get the lock. */
if (unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
......@@ -640,9 +629,9 @@ unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: (%s)\n", __LINE__,
fprintf (stderr, "Error expunge:%d: (%s)\n", __LINE__,
strerror (status));
goto bailout;
goto bailout0;
}
len -= n;
total += n;
......@@ -676,9 +665,9 @@ unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: %s", __LINE__,
fprintf (stderr, "Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout;
goto bailout0;
}
len -= n;
total += n;
......@@ -701,9 +690,9 @@ unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: %s", __LINE__,
fprintf (stderr, "Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout;
goto bailout0;
}
len -= n;
total += n;
......@@ -731,9 +720,9 @@ unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: %s", __LINE__,
fprintf (stderr, "Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout;
goto bailout0;
}
len -= n;
total += n;
......@@ -755,7 +744,11 @@ unix_expunge (mailbox_t mbox)
{
status = stream_write (mbox->stream, buffer, nread, offset, &n);
if (status != 0)
goto bailout;
{
fprintf (stderr, "Error expunge:%d: %s\n", __LINE__,
strerror (status));
goto bailout;
}
nread -= n;
offset += n;
}
......@@ -770,12 +763,12 @@ unix_expunge (mailbox_t mbox)
status = stream_truncate (mbox->stream, total);
if (status != 0)
{
fprintf (stderr, "expunge:%d: %s", __LINE__,
strerror (status));
fprintf (stderr, "Error expunging:%d: %s", __LINE__, strerror (status));
goto bailout;
}
/* Don't remove the tmp mbox in case of errors. */
bailout0:
/* Don't remove the tmp mbox in case of errors, when writing back. */
remove (tmpmbox);
bailout:
......@@ -814,7 +807,7 @@ unix_expunge (mailbox_t mbox)
mum->body = mum->body_end = 0;
mum->header_lines = mum->body_lines = 0;
}
/* This is should reset the messages_count, the last * argument 0 means
/* This is should reset the messages_count, the last argument 0 means
not to send event notification. */
unix_scan0 (mbox, dirty, NULL, 0);
}
......@@ -824,9 +817,9 @@ unix_expunge (mailbox_t mbox)
static int
unix_get_fd (stream_t is, int *pfd)
{
unix_message_t mum;
unix_message_t mum = is->owner;
if (is == NULL || (mum = is->owner) == NULL)
if (mum == NULL)
return EINVAL;
return stream_get_fd (mum->stream, pfd);
......@@ -835,9 +828,9 @@ unix_get_fd (stream_t is, int *pfd)
static int
unix_get_flags (attribute_t attr, int *pflags)
{
unix_message_t mum;
unix_message_t mum = attr->owner;
if (attr == NULL || (mum = attr->owner) == NULL)
if (mum == NULL)
return EINVAL;
if (pflags)
......@@ -848,9 +841,9 @@ unix_get_flags (attribute_t attr, int *pflags)
static int
unix_set_flags (attribute_t attr, int flags)
{
unix_message_t mum;
unix_message_t mum = attr->owner;
if (attr == NULL || (mum = attr->owner) == NULL)
if (mum == NULL)
return EINVAL;
mum->new_flags |= flags;
......@@ -860,12 +853,12 @@ unix_set_flags (attribute_t attr, int flags)
static int
unix_unset_flags (attribute_t attr, int flags)
{
unix_message_t mum;
unix_message_t mum = attr->owner;
if (attr == NULL || (mum = attr->owner) == NULL)
if (mum == NULL)
return EINVAL;
mum->new_flags &= flags;
mum->new_flags &= ~flags;
return 0;
}
......@@ -873,10 +866,10 @@ static int
unix_readstream (stream_t is, char *buffer, size_t buflen,
off_t off, size_t *pnread)
{
unix_message_t mum;
unix_message_t mum = is->owner;
size_t nread = 0;
if (is == NULL || (mum = (unix_message_t)is->owner) == NULL)
if (mum == NULL)
return EINVAL;
if (buffer == NULL || buflen == 0)
......@@ -909,12 +902,12 @@ static int
unix_get_header_read (stream_t is, char *buffer, size_t len,
off_t off, size_t *pnread)
{
unix_message_t mum;
unix_message_t mum = is->owner;
size_t nread = 0;
int status = 0;
off_t ln;
if (is == NULL || (mum = is->owner) == NULL)
if (mum == NULL)
return EINVAL;
ln = mum->body - (mum->header_from_end + off);
......@@ -931,13 +924,35 @@ unix_get_header_read (stream_t is, char *buffer, size_t len,
}
static int
unix_header_size (header_t header, size_t *psize)
{
unix_message_t mum = header->owner;
if (mum == NULL)
return EINVAL;
if (psize)
*psize = mum->body - mum->header_from_end;
return 0;
}
static int
unix_header_lines (header_t header, size_t *plines)
{
unix_message_t mum = header->owner;
if (mum == NULL)
return EINVAL;
if (plines)
*plines = mum->header_lines;
return 0;
}
static int
unix_body_size (body_t body, size_t *psize)
{
unix_message_t mum = body->owner;
if (mum == NULL)
return EINVAL;
if (psize)
*psize = mum->body_end - mum->body;
*psize = mum->body_end - mum->body + 1;
return 0;
}
......@@ -1046,14 +1061,13 @@ static int
unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
int status;
unix_data_t mud;
unix_data_t mud = mbox->data;
unix_message_t mum;
message_t msg = NULL;
/* Sanity checks. */
if (mbox == NULL || pmsg == NULL || (mud = (unix_data_t)mbox->data) == NULL
|| (!(mud->messages_count > 0 && msgno > 0
&& msgno <= mud->messages_count)))
if (pmsg == NULL || mud == NULL || (!(mud->messages_count > 0 && msgno > 0
&& msgno <= mud->messages_count)))
return EINVAL;
mum = mud->umessages[msgno - 1];
......@@ -1088,6 +1102,8 @@ unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
stream_set_fd (stream, unix_get_fd, mum);
stream_set_flags (stream, MU_STREAM_READ, mum);
header_set_stream (header, stream, mum);
header_set_size (header, unix_header_size, mum);
header_set_lines (header, unix_header_lines, mum);
message_set_header (msg, header, mum);
}
......@@ -1143,9 +1159,8 @@ unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
static int
unix_append_message (mailbox_t mbox, message_t msg)
{
unix_data_t mud;
if (mbox == NULL || msg == NULL ||
(mud = (unix_data_t)mbox->data) == NULL)
unix_data_t mud = mbox->data;
if (msg == NULL || mud == NULL)
return EINVAL;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
......@@ -1166,53 +1181,129 @@ unix_append_message (mailbox_t mbox, message_t msg)
return status;
}
/* Generate a "From " separator. */
{
char from[128];
char date[128];
char *s;
size_t f = 0, d = 0;
*date = *from = '\0';
message_from (msg, from, sizeof (from), &f);
s = memchr (from, nl, f);
if (s)
switch (mud->state)
{
case UNIX_NO_STATE:
mud->from = calloc (128, sizeof (char));
if (mud->from == NULL)
{
unix_unlock (mbox);
return ENOMEM;
}
mud->date = calloc (128, sizeof (char));
if (mud->date == NULL)
{
free (mud->from);
mud->from = NULL;
mud->state = UNIX_NO_STATE;
unix_unlock (mbox);
return ENOMEM;
}
mud->off = 0;
mud->state = UNIX_STATE_FROM;
case UNIX_STATE_FROM:
/* Generate a "From " separator. */
{
*s = '\0';
f--;
char *s;
size_t len = 0;
status = message_from (msg, mud->from, 127, &len);
if (status != 0)
{
if (status != EAGAIN)
{
free (mud->from);
free (mud->date);
mud->date = mud->from = NULL;
mud->state = UNIX_NO_STATE;
unix_unlock (mbox);
}
return status;
}
/* Nuke trailing newline. */
s = memchr (mud->from, nl, len);
if (s)
*s = '\0';
mud->state = UNIX_STATE_DATE;
}
message_received (msg, date, sizeof (date), &d);
s = memchr (date, nl, d);
if (s)
case UNIX_STATE_DATE:
/* Generate a date for the "From " separator. */
{
*s = '\0';
d--;
char *s;
size_t len = 0;
status = message_received (msg, mud->date, 127, &len);
if (status != 0)
{
if (status != EAGAIN)
{
free (mud->from);
free (mud->date);
mud->date = mud->from = NULL;
mud->state = UNIX_NO_STATE;
unix_unlock (mbox);
}
return status;
}
/* Nuke trailing newline. */
s = memchr (mud->date, nl, len);
if (s)
*s = '\0';
/* Write the separator to the mailbox. */
stream_write (mbox->stream, "From ", 5, size, &n);
size += n;
stream_write (mbox->stream, mud->from, strlen (mud->from), size, &n);
size += n;
stream_write (mbox->stream, " ", 1, size, &n);
size += n;
stream_write (mbox->stream, mud->date, strlen (mud->date), size, &n);
size += n;
stream_write (mbox->stream, &nl , 1, size, &n);
size += n;
free (mud->from);
free (mud->date);
mud->from = mud->date = NULL;
mud->state = UNIX_STATE_APPEND;
}
stream_write (mbox->stream, "From ", 5, size, &n); size += n;
stream_write (mbox->stream, from, f, size, &n); size += n;
stream_write (mbox->stream, " ", 1, size, &n); size += n;
stream_write (mbox->stream, date, d, size, &n); size += n;
stream_write (mbox->stream, &nl , 1, size, &n); size += n;
}
/* Append the Message. */
{
char buffer[BUFSIZ];
size_t nread = 0;
off_t off = 0;
stream_t is;
message_get_stream (msg, &is);
do
case UNIX_STATE_APPEND:
/* Append the Message. */
{
stream_read (is, buffer, sizeof (buffer), off, &nread);
stream_write (mbox->stream, buffer, nread, size, &n);
off += nread;
size += n;
char buffer[BUFSIZ];
size_t nread = 0;
stream_t is;
message_get_stream (msg, &is);
do
{
status = stream_read (is, buffer, sizeof (buffer), mud->off,
&nread);
if (status != 0)
{
if (status != EAGAIN)
{
free (mud->from);
free (mud->date);
mud->date = mud->from = NULL;
mud->state = UNIX_NO_STATE;
unix_unlock (mbox);
}
stream_flush (mbox->stream);
return status;
}
stream_write (mbox->stream, buffer, nread, size, &n);
mud->off += nread;
size += n;
}
while (nread > 0);
stream_write (mbox->stream, &nl, 1, size, &n);
}
while (nread > 0);
stream_write (mbox->stream, &nl, 1, size, &n);
}
default:
break;
}
}
stream_flush (mbox->stream);
mud->state = UNIX_NO_STATE;
unix_unlock (mbox);
return 0;
}
......@@ -1238,8 +1329,8 @@ unix_size (mailbox_t mbox, off_t *psize)
static int
unix_messages_count (mailbox_t mbox, size_t *pcount)
{
unix_data_t mud;
if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
unix_data_t mud = mbox->data;
if (mud == NULL)
return EINVAL;
if (! unix_is_updated (mbox))
......
......@@ -153,6 +153,17 @@ message_set_body (message_t msg, body_t body, void *owner)
}
int
message_set_stream (message_t msg, stream_t stream, void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->stream = stream;
return 0;
}
int
message_get_stream (message_t msg, stream_t *pstream)
{
if (msg == NULL || pstream == NULL)
......@@ -177,11 +188,26 @@ message_get_stream (message_t msg, stream_t *pstream)
}
int
message_set_lines (message_t msg, int (*_lines)
(message_t, size_t *), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_lines = _lines;
return 0;
}
int
message_lines (message_t msg, size_t *plines)
{
size_t hlines, blines;
if (msg == NULL)
return EINVAL;
/* Overload */
if (msg->_lines)
return msg->_lines (msg, plines);
if (plines)
{
hlines = blines = 0;
......@@ -193,11 +219,26 @@ message_lines (message_t msg, size_t *plines)
}
int
message_set_size (message_t msg, int (*_size)
(message_t, size_t *), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_size = _size;
return 0;
}
int
message_size (message_t msg, size_t *psize)
{
size_t hsize, bsize;
if (msg == NULL)
return EINVAL;
/* Overload ? */
if (msg->_size)
return msg->_size (msg, psize);
if (psize)
{
hsize = bsize = 0;
......@@ -235,14 +276,14 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
if (msg->_from)
return msg->_from (msg, buf, len, pnwrite);
/* can it be extracted from the FROM: */
/* can it be extracted from the From: */
message_get_header (msg, &header);
status = header_get_value (header, "FROM", NULL, 0, &n);
status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &n);
if (status == 0 && n != 0)
{
char *from = calloc (1, n + 1);
char *addr;
header_get_value (header, "FROM", from, n + 1, NULL);
header_get_value (header, MU_HEADER_FROM, from, n + 1, NULL);
if (extract_addr (from, n, &addr, &n) == 0)
{
n = (n > len) ? len : n;
......@@ -258,6 +299,8 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
return 0;
}
}
else if (status == EAGAIN)
return status;
/* oops */
n = (7 > len) ? len: 7;
......@@ -374,16 +417,43 @@ message_set_uidl (message_t msg, int (* _get_uidl)
}
int
message_is_mime (message_t msg)
message_set_is_multipart (message_t msg, int (*_is_multipart)
__P ((message_t, int *)), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_is_multipart = _is_multipart;
return 0;
}
int
message_is_multipart (message_t msg, int *p_is_mp)
{
header_t header;
int status;
size_t len = 0;
status = message_get_header(msg, &header);
if (status != 0)
return status;
status = header_get_value (header, "Mime-Version", NULL, 0, NULL);
return (status == 0);
if (msg == NULL || p_is_mp)
return EINVAL;
message_get_header(msg, &header);
status = header_get_value (header, "Content-Type", NULL, 0, &len);
if (status == 0)
{
char *content_type = calloc (len + 1, sizeof (char));
if (content_type == NULL)
return ENOMEM;
status = header_get_value (header, "Content-Type", content_type,
len, NULL);
*p_is_mp = strncasecmp ("multipart", content_type,
strlen ("multipart")) ? 0: 1;
free (content_type);
}
else
*p_is_mp = 0;
return status;
}
int
......@@ -422,6 +492,7 @@ message_get_part (message_t msg, size_t part, message_t *pmsg)
if (msg == NULL || pmsg == NULL)
return EINVAL;
/* Overload. */
if (msg->_get_part)
return msg->_get_part (msg, part, pmsg);
......@@ -518,12 +589,11 @@ static int
message_read (stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread )
{
message_t msg;
message_t msg = is->owner;
stream_t his, bis;
size_t hread, hsize, bread, bsize;
if (is == NULL || (msg = is->owner) == NULL)
if (msg == NULL)
return EINVAL;
bsize = hsize = bread = hread = 0;
......@@ -536,16 +606,10 @@ message_read (stream_t is, char *buf, size_t buflen,
until you start reading them. So by checking hsize == bsize == 0,
this kludge is a way of detecting the anomalie and start by the
header. */
if ((size_t)off <= hsize || (hsize == 0 && bsize == 0))
if ((size_t)off < hsize || (hsize == 0 && bsize == 0))
{
header_get_stream (msg->header, &his);
stream_read (his, buf, buflen, off, &hread);
/* still room left for some body, .. a pun ;-) */
if ((buflen - hread) > 0)
{
body_get_stream (msg->body, &bis);
stream_read (bis, buf + hread, buflen - hread, 0, &bread);
}
}
else
{
......