diff options
-rw-r--r-- | include/mailutils/message.h | 3 | ||||
-rw-r--r-- | include/mailutils/sys/message.h | 2 | ||||
-rw-r--r-- | libmailutils/diag/errors | 2 | ||||
-rw-r--r-- | libmailutils/mailbox/message.c | 34 | ||||
-rw-r--r-- | libproto/pop/mbox.c | 180 | ||||
-rw-r--r-- | mail/from.c | 23 | ||||
-rw-r--r-- | pop3d/capa.c | 4 | ||||
-rw-r--r-- | pop3d/list.c | 34 | ||||
-rw-r--r-- | pop3d/pop3d.c | 3 | ||||
-rw-r--r-- | pop3d/pop3d.h | 1 | ||||
-rw-r--r-- | pop3d/stat.c | 1 |
11 files changed, 239 insertions, 48 deletions
diff --git a/include/mailutils/message.h b/include/mailutils/message.h index f6974cce1..549c5e0ab 100644 --- a/include/mailutils/message.h +++ b/include/mailutils/message.h @@ -97,8 +97,9 @@ extern int mu_message_set_size (mu_message_t, void *owner); extern int mu_message_lines (mu_message_t, size_t *); +extern int mu_message_quick_lines (mu_message_t, size_t *); extern int mu_message_set_lines (mu_message_t, - int (*_lines) (mu_message_t, size_t *), + int (*_lines) (mu_message_t, size_t *, int), void *owner); extern int mu_message_get_num_parts (mu_message_t, size_t *nparts); diff --git a/include/mailutils/sys/message.h b/include/mailutils/sys/message.h index 53f367228..bcea04f7c 100644 --- a/include/mailutils/sys/message.h +++ b/include/mailutils/sys/message.h @@ -58,7 +58,7 @@ struct _mu_message int (*_get_num_parts) (mu_message_t, size_t *); int (*_get_part) (mu_message_t, size_t, mu_message_t *); int (*_is_multipart) (mu_message_t, int *); - int (*_lines) (mu_message_t, size_t *); + int (*_lines) (mu_message_t, size_t *, int); int (*_size) (mu_message_t, size_t *); }; diff --git a/libmailutils/diag/errors b/libmailutils/diag/errors index 3807524b6..0b71e3ccd 100644 --- a/libmailutils/diag/errors +++ b/libmailutils/diag/errors @@ -95,3 +95,5 @@ MU_ERR_AUTH_NO_CRED _("No credentials supplied") MU_ERR_URL_MISS_PARTS _("URL missing required parts") MU_ERR_URL_EXTRA_PARTS _("URL has parts not allowed by its scheme") + +MU_ERR_INFO_UNAVAILABLE _("Information is not yet available") diff --git a/libmailutils/mailbox/message.c b/libmailutils/mailbox/message.c index 684fe39e4..2a2ebe3dd 100644 --- a/libmailutils/mailbox/message.c +++ b/libmailutils/mailbox/message.c @@ -882,7 +882,7 @@ mu_message_set_get_stream (mu_message_t msg, int mu_message_set_lines (mu_message_t msg, int (*_lines) - (mu_message_t, size_t *), void *owner) + (mu_message_t, size_t *, int), void *owner) { if (msg == NULL) return EINVAL; @@ -902,7 +902,7 @@ mu_message_lines (mu_message_t msg, size_t *plines) return EINVAL; /* Overload. */ if (msg->_lines) - return msg->_lines (msg, plines); + return msg->_lines (msg, plines, 0); if (plines) { hlines = blines = 0; @@ -913,6 +913,36 @@ mu_message_lines (mu_message_t msg, size_t *plines) return ret; } +/* Return the number of lines in the message, without going into + excess trouble for calculating it. If obtaining the result + means downloading the entire message (as is the case for POP3, + for example), return MU_ERR_INFO_UNAVAILABLE. */ +int +mu_message_quick_lines (mu_message_t msg, size_t *plines) +{ + size_t hlines, blines; + int rc; + + if (msg == NULL) + return EINVAL; + /* Overload. */ + if (msg->_lines) + { + int rc = msg->_lines (msg, plines, 1); + if (rc != ENOSYS) + return rc; + } + if (plines) + { + hlines = blines = 0; + if ((rc = mu_header_lines (msg->header, &hlines)) == 0) + rc = mu_body_lines (msg->body, &blines); + if (rc == 0) + *plines = hlines + blines; + } + return rc; +} + int mu_message_set_size (mu_message_t msg, int (*_size) (mu_message_t, size_t *), void *owner) diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c index 8311152cd..570ec766f 100644 --- a/libproto/pop/mbox.c +++ b/libproto/pop/mbox.c @@ -60,6 +60,7 @@ #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 */ +#define _POP3_MSG_LINES 0x10 /* Number of lines was obtained */ struct _pop3_message { @@ -70,7 +71,8 @@ struct _pop3_message 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 message_size; /* Message size */ + size_t message_lines; /* Number of lines in the message */ size_t num; /* Message number */ char *uidl; /* Cached uidl string. */ mu_message_t message; /* Pointer to the message structure */ @@ -95,6 +97,9 @@ struct _pop3_mailbox mu_secret_t secret; }; +static int pop_create_pop3_message (struct _pop3_mailbox *mpd, size_t msgno, + struct _pop3_message **mptr); + /* ------------------------------------------------------------------------- */ /* Basic operations */ @@ -270,34 +275,89 @@ pop_messages_count (mu_mailbox_t mbox, size_t *pcount) } return status; } - + static int pop_scan (mu_mailbox_t mbox, size_t msgno, size_t *pcount) { int status; size_t i; size_t count = 0; - + struct _pop3_mailbox *mpd = mbox->data; + int flags; + mu_iterator_t itr; + status = pop_messages_count (mbox, &count); if (status != 0) return status; if (pcount) *pcount = count; - if (mbox->observable == NULL) - return 0; - for (i = msgno; i <= count; i++) + + flags = _POP3_MSG_SIZE; + if (!mu_pop3_capa_test (mpd->pop3, "XLINES", NULL)) + flags |= _POP3_MSG_LINES; + + status = mu_pop3_list_all (mpd->pop3, &itr); + if (status) + return status; + + for (i = 0, mu_iterator_first (itr); + i <= count && !mu_iterator_is_done (itr); + i++, mu_iterator_next (itr)) { - size_t tmp = i; - if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, - &tmp) != 0) - break; - if (((i + 1) % 10) == 0) + const char *str; + char *p; + size_t num; + + mu_iterator_current (itr, (void**) &str); + num = strtoul (str, &p, 10); + + if (*p != ' ') { - mu_observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS, - NULL); + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, + ("invalid reply to LIST command: %s", str)); + status = MU_ERR_BADREPLY; + break; + } + if (num >= msgno) + { + size_t size, lines; + struct _pop3_message *mpm; + + size = strtoul (p + 1, &p, 10); + if (flags & _POP3_MSG_LINES) + { + if (*p != ' ') + { + mu_debug (MU_DEBCAT_MAILBOX, MU_DEBUG_ERROR, + ("invalid reply to LIST command: %s", str)); + status = MU_ERR_BADREPLY; + break; + } + lines = strtoul (p + 1, &p, 10); + } + + status = pop_create_pop3_message (mpd, num, &mpm); + if (status) + break; + mpm->message_size = size; + if (flags & _POP3_MSG_LINES) + mpm->message_lines = lines; + mpm->flags |= flags; + + if (mbox->observable) + { + if (mu_observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD, + &num) != 0) + break; + if (((i + 1) % 10) == 0) + mu_observable_notify (mbox->observable, + MU_EVT_MAILBOX_PROGRESS, + NULL); + } } } - return 0; + mu_iterator_destroy (&itr); + return status; } /* There's no way to retrieve this info via POP3 */ @@ -475,6 +535,29 @@ pop_message_size (mu_message_t msg, size_t *psize) } static int +pop_message_lines (mu_message_t msg, size_t *plines, int quick) +{ + int rc; + struct _pop3_message *mpm = mu_message_get_owner (msg); + + if (!(mpm->flags & _POP3_MSG_LINES)) + { + if (quick && !(mpm->flags & _POP3_MSG_CACHED)) + return MU_ERR_INFO_UNAVAILABLE; + if (!pop_is_updated (mpm->mpd->mbox)) + pop_scan (mpm->mpd->mbox, 1, NULL); + rc = pop_scan_message (mpm); + if (rc) + return rc; + mpm->message_lines = mpm->header_lines + mpm->body_lines + 1; + mpm->flags |= _POP3_MSG_LINES; + } + + *plines = mpm->message_lines; + return 0; +} + +static int pop_create_message (struct _pop3_message *mpm, struct _pop3_mailbox *mpd) { int status; @@ -486,10 +569,47 @@ pop_create_message (struct _pop3_message *mpm, struct _pop3_mailbox *mpd) mu_message_set_get_stream (msg, pop_message_get_stream, mpm); mu_message_set_size (msg, pop_message_size, mpm); + mu_message_set_lines (msg, pop_message_lines, mpm); mpm->message = msg; return 0; } +static int +pop_create_pop3_message (struct _pop3_mailbox *mpd, size_t msgno, + struct _pop3_message **mptr) +{ + int status; + struct _pop3_message *mpm; + + if (msgno > mpd->msg_count) + return EINVAL; + + if (!mpd->msg) + { + mpd->msg = calloc (mpd->msg_count, sizeof (mpd->msg[0])); + if (!mpd->msg) + return ENOMEM; + } + if (mpd->msg[msgno - 1]) + { + *mptr = mpd->msg[msgno - 1]; + return 0; + } + + mpm = calloc (1, sizeof (*mpm)); + if (mpm == NULL) + return ENOMEM; + + /* Back pointer. */ + mpm->mpd = mpd; + mpm->num = msgno; + + mpd->msg[msgno - 1] = mpm; + *mptr = mpm; + return status; +} + + /* ------------------------------------------------------------------------- */ /* Header */ @@ -798,36 +918,19 @@ pop_get_message (mu_mailbox_t mbox, size_t msgno, mu_message_t *pmsg) if (!pop_is_updated (mbox)) pop_scan (mbox, 1, NULL); - if (msgno > mpd->msg_count) - return EINVAL; - - if (!mpd->msg) - { - mpd->msg = calloc (mpd->msg_count, sizeof (mpd->msg[0])); - if (!mpd->msg) - return ENOMEM; - } - if (mpd->msg[msgno - 1]) + status = pop_create_pop3_message (mpd, msgno, &mpm); + if (status) + return status; + if (mpm->message) { - *pmsg = mpd->msg[msgno - 1]->message; + *pmsg = mpm->message; return 0; } - mpm = calloc (1, sizeof (*mpm)); - if (mpm == NULL) - return ENOMEM; - - /* Back pointer. */ - mpm->mpd = mpd; - mpm->num = msgno; - status = pop_create_message (mpm, mpd); if (status) - { - free (mpm); - return status; - } - + return status; + do { status = pop_create_header (mpm); @@ -852,7 +955,6 @@ 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 - 1] = mpm; mu_message_set_mailbox (mpm->message, mbox, mpm); *pmsg = mpm->message; return 0; diff --git a/mail/from.c b/mail/from.c index f8863a563..73cc404a2 100644 --- a/mail/from.c +++ b/mail/from.c @@ -294,11 +294,29 @@ hdr_lines (struct header_call_args *args, void *data) { size_t m_lines; char buf[UINTMAX_STRSIZE_BOUND]; + mu_message_lines (args->msg, &m_lines); return header_buf_string (args, umaxtostr (m_lines, buf)); } +/* %L */ +static char * +hdr_quick_lines (struct header_call_args *args, void *data) +{ + size_t m_lines; + char buf[UINTMAX_STRSIZE_BOUND]; + int rc; + const char *p; + + rc = mu_message_quick_lines (args->msg, &m_lines); + if (rc == 0) + p = umaxtostr (m_lines, buf); + else + p = "NA"; + return header_buf_string (args, p); +} + /* %m */ static char * hdr_number (struct header_call_args *args, void *data) @@ -466,6 +484,11 @@ compile_headline (const char *str) case 'l': /* The number of lines of the message */ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_lines); break; + + case 'L': /* Same, but in quick mode */ + seg = new_header_segment (ALIGN_NUMBER, width, NULL, + hdr_quick_lines); + break; case 'm': /* Message number */ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_number); diff --git a/pop3d/capa.c b/pop3d/capa.c index 38d5fed12..da19be8aa 100644 --- a/pop3d/capa.c +++ b/pop3d/capa.c @@ -38,7 +38,9 @@ pop3d_capa (char *arg) pop3d_outf ("UIDL\n"); pop3d_outf ("RESP-CODES\n"); pop3d_outf ("PIPELINING\n"); - + if (pop3d_xlines) + pop3d_outf ("XLINES\n"); + #ifdef WITH_TLS if (tls_available && tls_done == 0) pop3d_outf ("STLS\n"); diff --git a/pop3d/list.c b/pop3d/list.c index a212e4146..23516fc20 100644 --- a/pop3d/list.c +++ b/pop3d/list.c @@ -17,8 +17,27 @@ #include "pop3d.h" -/* Displays the size of message number arg or all messages (if no arg) */ - +/* From RFC 1939: + + In order to simplify parsing, all POP3 servers are + required to use a certain format for scan listings. A + scan listing consists of the message-number of the + message, followed by a single space and the exact size of + the message in octets. Methods for calculating the exact + size of the message are described in the "Message Format" + section below. This memo makes no requirement on what + follows the message size in the scan listing. Minimal + implementations should just end that line of the response + with a CRLF pair. More advanced implementations may + include other information, as parsed from the message. + <end of quote> + + GNU pop3d uses this allowance and includes in the scan + listing the number of lines in message. This optional + feature is enabled by setting "scan-lines yes" in the + configuration file. When on, it is indicated by the + XLINES capability. +*/ int pop3d_list (char *arg) { @@ -47,9 +66,12 @@ pop3d_list (char *arg) { mu_message_size (msg, &size); mu_message_lines (msg, &lines); - pop3d_outf ("%s %s\n", + pop3d_outf ("%s %s", mu_umaxtostr (0, mesgno), mu_umaxtostr (1, size + lines)); + if (pop3d_xlines) + pop3d_outf (" %s", mu_umaxtostr (2, lines)); + pop3d_outf ("\n"); } } pop3d_outf (".\n"); @@ -64,10 +86,14 @@ pop3d_list (char *arg) return ERR_MESG_DELE; mu_message_size (msg, &size); mu_message_lines (msg, &lines); - pop3d_outf ("+OK %s %s\n", + pop3d_outf ("+OK %s %s", mu_umaxtostr (0, mesgno), mu_umaxtostr (1, size + lines)); + if (pop3d_xlines) + pop3d_outf (" %s", mu_umaxtostr (2, lines)); + pop3d_outf ("\n"); } return OK; } + diff --git a/pop3d/pop3d.c b/pop3d/pop3d.c index 40c51c017..d470b20e5 100644 --- a/pop3d/pop3d.c +++ b/pop3d/pop3d.c @@ -30,6 +30,7 @@ unsigned int idle_timeout; int pop3d_transcript; int debug_mode; int tls_required; +int pop3d_xlines; #ifdef WITH_TLS int tls_available; @@ -95,6 +96,8 @@ static struct mu_cfg_param pop3d_cfg_param[] = { N_("days") }, { "delete-expired", mu_cfg_bool, &expire_on_exit, 0, NULL, N_("Delete expired messages upon closing the mailbox.") }, + { "scan-lines", mu_cfg_bool, &pop3d_xlines, 0, NULL, + N_("Output the number of lines in the message in its scan listing.") }, #ifdef WITH_TLS { "tls-required", mu_cfg_bool, &tls_required, 0, NULL, N_("Always require STLS before entering authentication phase.") }, diff --git a/pop3d/pop3d.h b/pop3d/pop3d.h index f3ceaee37..0a4e6c506 100644 --- a/pop3d/pop3d.h +++ b/pop3d/pop3d.h @@ -196,6 +196,7 @@ extern struct mu_auth_data *auth_data; extern unsigned int idle_timeout; extern int pop3d_transcript; extern size_t pop3d_output_bufsize; +extern int pop3d_xlines; extern pop3d_command_handler_t pop3d_find_command (const char *name); diff --git a/pop3d/stat.c b/pop3d/stat.c index f108b76fe..1e72206be 100644 --- a/pop3d/stat.c +++ b/pop3d/stat.c @@ -59,3 +59,4 @@ pop3d_stat (char *arg) return OK; } + |