Commit 193c1ef7 193c1ef73dcbc058ee4481e2eed90288ffa5db24 by Alain Magloire

attribute.c attribute.h attribute0.h header.c header.h

 	header0.h mailbox.c mailbox.h mailbox0.h mbx_mbox.c mbx_unix.c
 	message.c registrar.c registrar.h registrar0.h rfc822.c url.c

more cleanups.
1 parent e3fa2e8c
......@@ -62,7 +62,6 @@ attribute_set_answered (attribute_t attr)
if (attr == NULL)
return EINVAL;
attr->flag|= MU_ATTRIBUTE_ANSWERED;
attr->flag |= MU_ATTRIBUTE_SEEN;
return 0;
}
......@@ -72,7 +71,6 @@ attribute_set_flagged (attribute_t attr)
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_FLAGGED;
attr->flag |= MU_ATTRIBUTE_SEEN;
return 0;
}
......@@ -82,7 +80,6 @@ attribute_set_read (attribute_t attr)
if (attr == NULL)
return EINVAL;
attr->flag |= MU_ATTRIBUTE_READ;
attr->flag |= MU_ATTRIBUTE_SEEN;
return 0;
}
......@@ -175,9 +172,6 @@ attribute_unset_seen (attribute_t attr)
if (attr == NULL)
return 0;
attr->flag ^= MU_ATTRIBUTE_SEEN;
attr->flag ^= MU_ATTRIBUTE_ANSWERED;
attr->flag ^= MU_ATTRIBUTE_FLAGGED;
attr->flag ^= MU_ATTRIBUTE_READ;
return 0;
}
......@@ -235,3 +229,38 @@ attribute_unset_recent (attribute_t attr)
return 0;
}
int
attribute_is_equal (attribute_t attr, attribute_t attr2)
{
if (attr == NULL || attr2 == NULL)
return 0;
return attr->flag == attr2->flag;
}
int
attribute_copy (attribute_t dest, attribute_t src)
{
if (dest == NULL || src == NULL)
return EINVAL;
memcpy (dest, src, sizeof (*dest));
return 0;
}
int
attribute_set_owner (attribute_t attr, message_t *msg)
{
if (attr == NULL)
return EINVAL;
attr->message = msg;
return 0;
}
int
attribute_get_owner (attribute_t attr, message_t *msg)
{
if (attr == NULL)
return EINVAL;
if (msg)
*msg = attr->message;
return 0;
}
......
......@@ -60,6 +60,8 @@ 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_is_equal __P ((attribute_t att1, attribute_t att2));
#ifdef __cplusplus
}
#endif
......
......@@ -18,6 +18,7 @@
#ifndef _ATTRIBUTE0_H
#define _ATTRIBUTE0_H
#include <message.h>
#include <attribute.h>
#include <sys/types.h>
......@@ -48,6 +49,11 @@ struct _attribute
void *message;
};
/* not user visible ?? */
extern int attribute_copy __P ((attribute_t dst, attribute_t src));
extern int attribute_set_owner __P ((attribute_t attr, message_t *msg));
extern int attribute_get_owner __P ((attribute_t attr, message_t *msg));
#ifdef __cplusplus
}
#endif
......
......@@ -45,7 +45,7 @@ int
header_set_value (header_t h, const char *fn, const char *fb, size_t n,
int replace)
{
if (h == NULL)
if (h == NULL || h->_set_value == NULL)
return EINVAL;
return h->_set_value (h, fn, fb, n, replace);
}
......@@ -54,15 +54,41 @@ int
header_get_value (header_t h, const char *fn, char *fb,
size_t len, size_t *n)
{
if (h == NULL)
if (h == NULL || h->_get_value == NULL )
return EINVAL;
return h->_get_value (h, fn, fb, len, n);
}
int
header_entry_name (header_t h, size_t num, char *buf, size_t len, size_t *n)
{
if (h == NULL || h->_entry_name == NULL)
return EINVAL;
return h->_entry_name (h, num, buf, len, n);
}
int
header_entry_value (header_t h, size_t num, char *buf, size_t len, size_t *n)
{
if (h == NULL || h->_entry_value == NULL)
return EINVAL;
return h->_entry_value (h, num, buf, len, n);
}
int
header_entry_count (header_t h, size_t *num)
{
if (h == NULL || h->_entry_count)
return EINVAL;
return h->_entry_count (h, num);
}
ssize_t
header_get_data (header_t h, char *data, size_t len, off_t off, int *err)
{
if (h == NULL)
if (h == NULL || h->_get_data)
return EINVAL;
return h->_get_data (h, data, len, off, err);
}
......
......@@ -74,9 +74,12 @@ extern void header_destroy __P ((header_t *));
extern int header_set_value __P ((header_t, const char *fn,
const char *fv, size_t n, int replace));
extern int header_get_value __P ((header_t, const char *fn, char *fv,
size_t len, size_t *n));
extern ssize_t header_get_data __P ((header_t h, char *data,
size_t len, off_t off, int *err));
size_t len, 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));
#ifdef _cpluscplus
}
#endif
......
......@@ -44,6 +44,7 @@ typedef struct _hdr *hdr_t;
struct _header
{
size_t num;
/* Data */
void *data;
/* owner ? */
......@@ -56,13 +57,23 @@ struct _header
size_t n, int replace));
int (*_get_value) __P ((header_t, const char *fn, char *fv,
size_t len, size_t *n));
ssize_t (*_get_data) __P ((header_t h, char *data,
size_t len, off_t off, int *err));
int (*_entry_count) __P ((header_t, size_t *));
int (*_entry_name) __P ((header_t, size_t num, char *buf,
size_t buflen, size_t *nwritten));
int (*_entry_value) __P ((header_t, size_t num, char *buf,
size_t buflen, size_t *nwritten));
ssize_t (*_get_data) __P ((header_t h, char *data, size_t len,
off_t off, int *err));
int (*_parse) __P ((header_t, const char *blurb, size_t len));
} ;
};
extern ssize_t header_get_data __P ((header_t h, char *data,
size_t len, off_t off, int *err));
/* rfc822 */
extern int rfc822_init __P ((header_t *ph, const char *blurb, size_t len));
extern void rfc822_destroy __P ((header_t *ph));
#ifdef _cpluscplus
}
#endif
......
......@@ -61,11 +61,7 @@ mailbox_init (mailbox_t *pmbox, const char *name, int id)
/* if things went ok set mreg for mailbox_destroy and the URL */
if (status == 0)
{
(*pmbox)->url = url;
(*pmbox)->_init = mreg->_init;
(*pmbox)->_destroy = mreg->_destroy;
}
return status;
}
......@@ -245,10 +241,26 @@ mailbox_set_auth (mailbox_t mbox, auth_t auth)
}
int
mailbox_get_auth (mailbox_t mbox, auth_t *auth)
mailbox_get_auth (mailbox_t mbox, auth_t *pauth)
{
if (mbox == NULL || auth == NULL)
if (mbox == NULL || pauth == NULL)
return EINVAL;
*auth = mbox->auth;
*pauth = mbox->auth;
return 0;
}
int
mailbox_get_attribute (mailbox_t mbox, size_t msgno, attribute_t *pattr)
{
if (mbox == NULL || mbox->_get_attribute == NULL)
return ENOSYS;
return mbox->_get_attribute (mbox, msgno, pattr);
}
int
mailbox_set_attribute (mailbox_t mbox, size_t msgno, attribute_t attr)
{
if (mbox == NULL || mbox->_set_attribute == NULL)
return ENOSYS;
return mbox->_set_attribute (mbox, msgno, attr);
}
......
......@@ -22,6 +22,7 @@
#include <url.h>
#include <message.h>
#include <attribute.h>
#include <auth.h>
#include <locker.h>
......
......@@ -85,6 +85,10 @@ struct _mailbox
size_t len, off_t off, int *err));
ssize_t (*_get_body) __P ((mailbox_t, size_t msgno, char *b,
size_t len, off_t off, int *err));
int (*_get_attribute) __P ((mailbox_t mbox, size_t msgno,
attribute_t *attr));
int (*_set_attribute) __P ((mailbox_t mbox, size_t msgno,
attribute_t attr));
};
/* private */
......@@ -103,6 +107,10 @@ extern int mailbox_get_auth __P ((mailbox_t mbox, auth_t *auth));
extern int mailbox_set_auth __P ((mailbox_t mbox, auth_t auth));
extern int mailbox_get_locker __P ((mailbox_t mbox, locker_t *locker));
extern int mailbox_set_locker __P ((mailbox_t mbox, locker_t locker));
extern int mailbox_get_attribute __P ((mailbox_t mbox, size_t msgno,
attribute_t *attr));
extern int mailbox_set_attribute __P ((mailbox_t mbox, size_t msgno,
attribute_t attr));
extern int mailbox_progress __P ((mailbox_t mbox,
int (*progress) (int, void *arg),
void *arg));
......
......@@ -32,32 +32,41 @@ struct mailbox_registrar _mailbox_mbox_registrar =
};
/*
if there is no specific URL for file mailbox,
file://<path_name>
Caveat there is no specific URL for file mailbox or simple path name,
<path_name>
file:<path_name>
It would be preferrable to use :
maildir://<path>
unix://<path>
mmdf://<path>
maildir:<path>
unix:<path>
mmdf:<path>
This would eliminate heuristic discovery that would turn
out to be wrong. Caveat, there is no std URL for those
mailbox.
out to be wrong.
*/
static int
mailbox_mbox_init (mailbox_t *mbox, const char *name)
{
struct stat st;
char *scheme = strstr (name, "://");
size_t len;
if (scheme)
if (name == NULL || mbox == NULL)
return EINVAL;
len = strlen (name);
if (len >= 5 &&
(name[0] == 'f' || name[0] == 'F') &&
(name[1] == 'i' || name[1] == 'I') &&
(name[2] == 'l' || name[2] == 'L') &&
(name[3] == 'e' || name[3] == 'E') &&
name[4] == ':')
{
scheme += 3;
name = scheme;
name += 5;
}
/*
If they want to creat ?? should they know the type ???
What is the best course of action ??
* If they want to creat ?? should they know the type ???
* What is the best course of action ??
* For the default is unix if the file does not exist.
*/
if (stat (name, &st) < 0)
return _mailbox_unix_registrar._init (mbox, name);
......@@ -99,7 +108,7 @@ mailbox_mbox_init (mailbox_t *mbox, const char *name)
{
if (strncmp (head, "From ", 5) == 0)
{
/* This is Unix Mbox */
/* This is a Unix Mbox */
close (fd);
return _mailbox_unix_registrar._init (mbox, name);
}
......
......@@ -15,6 +15,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* First draft by Alain Magloire */
#include <mailbox0.h>
#include <registrar0.h>
#include <message0.h>
......@@ -40,6 +42,7 @@
#endif
#include <string.h>
#include <ctype.h>
#include <limits.h>
static int mailbox_unix_init (mailbox_t *pmbox, const char *name);
static void mailbox_unix_destroy (mailbox_t *pmbox);
......@@ -51,23 +54,28 @@ struct mailbox_registrar _mailbox_unix_registrar =
};
/*
* Keep a reference of where the header and body starts
* and end.
* Keep the position of where the header and body starts
* and ends. old_attr is the one that is part of the "Status:" message.
*/
typedef struct _mailbox_unix_message
{
off_t header;
off_t header_end;
/* little hack to make things easier
* when updating the attribute
*/
off_t status;
off_t status_end;
off_t body;
off_t body_end;
attribute_t attribute;
attribute_t old_attr;
attribute_t new_attr;
} *mailbox_unix_message_t;
typedef struct _mailbox_unix_data
{
mailbox_unix_message_t messages;
size_t messages_count;
size_t num_deleted;
FILE *file;
char *dirname;
char *basename;
......@@ -92,11 +100,16 @@ static int mailbox_unix_num_deleted (mailbox_t, size_t *);
static int mailbox_unix_get_size (mailbox_t, size_t msgno, size_t *header,
size_t *body);
static int mailbox_unix_scan (mailbox_t, size_t *msgs);
static int mailbox_unix_parse (mailbox_t, size_t *msgs);
static int mailbox_unix_is_updated (mailbox_t);
static int mailbox_unix_size (mailbox_t, off_t *size);
static int mailbox_unix_get_attribute (mailbox_t mbox, size_t msgno,
attribute_t *pattribute);
static int mailbox_unix_set_attribute (mailbox_t mbox, size_t msgno,
attribute_t attribute);
static ssize_t mailbox_unix_get_header (mailbox_t, size_t msgno, char *h,
size_t len, off_t off, int *err);
static ssize_t mailbox_unix_get_body (mailbox_t, size_t msgno, char *b,
......@@ -106,12 +119,19 @@ static ssize_t mailbox_unix_get_body (mailbox_t, size_t msgno, char *b,
/* private stuff */
static int mailbox_unix_is_from (const char *);
static int mailbox_unix_readhdr (mailbox_t mbox, char *buf, size_t len,
off_t *content_length, attribute_t attr);
off_t *content_length, size_t msgno);
static int mailbox_unix_lock (mailbox_t mbox, int flag);
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 thest for existence.
* However we do strip any leading "unix:" part of
* our name, this is suppose to be the protocol/scheme name.
* Hopefully there will not be a mailbox name "unix:"
*/
static int
mailbox_unix_init (mailbox_t *pmbox, const char *name)
{
......@@ -131,10 +151,12 @@ mailbox_unix_init (mailbox_t *pmbox, const char *name)
#define UNIX_SCHEME_LEN 5
#define SEPARATOR '/'
/* pass the url */
/* sskip the url scheme */
if (name_len > UNIX_SCHEME_LEN &&
name[0] == 'u' && name[1] == 'n' &&
name[2] == 'i' && name[3] == 'x' &&
(name[0] == 'u' || name[0] == 'U') &&
(name[1] == 'n' || name[1] == 'N') &&
(name[2] == 'i' || name[2] == 'i') &&
(name[3] == 'x' || name[3] == 'x' ) &&
name[4] == ':')
{
name += UNIX_SCHEME_LEN;
......@@ -164,6 +186,11 @@ mailbox_unix_init (mailbox_t *pmbox, const char *name)
memcpy (mbox->name, name, name_len);
/* save the basename and dirname */
/* FIXME: We may have to support imap "SELECT"
* So we split the name. But this should probably be
* supported via "maildir:"
*/
/* equivalent to strrchr (name, '/'); */
for (i = name_len, sep = NULL; i >= 0; i--)
{
/* break on the first separator */
......@@ -215,9 +242,9 @@ mailbox_unix_init (mailbox_t *pmbox, const char *name)
memcpy (mud->basename, name, name_len);
}
#ifdef HAVE_PHTREAD_H
/* mutex when accessing the structure fields */
/* FIXME: should we use rdwr locks instead ?? */
#ifdef HAVE_PHTREAD_H
pthread_mutex_init (&(mud->mutex), NULL);
#endif
......@@ -241,6 +268,9 @@ mailbox_unix_init (mailbox_t *pmbox, const char *name)
mbox->_size = mailbox_unix_size;
mbox->_get_attribute = mailbox_unix_get_attribute;
mbox->_set_attribute = mailbox_unix_set_attribute;
mbox->_get_header = mailbox_unix_get_header;
mbox->_get_body = mailbox_unix_get_body;
......@@ -265,8 +295,10 @@ mailbox_unix_destroy (mailbox_t *pmbox)
for (i = 0; i < mud->messages_count; i++)
{
/* orphan the message */
mud->messages[i].attribute->message = NULL;
attribute_destroy (&(mud->messages[i].attribute));
mud->messages[i].old_attr->message = NULL;
mud->messages[i].new_attr->message = NULL;
attribute_destroy (&(mud->messages[i].old_attr));
attribute_destroy (&(mud->messages[i].new_attr));
}
free (mud->messages);
free (mbox->data);
......@@ -331,14 +363,13 @@ mailbox_unix_open (mailbox_t mbox, int flags)
/* oops bail out */
if (errno != ENOENT)
return errno;
/* Create the file */
/* Race condition here when creating the file ?? */
fd = open(mbox->name, flg|O_CREAT|O_EXCL, 0600);
if (fd < 0)
return errno;
}
/*
FIXME: How about owner(uid), to whom we set it to ?
do We need a _set_owner(uid) to mailbox_t
* Set the owner ship, but should we return the errno
*/
if (mbox->auth)
{
......@@ -365,10 +396,8 @@ mailbox_unix_open (mailbox_t mbox, int flags)
/* we use FILE * object */
if (flags & MU_MAILBOX_APPEND)
mode = "a";
else if (flags & MU_MAILBOX_RDWR)
else if (flags & MU_MAILBOX_RDWR || flags & MU_MAILBOX_WRONLY)
mode = "r+";
else if (flags & MU_MAILBOX_WRONLY)
mode = "w";
else /* default readonly*/
mode = "r";
......@@ -388,7 +417,7 @@ mailbox_unix_open (mailbox_t mbox, int flags)
/* Check to make sure this is indeed a Unix Mail format */
flockfile (mud->file);
{
char buf [BUFSIZ];
char buf [6];
if (fgets (buf, sizeof (buf), mud->file) == NULL)
{
if (feof (mud->file))
......@@ -408,14 +437,13 @@ mailbox_unix_open (mailbox_t mbox, int flags)
mailbox_unix_iunlock (mbox);
return EIO;
}
else
rewind (mud->file);
}
rewind (mud->file);
}
funlockfile (mud->file);
mud->flags = flags;
}
mailbox_unix_iunlock (mbox);
mud->flags = flags;
return 0;
}
......@@ -502,14 +530,15 @@ mailbox_unix_is_from (const char *from)
/*
* We skip over the rest of the header. Scan for
* Status: to set the attribute. Hopfully the Content-Length
* Status: to set the attribute. Hopefully the Content-Length
* in there too.
*/
static int
mailbox_unix_readhdr (mailbox_t mbox, char *buf, size_t len,
off_t *content_length, attribute_t attribute)
off_t *content_length, size_t msgno)
{
mailbox_unix_data_t mud = (mailbox_unix_data_t)mbox->data;
mailbox_unix_message_t mum = &mud->messages[msgno];
char *sep;
/* skip over the remaining header */
......@@ -524,24 +553,40 @@ mailbox_unix_readhdr (mailbox_t mbox, char *buf, size_t len,
|| (isalpha (buf[0]) && (sep = strchr (buf, ':')) == NULL))
break;
/* get the the Content lenght of the body if possible */
if (strncmp (buf, "Content-Length:", 15) == 0)
else if (strncmp (buf, "Content-Length:", 15) == 0)
{
sep = strchr(buf, ':'); /* pass the ':' */
sep[strlen (sep) - 1] = '\0'; /* chop the newline */
/* FIXME: use xstrtol() if strtol() is not on the platform */
/* FIXME: what an awkward way of handling error
Some damage control can be done here.
for example just set content_length = -1;
and rely above to discover the body part */
errno = 0;
*content_length = strtol (sep + 1, NULL, 10);
if (*content_length == 0 ||
*content_length == LONG_MIN ||
*content_length == LONG_MAX)
{
if (errno != 0)
return errno;
}
}
/* Set the attribute */
if (strncmp (buf, "Status:", 7) == 0)
else if (strncmp (buf, "Status:", 7) == 0)
{
mum->status = ftell (mud->file);
mum->status_end = mum->status + strlen (buf);
sep = strchr(buf, ':'); /* pass the ':' */
if (strchr (sep, 'R') != NULL)
attribute_set_read (attribute);
attribute_set_read (mum->old_attr);
if (strchr (sep, 'O') != NULL)
attribute_set_seen (attribute);
attribute_set_seen (mum->old_attr);
if (strchr (sep, 'A') != NULL)
attribute_set_answered (attribute);
attribute_set_answered (mum->old_attr);
if (strchr (sep, 'F') != NULL)
attribute_set_flagged (attribute);
attribute_set_flagged (mum->old_attr);
attribute_copy (mum->new_attr, mum->old_attr);
}
}
/* check for any dubious conditions */
......@@ -553,13 +598,13 @@ mailbox_unix_readhdr (mailbox_t mbox, char *buf, size_t len,
/* Parsing.
* This a bit fragile, I need to secure this.
* The approach is to detect the "From " as start of a
* new message give the position of the header and scan
* until "\n" set header_end, set body position, we have
* a Content-Length header jump to the point if not
* new message, give the position of the header and scan
* until "\n" then set header_end, set body position, if we have
* a Content-Length field jump to the point if not
* scan until we it another "From " and set body_end.
*/
static int
mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
mailbox_unix_parse (mailbox_t mbox, size_t *msgs)
{
char buf[BUFSIZ];
int header = 1;
......@@ -570,6 +615,7 @@ mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
mailbox_unix_message_t mum;
struct stat st;
/* sanity */
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL)
return EINVAL;
......@@ -615,7 +661,7 @@ mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
count++;
/* FIXME: This is a bad idea, we should not be allowed to
* jump out from the scanning this way. We sit at the mercy
* jump out from the parsing this way. We sit at the mercy
* of this function(_progress) waiting for disaster.
*/
if (mbox->_progress)
......@@ -629,6 +675,7 @@ mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
return EINTR;
}
}
/* allocate space for the new message */
if (count > mud->messages_count)
{
mum = realloc (mud->messages, count * sizeof (*mum));
......@@ -641,15 +688,17 @@ mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
}
mud->messages_count++;
memset (&mum[count - 1], 0, sizeof (*mum));
attribute_init (&(mum[count - 1].attribute));
attribute_init (&(mum[count - 1].old_attr));
attribute_init (&(mum[count - 1].new_attr));
}
mud->messages = mum;
mum[count - 1].header = ftell (mud->file);
/* substract the overrun */
mum[count - 1].header -= over;
/* skip over the remaining header */
if (mailbox_unix_readhdr (mbox, buf, sizeof (buf), &content_length,
mum[count - 1].attribute) != 0)
/* skip the remaining header and set the attributes */
if (mailbox_unix_readhdr (mbox, buf, sizeof (buf),
&content_length, count - 1) != 0)
{
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
......@@ -664,12 +713,13 @@ mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
/* body */
if (body)
{
/* set the body position */
if (mum[count - 1].body == 0)
mum[count - 1].body = ftell (mud->file);
if (content_length >= 0)
{
/* ouf ! we got the size */
/* ouf ! we got the lenght, jump */
mum[count - 1].body_end = mum[count -1].body + content_length;
fseek (mud->file, content_length, SEEK_CUR);
content_length = -1;
......@@ -678,6 +728,7 @@ mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
}
} /* while */
mum[count - 1].body_end = ftell (mud->file);
if (feof (mud->file))
clearerr (mud->file);
else if (ferror (mud->file))
......@@ -696,6 +747,11 @@ mailbox_unix_scan (mailbox_t mbox, size_t *msgs)
return 0;
}
/* 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)
{
......@@ -712,7 +768,8 @@ static int
mailbox_unix_is_valid (mailbox_t mbox, size_t msgno)
{
mailbox_unix_data_t mud;
if (mbox == NULL || (mud = (mailbox_unix_data_t) mbox->data) == NULL)
if (mbox == NULL ||
(mud = (mailbox_unix_data_t) mbox->data) == NULL)
return 0;
/* valid ? */
return (mud->messages_count > 0 && msgno <= mud->messages_count);
......@@ -723,12 +780,11 @@ mailbox_unix_is_deleted (mailbox_t mbox, size_t msgno)
{
mailbox_unix_data_t mud;
/* Do we have a consistent view of the mbox ? */
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL ||
! mailbox_unix_is_valid (mbox, msgno))
return 0;
return attribute_is_deleted (mud->messages[msgno].attribute);
return attribute_is_deleted (mud->messages[msgno].new_attr);
}
static int
......@@ -747,8 +803,7 @@ mailbox_unix_delete (mailbox_t mbox, size_t msgno)
return 0;
/* Mark for deletion */
attribute_set_deleted (mud->messages[msgno].attribute);
mud->num_deleted++;
attribute_set_deleted (mud->messages[msgno].new_attr);
return 0;
}
......@@ -756,11 +811,20 @@ static int
mailbox_unix_num_deleted (mailbox_t mbox, size_t *num)
{
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
size_t i, total;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t) mbox->data) == NULL)
return EINVAL;
for (i = total = 0; i < mud->messages_count; i++)
{
mum = &mud->messages[i];
if (attribute_is_deleted (mum->new_attr))
total++;
}
if (num)
*num = mud->num_deleted;
*num = total;
return 0;
}
......@@ -779,8 +843,7 @@ mailbox_unix_undelete (mailbox_t mbox, size_t msgno)
return 0;
/* Mark undeletion */
attribute_unset_deleted (mud->messages[msgno].attribute);
mud->num_deleted--;
attribute_unset_deleted (mud->messages[msgno].new_attr);
return 0;
}
......@@ -795,7 +858,7 @@ mailbox_unix_tmpfile ()
{
/*FIXME: racing conditions, to correct, .i.e don;t use tmpfile*/
//return tmpfile ();
return fopen ("/tmp/mymail", "w");
return fopen ("/tmp/mymail", "w+");
}
static int
......@@ -803,9 +866,12 @@ mailbox_unix_expunge (mailbox_t mbox)
{
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
int status = 0;
sigset_t sigset;
FILE *tmpfile;
size_t i;
size_t nread;
size_t i, j, first;
off_t marker = 0;
off_t total = 0;
char buffer [BUFSIZ];
......@@ -814,144 +880,208 @@ mailbox_unix_expunge (mailbox_t mbox)
return EINVAL;
/* noop */
if (mud->messages_count == 0 || mud->num_deleted <= 0)
if (mud->messages_count == 0)
return 0;
tmpfile = mailbox_unix_tmpfile ();
if (tmpfile == NULL)
return errno;
/* Critical section, we can not allowed signal here */
/* FIXME: If NONBLOCKING is set we should unset reset to
* later, we can not afford to luxury here
*/
sigemptyset (&sigset);
sigaddset (&sigset, SIGTERM);
sigaddset (&sigset, SIGHUP);
sigaddset (&sigset, SIGTSTP);
sigaddset (&sigset, SIGINT);
sigaddset (&sigset, SIGWINCH);
sigprocmask (SIG_BLOCK, &sigset, 0);
/* Get the lock */
mailbox_unix_ilock (mbox, MU_LOCKER_RDLOCK);
flockfile (mud->file);
if (mailbox_unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
{
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
return EINVAL;
status = EIO;
goto bailout;
}
mailbox_unix_ilock (mbox, MU_LOCKER_RDLOCK);
flockfile (mud->file);
/* Do we have a consistent view of the mbox */
/* 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))
{
/* things change, flag an error */
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
return EAGAIN;
status = EAGAIN;
goto bailout;
}
rewind (mud->file);
/* copy to temp file emails not mark deleted emails */
for (i = 1; i <= mud->messages_count; i++)
/* Go to the first mail with an attribute change */
for (j = 0; j < mud->messages_count; j++)
{
mum = &mud->messages[j];
if (! attribute_is_equal (mum->old_attr, mum->new_attr))
break;
}
/* did something change ? */
if ((j + 1) == mud->messages_count)
{
/* nothing change, bail out */
status = 0;
goto bailout;
}
/* set the marker position */
total = marker = mud->messages[j].header;
/* copy to tempfile emails not mark changed */
for (first = 1, i = j; i < mud->messages_count; i++)
{
size_t len;
off_t current;
mum = &mud->messages[i];
if ( ! attribute_is_deleted (mum->attribute))
/* skip it, if mark for deletion */
if (attribute_is_deleted (mum->new_attr))
continue;
/* add a NL separtor between messages */
if (first)
first = 0;
else
{
size_t len = mum->body - mum->header;
size_t nread;
fputc ('\n', tmpfile);
total++;
}
/* copy the header */
if (fseek (mud->file, mum->header, SEEK_SET) == -1)
{
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
return EIO;
status = EIO;
goto bailout;
}
/* attribute change ? */
if (! attribute_is_equal (mum->old_attr, mum->new_attr) &&
mum->status > mum->header)
{
len = mum->status - mum->header;
current = mum->status_end;
while (len > 0)
{
nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
if (fread (buffer, sizeof (*buffer), nread, mud->file) != nread
|| fwrite(buffer, sizeof(*buffer), nread, tmpfile) != nread)
{
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
return EIO;
status = EIO;
goto bailout;
}
len -= nread;
total += nread;
}
/* copy the body */
len = mum->body_end - mum->body;
if (fseek (mud->file, mum->body, SEEK_SET) < 0)
/* put the new attributes */
{
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
return EIO;
attribute_t attr = mum->new_attr;
fputs ("Status: ", tmpfile);
total += 8;
if (attribute_is_seen (attr))
{
fputc ('R', tmpfile);
total++;
}
if (attribute_is_answered (attr))
{
fputc ('A', tmpfile);
total++;
}
if (attribute_is_flagged (attr))
{
fputc ('F', tmpfile);
total++;
}
if (attribute_is_read (attr))
{
fputc ('O', tmpfile);
total++;
}
fputc ('\n', tmpfile);
total++;
}
}
else /* attribute did not change */
{
current = mum->header;
}
len = mum->header_end - current;
while (len > 0)
{
nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
if (fread (buffer, sizeof (*buffer), nread, mud->file) != nread
|| fwrite(buffer, sizeof(*buffer), nread, tmpfile) != nread)
{
mailbox_unix_unlock (mbox);
fclose (tmpfile);
mailbox_unix_iunlock (mbox);
funlockfile (mud->file);
return EIO;
status = EIO;
goto bailout;
}
len -= nread;
total += nread;
}
}
}
/* Critical section, we can not allowed signal here */
sigemptyset (&sigset);
sigaddset (&sigset, SIGTERM);
sigaddset (&sigset, SIGHUP);
sigaddset (&sigset, SIGTSTP);
sigaddset (&sigset, SIGINT);
sigaddset (&sigset, SIGWINCH);
sigprocmask (SIG_BLOCK, &sigset, 0);
/* Separate the header from body */
fputc ('\n', tmpfile);
total++;
/* truncate the mailbox and rewrite it */
rewind (mud->file);
rewind (tmpfile);
if (ftruncate (fileno(mud->file), total) < 0)
/* copy the body */
if (fseek (mud->file, mum->body, SEEK_SET) < 0)
{
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
sigprocmask (SIG_UNBLOCK, &sigset, 0);
return EIO;
status = EIO;
goto bailout;
}
while (total > 0)
len = mum->body_end - mum->body;
while (len > 0)
{
size_t nread = ((unsigned)total < sizeof (buffer)) ? total : sizeof (buffer);
nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
if (fread (buffer, sizeof (*buffer), nread, mud->file) != nread
|| fwrite (buffer, sizeof (*buffer), nread, tmpfile) != nread)
|| fwrite(buffer, sizeof(*buffer), nread, tmpfile) != nread)
{
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
sigprocmask (SIG_UNBLOCK, &sigset, 0);
return EIO;
status = EIO;
goto bailout;
}
total -= nread;
len -= nread;
total += nread;
}
}
/* truncate the mailbox and rewrite it */
if (total <= 0 || fseek (mud->file, marker, SEEK_SET) < 0 ||
ftruncate (fileno(mud->file), total) < 0)
{
status = EIO;
goto bailout;
}
rewind (tmpfile);
while ((nread = fread (buffer, sizeof (*buffer), sizeof (buffer), tmpfile)) != 0)
fwrite (buffer, sizeof (*buffer), nread, mud->file);
/* how can I handle error here ?? */
clearerr (tmpfile);
clearerr (mud->file);
fflush (mud->file);
bailout:
/* Release the lock */
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
fclose (tmpfile);
sigprocmask (SIG_UNBLOCK, &sigset, 0);
return 0;
return status;
}
/* reading */
......@@ -1160,11 +1290,10 @@ mailbox_unix_get_size (mailbox_t mbox, size_t msgno, size_t *h, size_t *b)
mailbox_unix_message_t mum;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL)
(mud = (mailbox_unix_data_t)mbox->data) == NULL ||
!mailbox_unix_is_valid (mbox, msgno))
return EINVAL;
if (mailbox_unix_is_valid (mbox, msgno))
return EINVAL;
mum = &(mud->messages[msgno]);
if (h)
*h = mum->header_end - mum->header;
......@@ -1173,14 +1302,15 @@ mailbox_unix_get_size (mailbox_t mbox, size_t msgno, size_t *h, size_t *b)
return 0;
}
static int mailbox_unix_messages_count (mailbox_t mbox, size_t *count)
static int
mailbox_unix_messages_count (mailbox_t mbox, size_t *count)
{
mailbox_unix_data_t mud;
if (mbox == NULL || (mud = (mailbox_unix_data_t) mbox->data) == NULL)
return EINVAL;
if (! mailbox_is_updated (mbox))
return mailbox_unix_scan (mbox, count);
if (! mailbox_unix_is_updated (mbox))
return mailbox_unix_parse (mbox, count);
if (count)
*count = mud->messages_count;
......@@ -1188,6 +1318,34 @@ static int mailbox_unix_messages_count (mailbox_t mbox, size_t *count)
return 0;
}
static int
mailbox_unix_get_attribute (mailbox_t mbox, size_t msgno,
attribute_t *pattribute)
{
mailbox_unix_data_t mud;
if (mbox == NULL || pattribute == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL ||
! mailbox_unix_is_valid (mbox, msgno))
return EINVAL;
*pattribute = mud->messages[msgno].new_attr;
return 0;
}
static int
mailbox_unix_set_attribute (mailbox_t mbox, size_t msgno,
attribute_t attribute)
{
mailbox_unix_data_t mud;
if (mbox == NULL ||
(mud = (mailbox_unix_data_t)mbox->data) == NULL ||
! mailbox_unix_is_valid (mbox, msgno))
return EINVAL;
attribute_copy (mud->messages[msgno].new_attr, attribute);
return 0;
}
/* locking */
static int
mailbox_unix_lock (mailbox_t mbox, int flag)
......
......@@ -183,12 +183,37 @@ message_size (message_t msg, size_t *size)
size_t hs, bs;
int status;
status = mailbox_get_size (msg->mailbox, msg->num, &hs, &bs);
if (status == 0)
{
if (size)
if (status != 0)
return status;
*size = hs + bs;
return 0;
}
return ENOSYS;
}
int
message_get_attribute (message_t msg, attribute_t *pattribute)
{
if (msg == NULL || pattribute == NULL)
return EINVAL;
if (msg->attribute)
*pattribute = msg->attribute;
if (msg->mailbox)
{
int status;
status = mailbox_get_attribute (msg->mailbox, msg->num, pattribute);
if (status != 0)
return status;
msg->attribute = *pattribute;
(*pattribute)->message = msg;
return 0;
}
return ENOSYS;
}
int
message_set_attribute (message_t msg, attribute_t attribute)
{
(void)msg; (void)attribute;
return ENOSYS;
}
......
......@@ -33,11 +33,12 @@
static struct _registrar registrar [] = {
{ NULL, NULL, 0, &registrar[1] }, /* sentinel, head list */
{ &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, &registrar[2] },
{ &_url_unix_registrar, &_mailbox_unix_registrar, 0, &registrar[3] },
{ &_url_maildir_registrar, &_mailbox_maildir_registrar, 0, &registrar[4] },
{ &_url_mmdf_registrar, &_mailbox_mmdf_registrar, 0, &registrar[5] },
{ &_url_pop_registrar, &_mailbox_pop_registrar, 0, &registrar[6] },
{ &_url_file_registrar, &_mailbox_mbox_registrar, 0, &registrar[2] },
{ &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, &registrar[3] },
{ &_url_unix_registrar, &_mailbox_unix_registrar, 0, &registrar[4] },
{ &_url_maildir_registrar, &_mailbox_maildir_registrar, 0, &registrar[5] },
{ &_url_mmdf_registrar, &_mailbox_mmdf_registrar, 0, &registrar[6] },
{ &_url_pop_registrar, &_mailbox_pop_registrar, 0, &registrar[7] },
{ &_url_imap_registrar, &_mailbox_imap_registrar, 0, &registrar[0] },
};
......@@ -175,6 +176,43 @@ registrar_get (int id,
}
int
registrar_entry_count (size_t *num)
{
struct _registrar *current;
size_t count;
for (count = 0, current = registrar->next; current != registrar;
current = current->next, count++)
;
if (num)
*num = count;
return 0;
}
int
registrar_entry (size_t num, struct url_registrar **ureg,
struct mailbox_registrar **mreg, int *id)
{
struct _registrar *current;
size_t count, status;
for (status = ENOENT, count = 0, current = registrar->next;
current != registrar; current = current->next, count++)
{
if (num == count)
{
if (ureg)
*ureg = current->ureg;
if (mreg)
*mreg = current->mreg;
if (id)
*id = (int)current;
status = 0;
break;
}
}
return status;
}
int
registrar_list (struct url_registrar **ureg, struct mailbox_registrar **mreg,
int *id, registrar_t *reg)
{
......
......@@ -59,6 +59,10 @@ extern int registrar_add __P ((struct url_registrar *ureg,
extern int registrar_remove __P ((int id));
extern int registrar_get __P ((int id, struct url_registrar **ureg,
struct mailbox_registrar **mreg));
extern int registrar_num __P ((size_t *num));
extern int registrar_get_entry __P ((size_t num, struct url_registrar **ureg,
struct mailbox_registrar **mreg,
int *id));
extern int registrar_list __P ((struct url_registrar **ureg,
struct mailbox_registrar **mreg,
int *id, registrar_t *reg));
......
......@@ -46,10 +46,21 @@ struct _registrar
struct _registrar *next;
};
/* This is function is obsolete use the registrar_entry_*() ones */
extern int registrar_list __P ((struct url_registrar **ureg,
struct mailbox_registrar **mreg,
int *id, registrar_t *reg));
extern int registrar_entry_count __P ((size_t *num));
extern int registrar_entry __P ((size_t num, struct url_registrar **ureg,
struct mailbox_registrar **mreg,
int *id));
/* IMAP */
extern struct mailbox_registrar _mailbox_imap_registrar;
extern struct url_registrar _url_imap_registrar;
/* FILE */
extern struct url_registrar _url_file_registrar;
/* MBOX */
extern struct mailbox_registrar _mailbox_mbox_registrar;
extern struct url_registrar _url_mbox_registrar;
......
......@@ -28,10 +28,15 @@
static int rfc822_parse (header_t h, const char *blurb, size_t len);
static int rfc822_set_value (header_t h, const char *fn, const char *fb,
size_t n, int replace);
ssize_t rfc822_get_data (header_t h, char *buf, size_t buflen,
static int rfc822_get_value (header_t h, const char *fn, char *fb,
size_t len, size_t *n);
static int rfc822_entry_count (header_t, size_t *num);
static int rfc822_entry_name (header_t h, size_t num, char *buf,
size_t buflen, size_t *total);
static int rfc822_entry_value (header_t h, size_t num, char *buf,
size_t buflen, size_t *total);
static ssize_t rfc822_get_data (header_t h, char *buf, size_t buflen,
off_t off, int *err);
static int rfc822_get_value (header_t h, const char *fn,
char *fb, size_t len, size_t *n);
struct _rfc822
{
......@@ -57,6 +62,9 @@ rfc822_init (header_t *ph, const char *blurb, size_t len)
h->_parse = rfc822_parse;
h->_get_value = rfc822_get_value;
h->_set_value = rfc822_set_value;
h->_entry_count = rfc822_entry_count;
h->_entry_name = rfc822_entry_name;
h->_entry_value = rfc822_entry_value;
h->_get_data = rfc822_get_data;
status = h->_parse (h, blurb, len);
......@@ -90,6 +98,14 @@ rfc822_destroy (header_t *ph)
}
}
/*
* Parsing is done in a rather simple fashion.
* meaning we just consider an entry to be
* a field-name an a field-value. So they
* maybe duplicate of field-name like "Received"
* they are just put in the array, see _get_value()
* on how to handle the case.
*/
static int
rfc822_parse (header_t h, const char *blurb, size_t len)
{
......@@ -118,8 +134,8 @@ rfc822_parse (header_t h, const char *blurb, size_t len)
for (header_start = rfc->blurb;; header_start = ++header_end)
{
/* get a header, a header is :
field-name ':' field-body1
[ ' ' '\t' field-body2 ] '\r' '\n'
* field-name ':' ' ' field-value '\r' '\n'
* [ (' ' | '\t') field-value '\r' '\n' ]
*/
for (header_start2 = header_start;;header_start2 = ++header_end)
{
......@@ -195,36 +211,124 @@ rfc822_set_value (header_t h, const char *fn, const char *fv,
}
static int
rfc822_get_value (header_t h, const char *fn, char *fv, size_t len, size_t *n)
rfc822_get_value (header_t h, const char *name, char *buffer,
size_t buflen, size_t *n)
{
size_t i = 0;
size_t j = 0;
size_t name_len, fn_len, fv_len;
size_t name_len;
size_t total = 0, fn_len = 0, fv_len = 0;
int threshold;
rfc822_t rfc;
if (h == NULL || fn == NULL || (rfc = (rfc822_t)h->data) == NULL)
if (h == NULL || name == NULL ||
(rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
for (name_len = strlen (fn), i = 0; i < rfc->hdr_count; i++)
/* 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.
*/
for (name_len = strlen (name), i = 0; i < rfc->hdr_count; i++)
{
fn_len = rfc->hdr[i].fn_end - rfc->hdr[i].fn;
if (fn_len == name_len && memcmp (rfc->hdr[i].fn, fn, fn_len) == 0)
if (fn_len == name_len && memcmp (rfc->hdr[i].fn, name, fn_len) == 0)
{
fv_len = rfc->hdr[i].fv_end - rfc->hdr[i].fv;
j = (len < fv_len) ? len : fv_len;
if (fv)
memcpy (fv, rfc->hdr[i].fv, j);
break;
fv_len = (rfc->hdr[i].fv_end - rfc->hdr[i].fv);
total += fv_len;
/* can everything fit in the buffer */
if (buffer && threshold > 0)
{
threshold -= fv_len;
if (threshold > 0)
{
memcpy (buffer, rfc->hdr[i].fv, fv_len);
buffer += fv_len;
}
else if (threshold < 0)
{
threshold += fv_len;
memcpy (buffer, rfc->hdr[i].fv, threshold);
buffer += threshold;
threshold = 0;
}
}
}
}
if (fv)
fv[j] = '\0'; /* null terminated */
if (buffer)
*buffer = '\0'; /* null terminated */
if (n)
*n = fv_len;
*n = total;
return 0;
}
static int
rfc822_entry_count (header_t h, size_t *num)
{
rfc822_t rfc;
if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
if (num)
*num = rfc->hdr_count;
return 0;
}
static int
rfc822_entry_name (header_t h, size_t num, char *buf,
size_t buflen, size_t *nwritten)
{
rfc822_t rfc;
size_t len;
if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
if (rfc->hdr_count == 0 || num > rfc->hdr_count)
return ENOENT;
len = rfc->hdr[num].fn_end - rfc->hdr[num].fn;
/* save one for the null */
--buflen;
if (buf && buflen > 0)
{
buflen = (len > buflen) ? buflen : len;
memcpy (buf, rfc->hdr[num].fn, buflen);
buf[buflen] = '\0';
}
if (nwritten)
*nwritten = len;
return 0;
}
static int
rfc822_entry_value (header_t h, size_t num, char *buf,
size_t buflen, size_t *nwritten)
{
rfc822_t rfc;
size_t len;
if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
if (rfc->hdr_count == 0 || num > rfc->hdr_count)
return ENOENT;
len = rfc->hdr[num].fv_end - rfc->hdr[num].fv;
/* save one for the null */
--buflen;
if (buf && buflen > 0)
{
buflen = (len > buflen) ? buflen : len;
memcpy (buf, rfc->hdr[num].fv, buflen);
buf[buflen] = '\0';
}
if (nwritten)
*nwritten = len;
return 0;
}
ssize_t
static ssize_t
rfc822_get_data (header_t h, char *buf, size_t buflen, off_t off, int *err)
{
rfc822_t rfc;
......
......@@ -47,6 +47,7 @@ url_init (url_t * purl, const char *name)
registrar_t reg = NULL;
size_t name_len;
int id;
size_t i, entry_count = 0;
/* Sanity checks */
if (name == NULL || *name == '\0')
......@@ -55,6 +56,22 @@ url_init (url_t * purl, const char *name)
name_len = strlen (name);
/* Search for a known scheme */
registrar_entry_count (&entry_count);
for (i = 0; i < entry_count; i++)
{
if (registrar_entry (i, &ureg, &mreg, &id) == 0)
{
size_t scheme_len;
if (ureg && ureg->scheme &&
name_len > (scheme_len = strlen (ureg->scheme)) &&
memcmp (name, ureg->scheme, scheme_len) == 0)
{
status = 0;
break;
}
}
}
/*
while (registrar_list (&ureg, &mreg, &id, &reg) == 0)
{
size_t scheme_len;
......@@ -66,6 +83,7 @@ url_init (url_t * purl, const char *name)
break;
}
}
*/
/* Found one initialize it */
if (status == 0)
......