Commit efd8da5e efd8da5ebbdd6411f4d0869f14d934e5006e1372 by Alain Magloire

* mailbox/message.c (message_get_uid) : Add message_get_uid() for

the UID of the message (IMAP definition) and message_get_uidl() for
the POP3 definition.
* mailbox/attachment.c : Indentation fixes.
* mailbox/file_stream.c : Make sure that the FILE* is close before
opening.
* mailbox/folder_imap.c : Use strcasecmp() not strcmp().
* mailbox/mailbox.c : Added mailbox_uidnext() and mailbox_uidvalidity.
* mailbox/mapfile_stream.c : When munmap() failed we should check
against MAP_FAILED, not NULL.
* mailbox/mbx_imap.c : Implement imap_uidnext(), imap_uidvalidity()
imap_message_uid().
* mailbox/mbx_mbox.c : Implement mbox_uidnext(), mbox_uidvalidity()
mbox_message_uid().
* mailbox/mbx_mboxscan.c : Implement uidvalidity, it is save int the
header of the first message, "X-IMAPbase: 127673838 123", a la c-client.
Save UID, it is save in "X-UID".
* mailbox/mbx_pop.c : Implement pop_messages_recent(),
pop_message_unseen() and pop_uid().
* mailbox/trans_stream.c : Indentation fixes.
1 parent 0d961fe9
......@@ -31,6 +31,9 @@
#define MAX_HDR_LEN 256
#define BUF_SIZE 2048
/* FIXME: this should be in a public header. */
extern int message_attachment_filename __P ((message_t, const char **filename));
struct _msg_info {
char *buf;
size_t nbytes;
......@@ -174,7 +177,7 @@ static char *_header_get_param(char *field_body, const char *param, size_t *len)
return NULL;
}
int message_attachment_filename(message_t msg, char **filename)
int message_attachment_filename(message_t msg, const char **filename)
{
char *pTmp, *fname = NULL;
header_t hdr;
......@@ -219,7 +222,8 @@ int message_save_attachment(message_t msg, const char *filename, void **data)
size_t size;
size_t nbytes;
header_t hdr;
const char *content_encoding, *fname = NULL;
char *content_encoding;
const char *fname = NULL;
if ( msg == NULL || filename == NULL)
return EINVAL;
......@@ -240,7 +244,7 @@ int message_save_attachment(message_t msg, const char *filename, void **data)
ret = ENOMEM;
header_get_value(hdr, "Content-Transfer-Encoding", content_encoding, size+1, 0);
} else
content_encoding = "7bit";
content_encoding = (char *)"7bit";
ret = decoder_stream_create(&info->ostream, fstream, content_encoding);
}
}
......
......@@ -227,6 +227,12 @@ _file_open (stream_t stream, const char *filename, int port, int flags)
if (fs == NULL)
return EINVAL;
if (fs->file)
{
fclose (fs->file);
fs->file = NULL;
}
/* Map the flags to the system equivalent. */
if (flags & MU_STREAM_WRITE)
flg = O_WRONLY;
......
......@@ -1155,35 +1155,35 @@ imap_flags (f_imap_t f_imap)
msg_imap_t msg_imap = f_imap->callback.msg_imap;
while ((flag = strtok_r (flags, " ()", &sp)) != NULL)
{
if (strcmp (flag, "\\Seen") == 0)
if (strcasecmp (flag, "\\Seen") == 0)
{
if (msg_imap)
msg_imap->flags |= MU_ATTRIBUTE_SEEN;
else
f_imap->flags |= MU_ATTRIBUTE_SEEN;
}
else if (strcmp (flag, "\\Answered") == 0)
else if (strcasecmp (flag, "\\Answered") == 0)
{
if (msg_imap)
msg_imap->flags |= MU_ATTRIBUTE_ANSWERED;
else
f_imap->flags |= MU_ATTRIBUTE_ANSWERED;
}
else if (strcmp (flag, "\\Flagged") == 0)
else if (strcasecmp (flag, "\\Flagged") == 0)
{
if (msg_imap)
msg_imap->flags |= MU_ATTRIBUTE_FLAGGED;
else
f_imap->flags |= MU_ATTRIBUTE_FLAGGED;
}
else if (strcmp (flag, "\\Deleted") == 0)
else if (strcasecmp (flag, "\\Deleted") == 0)
{
if (msg_imap)
msg_imap->flags |= MU_ATTRIBUTE_DELETED;
else
f_imap->flags |= MU_ATTRIBUTE_DELETED;
}
else if (strcmp (flag, "\\Draft") == 0)
else if (strcasecmp (flag, "\\Draft") == 0)
{
if (msg_imap)
msg_imap->flags |= MU_ATTRIBUTE_DRAFT;
......@@ -1256,8 +1256,7 @@ imap_fetch (f_imap_t f_imap)
{
status = imap_flags (f_imap);
}
/* This the short form for BODYSTRUCTURE. */
else if (strcmp (command, "BODY") == 0)
else if (strcasecmp (command, "BODY") == 0)
{
status = imap_bodystructure (f_imap);
}
......@@ -1269,12 +1268,18 @@ imap_fetch (f_imap_t f_imap)
{
command = strtok_r (NULL, " ()\n", &sp);
if (f_imap->callback.msg_imap)
f_imap->callback.msg_imap->message_size = strtol (command, NULL, 10);
f_imap->callback.msg_imap->message_size = strtoul (command, NULL, 10);
}
else if (strncmp (command, "BODY", 4) == 0)
{
status = imap_string (f_imap);
}
else if (strncmp (command, "UID", 3) == 0)
{
command = strtok_r (NULL, " ()\n", &sp);
if (f_imap->callback.msg_imap)
f_imap->callback.msg_imap->uid = strtoul (command, NULL, 10);
}
return status;
}
......@@ -1483,7 +1488,7 @@ imap_parse (f_imap_t f_imap)
{
/* Is it a Status Response. */
if (strcmp (response, "OK") == 0)
if (strcasecmp (response, "OK") == 0)
{
/* Check for status response [code]. */
if (*remainder == '[')
......@@ -1496,13 +1501,14 @@ imap_parse (f_imap_t f_imap)
subtag = strtok_r (cruft, " ", &sp);
if (!subtag) subtag = empty;
if (strcmp (subtag, "ALERT") == 0)
if (strcasecmp (subtag, "ALERT") == 0)
{
/* The human-readable text contains a special alert that
MUST be presented to the user in a fashion that calls
the user's attention to the message. */
fprintf (stderr, "ALERT: %s\n", (sp) ? sp : "");
}
else if (strcmp (subtag, "BADCHARSET") == 0)
else if (strcasecmp (subtag, "BADCHARSET") == 0)
{
/* Optionally followed by a parenthesized list of
charsets. A SEARCH failed because the given charset
......@@ -1510,7 +1516,7 @@ imap_parse (f_imap_t f_imap)
optional list of charsets is given, this lists the
charsets that are supported by this implementation. */
}
else if (strcmp (subtag, "CAPABILITY") == 0)
else if (strcasecmp (subtag, "CAPABILITY") == 0)
{
/* Followed by a list of capabilities. This can appear
in the initial OK or PREAUTH response to transmit an
......@@ -1521,7 +1527,7 @@ imap_parse (f_imap_t f_imap)
free (f_imap->capa);
f_imap->capa = strdup (cruft);
}
else if (strcmp (subtag, "NEWNAME") == 0)
else if (strcasecmp (subtag, "NEWNAME") == 0)
{
/* Followed by a mailbox name and a new mailbox name. A
SELECT or EXAMINE failed because the target mailbox
......@@ -1530,13 +1536,13 @@ imap_parse (f_imap_t f_imap)
operation can succeed if the SELECT or EXAMINE is
reissued with the new mailbox name. */
}
else if (strcmp (subtag, "PARSE") == 0)
else if (strcasecmp (subtag, "PARSE") == 0)
{
/* The human-readable text represents an error in
parsing the [RFC-822] header or [MIME-IMB] headers
of a message in the mailbox. */
}
else if (strcmp (subtag, "PERMANENTFLAGS") == 0)
else if (strcasecmp (subtag, "PERMANENTFLAGS") == 0)
{
/* Followed by a parenthesized list of flags, indicates
which of the known flags that the client can change
......@@ -1551,19 +1557,19 @@ imap_parse (f_imap_t f_imap)
that it is possible to create new keywords by
attempting to store those flags in the mailbox. */
}
else if (strcmp (subtag, "READ-ONLY") == 0)
else if (strcasecmp (subtag, "READ-ONLY") == 0)
{
/* The mailbox is selected read-only, or its access
while selected has changed from read-write to
read-only. */
}
else if (strcmp (subtag, "READ-WRITE") == 0)
else if (strcasecmp (subtag, "READ-WRITE") == 0)
{
/* The mailbox is selected read-write, or its access
while selected has changed from read-only to
read-write. */
}
else if (strcmp (subtag, "TRYCREATE") == 0)
else if (strcasecmp (subtag, "TRYCREATE") == 0)
{
/* An APPEND or COPY attempt is failing because the
target mailbox does not exist (as opposed to some
......@@ -1571,13 +1577,15 @@ imap_parse (f_imap_t f_imap)
the operation can succeed if the mailbox is first
created by the CREATE command. */
}
else if (strcmp (subtag, "UIDNEXT") == 0)
else if (strcasecmp (subtag, "UIDNEXT") == 0)
{
/* Followed by a decimal number, indicates the next
unique identifier value. Refer to section 2.3.1.1
for more information. */
char *value = strtok_r (NULL, " ", &sp);
f_imap->selected->uidnext = strtol (value, NULL, 10);
}
else if (strcmp (subtag, "UIDVALIDITY") == 0)
else if (strcasecmp (subtag, "UIDVALIDITY") == 0)
{
/* Followed by a decimal number, indicates the unique
identifier validity value. Refer to section 2.3.1.1
......@@ -1585,7 +1593,7 @@ imap_parse (f_imap_t f_imap)
char *value = strtok_r (NULL, " ", &sp);
f_imap->selected->uidvalidity = strtol (value, NULL, 10);
}
else if (strcmp (subtag, "UNSEEN") == 0)
else if (strcasecmp (subtag, "UNSEEN") == 0)
{
/* Followed by a decimal number, indicates the number of
the first message without the \Seen flag set. */
......@@ -1608,66 +1616,66 @@ imap_parse (f_imap_t f_imap)
printf("Untagged OK: %s\n", remainder);
}
}
else if (strcmp (response, "NO") == 0)
else if (strcasecmp (response, "NO") == 0)
{
/* This does not mean failure but rather a strong warning. */
printf ("Untagged NO: %s\n", remainder);
}
else if (strcmp (response, "BAD") == 0)
else if (strcasecmp (response, "BAD") == 0)
{
/* We're dead, protocol/syntax error. */
printf ("Untagged BAD: %s\n", remainder);
}
else if (strcmp (response, "PREAUTH") == 0)
else if (strcasecmp (response, "PREAUTH") == 0)
{
}
else if (strcmp (response, "BYE") == 0)
else if (strcasecmp (response, "BYE") == 0)
{
/* We should close the stream. This is not recoverable. */
done = 1;
f_imap->isopen = 0;
stream_close (f_imap->folder->stream);
}
else if (strcmp (response, "CAPABILITY") == 0)
else if (strcasecmp (response, "CAPABILITY") == 0)
{
if (f_imap->capa)
free (f_imap->capa);
f_imap->capa = strdup (remainder);
}
else if (strcmp (remainder, "EXISTS") == 0)
else if (strcasecmp (remainder, "EXISTS") == 0)
{
f_imap->selected->messages_count = strtol (response, NULL, 10);
}
else if (strcmp (remainder, "EXPUNGE") == 0)
else if (strcasecmp (remainder, "EXPUNGE") == 0)
{
}
else if (strncmp (remainder, "FETCH", 5) == 0)
else if (strncasecmp (remainder, "FETCH", 5) == 0)
{
status = imap_fetch (f_imap);
if (status != 0)
break;
}
else if (strcmp (response, "FLAGS") == 0)
else if (strcasecmp (response, "FLAGS") == 0)
{
/* Flags define on the mailbox not a message flags. */
status = imap_flags (f_imap);
}
else if (strcmp (response, "LIST") == 0)
else if (strcasecmp (response, "LIST") == 0)
{
status = imap_list (f_imap);
}
else if (strcmp (response, "LSUB") == 0)
else if (strcasecmp (response, "LSUB") == 0)
{
status = imap_list (f_imap);
}
else if (strcmp (remainder, "RECENT") == 0)
else if (strcasecmp (remainder, "RECENT") == 0)
{
f_imap->selected->recent = strtol (response, NULL, 10);
}
else if (strcmp (response, "SEARCH") == 0)
else if (strcasecmp (response, "SEARCH") == 0)
{
}
else if (strcmp (response, "STATUS") == 0)
else if (strcasecmp (response, "STATUS") == 0)
{
}
else
......@@ -1686,12 +1694,12 @@ imap_parse (f_imap_t f_imap)
{
/* Every transaction ends with a tagged response. */
done = 1;
if (strcmp (response, "OK") == 0)
if (strcasecmp (response, "OK") == 0)
{
}
else /* NO and BAD */
{
if (strncmp (remainder, "LOGIN", 5) == 0)
if (strncasecmp (remainder, "LOGIN", 5) == 0)
{
observable_t observable = NULL;
folder_get_observable (f_imap->folder, &observable);
......
......@@ -166,7 +166,8 @@ struct _m_imap
msg_imap_t *imessages;
size_t recent;
size_t unseen;
size_t uidvalidity;
unsigned long uidvalidity;
size_t uidnext;
char *name;
};
......@@ -181,7 +182,7 @@ struct _msg_imap
msg_imap_t *parts;
msg_imap_t parent;
int flags;
char *uid;
size_t uid;
size_t message_size;
size_t message_lines;
......
......@@ -69,8 +69,11 @@ struct _mailbox
int (*_get_message) __P ((mailbox_t, size_t msgno, message_t *msg));
int (*_append_message) __P ((mailbox_t, message_t msg));
int (*_messages_count) __P ((mailbox_t, size_t *num));
int (*_unseen_count) __P ((mailbox_t, size_t *num));
int (*_messages_recent) __P ((mailbox_t, size_t *num));
int (*_message_unseen) __P ((mailbox_t, size_t *num));
int (*_expunge) __P ((mailbox_t));
int (*_uidvalidity) __P ((mailbox_t, unsigned long *num));
int (*_uidnext) __P ((mailbox_t, size_t *num));
int (*_scan) __P ((mailbox_t, size_t msgno, size_t *count));
int (*_is_updated) __P ((mailbox_t));
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
......@@ -65,7 +65,8 @@ struct _message
size_t hdr_buflen;
int hdr_done;
int (*_get_uid) __P ((message_t, char *, size_t, size_t *));
int (*_get_uidl) __P ((message_t, char *, size_t, size_t *));
int (*_get_uid) __P ((message_t, size_t *));
int (*_get_num_parts) __P ((message_t, size_t *));
int (*_get_part) __P ((message_t, size_t, message_t *));
int (*_is_multipart) __P ((message_t, int *));
......
......@@ -220,11 +220,18 @@ mailbox_messages_count (mailbox_t mbox, size_t *num)
}
int
mailbox_unseen_count (mailbox_t mbox, size_t *num)
mailbox_messages_recent (mailbox_t mbox, size_t *num)
{
if (mbox && mbox->_unseen_count)
return mbox->_unseen_count (mbox, num);
return mailbox_messages_count (mbox, num);
if (mbox == NULL || mbox->_messages_recent == NULL)
return ENOSYS;
return mbox->_messages_recent (mbox, num);
}
int
mailbox_message_unseen (mailbox_t mbox, size_t *num)
{
if (mbox == NULL || mbox->_message_unseen == NULL)
return ENOSYS;
return mbox->_message_unseen (mbox, num);
}
int
......@@ -259,6 +266,22 @@ mailbox_size (mailbox_t mbox, off_t *psize)
return mbox->_size (mbox, psize);
}
int
mailbox_uidvalidity (mailbox_t mbox, unsigned long *pvalid)
{
if (mbox == NULL || mbox->_uidvalidity == NULL)
return 0;
return mbox->_uidvalidity (mbox, pvalid);
}
int
mailbox_uidnext (mailbox_t mbox, size_t *puidnext)
{
if (mbox == NULL || mbox->_uidnext == NULL)
return 0;
return mbox->_uidnext (mbox, puidnext);
}
/* locking */
int
mailbox_set_locker (mailbox_t mbox, locker_t locker)
......
......@@ -48,7 +48,7 @@ _mapfile_destroy (stream_t stream)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs && mfs->ptr)
if (mfs && mfs->ptr != MAP_FAILED)
{
munmap (mfs->ptr, mfs->size);
close (mfs->fd);
......@@ -63,7 +63,7 @@ _mapfile_read (stream_t stream, char *optr, size_t osize,
struct _mapfile_stream *mfs = stream_get_owner (stream);
size_t n;
if (mfs == NULL || mfs->ptr == NULL)
if (mfs == NULL || mfs->ptr == MAP_FAILED)
return EINVAL;
if (offset >= (off_t)mfs->size)
......@@ -89,7 +89,7 @@ _mapfile_readline (stream_t stream, char *optr, size_t osize,
char *nl;
size_t n = 0;
if (mfs == NULL || mfs->ptr == NULL)
if (mfs == NULL || mfs->ptr == MAP_FAILED)
return EINVAL;
/* Save space for the null byte. */
osize--;
......@@ -116,7 +116,7 @@ _mapfile_write (stream_t stream, const char *iptr, size_t isize,
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL || mfs->ptr == NULL)
if (mfs == NULL || mfs->ptr == MAP_FAILED)
return EINVAL;
if (! (mfs->flags & PROT_WRITE))
......@@ -155,7 +155,7 @@ static int
_mapfile_truncate (stream_t stream, off_t len)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL || mfs->ptr == NULL)
if (mfs == NULL || mfs->ptr == MAP_FAILED)
return EINVAL;
/* Remap. */
if (munmap (mfs->ptr, mfs->size) != 0)
......@@ -185,7 +185,7 @@ _mapfile_size (stream_t stream, off_t *psize)
struct stat stbuf;
int err = 0;
if (mfs == NULL || mfs->ptr == NULL)
if (mfs == NULL || mfs->ptr == MAP_FAILED)
return EINVAL;
msync (mfs->ptr, mfs->size, MS_SYNC);
if (fstat(mfs->fd, &stbuf) != 0)
......@@ -204,7 +204,7 @@ _mapfile_size (stream_t stream, off_t *psize)
}
if (err != 0)
{
mfs->ptr = NULL;
mfs->ptr = MAP_FAILED;
close (mfs->fd);
mfs->fd = -1;
}
......@@ -241,13 +241,13 @@ _mapfile_close (stream_t stream)
{
struct _mapfile_stream *mfs = stream_get_owner (stream);
int err = 0;
if (mfs && mfs->ptr)
if (mfs && mfs->ptr != MAP_FAILED)
{
if (munmap (mfs->ptr, mfs->size) != 0)
err = errno;
if (close (mfs->fd) != 0)
err = errno;
mfs->ptr = NULL;
mfs->ptr = MAP_FAILED;
mfs->fd = -1;
}
return err;
......@@ -265,6 +265,17 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags)
if (mfs == NULL)
return EINVAL;
/* Close any previous file. */
if (mfs->ptr != MAP_FAILED)
{
munmap (mfs->ptr, mfs->size);
mfs->ptr = MAP_FAILED;
}
if (mfs->fd != -1)
{
close (mfs->fd);
mfs->fd = -1;
}
/* Map the flags to the system equivalent */
if (flags & MU_STREAM_WRITE)
{
......@@ -299,7 +310,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags)
{
int err = errno;
close (mfs->fd);
mfs->ptr = NULL;
mfs->ptr = MAP_FAILED;
return err;
}
mfs->flags = mflag;
......@@ -325,6 +336,9 @@ mapfile_stream_create (stream_t *stream)
if (fs == NULL)
return ENOMEM;
fs->fd = -1;
fs->ptr = MAP_FAILED;
ret = stream_create (stream, MU_STREAM_NO_CHECK, fs);
if (ret != 0)
{
......
......@@ -33,10 +33,13 @@
static void mailbox_imap_destroy (mailbox_t);
static int mailbox_imap_open (mailbox_t, int);
static int mailbox_imap_close (mailbox_t);
static int imap_uidvalidity (mailbox_t, unsigned long *);
static int imap_uidnext (mailbox_t, size_t *);
static int imap_expunge (mailbox_t);
static int imap_get_message (mailbox_t, size_t, message_t *);
static int imap_messages_count (mailbox_t, size_t *);
static int imap_unseen_count (mailbox_t, size_t *);
static int imap_messages_recent (mailbox_t, size_t *);
static int imap_message_unseen (mailbox_t, size_t *);
static int imap_scan (mailbox_t, size_t, size_t *);
static int imap_is_updated (mailbox_t);
static int imap_append_message (mailbox_t, message_t);
......@@ -47,7 +50,7 @@ static int imap_message_size (message_t, size_t *);
static int imap_message_lines (message_t, size_t *);
static int imap_message_fd (stream_t, int *);
static int imap_message_read (stream_t , char *, size_t, off_t, size_t *);
static int imap_message_uid (message_t, char *, size_t, size_t *);
static int imap_message_uid (message_t, size_t *);
/* Mime handling. */
static int imap_is_multipart (message_t, int *);
......@@ -66,7 +69,6 @@ static int imap_attr_unset_flags (attribute_t, int);
/* Header. */
static int imap_header_read (header_t, char*, size_t, off_t, size_t *);
static int imap_header_get_value (header_t, const char*, char *, size_t, size_t *);
static int imap_header_fd (stream_t, int *);
/* Body. */
static int imap_body_read (stream_t, char *, size_t, off_t, size_t *);
......@@ -116,8 +118,11 @@ _mailbox_imap_init (mailbox_t mailbox)
mailbox->_get_message = imap_get_message;
mailbox->_append_message = imap_append_message;
mailbox->_messages_count = imap_messages_count;
mailbox->_unseen_count = imap_unseen_count;
mailbox->_messages_recent = imap_messages_recent;
mailbox->_message_unseen = imap_message_unseen;
mailbox->_expunge = imap_expunge;
mailbox->_uidvalidity = imap_uidvalidity;
mailbox->_uidnext = imap_uidnext;
mailbox->_scan = imap_scan;
mailbox->_is_updated = imap_is_updated;
......@@ -142,8 +147,6 @@ free_subparts (msg_imap_t msg_imap)
if (msg_imap->message)
message_destroy (&(msg_imap->message), msg_imap);
if (msg_imap->uid)
free (msg_imap->uid);
if (msg_imap->parts)
free (msg_imap->parts);
free(msg_imap);
......@@ -411,7 +414,7 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
message_set_get_num_parts (msg, imap_get_num_parts, msg_imap);
message_set_get_part (msg, imap_get_part, msg_imap);
/* Set the UIDL call on the message. */
/* Set the UID on the message. */
message_set_uid (msg, imap_message_uid, msg_imap);
*pmsg = msg;
......@@ -419,12 +422,37 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
}
static int
imap_unseen_count (mailbox_t mailbox, size_t *pnum)
imap_message_unseen (mailbox_t mailbox, size_t *punseen)
{
m_imap_t m_imap = mailbox->data;
*pnum = m_imap->unseen;
*punseen = m_imap->unseen;
return 0;
}
static int
imap_messages_recent (mailbox_t mailbox, size_t *precent)
{
m_imap_t m_imap = mailbox->data;
*precent = m_imap->recent;
return 0;
}
static int
imap_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity)
{
m_imap_t m_imap = mailbox->data;
*puidvalidity = m_imap->uidvalidity;
return 0;
}
static int
imap_uidnext (mailbox_t mailbox, size_t *puidnext)
{
m_imap_t m_imap = mailbox->data;
*puidnext = m_imap->uidnext;
return 0;
}
/* There is no explicit call to get the message count. The count is send on
a SELECT/EXAMINE command it is also sent async, meaning it will be piggy
back on other server response as an untag "EXIST" response. But we still
......@@ -687,12 +715,37 @@ imap_message_size (message_t msg, size_t *psize)
}
static int
imap_message_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
imap_message_uid (message_t msg, size_t *puid)
{
(void)msg; (void)buffer; (void)buflen;
if (pnwriten)
*pnwriten = 0;
return ENOSYS;
msg_imap_t msg_imap = message_get_owner (msg);
m_imap_t m_imap = msg_imap->m_imap;
f_imap_t f_imap = m_imap->f_imap;
int status;
if (puid)
return 0;
/* Select first. */
if (f_imap->state == IMAP_NO_STATE)
{
if (msg_imap->uid)
{
*puid = msg_imap->uid;
return 0;
}
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
status = imap_writeline (f_imap, "g%d FETCH %d UID\r\n",
f_imap->seq++, msg_imap->num);
CHECK_ERROR (f_imap, status);
MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
f_imap->state = IMAP_FETCH;
}
status = message_operation (f_imap, msg_imap, 0, 0, 0, 0);
if (status != 0)
return status;
*puid = msg_imap->uid;
return 0;
}
static int
......@@ -1057,16 +1110,6 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
plen);
}
static int
imap_header_fd (stream_t stream, int *pfd)
{
header_t header = stream_get_owner (stream);
message_t msg = header_get_owner (header);
msg_imap_t msg_imap = message_get_owner (msg);
return imap_get_fd (msg_imap, pfd);
}
/* Body. */
static int
imap_body_size (body_t body, size_t *psize)
......
......@@ -58,7 +58,8 @@ struct _mbox_data;
typedef struct _mbox_data* mbox_data_t;
typedef struct _mbox_message* mbox_message_t;
#define HDRSIZE 8
/* These represent the header field-name that we are caching for speed. */
#define HDRSIZE 9
const char *fhdr_table[] =
{
#define HFROM 0
......@@ -71,38 +72,36 @@ const char *fhdr_table[] =
"Subject",
#define HDATE 4
"Date",
#define HX_UIDL 5
#define HX_IMAPBASE 5
"X-IMAPbase",
#define HX_UIDL 6
"X-UIDL",
#define HX_UID 6
#define HX_UID 7
"X-UID",
#define HCONTENT_TYPE 7
#define HCONTENT_TYPE 8
"Content-Type",
};
/* Keep the position of where the header and body starts and ends.
old_flags is the "Status:" message. */
/* Keep the positions of where the headers and bodies start and end.
attr_flags is the "Status:" message. */
struct _mbox_message
{
/* 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. */
off_t header_status;
off_t header_status_end;
off_t body;
off_t body_end;
/* Fast header retrieve, we save here the most common header. Reasons this
will speed the header search. The header are copied on write or if we
the fast status failed. */
/* Fast header retrieve, we save here the most common header. This will
speed the header search. The header are copied when modified by the
header_t object, we should not worry about updating them. */
char *fhdr[HDRSIZE];
/* 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;
/* IMAP uid. */
size_t uid;
/* The attr_flags contains the "Status:" attribute */
int attr_flags;
size_t header_lines;
size_t body_lines;
......@@ -125,6 +124,8 @@ struct _mbox_data
size_t messages_count; /* How many valid entry in umessages[]. */
stream_t stream;
off_t size;
unsigned long uidvalidity;
size_t uidnext;
char *name;
/* The variables below are use to hold the state when appending messages. */
......@@ -132,7 +133,7 @@ struct _mbox_data
{
MBOX_NO_STATE = 0,
MBOX_STATE_APPEND_SENDER, MBOX_STATE_APPEND_DATE, MBOX_STATE_APPEND_HEADER,
MBOX_STATE_APPEND_ATTRIBUTE, MBOX_STATE_APPEND_BODY,
MBOX_STATE_APPEND_ATTRIBUTE, MBOX_STATE_APPEND_UID, MBOX_STATE_APPEND_BODY,
MBOX_STATE_APPEND_MESSAGE
} state ;
char *sender;
......@@ -147,8 +148,11 @@ static int mbox_close __P ((mailbox_t));
static int mbox_get_message __P ((mailbox_t, size_t, message_t *));
static int mbox_append_message __P ((mailbox_t, message_t));
static int mbox_messages_count __P ((mailbox_t, size_t *));
static int mbox_unseen_count __P ((mailbox_t, size_t *));
static int mbox_messages_recent __P ((mailbox_t, size_t *));
static int mbox_message_unseen __P ((mailbox_t, size_t *));
static int mbox_expunge __P ((mailbox_t));
static int mbox_uidvalidity __P ((mailbox_t, unsigned long *));
static int mbox_uidnext __P ((mailbox_t, size_t *));
static int mbox_scan __P ((mailbox_t, size_t, size_t *));
static int mbox_is_updated __P ((mailbox_t));
static int mbox_size __P ((mailbox_t, off_t *));
......@@ -156,7 +160,8 @@ static int mbox_size __P ((mailbox_t, off_t *));
/* private stuff */
static int mbox_scan0 __P ((mailbox_t, size_t, size_t *, int));
static int mbox_append_message0 __P ((mailbox_t, message_t, off_t *,
int));
int, int));
static int mbox_message_uid __P ((message_t, size_t *));
static int mbox_header_fill __P ((header_t, char *, size_t, off_t,
size_t *));
static int mbox_get_header_readstream __P ((message_t, char *, size_t, off_t,
......@@ -212,7 +217,7 @@ _mailbox_mbox_init (mailbox_t mailbox)
for example if we receive: "mbox:///var/mail/alain" the mailbox name
will be "///var/mail/alain", we let open() do the right thing.
So it will let things like this "mbox://390/var/mail/alain" where
"//390/var/mail/alain" _is_ the filename, pass correctely. */
the "//" _is_ part of the filename, pass correctely. */
url_get_path (mailbox->url, NULL, 0, &name_len);
mud->name = calloc (name_len + 1, sizeof (char));
if (mud->name == NULL)
......@@ -225,7 +230,7 @@ _mailbox_mbox_init (mailbox_t mailbox)
mud->state = MBOX_NO_STATE;
/* Overloading the default. */
/* Overloading the defaults. */
mailbox->_destroy = mbox_destroy;
mailbox->_open = mbox_open;
......@@ -235,8 +240,11 @@ _mailbox_mbox_init (mailbox_t mailbox)
mailbox->_get_message = mbox_get_message;
mailbox->_append_message = mbox_append_message;
mailbox->_messages_count = mbox_messages_count;
mailbox->_unseen_count = mbox_unseen_count;
mailbox->_messages_recent = mbox_messages_recent;
mailbox->_message_unseen = mbox_message_unseen;
mailbox->_expunge = mbox_expunge;
mailbox->_uidvalidity = mbox_uidvalidity;
mailbox->_uidnext = mbox_uidnext;
mailbox->_scan = mbox_scan;
mailbox->_is_updated = mbox_is_updated;
......@@ -281,7 +289,8 @@ mbox_destroy (mailbox_t mailbox)
}
}
/* Open the file. */
/* Open the file. For MU_STREAM_READ, the code tries mmap() first and fall
back to normal file. */
static int
mbox_open (mailbox_t mailbox, int flags)
{
......@@ -296,8 +305,6 @@ mbox_open (mailbox_t mailbox, int flags)
/* Get a stream. */
if (mailbox->stream == NULL)
{
/* FIXME: for small mbox we should try to mmap (). */
/* We do not try to mmap for CREAT or APPEND, it is not supported. */
status = (flags & MU_STREAM_CREAT)
|| (mailbox->flags & MU_STREAM_APPEND);
......@@ -393,7 +400,7 @@ mbox_close (mailbox_t mailbox)
return stream_close (mailbox->stream);
}
/* Mailbox Parsing. */
/* Mailbox Parsing. Routing was way to ugly to put here. */
#include "mbx_mboxscan.c"
static int
......@@ -404,7 +411,6 @@ mbox_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
return mbox_scan0 (mailbox, msgno, pcount, 1);
}
/* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
browsers and deleted emails in one. My views is that we should scream
bloody murder and hunt them with a machette. But for now just play dumb,
......@@ -420,7 +426,9 @@ mbox_is_updated (mailbox_t mailbox)
{
observable_notify (mailbox->observable, MU_EVT_MAILBOX_CORRUPT);
/* And be verbose. */
fprintf (stderr, "Mailbox corrupted, shrink size\n");
fprintf (stderr, "Mailbox corrupted, shrank size\n");
/* FIXME: I should crash. */
return 1;
}
return (mud->size == size);
}
......@@ -473,8 +481,8 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox)
/* For the expunge bits we took a very cautionnary approach, meaning
we create a temporary mailbox in the tmpdir copy all the message not mark
deleted(Actually we copy all the message that may have been modified, we
do not have(yet) an api call to tell whether a message was modified)
deleted(Actually we copy all the message that may have been modified
i.e new header values set; UIDL or UID or etc ....
and skip the deleted ones, truncate the real mailbox to the desired size
and overwrite with the tmp mailbox. The approach to do everyting
in core is tempting but require
......@@ -485,7 +493,7 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox)
a new message while your expunging etc ...
The real downside to the approach we take is that when things go wrong
the temporary file may be left in /tmp, which is not all that bad
because at least, we have something to recuparate when failure. */
because at least, we have something to recuperate when failure. */
static int
mbox_expunge (mailbox_t mailbox)
{
......@@ -494,11 +502,12 @@ mbox_expunge (mailbox_t mailbox)
int status = 0;
sigset_t signalset;
int tempfile;
size_t i, j, dirty;
off_t marker = 0;
size_t i, j, dirty; /* dirty will indicate the first modified message. */
off_t marker = 0; /* marker will be the position to truncate. */
off_t total = 0;
char *tmpmboxname = NULL;
mailbox_t tmpmailbox = NULL;
size_t save_imapbase = 0; /* uidvalidity is save in the first message. */
#ifdef WITH_PTHREAD
int state;
#endif
......@@ -512,83 +521,78 @@ mbox_expunge (mailbox_t mailbox)
if (mud->messages_count == 0)
return 0;
/* Mark dirty the first mum(concrete message) with a message pointer. */
/* FIXME: This is not right, the way to really know if a message is modified
is by changing the API, we should have an message_is_modified (). */
/* Find the first dirty(modified) message. */
for (dirty = 0; dirty < mud->messages_count; dirty++)
{
mum = mud->umessages[dirty];
#if 0
/* No, cheking if the attribute was changed is not enough, for example
They may have modified a header, say adding the X-UIDL field. Those
changes are not save yet but still in memory part of the header blurb.
So unless we have a message_is_modified() call we should assume that
the message was modified. */
if (mum->new_flags &&
! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags))
break;
#else
/* Message may have been tampered, break here. */
if (mum->message && message_is_modified (mum->message))
if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED) ||
(mum->message && message_is_modified (mum->message)))
break;
#endif
}
/* Did something change ? */
if (dirty == mud->messages_count)
return 0; /* Nothing change, bail out. */
/* Create a temporary file. */
tempfile = mbox_tmpfile (mailbox, &tmpmboxname);
if (tempfile == -1)
{
if (tmpmboxname)
free (tmpmboxname);
fprintf (stderr, "Failed to create temporary file when expunging.\n");
return errno;
}
/* 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. Destroy all the
messages mark for deletion. */
for (j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
if (mum && mum->message && mum->new_flags &&
ATTRIBUTE_IS_DELETED (mum->new_flags))
if (mum && mum->message && ATTRIBUTE_IS_DELETED (mum->attr_flags))
message_destroy (&(mum->message), mum);
}
/* Create a temporary file. */
tempfile = mbox_tmpfile (mailbox, &tmpmboxname);
if (tempfile == -1)
{
free (tmpmboxname);
fprintf (stderr, "Failed to create temporary file when expunging.\n");
return errno;
}
else
{
char *m = alloca (5 + strlen (tmpmboxname) + 1);
/* Try via the mbox: protocol. */
sprintf (m, "mbox:%s", tmpmboxname);
status = mailbox_create (&tmpmailbox, m);
if (status != 0)
{
/* Do not give up just yet, maybe they register the path_record. */
sprintf (m, "%s", tmpmboxname);
status = mailbox_create (&tmpmailbox, m);
if (status != 0)
{
/* Ok give up. */
close (tempfile);
remove (tmpmboxname);
free (tmpmboxname);
return status;
}
}
/* Create temporary mailbox_t. */
{
mbox_data_t tmp_mud;
char *m = alloca (5 + strlen (tmpmboxname) + 1);
/* Try via the mbox: protocol. */
sprintf (m, "mbox:%s", tmpmboxname);
status = mailbox_create (&tmpmailbox, m);
if (status != 0)
{
/* Do not give up just yet, maybe they register the path_record. */
sprintf (m, "%s", tmpmboxname);
status = mailbox_create (&tmpmailbox, m);
if (status != 0)
{
/* Ok give up. */
close (tempfile);
remove (tmpmboxname);
free (tmpmboxname);
return status;
}
}
/* Must be flag create if not the open will try to mmap() the file. */
status = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR);
if (status != 0)
{
close (tempfile);
remove (tmpmboxname);
free (tmpmboxname);
return status;
}
close (tempfile); /* This one is useless the mailbox have its own. */
}
/* Must be flag CREATE if not the mailbox_open will try to mmap()
the file. */
status = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR);
if (status != 0)
{
close (tempfile);
remove (tmpmboxname);
free (tmpmboxname);
return status;
}
close (tempfile); /* This one is useless the mailbox have its own. */
tmp_mud = tmpmailbox->data;
/* May need when appending. */
tmp_mud->uidvalidity = mud->uidvalidity;
tmp_mud->uidnext = mud->uidnext;
}
/* Get the File lock. */
if (locker_lock (mailbox->locker, MU_LOCKER_WRLOCK) < 0)
......@@ -617,18 +621,26 @@ mbox_expunge (mailbox_t mailbox)
marker = mud->umessages[dirty]->header_from;
total = 0;
/* Copy to tempfile emails not mark deleted. */
/* Copy to the temporary mailbox emails not mark deleted. */
for (i = dirty; i < mud->messages_count; i++)
{
mum = mud->umessages[i];
/* Skip it, if mark for deletion. */
if (ATTRIBUTE_IS_DELETED (mum->new_flags))
continue;
if (ATTRIBUTE_IS_DELETED (mum->attr_flags))
{
/* We save the uidvalidity in the first message, if it is being
deleted we need to the header to the first available(non-deleted)
message. */
if (i == 0)
save_imapbase = i + 1;
continue;
}
if (mum->message)
{
status = mbox_append_message0 (tmpmailbox, mum->message, &total, 1);
status = mbox_append_message0 (tmpmailbox, mum->message,
&total, 1, (i == save_imapbase));
if (status != 0)
{
fprintf (stderr, "Error expunge:%d: %s", __LINE__,
......@@ -672,9 +684,8 @@ mbox_expunge (mailbox_t mailbox)
} /* for (;;) */
/* Caution: before ftruncate()ing the file see
- if we've receive new mails.
Some programs may not respect the lock, or the lock was held for too
long.
- if we've receive new mails. Some programs may not respect the lock,
or the lock was held for too long.
- The mailbox may not have been properly updated before expunging. */
{
off_t size = 0;
......@@ -740,7 +751,8 @@ mbox_expunge (mailbox_t mailbox)
status = stream_truncate (mailbox->stream, total + marker);
if (status != 0)
{
fprintf (stderr, "Error expunging:%d: %s\n", __LINE__, strerror (status));
fprintf (stderr, "Error expunging:%d: %s\n", __LINE__,
strerror (status));
goto bailout;
}
......@@ -771,7 +783,7 @@ mbox_expunge (mailbox_t mailbox)
/* Clear all the references, any attach messages been already
destroy above. */
mum = mud->umessages[j];
if (mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
if (ATTRIBUTE_IS_DELETED (mum->attr_flags))
{
if ((j + 1) <= dlast)
{
......@@ -780,13 +792,13 @@ mbox_expunge (mailbox_t mailbox)
memmove (mud->umessages + j, mud->umessages + j + 1,
(dlast - j) * sizeof (mum));
//mum->header_from = mum->header_from_end = 0;
//mum->header_status = mum->header_status_end = 0;
//mum->body = mum->body_end = 0;
//mum->header_lines = mum->body_lines = 0;
for (i = 0; i < HDRSIZE; i++)
if (mum->fhdr[i])
{
free (mum->fhdr[i]);
mum->fhdr[i] = NULL;
}
memset (mum, 0, sizeof (*mum));
/* We are not free()ing the useless mum, but instead
......@@ -803,7 +815,6 @@ mbox_expunge (mailbox_t mailbox)
}
}
mum->header_from = mum->header_from_end = 0;
mum->header_status = mum->header_status_end = 0;
mum->body = mum->body_end = 0;
mum->header_lines = mum->body_lines = 0;
}
......@@ -816,6 +827,15 @@ mbox_expunge (mailbox_t mailbox)
}
static int
mbox_message_uid (message_t msg, size_t *puid)
{
mbox_message_t mum = message_get_owner (msg);
if (puid)
*puid = mum->uid;
return 0;
}
static int
mbox_get_body_fd (stream_t is, int *pfd)
{
body_t body = stream_get_owner (is);
......@@ -843,7 +863,7 @@ mbox_get_attr_flags (attribute_t attr, int *pflags)
if (mum == NULL)
return EINVAL;
if (pflags)
*pflags = mum->new_flags;
*pflags = mum->attr_flags;
return 0;
}
......@@ -855,7 +875,7 @@ mbox_set_attr_flags (attribute_t attr, int flags)
if (mum == NULL)
return EINVAL;
mum->new_flags |= flags;
mum->attr_flags |= flags;
return 0;
}
......@@ -867,7 +887,7 @@ mbox_unset_attr_flags (attribute_t attr, int flags)
if (mum == NULL)
return EINVAL;
mum->new_flags &= ~flags;
mum->attr_flags &= ~flags;
return 0;
}
......@@ -920,8 +940,8 @@ mbox_body_readstream (stream_t is, char *buffer, size_t buflen,
{
status = stream_readline (mum->stream, buffer, buflen,
mum->body + off, &nread);
/* This mean we went pass the message boundary, thechnically it
should not be sine we are reading by line, but just in case
/* This mean we went pass the message boundary, technically it
should not be since we are reading by line, but just in case
truncate the string. */
if (nread > (size_t)ln)
{
......@@ -952,6 +972,18 @@ mbox_header_fill (header_t header, char *buffer, size_t len,
off_t off, size_t *pnread)
{
message_t msg = header_get_owner (header);
mbox_message_t mum = message_get_owner (msg);
size_t j;
/* Since we are filling the header there is no need for the cache headers
discard them. */
for (j = 0; j < HDRSIZE; j++)
{
if (mum->fhdr[j])
{
free (mum->fhdr[j]);
mum->fhdr[j] = NULL;
}
}
return mbox_get_header_readstream (msg, buffer, len, off, pnread, 0);
}
......@@ -964,19 +996,26 @@ mbox_header_get_fvalue (header_t header, const char *name, char *buffer,
mbox_message_t mum = message_get_owner (msg);
int err = ENOENT;
for (i = 0; i < HDRSIZE; i++)
if (*name == *(fhdr_table[i]) && strcasecmp (fhdr_table[i], name) == 0)
{
fv_value = (mum->fhdr[i]) ? strlen (mum->fhdr[i]) : 0;
if (buffer && buflen > 0)
{
buflen--;
fv_value = (fv_value < buflen) ? fv_value : buflen;
memcpy (buffer, mum->fhdr[i], fv_value);
buffer[fv_value] = '\0';
}
err = 0;
break;
}
{
if (*name == *(fhdr_table[i]) && strcasecmp (fhdr_table[i], name) == 0)
{
if (mum->fhdr[i])
{
fv_value = strlen (mum->fhdr[i]);
if (buffer && buflen > 0)
{
buflen--;
fv_value = (fv_value < buflen) ? fv_value : buflen;
memcpy (buffer, mum->fhdr[i], fv_value);
buffer[fv_value] = '\0';
}
err = 0;
}
else
err = ENOENT;
break;
}
}
if (pnread)
*pnread = fv_value;
......@@ -1228,7 +1267,6 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
message_destroy (&msg, mum);
return status;
}
mum->new_flags = mum->old_flags;
attribute_set_get_flags (attribute, mbox_get_attr_flags, msg);
attribute_set_set_flags (attribute, mbox_set_attr_flags, msg);
attribute_set_unset_flags (attribute, mbox_unset_attr_flags, msg);
......@@ -1270,6 +1308,9 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
message_set_envelope (msg, envelope, mum);
}
/* Set the UID. */
message_set_uid (msg, mbox_message_uid, mum);
/* Attach the message to the mailbox mbox data. */
mum->message = msg;
message_set_mailbox (msg, mailbox);
......@@ -1299,7 +1340,7 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
int status;
/* Move to the end of the file, not necesary if _APPEND mode. */
if ((status = stream_size (mailbox->stream, &size)) != 0
|| (status = mbox_append_message0 (mailbox, msg, &size, 0)) != 0)
|| (status = mbox_append_message0 (mailbox, msg, &size, 0, 0)) != 0)
{
if (status != EAGAIN)
locker_unlock (mailbox->locker);
......@@ -1311,9 +1352,13 @@ mbox_append_message (mailbox_t mailbox, message_t msg)
return 0;
}
/* FIXME: We need to escape line body line that begins with "From ", this
will required to read the body by line instead of by chuncks hearting
perfomance big time when expunging. But should not this be the
responsability of the client ? */
static int
mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
int is_expunging)
int is_expunging, int first)
{
mbox_data_t mud = mailbox->data;
int status = 0;
......@@ -1370,6 +1415,7 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
char *s;
size_t len = 0;
envelope_t envelope;
char buffer[1024];
message_get_envelope (msg, &envelope);
status = envelope_date (envelope, mud->date, 128, &len);
if (status != 0)
......@@ -1390,41 +1436,21 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
*s = '\0';
/* Write the separator to the mailbox. */
status = stream_write (mailbox->stream, "From ", 5, *psize, &n);
if (status != 0)
break;
*psize += n;
/* Write sender. */
status = stream_write (mailbox->stream, mud->sender,
strlen (mud->sender), *psize, &n);
if (status != 0)
break;
*psize += n;
status = stream_write (mailbox->stream, " ", 1, *psize, &n);
if (status != 0)
break;
*psize += n;
/* Write date. */
status = stream_write (mailbox->stream, mud->date, strlen(mud->date),
*psize, &n);
if (status != 0)
break;
n = snprintf (buffer, sizeof (buffer), "From %s %s",
mud->sender, mud->date);
stream_write (mailbox->stream, buffer, n, *psize, &n);
*psize += n;
status = stream_write (mailbox->stream, &nl , 1, *psize, &n);
if (status != 0)
break;
/* Add the newline, the above may be truncated. */
stream_write (mailbox->stream, &nl , 1, *psize, &n);
*psize += n;
free (mud->sender);
free (mud->date);
mud->sender = mud->date = NULL;
/* If we are not expunging get the message in one block via the stream
message instead of the header/body. This is good for example for
POP where there is no separtation between header and body. */
message instead of the header/body. This is good for POP where
there is no separation between header and body(RETR). */
if (! is_expunging)
{
mud->state = MBOX_STATE_APPEND_MESSAGE;
......@@ -1460,12 +1486,15 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
break;
/* We do not copy the Status since it is rewritten by the
attribute code below. */
/* FIXME: - We have a problem here the header field may not fit
the buffer.
- Should we skip the IMAP "X-Status"?
strncasecmp (buffer, "X-Status", 8) == 0) */
if (strncasecmp (buffer, "Status", 6) == 0)
attribute code below. Ditto for X-UID and X-IMAPBase.
FIXME:
- We have a problem here the header may not fit the buffer.
- Should we skip the IMAP "X-Status"? */
if ((strncasecmp (buffer, "Status", 6) == 0)
|| (strncasecmp (buffer, "X-IMAPbase", 10) == 0)
|| (strncasecmp (buffer, "X-UID", 4) == 0
&& (buffer[5] == ':' || buffer[5] == ' '
|| buffer[5] == '\t')))
continue;
status = stream_write (mailbox->stream, buffer, nread,
......@@ -1476,6 +1505,15 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
}
while (nread > 0);
mud->off = 0;
/* Rewrite the X-IMAPbase marker. */
if (first && is_expunging)
{
n = sprintf (buffer, "X-IMAPbase: %lu %u\n",
mud->uidvalidity, mud->uidnext);
stream_write (mailbox->stream, buffer, n, *psize, &n);
*psize += n;
}
mud->state = MBOX_STATE_APPEND_ATTRIBUTE;
}
......@@ -1494,6 +1532,34 @@ mbox_append_message0 (mailbox_t mailbox, message_t msg, off_t *psize,
break;
*psize += n;
mud->state = MBOX_STATE_APPEND_UID;
}
case MBOX_STATE_APPEND_UID:
/* The new X-UID. */
{
char suid[64];
size_t uid = 0;
if (is_expunging)
{
status = message_get_uid (msg, &uid);
if (status == EAGAIN)
return status;
}
else
uid = mud->uidnext++;
if (status == 0 || uid != 0)
{
n = sprintf (suid, "X-UID: %d\n", uid);
/* Put the UID. */
status = stream_write (mailbox->stream, suid, n, *psize, &n);
if (status != 0)
break;
*psize += n;
}
/* New line separator of the Header. */
status = stream_write (mailbox->stream, &nl , 1, *psize, &n);
if (status != 0)
break;
......@@ -1608,7 +1674,7 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount)
return EINVAL;
if (! mbox_is_updated (mailbox))
return mbox_scan0 (mailbox, 1, pcount, 1);
return mbox_scan0 (mailbox, mud->messages_count, pcount, 1);
if (pcount)
*pcount = mud->messages_count;
......@@ -1617,21 +1683,67 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount)
}
static int
mbox_unseen_count (mailbox_t mailbox, size_t *pcount)
mbox_messages_recent (mailbox_t mailbox, size_t *pcount)
{
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
size_t j, total;
size_t j, recent;
if (pcount)
return EINVAL;
for (total = j = 0; j < mud->messages_count; j++)
for (recent = j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
if (mum && ((mum->attr_flags == 0) ||
! ((mum->attr_flags & MU_ATTRIBUTE_SEEN)
&& (mum->attr_flags & MU_ATTRIBUTE_READ))))
recent++;
}
*pcount = recent;
return 0;
}
static int
mbox_message_unseen (mailbox_t mailbox, size_t *pmsgno)
{
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
size_t j, unseen;
for (unseen = j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
if (mum && mum->new_flags == 0)
total++;
if (mum && ((mum->attr_flags == 0) ||
! ((mum->attr_flags & MU_ATTRIBUTE_SEEN)
&& (mum->attr_flags & MU_ATTRIBUTE_READ))))
{
unseen = j + 1;
break;
}
}
*pcount = total;
*pmsgno = unseen;
return 0;
}
static int
mbox_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity)
{
mbox_data_t mud = mailbox->data;
int status = mbox_messages_count (mailbox, NULL);
if (status != 0)
return status;
if (puidvalidity)
*puidvalidity = mud->uidvalidity;
return 0;
}
static int
mbox_uidnext (mailbox_t mailbox, size_t *puidnext)
{
mbox_data_t mud = mailbox->data;
int status = mbox_messages_count (mailbox, NULL);
if (status != 0)
return status;
if (puidnext)
*puidnext = mud->uidnext;
return 0;
}
......
......@@ -156,7 +156,7 @@ do \
{ \
if (*s == c0 || *s == c1) \
{ \
(mum)->old_flags |= (type); \
(mum)->attr_flags |= (type); \
break; \
} \
} \
......@@ -220,6 +220,19 @@ do \
&& (buf[1] == 'O' || buf[1] == 'o') \
&& (buf[2] == ':' || buf[2] == ' ' || buf[2] == '\t'))
#define ISX_IMAPBASE(buf) (\
(buf[0] == 'X' || buf[0] == 'x') \
&& (buf[1] == '-') \
&& (buf[2] == 'I' || buf[2] == 'i') \
&& (buf[3] == 'M' || buf[3] == 'm') \
&& (buf[4] == 'A' || buf[4] == 'a') \
&& (buf[5] == 'P' || buf[5] == 'p') \
&& (buf[6] == 'B' || buf[6] == 'b') \
&& (buf[7] == 'A' || buf[7] == 'a') \
&& (buf[8] == 'S' || buf[8] == 's') \
&& (buf[9] == 'E' || buf[9] == 'e') \
&& (buf[10] == ':' || buf[10] == ' ' || buf[10] == '\t'))
#define ISX_UIDL(buf) (\
(buf[0] == 'X' || buf[0] == 'x') \
&& (buf[1] == '-') \
......@@ -268,8 +281,6 @@ do { \
} \
} while (0)
//fprintf (stderr, "%d %d <%s> <%s>\n", i, l, (i)?field:"", p);
#define FAST_HCONTENT_TYPE(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HCONTENT_TYPE],buf,n); \
sf = &(mum->fhdr[HCONTENT_TYPE])
......@@ -294,6 +305,10 @@ sf = &(mum->fhdr[HSUBJECT])
FAST_HEADER(mum->fhdr[HTO],buf,n); \
sf = &(mum->fhdr[HTO])
#define FAST_HX_IMAPBASE(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HX_IMAPBASE],buf,n); \
sf = &(mum->fhdr[HX_UID])
#define FAST_HX_UIDL(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HX_UIDL],buf,n); \
sf = &(mum->fhdr[HX_UIDL])
......@@ -483,45 +498,47 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
mum->fhdr[j] = NULL;
}
}
else if (/*(n > 7) && */ ISSTATUS(buf))
else if (ISSTATUS(buf))
{
mum->header_status = total - n;
mum->header_status_end = total;
ATTRIBUTE_SET(buf, mum, 'r', 'R', MU_ATTRIBUTE_READ);
ATTRIBUTE_SET(buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN);
ATTRIBUTE_SET(buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED);
ATTRIBUTE_SET(buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED);
sfield = NULL;
}
else if (/*(n > 12) && */ ISCONTENT_TYPE(buf))
else if (ISCONTENT_TYPE(buf))
{
FAST_HCONTENT_TYPE(mum, sfield, buf, n);
}
else if (/*(n > 3) && */ ISCC(buf))
else if (ISCC(buf))
{
FAST_HCC(mum, sfield, buf, n);
}
else if (/*(n > 5) && */ ISDATE(buf))
else if (ISDATE(buf))
{
FAST_HDATE(mum, sfield, buf, n);
}
else if (/*(n > 5) && */ ISFROM(buf))
else if (ISFROM(buf))
{
FAST_HFROM(mum, sfield, buf, n);
}
else if (/*(n > 8) && */ ISSUBJECT(buf))
else if (ISSUBJECT(buf))
{
FAST_HSUBJECT (mum, sfield, buf, n);
}
else if (/*(n > 3) && */ ISTO(buf))
else if (ISTO(buf))
{
FAST_HTO (mum, sfield, buf, n);
}
else if (/*(n > 7) && */ ISX_UIDL(buf))
else if (ISX_IMAPBASE(buf))
{
FAST_HX_IMAPBASE (mum, sfield, buf, n);
}
else if (ISX_UIDL(buf))
{
FAST_HX_UIDL (mum, sfield, buf, n);
}
else if (/*(n > 6) && */ ISX_UID(buf))
else if (ISX_UID(buf))
{
FAST_HX_UID (mum, sfield, buf, n);
}
......@@ -551,11 +568,11 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
newline = nl;
/* Every 50 mesgs update the lock, it should be every minute. */
if ((mud->messages_count % 50) == 0)
/* Every 100 mesgs update the lock, it should be every minute. */
if ((mud->messages_count % 100) == 0)
locker_touchlock (mailbox->locker);
/* Ping them every 1000 lines. */
/* Ping them every 1000 lines. Should be tunable. */
if (do_notif)
if (((lines +1) % 1000) == 0)
DISPATCH_PROGRESS(mailbox, mud);
......@@ -574,6 +591,72 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
locker_unlock (mailbox->locker);
monitor_unlock (mailbox->monitor);
/* Reset the uidvalidity. */
if (mud->messages_count > 0)
{
mum = mud->umessages[0];
if (mum->fhdr[HX_IMAPBASE])
{
char *s = mum->fhdr[HX_IMAPBASE];
while (*s && !isdigit (*s)) s++;
mud->uidvalidity = strtoul (s, &s, 10);
mud->uidnext = strtoul (s, NULL, 10);
}
if (mud->uidvalidity == 0)
{
char u[64];
mud->uidvalidity = (unsigned long)time (NULL);
mud->uidnext = mud->messages_count + 1;
if (mum->fhdr[HX_IMAPBASE])
free (mum->fhdr[HX_IMAPBASE]);
sprintf (u, "%lu %u", mud->uidvalidity, mud->uidnext);
mum->fhdr[HX_IMAPBASE] = strdup (u);
/* Tell that we have been modified for expunging. */
mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
}
}
/* Reset the IMAP uids, if necessary. */
{
size_t uid;
size_t ouid;
size_t i;
for (uid = ouid = i = 0; i < mud->messages_count; i++)
{
char *s;
mum = mud->umessages[i];
s = mum->fhdr[HX_UID];
if (s)
{
while (*s && !isdigit (*s)) s++;
uid = strtoul (s, &s, 10);
}
else
uid = 0;
if (uid <= ouid)
{
char u[64];
uid = ouid + 1;
sprintf (u, "%d", uid);
if (mum->fhdr[HX_UID])
free (mum->fhdr[HX_UID]);
mum->fhdr[HX_UID] = strdup (u);
/* Note that we have modified for expunging. */
mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
}
mum->uid = ouid = uid;
}
if (uid > mud->messages_count)
{
char u[64];
mud->uidnext = uid + 1;
mum = mud->umessages[0];
if (mum->fhdr[HX_IMAPBASE])
free (mum->fhdr[HX_IMAPBASE]);
sprintf (u, "%lu %u", mud->uidvalidity, uid + 1);
mum->fhdr[HX_IMAPBASE] = strdup (u);
mum->attr_flags |= MU_ATTRIBUTE_MODIFIED;
}
}
#ifdef WITH_PTHREAD
pthread_cleanup_pop (0);
#endif
......
......@@ -70,39 +70,42 @@ enum pop_state
POP_AUTH_PASS, POP_AUTH_PASS_ACK
};
static void pop_destroy __P ((mailbox_t));
static void pop_destroy __P ((mailbox_t));
/* Functions/Methods that implements the mailbox_t API. */
static int pop_open __P ((mailbox_t, int));
static int pop_close __P ((mailbox_t));
static int pop_get_message __P ((mailbox_t, size_t, message_t *));
static int pop_messages_count __P ((mailbox_t, size_t *));
static int pop_expunge __P ((mailbox_t));
static int pop_scan __P ((mailbox_t, size_t, size_t *));
static int pop_is_updated __P ((mailbox_t));
static int pop_open __P ((mailbox_t, int));
static int pop_close __P ((mailbox_t));
static int pop_get_message __P ((mailbox_t, size_t, message_t *));
static int pop_messages_count __P ((mailbox_t, size_t *));
static int pop_messages_recent __P ((mailbox_t, size_t *));
static int pop_message_unseen __P ((mailbox_t, size_t *));
static int pop_expunge __P ((mailbox_t));
static int pop_scan __P ((mailbox_t, size_t, size_t *));
static int pop_is_updated __P ((mailbox_t));
/* The implementation of message_t */
static int pop_user __P ((authority_t));
static int pop_size __P ((mailbox_t, off_t *));
static int pop_user __P ((authority_t));
static int pop_size __P ((mailbox_t, off_t *));
/* We use pop_top for retreiving headers. */
/* static int pop_header_read (header_t, char *, size_t, off_t, size_t *); */
static int pop_body_fd __P ((stream_t, int *));
static int pop_body_size __P ((body_t, size_t *));
static int pop_body_lines __P ((body_t, size_t *));
static int pop_body_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int pop_message_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int pop_message_size __P ((message_t, size_t *));
static int pop_message_fd __P ((stream_t, int *));
static int pop_top __P ((header_t, char *, size_t, off_t, size_t *));
static int pop_retr __P ((pop_message_t, char *, size_t, off_t, size_t *));
static int pop_get_fd __P ((pop_message_t, int *));
static int pop_attr_flags __P ((attribute_t, int *));
static int pop_uid __P ((message_t, char *, size_t, size_t *));
static int fill_buffer __P ((pop_data_t, char *, size_t));
static int pop_readline __P ((pop_data_t));
static int pop_read_ack __P ((pop_data_t));
static int pop_writeline __P ((pop_data_t, const char *, ...));
static int pop_write __P ((pop_data_t));
static int pop_body_fd __P ((stream_t, int *));
static int pop_body_size __P ((body_t, size_t *));
static int pop_body_lines __P ((body_t, size_t *));
static int pop_body_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int pop_message_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int pop_message_size __P ((message_t, size_t *));
static int pop_message_fd __P ((stream_t, int *));
static int pop_top __P ((header_t, char *, size_t, off_t, size_t *));
static int pop_retr __P ((pop_message_t, char *, size_t, off_t, size_t *));
static int pop_get_fd __P ((pop_message_t, int *));
static int pop_attr_flags __P ((attribute_t, int *));
static int pop_uidl __P ((message_t, char *, size_t, size_t *));
static int pop_uid __P ((message_t, size_t *));
static int fill_buffer __P ((pop_data_t, char *, size_t));
static int pop_readline __P ((pop_data_t));
static int pop_read_ack __P ((pop_data_t));
static int pop_writeline __P ((pop_data_t, const char *, ...));
static int pop_write __P ((pop_data_t));
/* This structure holds the info for a message. The pop_message_t
type, will serve as the owner of the message_t and contains the command to
......@@ -122,7 +125,7 @@ struct _pop_message
size_t header_lines;
size_t message_size;
size_t num;
char *uid; /* Cache the uid string. */
char *uidl; /* Cache the uidl string. */
message_t message;
pop_data_t mpd; /* Back pointer. */
};
......@@ -280,6 +283,8 @@ _mailbox_pop_init (mailbox_t mbox)
/* Messages. */
mbox->_get_message = pop_get_message;
mbox->_messages_count = pop_messages_count;
mbox->_messages_recent = pop_messages_recent;
mbox->_message_unseen = pop_message_unseen;
mbox->_expunge = pop_expunge;
mbox->_scan = pop_scan;
......@@ -306,8 +311,8 @@ pop_destroy (mailbox_t mbox)
{
message_destroy (&(mpd->pmessages[i]->message),
mpd->pmessages[i]);
if (mpd->pmessages[i]->uid)
free (mpd->pmessages[i]->uid);
if (mpd->pmessages[i]->uidl)
free (mpd->pmessages[i]->uidl);
free (mpd->pmessages[i]);
mpd->pmessages[i] = NULL;
}
......@@ -624,8 +629,8 @@ pop_close (mailbox_t mbox)
{
message_destroy (&(mpd->pmessages[i]->message),
mpd->pmessages[i]);
if (mpd->pmessages[i]->uid)
free (mpd->pmessages[i]->uid);
if (mpd->pmessages[i]->uidl)
free (mpd->pmessages[i]->uidl);
free (mpd->pmessages[i]);
mpd->pmessages[i] = NULL;
}
......@@ -753,6 +758,9 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
}
/* Set the UIDL call on the message. */
message_set_uidl (msg, pop_uidl, mpm);
/* Set the UID on the message. */
message_set_uid (msg, pop_uid, mpm);
/* Add it to the list. */
......@@ -780,6 +788,30 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
return 0;
}
/* There is no such thing in pop all messages should be consider recent.
FIXME: We could cheat and peek at the status if it was not strip
by the server ... */
static int
pop_messages_recent (mailbox_t mbox, size_t *precent)
{
return pop_messages_count (mbox, precent);
}
/* There is no such thing in pop all messages should be consider unseen.
FIXME: We could cheat and peek at the status if it was not strip
by the server ... */
static int
pop_message_unseen (mailbox_t mbox, size_t *punseen)
{
size_t count = 0;
int status = pop_messages_count (mbox, &count);
if (status != 0)
return status;
if (punseen)
*punseen = (count > 0) ? 1 : 0;
return 0;
}
/* How many messages we have. Done with STAT. */
static int
pop_messages_count (mailbox_t mbox, size_t *pcount)
......@@ -1025,7 +1057,7 @@ pop_message_size (message_t msg, size_t *psize)
default:
/*
fprintf (stderr, "pop_uid state\n");
fprintf (stderr, "pop_message_size state\n");
*/
break;
}
......@@ -1141,19 +1173,28 @@ pop_get_fd (pop_message_t mpm, int *pfd)
return EINVAL;
}
static int
pop_uid (message_t msg, size_t *puid)
{
pop_message_t mpm = message_get_owner (msg);
if (puid)
*puid = mpm->num;
return 0;
}
/* Get the UIDL. Client should be prepare since it may fail. UIDL is
optional on many POP servers.
FIXME: We should check this with CAPA and fall back to a md5 scheme ?
Or maybe check for "X-UIDL" a la Qpopper ? */
static int
pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
{
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
int status = 0;
void *func = (void *)pop_uid;
void *func = (void *)pop_uidl;
size_t num;
/* According to the RFC uid's are no longer then 70 chars. Still playit
/* According to the RFC uidl's are no longer then 70 chars. Still playit
safe */
char uniq[128];
......@@ -1161,14 +1202,14 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
return EINVAL;
/* Is it cache ? */
if (mpm->uid)
if (mpm->uidl)
{
size_t len = strlen (mpm->uid);
size_t len = strlen (mpm->uidl);
if (buffer)
{
buflen--; /* Leave space for the null. */
buflen = (len > buflen) ? buflen : len;
memcpy (buffer, mpm->uid, buflen);
memcpy (buffer, mpm->uidl, buflen);
buffer[buflen] = '\0';
}
else
......@@ -1207,7 +1248,7 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
default:
/*
fprintf (stderr, "pop_uid state\n");
fprintf (stderr, "pop_uidl state\n");
*/
break;
}
......@@ -1233,7 +1274,7 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
}
else
buflen = num - 1; /* Do not count newline. */
mpm->uid = strdup (uniq);
mpm->uidl = strdup (uniq);
status = 0;
}
......
......@@ -411,9 +411,19 @@ message_set_attribute (message_t msg, attribute_t attribute, void *owner)
return 0;
}
/* FIXME: not nonblocking safe. */
int
message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
message_get_uid (message_t msg, size_t *puid)
{
if (msg == NULL)
return EINVAL;
if (msg->_get_uid)
return msg->_get_uid (msg, puid);
*puid = 0;
return 0;
}
int
message_get_uidl (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
{
header_t header = NULL;
size_t n = 0;
......@@ -424,9 +434,9 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
buffer[0] = '\0';
/* Try the function overload if error fallback. */
if (msg->_get_uid)
if (msg->_get_uidl)
{
status = msg->_get_uid (msg, buffer, buflen, pwriten);
status = msg->_get_uidl (msg, buffer, buflen, pwriten);
if (status == 0)
return status;
}
......@@ -458,7 +468,7 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
}
else
{
static unsigned long seq;
size_t uid = 0;
struct md5_ctx md5context;
stream_t stream = NULL;
char buf[1024];
......@@ -466,6 +476,7 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
unsigned char md5digest[16];
char *tmp;
n = 0;
message_get_uid (msg, &uid);
message_get_stream (msg, &stream);
md5_init_ctx (&md5context);
while (stream_read (stream, buf, sizeof (buf), offset, &n) == 0
......@@ -479,10 +490,8 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
for (n = 0; n < 16; n++, tmp += 2)
sprintf (tmp, "%02x", md5digest[n]);
*tmp = '\0';
/* Access to sequence is not thread-safe, but that is not a problem. */
seq++;
/* POP3 rfc says that an UID should not be longer than 70. */
snprintf (buf + 32, 70, ".%lu.%lu", (unsigned long)time (NULL), seq);
snprintf (buf + 32, 70, ".%lu.%u", (unsigned long)time (NULL), uid);
header_set_value (header, "X-UIDL", buf, 1);
buflen--; /* leave space for the NULL. */
......@@ -492,8 +501,8 @@ message_get_uid (message_t msg, char *buffer, size_t buflen, size_t *pwriten)
}
int
message_set_uid (message_t msg, int (* _get_uid)
__P ((message_t, char *, size_t, size_t *)), void *owner)
message_set_uid (message_t msg, int (*_get_uid) __P ((message_t, size_t *)),
void *owner)
{
if (msg == NULL)
return EINVAL;
......@@ -504,6 +513,18 @@ message_set_uid (message_t msg, int (* _get_uid)
}
int
message_set_uidl (message_t msg, int (* _get_uidl)
__P ((message_t, char *, size_t, size_t *)), void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_uidl = _get_uidl;
return 0;
}
int
message_set_is_multipart (message_t msg, int (*_is_multipart)
__P ((message_t, int *)), void *owner)
{
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
......@@ -16,9 +16,9 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Notes:
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
......@@ -39,22 +39,22 @@ struct _trans_stream
{
stream_t stream; /* encoder/decoder read/writes data to/from here */
int t_offset;
int min_size;
int s_offset;
char *s_buf; /* used when read it not big enough to handle min_size for decoder/encoder */
int offset; /* current stream offset */
int line_len;
int w_rhd; /* working buffer read head */
int w_whd; /* working buffer write head */
int w_whd; /* working buffer write head */
char w_buf[MU_TRANS_BSIZE]; /* working source/dest buffer */
int (*transcoder)(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
};
struct _ts_desc
struct _ts_desc
{
const char *encoding;
......@@ -72,14 +72,15 @@ static int _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize,
static int _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len);
#define NUM_TRANSCODERS 5
struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_init, _base64_decode, _base64_encode},
{ "quoted-printable", _qp_init, _qp_decode, _qp_encode},
{ "7bit", NULL},
{ "8bit", NULL},
{ "binary", NULL}
};
static void
struct _ts_desc tslist[NUM_TRANSCODERS] = {
{ "base64", _base64_init, _base64_decode, _base64_encode},
{ "quoted-printable", _qp_init, _qp_decode, _qp_encode},
{ "7bit", NULL, NULL, NULL},
{ "8bit", NULL, NULL, NULL},
{ "binary", NULL, NULL, NULL}
};
static void
_trans_destroy(stream_t stream)
{
struct _trans_stream *ts = stream_get_owner(stream);
......@@ -88,13 +89,13 @@ _trans_destroy(stream_t stream)
free(ts);
}
static int
static int
_trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes)
{
struct _trans_stream *ts = stream_get_owner(stream);
size_t obytes, wbytes;
int ret = 0, i;
if ( nbytes == NULL || optr == NULL || osize == 0 )
return EINVAL;
......@@ -107,7 +108,7 @@ _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nby
if ( offset == 0 )
ts->s_offset = ts->t_offset = ts->w_whd = ts->w_rhd = ts->offset = ts->line_len = 0;
while ( *nbytes < osize ) {
if ( ( ts->w_rhd + ts->min_size ) >= ts->w_whd ) {
memmove(ts->w_buf, ts->w_buf + ts->w_rhd, ts->w_whd - ts->w_rhd);
......@@ -149,11 +150,10 @@ _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nby
}
static int
static int
_trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes)
{
struct _trans_stream *ts = stream_get_owner(stream);
int ret = 0;
if ( nbytes == NULL || iptr == NULL || isize == 0 )
return EINVAL;
......@@ -171,7 +171,7 @@ _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size
return EINVAL;
}
static int
static int
_trans_open (stream_t stream, const char *filename, int port, int flags)
{
struct _trans_stream *ts = stream_get_owner(stream);
......@@ -179,7 +179,7 @@ _trans_open (stream_t stream, const char *filename, int port, int flags)
return stream_open(ts->stream, filename, port, flags);
}
static int
static int
_trans_truncate (stream_t stream, off_t len)
{
struct _trans_stream *ts = stream_get_owner(stream);
......@@ -187,22 +187,22 @@ _trans_truncate (stream_t stream, off_t len)
return stream_truncate(ts->stream, len);
}
static int
static int
_trans_size (stream_t stream, off_t *psize)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_size(ts->stream, psize);
}
static int
static int
_trans_flush (stream_t stream)
{
struct _trans_stream *ts = stream_get_owner(stream);
return stream_flush(ts->stream);
}
static int
static int
_trans_get_fd (stream_t stream, int *pfd)
{
struct _trans_stream *ts = stream_get_owner(stream);
......@@ -210,7 +210,7 @@ _trans_get_fd (stream_t stream, int *pfd)
return stream_get_fd(ts->stream, pfd);
}
static int
static int
_trans_close (stream_t stream)
{
struct _trans_stream *ts = stream_get_owner(stream);
......@@ -222,7 +222,7 @@ _trans_close (stream_t stream)
* base64 encode/decode
*----------------------------------------------------*/
static int
static int
_b64_input(char c)
{
const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
......@@ -235,7 +235,7 @@ _b64_input(char c)
return -1;
}
static int
static int
_base64_init(struct _trans_stream *ts, int type)
{
ts->min_size = 4;
......@@ -244,7 +244,7 @@ _base64_init(struct _trans_stream *ts, int type)
return 0;
}
static int
static int
_base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
{
int i = 0, tmp = 0, pad = 0;
......@@ -281,13 +281,13 @@ _base64_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t
}
#define BASE64_LINE_MAX 77
static int
static int
_base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
{
size_t consumed = 0;
int pad = 0;
const char *b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
*nbytes = 0;
if ( isize <= 3 )
pad = 1;
......@@ -317,7 +317,7 @@ _base64_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t
*------------------------------------------------------*/
static const char _hexdigits[16] = "0123456789ABCDEF";
static int
static int
_qp_init(struct _trans_stream *ts, int type)
{
ts->min_size = 4;
......@@ -326,7 +326,8 @@ _qp_init(struct _trans_stream *ts, int type)
return 0;
}
static int
#if 0
static int
_ishex(int c)
{
int i;
......@@ -340,8 +341,9 @@ _ishex(int c)
return 0;
}
#endif
static int
static int
_qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
{
char c;
......@@ -403,7 +405,7 @@ _qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nby
}
static int
static int
_qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
{
#define QP_LINE_MAX 76
......@@ -449,7 +451,7 @@ _qp_encode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nby
return consumed;
}
int
int
encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
{
struct _trans_stream *ts;
......@@ -479,7 +481,7 @@ encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
stream_set_flush(*stream, _trans_flush, ts );
ts->stream = iostream;
if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_ENCODE)) != 0 )
stream_destroy(stream, NULL);
stream_destroy(stream, NULL);
else {
stream_set_read(*stream, _trans_read, ts );
stream_set_write(*stream, _trans_write, ts );
......@@ -488,7 +490,7 @@ encoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
return ret;
}
int
int
decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
{
struct _trans_stream *ts;
......@@ -519,7 +521,7 @@ decoder_stream_create(stream_t *stream, stream_t iostream, const char *encoding)
stream_set_flush(*stream, _trans_flush, ts );
ts->stream = iostream;
if ( tslist[i]._init != NULL && (ret = tslist[i]._init(ts, MU_TRANS_DECODE)) != 0 )
stream_destroy(stream, NULL);
stream_destroy(stream, NULL);
else {
stream_set_read(*stream, _trans_read, ts );
stream_set_write(*stream, _trans_write, ts );
......