Commit 0c013ac5 0c013ac57ef780d2d6f2a9b389b1c754b5c29033 by Sergey Poznyakoff

Fix UNIX mbox driver and mail utility.

The `mail' and `frm' utilities pass tests.

* include/mailutils/stream.h (mu_stream_err): New proto.
* libproto/mbox/mbox.c (_msg_stream_setup)
(_msg_body_setup): Fix stream abridgement.
(mbox_envelope_date, mbox_envelope_sender): Fix seek position.
(uid_to_stream): Fix invocation of mu_stream_printf.
(append_message_to_stream): Likewise.
(mbox_expunge_unlocked): Rewind tempstr before copying its
contents back to the mailbox.
(mbox_expunge0): Open tempstr.
* libproto/mbox/mbox0.h (_mbox_message)<header_from>: Rename to
envel_from.
<header_from_end>: Rename to envel_from_end. All uses changed.
* libproto/mbox/mboxscan.c: Minor changes.

* mail/decode.c: Use streamrefs.
* mail/escape.c: Likewise.
* mail/msgset.y: Likewise.
* mail/pipe.c: Likewise.
* mail/print.c: Likewise.
* mail/top.c: Likewise.
* mail/write.c: Likewise.

* mail/send.c: Use streamrefs.
(mail_send0): Reset env->header after assigning it to
the message.

* mailbox/body.c (_body_seek): Fix a typo which produced
a recursive call.
* mailbox/file_stream.c (fd_truncate): New function.
(_mu_file_stream_create): Initialize str->stream.truncate.

* mailbox/header.c (header_parse): Fix parsing of blurbs lacking
terminating empty line.
(header_seek): Fix boundary checks.
Return new position in presult.
* mailbox/message.c (string_find_eoh): Rewrite to handle \n\n
split between two successive invocations.
(_header_fill): Update the invocation of string_find_eoh.

