Commit 7bfe0ed9 7bfe0ed907c5300d68fea2f2d4e53bac6dc78b60 by Sergey Poznyakoff

Finish pop3 mailbox implementation.

* mailbox/msgscan.c: New file.
* mailbox/Makefile.am (libmailutils_la_SOURCES): Add it.

* include/mailutils/body.h (mu_body_set_get_stream): New prototype.
* include/mailutils/message.h (MU_SCAN_SEEK, MU_SCAN_SIZE): New
defines.
(mu_message_scan): New structure.
(mu_stream_scan_message): New prototype.
(mu_message_set_get_stream): New prototype.
* include/mailutils/stream.h (mu_stream_copy): Change signature: takes
4 arguments now.
* include/mailutils/sys/body.h (_mu_body) <_get_stream>: New method.
* include/mailutils/sys/message.h (_mu_message) <_get_stream>: New method.
* mailbox/body.c (_body_get_stream): Call _get_stream, if provided.
* mailbox/message.c (_message_get_stream): Call _get_stream, if provided.

* mailbox/stream.c (_stream_flush_buffer): Avoid infinite recursion:
call stream->seek directly.
* mailbox/streamcpy.c (mu_stream_copy): Return the number of bytes
actually copied in the fourth argument. All uses updated.
* mailbox/streamref.c (streamref_return): Do not propagate internal
flags.
(_streamref_readdelim): Ensure there is enough buffer space for the
mu_stream_readdelim call.

* libproto/pop/mbox.c: Finish client implementation.

