summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mailutils/message.h3
-rw-r--r--include/mailutils/sys/message.h2
-rw-r--r--libmailutils/diag/errors2
-rw-r--r--libmailutils/mailbox/message.c34
-rw-r--r--libproto/pop/mbox.c180
-rw-r--r--mail/from.c23
-rw-r--r--pop3d/capa.c4
-rw-r--r--pop3d/list.c34
-rw-r--r--pop3d/pop3d.c3
-rw-r--r--pop3d/pop3d.h1
-rw-r--r--pop3d/stat.c1
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;
}
+

Return to:

Send suggestions and report system problems to the System administrator.