Commit 24d3722e 24d3722ecab73da942988dc586ebfc28748fb873 by Alain Magloire

Cleanup again and all of this done with one hand !!!

We're moving closer to cleaning the repository and using
autoconf and all.  But my keyboard quota is almost expired.
1 parent 75a14dc5
......@@ -23,7 +23,7 @@
#include <errno.h>
int
attribute_create (attribute_t *pattr)
attribute_create (attribute_t *pattr, void *owner)
{
attribute_t attr;
if (pattr == NULL)
......@@ -31,16 +31,19 @@ attribute_create (attribute_t *pattr)
attr = calloc (1, sizeof(*attr));
if (attr == NULL)
return ENOMEM;
attr->owner = owner;
*pattr = attr;
return 0;
}
void
attribute_destroy (attribute_t *pattr)
attribute_destroy (attribute_t *pattr, void *owner)
{
if (pattr && *pattr)
{
free (*pattr);
attribute_t attr = *pattr;
if (attr->owner != owner)
free (*pattr);
/* loose the link */
*pattr = NULL;
}
......@@ -48,68 +51,144 @@ attribute_destroy (attribute_t *pattr)
}
int
attribute_get_flags (attribute_t attr, int *pflags)
{
if (attr->_get_flags)
return attr->_get_flags (attr, pflags);
if (pflags)
*pflags = attr->flags;
return 0;
}
int
attribute_set_flags (attribute_t attr, int flags)
{
if (attr->_set_flags)
return attr->_set_flags (attr, flags);
attr->flags |= flags;
return 0;
}
int
attribute_set_get_flags (attribute_t attr, int (*_get_flags)
(attribute_t, int *), void *owner)
{
if (attr == NULL)
return EINVAL;
if (attr->owner != owner)
return EACCES;
attr->_get_flags = _get_flags;
return 0;
}
int
attribute_set_set_flags (attribute_t attr, int (*_set_flags)
(attribute_t, int), void *owner)
{
if (attr == NULL)
return EINVAL;
if (attr->owner != owner)
return EACCES;
attr->_set_flags = _set_flags;
return 0;
}
int
attribute_set_unset_flags (attribute_t attr, int (*_unset_flags)
(attribute_t, int), void *owner)
{
if (attr == NULL)
return EINVAL;
if (attr->owner != owner)
return EACCES;
attr->_unset_flags = _unset_flags;
return 0;
}
int
attribute_set_seen (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_SEEN;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
attr->flags |= MU_ATTRIBUTE_SEEN;
return 0;
}
int
attribute_set_answered (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_ANSWERED;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
attr->flags |= MU_ATTRIBUTE_ANSWERED;
return 0;
}
int
attribute_set_flagged (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_FLAGGED;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
attr->flags |= MU_ATTRIBUTE_FLAGGED;
return 0;
}
int
attribute_set_read (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_READ;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
attr->flags |= MU_ATTRIBUTE_READ;
return 0;
}
int
attribute_set_deleted (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_DELETED;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
attr->flags |= MU_ATTRIBUTE_DELETED;
return 0;
}
int
attribute_set_draft (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_DRAFT;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
attr->flags |= MU_ATTRIBUTE_DRAFT;
return 0;
}
int
attribute_set_recent (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return EINVAL;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
if (attr == NULL)
{
attr->flag &= ~MU_ATTRIBUTE_READ;
attr->flag &= ~MU_ATTRIBUTE_SEEN;
attr->flags &= ~MU_ATTRIBUTE_READ;
attr->flags &= ~MU_ATTRIBUTE_SEEN;
return 0;
}
return EACCES;
......@@ -118,131 +197,176 @@ attribute_set_recent (attribute_t attr)
int
attribute_is_seen (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
return attr->flag & MU_ATTRIBUTE_SEEN;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
return attr->flags & MU_ATTRIBUTE_SEEN;
}
int
attribute_is_answered (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
return attr->flag & MU_ATTRIBUTE_ANSWERED;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
return attr->flags & MU_ATTRIBUTE_ANSWERED;
}
int
attribute_is_flagged (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
return attr->flag & MU_ATTRIBUTE_FLAGGED;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
return attr->flags & MU_ATTRIBUTE_FLAGGED;
}
int
attribute_is_read (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
return attr->flag & MU_ATTRIBUTE_READ;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
return attr->flags & MU_ATTRIBUTE_READ;
}
int
attribute_is_deleted (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
return attr->flag & MU_ATTRIBUTE_DELETED;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
return attr->flags & MU_ATTRIBUTE_DELETED;
}
int
attribute_is_draft (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
return attr->flag & MU_ATTRIBUTE_DRAFT;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
return attr->flags & MU_ATTRIBUTE_DRAFT;
}
int
attribute_is_recent (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
/* something is recent when it is not read and not seen. */
return (attr->flag == 0
|| ! ((attr->flag & MU_ATTRIBUTE_SEEN)
&& (attr->flag & MU_ATTRIBUTE_READ)));
return (attr->flags == 0
|| ! ((attr->flags & MU_ATTRIBUTE_SEEN)
&& (attr->flags & MU_ATTRIBUTE_READ)));
}
int
attribute_unset_seen (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
attr->flag &= ~MU_ATTRIBUTE_SEEN;
return 0;
if (attr->_unset_flags)
status = attr->_unset_flags (attr, MU_ATTRIBUTE_SEEN);
attr->flags &= ~MU_ATTRIBUTE_SEEN;
return status;
}
int
attribute_unset_answered (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
attr->flag &= ~MU_ATTRIBUTE_ANSWERED;
return 0;
if (attr->_unset_flags)
status = attr->_unset_flags (attr, MU_ATTRIBUTE_ANSWERED);
attr->flags &= ~MU_ATTRIBUTE_ANSWERED;
return status;
}
int
attribute_unset_flagged (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
attr->flag &= ~MU_ATTRIBUTE_FLAGGED;
return 0;
if (attr->_unset_flags)
status = attr->_unset_flags (attr, MU_ATTRIBUTE_FLAGGED);
attr->flags &= ~MU_ATTRIBUTE_FLAGGED;
return status;
}
int
attribute_unset_read (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
attr->flag &= ~MU_ATTRIBUTE_READ;
return 0;
if (attr->_unset_flags)
status = attr->_unset_flags (attr, MU_ATTRIBUTE_READ);
attr->flags &= ~MU_ATTRIBUTE_READ;
return status;
}
int
attribute_unset_deleted (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
attr->flag &= ~MU_ATTRIBUTE_DELETED;
return 0;
if (attr->_unset_flags)
status = attr->_unset_flags (attr, MU_ATTRIBUTE_DELETED);
attr->flags &= ~MU_ATTRIBUTE_DELETED;
return status;
}
int
attribute_unset_draft (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
attr->flag &= ~MU_ATTRIBUTE_DRAFT;
return 0;
if (attr->_unset_flags)
status = attr->_unset_flags (attr, MU_ATTRIBUTE_DRAFT);
attr->flags &= ~MU_ATTRIBUTE_DRAFT;
return status;
}
int
attribute_unset_recent (attribute_t attr)
{
int status = 0;
if (attr == NULL)
return 0;
attr->flag |= MU_ATTRIBUTE_SEEN;
return 0;
if (attr->_unset_flags)
status = attr->_unset_flags (attr, MU_ATTRIBUTE_SEEN);
attr->flags |= MU_ATTRIBUTE_SEEN;
return status;
}
int
attribute_is_equal (attribute_t attr, attribute_t attr2)
{
int status = 0;
if (attr == NULL || attr2 == NULL)
return 0;
return attr->flag == attr2->flag;
if (attr->_get_flags)
status = attr->_get_flags (attr, &(attr->flags));
return attr->flags == attr2->flags;
}
int
......@@ -255,14 +379,12 @@ attribute_copy (attribute_t dest, attribute_t src)
}
int
string_to_attribute (const char *buffer, attribute_t *pattr)
string_to_flags (const char *buffer, int *pflags)
{
const char *sep;
int status;
status = attribute_create (pattr);
if (status != 0)
return status;
if (pflags == NULL)
return EINVAL;
/* Set the attribute */
if (strncasecmp (buffer, "Status:", 7) == 0)
......@@ -271,22 +393,22 @@ string_to_attribute (const char *buffer, attribute_t *pattr)
sep++;
}
else
sep = buffer;
return EINVAL;
while (*sep == ' ') sep++; /* glob spaces */
if (strchr (sep, 'R') != NULL || strchr (sep, 'r') != NULL)
attribute_set_read (*pattr);
*pflags |= MU_ATTRIBUTE_READ;
if (strchr (sep, 'O') != NULL || strchr (sep, 'o') != NULL)
attribute_set_seen (*pattr);
*pflags |= MU_ATTRIBUTE_SEEN;
if (strchr (sep, 'A') != NULL || strchr (sep, 'a') != NULL)
attribute_set_answered (*pattr);
*pflags |= MU_ATTRIBUTE_ANSWERED;
if (strchr (sep, 'F') != NULL || strchr (sep, 'f') != NULL)
attribute_set_flagged (*pattr);
*pflags |= MU_ATTRIBUTE_FLAGGED;
return 0;
}
int
attribute_to_string (attribute_t attr, char *buffer, size_t len, size_t *pn)
int
flags_to_string (int flags, char *buffer, size_t len, size_t *pn)
{
char status[32];
char a[8];
......@@ -294,14 +416,16 @@ attribute_to_string (attribute_t attr, char *buffer, size_t len, size_t *pn)
*status = *a = '\0';
if (attribute_is_seen (attr))
if (flags & MU_ATTRIBUTE_SEEN)
strcat (a, "R");
if (attribute_is_answered (attr))
if (flags & MU_ATTRIBUTE_ANSWERED)
strcat (a, "A");
if (attribute_is_flagged (attr))
if (flags & MU_ATTRIBUTE_FLAGGED)
strcat (a, "F");
if (attribute_is_read (attr))
if (flags & MU_ATTRIBUTE_READ)
strcat (a, "O");
if (flags & MU_ATTRIBUTE_DELETED)
strcat (a, "d");
if (*a != '\0')
{
......
......@@ -20,7 +20,7 @@
# include "config.h"
#endif
#include <header.h>
#include <header0.h>
#include <io0.h>
#include <string.h>
#include <stdlib.h>
......@@ -33,30 +33,6 @@ static int header_read (stream_t is, char *buf, size_t buflen,
static int header_write (stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite);
struct _hdr
{
char *fn;
char *fn_end;
char *fv;
char *fv_end;
};
struct _header
{
/* Owner. */
void *owner;
/* Data. */
char *blurb;
size_t blurb_len;
size_t hdr_count;
struct _hdr *hdr;
/* Streams. */
stream_t stream;
int (*_get_value) __P ((header_t, const char *, char *, size_t , size_t *));
};
int
header_create (header_t *ph, const char *blurb, size_t len, void *owner)
{
......@@ -66,6 +42,7 @@ header_create (header_t *ph, const char *blurb, size_t len, void *owner)
return ENOMEM;
h->owner = owner;
/* Ignore the return value. */
header_parse (h, blurb, len);
*ph = h;
......@@ -83,8 +60,10 @@ header_destroy (header_t *ph, void *owner)
if (h->owner == owner)
{
stream_destroy (&(h->stream), h);
free (h->hdr);
free (h->blurb);
if (h->hdr)
free (h->hdr);
if (h->blurb)
free (h->blurb);
free (h);
}
*ph = NULL;
......@@ -207,8 +186,7 @@ header_parse (header_t header, const char *blurb, int len)
}
/* FIXME: grossly inneficient, to many copies and reallocating.
* This all header business need a good rewrite.
*/
This all header business need a good rewrite. */
int
header_set_value (header_t header, const char *fn, const char *fv, int replace)
{
......@@ -218,11 +196,14 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
if (header == NULL || fn == NULL || fv == NULL)
return EINVAL;
/* Easy approach: if replace, overwrite the field-{namve,value}
and readjust the pointers by calling header_parse ()
this is wastefull, we're just fragmenting the memory
it can be done better. But that may imply a rewite of the headers
So for another day. */
/* Try to fill out the buffer, if we know how. */
if (header->_set_value != NULL)
return header->_set_value (header, fn, fv, replace);
/* Easy approach: if replace, overwrite the field-{name,value} and readjust
the pointers by calling header_parse () this is wastefull, we're just
fragmenting the memory it can be done better. But that may imply a
rewite of the headers So for another day. */
if (replace)
{
size_t name_len;
......@@ -251,8 +232,8 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
}
}
/* Replacing was taking care of above now just add to
the end the new header. Really not cute. */
/* Replacing was taking care of above now just add to the end the new
header. Really not cute. */
len = strlen (fn) + strlen (fv) + 1 + 1 + 1 + 1;
blurb = calloc (header->blurb_len + len, 1);
if (blurb == NULL)
......@@ -266,20 +247,6 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
}
int
header_set_get_value (header_t header, int (*_get_value)
(header_t, const char *, char *, size_t, size_t *),
void *owner)
{
if (header == NULL)
return EINVAL;
if (header->owner != owner)
return EACCES;
header->_get_value = _get_value;
return 0;
}
int
header_get_value (header_t header, const char *name, char *buffer,
size_t buflen, size_t *pn)
{
......@@ -287,20 +254,61 @@ header_get_value (header_t header, const char *name, char *buffer,
size_t name_len;
size_t total = 0, fn_len = 0, fv_len = 0;
int threshold;
int err = 0;
if (header == NULL || name == NULL)
return EINVAL;
if (header->_get_value != NULL)
return header->_get_value (header, name, buffer, buflen, pn);
/* Try to fill out the buffer, if we know how. */
if (header->blurb == NULL)
{
stream_t is;
err = header_get_stream (header, &is);
if (err != 0)
return err;
else
{
char buf[1024];
char *tbuf;
size_t nread = 0;
do
{
err = stream_read (is, buf, sizeof (buf), header->temp_blurb_len,
&nread);
if (err != 0
|| (tbuf = realloc (header->temp_blurb,
header->temp_blurb_len + nread)) == NULL)
{
free (header->temp_blurb);
header->temp_blurb = NULL;
header->temp_blurb_len = 0;
return err;
}
else
header->temp_blurb = tbuf;
memcpy (header->temp_blurb + header->temp_blurb_len, buf, nread);
header->temp_blurb_len += nread;
} while (nread != 0);
/* parse it. */
header_parse (header, header->temp_blurb, header->temp_blurb_len);
free (header->temp_blurb);
header->temp_blurb = NULL;
header->temp_blurb_len = 0;
}
}
/* We set the threshold to be 1 less for the null. */
threshold = --buflen;
/* Caution: We may have more then one value for a field
name, for example a "Received" field-name is added by
each passing MTA. The way that the parsing (_parse())
is done it's not take to account. So we just stuff in
the buffer all the field-values to a corresponding field-name.
FIXME: Should we kosher the output ? meaning replace
occurences of " \t\r\n" for spaces ? for now we don't. */
/* Caution: We may have more then one value for a field name, for example
a "Received" field-name is added by each passing MTA. The way that the
parsing (_parse()) is done it's not take to account. So we just stuff
in the buffer all the field-values to a corresponding field-name.
FIXME: Should we kosher the output ? meaning replace occurences of
" \t\r\n" for spaces ? for now we don't. */
for (name_len = strlen (name), i = 0; i < header->hdr_count; i++)
{
fn_len = header->hdr[i].fn_end - header->hdr[i].fn;
......@@ -332,48 +340,35 @@ header_get_value (header_t header, const char *name, char *buffer,
*buffer = '\0'; /* Null terminated. */
if (pn)
*pn = total;
/* Check if they provided a hook. */
if (total == 0)
{
int err = ENOENT;
/* Check if they provided a hook. */
err = ENOENT;
if (header->_get_value != NULL)
err = header->_get_value (header, name, buffer, buflen, pn);
/* Cache it locally. */
/* Success. Cache it locally. */
if (err == 0)
header_set_value (header, name, buffer, 0);
return err;
}
return 0;
}
int
header_entry_count (header_t header, size_t *pnum)
{
if (header == NULL)
{
if (pnum)
*pnum = 0;
return EINVAL;
}
if (pnum)
*pnum = header->hdr_count;
return 0;
return err;
}
int
header_lines (header_t header, size_t *plines)
{
int n;
size_t t = 0;
size_t lines = 0;
if (header == NULL)
return EINVAL;
for (n = header->blurb_len - 1; n >= 0; n--)
{
if (header->blurb[n] == '\n')
t++;
lines++;
}
if (plines)
*plines = t;
*plines = lines;
return 0;
}
......@@ -382,57 +377,50 @@ header_size (header_t header, size_t *pnum)
{
if (header == NULL)
return EINVAL;
if (pnum)
*pnum = header->blurb_len;
return 0;
}
int
header_entry_name (header_t header, size_t num, char *buf,
size_t buflen, size_t *nwritten)
header_set_get_value (header_t header, int (*_get_value)
(header_t, const char *, char *, size_t, size_t *),
void *owner)
{
size_t len;
if (header == NULL)
return EINVAL;
if (header->hdr_count == 0 || num > header->hdr_count)
return ENOENT;
len = header->hdr[num].fn_end - header->hdr[num].fn;
/* save one for the null */
--buflen;
if (buf && buflen > 0)
{
buflen = (len > buflen) ? buflen : len;
memcpy (buf, header->hdr[num].fn, buflen);
buf[buflen] = '\0';
}
if (nwritten)
*nwritten = len;
if (header->owner != owner)
return EACCES;
header->_get_value = _get_value;
return 0;
}
int
header_entry_value (header_t header, size_t num, char *buf,
size_t buflen, size_t *nwritten)
header_set_set_value (header_t header, int (*_set_value)
(header_t , const char *, const char *, int),
void *owner)
{
size_t len;
if (header == NULL)
return EINVAL;
if (header->hdr_count == 0 || num > header->hdr_count)
return ENOENT;
len = header->hdr[num].fv_end - header->hdr[num].fv;
/* Save one for the null. */
--buflen;
if (buf && buflen > 0)
{
buflen = (len > buflen) ? buflen : len;
memcpy (buf, header->hdr[num].fv, buflen);
buf[buflen] = '\0';
}
if (nwritten)
*nwritten = len;
if (header->owner != owner)
return EACCES;
header->_set_value = _set_value;
return 0;
}
int
header_set_stream (header_t header, stream_t stream, void *owner)
{
if (header == NULL)
return EINVAL;
if (header->owner != owner)
return EACCES;
header->stream = stream;
return 0;
}
static int
header_write (stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite)
......
......@@ -34,17 +34,13 @@ extern "C" {
struct _attribute
{
size_t flag;
void *owner;
size_t flags;
int (*_get_flags) __P ((attribute_t, int *));
int (*_set_flags) __P ((attribute_t, int));
int (*_unset_flags) __P ((attribute_t, int));
};
#define MU_ATTRIBUTE_ANSWERED 0x01
#define MU_ATTRIBUTE_FLAGGED 0x02
#define MU_ATTRIBUTE_DELETED 0x04
#define MU_ATTRIBUTE_DRAFT 0x08
#define MU_ATTRIBUTE_SEEN 0x10
#define MU_ATTRIBUTE_READ 0x20
#define MU_ATTRIBUTE_RECENT 0x00
#ifdef __cplusplus
}
#endif
......
......@@ -35,8 +35,16 @@ extern "C" {
struct _attribute;
typedef struct _attribute * attribute_t;
extern int attribute_create __P ((attribute_t *));
extern void attribute_destroy __P ((attribute_t *));
#define MU_ATTRIBUTE_ANSWERED 0x01
#define MU_ATTRIBUTE_FLAGGED 0x02
#define MU_ATTRIBUTE_DELETED 0x04
#define MU_ATTRIBUTE_DRAFT 0x08
#define MU_ATTRIBUTE_SEEN 0x10
#define MU_ATTRIBUTE_READ 0x20
#define MU_ATTRIBUTE_RECENT 0x00
extern int attribute_create __P ((attribute_t *, void *));
extern void attribute_destroy __P ((attribute_t *, void *));
extern int attribute_is_seen __P ((attribute_t));
extern int attribute_is_answered __P ((attribute_t));
......@@ -62,14 +70,22 @@ extern int attribute_unset_draft __P ((attribute_t));
extern int attribute_unset_recent __P ((attribute_t));
extern int attribute_unset_read __P ((attribute_t));
extern int attribute_get_flags __P ((attribute_t, int *));
extern int attribute_set_flags __P ((attribute_t, int));
extern int attribute_set_set_flags __P ((attribute_t, int (*_set_flags)
__P ((attribute_t, int)), void *));
extern int attribute_set_unset_flags __P ((attribute_t, int (*_unset_flags)
__P ((attribute_t, int)), void *));
extern int attribute_set_get_flags __P ((attribute_t, int (*_get_flags)
__P ((attribute_t, int *)), void *));
extern int attribute_is_equal __P ((attribute_t att1, attribute_t att2));
extern int attribute_copy __P ((attribute_t dst,
attribute_t src));
extern int string_to_attribute __P ((const char *buf,
attribute_t *pattr));
extern int attribute_to_string __P ((attribute_t attr, char *buf,
extern int string_to_flags __P ((const char *buf, int *pattr));
extern int flags_to_string __P ((int flags, char *buf,
size_t len, size_t *));
#ifdef __cplusplus
......
......@@ -67,27 +67,27 @@ extern "C" {
struct _header;
typedef struct _header * header_t;
extern int header_create __P ((header_t *, const char *blurb,
size_t ln, void *owner));
extern void header_destroy __P ((header_t *, void *owner));
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_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_value __P ((header_t, const char *fn,
const char *fv, int replace));
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 *fn, char *buf,
size_t buflen, size_t *nwritten)),
void *owner));
extern int header_get_value __P ((header_t, const char *fn, char *buf,
size_t buflen, size_t *nwritten));
extern int header_entry_count __P ((header_t, size_t *num));
extern int header_entry_name __P ((header_t, size_t num, char *buf,
size_t buflen, size_t *total));
extern int header_entry_value __P ((header_t, size_t num, char *buf,
size_t buflen, size_t *total));
extern int header_get_stream __P ((header_t, stream_t *stream));
extern int header_size __P ((header_t, size_t *size));
extern int header_lines __P ((header_t, size_t *lines));
__P ((header_t, const char *,
char *, size_t, size_t *)),
void *));
#ifdef _cplusplus
}
......
......@@ -21,8 +21,8 @@
#include <message0.h>
#include <registrar0.h>
#include <auth0.h>
#include <attribute.h>
#include <mailutils_errno.h>
#include <header0.h>
#include <attribute0.h>
#include <termios.h>
#include <errno.h>
......@@ -33,34 +33,62 @@
#include <fcntl.h>
static int mailbox_pop_create (mailbox_t *mbox, const char *name);
static void mailbox_pop_destroy (mailbox_t *mbox);
struct mailbox_registrar _mailbox_pop_registrar =
/* 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. */
enum pop_state
{
"POP3",
mailbox_pop_create, mailbox_pop_destroy
/* 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_OPEN_CONNECTION,
POP_GREETINGS,
POP_APOP_TX, POP_APOP_ACK,
POP_DELE_TX, POP_DELE_ACK,
POP_LIST_TX, POP_LIST_ACK, POP_LIST_RX,
POP_PASS_TX, POP_PASS_ACK,
POP_QUIT_TX, POP_QUIT_ACK,
POP_NOOP_TX, POP_NOOP_ACK,
POP_RETR_TX, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY,
POP_RSET_TX, POP_RSET_ACK,
POP_STAT_TX, POP_STAT_ACK,
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. */
};
static int mailbox_pop_open (mailbox_t, int flags);
static int mailbox_pop_close (mailbox_t);
static int mailbox_pop_get_message (mailbox_t, size_t msgno, message_t *msg);
static int mailbox_pop_messages_count (mailbox_t, size_t *num);
static int mailbox_pop_expunge (mailbox_t);
static int mailbox_pop_num_deleted (mailbox_t, size_t *);
/* Those two are exportable funtions i.e. they are visible/call when you
call a URL "pop://..." to mailbox_create. */
/* update and scanning*/
static int mailbox_pop_is_updated (mailbox_t);
static int mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount);
static int pop_create (mailbox_t *, const char *);
static void pop_destroy (mailbox_t *);
/* mailbox size ? */
static int mailbox_pop_size (mailbox_t, off_t *size);
static int mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread);
static int mailbox_pop_getfd (stream_t, int *pfd);
static int mailbox_pop_body_size (body_t, size_t *psize);
struct mailbox_registrar _mailbox_pop_registrar =
{
"POP3",
pop_create, pop_destroy
};
/* Functions/Methods that implements the mailbox_t API. */
static int pop_open (mailbox_t, int);
static int pop_close (mailbox_t);
static int pop_get_message (mailbox_t, size_t, message_t *);
static int pop_messages_count (mailbox_t, size_t *);
static int pop_expunge (mailbox_t);
static int pop_num_deleted (mailbox_t, size_t *);
static int pop_scan (mailbox_t, size_t, size_t *);
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_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 *);
/* According to the rfc:
RFC 2449 POP3 Extension Mechanism November 1998
......@@ -82,7 +110,15 @@ static int mailbox_pop_body_size (body_t, size_t *psize);
the initial greeting) is unchanged at 512 octets (including the
terminating CRLF). */
/* buffered IO */
/* Buffered I/O, since the connection maybe non-blocking, we use a little
working buffer to hold the I/O between us and the POP3 Server. For
example if write () return EAGAIN, we keep on calling bio_write () until
the buffer is empty. bio_read () does a little more, it takes care of
filtering out the starting "." and return O(zero) when seeing the terminal
octets ".\r\n". bio_readline () insists on having a _complete_ line .i.e
a string terminated by \n, it will allocate/grow the working buffer as
needed. The '\r\n" termination is converted to '\n'. bio_destroy ()
does not close the stream but only free () the working buffer. */
struct _bio
{
#define POP_BUFSIZ 512
......@@ -94,64 +130,93 @@ 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 *);
static int bio_readline (bio_t);
static int bio_read (bio_t);
static int bio_write (bio_t);
struct _mailbox_pop_data;
struct _mailbox_pop_message;
typedef struct _mailbox_pop_data * mailbox_pop_data_t;
typedef struct _mailbox_pop_message * mailbox_pop_message_t;
struct _mailbox_pop_message
static int bio_create (bio_t *, stream_t);
static void bio_destroy (bio_t *);
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
the command to send to RETReive the specify message. The problem comes
from the header. If the POP server supports TOP, we can cleanly fetch
the header. But otherwise we use the clumsy approach. .i.e for the header
we read 'til ^\n then discard the rest for the body we read after ^\n and
discard the beginning. This a waste, Pop was not conceive for this
obviously. */
struct _pop_message
{
bio_t bio;
int inbody;
size_t body_size;
size_t body_lines;
size_t num;
off_t body_size;
message_t message;
mailbox_pop_data_t mpd;
pop_data_t mpd; /* Back pointer. */
};
struct _mailbox_pop_data
/* Structure to hold things general to the POP client, like its state, how
many messages we have so far etc ... */
struct _pop_data
{
void *func;
void *id;
int state;
mailbox_pop_message_t *pmessages;
void *func; /* Indicate a command is in operation, busy. */
size_t id; /* Use in pop_expunge to indiate the message, if bailing out. */
enum pop_state state;
pop_message_t *pmessages;
size_t pmessages_count;
size_t messages_count;
size_t size;
#ifdef HAVE_PTHREAD_H
pthread_mutex_t mutex;
#endif
int flags;
bio_t bio;
int flags; /* Flags of for the stream_t object. */
bio_t bio; /* Working I/O buffer. */
int is_updated;
char *user;
char *user; /* Temporary holders for user and passwd. */
char *passwd;
mailbox_pop_message_t mpm;
mailbox_t mbox; /* Back pointer. */
} ;
/* Little Macro, since this is very repetitive. */
#define CLEAR_STATE(mpd) \
mpd->func = NULL, \
mpd->state = POP_NO_STATE
/* Clear the state for non recoverable error. */
#define CHECK_NON_RECOVERABLE(mpd, status) \
do \
{ \
if (status != 0) \
{ \
if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
{ \
CLEAR_STATE (mpd); \
} \
return status; \
} \
} \
while (0)
/* Parse the url, allocate mailbox_t etc .. */
static int
mailbox_pop_create (mailbox_t *pmbox, const char *name)
pop_create (mailbox_t *pmbox, const char *name)
{
mailbox_t mbox;
mailbox_pop_data_t mpd;
pop_data_t mpd;
size_t name_len;
int status;
/* Sanity check. */
if (pmbox == NULL || name == NULL || *name == '\0')
return MU_ERROR_INVALID_ARG;
return EINVAL;
name_len = strlen (name);
......@@ -173,95 +238,104 @@ mailbox_pop_create (mailbox_t *pmbox, const char *name)
/* Allocate memory for mbox. */
mbox = calloc (1, sizeof (*mbox));
if (mbox == NULL)
return MU_ERROR_OUT_OF_MEMORY;
return ENOMEM;
/* Allocate specific pop box data. */
/* Allocate specifics for pop data. */
mpd = mbox->data = calloc (1, sizeof (*mpd));
if (mbox->data == NULL)
{
mailbox_pop_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
}
/* Allocate the struct for buffered I/O. */
status = bio_create (&(mpd->bio), NULL);
if (status != 0)
{
mailbox_pop_destroy (&mbox);
return status;
pop_destroy (&mbox);
return ENOMEM;
}
mpd->state = POP_NO_STATE;
mpd->mbox = mbox;
/* Copy the name. */
mbox->name = calloc (name_len + 1, sizeof (char));
if (mbox->name == NULL)
{
mailbox_pop_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
pop_destroy (&mbox);
return ENOMEM;
}
memcpy (mbox->name, name, name_len);
#ifdef HAVE_PHTREAD_H
/* Mutex when accessing the structure fields. */
/* FIXME: should we use rdwr locks instead ?? */
pthread_mutex_init (&(mud->mutex), NULL);
/* XXXX: This is not use yet and the library is still not thread safe. This
is more a gentle remider that I got more work to do. */
pthread_mutex_init (&(mpd->mutex), NULL);
#endif
/* Initialize the structure. */
mbox->_create = mailbox_pop_create;
mbox->_destroy = mailbox_pop_destroy;
mbox->_create = pop_create;
mbox->_destroy = pop_destroy;
mbox->_open = mailbox_pop_open;
mbox->_close = mailbox_pop_close;
mbox->_open = pop_open;
mbox->_close = pop_close;
/* Messages. */
mbox->_get_message = mailbox_pop_get_message;
mbox->_messages_count = mailbox_pop_messages_count;
mbox->_expunge = mailbox_pop_expunge;
mbox->_num_deleted = mailbox_pop_num_deleted;
mbox->_get_message = pop_get_message;
mbox->_messages_count = pop_messages_count;
mbox->_expunge = pop_expunge;
mbox->_num_deleted = pop_num_deleted;
mbox->_scan = mailbox_pop_scan;
mbox->_is_updated = mailbox_pop_is_updated;
mbox->_scan = pop_scan;
mbox->_is_updated = pop_is_updated;
mbox->_size = mailbox_pop_size;
mbox->_size = pop_size;
(*pmbox) = mbox;
return 0; /* Okdoke. */
}
/* Cleaning up all the ressources. */
static void
mailbox_pop_destroy (mailbox_t *pmbox)
pop_destroy (mailbox_t *pmbox)
{
if (pmbox && *pmbox)
{
mailbox_t mbox = *pmbox;
if (mbox->data)
{
mailbox_pop_data_t mpd = mbox->data;
pop_data_t mpd = mbox->data;
size_t i;
/* Destroy the pop messages and ressources associated to them. */
for (i = 0; i < mpd->pmessages_count; i++)
{
if (mpd->pmessages[i])
{
bio_destroy (&(mpd->pmessages[i]->bio));
message_destroy (&(mpd->pmessages[i]->message),
mpd->pmessages[i]);
free (mpd->pmessages[i]);
}
free (mpd->pmessages[i]);
}
bio_destroy (&(mpd->bio));
free (mpd->pmessages);
free (mpd);
#ifdef HAVE_PHTREAD_H
pthread_mutex_destroy (&(mpd->mutex));
#endif
}
free (mbox->name);
free (mbox->event);
/* Since the mailbox is destroy, close the stream but not via
pop_close () which can return EAGAIN, or other unpleasant side
effects, but rather the hard way. */
stream_close (mbox->stream);
stream_destroy (&(mbox->stream), mbox);
auth_destroy (&(mbox->auth), mbox);
if (mbox->name)
free (mbox->name);
if (mbox->event)
free (mbox->event);
if (mbox->url)
url_destroy (&(mbox->url));
free (mbox);
*pmbox = NULL;
}
}
/* We should probably use getpass () or something similar. */
static struct termios stored_settings;
static void
......@@ -283,9 +357,8 @@ echo_on(void)
static int
pop_authenticate (auth_t auth, char **user, char **passwd)
{
/* FIXME: this incorrect and goes against GNU style: having a limitation
* on the user/passwd length, it should be fix
*/
/* FIXME: This incorrect and goes against GNU style: having a limitation on
the user/passwd length, it should be fix. */
char u[128];
char p[128];
mailbox_t mbox = auth->owner;
......@@ -294,7 +367,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
*u = '\0';
*p = '\0';
/* prompt for the user/login name */
/* Prompt for the user/login name. */
status = url_get_user (mbox->url, u, sizeof (u), NULL);
if (status != 0 || *u == '\0')
{
......@@ -302,8 +375,7 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
fgets (u, sizeof (u), stdin);
u [strlen (u) - 1] = '\0'; /* nuke the trailing NL */
}
/* prompt for the passwd */
/* FIXME: should turn off echo .... */
/* Prompt for the passwd. */
status = url_get_passwd (mbox->url, p, sizeof (p), NULL);
if (status != 0 || *p == '\0' || *p == '*')
{
......@@ -320,12 +392,12 @@ pop_authenticate (auth_t auth, char **user, char **passwd)
}
static int
mailbox_pop_open (mailbox_t mbox, int flags)
pop_open (mailbox_t mbox, int flags)
{
mailbox_pop_data_t mpd;
pop_data_t mpd;
int status;
bio_t bio;
void *func = (void *)mailbox_pop_open;
void *func = (void *)pop_open;
char host[256] ;
long port;
......@@ -333,20 +405,12 @@ mailbox_pop_open (mailbox_t mbox, int flags)
if (mbox == NULL || mbox->url == NULL || (mpd = mbox->data) == NULL)
return EINVAL;
/* Create the networking stack. */
if (mbox->stream == NULL)
{
status = tcp_stream_create (&(mbox->stream));
if (status != 0)
return status;
}
if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0 ||
(status = url_get_port (mbox->url, &port)) != 0)
/* Fetch the pop server name and the port in the url_t. */
if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0
|| (status = url_get_port (mbox->url, &port)) != 0)
return status;
/* Dealing whith Authentication. */
/* So far only normal user/pass supported. */
/* Dealing whith Authentication. So far only normal user/pass supported. */
if (mbox->auth == NULL)
{
status = auth_create (&(mbox->auth), mbox);
......@@ -361,141 +425,134 @@ mailbox_pop_open (mailbox_t mbox, int flags)
mpd->func = func;
bio = mpd->bio;
/* Enter the state machine. */
/* Enter the pop state machine, and boogy: AUTHORISATION State. */
switch (mpd->state)
{
/* Establish the connection. */
case 0:
case POP_NO_STATE:
/* Spawn auth prologue. */
auth_prologue (mbox->auth);
/* Create the networking stack. */
if (mbox->stream == NULL)
{
status = tcp_stream_create (&(mbox->stream));
if (status != 0)
return status;
}
mpd->state = POP_OPEN_CONNECTION;
case POP_OPEN_CONNECTION:
/* Establish the connection. */
status = stream_open (mbox->stream, host, port, flags);
if (status != 0)
{
/* Clear the state for non recoverable error. */
if (status != EAGAIN && status != EINPROGRESS && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
mpd->state = POP_NO_STATE;
}
return status;
}
/* Set the Buffer I/O. */
bio->stream = mbox->stream;
bio->ptr = bio->buffer;
bio->nl = NULL;
mpd->state = 1;
/* Glob the greetings. */
case 1:
status = bio_readline (bio);
/* Allocate the struct for buffered I/O. */
bio_destroy (&(mpd->bio));
status = bio_create (&(mpd->bio), mbox->stream);
/* Can't recover bailout. */
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
stream_close (bio->stream);
CLEAR_STATE (mpd);
return status;
}
bio = mpd->bio;
mpd->state = POP_GREETINGS;
case POP_GREETINGS:
/* Swallow the greetings. */
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
{
mpd->func = NULL;
mpd->state = 0;
stream_close (bio->stream);
bio->stream = NULL;
CLEAR_STATE (mpd);
return EACCES;
}
/* Fetch the the user/passwd from them. */
auth_authenticate (mbox->auth, &mpd->user, &mpd->passwd);
/* FIXME: Use snprintf. */
//mpd->len = sprintf (pop->buffer, POP_BUFSIZ, "USER %s\r\n", user);
bio->len = sprintf (bio->buffer, "USER %s\r\n", mpd->user);
bio->len = snprintf (bio->buffer, bio->maxlen, "USER %s\r\n", mpd->user);
bio->ptr = bio->buffer;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
free (mpd->user); mpd->user = NULL;
mpd->state = 2;
mpd->state = POP_USER_TX;
case POP_USER_TX:
/* Send username. */
case 2:
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
mpd->state = 3;
/* Get the ack. */
case 3:
CHECK_NON_RECOVERABLE (mpd, status);
mpd->state = POP_USER_ACK;
case POP_USER_ACK:
/* Get the user ack. */
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
CHECK_NON_RECOVERABLE (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
return EACCES;
/* FIXME Use snprintf. */
//mpd->len = snprintf (mpd->buffer, POP_BUFSIZ, "PASS %s\r\n", passwd);
bio->len = sprintf (bio->buffer, "PASS %s\r\n", mpd->passwd);
{
stream_close (bio->stream);
CLEAR_STATE (mpd);
return EACCES;
}
bio->len = snprintf (bio->buffer, POP_BUFSIZ, "PASS %s\r\n",
mpd->passwd);
bio->ptr = bio->buffer;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
/* We have to nuke the passwd. */
memset (mpd->passwd, 0, strlen (mpd->passwd));
free (mpd->passwd); mpd->passwd = NULL;
mpd->state = 4;
mpd->state = POP_PASS_TX;
case POP_PASS_TX:
/* Send passwd. */
case 4:
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
mpd->state = 5;
CHECK_NON_RECOVERABLE (mpd, status);
mpd->state = POP_PASS_ACK;
case POP_PASS_ACK:
/* Get the ack from passwd. */
case 5:
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = NULL;
mpd->state = 0;
}
return status;
}
CHECK_NON_RECOVERABLE (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
return EACCES;
}/* Swith state. */
{
stream_close (bio->stream);
CLEAR_STATE (mpd);
return EACCES;
}
break; /* We're outta here. */
default:
/*
fprintf (stderr, "pop_open unknown state\n");
*/
}/* End AUTHORISATION state. */
/* Spawn cleanup functions. */
auth_epilogue (mbox->auth);
/* Clear any state. */
mpd->id = mpd->func = NULL;
mpd->state = 0;
CLEAR_STATE (mpd);
return 0;
}
static int
mailbox_pop_close (mailbox_t mbox)
pop_close (mailbox_t mbox)
{
mailbox_pop_data_t mpd;
void *func = (void *)mailbox_pop_close;
pop_data_t mpd;
void *func = (void *)pop_close;
int status;
bio_t bio;
size_t i;
if (mbox == NULL || (mpd = mbox->data) == NULL)
return EINVAL;
......@@ -506,65 +563,74 @@ mailbox_pop_close (mailbox_t mbox)
mpd->func = func;
bio = mpd->bio;
if (bio->stream != NULL)
/* Ok boys, it's a wrap: UPDATE State. */
switch (mpd->state)
{
case POP_NO_STATE:
bio->len = snprintf (bio->buffer, bio->maxlen, "QUIT\r\n");
bio->ptr = bio->buffer;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
mpd->state = POP_QUIT_TX;
case POP_QUIT_TX:
/* Send the quit. */
status = bio_write (mpd->bio);
CHECK_NON_RECOVERABLE (mpd, status);
mpd->state = POP_QUIT_ACK;
case POP_QUIT_ACK:
/* Glob the acknowledge. */
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
/* Now what ! and how can we tell them about errors ? So for now
lets just be verbose about the error but close the connection
anyway. */
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
fprintf (stderr, "pop_close: %s\n", bio->buffer);
stream_close (bio->stream);
bio->stream = NULL;
break;
default:
/*
fprintf (stderr, "pop_close unknow state");
*/
} /* UPDATE state. */
/* free the messages */
for (i = 0; i < mpd->pmessages_count; i++)
{
switch (mpd->state)
if (mpd->pmessages[i])
{
case 0:
bio->len = sprintf (bio->buffer, "QUIT\r\n");
bio->ptr = bio->buffer;
mpd->state = 1;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
case 1:
status = bio_write (mpd->bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
}
case 2:
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
}
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
return EINVAL;
case 3:
stream_close (bio->stream);
bio->stream = NULL;
message_destroy (&(mpd->pmessages[i]->message),
mpd->pmessages[i]);
free (mpd->pmessages[i]);
}
}
free (mpd->pmessages);
mpd->pmessages = NULL;
mpd->pmessages_count = 0;
mpd->is_updated = 0;
bio_destroy (&(mpd->bio));
mpd->func = mpd->id = NULL;
mpd->state = 0;
CLEAR_STATE (mpd);
return 0;
}
static int
mailbox_pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
mailbox_pop_data_t mpd;
bio_t bio;
pop_data_t mpd;
int status;
pop_message_t mpm;
size_t i;
void *func = (void *)mailbox_pop_get_message;
/* Sanity. */
if (mbox == NULL || pmsg == NULL || (mpd = mbox->data) == NULL)
return EINVAL;
/* See if we already have this message. */
/* See if we have already this message. */
for (i = 0; i < mpd->pmessages_count; i++)
{
if (mpd->pmessages[i])
......@@ -577,280 +643,120 @@ mailbox_pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
}
}
/* Are we busy in another function ? */
if (mpd->func && mpd->func != func)
return EBUSY;
/* In the function, but are we busy with an other message/request ? */
if (mpd->id && mpd->id != *pmsg)
return EBUSY;
mpd->func = func;
bio = mpd->bio;
/* Ok men, we're going in. */
switch (mpd->state)
{
/* The message. */
case 0:
{
message_t msg;
mailbox_pop_message_t mpm ;
mpm = calloc (1, sizeof (*mpm));
if (mpm == NULL)
return ENOMEM;
/* We'll use the bio to store headers. */
mpm->bio = calloc (1, sizeof (*(mpm->bio)));
if (mpm->bio == NULL)
{
free (mpm);
mpd->func = NULL;
return ENOMEM;
}
/* Create the message. */
status = message_create (&msg, mpm);
if (status != 0)
{
free (mpm->bio);
free (mpm);
mpd->func = NULL;
return status;
}
mpm = calloc (1, sizeof (*mpm));
if (mpm == NULL)
return ENOMEM;
/* back pointer */
mpm->mpd = mpd;
mpm->num = msgno;
/* The message. */
mpm->message = msg;
mpm->num = msgno;
mpd->mpm = mpm;
/* back pointer */
mpm->mpd = mpd;
/* set the busy request state */
mpd->id = (void *)msg;
/* Get the header.
FIXME: TOP is an optionnal command, if we want to
be compliant we can not count on it to exists.
So we should be prepare when it fails and fall to
a second scheme. */
/*bio->len = snprintf (bio->buffer, POP_BUFSIZ, "TOP %d 0\r\n", msgno);*/
bio->len = sprintf (bio->buffer, "TOP %d 0\r\n", msgno);
bio->ptr = bio->buffer;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
mpd->state = 1;
}
/* Send the TOP. */
case 1:
{
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
}
return status;
}
mpd->state = 2;
}
/* Ack from TOP. */
case 2:
/* Create the message. */
{
message_t msg;
status = message_create (&msg, mpm);
if (status != 0)
{
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
}
return status;
}
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
return ERANGE;
}
free (mpm);
return status;
}
mpd->state = 5;
/* Get the header. */
case 5:
{
char *tbuf;
int nread;
while (1)
{
status = bio_readline (bio);
if (status != 0)
{
/* Recoverable. */
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
}
return status;
}
/* Our ticket out. */
if (bio->buffer[0] == '\0')
break;
nread = bio->nl - bio->buffer;
tbuf = realloc (mpd->mpm->bio->buffer,
mpd->mpm->bio->maxlen + nread);
if (tbuf == NULL)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
return ENOMEM;
}
else
mpd->mpm->bio->buffer = tbuf;
memcpy (mpd->mpm->bio->buffer + mpd->mpm->bio->maxlen,
bio->buffer, nread);
mpd->mpm->bio->maxlen += nread;
} /* while () */
} /* case 5: */
break;
default:
/* Error here unknow case. */
fprintf (stderr, "Pop unknown state(get_message)\n");
} /* switch (state) */
/* No need to carry a state anymore. */
mpd->func = mpd->id = NULL;
mpd->state = 0;
/* The message. */
mpm->message = msg;
}
/* Create the header. */
{
header_t header;
status = header_create (&header, mpd->mpm->bio->buffer,
mpd->mpm->bio->maxlen, mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
if (status != 0)
stream_t stream;
if ((status = header_create (&header, NULL, 0, mpm)) != 0
|| (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
free (mpd->mpm);
mpd->mpm = NULL;
message_destroy (&(mpm->message), mpm);
free (mpm);
return status;
}
message_set_header ((mpd->mpm->message), header, mpd->mpm);
stream_set_read (stream, pop_header_read, mpm);
stream_set_fd (stream, pop_get_fd, mpm);
stream_set_flags (stream, MU_STREAM_READ, mpm);
header_set_stream (header, stream, mpm);
message_set_header (mpm->message, header, mpm);
}
/* Reallocate the working I/O buffer. */
bio_create (&(mpd->mpm->bio), bio->stream);
/* Create the attribute. */
{
attribute_t attribute;
char hdr_status[64];
header_t header = NULL;
hdr_status[0] = '\0';
message_get_header (mpd->mpm->message, &header);
header_get_value (header, "Status", hdr_status, sizeof (hdr_status), NULL);
/* Create the attribute. */
status = string_to_attribute (hdr_status, &attribute);
status = attribute_create (&attribute, mpm);
if (status != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
message_destroy (&(mpm->message), mpm);
free (mpm);
return status;
}
message_set_attribute (mpd->mpm->message, attribute, mpd->mpm);
attribute_set_get_flags (attribute, pop_get_flags, mpm);
message_set_attribute (mpm->message, attribute, mpm);
}
/* Create the body. */
/* Create the body and its stream. */
{
stream_t stream;
body_t body;
status = body_create (&body, mpd->mpm);
status = body_create (&body, mpm);
if (status != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
message_destroy (&(mpm->message), mpm);
free (mpm);
return status;
}
message_set_body (mpd->mpm->message, body, mpd->mpm);
status = stream_create (&stream, MU_STREAM_READ, mpd->mpm);
status = stream_create (&stream, MU_STREAM_READ, mpm);
if (status != 0)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
bio_destroy (&(mpd->mpm->bio));
free (mpd->mpm);
mpd->mpm = NULL;
message_destroy (&(mpm->message), mpm);
free (mpm);
return status;
}
stream_set_read (stream, mailbox_pop_readstream, mpd->mpm);
stream_set_fd (stream, mailbox_pop_getfd, mpd->mpm);
stream_set_flags (stream, mpd->flags, mpd->mpm);
body_set_size (body, mailbox_pop_body_size, mpd->mpm);
//body_set_lines (body, mailbox_pop_body_lines, mpd->mpm);
body_set_stream (body, stream, mpd->mpm);
stream_set_read (stream, pop_readstream, mpm);
stream_set_fd (stream, pop_get_fd, mpm);
stream_set_flags (stream, mpd->flags, mpm);
body_set_size (body, pop_body_size, mpm);
body_set_lines (body, pop_body_lines, mpm);
body_set_stream (body, stream, mpm);
message_set_body (mpm->message, body, mpm);
}
/* Set the UIDL call on the message. */
message_set_uidl (mpm->message, pop_uidl, mpm);
/* Add it to the list. */
{
mailbox_pop_message_t *m ;
pop_message_t *m ;
m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m));
if (m == NULL)
{
message_destroy (&(mpd->mpm->message), mpd->mpm);
free (mpd->mpm);
mpd->mpm = NULL;
message_destroy (&(mpm->message), mpm);
free (mpm);
return ENOMEM;
}
mpd->pmessages = m;
mpd->pmessages[mpd->pmessages_count] = mpd->mpm;
mpd->pmessages[mpd->pmessages_count] = mpm;
mpd->pmessages_count++;
}
*pmsg = mpd->mpm->message;
*pmsg = mpm->message;
return 0;
}
static int
mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount)
pop_messages_count (mailbox_t mbox, size_t *pcount)
{
mailbox_pop_data_t mpd;
pop_data_t mpd;
int status;
void *func = (void *)mailbox_pop_messages_count;
void *func = (void *)pop_messages_count;
bio_t bio;
if (mbox == NULL || (mpd = (mailbox_pop_data_t)mbox->data) == NULL)
if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL)
return EINVAL;
if (mailbox_pop_is_updated (mbox))
if (pop_is_updated (mbox))
{
if (pcount)
*pcount = mpd->messages_count;
......@@ -862,34 +768,39 @@ mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount)
mpd->func = func;
bio = mpd->bio;
/* TRANSACTION state. */
switch (mpd->state)
{
case 0:
case POP_NO_STATE:
bio->len = sprintf (bio->buffer, "STAT\r\n");
bio->ptr = bio->buffer;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
mpd->state = 1;
mpd->state = POP_STAT_TX;
case POP_STAT_TX:
/* Send the STAT. */
case 1:
status = bio_write (bio);
if (status != 0)
return status;
mpd->state = 2;
CHECK_NON_RECOVERABLE (mpd, status);
mpd->state = POP_STAT_ACK;
case POP_STAT_ACK:
/* Get the ACK. */
case 2:
status = bio_readline (bio);
if (status != 0)
return status;
CHECK_NON_RECOVERABLE (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
break;
default:
fprintf (stderr, "unknow state(messages_count)\n");
/*
fprintf (stderr, "pomp_messages_count: unknow state\n");
*/
}
mpd->id = mpd->func = NULL;
mpd->state = 0;
status = sscanf (bio->buffer, "+OK %d %d", &(mpd->messages_count),
&(mpd->size));
CLEAR_STATE (mpd);
mpd->is_updated = 1;
if (pcount)
*pcount = mpd->messages_count;
......@@ -901,23 +812,24 @@ mailbox_pop_messages_count (mailbox_t mbox, size_t *pcount)
/* Update and scanning. */
static int
mailbox_pop_is_updated (mailbox_t mbox)
pop_is_updated (mailbox_t mbox)
{
mailbox_pop_data_t mpd;
if ((mpd = (mailbox_pop_data_t)mbox->data) == NULL)
pop_data_t mpd;
if ((mpd = (pop_data_t)mbox->data) == NULL)
return 0;
return mpd->is_updated;
}
static int
mailbox_pop_num_deleted (mailbox_t mbox, size_t *pnum)
pop_num_deleted (mailbox_t mbox, size_t *pnum)
{
mailbox_pop_data_t mpd;
pop_data_t mpd;
size_t i, total;
attribute_t attr;
if (mbox == NULL ||
(mpd = (mailbox_pop_data_t) mbox->data) == NULL)
if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL)
return EINVAL;
for (i = total = 0; i < mpd->messages_count; i++)
{
if (message_get_attribute (mpd->pmessages[i]->message, &attr) != 0)
......@@ -934,11 +846,12 @@ mailbox_pop_num_deleted (mailbox_t mbox, size_t *pnum)
/* We just simulated. */
static int
mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
{
int status;
size_t i;
status = mailbox_pop_messages_count (mbox, pcount);
status = pop_messages_count (mbox, pcount);
if (status != 0)
return status;
for (i = msgno; i <= *pcount; i++)
......@@ -949,17 +862,16 @@ mailbox_pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
/* This were we actually sending the DELE command. */
static int
mailbox_pop_expunge (mailbox_t mbox)
pop_expunge (mailbox_t mbox)
{
mailbox_pop_data_t mpd;
pop_data_t mpd;
size_t i;
attribute_t attr;
bio_t bio;
int status;
void *func = (void *)mailbox_pop_expunge;
void *func = (void *)pop_expunge;
if (mbox == NULL ||
(mpd = (mailbox_pop_data_t) mbox->data) == NULL)
if (mbox == NULL || (mpd = (pop_data_t) mbox->data) == NULL)
return EINVAL;
/* Busy ? */
......@@ -969,94 +881,96 @@ mailbox_pop_expunge (mailbox_t mbox)
mpd->func = func;
bio = mpd->bio;
for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = (void *)++i)
for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = ++i)
{
if (message_get_attribute (mpd->pmessages[i]->message, &attr) == 0)
{
/* Send DELETE. */
if (attribute_is_deleted (attr))
{
switch (mpd->state)
{
case 0:
case POP_NO_STATE:
bio->len = sprintf (bio->buffer, "DELE %d\r\n",
mpd->pmessages[i]->num);
bio->ptr = bio->buffer;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
mpd->state = 1;
case 1:
mpd->state = POP_DELE_TX;
case POP_DELE_TX:
/* Send DELETE. */
status = bio_write (bio);
if (status != 0)
{
/* Clear the state for non recoverable error. */
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
fprintf(stderr, "PROBLEM write %d\n", status);
mpd->func = NULL;
mpd->id = 0;
mpd->state = POP_NO_STATE;
}
return status;
}
mpd->state = 2;
case 2:
mpd->state = POP_DELE_ACK;
case POP_DELE_ACK:
status = bio_readline (bio);
if (status != 0)
{
/* Clear the state for non recoverable error. */
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
fprintf(stderr, "PROBLEM readline %d\n", status);
mpd->func = NULL;
mpd->id = 0;
mpd->state = POP_NO_STATE;
}
return status;
}
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
fprintf(stderr, "PROBLEM strcmp\n");
mpd->func = NULL;
mpd->id = 0;
mpd->state = POP_NO_STATE;
return ERANGE;
}
mpd->state = 0;
mpd->state = POP_NO_STATE;
break;
default:
/* fprintf (stderr, "pop_expunge: unknow state\n"); */
} /* switch (state) */
} /* if attribute_is_deleted() */
} /* message_get_attribute() */
} /* for */
mpd->func = mpd->id = NULL;
mpd->state = 0;
/* Invalidate. */
mpd->id = 0;
mpd->func = NULL;
mpd->state = POP_NO_STATE;
/* Invalidate. But Really they should shutdown the challen POP protocol
is not meant for this like IMAP. */
mpd->is_updated = 0;
return 0;
}
/* Mailbox size ? */
static int
mailbox_pop_size (mailbox_t mbox, off_t *psize)
pop_size (mailbox_t mbox, off_t *psize)
{
mailbox_pop_data_t mpd;
size_t count;
int status;
pop_data_t mpd;
int status = 0;
if (mbox == NULL || (mpd = (mailbox_pop_data_t)mbox->data) == NULL)
if (mbox == NULL || (mpd = (pop_data_t)mbox->data) == NULL)
return EINVAL;
if (mailbox_pop_is_updated (mbox))
{
if (psize)
*psize = mpd->size;
return 0;
}
status = mailbox_pop_messages_count (mbox, &count);
if (! pop_is_updated (mbox))
status = pop_messages_count (mbox, &mpd->size);
if (psize)
*psize = mpd->size;
return status;
}
static int
mailbox_pop_body_size (body_t body, size_t *psize)
pop_body_size (body_t body, size_t *psize)
{
mailbox_pop_message_t mpm;
pop_message_t mpm;
if (body == NULL || (mpm = body->owner) == NULL)
return EINVAL;
if (psize)
......@@ -1065,29 +979,235 @@ mailbox_pop_body_size (body_t body, size_t *psize)
}
static int
mailbox_pop_getfd (stream_t stream, int *pfd)
pop_body_lines (body_t body, size_t *plines)
{
mailbox_pop_message_t mpm;
pop_message_t mpm;
if (body == NULL || (mpm = body->owner) == NULL)
return EINVAL;
if (plines)
*plines = mpm->body_lines;
return 0;
}
static int
pop_get_flags (attribute_t attr, int *pflags)
{
pop_message_t mpm;
char hdr_status[64];
header_t header = NULL;
int err;
if (attr == NULL || (mpm = attr->owner) == NULL)
return EINVAL;
hdr_status[0] = '\0';
message_get_header (mpm->message, &header);
err = header_get_value (header, "Status",
hdr_status, sizeof (hdr_status), NULL);
if (err != 0)
err = string_to_flags (hdr_status, pflags);
return err;
}
static int
pop_get_fd (stream_t stream, int *pfd)
{
pop_message_t mpm;
if (stream == NULL || (mpm = stream->owner) == NULL)
return EINVAL;
return stream_get_fd (mpm->bio->stream, pfd);
if (mpm->mpd->bio)
return stream_get_fd (mpm->mpd->bio->stream, pfd);
return EINVAL;
}
static int
pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
{
pop_message_t mpm;
pop_data_t mpd;
bio_t bio;
int status = 0;
void *func = (void *)pop_uidl;
size_t num;
/* According to the RFC uidl's are no longer then 70 chars. */
char uniq[128];
if (msg == NULL || (mpm = msg->owner) == NULL)
return EINVAL;
mpd = mpm->mpd;
bio = mpd->bio;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
/* Get the UIDL. */
switch (mpd->state)
{
case POP_NO_STATE:
bio->len = sprintf (bio->buffer, "UIDL %d\r\n", mpm->num);
bio->ptr = bio->buffer;
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
mpd->state = POP_UIDL_TX;
case POP_UIDL_TX:
/* Send the UIDL. */
status = bio_write (bio);
CHECK_NON_RECOVERABLE (mpd, status);
mpd->state = POP_UIDL_ACK;
case POP_UIDL_ACK:
/* Resp from TOP. */
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
break;
default:
/*
fprintf (stderr, "pop_uidl state\n");
*/
}
CLEAR_STATE (mpd);
*uniq = '\0';
status = sscanf (bio->buffer, "+OK %d %127s\n", &num, uniq);
if (status != 2)
{
status = EINVAL;
buflen = 0;
}
else
{
num = strlen (uniq);
uniq[num - 1] = '\0'; /* Nuke newline. */
buflen = (buflen < num) ? buflen : num;
memcpy (buffer, uniq, buflen);
buffer [buflen - 1] = '\0';
status = 0;
}
if (pnwriten)
*pnwriten = buflen;
return status;
}
static int
pop_header_read (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread)
{
pop_message_t mpm;
pop_data_t mpd;
bio_t bio;
size_t nread = 0;
int status = 0;
void *func = (void *)pop_header_read;
if (is == NULL || (mpm = is->owner) == NULL)
return EINVAL;
(void)offset;
mpd = mpm->mpd;
bio = mpd->bio;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
/* Get the header. */
switch (mpd->state)
{
case POP_NO_STATE:
/* TOP is an optionnal command, if we want to be compliant we can not
count on it to exists. So we should be prepare when it fails and
fall to a second scheme. */
bio->len = sprintf (bio->buffer, "TOP %d 0\r\n", mpm->num);
bio->ptr = bio->buffer;
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, bio->buffer);
mpd->state = POP_TOP_TX;
case POP_TOP_TX:
/* Send the TOP. */
status = bio_write (bio);
CHECK_NON_RECOVERABLE (mpd, status);
mpd->state = POP_TOP_ACK;
case POP_TOP_ACK:
/* Ack from TOP. */
status = bio_readline (bio);
CHECK_NON_RECOVERABLE (mpd, status);
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;
}
mpd->state = POP_TOP_RX;
bio->current = bio->nl;
case POP_TOP_RX:
/* Get the header. */
{
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
{
/* Drain the buffer. */
memcpy (buffer, bio->current, n);
bio->current += n;
nread = n;
}
break;
}
break;
default:
/* fprintf (stderr, "pop_header_blurb unknown state\n"); */
} /* switch (state) */
if (nread == 0)
{
CLEAR_STATE (mpd);
}
if (pnread)
*pnread = nread;
return 0;
}
static int
mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
pop_readstream (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread)
{
mailbox_pop_message_t mpm;
mailbox_pop_data_t mpd;
pop_message_t mpm;
pop_data_t mpd;
size_t nread = 0;
bio_t bio;
int status = 0;
void *func = (void *)mailbox_pop_readstream;
void *func = (void *)pop_readstream;
(void)offset;
if (is == NULL || (mpm = is->owner) == NULL)
return EINVAL;
/* Take care of the obvious. */
if (buffer == NULL || buflen == 0)
{
if (pnread)
......@@ -1095,67 +1215,44 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
return 0;
}
bio = mpm->bio;
mpd = mpm->mpd;
bio = mpd->bio;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
/* Which request. */
if (mpd->id && mpd->id != mpm)
return EBUSY;
mpd->func = func;
mpd->id = mpm;
switch (mpd->state)
{
/* Send the RETR command. */
case 0:
case POP_NO_STATE:
bio->len = sprintf (bio->buffer, "RETR %d\r\n", mpm->num);
mpd->state = 1;
case 1:
mpd->state = POP_RETR_TX;
case POP_RETR_TX:
/* Send the RETR command. */
status = bio_write (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
}
mpd->state = 2;
CHECK_NON_RECOVERABLE (mpd, status);
mpd->state = POP_RETR_ACK;
case POP_RETR_ACK:
/* RETR ACK. */
case 2:
status = bio_readline (bio);
if (status != 0)
CHECK_NON_RECOVERABLE (mpd, status);
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
CLEAR_STATE (mpd);
return EACCES;
}
if (strncasecmp (bio->buffer, "+OK", 3) != 0)
return EINVAL;
mpd->state = 3;
mpd->state = POP_RETR_RX_HDR;
case POP_RETR_RX_HDR:
/* Skip the header. */
case 3:
while (!mpm->inbody)
{
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
return status;
}
CHECK_NON_RECOVERABLE (mpd, status);
if (bio->buffer[0] == '\n')
{
mpm->inbody = 1;
......@@ -1164,10 +1261,11 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
}
/* Skip the newline. */
bio_readline (bio);
/* Start taking the header. */
mpd->state = 4;
bio->current = bio->buffer;
case 4:
bio->current = bio->current;
mpd->state = POP_RETR_RX_BODY;
case POP_RETR_RX_BODY:
/* Start taking the body. */
{
int nleft, n;
/* Do we need to fill up. */
......@@ -1175,14 +1273,7 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
{
bio->current = bio->buffer;
status = bio_readline (bio);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
}
}
CHECK_NON_RECOVERABLE (mpd, status);
}
n = bio->nl - bio->current;
nleft = buflen - n;
......@@ -1200,13 +1291,15 @@ mailbox_pop_readstream (stream_t is, char *buffer, size_t buflen,
bio->current += n;
nread = n;
}
break;
}
default:
/* fprintf (stderr, "pop_readstream unknow state\n"); */
} /* Switch state. */
if (nread == 0)
{
mpd->func = mpd->id = NULL;
mpd->state = 0;
CLEAR_STATE (mpd);
}
if (pnread)
*pnread = nread;
......@@ -1221,12 +1314,7 @@ bio_create (bio_t *pbio, stream_t stream)
if (bio == NULL)
return ENOMEM;
bio->maxlen = POP_BUFSIZ + 1;
bio->current = bio->ptr = bio->buffer = calloc (1, POP_BUFSIZ + 1);
if (bio->buffer == NULL)
{
free (bio);
return ENOMEM;
}
bio->current = bio->ptr = bio->buffer = calloc (1, bio->maxlen);
bio->stream = stream;
*pbio = bio;
return 0;
......@@ -1273,8 +1361,8 @@ bio_read (bio_t bio)
status = stream_read (bio->stream, bio->ptr, len, 0, &nread);
if (status != 0)
return status;
else if (nread == 0)
{ /* EOF ???? We got a situation here ??? */
else if (nread == 0) /* EOF ???? We got a situation here ??? */
{
bio->buffer[0] = '.';
bio->buffer[1] = '\r';
bio->buffer[2] = '\n';
......@@ -1312,7 +1400,7 @@ bio_readline (bio_t bio)
for (;;)
{
status = bio_read (bio);
if (status < 0)
if (status != 0)
return status;
len = bio->ptr - bio->buffer;
/* Newline. */
......
......@@ -49,57 +49,57 @@
#include <ctype.h>
#include <limits.h>
static int mailbox_unix_create (mailbox_t *pmbox, const char *name);
static void mailbox_unix_destroy (mailbox_t *pmbox);
#define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED)
#define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2)
static int unix_create (mailbox_t *pmbox, const char *name);
static void unix_destroy (mailbox_t *pmbox);
struct mailbox_registrar _mailbox_unix_registrar =
{
"UNIX MBOX",
mailbox_unix_create, mailbox_unix_destroy
unix_create, unix_destroy
};
/*
* Keep the position of where the header and body starts
* and ends. old_attr is the "Status:" message.
*/
typedef struct _mailbox_unix_message
/* Keep the position of where the header and body starts and ends.
old_flags is the "Status:" message. */
typedef struct _unix_message
{
/* offset of the parts of the messages in the mailbox*/
/* Offset of the parts of the messages in the mailbox. */
off_t header_from;
off_t header_from_end;
/* little hack to make things easier
* when updating the attribute
*/
/* Little hack to make things easier * when updating the attribute. */
off_t header_status;
off_t header_status_end;
off_t body;
off_t body_end;
/* old_attr contains the definition of Header: */
/* new_attr what we want when expunging */
attribute_t old_attr;
attribute_t new_attr;
/* The old_flags contains the definition of Header. */
int old_flags;
/* The new_flags holds the attributes changes for the current session. We
use this so when expunging we can tell when an attribute been modified.
This is a big help so we can jump to the first modify email for speed
in expunging (see mark dirty). */
int new_flags;
size_t header_lines;
size_t body_lines;
stream_t stream;
/* if we have a message attach to it */
/* A message attach to it. */
message_t message;
} *mailbox_unix_message_t;
/*
* umessages is an array of pointers that contains umessages_count
* of mailbox_unix_message_t*; umessages[umessages_count].
* We do it this because realloc() can move everything to
* a new memory region and invalidating all the pointers someone
* has on the messages. Thanks to <Dave Inglis> for pointing this out.
* messages_count is the count number of messages parsed so far.
*/
typedef struct _mailbox_unix_data
} *unix_message_t;
/* The umessages is an array of pointers that contains umessages_count of
unix_message_t*; umessages[umessages_count]. We do it this because
realloc() can move everything to a new memory region and invalidating all
the pointers someone has on the messages. Thanks to <Dave Inglis> for
pointing this out. The messages_count is the count number of messages
parsed so far. */
typedef struct _unix_data
{
mailbox_unix_message_t *umessages;
unix_message_t *umessages;
size_t umessages_count;
size_t messages_count;
stream_t stream;
......@@ -110,59 +110,55 @@ typedef struct _mailbox_unix_data
#endif
off_t size;
} *mailbox_unix_data_t;
static int mailbox_unix_open (mailbox_t mbox, int flag);
static int mailbox_unix_close (mailbox_t mbox);
static int mailbox_unix_get_message (mailbox_t, size_t msgno, message_t *msg);
static int mailbox_unix_append_message (mailbox_t, message_t msg);
static int mailbox_unix_messages_count (mailbox_t, size_t *msgno);
static int mailbox_unix_expunge (mailbox_t);
static int mailbox_unix_num_deleted (mailbox_t, size_t *);
static int mailbox_unix_scan0 (mailbox_t, size_t count, size_t *pcount, int);
static int mailbox_unix_scan (mailbox_t, size_t count, size_t *pcount);
static int mailbox_unix_is_updated (mailbox_t);
} *unix_data_t;
static int mailbox_unix_size (mailbox_t, off_t *size);
static int unix_open (mailbox_t mbox, int flag);
static int unix_close (mailbox_t mbox);
static int unix_get_message (mailbox_t, size_t msgno, message_t *msg);
static int unix_append_message (mailbox_t, message_t msg);
static int unix_messages_count (mailbox_t, size_t *msgno);
static int unix_expunge (mailbox_t);
static int unix_num_deleted (mailbox_t, size_t *);
static int unix_scan (mailbox_t, size_t count, size_t *pcount);
static int unix_is_updated (mailbox_t);
static int unix_size (mailbox_t, off_t *size);
/* private stuff */
static int mailbox_unix_get_header (mailbox_unix_message_t mum, char *buffer,
size_t len, off_t off, ssize_t *pnread);
static int mailbox_unix_getfd (stream_t is, int *pfd);
static int mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen,
static int unix_scan0 (mailbox_t, size_t count, size_t *pcount, int);
static int unix_get_header_read (stream_t is, char *buffer, size_t len,
off_t off, size_t *pnread);
static int unix_get_fd (stream_t is, int *pfd);
static int unix_get_flags (attribute_t, int *);
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 mailbox_unix_body_size (body_t body, size_t *psize);
static int mailbox_unix_body_lines (body_t body, size_t *plines);
static int mailbox_unix_msg_from (message_t msg, char *buf, size_t len,
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,
size_t *pnwrite);
static int mailbox_unix_msg_received (message_t msg, char *buf, size_t len,
static int unix_msg_received (message_t msg, char *buf, size_t len,
size_t *pnwrite);
static int mailbox_unix_lock (mailbox_t mbox, int flag);
static int mailbox_unix_touchlock (mailbox_t mbox);
static int mailbox_unix_unlock (mailbox_t mbox);
static int mailbox_unix_ilock (mailbox_t mbox, int flag);
static int mailbox_unix_iunlock (mailbox_t mbox);
/* We allocate the mailbox_t struct, but don't do any
* parsing on the name or even test for existence.
* However we do strip any leading "unix:" part of
* the name, this is suppose to be the protocol/scheme name.
* Hopefully there will not be a mailbox name "unix:"
*/
static int unix_lock (mailbox_t mbox, int flag);
static int unix_touchlock (mailbox_t mbox);
static int unix_unlock (mailbox_t mbox);
static int unix_ilock (mailbox_t mbox, int flag);
static int unix_iunlock (mailbox_t mbox);
/* We allocate the mailbox_t struct, but don't do any parsing on the name or
even test for existence. However we do strip any leading "unix:" part of
the name, this is suppose to be the protocol/scheme name. Hopefully there
will not be a mailbox name "unix:". */
static int
mailbox_unix_create (mailbox_t *pmbox, const char *name)
unix_create (mailbox_t *pmbox, const char *name)
{
mailbox_t mbox;
mailbox_unix_data_t mud;
unix_data_t mud;
const char *sep;
size_t name_len;
int i;
/* sanity check */
/* Sanity check. */
if (name == NULL || *name == '\0')
return MU_ERROR_INVALID_ARG;
......@@ -172,7 +168,7 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
#define UNIX_SCHEME_LEN 5
#define SEPARATOR '/'
/* skip the url scheme */
/* Skip the url scheme. */
if (name_len > UNIX_SCHEME_LEN &&
(name[0] == 'u' || name[0] == 'U') &&
(name[1] == 'n' || name[1] == 'N') &&
......@@ -184,50 +180,38 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
name_len -= UNIX_SCHEME_LEN;
}
/* allocate memory for mbox */
/* Allocate memory for mbox. */
mbox = calloc (1, sizeof (*mbox));
if (mbox == NULL)
return MU_ERROR_OUT_OF_MEMORY;
/* allocate specific unix mbox data */
/* Allocate specific unix mbox data. */
mud = mbox->data = calloc (1, sizeof (*mud));
if (mbox->data == NULL)
{
mailbox_unix_destroy (&mbox);
unix_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
}
/* copy the name */
/* Copy the name. */
mbox->name = calloc (name_len + 1, sizeof (char));
if (mbox->name == NULL)
{
mailbox_unix_destroy (&mbox);
unix_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
}
memcpy (mbox->name, name, name_len);
/* save the basename and dirname
* So we split the name. But this should probably be
* supported via "maildir:" or the mailbox mgr.
*/
/* equivalent to strrchr (name, '/'); */
for (i = name_len, sep = NULL; i >= 0; i--)
{
/* break on the first separator */
if (name[i] == SEPARATOR)
{
sep = &(name[i]);
break;
}
}
/* 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 */
/* Split it into two. */
mud->dirname = calloc ((sep - name) + 1, sizeof (char));
if (mud->dirname == NULL)
{
mailbox_unix_destroy (&mbox);
unix_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
}
memcpy (mud->dirname, name, sep - name);
......@@ -236,19 +220,19 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
mud->basename = calloc (name_len - (sep - name) + 1, sizeof (char));
if (mud->basename == NULL)
{
mailbox_unix_destroy (&mbox);
unix_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
}
memcpy (mud->basename, sep, name_len - (sep - name));
}
else
{
/* use the relative directory "." */
/* FIXME: should we call getcwd() instead ? */
/* Use the relative directory ".". */
/* FIXME: should we call getcwd () instead ? */
mud->dirname = calloc (2 , sizeof (char));
if (mud->dirname == NULL)
{
mailbox_unix_destroy (&mbox);
unix_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
}
mud->dirname[0] = '.';
......@@ -256,37 +240,37 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
mud->basename = calloc (name_len + 1, sizeof (char));
if (mud->basename == NULL)
{
mailbox_unix_destroy (&mbox);
unix_destroy (&mbox);
return MU_ERROR_OUT_OF_MEMORY;
}
memcpy (mud->basename, name, name_len);
}
#ifdef HAVE_PHTREAD_H
/* mutex when accessing the structure fields */
/* FIXME: should we use rdwr locks instead ?? */
/* Mutex when accessing the structure fields. */
/* FIXME: should we use rdwr locks instead ?? */
pthread_mutex_init (&(mbox->mutex), NULL);
#endif
mbox->_create = mailbox_unix_create;
mbox->_destroy = mailbox_unix_destroy;
mbox->_create = unix_create;
mbox->_destroy = unix_destroy;
mbox->_open = mailbox_unix_open;
mbox->_close = mailbox_unix_close;
mbox->_open = unix_open;
mbox->_close = unix_close;
/* messages */
mbox->_get_message = mailbox_unix_get_message;
mbox->_append_message = mailbox_unix_append_message;
mbox->_messages_count = mailbox_unix_messages_count;
mbox->_expunge = mailbox_unix_expunge;
mbox->_num_deleted = mailbox_unix_num_deleted;
/* Messages. */
mbox->_get_message = unix_get_message;
mbox->_append_message = unix_append_message;
mbox->_messages_count = unix_messages_count;
mbox->_expunge = unix_expunge;
mbox->_num_deleted = unix_num_deleted;
mbox->_scan = mailbox_unix_scan;
mbox->_is_updated = mailbox_unix_is_updated;
mbox->_scan = unix_scan;
mbox->_is_updated = unix_is_updated;
mbox->_size = mailbox_unix_size;
mbox->_size = unix_size;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_create (%s/%s)\n",
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_create (%s/%s)\n",
mud->dirname, mud->basename);
(*pmbox) = mbox;
......@@ -294,40 +278,37 @@ mailbox_unix_create (mailbox_t *pmbox, const char *name)
}
static void
mailbox_unix_destroy (mailbox_t *pmbox)
unix_destroy (mailbox_t *pmbox)
{
if (pmbox && *pmbox)
{
mailbox_t mbox = *pmbox;
mailbox_unix_close (mbox);
unix_close (mbox);
if (mbox->data)
{
size_t i;
mailbox_unix_data_t mud = mbox->data;
unix_data_t mud = mbox->data;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
"mailbox_unix_destroy (%s/%s)\n",
"unix_destroy (%s/%s)\n",
mud->dirname, mud->basename);
free (mud->dirname);
free (mud->basename);
for (i = 0; i < mud->umessages_count; i++)
{
mailbox_unix_message_t mum = mud->umessages[i];
unix_message_t mum = mud->umessages[i];
if (mum == NULL)
continue;
/* Destroy the attach messages */
attribute_destroy (&(mum->old_attr));
message_destroy (&(mum->message), mum);
/* new_attr free by message_destroy() */
/* attribute_destroy (&(mum->new_attr)); */
free (mum);
{
message_destroy (&(mum->message), mum);
free (mum);
}
}
free (mud->umessages);
free (mbox->data);
}
free (mbox->name);
/* free the event array */
/* Free the event array. */
free (mbox->event);
/* destroy the url */
/* Destroy the url. */
if (mbox->url)
url_destroy (&(mbox->url));
if (mbox->locker)
......@@ -336,38 +317,38 @@ mailbox_unix_destroy (mailbox_t *pmbox)
auth_destroy (&(mbox->auth), mbox);
if(mbox->stream)
stream_destroy (&(mbox->stream), mbox);
mailbox_unix_iunlock (mbox);
unix_iunlock (mbox);
#ifdef HAVE_PTHREAD_H
if (mbox->mutex)
ptread_mutex_destroy (&(mbox->mutex));
#endif
free (*pmbox);
free (mbox);
*pmbox = NULL;
}
}
/* Open the file. */
/* Open the file. */
static int
mailbox_unix_open (mailbox_t mbox, int flags)
unix_open (mailbox_t mbox, int flags)
{
mailbox_unix_data_t mud;
unix_data_t mud;
int status = 0;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL)
(mud = (unix_data_t)mbox->data) == NULL)
return EINVAL;
/* Authentication prologues */
/* Authentication prologues. */
if (mbox->auth)
auth_prologue (mbox->auth);
/* get a stream */
/* Get a stream. */
if (mbox->stream == NULL)
{
/* FIXME: for small mbox we shout try to mmap() */
/* FIXME: for small mbox we shout try to mmap (). */
status = (flags & MU_STREAM_CREAT) || (flags & MU_STREAM_APPEND);
if (status == 0)
int trymap = (flags & MU_STREAM_CREAT) || (flags & MU_STREAM_APPEND);
if (trymap == 0)
status = mapfile_stream_create (&(mbox->stream));
if (status != 0)
{
......@@ -377,76 +358,55 @@ mailbox_unix_open (mailbox_t mbox, int flags)
}
status = stream_open (mbox->stream, mbox->name, 0, flags);
if (status != 0)
{
stream_destroy (&(mbox->stream), mbox);
return status;
}
return status;
}
else
{
status = stream_open (mbox->stream, mbox->name, 0, flags);
if (status != 0)
{
stream_destroy (&(mbox->stream), mbox);
return status;
}
}
/* Authentication */
if (mbox->auth)
{
char *user = NULL;
char *passwd = NULL;
status = auth_authenticate (mbox->auth, &user, &passwd);
free (user);
free (passwd);
if (status != 0)
return status;
}
/* Authentication epilogues */
/* Authentication epilogue. */
if (mbox->auth)
auth_epilogue (mbox->auth);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_open(%s, %d)\n",
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_open(%s, %d)\n",
mbox->name, flags);
/* give an appopriate way to lock */
/* Give an appopriate way to lock. */
if (mbox->locker == NULL)
locker_create (&(mbox->locker), mbox->name,
strlen (mbox->name), MU_LOCKER_PID | MU_LOCKER_FCNTL);
locker_create (&(mbox->locker), mbox->name, strlen (mbox->name),
MU_LOCKER_PID | MU_LOCKER_FCNTL);
return 0;
}
static int
mailbox_unix_close (mailbox_t mbox)
unix_close (mailbox_t mbox)
{
mailbox_unix_data_t mud;
unix_data_t mud;
size_t i;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL)
if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL)
return EINVAL;
/* make sure we do not hold any lock for that file */
mailbox_unix_unlock (mbox);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_close(%s)\n",
/* Make sure we do not hold any lock for that file. */
unix_unlock (mbox);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_close(%s)\n",
mbox->name);
/* before closing we need to remove all the messages
* - to reclaim the memory
* - to prepare for another scan.
*/
/* Before closing we need to remove all the messages
- to reclaim the memory
- to prepare for another scan. */
for (i = 0; i < mud->umessages_count; i++)
{
mailbox_unix_message_t mum = mud->umessages[i];
unix_message_t mum = mud->umessages[i];
/* Destroy the attach messages. */
if (mum == NULL)
continue;
/* Destroy the attach messages */
attribute_destroy (&(mum->old_attr));
message_destroy (&(mum->message), mum);
/* new_attr free by message_destroy() */
/* attribute_destroy (&(mum->new_attr)); */
free (mum);
{
message_destroy (&(mum->message), mum);
free (mum);
}
}
free (mud->umessages);
mud->umessages = NULL;
......@@ -455,30 +415,26 @@ mailbox_unix_close (mailbox_t mbox)
return stream_close (mbox->stream);
}
/* Mailbox Parsing */
/* Mailbox Parsing. */
#include "mbx_unixscan.c"
static int
mailbox_unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
unix_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
{
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_scan(%s)\n",
mbox->name);
return mailbox_unix_scan0 (mbox, msgno, pcount, 1);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_scan(%s)\n", mbox->name);
return unix_scan0 (mbox, msgno, pcount, 1);
}
/* 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.
*/
/* 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. */
static int
mailbox_unix_is_updated (mailbox_t mbox)
unix_is_updated (mailbox_t mbox)
{
off_t size;
mailbox_unix_data_t mud;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t) mbox->data) == NULL)
unix_data_t mud;
if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
return EINVAL;
if (stream_size (mbox->stream, &size) != 0)
return 0;
......@@ -486,18 +442,17 @@ mailbox_unix_is_updated (mailbox_t mbox)
}
static int
mailbox_unix_num_deleted (mailbox_t mbox, size_t *pnum)
unix_num_deleted (mailbox_t mbox, size_t *pnum)
{
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
unix_data_t mud;
unix_message_t mum;
size_t i, total;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t) mbox->data) == NULL)
if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
return EINVAL;
for (i = total = 0; i < mud->messages_count; i++)
{
mum = mud->umessages[i];
if (attribute_is_deleted (mum->new_attr))
if (ATTRIBUTE_IS_DELETED (mum->new_flags))
total++;
}
......@@ -506,42 +461,41 @@ mailbox_unix_num_deleted (mailbox_t mbox, size_t *pnum)
return 0;
}
/*
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.
*/
/* 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. */
static FILE *
mailbox_unix_tmpfile (mailbox_t mbox, char **pbox)
unix_tmpfile (mailbox_t mbox, char **pbox)
{
mailbox_unix_data_t mud = (mailbox_unix_data_t)mbox->data;
const char *tmpdir;
int fd;
FILE *fp;
unix_data_t mud = (unix_data_t)mbox->data;
/* P_tmpdir should be define in <stdio.h>. */
#ifndef P_tmpdir
# define P_tmpdir "/tmp"
# define P_tmpdir "/tmp"
#endif
*pbox = calloc (1, strlen (P_tmpdir) + strlen ("MBOX_") +
strlen (mud->basename) + 1);
tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir;
*pbox = calloc (1, strlen (tmpdir) + strlen ("MBOX_") +
strlen (mud->basename) + 1);
if (*pbox == NULL)
return NULL;
sprintf (*pbox, "%s/%s%s", P_tmpdir, "MBOX_", mud->basename);
/* FIXME: I don't think this is the righ approach
* Creating an anonymous file would be better ?
* no trace left behind.
*/
/* Create the file. It must not exist. If it does exist, fail. */
fd = open(*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", mud->basename);
/* FIXME: I don't think this is the righ approach, creating an anonymous
file would be better ? no trace left behind. */
/* Create the file. It must not exist. If it does exist, fail. */
fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd < 0)
{
fprintf(stderr,"Can't create %s\n", *pbox);
fprintf(stderr,"delete file <%s>, Please\n", *pbox);
fprintf (stderr,"Can't create %s\n", *pbox);
fprintf (stderr,"delete file <%s>, Please\n", *pbox);
fprintf (stderr, "It was likely due to an error when expunging\n");
return NULL;
}
fp = fdopen(fd, "w+");
fp = fdopen (fd, "w+");
if (fp == 0)
{
close(fd);
......@@ -549,16 +503,16 @@ mailbox_unix_tmpfile (mailbox_t mbox, char **pbox)
*pbox = NULL;
}
/* really I should just remove the file here */
/* Really I should just remove the file here. */
/* remove(*pbox); */
return fp;
}
static int
mailbox_unix_expunge (mailbox_t mbox)
unix_expunge (mailbox_t mbox)
{
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
unix_data_t mud;
unix_message_t mum;
int status = 0;
sigset_t sigset;
FILE *tempfile;
......@@ -569,74 +523,65 @@ mailbox_unix_expunge (mailbox_t mbox)
char buffer [BUFSIZ];
char *tmpmbox = NULL;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL)
if (mbox == NULL || (mud = (unix_data_t)mbox->data) == NULL)
return EINVAL;
/* noop */
/* Noop. */
if (mud->messages_count == 0)
return 0;
/* Do we have a consistent view of the mailbox */
/* Do we have a consistent view of the mailbox. */
/* FIXME: this is not enough, we can do better
* - by checking the file size and scream bloody murder
* if it has shrink.
* - if its bigger we should be able to handle it
* before the ftruncate() by copying back the new messages.
*/
if (! mailbox_unix_is_updated (mbox))
return EAGAIN;
/* mark dirty the first mail with an attribute change */
- by checking the file size and scream bloody murder if it has shrink.
- if its bigger we should be able to handle it before the ftruncate ()
by copying back the new messages. */
if (! unix_is_updated (mbox))
{
fprintf (stderr, "mailbox is not updated, try again.\n");
return EAGAIN;
}
/* Mark dirty the first mail with an attribute change. */
for (dirty = 0; dirty < mud->messages_count; dirty++)
{
mum = mud->umessages[dirty];
if (mum->new_attr &&
! attribute_is_equal (mum->old_attr, mum->new_attr))
if (mum->new_flags &&
! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags))
break;
}
/* did something change ? */
/* Did something change ? */
if (dirty == mud->messages_count)
return 0; /* nothing change, bail out */
return 0; /* Nothing change, bail out. */
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "mailbox_unix_expunge (%s)\n",
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE, "unix_expunge (%s)\n",
mbox->name);
/* Send notification to all the listeners
* this is redundant, we go to the loop again
* But it's more secure here since we don't
* want to be disturb when expunging.
*/
/* This is redundant, we go to the loop again. But it's more secure here
since we don't want to be disturb when expunging. */
for (j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
if (mum && mum->new_attr && attribute_is_deleted (mum->new_attr))
{
attribute_t attr;
attribute_create (&attr);
attribute_copy (attr, mum->new_attr);
/* Hack: message_destroy() will free() the attribute, save it */
message_destroy (&(mum->message), mum);
mum->new_attr = attr;
}
if (mum && mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
message_destroy (&(mum->message), mum);
}
/* create a tempory file */
tempfile = mailbox_unix_tmpfile (mbox, &tmpmbox);
/* Create a tempory file. */
tempfile = unix_tmpfile (mbox, &tmpmbox);
if (tempfile == NULL)
return errno;
/* Get the lock */
if (mailbox_unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
/* Get the lock. */
if (unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
{
fclose (tempfile);
remove (tmpmbox);
free (tmpmbox);
fprintf (stderr, "Failed to grab the lock\n");
return ENOLCK;
}
/* Critical section, we can not allowed signal here */
/* Critical section, we can not allowed signal here. */
sigemptyset (&sigset);
sigaddset (&sigset, SIGTERM);
sigaddset (&sigset, SIGHUP);
......@@ -645,21 +590,21 @@ mailbox_unix_expunge (mailbox_t mbox)
sigaddset (&sigset, SIGWINCH);
sigprocmask (SIG_BLOCK, &sigset, 0);
mailbox_unix_ilock (mbox, MU_LOCKER_RDLOCK);
unix_ilock (mbox, MU_LOCKER_RDLOCK);
/* set the marker position */
/* Set the marker position. */
total = marker = mud->umessages[dirty]->header_from;
/* copy to tempfile emails not mark deleted */
/* Copy to tempfile emails not mark deleted. */
for (first = 1, i = dirty; i < mud->messages_count; i++)
{
mum = mud->umessages[i];
/* skip it, if mark for deletion */
if (attribute_is_deleted (mum->new_attr))
/* Skip it, if mark for deletion. */
if (ATTRIBUTE_IS_DELETED (mum->new_flags))
continue;
/* add a NL separator between messages */
/* Add a NL separator between messages. */
if (first)
first = 0;
else
......@@ -668,19 +613,18 @@ mailbox_unix_expunge (mailbox_t mbox)
total++;
}
/* Begining of header copy */
/* Begining of header copy. */
{
off_t current;
/* This is done in two parts first we check if the attribute
* changed, if yes then we have to update the "Status:" field.
* Unfortunately there is no requirement for the "Status:"
* to be the last field, so we take the long approach;
* Copy up to the Status, update the Status and copy the rest.
*/
/* attribute change ? */
if (mum->new_attr
&&! attribute_is_equal (mum->old_attr, mum->new_attr)
/* This is done in two parts first we check if the attribute changed,
if yes then we have to update the "Status:" field. Unfortunately
there is no requirement for the "Status:" to be the last field, so
we take the long approach; Copy up to the Status, update the
Status and copy the rest. */
/* Attribute change ? */
if (mum->new_flags
&&! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags)
&& mum->header_status > mum->header_from)
{
size_t n = 0;
......@@ -696,6 +640,8 @@ mailbox_unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: (%s)\n", __LINE__,
strerror (status));
goto bailout;
}
len -= n;
......@@ -703,20 +649,20 @@ mailbox_unix_expunge (mailbox_t mbox)
offset += n;
}
/* put the new attributes */
/* Put the new attributes. */
{
char abuf[64];
size_t na = 0;
abuf[0] = '\0';
attribute_to_string (mum->new_attr, abuf, sizeof(abuf), &na);
flags_to_string (mum->new_flags, abuf, sizeof(abuf), &na);
fputs (abuf, tempfile);
total += na;
}
}
else /* attribute did not change */
else /* Attribute did not change. */
current = mum->header_from;
/* copy the rest of header without changes */
/* Copy the rest of header without changes. */
{
size_t n = 0;
off_t offset = current;
......@@ -730,6 +676,8 @@ mailbox_unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: %s", __LINE__,
strerror (status));
goto bailout;
}
len -= n;
......@@ -737,9 +685,9 @@ mailbox_unix_expunge (mailbox_t mbox)
offset += n;
}
}
} /* end of header copy */
} /* End of header copy. */
/* copy the body */
/* Copy the body. */
{
size_t n = 0;
off_t offset = mum->body;
......@@ -753,21 +701,20 @@ mailbox_unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: %s", __LINE__,
strerror (status));
goto bailout;
}
len -= n;
total += n;
offset += n;
}
} /* end of body copy */
} /* End of body copy. */
} /* for (;;) */
/*
* Caution:
* before ftruncate()ing the file see if we've receiving new mail
* Some program may not respect the lock, or the lock was held
* for too long.
*/
/* Caution: before ftruncate()ing the file see if we've receiving new mail
Some program may not respect the lock, or the lock was held for too
long. */
{
off_t size = 0;
if (stream_size (mbox->stream, &size) == 0)
......@@ -784,6 +731,8 @@ mailbox_unix_expunge (mailbox_t mbox)
{
if (status == 0)
status = errno;
fprintf (stderr, "expunge:%d: %s", __LINE__,
strerror (status));
goto bailout;
}
len -= n;
......@@ -791,9 +740,9 @@ mailbox_unix_expunge (mailbox_t mbox)
offset += n;
}
}
} /* end of precaution */
} /* End of precaution. */
/* Seek and rewrite it */
/* Seek and rewrite it. */
rewind (tempfile);
if (total > 0)
{
......@@ -813,39 +762,42 @@ mailbox_unix_expunge (mailbox_t mbox)
}
}
/* how can I handle error here ?? */
/* How can I handle error here ?? */
clearerr (tempfile);
/* flush/truncation */
/* Flush/truncation. */
stream_flush (mbox->stream);
status = stream_truncate (mbox->stream, total);
if (status != 0)
goto bailout;
{
fprintf (stderr, "expunge:%d: %s", __LINE__,
strerror (status));
goto bailout;
}
/* Don't remove the tmp mbox in case of errors */
/* Don't remove the tmp mbox in case of errors. */
remove (tmpmbox);
bailout:
free (tmpmbox);
/* Release the locks */
mailbox_unix_unlock (mbox);
mailbox_unix_iunlock (mbox);
/* Release the locks. */
unix_unlock (mbox);
unix_iunlock (mbox);
fclose (tempfile);
sigprocmask (SIG_UNBLOCK, &sigset, 0);
/* we need to readjust the pointers */
/* We need to readjust the pointers. */
if (status == 0)
{
size_t dlast;
for (j = dirty, dlast = mud->messages_count - 1;
j < mud->messages_count; j++)
{
/* clear all the references,
* any attach messages been already destroy above
*/
/* Clear all the references, any attach messages been already
destroy above. */
mum = mud->umessages[j];
if (mum->new_attr && attribute_is_deleted (mum->new_attr))
if (mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
{
memmove (mud->umessages + j, mud->umessages + j + 1,
(dlast - dirty) * sizeof (mum));
......@@ -853,7 +805,6 @@ mailbox_unix_expunge (mailbox_t mbox)
mum->header_status = mum->header_status_end = 0;
mum->body = mum->body_end = 0;
mum->header_lines = mum->body_lines = 0;
attribute_destroy (&(mum->new_attr));
mud->umessages[dlast] = mum;
dlast--;
mum = mud->umessages[j];
......@@ -863,18 +814,17 @@ mailbox_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 not to send event notification
*/
mailbox_unix_scan0 (mbox, dirty, NULL, 0);
/* This is should reset the messages_count, the last * argument 0 means
not to send event notification. */
unix_scan0 (mbox, dirty, NULL, 0);
}
return status;
}
static int
mailbox_unix_getfd (stream_t is, int *pfd)
unix_get_fd (stream_t is, int *pfd)
{
mailbox_unix_message_t mum;
unix_message_t mum;
if (is == NULL || (mum = is->owner) == NULL)
return EINVAL;
......@@ -883,13 +833,50 @@ mailbox_unix_getfd (stream_t is, int *pfd)
}
static int
mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen,
off_t off, size_t *pnread)
unix_get_flags (attribute_t attr, int *pflags)
{
unix_message_t mum;
if (attr == NULL || (mum = attr->owner) == NULL)
return EINVAL;
if (pflags)
*pflags = mum->new_flags;
return 0;
}
static int
unix_set_flags (attribute_t attr, int flags)
{
unix_message_t mum;
if (attr == NULL || (mum = attr->owner) == NULL)
return EINVAL;
mum->new_flags |= flags;
return 0;
}
static int
unix_unset_flags (attribute_t attr, int flags)
{
unix_message_t mum;
if (attr == NULL || (mum = attr->owner) == NULL)
return EINVAL;
mum->new_flags &= flags;
return 0;
}
static int
unix_readstream (stream_t is, char *buffer, size_t buflen,
off_t off, size_t *pnread)
{
mailbox_unix_message_t mum;
unix_message_t mum;
size_t nread = 0;
if (is == NULL || (mum = (mailbox_unix_message_t)is->owner) == NULL)
if (is == NULL || (mum = (unix_message_t)is->owner) == NULL)
return EINVAL;
if (buffer == NULL || buflen == 0)
......@@ -906,7 +893,7 @@ mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen,
if (ln > 0)
{
nread = ((size_t)ln < buflen) ? ln : buflen;
/* position the file pointer and the buffer */
/* Position the file pointer and the buffer. */
status = stream_read (mum->stream, buffer, nread, mum->body + off, &n);
if (status != 0)
return status;
......@@ -919,30 +906,34 @@ mailbox_unix_readstream (stream_t is, char *buffer, size_t buflen,
}
static int
mailbox_unix_get_header (mailbox_unix_message_t mum, char *buffer,
size_t len, off_t off, ssize_t *pnread)
unix_get_header_read (stream_t is, char *buffer, size_t len,
off_t off, size_t *pnread)
{
unix_message_t mum;
size_t nread = 0;
size_t n = 0;
int status;
off_t ln = mum->body - (mum->header_from_end + off);
int status = 0;
off_t ln;
if (is == NULL || (mum = is->owner) == NULL)
return EINVAL;
ln = mum->body - (mum->header_from_end + off);
if (ln > 0)
{
nread = ((size_t)ln < len) ? ln : len;
/* position the file pointer and the buffer */
/* Position the file pointer and the buffer. */
status = stream_read (mum->stream, buffer, nread,
mum->header_from_end + off, &n);
if (status != 0)
return status;
mum->header_from_end + off, &nread);
}
*pnread = nread;
return 0;
if (pnread)
*pnread = nread;
return status;
}
static int
mailbox_unix_body_size (body_t body, size_t *psize)
unix_body_size (body_t body, size_t *psize)
{
mailbox_unix_message_t mum = body->owner;
unix_message_t mum = body->owner;
if (mum == NULL)
return EINVAL;
if (psize)
......@@ -951,9 +942,9 @@ mailbox_unix_body_size (body_t body, size_t *psize)
}
static int
mailbox_unix_body_lines (body_t body, size_t *plines)
unix_body_lines (body_t body, size_t *plines)
{
mailbox_unix_message_t mum = body->owner;
unix_message_t mum = body->owner;
if (mum == NULL)
return EINVAL;
if (plines)
......@@ -962,10 +953,10 @@ mailbox_unix_body_lines (body_t body, size_t *plines)
}
static int
mailbox_unix_msg_received (message_t msg, char *buf, size_t len,
unix_msg_received (message_t msg, char *buf, size_t len,
size_t *pnwrite)
{
mailbox_unix_message_t mum = msg->owner;
unix_message_t mum = msg->owner;
size_t n = 0;
int status;
char buffer[512];
......@@ -975,7 +966,6 @@ mailbox_unix_msg_received (message_t msg, char *buf, size_t len,
status = stream_readline (mum->stream, buffer, sizeof(buffer),
mum->header_from, &n);
if (status != 0)
{
if (pnwrite)
......@@ -1008,9 +998,9 @@ mailbox_unix_msg_received (message_t msg, char *buf, size_t len,
}
static int
mailbox_unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
{
mailbox_unix_message_t mum = msg->owner;
unix_message_t mum = msg->owner;
size_t n = 0;
int status;
char buffer[512];
......@@ -1053,31 +1043,22 @@ mailbox_unix_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
}
static int
mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
int status;
ssize_t nread;
char *pbuf = NULL;
char *tbuf = NULL;
char buf[BUFSIZ];
off_t offset = 0;
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
unix_data_t mud;
unix_message_t mum;
message_t msg = NULL;
stream_t stream = NULL;
header_t header = NULL;
body_t body = NULL;
int flags = 0;
if (mbox == NULL || pmsg == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL ||
(!(mud->messages_count > 0 && msgno > 0 &&
msgno <= mud->messages_count)))
/* Sanity checks. */
if (mbox == NULL || pmsg == NULL || (mud = (unix_data_t)mbox->data) == NULL
|| (!(mud->messages_count > 0 && msgno > 0
&& msgno <= mud->messages_count)))
return EINVAL;
mum = mud->umessages[msgno - 1];
/* check if we already have it */
/* Check if we already have it. */
if (mum->message)
{
if (pmsg)
......@@ -1086,89 +1067,72 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
}
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
"mailbox_unix_get_message(%s, %d)\n", mbox->name, msgno);
/* get the headers */
do
{
status = mailbox_unix_get_header (mum, buf, sizeof(buf), offset, &nread);
if (status != 0)
{
free (pbuf);
return status;
}
if (nread == 0)
break;
"unix_get_message(%s, %d)\n", mbox->name, msgno);
tbuf = realloc (pbuf, offset + nread);
if (tbuf == NULL)
{
free (pbuf);
return ENOMEM;
}
else
pbuf = tbuf;
memcpy (pbuf + offset, buf, nread);
offset += nread;
} while (nread > 0);
/* get an empty message struct */
/* Get an empty message struct. */
status = message_create (&msg, mum);
if (status != 0)
{
free (pbuf);
return status;
}
return status;
/* set the header */
status = header_create (&header, pbuf, offset, mum);
if (status != 0)
{
free (pbuf);
message_destroy (&msg, mum);
return status;
}
free (pbuf);
message_set_header (msg, header, mum);
/* Set the header. */
{
header_t header;
stream_t stream;
if ((status = header_create (&header, NULL, 0, mum)) != 0
|| (status = stream_create (&stream, MU_STREAM_READ, mum)) != 0)
{
message_destroy (&msg, mum);
return status;
}
stream_set_read (stream, unix_get_header_read, mum);
stream_set_fd (stream, unix_get_fd, mum);
stream_set_flags (stream, MU_STREAM_READ, mum);
header_set_stream (header, stream, mum);
message_set_header (msg, header, mum);
}
/* prepare the body */
status = body_create (&body, mum);
if (status != 0)
{
message_destroy (&msg, mum);
return status;
}
message_set_body (msg, body, mum);
/* Set the attribute. */
{
attribute_t attribute;
status = attribute_create (&attribute, mum);
if (status != 0)
{
message_destroy (&msg, mum);
return status;
}
mum->new_flags = mum->old_flags;
attribute_set_get_flags (attribute, unix_get_flags, mum);
attribute_set_set_flags (attribute, unix_set_flags, mum);
attribute_set_unset_flags (attribute, unix_unset_flags, mum);
message_set_attribute (msg, attribute, mum);
}
status = stream_create (&stream, MU_STREAM_READ, mum);
if (status != 0)
{
message_destroy (&msg, mum);
return status;
}
stream_set_read (stream, mailbox_unix_readstream, mum);
stream_set_fd (stream, mailbox_unix_getfd, mum);
stream_get_flags (mbox->stream, &flags);
stream_set_flags (stream, flags, mum);
body_set_stream (body, stream, mum);
body_set_size (body, mailbox_unix_body_size, mum);
body_set_lines (body, mailbox_unix_body_lines, mum);
/* set the attribute */
attribute_create (&(mum->new_attr));
mum->new_attr->flag = mum->old_attr->flag;
status = message_set_attribute (msg, mum->new_attr, mum);
if (status != 0)
{
message_destroy (&msg, mum);
return status;
}
/* Prepare the body. */
{
body_t body;
stream_t stream;
int flags = MU_STREAM_READ;
if ((status = body_create (&body, mum)) != 0
|| (status = stream_create (&stream, flags, mum)) != 0)
{
message_destroy (&msg, mum);
return status;
}
stream_set_read (stream, unix_readstream, mum);
stream_set_fd (stream, unix_get_fd, mum);
stream_get_flags (mbox->stream, &flags);
stream_set_flags (stream, flags, mum);
body_set_stream (body, stream, mum);
body_set_size (body, unix_body_size, mum);
body_set_lines (body, unix_body_lines, mum);
message_set_body (msg, body, mum);
}
/* set the envelope */
message_set_from (msg, mailbox_unix_msg_from, mum);
message_set_received (msg, mailbox_unix_msg_received, mum);
/* Set the envelope. */
message_set_from (msg, unix_msg_from, mum);
message_set_received (msg, unix_msg_received, mum);
/* attach the message to the mailbox unix data */
/* Attach the message to the mailbox unix data. */
mum->message = msg;
if (pmsg)
......@@ -1177,17 +1141,17 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
}
static int
mailbox_unix_append_message (mailbox_t mbox, message_t msg)
unix_append_message (mailbox_t mbox, message_t msg)
{
mailbox_unix_data_t mud;
unix_data_t mud;
if (mbox == NULL || msg == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL)
(mud = (unix_data_t)mbox->data) == NULL)
return EINVAL;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_TRACE,
"mailbox_unix_append_message (%s)\n", mbox->name);
"unix_append_message (%s)\n", mbox->name);
mailbox_unix_lock (mbox, MU_LOCKER_WRLOCK);
unix_lock (mbox, MU_LOCKER_WRLOCK);
{
off_t size;
char buffer[BUFSIZ];
......@@ -1199,16 +1163,16 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
size_t n = 0;
char nl = '\n';
/* move to the end of the file, not necesary if _APPEND mode */
/* Move to the end of the file, not necesary if _APPEND mode. */
status = stream_size (mbox->stream, &size);
if (status != 0)
{
mailbox_unix_unlock (mbox);
unix_unlock (mbox);
return status;
}
/* header */
/* Header. */
message_get_header (msg, &hdr);
/* generate a "From " separator */
/* Generate a "From " separator. */
{
char from[128];
char date[128];
......@@ -1249,10 +1213,10 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
} while (nread > 0);
*buffer = '\0';
/* separator */
/* Separator. */
/*fputc ('\n', mud->file);*/
/* body */
/* Body. */
message_get_stream (msg, &is);
do {
stream_read (is, buffer, sizeof (buffer), off, &nread);
......@@ -1263,12 +1227,12 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
stream_write (mbox->stream, &nl, 1, size, &n);
}
stream_flush (mbox->stream);
mailbox_unix_unlock (mbox);
unix_unlock (mbox);
return 0;
}
static int
mailbox_unix_size (mailbox_t mbox, off_t *psize)
unix_size (mailbox_t mbox, off_t *psize)
{
off_t size;
int status;
......@@ -1276,7 +1240,7 @@ mailbox_unix_size (mailbox_t mbox, off_t *psize)
if (mbox == NULL)
return EINVAL;
/* maybe was not open yet ?? */
/* Maybe was not open yet ?? */
status = stream_size (mbox->stream, &size);
if (status != 0)
return status;
......@@ -1286,14 +1250,14 @@ mailbox_unix_size (mailbox_t mbox, off_t *psize)
}
static int
mailbox_unix_messages_count (mailbox_t mbox, size_t *pcount)
unix_messages_count (mailbox_t mbox, size_t *pcount)
{
mailbox_unix_data_t mud;
if (mbox == NULL || (mud = (mailbox_unix_data_t) mbox->data) == NULL)
unix_data_t mud;
if (mbox == NULL || (mud = (unix_data_t) mbox->data) == NULL)
return EINVAL;
if (! mailbox_unix_is_updated (mbox))
return mailbox_unix_scan0 (mbox, 1, pcount, 1);
if (! unix_is_updated (mbox))
return unix_scan0 (mbox, 1, pcount, 1);
if (pcount)
*pcount = mud->messages_count;
......@@ -1301,9 +1265,9 @@ mailbox_unix_messages_count (mailbox_t mbox, size_t *pcount)
return 0;
}
/* locking */
/* Locking. */
static int
mailbox_unix_lock (mailbox_t mbox, int flag)
unix_lock (mailbox_t mbox, int flag)
{
if (mbox && mbox->locker != NULL)
{
......@@ -1314,7 +1278,7 @@ mailbox_unix_lock (mailbox_t mbox, int flag)
}
static int
mailbox_unix_touchlock (mailbox_t mbox)
unix_touchlock (mailbox_t mbox)
{
if (mbox && mbox->locker != NULL)
{
......@@ -1325,7 +1289,7 @@ mailbox_unix_touchlock (mailbox_t mbox)
}
static int
mailbox_unix_unlock (mailbox_t mbox)
unix_unlock (mailbox_t mbox)
{
if (mbox && mbox->locker != NULL)
{
......@@ -1336,10 +1300,10 @@ mailbox_unix_unlock (mailbox_t mbox)
}
static int
mailbox_unix_ilock (mailbox_t mbox, int flag)
unix_ilock (mailbox_t mbox, int flag)
{
#ifdef HAVE_PTHREAD_H
(void)flag; /* we should use rwlocks for more concurency */
(void)flag; /* We should use rwlocks for more concurency. */
if (mbox == NULL)
return EINVAL;
return pthread_mutex_lock (&(mbox->mutex));
......@@ -1350,7 +1314,7 @@ mailbox_unix_ilock (mailbox_t mbox, int flag)
}
static int
mailbox_unix_iunlock (mailbox_t mbox)
unix_iunlock (mailbox_t mbox)
{
#ifdef HAVE_PTHREAD_H
if (mbox == NULL)
......
......@@ -173,7 +173,7 @@ do \
{ \
if (*s == c0 || *s == c1) \
{ \
(mum)->old_attr->flag |= (type); \
(mum)->old_flags |= (type); \
break; \
} \
} \
......@@ -206,16 +206,16 @@ do \
do \
{ \
int bailing = 0; \
mailbox_unix_iunlock (mbox); \
unix_iunlock (mbox); \
MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_MSG_ADD, bailing); \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mailbox_unix_unlock (mbox); \
unix_unlock (mbox); \
return EINTR; \
} \
mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); \
unix_ilock (mbox, MU_LOCKER_WRLOCK); \
} while (0);
/* notification MBX_PROGRESS
......@@ -234,33 +234,38 @@ do \
{ \
{ \
int bailing = 0; \
mailbox_unix_iunlock (mbox); \
unix_iunlock (mbox); \
mud->messages_count--; \
MAILBOX_NOTIFICATION (mbox, MU_EVT_MBX_PROGRESS,bailing); \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mailbox_unix_unlock (mbox); \
unix_unlock (mbox); \
return EINTR; \
} \
mud->messages_count++; \
mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK); \
unix_ilock (mbox, MU_LOCKER_WRLOCK); \
} \
} while (0)
#if 0
/* skip a function call, ?? do we gain that much */
#define ATTRIBUTE_CREATE(attr,mbox) \
#define ATTRIBUTE_CREATE(attr, m, mbox) \
do \
{ \
attr = calloc (1, sizeof(*(attr))); \
attr->owner = m; \
if ((attr) == NULL) \
{ \
mailbox_unix_iunlock (mbox); \
mailbox_unix_unlock (mbox); \
unix_iunlock (mbox); \
unix_unlock (mbox); \
return ENOMEM; \
} \
} while (0)
#else
# define ATTRIBUTE_CREATE
#endif
/* allocate slots for the new messages */
/* size_t num = 2 * ((mud)->messages_count) + 10; */
......@@ -269,38 +274,37 @@ do \
{ \
if ((mud)->messages_count >= (mud)->umessages_count) \
{ \
mailbox_unix_message_t *m; \
unix_message_t *m; \
size_t num = ((mud)->umessages_count) + 1; \
m = realloc ((mud)->umessages, num * sizeof (*m)); \
if (m == NULL) \
{ \
mailbox_unix_iunlock (mbox); \
mailbox_unix_unlock (mbox); \
unix_iunlock (mbox); \
unix_unlock (mbox); \
return ENOMEM; \
} \
(mud)->umessages = m; \
(mud)->umessages[num - 1] = calloc (1, sizeof (*(mum))); \
if ((mud)->umessages[num - 1] == NULL) \
{ \
mailbox_unix_iunlock (mbox); \
mailbox_unix_unlock (mbox); \
unix_iunlock (mbox); \
unix_unlock (mbox); \
return ENOMEM; \
} \
ATTRIBUTE_CREATE (((mud)->umessages[num - 1])->old_attr, mbox); \
(mud)->umessages_count = num; \
} \
} while (0)
static int
mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
{
#define MSGLINELEN 1024
char buf[MSGLINELEN];
int inheader;
int inbody;
off_t total = 0;
mailbox_unix_data_t mud;
mailbox_unix_message_t mum = NULL;
unix_data_t mud;
unix_message_t mum = NULL;
int status = 0;
size_t lines;
int newline;
......@@ -311,7 +315,7 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
/* sanity */
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL)
(mud = (unix_data_t)mbox->data) == NULL)
return EINVAL;
/* save the timestamp and size */
......@@ -320,8 +324,8 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
return status;
/* grab the locks */
mailbox_unix_ilock (mbox, MU_LOCKER_WRLOCK);
mailbox_unix_lock (mbox, MU_LOCKER_RDLOCK);
unix_ilock (mbox, MU_LOCKER_WRLOCK);
unix_lock (mbox, MU_LOCKER_RDLOCK);
/* seek to the starting point */
if (mud->umessages && msgno > 0 && mud->messages_count > 0
......@@ -403,7 +407,7 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
/* every 50 mesgs update the lock, it should be every minute */
if ((mud->messages_count % 50) == 0)
mailbox_unix_touchlock (mbox);
unix_touchlock (mbox);
/* ping them every 1000 lines */
if (do_notif)
......@@ -419,8 +423,8 @@ mailbox_unix_scan0 (mailbox_t mbox, size_t msgno, size_t *pcount, int do_notif)
if (do_notif)
DISPATCH_ADD_MSG(mbox, mud);
}
mailbox_unix_iunlock (mbox);
mailbox_unix_unlock (mbox);
unix_iunlock (mbox);
unix_unlock (mbox);
if (pcount)
*pcount = mud->messages_count;
return status;
......
......@@ -68,7 +68,7 @@ message_destroy (message_t *pmsg, void *owner)
/* header */
header_destroy (&(msg->header), owner);
/* attribute */
attribute_destroy (&(msg->attribute));
attribute_destroy (&(msg->attribute), owner);
/* stream */
stream_destroy (&(msg->stream), owner);
......@@ -325,7 +325,7 @@ message_get_attribute (message_t msg, attribute_t *pattribute)
if (msg->attribute == NULL)
{
attribute_t attribute;
int status = attribute_create (&attribute);
int status = attribute_create (&attribute, msg);
if (status != 0)
return status;
msg->attribute = attribute;
......@@ -341,7 +341,7 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner)
return EINVAL;
if (msg->owner != owner)
return EACCES;
attribute_destroy (&(msg->attribute));
attribute_destroy (&(msg->attribute), owner);
msg->attribute = attribute;
return 0;
}
......@@ -532,7 +532,11 @@ message_read (stream_t is, char *buf, size_t buflen,
header_size (msg->header, &hsize);
body_size (msg->body, &bsize);
if ((size_t)off <= hsize)
/* On some remote sever (POP) the size of the header and body is not known
until you start reading them. So by checking hsize == bsize == 0, we
This kludge of a way of detecting the anomalie and start by the
header. */
if ((size_t)off <= hsize || (hsize == 0 && bsize == 0))
{
header_get_stream (msg->header, &his);
stream_read (his, buf, buflen, off, &hread);
......
......@@ -25,13 +25,12 @@
#include <string.h>
#include <errno.h>
/*
Builtin mailbox types.
A circular list is use for the builtin.
/* Builtin mailbox types. A circular list is use for the builtin.
Proper locking is not done when accessing the list.
FIXME: not thread-safe. */
static struct _registrar registrar [] = {
static struct _registrar registrar [] =
{
{ NULL, NULL, 0, &registrar[1] }, /* sentinel, head list */
{ &_url_file_registrar, &_mailbox_mbox_registrar, 0, &registrar[2] },
{ &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, &registrar[3] },
......