* mail/print.c (mail_print_msg): Close pager before returning on
error.
1 parent 62c5c62a
......@@ -55,7 +55,7 @@ c_copy (mu_stream_t out, mu_stream_t in)
}
}
else
MU_ASSERT (mu_stream_copy (out, in, 0));
MU_ASSERT (mu_stream_copy (out, in, 0, NULL));
mu_stream_write (out, "\n", 1, NULL);
mu_stream_close (out);
mu_stream_close (in);
......
......@@ -69,14 +69,14 @@ main (int argc, char * argv [])
MU_ASSERT (mu_stream_seek (in, skip_off, MU_SEEK_SET, NULL));
}
MU_ASSERT (mu_stream_copy (out, in, 0));
MU_ASSERT (mu_stream_copy (out, in, 0, NULL));
if (reread_option)
{
mu_stream_printf (out, "rereading from %lu:\n",
(unsigned long) reread_off);
MU_ASSERT (mu_stream_seek (in, reread_off, MU_SEEK_SET, NULL));
MU_ASSERT (mu_stream_copy (out, in, 0));
MU_ASSERT (mu_stream_copy (out, in, 0, NULL));
}
mu_stream_close (in);
......
......@@ -152,7 +152,7 @@ sc2string (int rc)
int
io_copy_out (mu_stream_t str, size_t size)
{
return mu_stream_copy (iostream, str, size);
return mu_stream_copy (iostream, str, size, NULL);
}
int
......
......@@ -36,6 +36,9 @@ extern int mu_body_get_stream (mu_body_t, mu_stream_t *)
__attribute__ ((deprecated));
extern int mu_body_get_streamref (mu_body_t body, mu_stream_t *pstream);
extern int mu_body_set_stream (mu_body_t, mu_stream_t, void *owner);
extern int mu_body_set_get_stream (mu_body_t,
int (*) (mu_body_t, mu_stream_t *),
void *owner);
extern int mu_body_get_filename (mu_body_t, char *, size_t, size_t *);
......
......@@ -26,6 +26,25 @@
extern "C" {
#endif
#define MU_SCAN_SEEK 0x01
#define MU_SCAN_SIZE 0x02
struct mu_message_scan
{
int flags;
mu_off_t message_start;
mu_off_t message_size;
mu_off_t body_start;
mu_off_t body_end;
size_t header_lines;
size_t body_lines;
int attr_flags;
unsigned long uidvalidity;
};
int mu_stream_scan_message (mu_stream_t stream, struct mu_message_scan *sp);
/* A message is considered to be a container for:
mu_header_t, mu_body_t, and its mu_attribute_t. */
......@@ -34,7 +53,7 @@ extern void mu_message_destroy (mu_message_t *, void *owner);
extern int mu_message_create_copy (mu_message_t *to, mu_message_t from);
extern void * mu_message_get_owner (mu_message_t);
extern void *mu_message_get_owner (mu_message_t);
extern int mu_message_is_modified (mu_message_t);
extern int mu_message_clear_modified (mu_message_t);
extern int mu_message_get_mailbox (mu_message_t, mu_mailbox_t *);
......@@ -64,6 +83,9 @@ extern int mu_message_set_attribute (mu_message_t, mu_attribute_t, void *);
extern int mu_message_get_observable (mu_message_t, mu_observable_t *);
extern int mu_message_set_get_stream (mu_message_t,
int (*) (mu_message_t, mu_stream_t *),
void *);
extern int mu_message_is_multipart (mu_message_t, int *);
extern int mu_message_set_is_multipart (mu_message_t,
int (*_is_multipart) (mu_message_t,
......
......@@ -115,7 +115,8 @@ int mu_stream_clr_flags (mu_stream_t stream, int fl);
int mu_stream_vprintf (mu_stream_t str, const char *fmt, va_list ap);
int mu_stream_printf (mu_stream_t stream, const char *fmt, ...);
int mu_stream_copy (mu_stream_t dst, mu_stream_t src, size_t size);
int mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size,
mu_off_t *pcsz);
int mu_file_stream_create (mu_stream_t *pstream, const char *filename, int flags);
......
......@@ -40,6 +40,7 @@ struct _mu_body
int (*_size) (mu_body_t, size_t*);
int (*_lines) (mu_body_t, size_t*);
int (*_get_stream) (mu_body_t, mu_stream_t *);
};
#ifdef __cplusplus
......
......@@ -52,6 +52,7 @@ struct _mu_message
/* Reference count. */
int ref;
int (*_get_stream) (mu_message_t, mu_stream_t *);
int (*_get_uidl) (mu_message_t, char *, size_t, size_t *);
int (*_get_uid) (mu_message_t, size_t *);
int (*_get_qid) (mu_message_t, mu_message_qid_t *);
......
......@@ -219,7 +219,7 @@ SCM_DEFINE_PUBLIC (scm_mu_message_copy, "mu-message-copy", 1, 0, 0,
"Cannot get output stream", SCM_BOOL_F);
}
status = mu_stream_copy (out, in, 0);
status = mu_stream_copy (out, in, 0, NULL);
mu_stream_destroy (&in);
mu_stream_destroy (&out);
if (status)
......
......@@ -252,7 +252,7 @@ mime_create_quote (mu_mime_t mime, mu_message_t msg)
mu_body_get_streamref (body, &ostream);
mu_message_get_streamref (msg, &istream);
rc = mu_stream_copy (ostream, istream, 0);
rc = mu_stream_copy (ostream, istream, 0, NULL);
mu_stream_destroy (&istream);
mu_stream_close (ostream);
......
......@@ -118,7 +118,7 @@ sieve_action_pipe (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
ONERR (rc, _("stream write failed"), NULL);
}
rc = mu_stream_copy (pstr, mstr, 0);
rc = mu_stream_copy (pstr, mstr, 0, NULL);
ONERR (rc, _("command failed"), cmd);
}
while (0);
......
......@@ -117,7 +117,7 @@ spamd_send_message (mu_stream_t stream, mu_message_t msg)
return rc;
}
rc = mu_stream_copy (stream, flt, 0);
rc = mu_stream_copy (stream, flt, 0, NULL);
mu_stream_destroy (&mstr);
mu_stream_destroy (&flt);
......
......@@ -111,7 +111,7 @@ build_mime (mu_sieve_machine_t mach, mu_list_t tags, mu_mime_t *pmime,
}
mu_stream_seek (input, 0, MU_SEEK_SET, NULL);
rc = mu_stream_copy (stream, input, 0);
rc = mu_stream_copy (stream, input, 0, NULL);
if (rc)
{
mu_sieve_error (mach,
......
......@@ -1086,7 +1086,7 @@ append_message_to_stream (mu_stream_t ostr, mu_message_t msg,
if (status)
return status;
}
status = mu_stream_copy (ostr, istr, 0);
status = mu_stream_copy (ostr, istr, 0, NULL);
mu_stream_destroy (&istr);
if (status == 0)
status = mu_stream_write (ostr, "\n", 1, NULL);
......@@ -1264,7 +1264,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->envel_from);
mum->body_end - mum->envel_from, NULL);
if (status)
{
mu_error (_("%s:%d: error copying: %s"),
......@@ -1295,7 +1295,7 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
return status;
}
status = mu_stream_copy (tempstr, mailbox->stream, len);
status = mu_stream_copy (tempstr, mailbox->stream, len, NULL);
if (status)
{
mu_error (_("%s:%d: error writing to temporary stream: %s"),
......@@ -1342,7 +1342,7 @@ mbox_expunge_unlocked (mu_mailbox_t mailbox, size_t dirty, int remove_deleted,
return status;
}
status = mu_stream_copy (mailbox->stream, tempstr, size);
status = mu_stream_copy (mailbox->stream, tempstr, size, NULL);
if (status)
{
mu_error (_("%s:%d: copying from the temporary stream: %s"),
......
......@@ -424,7 +424,7 @@ run_metamail (const char *mailcap_cmd, mu_message_t mesg)
mu_error ("mu_stream_open: %s", mu_strerror (status));
break;
}
mu_stream_copy (pstr, stream, 0);
mu_stream_copy (pstr, stream, 0, NULL);
mu_stream_close (pstr);
mu_stream_destroy (&pstr);
exit (0);
......
......@@ -98,6 +98,8 @@ mail_print_msg (msgset_t *mspec, mu_message_t mesg, void *data)
if (status)
{
mu_error (_("get_stream error: %s"), mu_strerror (status));
if (out != ofile)
pclose (out);
return 0;
}
......
......@@ -108,6 +108,7 @@ libmailutils_la_SOURCES = \
mimehdr.c\
mkfilename.c\
monitor.c\
msgscan.c\
msrv.c\
mu_auth.c\
muctype.c\
......
......@@ -161,6 +161,14 @@ _body_get_stream (mu_body_t body, mu_stream_t *pstream, int ref)
if (body->stream == NULL)
{
if (body->_get_stream)
{
int status = body->_get_stream (body, &body->stream);
if (status)
return status;
}
else
{
int status;
struct _mu_body_stream *str =
(struct _mu_body_stream *)
......@@ -191,6 +199,8 @@ _body_get_stream (mu_body_t body, mu_stream_t *pstream, int ref)
body->_lines = _body_get_lines;
body->_size = _body_get_size;
}
}
if (!ref)
{
*pstream = body->stream;
......@@ -227,7 +237,21 @@ mu_body_set_stream (mu_body_t body, mu_stream_t stream, void *owner)
}
int
mu_body_set_lines (mu_body_t body, int (*_lines) (mu_body_t, size_t *), void *owner)
mu_body_set_get_stream (mu_body_t body,
int (*_getstr) (mu_body_t, mu_stream_t *),
void *owner)
{
if (body == NULL)
return EINVAL;
if (body->owner != owner)
return EACCES;
body->_get_stream = _getstr;
return 0;
}
int
mu_body_set_lines (mu_body_t body, int (*_lines) (mu_body_t, size_t *),
void *owner)
{
if (body == NULL)
return EINVAL;
......
......@@ -597,7 +597,7 @@ mu_message_create_copy (mu_message_t *to, mu_message_t from)
return status;
}
status = mu_stream_copy (tmp, fromstr, 0);
status = mu_stream_copy (tmp, fromstr, 0, NULL);
if (status == 0)
{
status = mu_message_create (to, NULL);
......@@ -797,6 +797,8 @@ mu_message_set_stream (mu_message_t msg, mu_stream_t stream, void *owner)
static int
_message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
{
int status;
if (msg == NULL)
return EINVAL;
if (pstream == NULL)
......@@ -804,7 +806,14 @@ _message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
if (msg->stream == NULL)
{
int status;
if (msg->_get_stream)
{
status = msg->_get_stream (msg, &msg->stream);
if (status)
return status;
}
else
{
mu_header_t hdr;
mu_body_t body;
......@@ -822,6 +831,7 @@ _message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref)
return status;
msg->flags |= MESSAGE_INTERNAL_STREAM;
}
}
if (!ref)
{
......@@ -845,6 +855,19 @@ mu_message_get_streamref (mu_message_t msg, mu_stream_t *pstream)
}
int
mu_message_set_get_stream (mu_message_t msg,
int (*_getstr) (mu_message_t, mu_stream_t *),
void *owner)
{
if (msg == NULL)
return EINVAL;
if (msg->owner != owner)
return EACCES;
msg->_get_stream = _getstr;
return 0;
}
int
mu_message_set_lines (mu_message_t msg, int (*_lines)
(mu_message_t, size_t *), void *owner)
{
......
/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2009, 2010 Free Software Foundation, Inc.
GNU Mailutils is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Mailutils is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <mailutils/types.h>
#include <mailutils/stream.h>
#include <mailutils/message.h>
#include <mailutils/attribute.h>
#include <mailutils/cstr.h>
int
mu_stream_scan_message (mu_stream_t stream, struct mu_message_scan *sp)
{
char buf[1024];
mu_off_t off;
size_t n;
int status;
int in_header = 1;
size_t hlines = 0;
size_t blines = 0;
size_t body_start = 0;
int attr_flags = 0;
unsigned long uidvalidity = 0;
if (sp->flags & MU_SCAN_SEEK)
{
status = mu_stream_seek (stream, sp->message_start, MU_SEEK_SET, NULL);
if (status)
return status;
}
off = 0;
while (1)
{
size_t rdsize;
status = mu_stream_readline (stream, buf, sizeof (buf), &n);
if (status || n == 0)
break;
if (sp->flags & MU_SCAN_SIZE)
{
rdsize = sp->message_size - off;
if (n > rdsize)
n = rdsize;
}
if (in_header)
{
if (buf[0] == '\n')
{
in_header = 0;
body_start = off + 1;
}
if (buf[n - 1] == '\n')
hlines++;
/* Process particular attributes */
if (mu_c_strncasecmp (buf, "status:", 7) == 0)
mu_string_to_flags (buf, &attr_flags);
else if (mu_c_strncasecmp (buf, "x-imapbase:", 11) == 0)
{
char *p;
uidvalidity = strtoul (buf + 11, &p, 10);
/* second number is next uid. Ignored */
}
}
else
{
if (buf[n - 1] == '\n')
blines++;
}
off += n;
}
if (status == 0)
{
if (!body_start)
body_start = off;
sp->body_start = body_start;
sp->body_end = off;
sp->header_lines = hlines;
sp->body_lines = blines;
sp->attr_flags = attr_flags;
sp->uidvalidity = uidvalidity;
}
return status;
}
......@@ -48,7 +48,7 @@ rdcache_read (struct _mu_stream *str, char *buf, size_t size, size_t *pnbytes)
status = mu_stream_seek (sp->cache, 0, MU_SEEK_END, NULL);
if (status)
return status;
status = mu_stream_copy (sp->cache, sp->transport, left);
status = mu_stream_copy (sp->cache, sp->transport, left, NULL);
if (status)
return status;
sp->size = sp->offset;
......
......@@ -153,9 +153,13 @@ _stream_flush_buffer (struct _mu_stream *stream, int all)
if (stream->flags & _MU_STR_DIRTY)
{
if ((stream->flags & MU_STREAM_SEEK)
&& (rc = mu_stream_seek (stream, stream->offset, MU_SEEK_SET, NULL)))
if ((stream->flags & MU_STREAM_SEEK) && stream->seek)
{
mu_off_t off;
rc = stream->seek (stream, stream->offset, &off);
if (rc)
return rc;
}
switch (stream->buftype)
{
......
......@@ -31,22 +31,22 @@
/* Copy SIZE bytes from SRC to DST. If SIZE is 0, copy everything up to
EOF. */
int
mu_stream_copy (mu_stream_t dst, mu_stream_t src, size_t size)
mu_stream_copy (mu_stream_t dst, mu_stream_t src, mu_off_t size,
mu_off_t *pcsz)
{
int status;
size_t bufsize, n;
char *buf;
mu_off_t total = 0;
if (pcsz)
*pcsz = 0;
if (size == 0)
{
mu_off_t strsize;
status = mu_stream_size (src, &strsize);
status = mu_stream_size (src, &size);
switch (status)
{
case 0:
size = strsize;
if ((mu_off_t)size != strsize)
return ERANGE;
break;
case ENOSYS:
......@@ -105,6 +105,7 @@ mu_stream_copy (mu_stream_t dst, mu_stream_t src, size_t size)
if (status)
break;
size -= rdsize;
total += rdsize;
}
else
while ((status = mu_stream_read (src, buf, bufsize, &n)) == 0
......@@ -113,8 +114,11 @@ mu_stream_copy (mu_stream_t dst, mu_stream_t src, size_t size)
status = mu_stream_write (dst, buf, n, NULL);
if (status)
break;
total += n;
}
if (pcsz)
*pcsz = total;
free (buf);
return status;
}
......
......@@ -24,13 +24,15 @@
#include <mailutils/errno.h>
#include <mailutils/sys/streamref.h>
#define _MU_STR_ERRMASK (_MU_STR_ERR|_MU_STR_EOF)
static int
streamref_return (struct _mu_streamref *sp, int rc)
{
if (rc)
sp->stream.last_err = sp->transport->last_err;
sp->stream.flags = (sp->stream.flags & ~_MU_STR_INTERN_MASK) |
(sp->transport->flags & _MU_STR_INTERN_MASK);
sp->stream.flags = (sp->stream.flags & ~_MU_STR_ERRMASK) |
(sp->transport->flags & _MU_STR_ERRMASK);
return rc;
}
......@@ -80,15 +82,15 @@ _streamref_readdelim (struct _mu_stream *str, char *buf, size_t bufsize,
rc = mu_stream_seek (sp->transport, sp->offset, MU_SEEK_SET, &off);
if (rc == 0)
{
if (sp->end)
{
size_t size = sp->end - off + 2; /* extra 1 to account for \0 */
if (size < bufsize)
bufsize = size;
}
rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &nread);
if (rc == 0)
{
if (sp->end)
{
size_t size = sp->end - off + 1;
if (nread > size)
nread = size;
}
sp->offset += nread;
*pnread = nread;
}
......
......@@ -496,7 +496,7 @@ msg_copy (size_t num, const char *file)
mu_mailbox_get_message (tmpbox, num, &msg);
mu_message_get_streamref (msg, &istream);
/* FIXME: Implement RFC 934 FSA? */
rc = mu_stream_copy (ostream, istream, 0);
rc = mu_stream_copy (ostream, istream, 0, NULL);
if (rc)
{
mu_error (_("copy stream error: %s"), mu_strerror (rc));
......
......@@ -171,7 +171,7 @@ copy_message (mu_mailbox_t mbox, size_t n, const char *file)
return rc;
}
rc = mu_stream_copy (out, in, 0);
rc = mu_stream_copy (out, in, 0, NULL);
mu_stream_destroy (&in);
mu_stream_close (out);
mu_stream_destroy (&out);
......
......@@ -1259,7 +1259,7 @@ show_internal (mu_message_t msg, msg_part_t part, char *encoding, mu_stream_t ou
MU_FILTER_DECODE, MU_STREAM_READ);
if (rc == 0)
bstr = dstr;
rc = mu_stream_copy (out, bstr, 0);
rc = mu_stream_copy (out, bstr, 0, NULL);
mu_stream_destroy (&bstr);
return rc;
}
......@@ -2004,7 +2004,7 @@ finish_text_msg (struct compose_env *env, mu_message_t *msg, int ascii)
MU_STREAM_READ);
if (rc == 0)
{
mu_stream_copy (output, fstr, 0);
mu_stream_copy (output, fstr, 0, NULL);
mu_stream_destroy (&fstr);
mu_message_unref (*msg);
*msg = newmsg;
......@@ -2064,7 +2064,7 @@ edit_extern (char *cmd, struct compose_env *env, mu_message_t *msg, int level)
free (id);
mu_header_get_streamref (hdr2, &in);
mu_stream_copy (out, in, 0);
mu_stream_copy (out, in, 0, NULL);
mu_stream_destroy (&in);
mu_stream_close (out);
mu_stream_destroy (&out);
......@@ -2295,7 +2295,7 @@ edit_mime (char *cmd, struct compose_env *env, mu_message_t *msg, int level)
mu_message_get_body (*msg, &body);
mu_body_get_streamref (body, &out);
mu_stream_copy (out, fstr, 0);
mu_stream_copy (out, fstr, 0, NULL);
mu_stream_close (out);
mu_stream_destroy (&out);
......@@ -2660,7 +2660,7 @@ mhn_compose ()
mhn_header (message, msg);
copy_header_to_stream (message, stream);
mu_message_get_streamref (msg, &in);
mu_stream_copy (stream, in, 0);
mu_stream_copy (stream, in, 0, NULL);
mu_stream_destroy (&in);
mu_stream_destroy (&stream);
......
......@@ -46,7 +46,7 @@ pop3d_retr (char *arg)
return ERR_UNKNOWN;
pop3d_outf ("+OK\n");
mu_stream_copy (iostream, stream, 0);
mu_stream_copy (iostream, stream, 0, NULL);
mu_stream_destroy (&stream);
if (!mu_attribute_is_read (attr))
......
......@@ -62,7 +62,7 @@ pop3d_top (char *arg)
return ERR_UNKNOWN;
pop3d_outf ("+OK\n");
mu_stream_copy (iostream, stream, 0);
mu_stream_copy (iostream, stream, 0, NULL);
pop3d_outf ("\n");
mu_stream_destroy (&stream);
......