* mailbox/stream.c (mu_stream_destroy): Call mu_stream_close.
(mu_stream_get_flags, mu_stream_set_flags)
(mu_stream_clr_flags): Ignore internal
bits.
(mu_stream_err): New function.
(mu_stream_close): Close the stream only if it is not used by anyone else.
* mailbox/streamref.c (_streamref_read): Clear transport error if
ESPIPE is returned.
(_streamref_size): Take into account sp->end and sp->start.
(mu_streamref_create_abridged): Set pointer to 0.
1 parent f900b3b0
......@@ -65,6 +65,7 @@ void mu_stream_unref (mu_stream_t stream);
void mu_stream_destroy (mu_stream_t *pstream);
int mu_stream_open (mu_stream_t stream);
const char *mu_stream_strerror (mu_stream_t stream, int rc);
int mu_stream_err (mu_stream_t stream);
int mu_stream_last_error (mu_stream_t stream);
void mu_stream_clearerr (mu_stream_t stream);
int mu_stream_eof (mu_stream_t stream);
......
......@@ -259,7 +259,7 @@ static int
mbox_message_qid (mu_message_t msg, mu_message_qid_t *pqid)
{
mbox_message_t mum = mu_message_get_owner (msg);
return mu_asprintf (pqid, "%lu", (unsigned long) mum->header_from);
return mu_asprintf (pqid, "%lu", (unsigned long) mum->envel_from);
}
......@@ -297,8 +297,8 @@ _msg_stream_setup (mu_message_t msg, mbox_message_t mum)
status = mu_streamref_create_abridged (&stream,
mum->mud->mailbox->stream,
mum->header_from_end + 1,
mum->body);
mum->envel_from_end,
mum->body_end);
if (status == 0)
status = mu_message_set_stream (msg, stream, mum);
return status;
......@@ -343,7 +343,7 @@ _msg_body_setup (mu_message_t msg, mbox_message_t mum)
status = mu_streamref_create_abridged (&stream,
mum->mud->mailbox->stream,
mum->body,
mum->body_end);
mum->body_end - 1);
if (status)
mu_body_destroy (&body, msg);
else
......@@ -373,7 +373,7 @@ mbox_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
return EINVAL;
status = mu_stream_seek (mum->mud->mailbox->stream,
mum->header_from, MU_SEEK_SET,
mum->envel_from, MU_SEEK_SET,
NULL);
if (status)
return status;
......@@ -419,7 +419,7 @@ mbox_envelope_sender (mu_envelope_t envelope, char *buf, size_t len,
return EINVAL;
status = mu_stream_seek (mum->mud->mailbox->stream,
mum->header_from, MU_SEEK_SET,
mum->envel_from, MU_SEEK_SET,
NULL);
if (status)
return status;
......@@ -1022,8 +1022,10 @@ uid_to_stream (mu_stream_t ostr, mu_message_t msg, mbox_data_t mud, int flags)
else
uid = mud->uidnext++;
return mu_stream_printf (ostr, "%s: %u\n", MU_HEADER_X_UID,
(unsigned) uid);
mu_stream_printf (ostr, "%s: %u\n", MU_HEADER_X_UID, (unsigned) uid);
if (mu_stream_err (ostr))
return mu_stream_last_error (ostr);
return 0;
}
/* Append MSG to stream OSTR in its current position */
......@@ -1048,12 +1050,14 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg,
if (flags & MBOX_FIRSTMSG)
{
status = mu_stream_printf (ostr, "%s: %lu %u\n",
/* FIXME: Perhaps printf should return error code,
like the rest of stream functions. */
mu_stream_printf (ostr, "%s: %lu %u\n",
MU_HEADER_X_IMAPBASE,
(unsigned long) mud->uidvalidity,
(unsigned) mud->uidnext);
if (status)
return status;
if (mu_stream_err (ostr))
return mu_stream_last_error (ostr);
}
status = msg_attr_to_stream (ostr, msg);
......@@ -1165,7 +1169,7 @@ mbox_reset (mu_mailbox_t mailbox, size_t dirty, int remove_deleted)
else
memset (mum, 0, sizeof (*mum));
}
mum->header_from = mum->header_from_end = 0;
mum->envel_from = mum->envel_from_end = 0;
mum->body = mum->body_end = 0;
mum->header_lines = mum->body_lines = 0;
}
......@@ -1187,7 +1191,7 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
mu_off_t size;
/* Set the marker position. */
start_off = mud->umessages[dirty]->header_from;
start_off = mud->umessages[dirty]->envel_from;
for (i = dirty; i < mud->messages_count; i++)
{
......@@ -1226,8 +1230,8 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
status = mbox_get_message (mailbox, i + 1, &msg);
if (status != 0)
{
mu_error (_("error expunging:%d: %s"), __LINE__,
mu_strerror (status));
mu_error (_("%s:%d: error expunging: %s"),
__FILE__, __LINE__, mu_strerror (status));
return status;
}
}
......@@ -1235,8 +1239,8 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
flags);
if (status != 0)
{
mu_error (_("error expunging:%d: %s"), __LINE__,
mu_strerror (status));
mu_error (_("%s:%d: error expunging: %s"),
__FILE__, __LINE__, mu_strerror (status));
return status;
}
/* Clear the dirty bits. */
......@@ -1247,7 +1251,7 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
{
/* Otherwise, copy bits from mailbox->stream as is. */
status = mu_stream_seek (mailbox->stream, mum->header_from,
status = mu_stream_seek (mailbox->stream, mum->envel_from,
MU_SEEK_SET, NULL);
if (status)
{
......@@ -1257,7 +1261,7 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
return status;
}
status = mu_stream_copy (tempstr, mailbox->stream,
mum->body_end - mum->header_from);
mum->body_end - mum->envel_from);
if (status)
{
mu_error (_("%s:%d: error copying: %s"),
......@@ -1336,10 +1340,19 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
return status;
}
status = mu_stream_seek (tempstr, 0, MU_SEEK_SET, NULL);
if (status)
{
mu_error (_("%s:%d: seek error: %s"),
__FILE__, __LINE__,
mu_stream_strerror (mailbox->stream, status));
return status;
}
status = mu_stream_copy (mailbox->stream, tempstr, size);
if (status)
{
mu_error (_("%s:%d: error writing to temporary stream: %s"),
mu_error (_("%s:%d: copying from the temporary stream: %s"),
__FILE__, __LINE__,
mu_strerror (status));
return status;
......@@ -1395,6 +1408,9 @@ mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted)
status = mu_temp_file_stream_create (&tempstr, NULL);
if (status == 0)
{
status = mu_stream_open (tempstr);
if (status == 0)
{
sigset_t signalset;
#ifdef WITH_PTHREAD
int state;
......@@ -1408,7 +1424,8 @@ mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted)
sigaddset (&signalset, SIGWINCH);
sigprocmask (SIG_BLOCK, &signalset, 0);
status = mbox_expunge_unlocked (mailbox, dirty, remove_deleted, tempstr);
status = mbox_expunge_unlocked (mailbox, dirty, remove_deleted,
tempstr);
#ifdef WITH_PTHREAD
pthread_setcancelstate (state, &state);
......@@ -1420,6 +1437,7 @@ mbox_expunge0 (mu_mailbox_t mailbox, int remove_deleted)
if (status == 0)
mbox_reset (mailbox, dirty, remove_deleted);
}
}
mu_locker_unlock (mailbox->locker);
return status;
}
......
......@@ -71,8 +71,8 @@ typedef struct _mbox_message *mbox_message_t;
struct _mbox_message
{
/* Offset of the messages in the mailbox. */
mu_off_t header_from; /* Start of envelope (^From ) */
mu_off_t header_from_end; /* End of envelope (terminating \n) */
mu_off_t envel_from; /* Start of envelope (^From ) */
mu_off_t envel_from_end; /* End of envelope (terminating \n) */
mu_off_t body; /* Start of body */
mu_off_t body_end; /* End of body */
......
......@@ -359,11 +359,10 @@ mbox_scan_internal (mu_mailbox_t mailbox, mbox_message_t mum,
}
/* Allocate_msgs will initialize mum. */
ALLOCATE_MSGS (mailbox, mud);
mud->messages_count++;
mum = mud->umessages[mud->messages_count - 1];
mum = mud->umessages[mud->messages_count++];
mum->mud = mud;
mum->header_from = total - n;
mum->header_from_end = total;
mum->envel_from = total - n;
mum->envel_from_end = total;
mum->body_end = mum->body = 0;
mum->attr_flags = 0;
lines = 0;
......@@ -467,7 +466,7 @@ mbox_scan0 (mu_mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
{
mum = mud->umessages[msgno - 1];
if (mum)
total = mum->header_from;
total = mum->envel_from;
mud->messages_count = msgno - 1;
}
else
......
......@@ -116,8 +116,11 @@ display_headers (FILE *out, mu_message_t mesg,
{
mu_stream_t stream = NULL;
if (mu_message_get_header (mesg, &hdr) == 0
&& mu_header_get_stream (hdr, &stream) == 0)
&& mu_header_get_streamref (hdr, &stream) == 0)
{
print_stream (stream, out);
mu_stream_destroy (&stream);
}
}
}
......@@ -254,10 +257,10 @@ display_submessage (struct mime_descend_closure *closure, void *data)
mu_message_get_body (closure->message, &body);
mu_message_get_header (closure->message, &hdr);
mu_body_get_stream (body, &b_stream);
mu_body_get_streamref (body, &b_stream);
/* Can we decode. */
if (mu_filter_create(&d_stream, b_stream, closure->encoding,
if (mu_filter_create (&d_stream, b_stream, closure->encoding,
MU_FILTER_DECODE,
MU_STREAM_READ|MU_STREAM_NO_CLOSE) == 0)
stream = d_stream;
......@@ -303,13 +306,13 @@ display_submessage (struct mime_descend_closure *closure, void *data)
if (out != ofile)
pclose (out);
}
if (d_stream)
mu_stream_destroy (&d_stream);
mu_stream_destroy (&stream);
}
return 0;
}
/* FIXME: Try to use mu_stream_copy instead */
static int
print_stream (mu_stream_t stream, FILE *out)
{
......@@ -317,12 +320,6 @@ print_stream (mu_stream_t stream, FILE *out)
size_t n = 0;
int rc;
rc = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (rc)
{
util_error (_("seek error: %s"), mu_stream_strerror (stream, rc));
return rc;
}
while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, &n) == 0
&& n != 0)
{
......@@ -397,20 +394,18 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg)
{
/* Child process */
int status;
mu_stream_t stream;
mu_stream_t stream = NULL;
do /* Fake loop to avoid gotos */
{
mu_stream_t pstr;
char buffer[512];
size_t n;
char *no_ask;
setenv ("METAMAIL_PAGER", getenv ("PAGER"), 0);
if (mailvar_get (&no_ask, "mimenoask", mailvar_type_string, 0))
setenv ("MM_NOASK", no_ask, 1);
status = mu_message_get_stream (mesg, &stream);
status = mu_message_get_streamref (mesg, &stream);
if (status)
{
mu_error ("mu_message_get_stream: %s", mu_strerror (status));
......@@ -430,12 +425,7 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg)
mu_error ("mu_stream_open: %s", mu_strerror (status));
break;
}
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
while (mu_stream_read (stream, buffer, sizeof buffer - 1,
&n) == 0
&& n > 0)
mu_stream_write (pstr, buffer, n, NULL);
mu_stream_copy (pstr, stream, 0);
mu_stream_close (pstr);
mu_stream_destroy (&pstr);
exit (0);
......
......@@ -30,19 +30,21 @@ dump_headers (FILE *fp, compose_env_t *env)
size_t n;
int rc;
mu_header_get_stream (env->header, &stream);
rc = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
rc = mu_header_get_streamref (env->header, &stream);
if (rc)
{
util_error (_("seek error: %s"), mu_stream_strerror (stream, rc));
util_error ("mu_header_get_streamref: %s",
mu_stream_strerror (stream, rc));
return;
}
/* FIXME: Use mu_stream_copy */
while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
&& n != 0)
{
buffer[n] = 0;
fprintf (fp, "%s", buffer);
}
mu_stream_destroy (&stream);
}
#define STATE_INIT 0
......@@ -478,24 +480,25 @@ quote0 (msgset_t *mspec, mu_message_t mesg, void *data)
}
fprintf (ofile, "%s\n", prefix);
mu_message_get_body (mesg, &body);
mu_body_get_stream (body, &stream);
rc = mu_body_get_streamref (body, &stream);
}
else
mu_message_get_stream (mesg, &stream);
rc = mu_message_get_streamref (mesg, &stream);
rc = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (rc)
{
util_error (_("seek error: %s"), mu_stream_strerror (stream, rc));
util_error (_("get_streamref error: %s"), mu_strerror (rc));
return rc;
}
/* FIXME: Use mu_stream_copy? */
while (mu_stream_readline (stream, buffer, sizeof buffer - 1, &n) == 0
&& n != 0)
{
buffer[n] = '\0';
fprintf (ofile, "%s%s", prefix, buffer);
}
mu_stream_destroy (&stream);
return 0;
}
......
......@@ -629,8 +629,7 @@ select_body (mu_message_t msg, void *closure)
mu_message_get_body (msg, &body);
mu_body_size (body, &size);
mu_body_lines (body, &lines);
mu_body_get_stream (body, &stream);
status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
status = mu_body_get_streamref (body, &stream);
while (status == 0
&& mu_stream_readline (stream, buffer, sizeof(buffer)-1, &n) == 0
&& n > 0)
......@@ -643,7 +642,7 @@ select_body (mu_message_t msg, void *closure)
else
status = regexec (&re, buffer, 0, NULL, 0);
}
mu_stream_destroy (&stream);
if (!noregex)
regfree (&re);
......
......@@ -49,14 +49,15 @@ mail_pipe (int argc, char **argv)
{
if (util_get_message (mbox, mp->msg_part[0], &msg) == 0)
{
mu_message_get_stream (msg, &stream);
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
mu_message_get_streamref (msg, &stream);
/* FIXME: Use mu_stream_copy */
while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, &n) == 0
&& n != 0)
{
buffer[n] = '\0';
fprintf (tube, "%s", buffer);
}
mu_stream_destroy (&stream);
if (mailvar_get (NULL, "page", mailvar_type_boolean, 0) == 0)
fprintf (tube, "\f\n");
}
......
......@@ -36,6 +36,7 @@ mail_print_msg (msgset_t *mspec, mu_message_t mesg, void *data)
size_t n = 0, lines = 0;
FILE *out = ofile;
int pagelines = util_get_crt ();
int status;
mu_message_lines (mesg, &lines);
if (mailvar_get (NULL, "showenvelope", mailvar_type_boolean, 0) == 0)
......@@ -89,12 +90,18 @@ mail_print_msg (msgset_t *mspec, mu_message_t mesg, void *data)
}
fprintf (out, "\n");
mu_message_get_body (mesg, &body);
mu_body_get_stream (body, &stream);
status = mu_body_get_streamref (body, &stream);
}
else
mu_message_get_stream (mesg, &stream);
status = mu_message_get_streamref (mesg, &stream);
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (status)
{
mu_error (_("get_stream error: %s"), mu_strerror (status));
return 0;
}
/* FIXME: Use mu_stream_copy instead? */
while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
&& n != 0)
{
......@@ -106,6 +113,7 @@ mail_print_msg (msgset_t *mspec, mu_message_t mesg, void *data)
buffer[n] = '\0';
fprintf (out, "%s", buffer);
}
mu_stream_destroy (&stream);
if (out != ofile)
pclose (out);
......
......@@ -293,36 +293,37 @@ compose_header_get (compose_env_t * env, char *name, char *defval)
}
void
compose_destroy (compose_env_t * env)
compose_destroy (compose_env_t *env)
{
mu_header_destroy (&env->header);
free (env->outfiles);
}
/* FIXME: Can we use mu_stream_t instead of FILE? If so,
replace the loop with a call to mu_stream_copy. */
static int
fill_body (mu_message_t msg, FILE *file)
{
mu_body_t body = NULL;
mu_stream_t stream = NULL;
off_t offset = 0;
char *buf = NULL;
size_t n = 0;
mu_message_get_body (msg, &body);
mu_body_get_stream (body, &stream);
mu_body_get_streamref (body, &stream);
int nullbody = 1;
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
offset = 0;
while (getline (&buf, &n, file) >= 0)
{
size_t len = strlen (buf);
if (len)
nullbody = 0;
mu_stream_write (stream, buf, len, NULL);
offset += len;
}
mu_stream_destroy (&stream);
if (buf)
free (buf);
if (offset == 0)
if (nullbody)
{
if (mailvar_get (NULL, "nullbody", mailvar_type_boolean, 0) == 0)
{
......@@ -525,7 +526,6 @@ mail_send0 (compose_env_t * env, int save_to)
int rc;
mu_message_create (&msg, NULL);
mu_message_set_header (msg, env->header, NULL);
/* Fill the body. */
rc = fill_body (msg, file);
......@@ -599,6 +599,8 @@ mail_send0 (compose_env_t * env, int save_to)
if (mailvar_get (&sendmail, "sendmail",
mailvar_type_string, 0) == 0)
{
mu_message_set_header (msg, env->header, NULL);
env->header = NULL;
if (sendmail[0] == '/')
msg_to_pipe (sendmail, msg);
else
......@@ -669,14 +671,15 @@ msg_to_pipe (const char *cmd, mu_message_t msg)
mu_stream_t stream = NULL;
char buffer[512];
size_t n = 0;
mu_message_get_stream (msg, &stream);
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
/* FIXME: Use mu_stream_copy */
mu_message_get_streamref (msg, &stream);
while (mu_stream_read (stream, buffer, sizeof buffer - 1, &n) == 0
&& n != 0)
{
buffer[n] = '\0';
fprintf (fp, "%s", buffer);
}
mu_stream_destroy (&stream);
pclose (fp);
}
else
......
......@@ -35,8 +35,8 @@ top0 (msgset_t *mspec, mu_message_t msg, void *data)
|| lines < 0)
return 1;
mu_message_get_stream (msg, &stream);
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
/* FIXME: Use mu_stream_copy */
mu_message_get_streamref (msg, &stream);
for (; lines > 0; lines--)
{
int status = mu_stream_readline (stream, buf, sizeof (buf), &n);
......@@ -44,6 +44,7 @@ top0 (msgset_t *mspec, mu_message_t msg, void *data)
break;
fprintf (ofile, "%s", buf);
}
mu_stream_destroy (&stream);
set_cursor (mspec->msg_part[0]);
util_mark_read (msg);
......
......@@ -98,8 +98,8 @@ mail_write (int argc, char **argv)
mu_body_lines (bod, &size);
total_lines += size;
mu_body_get_stream (bod, &stream);
mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
/* FIXME: Use mu_stream_copy */
mu_body_get_streamref (bod, &stream);
/* should there be a separator? */
while (mu_stream_read (stream, buffer, sizeof (buffer) - 1, &n) == 0
&& n != 0)
......@@ -107,6 +107,7 @@ mail_write (int argc, char **argv)
buffer[n] = '\0';
fprintf (output, "%s", buffer);
}
mu_stream_destroy (&stream);
/* mark as saved. */
......
......@@ -285,7 +285,7 @@ _body_seek (mu_stream_t stream, mu_off_t off, int whence, mu_off_t *presult)
{
struct _mu_body_stream *str = (struct _mu_body_stream*) stream;
mu_body_t body = str->body;
return mu_stream_seek (body->stream, off, whence, presult);
return mu_stream_seek (body->fstream, off, whence, presult);
}
static const char *
......
......@@ -221,6 +221,15 @@ fd_wait (mu_stream_t stream, int *pflags, struct timeval *tvp)
}
int
fd_truncate (mu_stream_t stream, mu_off_t size)
{
struct _mu_file_stream *fstr = (struct _mu_file_stream *) stream;
if (ftruncate (fstr->fd, size))
return errno;
return 0;
}
int
_mu_file_stream_create (mu_stream_t *pstream, size_t size,
char *filename, int flags)
{
......@@ -239,6 +248,7 @@ _mu_file_stream_create (mu_stream_t *pstream, size_t size,
str->stream.size = fd_size;
str->stream.ctl = fd_ioctl;
str->stream.wait = fd_wait;
str->stream.truncate = fd_truncate;
str->stream.error_string = fd_error_string;
str->filename = filename;
......
......@@ -329,7 +329,7 @@ header_parse (mu_header_t header, const char *blurb, int len)
*[ (' ' | '\t') field-value '\r' '\n' ]
*/
/* First loop goes through the blurb */
for (header_start = blurb; ; header_start = ++header_end)
for (header_start = blurb; len > 0; header_start = ++header_end)
{
const char *fn, *fn_end, *fv, *fv_end;
struct mu_hdrent *ent;
......@@ -340,7 +340,7 @@ header_parse (mu_header_t header, const char *blurb, int len)
break;
/* Second loop extract one header field. */
for (header_start2 = header_start; ;header_start2 = ++header_end)
for (header_start2 = header_start; len; header_start2 = ++header_end)
{
header_end = memchr (header_start2, '\n', len);
if (header_end == NULL)
......@@ -348,21 +348,14 @@ header_parse (mu_header_t header, const char *blurb, int len)
else
{
len -= (header_end - header_start2 + 1);
if (len < 0)
{
header_end = NULL;
break;
}
if (header_end[1] != ' '
&& header_end[1] != '\t')
if (!len
|| (header_end[1] != ' '
&& header_end[1] != '\t'))
break; /* New header break the inner for. */
}
/* *header_end = ' '; smash LF ? NO */
}
if (header_end == NULL)
break; /* FIXME: Bail out. */
/* Now save the header in the data structure. */
/* Treats unix "From " specially. FIXME: Should we? */
......@@ -956,9 +949,10 @@ header_seek (mu_stream_t str, mu_off_t off, int whence, mu_off_t *presult)
break;
}
if (off < 0 || off >= hstr->hdr->size)
if (off < 0 || off > hstr->hdr->size)
return ESPIPE;
hstr->off = off;
*presult = off;
return 0;
}
......
......@@ -270,21 +270,35 @@ _message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags)
}
enum eoh_state
{
eoh_no,
eoh_maybe,
eoh_yes
};
/* Message header stuff */
static int
string_find_eoh (const char *str, size_t len, size_t *ppos)
static enum eoh_state
string_find_eoh (enum eoh_state eoh, const char *str, size_t len,
size_t *ppos)
{
size_t pos;
int eoh = 0;
for (pos = 0; pos < len-1; pos++)
if (str[pos] == '\n' && str[pos+1] == '\n')
if (eoh == eoh_maybe && *str == '\n')
{
eoh = 1;
break;
*ppos = 0;
return eoh_yes;
}
for (pos = 0; pos < len - 1; pos++)
if (str[pos] == '\n' && str[pos + 1] == '\n')
{
*ppos = pos + 1;
return eoh_yes;
}
*ppos = pos + 1;
return eoh;
return str[pos] == '\n' ? eoh_maybe : eoh_no;
}
#define MIN_HEADER_BUF_SIZE 2048
......@@ -297,17 +311,21 @@ _header_fill (mu_stream_t stream, char **pbuf, size_t *plen)
size_t bufsize = 0;
char inbuf[MIN_HEADER_BUF_SIZE];
size_t nread;
enum eoh_state eoh = eoh_no;
status = mu_stream_seek (stream, 0, MU_SEEK_SET, NULL);
if (status)
return status;
while ((status = mu_stream_read (stream, inbuf, sizeof (inbuf), &nread))
== 0 && nread)
while (eoh != eoh_yes
&& (status = mu_stream_read (stream, inbuf, sizeof (inbuf), &nread))
== 0
&& nread)
{
char *nbuf;
size_t len;
int eoh = string_find_eoh (inbuf, nread, &len);
eoh = string_find_eoh (eoh, inbuf, nread, &len);
nbuf = realloc (buffer, bufsize + len);
if (!nbuf)
......@@ -318,8 +336,6 @@ _header_fill (mu_stream_t stream, char **pbuf, size_t *plen)
memcpy (nbuf + bufsize, inbuf, len);
buffer = nbuf;
bufsize += len;
if (eoh)
break;
}
if (status)
......
......@@ -53,7 +53,7 @@ _stream_seterror (struct _mu_stream *stream, int code, int perm)
#define _stream_cleareof(s) ((s)->flags &= ~_MU_STR_EOF)
#define _stream_advance_buffer(s,n) ((s)->cur += n, (s)->level -= n)
#define _stream_buffer_offset(s) ((s)->cur - (s)->buffer)
#define _stream_orig_level(s) ((s)->level + _stream_buffer_offset(s))
#define _stream_orig_level(s) ((s)->level + _stream_buffer_offset (s))
static int
_stream_fill_buffer (struct _mu_stream *stream)
......@@ -202,6 +202,7 @@ mu_stream_destroy (mu_stream_t *pstream)
mu_stream_t str = *pstream;
if (str && (str->ref_count == 0 || --str->ref_count == 0))
{
mu_stream_close (str);
if (str->done)
str->done (str);
free (str);
......@@ -213,7 +214,7 @@ mu_stream_destroy (mu_stream_t *pstream)
void
mu_stream_get_flags (mu_stream_t str, int *pflags)
{
*pflags = str->flags;
*pflags = str->flags & ~_MU_STR_INTERN_MASK;
}
void
......@@ -252,6 +253,12 @@ mu_stream_strerror (mu_stream_t stream, int rc)
}
int
mu_stream_err (mu_stream_t stream)
{
return stream->flags & _MU_STR_ERR;
}
int
mu_stream_last_error (mu_stream_t stream)
{
return stream->last_err;
......@@ -700,6 +707,9 @@ mu_stream_close (mu_stream_t stream)
if (!stream)
return EINVAL;
mu_stream_flush (stream);
/* Do close the stream only if it is not used by anyone else */
if (stream->ref_count > 1)
return 0;
if (stream->close)
rc = stream->close (stream);
return rc;
......@@ -785,7 +795,7 @@ mu_stream_set_flags (mu_stream_t stream, int fl)
{
if (stream == NULL)
return EINVAL;
stream->flags |= fl;
stream->flags |= (fl & ~_MU_STR_INTERN_MASK);
return 0;
}
......@@ -794,7 +804,7 @@ mu_stream_clr_flags (mu_stream_t stream, int fl)
{
if (stream == NULL)
return EINVAL;
stream->flags &= ~fl;
stream->flags &= ~(fl & ~_MU_STR_INTERN_MASK);
return 0;
}
......
......@@ -62,7 +62,7 @@ _streamref_read (struct _mu_stream *str, char *buf, size_t bufsize,
else if (rc == ESPIPE)
{
*pnread = 0;
str->flags |= _MU_STR_EOF;
mu_stream_clearerr (sp->transport);
return 0;
}
return streamref_return (sp, rc);
......@@ -170,7 +170,21 @@ static int
_streamref_size (struct _mu_stream *str, mu_off_t *psize)
{
struct _mu_streamref *sp = (struct _mu_streamref *)str;
return streamref_return (sp, mu_stream_size (sp->transport, psize));
mu_off_t size;
int rc = 0;
if (sp->end)
size = sp->end - sp->start + 1;
else
{
rc = mu_stream_size (sp->transport, &size);
if (rc)
return streamref_return (sp, rc);
size -= sp->start;
}
if (rc == 0)
*psize = size;
return rc;
}
static int
......@@ -240,12 +254,11 @@ mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str,
int flags;
struct _mu_streamref *sp;
rc = mu_stream_seek (str, 0, MU_SEEK_CUR, &off);
rc = mu_stream_seek (str, 0, MU_SEEK_SET, &off);
if (rc)
return rc;
mu_stream_get_flags (str, &flags);
sp = (struct _mu_streamref *) _mu_stream_create (sizeof (*sp),
flags | MU_STREAM_NO_CLOSE);
sp = (struct _mu_streamref *) _mu_stream_create (sizeof (*sp), flags);
if (!sp)
return ENOMEM;
mu_stream_ref (str);
......