This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "GNU Mailutils".
http://git.savannah.gnu.org/cgit/mailutils.git/commit/?id=817286698ccc3f262cd0003401becef6c11050ae The branch, stream-cleanup has been updated via 817286698ccc3f262cd0003401becef6c11050ae (commit) from bfb29ced5d88dbe449347d5b8b86e6ee887c450b (commit) Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below. - Log ----------------------------------------------------------------- commit 817286698ccc3f262cd0003401becef6c11050ae Author: Sergey Poznyakoff <g...@gnu.org.ua> Date: Tue Sep 7 13:57:30 2010 +0300 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. ----------------------------------------------------------------------- Summary of changes: examples/base64.c | 2 +- examples/mucat.c | 4 +- imap4d/io.c | 2 +- include/mailutils/body.h | 5 +- include/mailutils/message.h | 24 +++- include/mailutils/stream.h | 3 +- include/mailutils/sys/body.h | 1 + include/mailutils/sys/message.h | 1 + libmu_scm/mu_message.c | 2 +- libmu_sieve/actions.c | 2 +- libmu_sieve/extensions/pipe.c | 2 +- libmu_sieve/extensions/spamd.c | 2 +- libmu_sieve/extensions/vacation.c | 2 +- libproto/mbox/mbox.c | 8 +- libproto/pop/mbox.c | 385 +++++++++++++++++++++++++++++++------ mail/decode.c | 2 +- mail/print.c | 2 + mailbox/Makefile.am | 1 + mailbox/body.c | 84 +++++--- mailbox/message.c | 59 ++++-- mailbox/msgscan.c | 106 ++++++++++ mailbox/rdcache_stream.c | 2 +- mailbox/stream.c | 10 +- mailbox/streamcpy.c | 18 +- mailbox/streamref.c | 18 +- mh/burst.c | 2 +- mh/comp.c | 2 +- mh/mhn.c | 10 +- pop3d/retr.c | 2 +- pop3d/top.c | 2 +- 30 files changed, 611 insertions(+), 154 deletions(-) create mode 100644 mailbox/msgscan.c diff --git a/examples/base64.c b/examples/base64.c index 226cde9..aa6bdeb 100644 --- a/examples/base64.c +++ b/examples/base64.c @@ -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); diff --git a/examples/mucat.c b/examples/mucat.c index b8cb314..92f55eb 100644 --- a/examples/mucat.c +++ b/examples/mucat.c @@ -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); diff --git a/imap4d/io.c b/imap4d/io.c index 05645ae..a8b6cb0 100644 --- a/imap4d/io.c +++ b/imap4d/io.c @@ -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 diff --git a/include/mailutils/body.h b/include/mailutils/body.h index 5fc25b7..d935d00 100644 --- a/include/mailutils/body.h +++ b/include/mailutils/body.h @@ -36,7 +36,10 @@ 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 *); extern int mu_body_size (mu_body_t, size_t *); diff --git a/include/mailutils/message.h b/include/mailutils/message.h index 8a2416f..14df6f6 100644 --- a/include/mailutils/message.h +++ b/include/mailutils/message.h @@ -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, diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index f2af9b3..e7d04ea 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -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); diff --git a/include/mailutils/sys/body.h b/include/mailutils/sys/body.h index 9c82a2a..7ec58e3 100644 --- a/include/mailutils/sys/body.h +++ b/include/mailutils/sys/body.h @@ -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 diff --git a/include/mailutils/sys/message.h b/include/mailutils/sys/message.h index ec91372..5e96d85 100644 --- a/include/mailutils/sys/message.h +++ b/include/mailutils/sys/message.h @@ -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 *); diff --git a/libmu_scm/mu_message.c b/libmu_scm/mu_message.c index ffcf9e3..1cb06c0 100644 --- a/libmu_scm/mu_message.c +++ b/libmu_scm/mu_message.c @@ -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) diff --git a/libmu_sieve/actions.c b/libmu_sieve/actions.c index 940b691..952626a 100644 --- a/libmu_sieve/actions.c +++ b/libmu_sieve/actions.c @@ -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); diff --git a/libmu_sieve/extensions/pipe.c b/libmu_sieve/extensions/pipe.c index 717706a..1378461 100644 --- a/libmu_sieve/extensions/pipe.c +++ b/libmu_sieve/extensions/pipe.c @@ -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); diff --git a/libmu_sieve/extensions/spamd.c b/libmu_sieve/extensions/spamd.c index 26640d4..e620e58 100644 --- a/libmu_sieve/extensions/spamd.c +++ b/libmu_sieve/extensions/spamd.c @@ -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); diff --git a/libmu_sieve/extensions/vacation.c b/libmu_sieve/extensions/vacation.c index f22e0e6..6b220df 100644 --- a/libmu_sieve/extensions/vacation.c +++ b/libmu_sieve/extensions/vacation.c @@ -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, diff --git a/libproto/mbox/mbox.c b/libproto/mbox/mbox.c index 51da14e..7b14817 100644 --- a/libproto/mbox/mbox.c +++ b/libproto/mbox/mbox.c @@ -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"), diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c index 3b538a0..ced5126 100644 --- a/libproto/pop/mbox.c +++ b/libproto/pop/mbox.c @@ -41,6 +41,7 @@ #include <mailutils/observer.h> #include <mailutils/property.h> #include <mailutils/stream.h> +#include <mailutils/filter.h> #include <mailutils/url.h> #include <mailutils/secret.h> #include <mailutils/tls.h> @@ -56,22 +57,24 @@ #include <mailutils/sys/registrar.h> #include <mailutils/sys/url.h> -#define _POP3_MSG_INBODY 0x01 -#define _POP3_MSG_SKIPHDR 0x02 -#define _POP3_MSG_SKIPBDY 0x04 +#define _POP3_MSG_CACHED 0x01 /* Message is already cached */ +#define _POP3_MSG_SIZE 0x02 /* Message size obtained */ +#define _POP3_MSG_SCANNED 0x04 /* Message has been scanned */ +#define _POP3_MSG_ATTRSET 0x08 /* Attributes has been set */ struct _pop3_message { int flags; - size_t body_size; - size_t header_size; - size_t body_lines; - size_t header_lines; - size_t message_size; - size_t num; - char *uidl; /* Cache the uidl string. */ - int attr_flags; - mu_message_t message; + mu_off_t offset; /* Offset in the message cache stream */ + mu_off_t body_start; /* Start of message, relative to offset */ + mu_off_t body_end; /* End of message, relative to offset */ + size_t header_lines; /* Number of lines in the header */ + size_t body_lines; /* Number of lines in the body */ + int attr_flags; /* Message attributes */ + size_t message_size; /* Message size */ + size_t num; /* Message number */ + char *uidl; /* Cached uidl string. */ + mu_message_t message; /* Pointer to the message structure */ struct _pop3_mailbox *mpd; /* Back pointer. */ }; @@ -87,10 +90,16 @@ struct _pop3_mailbox size_t msg_max; /* Actual size of the array */ mu_mailbox_t mbox; /* MU mailbox corresponding to this one. */ - char *user; /* Temporary holders for user and passwd. */ + mu_stream_t cache; /* Message cache stream */ + /* Temporary holders for user and passwd: */ + char *user; mu_secret_t secret; }; + +/* ------------------------------------------------------------------------- */ +/* Basic operations */ + static int pop_open (mu_mailbox_t mbox, int flags) { @@ -193,6 +202,7 @@ pop_close (mu_mailbox_t mbox) if (status) mu_error ("mu_pop3_disconnect failed: %s", mu_strerror (status)); mu_pop3_destroy (&mpd->pop3); + mu_stream_destroy (&mpd->cache); return 0; } @@ -220,6 +230,7 @@ pop_destroy (mu_mailbox_t mbox) free (mpd->user); if (mpd->secret) mu_secret_unref (mpd->secret); + mu_stream_destroy (&mpd->cache); } } @@ -319,6 +330,156 @@ pop_get_size (mu_mailbox_t mbox, mu_off_t *psize) } +/* ------------------------------------------------------------------------- */ +/* POP3 message streams */ + +static void +pop_stream_drain (mu_stream_t str) +{ + char buf[2048]; + size_t size; + + while (mu_stream_read (str, buf, sizeof buf, &size) == 0 && size) + ; +} + +static int +_pop_message_get_stream (struct _pop3_message *mpm, mu_stream_t *pstr) +{ + int status; + struct _pop3_mailbox *mpd = mpm->mpd; + + if (!(mpm->flags & _POP3_MSG_CACHED)) + { + mu_stream_t stream; + mu_off_t size; + + status = mu_pop3_retr (mpd->pop3, mpm->num, &stream); + if (status) + return status; + + do + { + mu_stream_t flt; + + if (!mpd->cache) + { + status = mu_temp_file_stream_create (&mpd->cache, NULL); + if (status) + /* FIXME: Try to recover first */ + break; + + status = mu_stream_open (mpd->cache); + if (status) + { + mu_stream_destroy (&mpd->cache); + break; + } + mu_stream_set_buffer (mpd->cache, mu_buffer_full, 8192); + } + + status = mu_stream_size (mpd->cache, &mpm->offset); + if (status) + break; + + status = mu_filter_create (&flt, stream, "CRLF", MU_FILTER_DECODE, + MU_STREAM_READ); + if (status) + break; + + status = mu_stream_copy (mpd->cache, flt, 0, &size); + + mu_stream_destroy (&flt); + } + while (0); + + if (status) + { + pop_stream_drain (stream); + mu_stream_unref (stream); + return status; + } + + mu_stream_unref (stream); + + mpm->message_size = size; /* FIXME: Possible overflow. */ + + mpm->flags |= _POP3_MSG_CACHED | _POP3_MSG_SIZE; + } + return mu_streamref_create_abridged (pstr, mpd->cache, + mpm->offset, + mpm->offset + mpm->message_size - 1); +} + +static int +pop_message_get_stream (mu_message_t msg, mu_stream_t *pstr) +{ + struct _pop3_message *mpm = mu_message_get_owner (msg); + return _pop_message_get_stream (mpm, pstr); +} + +static int +pop_scan_message (struct _pop3_message *mpm) +{ + int status; + mu_stream_t stream; + struct mu_message_scan scan; + + if (mpm->flags & _POP3_MSG_SCANNED) + return 0; + + status = _pop_message_get_stream (mpm, &stream); + if (status) + return status; + + scan.flags = MU_SCAN_SEEK | MU_SCAN_SIZE; + scan.message_start = 0; + scan.message_size = mpm->message_size; + status = mu_stream_scan_message (stream, &scan); + mu_stream_unref (stream); + + if (status == 0) + { + mpm->body_start = scan.body_start; + mpm->body_end = scan.body_end; + mpm->header_lines = scan.header_lines; + mpm->body_lines = scan.body_lines; + if (!(mpm->flags & _POP3_MSG_ATTRSET)) + { + mpm->attr_flags = scan.attr_flags; + mpm->flags |= _POP3_MSG_ATTRSET; + } + + mpm->flags |= _POP3_MSG_SCANNED; + } + + return status; +} + + +static int +pop_message_size (mu_message_t msg, size_t *psize) +{ + struct _pop3_message *mpm = mu_message_get_owner (msg); + struct _pop3_mailbox *mpd = mpm->mpd; + + if (mpm == NULL) + return EINVAL; + + if (!(mpm->flags & _POP3_MSG_SIZE)) + { + /* FIXME: The size obtained this way may differ from the actual one + by the number of lines in the message. */ + int status = mu_pop3_list (mpd->pop3, mpm->num, &mpm->message_size); + if (status) + return status; + mpm->flags |= _POP3_MSG_SIZE; + } + if (psize) + *psize = mpm->message_size; + return 0; +} + static int pop_create_message (struct _pop3_message *mpm, struct _pop3_mailbox *mpd) { @@ -328,7 +489,9 @@ pop_create_message (struct _pop3_message *mpm, struct _pop3_mailbox *mpd) status = mu_message_create (&msg, mpm); if (status) return status; - // FIXME... + + mu_message_set_get_stream (msg, pop_message_get_stream, mpm); + mu_message_set_size (msg, pop_message_size, mpm); mpm->message = msg; return 0; } @@ -337,46 +500,34 @@ pop_create_message (struct _pop3_message *mpm, struct _pop3_mailbox *mpd) /* ------------------------------------------------------------------------- */ /* Header */ -static int -pop_header_fill (void *data, char **pbuf, size_t *plen) +int +pop_header_blurb (mu_stream_t stream, size_t maxlines, + char **pbuf, size_t *plen) { - struct _pop3_message *mpm = data; - struct _pop3_mailbox *mpd = mpm->mpd; - mu_stream_t stream; - mu_opool_t opool; int status; + mu_opool_t opool; + size_t size = 0; + char *buf = NULL; + size_t n; + size_t nlines = 0; status = mu_opool_create (&opool, 0); if (status) return status; - - if (mu_pop3_capa_test (mpd->pop3, "TOP", NULL) == 0) - status = mu_pop3_top (mpd->pop3, mpm->num, 0, &stream); - else - status = mu_pop3_retr (mpd->pop3, mpm->num, &stream); - + + while ((status = mu_stream_getline (stream, &buf, &size, &n)) == 0 && n > 0) + { + size_t len = mu_rtrim_cset (buf, "\r\n"); + if (len == 0) + break; + mu_opool_append (opool, buf, len); + mu_opool_append_char (opool, '\n'); + if (maxlines && ++nlines >= maxlines) + break; + } + if (status == 0) { - size_t size = 0; - char *buf = NULL; - size_t n; - - while (mu_stream_getline (stream, &buf, &size, &n) == 0 - && n > 0) - { - size_t len = mu_rtrim_cset (buf, "\r\n"); - if (len == 0) - break; - mu_opool_append (opool, buf, len); - mu_opool_append_char (opool, '\n'); - } - - if (!mu_stream_eof (stream)) - /* Drain the stream. */ - while (mu_stream_getline (stream, &buf, &size, &n) == 0 - && n > 0); - mu_stream_destroy (&stream); - n = mu_opool_size (opool); if (n > size) { @@ -384,19 +535,53 @@ pop_header_fill (void *data, char **pbuf, size_t *plen) if (!p) { free (buf); - mu_opool_destroy (&opool); - return ENOMEM; + status = ENOMEM; } - buf = p; + else + buf = p; } + } + if (status == 0) + { mu_opool_copy (opool, buf, n); *pbuf = buf; *plen = n; - status = 0; } + else + free (buf); mu_opool_destroy (&opool); - + + return 0; +} + +static int +pop_header_fill (void *data, char **pbuf, size_t *plen) +{ + struct _pop3_message *mpm = data; + struct _pop3_mailbox *mpd = mpm->mpd; + mu_stream_t stream; + int status; + + if (mpm->flags & _POP3_MSG_SCANNED) + status = _pop_message_get_stream (mpm, &stream); + else + { + status = mu_pop3_top (mpd->pop3, mpm->num, 0, &stream); + if (status == 0) + { + status = pop_header_blurb (stream, 0, pbuf, plen); + if (!mu_stream_eof (stream)) + pop_stream_drain (stream); + mu_stream_destroy (&stream); + return status; + } + else + status = _pop_message_get_stream (mpm, &stream); + } + + status = pop_header_blurb (stream, mpm->header_lines, pbuf, plen); + mu_stream_destroy (&stream); return status; } @@ -437,7 +622,7 @@ pop_get_attribute (mu_attribute_t attr, int *pflags) if (mpm == NULL || pflags == NULL) return EINVAL; - if (mpm->attr_flags == 0) + if (!(mpm->flags & _POP3_MSG_ATTRSET)) { hdr_status[0] = '\0'; @@ -458,6 +643,7 @@ pop_set_attribute (mu_attribute_t attr, int flags) if (mpm == NULL) return EINVAL; mpm->attr_flags |= flags; + mpm->flags |= _POP3_MSG_ATTRSET; return 0; } @@ -469,6 +655,7 @@ pop_unset_attribute (mu_attribute_t attr, int flags) if (mpm == NULL) return EINVAL; mpm->attr_flags &= ~flags; + mpm->flags |= _POP3_MSG_ATTRSET; return 0; } @@ -492,11 +679,58 @@ pop_create_attribute (struct _pop3_message *mpm) /* ------------------------------------------------------------------------- */ /* Body */ +int +pop_body_get_stream (mu_body_t body, mu_stream_t *pstr) +{ + struct _pop3_message *mpm = mu_body_get_owner (body); + struct _pop3_mailbox *mpd = mpm->mpd; + int status = pop_scan_message (mpm); + if (status) + return status; + return mu_streamref_create_abridged (pstr, mpd->cache, + mpm->offset + mpm->body_start, + mpm->offset + mpm->body_end - 1); +} + +static int +pop_body_size (mu_body_t body, size_t *psize) +{ + struct _pop3_message *mpm = mu_body_get_owner (body); + int status = pop_scan_message (mpm); + if (status) + return status; + *psize = mpm->body_end - mpm->body_start; + return 0; +} + +static int +pop_body_lines (mu_body_t body, size_t *plines) +{ + struct _pop3_message *mpm = mu_body_get_owner (body); + int status = pop_scan_message (mpm); + if (status) + return status; + *plines = mpm->body_lines; + return 0; +} + static int pop_create_body (struct _pop3_message *mpm) { - /* FIXME */ - return ENOSYS; + int status; + mu_body_t body = NULL; + + status = mu_body_create (&body, mpm); + if (status) + return status; + + mu_body_set_get_stream (body, pop_body_get_stream, mpm); + mu_body_set_size (body, pop_body_size, mpm); + mu_body_set_lines (body, pop_body_lines, mpm); + + mu_message_set_body (mpm->message, body, mpm); + + return 0; } @@ -568,9 +802,9 @@ pop_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg) if (!mpd->msg) return ENOMEM; } - if (mpd->msg[msgno]) + if (mpd->msg[msgno - 1]) { - *pmsg = mpd->msg[msgno]->message; + *pmsg = mpd->msg[msgno - 1]->message; return 0; } @@ -613,13 +847,45 @@ pop_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg) mu_message_set_uid (mpm->message, pop_uid, mpm); - mpd->msg[msgno] = mpm; + mpd->msg[msgno - 1] = mpm; mu_message_set_mailbox (mpm->message, mbox, mpm); *pmsg = mpm->message; return 0; } static int +pop_expunge (mu_mailbox_t mbox) +{ + struct _pop3_mailbox *mpd = mbox->data; + int status = 0; + size_t i; + + if (mpd == NULL) + return EINVAL; + + if (!mpd->msg) + return 0; + + for (i = 0; i < mpd->msg_count; i++) + { + struct _pop3_message *mpm = mpd->msg[i]; + + if (mpm && + (mpm->flags & _POP3_MSG_ATTRSET) && + (mpm->attr_flags & MU_ATTRIBUTE_DELETED)) + { + status = mu_pop3_dele (mpd->pop3, mpm->num); + if (status) + break; + } + } + return 0; +} + +/* ------------------------------------------------------------------------- */ +/* Initialization */ + +static int _pop3_mailbox_init (mu_mailbox_t mbox, int pops) { struct _pop3_mailbox *mpd; @@ -649,13 +915,10 @@ _pop3_mailbox_init (mu_mailbox_t mbox, int pops) mbox->_message_unseen = pop_message_unseen; mbox->_get_size = pop_get_size; -#if 0 //FIXME /* Messages. */ mbox->_get_message = pop_get_message; mbox->_expunge = pop_expunge; - - /* Set our properties. */ { mu_property_t property = NULL; @@ -663,7 +926,6 @@ _pop3_mailbox_init (mu_mailbox_t mbox, int pops) mu_property_set_value (property, "TYPE", "POP3", 1); } -#endif /* Hack! POP does not really have a folder. */ mbox->folder->data = mbox; return status; @@ -682,6 +944,7 @@ _mailbox_pops_init (mu_mailbox_t mbox) } +/* ------------------------------------------------------------------------- */ /* Authentication */ /* Extract the User from the URL or the ticket. */ diff --git a/mail/decode.c b/mail/decode.c index 1a2f369..cd1d159 100644 --- a/mail/decode.c +++ b/mail/decode.c @@ -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); diff --git a/mail/print.c b/mail/print.c index 9f0e409..89542f6 100644 --- a/mail/print.c +++ b/mail/print.c @@ -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; } diff --git a/mailbox/Makefile.am b/mailbox/Makefile.am index 7a82437..c24c257 100644 --- a/mailbox/Makefile.am +++ b/mailbox/Makefile.am @@ -108,6 +108,7 @@ libmailutils_la_SOURCES = \ mimehdr.c\ mkfilename.c\ monitor.c\ + msgscan.c\ msrv.c\ mu_auth.c\ muctype.c\ diff --git a/mailbox/body.c b/mailbox/body.c index 038d29a..513ad01 100644 --- a/mailbox/body.c +++ b/mailbox/body.c @@ -161,36 +161,46 @@ _body_get_stream (mu_body_t body, mu_stream_t *pstream, int ref) if (body->stream == NULL) { - int status; - struct _mu_body_stream *str = - (struct _mu_body_stream *) - _mu_stream_create (sizeof (*str), - MU_STREAM_RDWR|MU_STREAM_SEEK); - if (!str) - return ENOMEM; - - /* Create the temporary file. */ - body->filename = mu_tempname (NULL); - status = mu_file_stream_create (&body->fstream, - body->filename, MU_STREAM_RDWR); - if (status != 0) - return status; - status = mu_stream_open (body->fstream); - if (status != 0) - return status; - str->stream.ctl = _body_ioctl; - str->stream.read = _body_read; - str->stream.write = _body_write; - str->stream.truncate = _body_truncate; - str->stream.size = _body_size; - str->stream.seek = _body_seek; - str->stream.flush = _body_flush; - str->body = body; - body->stream = (mu_stream_t) str; - /* Override the defaults. */ - body->_lines = _body_get_lines; - body->_size = _body_get_size; + 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 *) + _mu_stream_create (sizeof (*str), + MU_STREAM_RDWR|MU_STREAM_SEEK); + if (!str) + return ENOMEM; + + /* Create the temporary file. */ + body->filename = mu_tempname (NULL); + status = mu_file_stream_create (&body->fstream, + body->filename, MU_STREAM_RDWR); + if (status != 0) + return status; + status = mu_stream_open (body->fstream); + if (status != 0) + return status; + str->stream.ctl = _body_ioctl; + str->stream.read = _body_read; + str->stream.write = _body_write; + str->stream.truncate = _body_truncate; + str->stream.size = _body_size; + str->stream.seek = _body_seek; + str->stream.flush = _body_flush; + str->body = body; + body->stream = (mu_stream_t) str; + /* Override the defaults. */ + 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; diff --git a/mailbox/message.c b/mailbox/message.c index 8ac1258..c227a09 100644 --- a/mailbox/message.c +++ b/mailbox/message.c @@ -586,7 +586,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); @@ -786,6 +786,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) @@ -793,25 +795,33 @@ _message_get_stream (mu_message_t msg, mu_stream_t *pstream, int ref) if (msg->stream == NULL) { - int status; - mu_header_t hdr; - mu_body_t body; + if (msg->_get_stream) + { + status = msg->_get_stream (msg, &msg->stream); + if (status) + return status; + } + else + { + mu_header_t hdr; + mu_body_t body; - /* FIXME: Kind of a kludge: make sure the message has header - and body initialized. */ - status = mu_message_get_header (msg, &hdr); - if (status) - return status; - status = mu_message_get_body (msg, &body); - if (status) - return status; - - status = _message_stream_create (&msg->stream, msg, MU_STREAM_RDWR); - if (status) - return status; - msg->flags |= MESSAGE_INTERNAL_STREAM; + /* FIXME: Kind of a kludge: make sure the message has header + and body initialized. */ + status = mu_message_get_header (msg, &hdr); + if (status) + return status; + status = mu_message_get_body (msg, &body); + if (status) + return status; + + status = _message_stream_create (&msg->stream, msg, MU_STREAM_RDWR); + if (status) + return status; + msg->flags |= MESSAGE_INTERNAL_STREAM; + } } - + if (!ref) { *pstream = msg->stream; @@ -834,6 +844,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) { diff --git a/mailbox/msgscan.c b/mailbox/msgscan.c new file mode 100644 index 0000000..dbbafed --- /dev/null +++ b/mailbox/msgscan.c @@ -0,0 +1,106 @@ +/* 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; +} diff --git a/mailbox/rdcache_stream.c b/mailbox/rdcache_stream.c index 8a8afbf..0d7eed7 100644 --- a/mailbox/rdcache_stream.c +++ b/mailbox/rdcache_stream.c @@ -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; diff --git a/mailbox/stream.c b/mailbox/stream.c index 55af4ab..1ea8b52 100644 --- a/mailbox/stream.c +++ b/mailbox/stream.c @@ -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))) - return rc; + 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) { diff --git a/mailbox/streamcpy.c b/mailbox/streamcpy.c index ec56a7a..4812667 100644 --- a/mailbox/streamcpy.c +++ b/mailbox/streamcpy.c @@ -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; } diff --git a/mailbox/streamref.c b/mailbox/streamref.c index 2ce35a4..b773983 100644 --- a/mailbox/streamref.c +++ b/mailbox/streamref.c @@ -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; } diff --git a/mh/burst.c b/mh/burst.c index 670ea79..1bd99c3 100644 --- a/mh/burst.c +++ b/mh/burst.c @@ -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)); diff --git a/mh/comp.c b/mh/comp.c index 71095a6..5439562 100644 --- a/mh/comp.c +++ b/mh/comp.c @@ -167,7 +167,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); diff --git a/mh/mhn.c b/mh/mhn.c index f92c70b..8beadd9 100644 --- a/mh/mhn.c +++ b/mh/mhn.c @@ -1258,7 +1258,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; } @@ -2003,7 +2003,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; @@ -2063,7 +2063,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); @@ -2294,7 +2294,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); @@ -2659,7 +2659,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); diff --git a/pop3d/retr.c b/pop3d/retr.c index 5c30643..61908c0 100644 --- a/pop3d/retr.c +++ b/pop3d/retr.c @@ -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)) diff --git a/pop3d/top.c b/pop3d/top.c index 3716875..7e0ce5d 100644 --- a/pop3d/top.c +++ b/pop3d/top.c @@ -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); hooks/post-receive -- GNU Mailutils _______________________________________________ Commit-mailutils mailing list Commit-mailutils@gnu.org http://lists.gnu.org/mailman/listinfo/commit-mailutils