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;
*punseen = m_imap->unseen;
return 0;
}
static int
imap_messages_recent (mailbox_t mailbox, size_t *precent)
{
m_imap_t m_imap = mailbox->data;
*pnum = m_imap->unseen;
*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)
......
......@@ -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
......
......@@ -77,6 +77,8 @@ 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));
......@@ -97,7 +99,8 @@ 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 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));
......@@ -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
......@@ -72,12 +72,13 @@ 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},
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}
};
{ "7bit", NULL, NULL, NULL},
{ "8bit", NULL, NULL, NULL},
{ "binary", NULL, NULL, NULL}
};
static void
_trans_destroy(stream_t stream)
......@@ -153,7 +154,6 @@ 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;
......@@ -326,6 +326,7 @@ _qp_init(struct _trans_stream *ts, int type)
return 0;
}
#if 0
static int
_ishex(int c)
{
......@@ -340,6 +341,7 @@ _ishex(int c)
return 0;
}
#endif
static int
_qp_decode(const char *iptr, size_t isize, char *optr, size_t osize, size_t *nbytes, int *line_len)
......