Commit 75cd3361 75cd3361ff84d6c8d5a77514e3fd87bb65e058b6 by Alain Magloire

According to rfc2060 the minimum timeout is 30 minutes. But

	it is not unusual to see server with a shorter timeout.  When
	the timeout occurs, the server sends a BYE.  To catch this
	all functions in folder_imap.c and mbx_imap.c use a proloque
	folder_open() or imap_messages_count to check if the server
	timedout and reconnect.  This is not bullet proof since the
	"* BYE" will be act upon on the second request, the first
	is where we catch "* BYE".  On mailbox2 this behaviour will
	be disable/enable with a property and make more reliable,
	so client set the property "AUTORECONNECT".

	* mailbox/folder_imap.c: Prologue to must functions calling
	folder_open().
	* mailbox/mbx_imap.c: Proloque to must functions calling
	folder_open() or imap_messages_count.
	(section_name): Buglet passed the wrong argument to sizeof().

	For debugging purposes, to see the traffic
	* mailbox/folder_imap.c:
	Print to stderr the command sent to the IMAP server.
	#define DEBUG_SHOW_COMMAND 1
	Print to stderr the responses received from the IMAP server.
	#define DEBUG_SHOW_RESPONSE 1
	Print to stderr the literal/quoted string received from the IMAP
	server. #define DEBUG_SHOW_DATA 1
