Commit 4290bdcd 4290bdcd312193ffedb77bcd9811b584db2a2529 by Alain Magloire

mbx_mbox.c mbx_mboxscan.c : I need to clean the expunge code

I realise that MBOX format means that we also have to escapes lines
that starting with "From " --> ">From ". So much for speed since
this will imply reading line by line.

mbx_pop.c : Some bug fixes, connection is close down if the client
is trying to seek() backward.

folder_imap.c mbx_imap.c : Unfinish business, but getting better.

stream.c : Don't force a flush on close, let the underlying implementatio
do that.
1 parent fb62000f
......@@ -63,11 +63,13 @@ static int folder_imap_unsubscribe __P ((folder_t, const char *));
/* Private */
/* static int imap_readline (f_imap_t); */
static int imap_fetch __P ((f_imap_t));
static int imap_flags __P ((f_imap_t));
static int imap_bodystructure __P ((f_imap_t));
static int imap_literal_string __P ((f_imap_t));
static int imap_string __P ((f_imap_t));
static int imap_quoted_string __P ((f_imap_t, char *));
static int imap_flags __P ((f_imap_t, char **));
static int imap_bodystructure __P ((f_imap_t, char **));
static int imap_literal_string __P ((f_imap_t, char **));
static int imap_string __P ((f_imap_t, char **));
static int imap_quoted_string __P ((f_imap_t, char **));
#define TOKENLEN 32
static int imap_token __P ((char *, char **));
/* Initialize the concrete IMAP mailbox: overload the folder functions */
int
......@@ -705,15 +707,15 @@ folder_imap_unsubscribe (folder_t folder, const char *name)
prefix-quoted with an octet count in the form of an open brace ("{"),
the number of octets, close brace ("}"), and CRLF. The sequence is read
and put in the callback buffer, hopefully the callee did have enough
room. Since we are using buffering on the stream(internal stream buffer)
We should have lots of room. */
room. */
static int
imap_literal_string (f_imap_t f_imap)
imap_literal_string (f_imap_t f_imap, char **ptr)
{
size_t len, total0, len0;
size_t len, len0, total;
int status = 0;
for (len0 = len = total0 = 0; total0 < f_imap->callback.nleft;
total0 += len0)
int nl;
/* The (len + 1) in the for is to count the strip '\r' by imap_readline. */
for (len0 = len = total = 0; total < f_imap->callback.nleft; total += (len + 1))
{
status = imap_readline (f_imap);
if (status != 0)
......@@ -722,179 +724,131 @@ imap_literal_string (f_imap_t f_imap)
break;
}
f_imap->ptr = f_imap->buffer;
/* How much ? */
len = len0 = f_imap->nl - f_imap->buffer;
/* Check if the last read did not finish on a line do not copy in
len0= len = f_imap->nl - f_imap->buffer;
/* Check if the last read did not finish on a line, if yes do not copy in
callback buffer the terminating sequence ")\r\n". We are doing this
by checking if the amounth (total0) we got so far correspond to what
we expect + the line we just read (+1 taking to account the '\r') if
yes then we should strip the termination string ")\r\n". */
if ((len0 + 1 + total0) >= f_imap->callback.nleft)
{
char *seq = memchr (f_imap->buffer, ')', len0);
if (seq)
{
len = seq - f_imap->buffer;
/* Bad luck, if it is \r meaning the imap server could not add
the adjacent \n in the substring, maybe because it did not
fit the number of byte we ask, skip it here. */
/* FIXME: Can this be dangerous ? It can be if a the message
contains char that is not 7bit ascii and no encoding were use
of that message. A solution would be to wait for the next
char and if it is '\n' skip it if not use it, but that is to
much work especially for nonblocking, the message should have
been encoded. */
if (*(seq -1) == '\r')
len--;
}
}
/* Put the sequence of string in the callback structre for the calle to
use. */
by checking if the amount(total) we got so far + the len of the line
+1 (taking to account the strip '\r'). */
if ((total + len + 1) > f_imap->callback.nleft)
{
len0 = len = f_imap->callback.nleft - total;
/* ALERT: if we ask for a substring, for example we have :
"123456\n", and ask for body[]<0.7> the server will send
body[] {7} --> "123456\r". There was not enough space
to fit the nl .. annoying. Take care of this here. */
if (f_imap->buffer[len - 1] == '\r')
len0--;
}
if (f_imap->callback.total < f_imap->callback.buflen)
{
/* Check how much we can fill the buffer. */
int x = (f_imap->callback.buflen - f_imap->callback.total) - len;
x = (x >= 0) ? len : -x;
/* Check how much we can fill the callback buffer. */
int x = (f_imap->callback.buflen - f_imap->callback.total) - len0;
x = (x >= 0) ? len0 : (x + len0);
memcpy (f_imap->callback.buffer + f_imap->callback.total,
f_imap->buffer, x);
f_imap->callback.total += x;
}
/* Depending on the type of request we incremente the xxxx_lines
and xxxx_sizes. */
if (len == len0 && f_imap->callback.msg_imap)
nl = (memchr (f_imap->buffer, '\n', len0)) ? 1 : 0;
if (f_imap->callback.msg_imap)
{
switch (f_imap->callback.type)
{
case IMAP_HEADER:
f_imap->callback.msg_imap->header_lines++;
f_imap->callback.msg_imap->header_size +=
f_imap->callback.total;
f_imap->callback.msg_imap->header_lines += nl;
f_imap->callback.msg_imap->header_size += f_imap->callback.total;
break;
case IMAP_BODY:
f_imap->callback.msg_imap->body_lines++;
f_imap->callback.msg_imap->body_size +=
f_imap->callback.total;
f_imap->callback.msg_imap->body_lines += nl;
f_imap->callback.msg_imap->body_size += f_imap->callback.total;
break;
case IMAP_MESSAGE:
f_imap->callback.msg_imap->message_lines++;
f_imap->callback.msg_imap->message_lines += nl;
/* The message size is known by sending RFC822.SIZE. */
default:
break;
}
}
}
else
f_imap->callback.nleft -= total;
/* Move the command buffer, or do a full readline. */
if (len == (f_imap->nl - f_imap->buffer))
{
/* This should never happen, the amount of in the literal string
response is the same or less that we requested in the buffer
of the callback. They should always be enough room. */
break;
}
/* count the '\r' too, since it was strip in imap_readline () */
len0 += 1;
len = 0;
status = imap_readline (f_imap);
}
f_imap->callback.nleft -= total0;
*ptr = f_imap->buffer + len;
return status;
}
/* A quoted string is a sequence of zero or more 7-bit characters,
excluding CR and LF, with double quote (<">) characters at each end.
Same thing as the literal, diferent format the result is put in the
callback buffer for the mailbox/calle. */
callback buffer for the mailbox/callee. */
static int
imap_quoted_string (f_imap_t f_imap, char *remainder)
imap_quoted_string (f_imap_t f_imap, char **ptr)
{
char *bquote;
bquote = memchr (remainder, '"', strlen (remainder));
if (bquote)
{
char *equote = memchr (bquote + 1, '"', strlen (bquote + 1));
if (equote)
int escaped = 0;
(*ptr)++;
bquote = *ptr;
while (**ptr && (**ptr != '"' || escaped))
{
/* {De,In}cremente by one to not count the quotes. */
bquote++;
equote--;
f_imap->callback.total = (equote - bquote) + 1;
escaped = (**ptr == '\\') ? 1 : 0;
(*ptr)++;
}
f_imap->callback.total = *ptr - bquote;
/* Fill the call back buffer. The if is redundant there should always
be enough room since the request is base on the buffer size. */
if (f_imap->callback.total <= f_imap->callback.buflen)
{
int nl = 0;
memcpy (f_imap->callback.buffer, bquote, f_imap->callback.total);
while (bquote && ((equote - bquote) >= 0))
{
bquote = memchr (f_imap->callback.buffer, '\n',
(equote - bquote) + 1);
if (bquote)
{
nl++;
bquote++;
}
else
break;
}
/* Depending on the type of request we incremente the xxxx_lines
and xxxx_sizes. */
switch (f_imap->callback.type)
{
case IMAP_HEADER:
f_imap->callback.msg_imap->header_lines += nl;
f_imap->callback.msg_imap->header_size +=
f_imap->callback.total;
break;
case IMAP_BODY:
f_imap->callback.msg_imap->body_lines += nl;
f_imap->callback.msg_imap->body_size +=
f_imap->callback.total;
break;
case IMAP_MESSAGE:
f_imap->callback.msg_imap->message_lines += nl;
default:
break;
}
}
}
}
if (**ptr == '"')
(*ptr)++;
return 0;
}
/* Find which type of string the response is: literal or quoted and let the
function fill the callback buffer. */
static int
imap_string (f_imap_t f_imap)
imap_string (f_imap_t f_imap, char **ptr)
{
int status = 0;
size_t len = f_imap->nl - f_imap->buffer;
char *bcurl = memchr (f_imap->buffer, '{', len);
if (bcurl)
/* Skip whites. */
while (**ptr == ' ')
(*ptr)++;
switch (**ptr)
{
char *ecurl;
len = f_imap->nl - bcurl;
ecurl = memchr (bcurl, '}', len);
if (ecurl)
case '{':
f_imap->callback.nleft = strtol ((*ptr) + 1, ptr, 10);
if (**ptr == '}')
{
*ecurl = '\0';
f_imap->callback.nleft = strtol (bcurl + 1, NULL, 10);
/* We had 3 for ")\r\n" terminates the fetch command. */
f_imap->callback.nleft += 3;
}
(*ptr)++;
/* Reset the buffer to the beginning. */
f_imap->ptr = f_imap->buffer;
status = imap_literal_string (f_imap);
status = imap_literal_string (f_imap, ptr);
}
else
{
char *bracket = memchr (f_imap->buffer, ']', len);
if (bracket == NULL)
bracket = f_imap->buffer;
f_imap->ptr = f_imap->buffer;
status = imap_quoted_string (f_imap, bracket);
break;
case '"':
status = imap_quoted_string (f_imap, ptr);
break;
/* NIL */
case 'N':
case 'n':
(*ptr)++; /* I|i */
(*ptr)++; /* L|l */
break;
default:
/* Problem. */
break;
}
return status;
}
......@@ -1027,30 +981,33 @@ section_name (msg_imap_t msg_imap)
return section;
}
/* FIXME: This does not work for nonblocking. */
/* Recursive call, to parse the dismay of parentesis "()" in a BODYSTRUCTURE
call, not we use the short form of BODYSTRUCTURE, BODY with no argument. */
/* We do not pay particular attention to the content of the bodystructure
but rather to the paremetized list layout to discover how many messages
the originial message is composed of. The information is later retrieve
when needed via the body[header.fields] command. Note that this function
is recursive. */
static int
imap_bodystructure0 (msg_imap_t msg_imap, char **buffer, char **base)
imap_bodystructure0 (msg_imap_t msg_imap, char **ptr)
{
int paren = 0;
int no_arg = 0;
int status = 0;
char *p = memchr (*buffer, '(', strlen (*buffer));
if (p == NULL)
return 0;
/* Skip space. */
while (**ptr == ' ')
(*ptr)++;
if (**ptr != '(')
return 0; /* Something is wrong. */
/* Pass lparen. */
++(*ptr);
paren++;
no_arg++;
for (p = (p + 1); *p != '\0'; p++)
for (; **ptr; ++(*ptr))
{
if (*p == '(')
if (**ptr == '(')
{
paren++;
/* If we did not parse any argment it means that it is a subpart of
the message. We create a new concrete msg_api for it. */
if (no_arg)
{
msg_imap_t new_part;
......@@ -1069,8 +1026,7 @@ imap_bodystructure0 (msg_imap_t msg_imap, char **buffer, char **base)
new_part->num = msg_imap->num;
new_part->m_imap = msg_imap->m_imap;
new_part->flags = msg_imap->flags;
//p++;
imap_bodystructure0 (new_part, &p, base);
status = imap_bodystructure0 (new_part, ptr);
}
else
status = ENOMEM;
......@@ -1079,7 +1035,7 @@ imap_bodystructure0 (msg_imap_t msg_imap, char **buffer, char **base)
status = ENOMEM;
}
}
if (*p == ')')
if (**ptr == ')')
{
no_arg = 1;
paren--;
......@@ -1087,74 +1043,78 @@ imap_bodystructure0 (msg_imap_t msg_imap, char **buffer, char **base)
if (paren <= 0)
break;
}
/* Skip over quoted strings. */
else if (*p == '"')
/* Skip the rests */
else
{
p++;
while (*p && *p != '"') p++;
if (*p == '\0') break;
/* FIXME: set the command callback if EAGAIN to resume. */
status = imap_string (msg_imap->m_imap->f_imap, ptr);
if (status != 0)
return status;
no_arg = 0;
}
/* Dam !! a literal in the body description !!! We just read the line
and continue the parsing with this newline. */
else if (*p == '{')
{
size_t count;
f_imap_t f_imap = msg_imap->m_imap->f_imap;
f_imap->ptr = f_imap->buffer;
imap_readline (f_imap);
count = f_imap->nl - f_imap->buffer;
if (count)
{
char *tmp = calloc (count + 1, sizeof (char));
if (tmp)
{
free (*base);
*base = tmp;
p = *base;
memcpy (p, f_imap->buffer, count);
}
}
if (**ptr == '\0')
break;
}
/* Skip the rests */
else if (*p != ' ')
no_arg = 0;
} /* for */
*buffer = p;
return status;
return 0;
}
/* Cover functions that calls the recursive imap_bodystructure0 to parse. */
static int
imap_bodystructure (f_imap_t f_imap)
imap_bodystructure (f_imap_t f_imap, char **ptr)
{
char *p = strchr (f_imap->buffer, '(');
if (p)
{
p++;
p = strchr (p, '(');
if (p && f_imap->callback.msg_imap)
{
char *s = calloc (strlen (p) + 1, sizeof (*s));
char *base = s;
strcpy (s, p);
imap_bodystructure0 (f_imap->callback.msg_imap, &s, &base);
free (base);
}
}
return 0;
return imap_bodystructure0 (f_imap->callback.msg_imap, ptr);
}
/* Parse the flags untag responses. */
/* The Format for a FLAG response is :
mailbox_data ::= "FLAGS" SPACE flag_list
flag_list ::= "(" #flag ")"
flag ::= "\Answered" / "\Flagged" / "\Deleted" /
"\Seen" / "\Draft" / flag_keyword / flag_extension
flag_extension ::= "\" atom
;; Future expansion. Client implementations
;; MUST accept flag_extension flags. Server
;; implementations MUST NOT generate
;; flag_extension flags except as defined by
;; future standard or standards-track
;; revisions of this specification.
flag_keyword ::= atom
S: * 14 FETCH (FLAGS (\Seen \Deleted))
S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
We assume that the '*' or the FLAGS keyword are strip.
FIXME: User flags are not take to account. */
static int
imap_flags (f_imap_t f_imap)
imap_flags (f_imap_t f_imap, char **ptr)
{
char *flag;
char *sp = NULL;
char *flags = memchr (f_imap->buffer, '(', f_imap->nl - f_imap->buffer);
/* msg_imap may be null for an untag response deal with it. */
msg_imap_t msg_imap = f_imap->callback.msg_imap;
while ((flag = strtok_r (flags, " ()", &sp)) != NULL)
{
/* Skip space. */
while (**ptr == ' ')
(*ptr)++;
/* Skip LPAREN. */
if (**ptr == '(')
(*ptr)++;
for (;**ptr && **ptr != ')'; ++(*ptr))
{
/* Skip space before next word. */
while (**ptr == ' ')
(*ptr)++;
/* Save the beginning of the word. */
flag = *ptr;
/* Get the next word boundary. */
while (**ptr && **ptr != ' ' && **ptr != ')')
++*ptr;
/* Make a C string for the strcasecmp. */
**ptr = '\0';
/* Bail out. */
if (*flag == '\0')
break;
/* Guess the flag. */
if (strcasecmp (flag, "\\Seen") == 0)
{
if (msg_imap)
......@@ -1190,46 +1150,70 @@ imap_flags (f_imap_t f_imap)
else
f_imap->flags |= MU_ATTRIBUTE_DRAFT;
}
flags = NULL;
}
return 0;
}
static int
imap_body (f_imap_t f_imap, char **ptr)
{
char *sep;
while (**ptr && **ptr == ' ')
(*ptr)++;
if (**ptr == '[')
{
sep = strchr (*ptr, ']');
if (sep)
{
sep++;
*ptr = sep;
}
}
while (**ptr && **ptr == ' ')
(*ptr)++;
if (**ptr == '<')
{
sep = strchr (*ptr, '>');
if (sep)
{
sep++;
*ptr = sep;
}
}
return imap_string (f_imap, ptr);
}
static int
imap_internaldate (f_imap_t f_imap, char **ptr)
{
return imap_string (f_imap, ptr);
}
/* Parse imap unfortunately FETCH is use as response for many commands. */
static int
imap_fetch (f_imap_t f_imap)
{
char *command;
char command[128];
size_t msgno = 0;
size_t len = f_imap->nl - f_imap->buffer;
m_imap_t m_imap = f_imap->selected;
const char *delim = " ()<>";
const char *delim = " ";
int status = 0;
char *sp = NULL;
/* If we have some data that was not clear it may mean that we returned
EAGAIN etc ... In any case we have to clear it first. */
if (f_imap->callback.nleft)
return imap_literal_string (f_imap);
/* We do not want to step over f_imap->buffer since it can be use further
down the chain. */
command = alloca (len + 1);
memcpy (command, f_imap->buffer, len + 1);
/* We should have a mailbox selected. */
assert (m_imap != NULL);
/* Parse the FETCH respones to extract the pieces. */
sp = f_imap->buffer;
/* Skip untag '*'. */
command = strtok_r (command, delim, &sp);
imap_token (command, &sp);
/* Get msgno. */
command = strtok_r (NULL, delim, &sp);
if (command)
imap_token (command, &sp);
msgno = strtol (command, NULL, 10);
/* Skip FETCH . */
command = strtok_r (NULL, delim, &sp);
imap_token (command, &sp);
/* It is actually possible, but higly unlikely that we do not have the
message yet, for example a "FETCH (FLAGS (\Recent))" notification
......@@ -1248,41 +1232,74 @@ imap_fetch (f_imap_t f_imap)
}
}
}
//assert (msg_imap != NULL);
// assert (msg_imap != NULL);
/* Get the command. */
command = strtok_r (NULL, delim, &sp);
#if 0
/* skip to '(' */
while (*sp && *sp != '(')
sp++;
#endif
/* Get the commands. */
while (*sp && *sp != ')')
{
imap_token (command, &sp);
if (strncmp (command, "FLAGS", 5) == 0)
{
status = imap_flags (f_imap);
status = imap_flags (f_imap, &sp);
}
else if (strcasecmp (command, "BODY") == 0)
else if (strcasecmp (command, "BODY") == 0
|| strcasecmp (command, "BODYSTRUCTURE") == 0)
{
status = imap_bodystructure (f_imap);
if (*sp == '[')
status = imap_body (f_imap, &sp);
else
status = imap_bodystructure (f_imap, &sp);
}
else if (strncmp (command, "INTERNALDATE", 12) == 0)
{
status = imap_string (f_imap);
status = imap_internaldate (f_imap, &sp);
}
else if (strncmp (command, "RFC822.SIZE", 10) == 0)
{
command = strtok_r (NULL, " ()\n", &sp);
imap_token (command, &sp);
if (f_imap->callback.msg_imap)
f_imap->callback.msg_imap->message_size = strtoul (command, NULL, 10);
}
else if (strncmp (command, "BODY", 4) == 0)
{
status = imap_string (f_imap);
f_imap->callback.msg_imap->message_size = strtoul (command,
NULL, 10);
}
else if (strncmp (command, "UID", 3) == 0)
{
command = strtok_r (NULL, " ()\n", &sp);
imap_token (command, &sp);
if (f_imap->callback.msg_imap)
f_imap->callback.msg_imap->uid = strtoul (command, NULL, 10);
}
}
return status;
}
static int
imap_token (char *buf, char **ptr)
{
char *start = *ptr;
while (**ptr && **ptr == ' ')
(*ptr)++;
for (; **ptr; (*ptr)++, buf++)
{
if (**ptr == ' ' || **ptr == '.'
|| **ptr == '(' || **ptr == ')'
|| **ptr == '[' || **ptr == ']'
|| **ptr == '<' || **ptr == '>')
{
if (start == (*ptr))
(*ptr)++;
break;
}
*buf = **ptr;
}
*buf = '\0';
return *ptr - start;;
}
/* C99 says that a conforming implementations of snprintf () should return the
number of char that would have been call but many GNU/Linux && BSD
implementations return -1 on error. Worse QnX/Neutrino actually does not
......@@ -1450,9 +1467,6 @@ imap_parse (f_imap_t f_imap)
int status = 0;
char empty[2];
if (f_imap->callback.nleft)
imap_literal_string (f_imap);
/* We use that moronic hack to not check null for the tockenize strings. */
empty[0] = '\0';
empty[1] = '\0';
......@@ -1658,7 +1672,7 @@ imap_parse (f_imap_t f_imap)
else if (strcasecmp (response, "FLAGS") == 0)
{
/* Flags define on the mailbox not a message flags. */
status = imap_flags (f_imap);
status = imap_flags (f_imap, &remainder);
}
else if (strcasecmp (response, "LIST") == 0)
{
......@@ -1685,7 +1699,7 @@ imap_parse (f_imap_t f_imap)
response, remainder);
}
}
/* Continuation token. */
/* Continuation token ???. */
else if (tag && tag[0] == '+')
{
done = 1;
......
......@@ -23,6 +23,7 @@
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <mailutils/address.h>
#include <mailbox0.h>
......@@ -83,6 +84,13 @@ static int message_operation (f_imap_t, msg_imap_t, enum imap_state, char *,
size_t, size_t *);
static void free_subparts (msg_imap_t);
static const char *MONTHS[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/* Initialize the concrete object mailbox_t by overloading the function of the
structure. */
int
......@@ -890,6 +898,12 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
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 year, mon, day, hour, min, sec;
int offt;
int i;
struct tm tm;
time_t now;
char month[5];
int status;
if (f_imap->state == IMAP_NO_STATE)
{
......@@ -904,7 +918,44 @@ imap_envelope_date (envelope_t envelope, char *buffer, size_t buflen,
MAILBOX_DEBUG0 (m_imap->mailbox, MU_DEBUG_PROT, f_imap->buffer);
f_imap->state = IMAP_FETCH;
}
return message_operation (f_imap, msg_imap, 0, buffer, buflen, plen);
status = message_operation (f_imap, msg_imap, 0, buffer, buflen, plen);
if (status != 0)
return status;
day = mon = year = hour = min = sec = offt = 0;
month[0] = '\0';
sscanf (buffer, "%2d-%3s-%4d %2d:%2d:%2d %d", &day, month, &year,
&hour, &min, &sec, &offt);
tm.tm_sec = sec;
tm.tm_min = min;
tm.tm_hour = hour;
tm.tm_mday = day;
for (i = 0; i < 12; i++)
{
if (strncasecmp(month, MONTHS[i], 3) == 0)
{
mon = i;
break;
}
}
tm.tm_mon = mon;
tm.tm_year = (year > 1900) ? year - 1900 : year;
tm.tm_yday = 0; /* unknown. */
tm.tm_wday = 0; /* unknown. */
tm.tm_isdst = -1; /* unknown. */
/* What to do the timezone? */
now = mktime (&tm);
if (now == (time_t)-1)
{
/* Fall back to localtime. */
now = time (NULL);
snprintf (buffer, buflen, "%s", ctime(&now));
}
else
{
strftime (buffer, buflen, " %a %b %d %H:%M:%S %Y", &tm);
}
return 0;
}
/* Attributes. */
......@@ -1131,6 +1182,7 @@ imap_body_lines (body_t body, size_t *plines)
return 0;
}
/* FIXME: Send EISPIPE if trying to seek back. */
static int
imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
size_t *plen)
......@@ -1144,11 +1196,12 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
char newbuf[2];
int status = 0;
/* This so F*$&#g annoying, a buffer len of 1 is a killer.
If you have for example "\n", IMAP servers will transform
this to "\r\n" and since you ask for only 1 sends '\r' only.
'\r' will be stripped and the number of char read will be 0
which means we're done. So we guard to at least ask for 2 chars. */
/* This is so annoying, a buffer len of 1 is a killer. If you have for
example "\n" to retrieve from the server, IMAP will transform this to
"\r\n" and since you ask for only 1, the server will send '\r' only.
And ... '\r' will be stripped by (imap_readline()) the number of char
read will be 0 which means we're done .... sigh ... So we guard to at
least ask for 2 chars. */
if (buflen == 1)
{
oldbuf = buffer;
......@@ -1161,8 +1214,8 @@ imap_body_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
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. */
/* 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)
{
char *section = section_name (msg_imap);
......
......@@ -1255,7 +1255,7 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
if (pmsg == NULL || mud == NULL)
return EINVAL;
/* We did not start a scanning yet do it now. */
/* If we did not start a scanning yet do it now. */
if (mud->messages_count == 0)
{
status = mbox_scan0 (mailbox, 1, NULL, 0);
......@@ -1397,8 +1397,8 @@ 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
/* FIXME: We need to escape body line that begins with "From ", this
will required to read the body by line instead of by chuncks hurting
perfomance big time when expunging. But should not this be the
responsability of the client ? */
static int
......@@ -1734,6 +1734,13 @@ mbox_messages_recent (mailbox_t mailbox, size_t *pcount)
mbox_message_t mum;
size_t j, recent;
/* If we did not start a scanning yet do it now. */
if (mud->messages_count == 0)
{
int status = mbox_scan0 (mailbox, 1, NULL, 0);
if (status != 0)
return status;
}
for (recent = j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
......@@ -1753,6 +1760,13 @@ mbox_message_unseen (mailbox_t mailbox, size_t *pmsgno)
mbox_message_t mum;
size_t j, unseen;
/* If we did not start a scanning yet do it now. */
if (mud->messages_count == 0)
{
int status = mbox_scan0 (mailbox, 1, NULL, 0);
if (status != 0)
return status;
}
for (unseen = j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
......@@ -1775,6 +1789,13 @@ mbox_uidvalidity (mailbox_t mailbox, unsigned long *puidvalidity)
int status = mbox_messages_count (mailbox, NULL);
if (status != 0)
return status;
/* If we did not start a scanning yet do it now. */
if (mud->messages_count == 0)
{
status = mbox_scan0 (mailbox, 1, NULL, 0);
if (status != 0)
return status;
}
if (puidvalidity)
*puidvalidity = mud->uidvalidity;
return 0;
......@@ -1787,6 +1808,13 @@ mbox_uidnext (mailbox_t mailbox, size_t *puidnext)
int status = mbox_messages_count (mailbox, NULL);
if (status != 0)
return status;
/* If we did not start a scanning yet do it now. */
if (mud->messages_count == 0)
{
status = mbox_scan0 (mailbox, 1, NULL, 0);
if (status != 0)
return status;
}
if (puidnext)
*puidnext = mud->uidnext;
return 0;
......
......@@ -643,7 +643,8 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
mum->mud = mud;
mum->header_from = total - n;
mum->header_from_end = total;
//mum->body_end = mum->body = 0;
mum->body_end = mum->body = 0;
mum->attr_flags = 0;
lines = 0;
sfield = NULL;
for (j = 0; j < HDRSIZE; j++)
......
......@@ -395,12 +395,13 @@ pop_user (authority_t auth)
CHECK_ERROR_CLOSE (mbox, mpd, EINVAL);
}
status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
/* We have to nuke the passwd. */
memset (mpd->passwd, '\0', strlen (mpd->passwd));
free (mpd->passwd);
mpd->passwd = NULL;
CHECK_ERROR_CLOSE (mbox, mpd, status);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, "PASS *\n");
//MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, "PASS *\n");
mpd->state = POP_AUTH_PASS;
case POP_AUTH_PASS:
......@@ -908,8 +909,14 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
if (mbox->observable == NULL)
return 0;
for (i = msgno; i <= count; i++)
{
if (observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD) != 0)
break;
if (((i +1) % 10) == 0)
{
observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS);
}
}
return 0;
}
......@@ -1306,6 +1313,9 @@ pop_top (header_t header, char *buffer, size_t buflen,
mpd = mpm->mpd;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
/* We start fresh then reset the sizes. */
if (mpd->state == POP_NO_STATE)
mpm->header_size = 0;
......@@ -1314,9 +1324,6 @@ pop_top (header_t header, char *buffer, size_t buflen,
if ((size_t)offset < mpm->header_size)
return ESPIPE;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
/* Get the header. */
switch (mpd->state)
{
......@@ -1408,17 +1415,17 @@ pop_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
mpd = mpm->mpd;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
/* We start fresh then reset the sizes. */
if (mpd->state == POP_NO_STATE)
mpm->header_size = 0;
mpm->header_size = mpm->inbody = 0;
/* Throw an error if trying to seek back. */
if ((size_t)offset < mpm->header_size)
return ESPIPE;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
mpm->skip_header = 0;
mpm->skip_body = 1;
return pop_retr (mpm, buffer, buflen, offset, pnread);
......@@ -1441,17 +1448,17 @@ pop_body_read (stream_t is, char *buffer, size_t buflen, off_t offset,
mpd = mpm->mpd;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
/* We start fresh then reset the sizes. */
if (mpd->state == POP_NO_STATE)
mpm->body_size = 0;
mpm->body_size = mpm->inbody = 0;
/* Can not seek back this a stream socket. */
if ((size_t)offset < mpm->body_size)
return ESPIPE;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
mpm->skip_header = 1;
mpm->skip_body = 0;
return pop_retr (mpm, buffer, buflen, offset, pnread);
......@@ -1472,17 +1479,17 @@ pop_message_read (stream_t is, char *buffer, size_t buflen, off_t offset,
mpd = mpm->mpd;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
/* We start fresh then reset the sizes. */
if (mpd->state == POP_NO_STATE)
mpm->header_size = mpm->body_size = 0;
mpm->header_size = mpm->body_size = mpm->inbody = 0;
/* Can not seek back this is a stream socket. */
if ((size_t)offset < (mpm->body_size + mpm->header_size))
return ESPIPE;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
mpm->skip_header = mpm->skip_body = 0;
return pop_retr (mpm, buffer, buflen, offset, pnread);
}
......
......@@ -102,8 +102,6 @@ stream_close (stream_t stream)
{
if (stream == NULL)
return EINVAL;
/* Make sure the writes were flush. */
stream_flush (stream);
stream->state = MU_STREAM_STATE_CLOSE;
/* Clear the buffer of any residue left. */
if (stream->rbuffer.base)
......