Commit fe1332fb fe1332fb4825c7e5ad3324b63602bfcd3fe1143d by Alain Magloire

attribute.c header.c header.h header0.h locker.c locker.h

 	mailbox.c mbx_unix.c message.c message.h message0.h rfc822.c
 	url.c
using [io]stream.
1 parent 0f4b13ec
......@@ -40,9 +40,11 @@ attribute_destroy (attribute_t *pattr)
if (pattr && *pattr)
{
attribute_t attr = *pattr;
/* no owner we can free */
/* no owner we really can free it */
if (! attr->message)
free (*pattr);
/* loose the link */
*pattr = NULL;
}
return;
}
......
......@@ -85,10 +85,18 @@ header_entry_count (header_t h, size_t *num)
return h->_entry_count (h, num);
}
ssize_t
header_get_data (header_t h, char *data, size_t len, off_t off, int *err)
int
header_get_istream (header_t h, istream_t *pis)
{
if (h == NULL || pis == NULL || h->_get_istream == NULL)
return EINVAL;
return h->_get_istream (h, pis);
}
int
header_get_ostream (header_t h, ostream_t *pos)
{
if (h == NULL || h->_get_data)
if (h == NULL || pos == NULL || h->_get_ostream == NULL)
return EINVAL;
return h->_get_data (h, data, len, off, err);
return h->_get_ostream (h, pos);
}
......
......@@ -19,6 +19,7 @@
#define _HEADER_H
#include <sys/types.h>
#include <io.h>
#ifndef __P
#ifdef __STDC__
......@@ -80,6 +81,8 @@ 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_istream __P ((header_t, istream_t *pis));
extern int header_get_ostream __P ((header_t, ostream_t *pos));
#ifdef _cpluscplus
}
#endif
......
......@@ -20,6 +20,7 @@
#include <sys/types.h>
#include <header.h>
#include <io0.h>
#ifndef __P
#ifdef __STDC__
......@@ -49,27 +50,27 @@ struct _header
void *data;
/* owner ? */
void *message;
/* streams */
istream_t is;
ostream_t os;
/* Functions */
int (*_init) __P ((header_t *, const char *, size_t));
void (*_destroy) __P ((header_t *));
int (*_set_value) __P ((header_t, const char *fn, const char *fv,
int (*_init) __P ((header_t *, const char *, size_t));
void (*_destroy) __P ((header_t *));
int (*_set_value) __P ((header_t, const char *fn, const char *fv,
size_t n, int replace));
int (*_get_value) __P ((header_t, const char *fn, char *fv,
size_t len, size_t *n));
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));
int (*_get_value) __P ((header_t, const char *fn, char *fv,
size_t len, size_t *n));
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));
int (*_get_istream) __P ((header_t h, istream_t *is));
int (*_get_ostream) __P ((header_t h, ostream_t *os));
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));
......
......@@ -20,6 +20,17 @@
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <utime.h>
#include <signal.h>
#define LOCKFILE_ATTR 0444
#define LOCK_EXPIRE_TIME (5 * 60)
/*
* Waiting for Brian E. to implement this.
......@@ -27,31 +38,42 @@
struct _locker
{
char *filename;
size_t filename_len;
int lock;
int fd;
char *fname;
int locked;
int flags;
};
int
locker_init (locker_t *plocker, char *filename, size_t len)
locker_init (locker_t *plocker, char *filename, size_t len, int flags)
{
locker_t l;
if (plocker == NULL)
return EINVAL;
if (filename == NULL || len == 0)
return EINVAL;
l = malloc (sizeof(*l));
if (l == NULL)
return ENOMEM;
l->filename = calloc (len + 1, sizeof(char));
if (l->filename == NULL)
l->fname = calloc (len + 5 + 1, sizeof(char));
if (l->fname == NULL)
{
free (l);
return ENOMEM;
}
memcpy (l->filename, filename, len);
l->lock = 0;
l->filename_len = len;
memcpy (l->fname, filename, len);
strcat (l->fname, ".lock");
l->locked = 0;
if (flags)
l->flags = flags;
else
l->flags = MU_LOCKER_TIME;
l->fd = -1;
*plocker = l;
return 0;
}
......@@ -61,35 +83,112 @@ locker_destroy (locker_t *plocker)
{
if (plocker && *plocker)
{
free ((*plocker)->filename);
free ((*plocker)->fname);
free (*plocker);
*plocker = NULL;
}
}
int
locker_lock (locker_t locker, int flags)
locker_lock (locker_t lock, int flags)
{
int fd = -1;
char buf[16];
pid_t pid;
int remove = 0;
(void)flags;
if (locker == NULL)
if (lock == NULL)
return EINVAL;
locker->lock++;
/* check for lock existance
* if it exists but the process is gone the lock can be removed
*/
if ((fd = open(lock->fname, O_RDONLY)) != -1)
{
if (lock->flags & MU_LOCKER_PID)
{
if (read(fd, buf, sizeof (pid_t)) > 0)
{
/* check to see if this process is still running */
if ((pid = atoi(buf)) > 0)
{
/* process is gone so we try to remove the lock */
if (kill(pid, 0) == -1)
remove = 1;
}
}
}
if (lock->flags & MU_LOCKER_TIME)
{
struct stat buf;
fstat(fd, &buf);
/* the lock has expired */
if ((time(NULL) - buf.st_mtime) > LOCK_EXPIRE_TIME)
remove = 1;
}
close(fd);
if (remove)
unlink(lock->fname);
}
/* try to create the lockfile */
if ((fd = open(lock->fname,
O_WRONLY | O_CREAT | O_EXCL, LOCKFILE_ATTR)) == -1)
return (-1);
/* success */
sprintf(buf, "%d", getpid());
write(fd, buf, strlen(buf));
/* try to get a file lock */
if (lock->flags & MU_LOCKER_FCNTL)
{
struct flock fl;
memset(&fl, 0, sizeof(struct flock));
fl.l_type = F_WRLCK;
if (fcntl(fd, F_SETLK, &fl) == -1)
{
/* could not get the file lock */
close (fd);
unlink(lock->fname); /* remove the file I created */
return -1;
}
}
lock->fd = fd;
return 0;
}
int
locker_touchlock (locker_t locker)
locker_touchlock (locker_t lock)
{
if (locker == NULL)
if (!lock || lock->fname || (lock->fd == -1))
return EINVAL;
return 0;
return (utime(lock->fname, NULL));
}
int
locker_unlock (locker_t locker)
locker_unlock (locker_t lock)
{
if (locker == NULL)
if (!lock || !lock->fname || (lock->fd == -1))
return EINVAL;
locker->lock--;
if (lock->flags & MU_LOCKER_FCNTL)
{
struct flock fl;
memset(&fl, 0, sizeof(struct flock));
fl.l_type = F_UNLCK;
/* unlock failed ? */
if (fcntl(lock->fd, F_SETLK, &fl) == -1)
return errno;
}
lock->locked = 0;
close(lock->fd);
lock->fd = -1;
unlink(lock->fname);
return 0;
}
......
......@@ -35,11 +35,18 @@ extern "C" {
struct _locker;
typedef struct _locker *locker_t;
extern int locker_init __P ((locker_t *, char *filename, size_t len));
extern int locker_init __P ((locker_t *, char *filename,
size_t len, int flags));
extern void locker_destroy __P ((locker_t *));
#define MU_LOCKER_RDLOCK 0
#define MU_LOCKER_WRLOCK 1
/* locking flags */
#define MU_LOCKER_PID 1
#define MU_LOCKER_FCNTL 2
#define MU_LOCKER_TIME 4
extern int locker_lock __P ((locker_t, int flag));
extern int locker_touchlock __P ((locker_t));
extern int locker_unlock __P ((locker_t));
......
......@@ -59,9 +59,11 @@ mailbox_init (mailbox_t *pmbox, const char *name, int id)
status = mreg->_init (pmbox, name);
}
/* if things went ok set mreg for mailbox_destroy and the URL */
/* set the URL */
if (status == 0)
(*pmbox)->url = url;
else
url_destroy (&url);
return status;
}
......
......@@ -20,7 +20,10 @@
#include <mailbox0.h>
#include <registrar0.h>
#include <message0.h>
#include <url0.h>
#include <attribute0.h>
#include <header.h>
#include <io.h>
#include <auth.h>
#include <locker.h>
......@@ -64,8 +67,8 @@ typedef struct _mailbox_unix_message
/* little hack to make things easier
* when updating the attribute
*/
off_t status;
off_t status_end;
off_t hdr_status;
off_t hdr_status_end;
off_t body;
off_t body_end;
attribute_t old_attr;
......@@ -84,7 +87,7 @@ typedef struct _mailbox_unix_data
pthread_mutex_t mutex;
#endif
time_t mtime;
size_t size;
off_t size;
} *mailbox_unix_data_t;
static int mailbox_unix_open (mailbox_t mbox, int flag);
......@@ -121,6 +124,7 @@ 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, size_t msgno);
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);
......@@ -315,6 +319,9 @@ mailbox_unix_destroy (mailbox_t *pmbox)
}
}
free (mbox->messages);
/* destroy the url */
if (mbox->url)
url_destroy (&(mbox->url));
free (*pmbox);
*pmbox = NULL;
}
......@@ -420,12 +427,13 @@ mailbox_unix_open (mailbox_t mbox, int flags)
char buf [6];
if (fgets (buf, sizeof (buf), mud->file) == NULL)
{
int status = errno;
if (feof (mud->file))
clearerr (mud->file); /* the file maybe empty */
else if (ferror (mud->file))
{
mailbox_unix_iunlock (mbox);
return EIO;
return status;
}
}
else
......@@ -542,6 +550,7 @@ mailbox_unix_readhdr (mailbox_t mbox, char *buf, size_t len,
char *sep;
/* skip over the remaining header */
errno = 0;
while (fgets (buf, len, mud->file))
{
/* FIXME: The heuristic is still weak
......@@ -575,8 +584,8 @@ mailbox_unix_readhdr (mailbox_t mbox, char *buf, size_t len,
/* Set the attribute */
else if (strncmp (buf, "Status:", 7) == 0)
{
mum->status = ftell (mud->file);
mum->status_end = mum->status + strlen (buf);
mum->hdr_status = ftell (mud->file);
mum->hdr_status_end = mum->hdr_status + strlen (buf);
sep = strchr(buf, ':'); /* pass the ':' */
if (strchr (sep, 'R') != NULL)
attribute_set_read (mum->old_attr);
......@@ -591,7 +600,7 @@ mailbox_unix_readhdr (mailbox_t mbox, char *buf, size_t len,
}
/* check for any dubious conditions */
if (feof (mud->file) || ferror (mud->file))
return EIO;
return errno;
return 0;
}
......@@ -614,6 +623,7 @@ mailbox_unix_parse (mailbox_t mbox, size_t *msgs)
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
struct stat st;
int status;
/* sanity */
if (mbox == NULL ||
......@@ -628,16 +638,18 @@ mailbox_unix_parse (mailbox_t mbox, size_t *msgs)
if (fstat (fileno (mud->file), &st) != 0)
{
status = errno;
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
mailbox_unix_unlock (mbox);
return EIO;
return status;
}
mud->mtime = st.st_mtime;
mud->size = st.st_size;
rewind (mud->file);
errno = 0;
while (fgets (buf, sizeof (buf), mud->file))
{
if (mailbox_unix_is_from (buf))
......@@ -697,13 +709,14 @@ mailbox_unix_parse (mailbox_t mbox, size_t *msgs)
mum[count - 1].header -= over;
/* skip the remaining header and set the attributes */
if (mailbox_unix_readhdr (mbox, buf, sizeof (buf),
&content_length, count - 1) != 0)
if ((status = mailbox_unix_readhdr (mbox, buf,
sizeof (buf), &content_length,
count - 1)) != 0)
{
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
mailbox_unix_unlock (mbox);
return EIO;
return status;
}
mum[count - 1].header_end = ftell (mud->file) - strlen(buf);
header = 0;
......@@ -726,25 +739,22 @@ mailbox_unix_parse (mailbox_t mbox, size_t *msgs)
body = 0;
}
}
mailbox_unix_touchlock (mbox);
} /* while */
mum[count - 1].body_end = ftell (mud->file);
status = errno;
if (feof (mud->file))
clearerr (mud->file);
else if (ferror (mud->file))
{
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
mailbox_unix_unlock (mbox);
return EIO;
}
status = 0;
clearerr (mud->file);
mum[count - 1].body_end = ftell (mud->file);
rewind (mud->file);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
mailbox_unix_unlock (mbox);
if (msgs)
*msgs = count;
return 0;
return status;
}
/* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user
......@@ -867,6 +877,7 @@ mailbox_unix_expunge (mailbox_t mbox)
mailbox_unix_data_t mud;
mailbox_unix_message_t mum;
int status = 0;
int oflags;
sigset_t sigset;
FILE *tmpfile;
size_t nread;
......@@ -887,6 +898,13 @@ mailbox_unix_expunge (mailbox_t mbox)
if (tmpfile == NULL)
return errno;
/* Get the lock */
if (mailbox_unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
{
fclose (tmpfile);
return ENOLCK;
}
/* 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
......@@ -899,12 +917,6 @@ mailbox_unix_expunge (mailbox_t mbox)
sigaddset (&sigset, SIGWINCH);
sigprocmask (SIG_BLOCK, &sigset, 0);
/* Get the lock */
if (mailbox_unix_lock (mbox, MU_LOCKER_WRLOCK) < 0)
{
status = EIO;
goto bailout;
}
mailbox_unix_ilock (mbox, MU_LOCKER_RDLOCK);
flockfile (mud->file);
......@@ -921,6 +933,17 @@ mailbox_unix_expunge (mailbox_t mbox)
goto bailout;
}
/*
* We can not be NONBLOCKING here.
* It would irresponsable.
*/
if ((oflags = fcntl (fileno (mud->file), F_GETFL, 0)) < 0)
{
status = errno;
goto bailout;
}
fcntl (fileno (mud->file), F_SETFL, oflags & ~O_NONBLOCK);
rewind (mud->file);
/* Go to the first mail with an attribute change */
......@@ -964,22 +987,22 @@ mailbox_unix_expunge (mailbox_t mbox)
/* copy the header */
if (fseek (mud->file, mum->header, SEEK_SET) == -1)
{
status = EIO;
status = errno;
goto bailout;
}
/* attribute change ? */
if (! attribute_is_equal (mum->old_attr, mum->new_attr) &&
mum->status > mum->header)
mum->hdr_status > mum->header)
{
len = mum->status - mum->header;
current = mum->status_end;
len = mum->hdr_status - mum->header;
current = mum->hdr_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)
{
status = EIO;
status = errno;
goto bailout;
}
len -= nread;
......@@ -1025,7 +1048,7 @@ mailbox_unix_expunge (mailbox_t mbox)
if (fread (buffer, sizeof (*buffer), nread, mud->file) != nread
|| fwrite(buffer, sizeof(*buffer), nread, tmpfile) != nread)
{
status = EIO;
status = errno;
goto bailout;
}
len -= nread;
......@@ -1039,7 +1062,7 @@ mailbox_unix_expunge (mailbox_t mbox)
/* copy the body */
if (fseek (mud->file, mum->body, SEEK_SET) < 0)
{
status = EIO;
status = errno;
goto bailout;
}
len = mum->body_end - mum->body;
......@@ -1049,7 +1072,7 @@ mailbox_unix_expunge (mailbox_t mbox)
if (fread (buffer, sizeof (*buffer), nread, mud->file) != nread
|| fwrite(buffer, sizeof(*buffer), nread, tmpfile) != nread)
{
status = EIO;
status = errno;
goto bailout;
}
len -= nread;
......@@ -1057,16 +1080,51 @@ mailbox_unix_expunge (mailbox_t mbox)
}
}
/*
* Caution:
* before truncating the file see if we've receiving new mail
* Some program may not respect the lock.
*/
{
struct stat st;
if (fstat (fileno (mud->file), &st) != 0)
{
status = errno;
goto bailout;
}
if (st.st_size > mud->size)
{
size_t len = st.st_size - mud->size;
if (fseek (mud->file, mud->size, SEEK_SET) < 0)
{
status = errno;
goto bailout;
}
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)
{
status = errno;
goto bailout;
}
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;
status = errno;
goto bailout;
}
rewind (tmpfile);
while ((nread = fread (buffer, sizeof (*buffer), sizeof (buffer), tmpfile)) != 0)
while ((nread = fread (buffer, sizeof (*buffer),
sizeof (buffer), tmpfile)) != 0)
fwrite (buffer, sizeof (*buffer), nread, mud->file);
/* how can I handle error here ?? */
......@@ -1075,7 +1133,9 @@ mailbox_unix_expunge (mailbox_t mbox)
fflush (mud->file);
bailout:
/* Release the lock */
/* Release the locks */
if (oflags > 0)
fcntl (fileno (mud->file), F_SETFL, oflags);
mailbox_unix_unlock (mbox);
funlockfile (mud->file);
mailbox_unix_iunlock (mbox);
......@@ -1101,7 +1161,7 @@ mailbox_unix_get_body (mailbox_t mbox, size_t msgno, char *buffer,
}
/* check if valid */
if (len < 1 || mud == NULL || ! mailbox_unix_is_valid (mbox, msgno))
if (len == 0 || mud == NULL || ! mailbox_unix_is_valid (mbox, msgno))
{
if (err)
*err = EINVAL;
......@@ -1159,7 +1219,7 @@ mailbox_unix_get_header (mailbox_t mbox, size_t msgno, char *buffer,
}
/* check if valid */
if (len < 1 || ! mailbox_unix_is_valid (mbox, msgno))
if (len == 0 || ! mailbox_unix_is_valid (mbox, msgno))
{
if (err)
*err = EINVAL;
......@@ -1219,10 +1279,9 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
struct stat st;
int fd;
char buffer[BUFSIZ];
header_t hdr;
off_t off = 0;
int err;
size_t nread;
off_t off = 0;
istream_t is;
fd = fileno (mud->file);
if (fstat (fd, &st) != 0)
......@@ -1237,23 +1296,33 @@ mailbox_unix_append_message (mailbox_t mbox, message_t msg)
mailbox_unix_unlock (mbox);
return errno;
}
message_get_header (msg, &hdr);
if (st.st_size != 0)
fputc ('\n', mud->file);
while ((nread = header_get_data (hdr, buffer, sizeof (buffer),
off, &err)) > 0)
{
fwrite (buffer, sizeof (*buffer), nread, mud->file);
off += nread;
}
/* header */
{
header_t hdr;
message_get_header (msg, &hdr);
header_get_istream (hdr, &is);
if (st.st_size != 0)
fputc ('\n', mud->file);
while ((nread = istream_read (is, buffer, sizeof (buffer), off)) > 0)
{
fwrite (buffer, sizeof (*buffer), nread, mud->file);
off += nread;
}
}
*buffer = '\0';
/* separator */
fputc ('\n', mud->file);
off = 0;
while ((nread = message_get_content (msg, buffer, sizeof (buffer),
off, &err)) > 0)
{
fwrite (buffer, sizeof (*buffer), nread, mud->file);
off += nread;
}
/* body */
{
off = 0;
message_get_istream (msg, &is);
while ((nread = istream_read (is, buffer, sizeof (buffer), off)) > 0)
{
fwrite (buffer, sizeof (*buffer), nread, mud->file);
off += nread;
}
}
}
fflush(mud->file);
funlockfile (mud->file);
......@@ -1359,6 +1428,17 @@ mailbox_unix_lock (mailbox_t mbox, int flag)
}
static int
mailbox_unix_touchlock (mailbox_t mbox)
{
if (mbox && mbox->locker != NULL)
{
locker_t locker = mbox->locker;
locker_touchlock (locker);
}
return 0;
}
static int
mailbox_unix_unlock (mailbox_t mbox)
{
if (mbox && mbox->locker != NULL)
......
......@@ -20,6 +20,7 @@
#include <attribute0.h>
#include <message0.h>
#include <mailbox0.h>
#include <io0.h>
#include <errno.h>
#include <stdio.h>
......@@ -46,38 +47,50 @@ message_destroy (message_t *pmsg)
{
message_t msg = *pmsg;
/*
* The message has an mailbox owner
* The message has a mailbox owner
* let the mailbox destroy when it finishes
*/
if (msg->mailbox)
{
/* but still loose the link */
*pmsg = NULL;
return;
}
/* is the header own by us ? */
if (msg->header->message == msg)
msg->header->message = NULL;
header_destroy (&(msg->header));
if (msg->header && msg->header->message == msg)
{
msg->header->message = NULL;
header_destroy (&(msg->header));
}
/* is the attribute own by us ? */
if (msg->attribute->message == msg)
msg->attribute->message = NULL;
attribute_destroy (&(msg->attribute));
if (msg->attribute && msg->attribute->message == msg)
{
msg->attribute->message = NULL;
attribute_destroy (&(msg->attribute));
}
/* is the istream own by us */
if (msg->is && msg->is->owner == msg)
{
msg->is->owner = NULL;
istream_destroy (&(msg->is));
}
/* is the ostream own by us */
if (msg->os && msg->os->owner == msg)
{
msg->os->owner = NULL;
ostream_destroy (&(msg->os));
}
/* is it sometype of floating/temporary message */
if (msg->body)
{
body_t body = msg->body;
if (body->file)
fclose (body->file);
free (body->content);
free (msg->body);
}
free (msg->body);
if (msg->part_num > 0)
{
size_t i;
for (i = 0; i < msg->part_num; i++)
message_destroy (&(msg->parts[i]));
}
free (msg->parts);
free (msg);
/* loose the link */
*pmsg = NULL;
}
}
......@@ -86,14 +99,14 @@ int
message_get_header (message_t msg, header_t *phdr)
{
int err = 0;
int nread, n = 0;
char *pbuf = NULL, *tbuf = NULL;
char buf [BUFSIZ];
int off = 0;
int nread;
char *tbuf = NULL;
char buf[BUFSIZ];
if (phdr == NULL || msg == NULL)
return EINVAL;
/* header allready retrieve ? */
if (msg->header != NULL)
{
*phdr = msg->header;
......@@ -103,74 +116,239 @@ message_get_header (message_t msg, header_t *phdr)
if (msg->mailbox == NULL)
return EINVAL;
do
/* Ok this is where the fun begins, we have to take to account
* the F&$#*#^#&g O_NONBLOCKING, thanks very much to Brian and David.
* So POP for example is a stream protocol where the server
* keeps on sending the data til' the wire turn red. So when
* we hit a bottleneck (EAGAIN, EWOULDBLOCK, EINPROGRESS, etc ..)
* we save our state and propagate the error up. Hopefully
* the people upstairs will do the right thing by recalling
* us again.
* To resume my thoughts ... I do not like it.
*/
while ((nread = mailbox_get_header (msg->mailbox,
msg->num, buf, sizeof(buf),
msg->header_offset, &err)) > 0)
{
nread = mailbox_get_header (msg->mailbox, msg->num, buf, sizeof(buf),
off, &err);
if (err == EAGAIN || err == EINPROGRESS)
continue;
else if (err != 0)
{
free (pbuf);
return err;
}
off += nread;
tbuf = realloc (pbuf, off);
tbuf = realloc (msg->header_buffer, msg->header_offset + nread);
if (tbuf == NULL)
{
free (pbuf);
free (msg->header_buffer);
msg->header_buffer = NULL;
msg->header_offset = 0;
return ENOMEM;
}
else
pbuf = tbuf;
memcpy (pbuf + n, buf, nread);
n = nread;
} while (nread > 0);
msg->header_buffer = tbuf;
memcpy (msg->header_buffer + msg->header_offset, buf, nread);
msg->header_offset += nread;
}
err = header_init (&(msg->header), pbuf, off, MU_HEADER_RFC822);
if (nread < 0)
{
if (err == EAGAIN || err == EINPROGRESS || err == EWOULDBLOCK)
return EAGAIN;
free (msg->header_buffer);
msg->header_buffer = NULL;
msg->header_offset = 0;
return err;
}
err = header_init (&(msg->header), msg->header_buffer,
msg->header_offset, MU_HEADER_RFC822);
if (err == 0)
{
/* we own it */
msg->header->message = msg;
*phdr = msg->header;
msg->header = NULL;
}
free (pbuf);
/* we can discard it */
free (msg->header_buffer);
msg->header_buffer = NULL;
msg->header_offset = 0;
return err;
}
int
message_set_header (message_t msg, header_t hdr)
{
/* Can not do that on a mailbox */
if (msg == NULL || msg->mailbox == NULL)
return EINVAL;
if (msg->header)
/* we own it ? */
if (msg->header && msg->header->message == msg)
{
if (msg->header->message == msg)
msg->header->message = NULL;
msg->header->message = NULL;
header_destroy (&(msg->header));
}
msg->header = hdr;
return 0;
}
ssize_t
message_get_content (message_t msg, char *buf, size_t buflen,
off_t off, int *err)
static ssize_t
message_read (istream_t is, char *buf, size_t buflen, off_t off)
{
if (msg == NULL || msg->mailbox == NULL)
message_t msg = NULL;
ssize_t nread = -1;
int err = 0;
if (is == NULL || (msg = (message_t)is->owner) == NULL)
{
if (err)
*err = EINVAL;
errno = EINVAL;
return -1;
}
return mailbox_get_body (msg->mailbox, msg->num, buf, buflen, off, err);
/* is it own by a mailbox ? */
if (msg->mailbox)
{
nread = mailbox_get_body (msg->mailbox, msg->num, buf,
buflen, off, &err);
errno = err;
}
else if (msg->body)
{
body_t body = msg->body;
if (body->file)
{
/* we're not checking the error of fseek for some handlers
* like socket in those not make sense.
* FIXME: Alternative is to check fseeck and errno == EBADF
* if not a seekable stream.
*/
fseek (body->file, off, SEEK_SET);
nread = fread (buf, sizeof (char), buflen, body->file);
if (nread == 0)
{
if (ferror (body->file))
nread = -1;
/* clear the error even for feof() */
clearerr (body->file);
}
/* errno set by fread()/fseek() ? */
}
else if (body->content)
{
off_t ln = body->content_len - off;
if (ln > 0)
{
nread = ((size_t)ln < buflen) ? ln : buflen;
memcpy (buf, body->content + off, nread);
}
else
nread = 0;
errno = 0;
}
else
{
errno = EINVAL;
nread = -1;
}
}
return nread;
}
int
message_set_content (message_t msg, char *buf, size_t buflen)
message_get_istream (message_t msg, istream_t *pis)
{
(void)msg;(void)buf; (void)buflen;
return ENOSYS;
int err;
if (msg == NULL || pis == NULL)
return EINVAL;
/* already done */
if (msg->is)
*pis = msg->is;
err = istream_init (&(msg->is));
if (err != 0)
return err;
/* tell the world this is ours */
msg->is->owner = msg;
msg->is->_read = message_read;
*pis = msg->is;
return 0;
}
static int
message_write (ostream_t os, const char *buf, size_t buflen, off_t off)
{
message_t msg = NULL;
ssize_t nwrite = -1;
if (os == NULL || (msg = (message_t)os->owner) == NULL)
{
errno = EINVAL;
return -1;
}
/* is it own by a mailbox ? */
if (msg->mailbox)
{
/* We can not write in a mailbox this way */
errno = ENOSYS;
return -1;
}
else if (msg->body)
{
body_t body = msg->body;
if (body->file)
{
/* we're not checking the error of fseek for some handlers
* like socket in those not make sense.
* FIXME: Alternative is to check fseeck and errno == EBADF
* if not a seekable stream.
*/
fseek (body->file, off, SEEK_SET);
nwrite = fwrite (buf, sizeof (char), buflen, body->file);
if (nwrite == 0)
{
if (ferror (body->file))
nwrite = -1;
/* clear the error even for feof() */
clearerr (body->file);
}
/* errno set by fread()/fseek() ? */
}
else if (body->content)
{
off_t ln = body->content_len - off;
if (ln > 0)
{
nwrite = ((size_t)ln < buflen) ? ln : buflen;
memcpy (body->content + off, buf, nwrite);
}
else
nwrite = 0;
errno = 0;
}
else
{
errno = EINVAL;
nwrite = -1;
}
}
return nwrite;
}
int
message_get_ostream (message_t msg, ostream_t *pos)
{
int err;
if (msg == NULL || pos == NULL)
return EINVAL;
/* already done */
if (msg->os)
*pos = msg->os;
err = ostream_init (&(msg->os));
if (err != 0)
return err;
/* tell the world this is ours */
msg->os->owner = msg;
msg->os->_write = message_write;
*pos = msg->os;
return 0;
}
int
......@@ -194,10 +372,15 @@ message_size (message_t msg, size_t *size)
int
message_get_attribute (message_t msg, attribute_t *pattribute)
{
int status;
if (msg == NULL || pattribute == NULL)
return EINVAL;
/* killroy was here ? */
if (msg->attribute)
*pattribute = msg->attribute;
if (msg->mailbox)
{
int status;
......@@ -205,15 +388,39 @@ message_get_attribute (message_t msg, attribute_t *pattribute)
if (status != 0)
return status;
msg->attribute = *pattribute;
/* set the owner of the attribute to be us */
(*pattribute)->message = msg;
return 0;
}
return ENOSYS;
status = attribute_init (&(msg->attribute));
if (status == 0)
{
/* we own this baby */
msg->attribute->message = msg;
*pattribute = msg->attribute;
}
return status;
}
int
message_set_attribute (message_t msg, attribute_t attribute)
{
(void)msg; (void)attribute;
return ENOSYS;
if (msg == NULL)
return EINVAL;
/* own by a mailbox can no set attribute this way */
if (msg->mailbox)
return ENOSYS;
/* we own it ? */
if (msg->attribute && msg->attribute->message == msg)
{
/* orphan it */
msg->attribute->message = NULL;
attribute_destroy (&(msg->attribute));
}
msg->attribute = attribute;
return 0;
}
......
......@@ -20,6 +20,7 @@
#include <header.h>
#include <attribute.h>
#include <io.h>
#include <sys/types.h>
......@@ -45,20 +46,20 @@ extern void message_destroy __P ((message_t *));
extern int message_get_header __P ((message_t, header_t *));
extern int message_set_header __P ((message_t, header_t));
extern ssize_t message_get_content __P ((message_t, char *,
size_t, off_t, int *));
extern int message_set_content __P ((message_t, char *, size_t));
extern int message_get_istream __P ((message_t, istream_t *));
extern int message_set_istream __P ((message_t, istream_t *));
extern int message_get_ostream __P ((message_t, ostream_t *));
extern int message_set_ostream __P ((message_t, ostream_t *));
extern int message_is_multipart __P ((message_t));
extern int message_get_part_count __P ((message_t, size_t *));
extern int message_get_part __P ((message_t, size_t, message_t *));
extern int message_add_part __P ((message_t, message_t));
extern int message_get_size __P ((message_t, size_t *));
extern int message_get_attribute __P ((message_t, attribute_t *));
extern int message_set_attribute __P ((message_t, attribute_t));
extern int message_clone __P ((message_t, message_t *));
#ifdef _cpluscplus
}
#endif
......
......@@ -42,13 +42,16 @@ typedef struct _body * body_t;
/* forward declaration */
struct _message
{
/* whos is the owner, only mailbox can own messages */
mailbox_t mailbox;
header_t header;
message_t *parts;
size_t part_num;
istream_t is;
ostream_t os;
body_t body;
size_t num;
attribute_t attribute;
char *header_buffer;
off_t header_offset;
int (*_get_header) __P ((message_t msg, header_t *hdr));
int (*_set_header) __P ((message_t msg, header_t hdr));
......@@ -56,9 +59,10 @@ struct _message
int (*_get_attribute) __P ((message_t msg, attribute_t *attr));
int (*_set_attribute) __P ((message_t msg, attribute_t attr));
int (*_get_content) __P ((message_t msg, char *buf, size_t len,
size_t *nread, off_t offset));
int (*_set_content) __P ((message_t msg, char *buf, size_t len));
int (*_get_istream) __P ((message_t msg, istream_t *));
int (*_set_istream) __P ((message_t msg, istream_t));
int (*_get_ostream) __P ((message_t msg, ostream_t *));
int (*_set_ostream) __P ((message_t msg, ostream_t));
int (*_size) __P ((message_t msg, size_t *size));
......
......@@ -35,8 +35,9 @@ 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_istream (header_t h, istream_t *pis);
static int rfc822_get_ostream (header_t h, ostream_t *pos);
static ssize_t rfc822_read (istream_t is, char *buf, size_t buflen, off_t off);
struct _rfc822
{
......@@ -65,7 +66,8 @@ rfc822_init (header_t *ph, const char *blurb, size_t len)
h->_entry_count = rfc822_entry_count;
h->_entry_name = rfc822_entry_name;
h->_entry_value = rfc822_entry_value;
h->_get_data = rfc822_get_data;
h->_get_istream = rfc822_get_istream;
h->_get_ostream = rfc822_get_ostream;
status = h->_parse (h, blurb, len);
if (status != 0)
......@@ -86,6 +88,18 @@ rfc822_destroy (header_t *ph)
*ph = NULL;
return;
}
/* is the istream own by us */
if (h->is && h->is->owner == h)
{
h->is->owner = NULL;
istream_destroy (&(h->is));
}
/* is the ostream own by us */
if (h->os && h->os->owner == h)
{
h->os->owner = NULL;
ostream_destroy (&(h->os));
}
if (h->data)
{
rfc822_t rfc = (rfc822_t)h->data;
......@@ -329,15 +343,16 @@ rfc822_entry_value (header_t h, size_t num, char *buf,
}
static ssize_t
rfc822_get_data (header_t h, char *buf, size_t buflen, off_t off, int *err)
rfc822_read (istream_t is, char *buf, size_t buflen, off_t off)
{
rfc822_t rfc;
header_t h;
rfc822_t rfc = NULL;
ssize_t len;
if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
if (is == NULL || (h = (header_t)is->owner) == NULL ||
(rfc = (rfc822_t)h->data) == NULL)
{
if (err)
*err = EINVAL;
errno = EINVAL;
return -1;
}
......@@ -355,3 +370,31 @@ rfc822_get_data (header_t h, char *buf, size_t buflen, off_t off, int *err)
return len;
}
int
rfc822_get_istream (header_t h, istream_t *pis)
{
int err;
if (h == NULL || pis == NULL)
return EINVAL;
/* already done */
if (h->is)
*pis = h->is;
err = istream_init (&(h->is));
if (err != 0)
return err;
/* tell the world this is ours */
h->is->owner = h;
h->is->_read = rfc822_read;
*pis = h->is;
return 0;
}
int
rfc822_get_ostream (header_t h, ostream_t *pos)
{
if (h == NULL || pos == NULL)
return EINVAL;
return ENOSYS;
}
......
......@@ -20,7 +20,7 @@
#endif
#include <url0.h>
#include <registrar.h>
#include <registrar0.h>
#include <cpystr.h>
#include <string.h>
......@@ -44,7 +44,6 @@ url_init (url_t * purl, const char *name)
int status = EINVAL;
struct url_registrar *ureg;
struct mailbox_registrar *mreg;
registrar_t reg = NULL;
size_t name_len;
int id;
size_t i, entry_count = 0;
......