Commit 9e5cc947 9e5cc947b01d31d06e6d431273ee8f84d2e7795d by Alain Magloire

attachment.c: Typo should be "Content-Disposition"

header.c mbx_mboxscan.c mbx_mbox.c : an other attempt for speed
when parsing, the most common use headers (From, To, Date, CC,..)
are save in the structure, so when retrieve them it will be
faster.  Downside the tight parsing loop is not so thight and
is frankly ugly.  More memory is being use per messages.
It is hard to guess at this stage the memory patterns
and where to optimise, probably my last attempt at this
before the code become truly unmaintable.

mbx_imap.c mailbox.c : I did not understand the difference between
"recent" and "unseen" english words.  I think that "unseen"
means new mail, an "recent" mail that was not read yet.
So I had to rename some functions mailbox_recent_count()
to mailbox_unseen_count(), but I maybe wrong ... sigh
somebody with better english skill should explain this
to me.

mbx_pop.c include/header0.h include/mailbox0.h :
Introduce header_set_fill() to let the mailboxes fill
up a buffer that will contains the entire headers.
1 parent a738518b
/* 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
......@@ -183,11 +183,11 @@ int message_attachment_filename(message_t msg, char **filename)
if ( filename != NULL && ( ret = message_get_header(msg, &hdr) ) == 0 ) {
*filename = NULL;
header_get_value(hdr, "Content-Dispostion", NULL, 0, &size);
header_get_value(hdr, "Content-Disposition", NULL, 0, &size);
if ( size ) {
if ( ( pTmp = alloca(size+1) ) == NULL )
ret = ENOMEM;
header_get_value(hdr, "Content-Dispostion", pTmp, size+1, 0);
header_get_value(hdr, "Content-Disposition", pTmp, size+1, 0);
if ( strstr( pTmp, "attachment" ) != NULL )
fname = _header_get_param(pTmp, "filename", &size);
}
......
......@@ -64,11 +64,21 @@ header_destroy (header_t *ph, void *owner)
/* Can we destroy ?. */
if (h->owner == owner)
{
size_t i;
stream_destroy (&(h->stream), h);
if (h->hdr)
free (h->hdr);
if (h->blurb)
free (h->blurb);
for (i = 0; i < h->fhdr_count; i++)
{
if (h->fhdr[i].fn)
free (h->fhdr[i].fn);
if (h->fhdr[i].fv)
free (h->fhdr[i].fv);
}
if (h->fhdr)
free (h->fhdr);
free (h);
}
*ph = NULL;
......@@ -87,13 +97,10 @@ header_is_modified (header_t header)
return (header) ? (header->flags & HEADER_MODIFIED) : 0;
}
/* Parsing is done in a rather simple fashion.
meaning we just consider an entry to be
a field-name an a field-value. So they
maybe duplicate of field-name like "Received"
they are just put in the array, see _get_value()
on how to handle the case.
in the case of error .i.e a bad header construct
/* Parsing is done in a rather simple fashion, meaning we just consider an
entry to be a field-name an a field-value. So they maybe duplicate of
field-name like "Received" they are just put in the array, see _get_value()
on how to handle the case. in the case of error .i.e a bad header construct
we do a full stop and return what we have so far. */
static int
header_parse (header_t header, const char *blurb, int len)
......@@ -191,11 +198,11 @@ header_parse (header_t header, const char *blurb, int len)
free (header->hdr);
return ENOMEM;
}
hdr[header->hdr_count].fn = fn;
hdr[header->hdr_count].fn_end = fn_end;
hdr[header->hdr_count].fv = fv;
hdr[header->hdr_count].fv_end = fv_end;
header->hdr = hdr;
header->hdr[header->hdr_count].fn = fn;
header->hdr[header->hdr_count].fn_end = fn_end;
header->hdr[header->hdr_count].fv = fv;
header->hdr[header->hdr_count].fv_end = fv_end;
header->hdr_count++;
} /* for (header_start ...) */
......@@ -218,7 +225,7 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
return header->_set_value (header, fn, fv, replace);
/* Try to fill out the buffer, if we know how. */
if (header->blurb == NULL && header->_get_value == NULL)
if (header->blurb == NULL)
{
int err = fill_blurb (header);
if (err != 0)
......@@ -310,6 +317,72 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
return 0;
}
static int
header_set_fvalue (header_t header, const char *name, char *buffer)
{
struct _hdr *thdr;
thdr = realloc (header->fhdr, (header->fhdr_count + 1) * sizeof(*thdr));
if (thdr)
{
size_t len = strlen (name);
char *field = malloc (len + 1);
if (field == NULL)
return ENOMEM;
memcpy (field, name, len);
field[len] = '\0';
thdr[header->fhdr_count].fn = field;
thdr[header->fhdr_count].fn_end = field + len;
len = strlen (buffer);
field = malloc (len + 1);
if (field == NULL)
return ENOMEM;
memcpy (field, buffer, len);
field[len] = '\0';
thdr[header->fhdr_count].fv = field;
thdr[header->fhdr_count].fv_end = field + len;
header->fhdr_count++;
header->fhdr = thdr;
return 0;
}
return ENOMEM;
}
static int
header_get_fvalue (header_t header, const char *name, char *buffer,
size_t buflen, size_t *pn)
{
size_t i, fn_len, fv_len = 0;
size_t name_len;
int err = ENOENT;
if (header->_get_fvalue)
return header->_get_fvalue (header, name, buffer, buflen, pn);
for (i = 0, name_len = strlen (name); i < header->fhdr_count; i++)
{
fn_len = header->fhdr[i].fn_end - header->fhdr[i].fn;
if (fn_len == name_len
&& strcasecmp (header->fhdr[i].fn, name) == 0)
{
fv_len = header->fhdr[i].fv_end - header->fhdr[i].fv;
if (buffer && buflen > 0)
{
buflen--;
fv_len = (fv_len < buflen) ? fv_len : buflen;
memcpy (buffer, header->fhdr[i].fv, fv_len);
buffer[fv_len] = '\0';
}
err = 0;
break;
}
}
if (pn)
*pn = fv_len;
return err;
}
int
header_get_value (header_t header, const char *name, char *buffer,
size_t buflen, size_t *pn)
......@@ -323,11 +396,35 @@ header_get_value (header_t header, const char *name, char *buffer,
if (header == NULL || name == NULL)
return EINVAL;
/* First Try the Fast header for hits. */
err = header_get_fvalue (header, name, buffer, buflen, pn);
if (err == 0)
return 0;
if (header->_get_value)
return header->_get_value (header, name, buffer, buflen, pn);
{
char buf[1024]; /* should suffice for field-value. */
size_t len = 0;
err = header->_get_value (header, name, buf, sizeof (buf), &len);
if (err == 0)
{
/* Save in the fast header buffer. */
header_set_fvalue (header, name, buf);
if (buffer && buflen > 0)
{
buflen--;
buflen = (len < buflen) ? len : buflen;
memcpy (buffer, buf, buflen);
buffer[buflen] = '\0';
if (pn)
*pn = buflen;
}
}
return err;
}
/* Try to fill out the buffer, if we know how. */
if (header->blurb == NULL && header->_get_value == NULL)
if (header->blurb == NULL)
{
err = fill_blurb (header);
if (err != 0)
......@@ -378,16 +475,6 @@ header_get_value (header_t header, const char *name, char *buffer,
if (total == 0)
{
err = ENOENT;
#if 0
/* No don't do this, the problem is we do not know if we have the
entire header value of part of it. */
if (header->_get_value)
{
err = header->_get_value (header, name, buffer, buflen + 1, pn);
if (err == 0)
header_set_value (header, name, buffer, 0);
}
#endif
}
return err;
......@@ -471,8 +558,21 @@ header_size (header_t header, size_t *psize)
}
int
header_set_get_fvalue (header_t header, int (*_get_fvalue)
__P ((header_t, const char *, char *, size_t, size_t *)),
void *owner)
{
if (header == NULL)
return EINVAL;
if (header->owner != owner)
return EACCES;
header->_get_fvalue = _get_fvalue;
return 0;
}
int
header_set_get_value (header_t header, int (*_get_value)
(header_t, const char *, char *, size_t, size_t *),
__P ((header_t, const char *, char *, size_t, size_t *)),
void *owner)
{
if (header == NULL)
......@@ -527,18 +627,27 @@ fill_blurb (header_t header)
char buf[1024];
char *tbuf;
size_t nread = 0;
size_t i;
if (header->_fill == NULL && header->stream == NULL)
if (header->_fill == NULL)
return 0;
/* Free any fast header, since we will load the entire headers. */
for (i = 0; i < header->fhdr_count; i++)
{
if (header->fhdr[i].fn)
free (header->fhdr[i].fn);
if (header->fhdr[i].fv)
free (header->fhdr[i].fv);
}
if (header->fhdr)
free (header->fhdr);
header->_get_fvalue = NULL;
do
{
if (header->_fill)
status = header->_fill (header, buf, sizeof (buf),
header->temp_blurb_len, &nread) ;
else
status = stream_read (header->stream, buf, sizeof (buf),
header->temp_blurb_len, &nread);
if (status != 0)
{
if (status != EAGAIN && status != EINTR)
......@@ -605,7 +714,7 @@ header_read (stream_t is, char *buf, size_t buflen, off_t off, size_t *pnread)
return EINVAL;
/* Try to fill out the buffer, if we know how. */
if (header->blurb == NULL && header->_fill)
if (header->blurb == NULL)
{
int err = fill_blurb (header);
if (err != 0)
......@@ -646,7 +755,7 @@ header_readline (stream_t is, char *buf, size_t buflen, off_t off, size_t *pn)
}
/* Try to fill out the buffer, if we know how. */
if (header->blurb == NULL && header->_fill)
if (header->blurb == NULL)
{
int err = fill_blurb (header);
if (err != 0)
......
......@@ -61,11 +61,14 @@ struct _header
size_t blurb_len;
size_t hdr_count;
struct _hdr *hdr;
size_t fhdr_count;
struct _hdr *fhdr;
int flags;
/* Streams. */
stream_t stream;
int (*_get_value) __P ((header_t, const char *, char *, size_t , size_t *));
int (*_get_fvalue) __P ((header_t, const char *, char *, size_t , size_t *));
int (*_set_value) __P ((header_t, const char *, const char *, int));
int (*_lines) __P ((header_t, size_t *));
int (*_size) __P ((header_t, size_t *));
......
......@@ -69,7 +69,7 @@ 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 (*_recent_count) __P ((mailbox_t, size_t *num));
int (*_unseen_count) __P ((mailbox_t, size_t *num));
int (*_expunge) __P ((mailbox_t));
int (*_scan) __P ((mailbox_t, size_t msgno, size_t *count));
......
......@@ -220,10 +220,10 @@ mailbox_messages_count (mailbox_t mbox, size_t *num)
}
int
mailbox_recent_count (mailbox_t mbox, size_t *num)
mailbox_unseen_count (mailbox_t mbox, size_t *num)
{
if (mbox && mbox->_recent_count)
return mbox->_recent_count (mbox, num);
if (mbox && mbox->_unseen_count)
return mbox->_unseen_count (mbox, num);
return mailbox_messages_count (mbox, num);
}
......
......@@ -36,6 +36,7 @@ static int mailbox_imap_close (mailbox_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_scan (mailbox_t, size_t, size_t *);
static int imap_is_updated (mailbox_t);
static int imap_append_message (mailbox_t, message_t);
......@@ -63,7 +64,7 @@ static int imap_attr_set_flags (attribute_t, int);
static int imap_attr_unset_flags (attribute_t, int);
/* Header. */
static int imap_header_read (stream_t, char*, size_t, off_t, size_t *);
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 *);
......@@ -115,6 +116,7 @@ _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->_expunge = imap_expunge;
mailbox->_scan = imap_scan;
......@@ -340,18 +342,12 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
/* Create the header. */
{
header_t header = NULL;
stream_t stream = NULL;
if ((status = header_create (&header, NULL, 0, msg)) != 0
|| (status = stream_create (&stream, mailbox->flags, header)) != 0)
if ((status = header_create (&header, NULL, 0, msg)) != 0)
{
stream_destroy (&stream, header);
header_destroy (&header, msg);
message_destroy (&msg, msg_imap);
return status;
}
stream_set_read (stream, imap_header_read, header);
stream_set_fd (stream, imap_header_fd, header);
header_set_stream (header, stream, msg);
header_set_fill (header, imap_header_read, msg);
header_set_get_value (header, imap_header_get_value, msg);
message_set_header (msg, header, msg_imap);
}
......@@ -422,11 +418,17 @@ imap_get_message0 (msg_imap_t msg_imap, message_t *pmsg)
return 0;
}
static int
imap_unseen_count (mailbox_t mailbox, size_t *pnum)
{
m_imap_t m_imap = mailbox->data;
*pnum = m_imap->unseen;
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
send a SELECT. */
static int
imap_messages_count (mailbox_t mailbox, size_t *pnum)
{
......@@ -1014,10 +1016,9 @@ imap_header_get_value (header_t header, const char *field, char * buffer,
}
static int
imap_header_read (stream_t stream, char *buffer, size_t buflen, off_t offset,
imap_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
size_t *plen)
{
header_t header = stream_get_owner (stream);
message_t msg = header_get_owner (header);
msg_imap_t msg_imap = message_get_owner (msg);
m_imap_t m_imap = msg_imap->m_imap;
......
......@@ -58,6 +58,26 @@ struct _mbox_data;
typedef struct _mbox_data* mbox_data_t;
typedef struct _mbox_message* mbox_message_t;
#define HDRSIZE 8
const char *fhdr_table[] =
{
#define HFROM 0
"From",
#define HTO 1
"To",
#define HCC 2
"Cc",
#define HSUBJECT 3
"Subject",
#define HDATE 4
"Date",
#define HX_UIDL 5
"X-UIDL",
#define HX_UID 6
"X-UID",
#define HCONTENT_TYPE 7
"Content-Type",
};
/* Keep the position of where the header and body starts and ends.
old_flags is the "Status:" message. */
struct _mbox_message
......@@ -71,6 +91,11 @@ struct _mbox_message
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. */
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
......@@ -122,7 +147,7 @@ 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_recent_count __P ((mailbox_t, size_t *));
static int mbox_unseen_count __P ((mailbox_t, size_t *));
static int mbox_expunge __P ((mailbox_t));
static int mbox_scan __P ((mailbox_t, size_t, size_t *));
static int mbox_is_updated __P ((mailbox_t));
......@@ -210,7 +235,7 @@ _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->_recent_count = mbox_recent_count;
mailbox->_unseen_count = mbox_unseen_count;
mailbox->_expunge = mbox_expunge;
mailbox->_scan = mbox_scan;
......@@ -238,7 +263,11 @@ mbox_destroy (mailbox_t mailbox)
mbox_message_t mum = mud->umessages[i];
if (mum)
{
size_t j;
message_destroy (&(mum->message), mum);
for (j = 0; j < HDRSIZE; j++)
if (mum->fhdr[j])
free (mum->fhdr[j]);
free (mum);
}
}
......@@ -347,7 +376,11 @@ mbox_close (mailbox_t mailbox)
/* Destroy the attach messages. */
if (mum)
{
size_t j;
message_destroy (&(mum->message), mum);
for (j = 0; j < HDRSIZE; j++)
if (mum->fhdr[j])
free (mum->fhdr[j]);
free (mum);
}
}
......@@ -735,6 +768,11 @@ mbox_expunge (mailbox_t mailbox)
//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]);
}
memset (mum, 0, sizeof (*mum));
/* We are not free()ing the useless mum, but instead
we put it back in the pool, to be reuse. */
......@@ -903,6 +941,34 @@ mbox_header_fill (header_t header, char *buffer, size_t len,
}
static int
mbox_header_get_fvalue (header_t header, const char *name, char *buffer,
size_t buflen, size_t *pnread)
{
size_t i, fv_value = 0;
message_t msg = header_get_owner (header);
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 (pnread)
*pnread = fv_value;
return err;
}
static int
mbox_get_header_readstream (message_t msg, char *buffer, size_t len,
off_t off, size_t *pnread, int isreadline)
{
......@@ -1128,12 +1194,11 @@ mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
status = header_create (&header, NULL, 0, msg);
if (status != 0)
{
//stream_destroy (&stream, header);
header_destroy (&header, msg);
message_destroy (&msg, mum);
return status;
}
header_set_fill (header, mbox_header_fill, msg);
header_set_get_fvalue (header, mbox_header_get_fvalue, msg);
header_set_size (header, mbox_header_size, msg);
header_set_lines (header, mbox_header_lines, msg);
message_set_header (msg, header, mum);
......@@ -1537,7 +1602,7 @@ mbox_messages_count (mailbox_t mailbox, size_t *pcount)
}
static int
mbox_recent_count (mailbox_t mailbox, size_t *pcount)
mbox_unseen_count (mailbox_t mailbox, size_t *pcount)
{
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
......
/* 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
......@@ -20,29 +20,21 @@
*/
/* Parsing.
* The approach is to detect the "From " as start of a
* new message, give the position of the header and scan
* until "\n" then set header_end, set body position,
* scan until we it another "From " and set body_end.
*
The approach is to detect the "From " as start of a new message, give the
position of the header and scan until "\n" then set header_end, set body
position, scan until we it another "From " and set body_end.
************************************
* This is a classic case of premature optimisation
* being the root of all Evil(Donald E. Knuth).
* But I'm under "pressure" ;-) to come with
* something "faster". I think it's wastefull
* to spend time to gain a few seconds on 30Megs mailboxes
* ... but then again ... in computer time, 60 seconds, is eternity.
*
* If they use the event notification stuff
* to get some headers/messages early ... it's like pissing
* in the wind(sorry don't have the english equivalent).
* The worst is progress_bar it should be ... &*($^ nuke.
* For the events, we have to remove the *.LCK file,
* release the locks, flush the stream save the pointers
* etc ... hurry and wait...
* I this point I'm pretty much ranting.
*
*/
This is a classic case of premature optimisation being the root of all
Evil(Donald E. Knuth). But I'm under "pressure" ;-) to come with
something "faster". I think it's wastefull * to spend time to gain a few
seconds on 30Megs mailboxes ... but then again ... in computer time, 60
seconds, is eternity. If they use the event notification stuff to get
some headers/messages early ... it's like pissing in the wind(sorry don't
have the english equivalent). The worst is progress_bar it should be ...
&*($^ nuke. For the events, we have to remove the *.LCK file, release the
locks, flush the stream save the pointers etc ... hurry and wait...
I this point I'm pretty much ranting. */
/* From the C-Client, part of pine */
/* You are not expected to understand this macro, but read the next page if
......@@ -156,14 +148,6 @@ h
} \
}
#define STRLEN(s, i) \
do \
{ \
char *tmp = (s);\
while (*tmp) tmp++; \
i = tmp - s; \
} while (0)
#define ATTRIBUTE_SET(buf,mum,c0,c1,type) \
do \
{ \
......@@ -178,13 +162,145 @@ do \
} \
} while (0)
#define ISCONTENT_TYPE(buf) (\
(buf[0] == 'C' || buf[0] == 'c') \
&& (buf[1] == 'O' || buf[1] == 'o') \
&& (buf[2] == 'N' || buf[2] == 'n') \
&& (buf[3] == 'T' || buf[3] == 't') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'N' || buf[5] == 'n') \
&& (buf[6] == 'T' || buf[6] == 't') \
&& (buf[7] == '-') \
&& (buf[8] == 'T' || buf[8] == 't') \
&& (buf[9] == 'Y' || buf[9] == 'y') \
&& (buf[10] == 'P' || buf[10] == 'p') \
&& (buf[11] == 'E' || buf[11] == 'e') \
&& (buf[12] == ':' || buf[12] == ' ' || buf[12] == '\t'))
#define ISCC(buf) (\
(buf[0] == 'C' || buf[0] == 'c') \
&& (buf[1] == 'C' || buf[1] == 'c') \
&& (buf[2] == ':' || buf[2] == ' ' || buf[2] == '\t'))
#define ISDATE(buf) (\
(buf[0] == 'D' || buf[0] == 'd') \
&& (buf[1] == 'A' || buf[1] == 'a') \
&& (buf[2] == 'T' || buf[2] == 't') \
&& (buf[3] == 'E' || buf[3] == 'e') \
&& (buf[4] == ':' || buf[4] == ' ' || buf[4] == '\t'))
#define ISFROM(buf) (\
(buf[0] == 'F' || buf[0] == 'f') \
&& (buf[1] == 'R' || buf[1] == 'r') \
&& (buf[2] == 'O' || buf[2] == 'o') \
&& (buf[3] == 'M' || buf[3] == 'm') \
&& (buf[4] == ':' || buf[4] == ' ' || buf[4] == '\t'))
#define ISSTATUS(buf) (\
(buf[0] == 'S' || buf[0] == 's') && \
(buf[1] == 'T' || buf[1] == 't') && \
(buf[2] == 'A' || buf[2] == 'a') && \
(buf[3] == 'T' || buf[3] == 't') && \
(buf[4] == 'U' || buf[4] == 'u') && \
(buf[5] == 'S' || buf[5] == 's') && (buf[6] == ':'))
(buf[0] == 'S' || buf[0] == 's') \
&& (buf[1] == 'T' || buf[1] == 't') \
&& (buf[2] == 'A' || buf[2] == 'a') \
&& (buf[3] == 'T' || buf[3] == 't') \
&& (buf[4] == 'U' || buf[4] == 'u') \
&& (buf[5] == 'S' || buf[5] == 's') \
&& (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t'))
#define ISSUBJECT(buf) (\
(buf[0] == 'S' || buf[0] == 's') \
&& (buf[1] == 'U' || buf[1] == 'u') \
&& (buf[2] == 'B' || buf[2] == 'b') \
&& (buf[3] == 'J' || buf[3] == 'j') \
&& (buf[4] == 'E' || buf[4] == 'e') \
&& (buf[5] == 'C' || buf[5] == 'c') \
&& (buf[6] == 'T' || buf[6] == 't') \
&& (buf[7] == ':' || buf[7] == ' ' || buf[7] == '\t'))
#define ISTO(buf) (\
(buf[0] == 'T' || buf[0] == 't') \
&& (buf[1] == 'O' || buf[1] == 'o') \
&& (buf[2] == ':' || buf[2] == ' ' || buf[2] == '\t'))
#define ISX_UIDL(buf) (\
(buf[0] == 'X' || buf[0] == 'x') \
&& (buf[1] == '-') \
&& (buf[2] == 'U' || buf[2] == 'u') \
&& (buf[3] == 'I' || buf[3] == 'i') \
&& (buf[4] == 'D' || buf[4] == 'd') \
&& (buf[5] == 'L' || buf[5] == 'l') \
&& (buf[6] == ':' || buf[6] == ' ' || buf[6] == '\t'))
#define ISX_UID(buf) (\
(buf[0] == 'X' || buf[0] == 'x') \
&& (buf[1] == '-') \
&& (buf[2] == 'U' || buf[2] == 'u') \
&& (buf[3] == 'I' || buf[3] == 'i') \
&& (buf[4] == 'D' || buf[4] == 'd') \
&& (buf[5] == ':' || buf[5] == ' ' || buf[5] == '\t'))
/* Skip prepen spaces. */
#define SKIPSPACE(p) while (*p == ' ') p++
/* Save/concatenate the field-value in the field. */
#define FAST_HEADER(field,buf,n) \
do { \
int i = 0; \
char *s = field; \
char *p = buf; \
if (s) \
while (*s++) i++; \
else \
p = memchr (buf, ':', n); \
if (p) \
{ \
int l; \
char *tmp; \
buf[n - 1] = '\0'; \
p++; \
if (!field) \
SKIPSPACE(p); \
l = n - (p - buf); \
tmp = realloc (field, (l + i + 1) * sizeof (char)); \
if (tmp) \
{ \
field = tmp; \
memcpy (field + i, p, l); \
} \
} \
} 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])
#define FAST_HCC(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HCC],buf,n); \
sf = &(mum->fhdr[HCC])
#define FAST_HDATE(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HDATE],buf,n); \
sf = &(mum->fhdr[HDATE])
#define FAST_HFROM(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HFROM],buf,n); \
sf = &(mum->fhdr[HFROM])
#define FAST_HSUBJECT(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HSUBJECT],buf,n); \
sf = &(mum->fhdr[HSUBJECT])
#define FAST_HTO(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HTO],buf,n); \
sf = &(mum->fhdr[HTO])
#define FAST_HX_UIDL(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HX_UIDL],buf,n); \
sf = &(mum->fhdr[HX_UIDL])
#define FAST_HX_UID(mum,sf,buf,n) \
FAST_HEADER(mum->fhdr[HX_UID],buf,n); \
sf = &(mum->fhdr[HX_UID])
/* Notifications ADD_MESG. */
#define DISPATCH_ADD_MSG(mbox,mud) \
......@@ -273,6 +389,8 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
size_t lines;
int newline;
size_t n = 0;
stream_t stream;
char **sfield = NULL;
int zn, isfrom = 0;
char *temp;
......@@ -315,6 +433,7 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
newline = 1;
errno = lines = inheader = inbody = 0;
stream = mailbox->stream;
while ((status = stream_readline (mailbox->stream, buf, sizeof (buf),
total, &n)) == 0 && n != 0)
{
......@@ -329,6 +448,7 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
inheader = isfrom | ((!nl) & inheader);
inbody = (!isfrom) & (!inheader);
if (buf[n - 1] == '\n')
lines++;
if (inheader)
......@@ -336,6 +456,7 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
/* New message. */
if (isfrom)
{
size_t j;
/* Signal the end of the body. */
if (mum && !mum->body_end)
{
......@@ -354,8 +475,15 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
mum->header_from_end = total;
mum->body_end = mum->body = 0;
lines = 0;
sfield = NULL;
for (j = 0; j < HDRSIZE; j++)
if (mum->fhdr[j])
{
free (mum->fhdr[j]);
mum->fhdr[j] = NULL;
}
}
else if ((n > 7) && ISSTATUS(buf))
else if (/*(n > 7) && */ ISSTATUS(buf))
{
mum->header_status = total - n;
mum->header_status_end = total;
......@@ -363,6 +491,49 @@ mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
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))
{
FAST_HCONTENT_TYPE(mum, sfield, buf, n);
}
else if (/*(n > 3) && */ ISCC(buf))
{
FAST_HCC(mum, sfield, buf, n);
}
else if (/*(n > 5) && */ ISDATE(buf))
{
FAST_HDATE(mum, sfield, buf, n);
}
else if (/*(n > 5) && */ ISFROM(buf))
{
FAST_HFROM(mum, sfield, buf, n);
}
else if (/*(n > 8) && */ ISSUBJECT(buf))
{
FAST_HSUBJECT (mum, sfield, buf, n);
}
else if (/*(n > 3) && */ ISTO(buf))
{
FAST_HTO (mum, sfield, buf, n);
}
else if (/*(n > 7) && */ ISX_UIDL(buf))
{
FAST_HX_UIDL (mum, sfield, buf, n);
}
else if (/*(n > 6) && */ ISX_UID(buf))
{
FAST_HX_UID (mum, sfield, buf, n);
}
else if (sfield && (buf[0] == ' ' || buf[0] == '\t'))
{
char *save = *sfield;
FAST_HEADER (save, buf, n);
*sfield = save;
}
else
{
sfield = NULL;
}
}
......
......@@ -85,8 +85,7 @@ static int pop_is_updated __P ((mailbox_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 (stream_t, char *, size_t, off_t, size_t *); */
static int pop_header_fd __P ((stream_t, int *));
/* 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 *));
......@@ -94,7 +93,7 @@ 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 ((stream_t, char *, size_t, off_t, size_t *));
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 *));
......@@ -706,19 +705,13 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
/* Create the header. */
{
header_t header = NULL;
stream_t stream = NULL;
if ((status = header_create (&header, NULL, 0, msg)) != 0
|| (status = stream_create (&stream, mbox->flags, header)) != 0)
if ((status = header_create (&header, NULL, 0, msg)) != 0)
{
stream_destroy (&stream, header);
header_destroy (&header, msg);
message_destroy (&msg, mpm);
free (mpm);
return status;
}
stream_set_read (stream, pop_top, header);
stream_set_fd (stream, pop_header_fd, header);
header_set_stream (header, stream, msg);
header_set_fill (header, pop_top, msg);
message_set_header (msg, header, mpm);
}
......@@ -1130,16 +1123,6 @@ pop_body_fd (stream_t stream, int *pfd)
return pop_get_fd (mpm, pfd);
}
/* Stub to call the fd from header object. */
static int
pop_header_fd (stream_t stream, int *pfd)
{
header_t header = stream_get_owner (stream);
message_t msg = header_get_owner (header);
pop_message_t mpm = message_get_owner (msg);
return pop_get_fd (mpm, pfd);
}
/* Stub to call the fd from message object. */
static int
pop_message_fd (stream_t stream, int *pfd)
......@@ -1267,10 +1250,9 @@ pop_uid (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
on a socket but we better warn them, some stuff like mime_t may try to
read ahead, for example for the headers. */
static int
pop_top (stream_t is, char *buffer, size_t buflen,
pop_top (header_t header, char *buffer, size_t buflen,
off_t offset, size_t *pnread)
{
header_t header = stream_get_owner (is);
message_t msg = header_get_owner (header);
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
......@@ -1372,10 +1354,10 @@ pop_top (stream_t is, char *buffer, size_t buflen,
#if 0
/* Stub to call pop_retr (). Call form the stream object of the header. */
static int
pop_header_read (stream_t is, char *buffer, size_t buflen, off_t offset,
pop_header_read (header_t header, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
message_t msg = stream_get_owner (is);
message_t msg = header_get_owner (header);
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
void *func = (void *)pop_header_read;
......