1 parent 1227d1dd
......@@ -38,6 +38,14 @@
#include <imap0.h>
#include <mailutils/error.h>
/* For dbg purposes set to one to see different level of traffic. */
/* Print to stderr the command sent to the IMAP server. */
#define DEBUG_SHOW_COMMAND 0
/* Print to stderr the responses received from the IMAP server. */
#define DEBUG_SHOW_RESPONSE 0
/* Print to stderr the literal/quoted string received from the IMAP server. */
#define DEBUG_SHOW_DATA 0
/* Variable use for the registrar. */
static struct _record _imap_record =
{
......@@ -262,7 +270,7 @@ folder_imap_open (folder_t folder, int flags)
in IMAP. We start with 255, which is quite reasonnable and grow
as we go along. */
f_imap->buflen = 255;
f_imap->buffer = calloc (f_imap->buflen + 1, sizeof (char));
f_imap->buffer = calloc (f_imap->buflen + 1, 1);
if (f_imap->buffer == NULL)
{
CHECK_ERROR (f_imap, ENOMEM);
......@@ -463,6 +471,11 @@ folder_imap_delete (folder_t folder, const char *name)
if (name == NULL)
return EINVAL;
status = folder_open (folder, folder->flags);
if (status != 0)
return status;
switch (f_imap->state)
{
case IMAP_NO_STATE:
......@@ -505,6 +518,10 @@ folder_imap_list (folder_t folder, const char *ref, const char *name,
if (pflist == NULL)
return EINVAL;
status = folder_open (folder, folder->flags);
if (status != 0)
return status;
if (ref == NULL)
ref = "";
if (name == NULL)
......@@ -541,7 +558,7 @@ folder_imap_list (folder_t folder, const char *ref, const char *name,
const char *s = strchr (p, '/');
if (s)
{
node[nodelen] = calloc (s - p + 1, sizeof (char));
node[nodelen] = calloc (s - p + 1, 1);
if (node[nodelen])
memcpy (node[nodelen], p, s - p);
p = s;
......@@ -651,6 +668,10 @@ folder_imap_lsub (folder_t folder, const char *ref, const char *name,
if (pflist == NULL)
return EINVAL;
status = folder_open (folder, folder->flags);
if (status != 0)
return status;
if (ref == NULL) ref = "";
if (name == NULL) name = "";
......@@ -719,6 +740,10 @@ folder_imap_rename (folder_t folder, const char *oldpath, const char *newpath)
if (oldpath == NULL || newpath == NULL)
return EINVAL;
status = folder_open (folder, folder->flags);
if (status != 0)
return status;
switch (f_imap->state)
{
case IMAP_NO_STATE:
......@@ -751,6 +776,10 @@ folder_imap_subscribe (folder_t folder, const char *name)
f_imap_t f_imap = folder->data;
int status = 0;
status = folder_open (folder, folder->flags);
if (status != 0)
return status;
if (name == NULL)
return EINVAL;
switch (f_imap->state)
......@@ -785,6 +814,10 @@ folder_imap_unsubscribe (folder_t folder, const char *name)
f_imap_t f_imap = folder->data;
int status = 0;
status = folder_open (folder, folder->flags);
if (status != 0)
return status;
if (name == NULL)
return EINVAL;
switch (f_imap->state)
......@@ -827,7 +860,8 @@ imap_literal_string (f_imap_t f_imap, char **ptr)
for (len0 = len = total = 0; total < f_imap->string.nleft; total += (len + 1))
{
status = imap_readline (f_imap);
/*fprintf (stderr, "%d: %s", strlen (f_imap->buffer), f_imap->buffer);*/
if (DEBUG_SHOW_DATA)
fprintf (stderr, "%s", f_imap->buffer);
if (status != 0)
{
/* Return what we got so far. */
......@@ -919,6 +953,8 @@ imap_quoted_string (f_imap_t f_imap, char **ptr)
f_imap->string.offset += len;
if (**ptr == '"')
(*ptr)++;
if (DEBUG_SHOW_DATA)
fprintf (stderr, "%.*s", len, bquote);
return 0;
}
......@@ -1030,7 +1066,7 @@ imap_list (f_imap_t f_imap)
if (s)
{
size_t n = strtoul (s + 1, NULL, 10);
lr->name = calloc (n + 1, sizeof (char));
lr->name = calloc (n + 1, 1);
f_imap->ptr = f_imap->buffer;
imap_readline (f_imap);
memcpy (lr->name, f_imap->buffer, n);
......@@ -1060,7 +1096,7 @@ section_name (msg_imap_t msg_imap)
char *tmp;
char part[64];
size_t partlen;
snprintf (part, sizeof (partlen), "%u", msg_imap->part);
snprintf (part, sizeof part, "%u", msg_imap->part);
partlen = strlen (part);
tmp = realloc (section, sectionlen + partlen + 2);
if (tmp == NULL)
......@@ -1397,7 +1433,7 @@ static int
imap_uid (f_imap_t f_imap, char **ptr)
{
char token[128];
imap_token (token, sizeof (token), ptr);
imap_token (token, sizeof token, ptr);
if (f_imap->string.msg_imap)
f_imap->string.msg_imap->uid = strtoul (token, NULL, 10);
return 0;
......@@ -1417,7 +1453,7 @@ static int
imap_rfc822_size (f_imap_t f_imap, char **ptr)
{
char token[128];
imap_token (token, sizeof (token), ptr);
imap_token (token, sizeof token, ptr);
if (f_imap->string.msg_imap)
f_imap->string.msg_imap->message_size = strtoul (token, NULL, 10);
return 0;
......@@ -1477,12 +1513,12 @@ imap_fetch (f_imap_t f_imap)
sp = f_imap->buffer;
/* Skip untag '*'. */
imap_token (token, sizeof (token), &sp);
imap_token (token, sizeof token, &sp);
/* Get msgno. */
imap_token (token, sizeof (token), &sp);
imap_token (token, sizeof token, &sp);
msgno = strtol (token, NULL, 10);
/* Skip FETCH . */
imap_token (token, sizeof (token), &sp);
imap_token (token, sizeof token, &sp);
/* It is actually possible, but higly unlikely that we do not have the
message yet, for example a "FETCH (FLAGS (\Recent))" notification
......@@ -1508,7 +1544,7 @@ imap_fetch (f_imap_t f_imap)
while (*sp && *sp != ')')
{
/* Get the token. */
imap_token (token, sizeof (token), &sp);
imap_token (token, sizeof token, &sp);
if (strncmp (token, "FLAGS", 5) == 0)
{
......@@ -1534,7 +1570,7 @@ imap_fetch (f_imap_t f_imap)
if (*sp == '.')
{
sp++;
imap_token (token, sizeof (token), &sp);
imap_token (token, sizeof token, &sp);
if (strcasecmp (token, "SIZE") == 0)
{
status = imap_rfc822_size (f_imap, &sp);
......@@ -1589,6 +1625,9 @@ imap_expunge (f_imap_t f_imap, unsigned msgno)
}
/* This function will advance ptr to the next character that IMAP
recognise as special: " .()[]<>" and put the result in buf which
is of size len. */
static int
imap_token (char *buf, size_t len, char **ptr)
{
......@@ -1649,6 +1688,9 @@ imap_writeline (f_imap_t f_imap, const char *format, ...)
while (!done);
va_end(ap);
f_imap->ptr = f_imap->buffer + len;
if (DEBUG_SHOW_COMMAND)
fprintf (stderr, "%s", f_imap->buffer);
return 0;
}
......@@ -1801,10 +1843,9 @@ imap_parse (f_imap_t f_imap)
{
break;
}
#if 0
/* Comment out to see all reading traffic. */
mu_error ("\t\t%s", f_imap->buffer);
#endif
if (DEBUG_SHOW_RESPONSE)
mu_error ("\t\t%s", f_imap->buffer);
/* We do not want to step over f_imap->buffer since it can be use
further down the chain. */
......
......@@ -503,14 +503,11 @@ imap_messages_count (mailbox_t mailbox, size_t *pnum)
int status = 0;
/* FIXME: It is debatable if we should reconnect when the connection
timeout or die. For timeout client should ping i.e. send
timeout or die. Probably for timeout client should ping i.e. send
a NOOP via imap_is_updated() function to keep the connection alive. */
if (!f_imap->isopen)
{
status = folder_open (mailbox->folder, mailbox->flags);
if (status != 0)
return status;
}
status = folder_open (mailbox->folder, mailbox->flags);
if (status != 0)
return status;
/* Are we already selected ? */
if (m_imap == (f_imap->selected))
......@@ -760,6 +757,14 @@ imap_append_message (mailbox_t mailbox, message_t msg)
m_imap_t m_imap = mailbox->data;
f_imap_t f_imap = m_imap->f_imap;
/* FIXME: It is debatable if we should reconnect when the connection
timeout or die. For timeout client should ping i.e. send
a NOOP via imap_is_updated() function to keep the connection alive. */
status = folder_open (mailbox->folder, mailbox->flags);
if (status != 0)
return status;
/* FIXME: Can we append to self. */
/* Check to see if we are selected. If the message was not modified
......@@ -905,6 +910,13 @@ imap_copy_message (mailbox_t mailbox, message_t msg)
msg_imap_t msg_imap = message_get_owner (msg);
int status = 0;
/* FIXME: It is debatable if we should reconnect when the connection
timeout or die. For timeout client should ping i.e. send
a NOOP via imap_is_updated() function to keep the connection alive. */
status = folder_open (mailbox->folder, mailbox->flags);
if (status != 0)
return status;
switch (f_imap->state)
{
case IMAP_NO_STATE:
......@@ -974,13 +986,14 @@ imap_message_read (stream_t stream, char *buffer, size_t buflen,
if (offset == 0)
msg_imap->message_lines = 0;
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* Select first. */
if (f_imap->state == IMAP_NO_STATE)
{
char *section = NULL;
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
if (msg_imap->part)
section = section_name (msg_imap);
......@@ -1034,7 +1047,6 @@ imap_submessage_size (msg_imap_t msg_imap, size_t *psize)
size_t i, size;
for (size = i = 0; i < msg_imap->num_parts; i++, size = 0)
{
if (msg_imap->parts[i])
imap_submessage_size (msg_imap->parts[i], &size);
*psize += size;
......@@ -1055,6 +1067,10 @@ imap_message_size (message_t msg, size_t *psize)
f_imap_t f_imap = m_imap->f_imap;
int status = 0;;
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* If there is a parent it means it is a sub message, IMAP does not give
the full size of mime messages, so the message_size retrieved from
doing a bodystructure represents rather the body_size. */
......@@ -1066,9 +1082,6 @@ imap_message_size (message_t msg, size_t *psize)
/* Select first. */
if (f_imap->state == IMAP_NO_STATE)
{
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* We strip the \r, but the offset/size on the imap server is with
that octet so add it in the offset, since it's the number of
lines. */
......@@ -1100,7 +1113,12 @@ imap_message_uid (message_t msg, size_t *puid)
if (puid)
return 0;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
if (f_imap->state == IMAP_NO_STATE)
{
if (msg_imap->uid)
......@@ -1108,9 +1126,6 @@ imap_message_uid (message_t msg, size_t *puid)
*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);
......@@ -1142,6 +1157,10 @@ imap_is_multipart (message_t msg, int *ismulti)
int status;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
if (f_imap->state == IMAP_NO_STATE)
{
if (msg_imap->num_parts || msg_imap->part)
......@@ -1150,9 +1169,6 @@ imap_is_multipart (message_t msg, int *ismulti)
*ismulti = (msg_imap->num_parts > 1);
return 0;
}
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
status = imap_writeline (f_imap,
"g%d FETCH %d BODYSTRUCTURE\r\n",
f_imap->seq++, msg_imap->num);
......@@ -1281,17 +1297,17 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
char datebuf[] = "mm-dd-yyyy hh:mm:ss +0000";
const char* date = datebuf;
const char** datep = &date;
/* reserve as much space as we need for internal-date */
/* reserve as much space as we need for internal-date */
int status;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
if (msg_imap->internal_date == NULL)
{
if (f_imap->state == IMAP_NO_STATE)
{
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
status = imap_writeline (f_imap,
"g%d FETCH %d INTERNALDATE\r\n",
f_imap->seq++, msg_imap->num);
......@@ -1359,6 +1375,11 @@ imap_attr_get_flags (attribute_t attribute, int *pflags)
f_imap_t f_imap = m_imap->f_imap;
int status = 0;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* Did we retrieve it alread ? */
if (msg_imap->flags != 0)
{
......@@ -1393,6 +1414,11 @@ imap_attr_set_flags (attribute_t attribute, int flag)
f_imap_t f_imap = m_imap->f_imap;
int status = 0;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* If already set don't bother. */
if (msg_imap->flags & flag)
return 0;
......@@ -1439,6 +1465,11 @@ imap_attr_unset_flags (attribute_t attribute, int flag)
f_imap_t f_imap = m_imap->f_imap;
int status = 0;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* The delete FLAG is not pass yet but only on the expunge. */
if (flag & MU_ATTRIBUTE_DELETED)
{
......@@ -1485,6 +1516,11 @@ imap_header_get_value (header_t header, const char *field, char * buffer,
size_t len = 0;
char *value;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* Hack, if buffer == NULL they want to know how big is the field value,
Unfortunately IMAP does not say, so we take a guess hoping that the
value will not be over 1024. */
......@@ -1560,6 +1596,11 @@ imap_header_get_fvalue (header_t header, const char *field, char * buffer,
size_t len = 0;
char *value;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* Do we all ready have the headers. */
if (msg_imap->fheader)
return header_get_value (msg_imap->fheader, field, buffer, buflen, plen);
......@@ -1626,11 +1667,12 @@ imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
msg_imap->header_lines = 0;
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
if (f_imap->state == IMAP_NO_STATE)
{
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* We strip the \r, but the offset/size on the imap server is with that
octet so add it in the offset, since it's the number of lines. */
if (msg_imap->part)
......@@ -1734,11 +1776,12 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
}
/* Select first. */
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
if (f_imap->state == IMAP_NO_STATE)
{
status = imap_messages_count (m_imap->mailbox, NULL);
if (status != 0)
return status;
/* We strip the \r, but the offset/size on the imap server is with the
octet, so add it since it's the number of lines. */
if (msg_imap->part)
......