summaryrefslogtreecommitdiff
path: root/mail
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-08-14 22:53:52 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2009-08-14 22:53:52 +0300
commit9b0dee5fa917d5804aa2ca89a186ea8da64578ca (patch)
treed4725ee292d4d803da77d3a283b1accfeec27f39 /mail
parentf2eb56bb7632e4044173a344964d6739a7ef4b7f (diff)
downloadmailutils-9b0dee5fa917d5804aa2ca89a186ea8da64578ca.tar.gz
mailutils-9b0dee5fa917d5804aa2ca89a186ea8da64578ca.tar.bz2
Mail: configurable `headers' output format.
* mail/from.c: Rewrite using format string. * mail/mail.c (default_setup): Set default value for `headline'. (main): Fix call to util_do_command. * mail/mail.h [HAVE_STDARG_H]: Remove conditions. (mail_compile_headline): New proto. * mail/mailvar.c (mailvar_tab): New variable "headline". * mail/util.c: Minor fixes. * NEWS, doc/programs.texi: Update.
Diffstat (limited to 'mail')
-rw-r--r--mail/from.c518
-rw-r--r--mail/mail.c3
-rw-r--r--mail/mail.h8
-rw-r--r--mail/mailvar.c4
-rw-r--r--mail/util.c21
5 files changed, 457 insertions, 97 deletions
diff --git a/mail/from.c b/mail/from.c
index add264347..31e2a9202 100644
--- a/mail/from.c
+++ b/mail/from.c
@@ -18,27 +18,220 @@
MA 02110-1301 USA */
#include "mail.h"
+#include <mu_umaxtostr.h>
-/*
- * f[rom] [msglist]
- */
+#define ALIGN_UNDEF -1
+#define ALIGN_RIGHT 0
+#define ALIGN_LEFT 1
-int
-mail_from0 (msgset_t *mspec, mu_message_t msg, void *data)
+struct header_call_args
+{
+ msgset_t *mspec;
+ mu_message_t msg;
+ size_t cols_rest;
+ char *buf;
+ size_t size;
+};
+
+struct header_segm
+{
+ struct header_segm *next;
+ int align;
+ size_t width;
+ void *data;
+ char *(*get) (struct header_call_args *args, void *data);
+};
+
+void
+header_ensure_space (struct header_call_args *args, size_t size)
+{
+ if (size > args->size)
+ {
+ args->buf = xrealloc (args->buf, size);
+ args->size = size;
+ }
+}
+
+static char *
+header_buf_string_len (struct header_call_args *args, const char *str,
+ size_t len)
+{
+ header_ensure_space (args, len + 1);
+ memcpy (args->buf, str, len);
+ args->buf[len] = 0;
+ return args->buf;
+}
+
+static char *
+header_buf_string (struct header_call_args *args, const char *str)
+{
+ if (!str)
+ return header_buf_string_len (args, "", 0);
+ return header_buf_string_len (args, str, strlen (str));
+}
+
+static void
+format_pad (size_t n)
+{
+ for (; n; n--)
+ fputc (' ', ofile);
+}
+
+static void
+format_headline (struct header_segm *seg, msgset_t *mspec, mu_message_t msg)
+{
+ int screen_cols = util_getcols () - 2;
+ int out_cols = 0;
+ struct header_call_args args;
+
+ args.mspec = mspec;
+ args.msg = msg;
+ args.buf = NULL;
+ args.size = 0;
+
+ for (; seg; seg = seg->next)
+ {
+ size_t width, len;
+ size_t cols_rest = screen_cols - out_cols;
+ char *p;
+
+ args.cols_rest = cols_rest;
+ p = seg->get (&args, seg->data);
+
+ if (!p)
+ p = "";
+ len = strlen (p);
+
+ if (seg->width)
+ width = seg->width;
+ else
+ width = len;
+ if (width > cols_rest)
+ width = cols_rest;
+
+ if (len > width)
+ len = width;
+
+ if (seg->align == ALIGN_RIGHT)
+ {
+ format_pad (width - len);
+ fprintf (ofile, "%*.*s", len, len, p);
+ }
+ else
+ {
+ fprintf (ofile, "%*.*s", len, len, p);
+ format_pad (width - len);
+ }
+ out_cols += width;
+ }
+
+ fprintf (ofile, "\n");
+ free (args.buf);
+}
+
+static void
+free_headline (struct header_segm *seg)
+{
+ while (seg)
+ {
+ struct header_segm *next = seg->next;
+ if (seg->data)
+ free (seg->data);
+ free (seg);
+ seg = next;
+ }
+}
+
+
+static char *
+hdr_text (struct header_call_args *args, void *data)
+{
+ return data;
+}
+
+static char *
+hdr_cur (struct header_call_args *args, void *data)
+{
+ if (is_current_message (args->mspec->msg_part[0]))
+ return (char*) data;
+ return " ";
+}
+
+/* %a */
+static char *
+hdr_attr (struct header_call_args *args, void *data)
{
- mu_header_t hdr = NULL;
- mu_envelope_t env;
mu_attribute_t attr;
- char *from = NULL, *subj = NULL, *fromp, *subjp;
- int froml, subjl;
- char date[80], st[10];
- int cols = util_getcols () - 6;
- int cflag;
- size_t m_size = 0, m_lines = 0;
+ char cflag;
+
+ mu_message_get_attribute (args->msg, &attr);
+
+ if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_MBOXED))
+ cflag = 'M';
+ else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_PRESERVED))
+ cflag = 'P';
+ else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_SAVED))
+ cflag = '*';
+ else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_TAGGED))
+ cflag = 'T';
+ else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_SHOWN))
+ cflag = 'R';
+ else if (mu_attribute_is_recent (attr))
+ cflag = 'N';
+ else if (!mu_attribute_is_read (attr))
+ cflag = 'U';
+ else
+ cflag = ' ';
+ return header_buf_string_len (args, &cflag, 1);
+}
+
+/* %d */
+static char *
+hdr_date (struct header_call_args *args, void *data)
+{
+ char date[80];
+ mu_header_t hdr;
+ mu_message_get_header (args->msg, &hdr);
+
+ date[0] = 0;
+ if (mailvar_get (NULL, "datefield", mailvar_type_boolean, 0) == 0
+ && mu_header_get_value (hdr, MU_HEADER_DATE,
+ date, sizeof (date), NULL) == 0)
+ {
+ time_t t;
+ if (mu_parse_date (date, &t, NULL) == 0)
+ strftime (date, sizeof(date), "%a %b %e %H:%M", localtime (&t));
+ else
+ date[0] = 0;
+ }
+
+ if (date[0] == 0)
+ {
+ const char *p;
+ struct tm tm;
+ mu_timezone tz;
+ mu_envelope_t env;
+
+ mu_message_get_envelope (args->msg, &env);
+ if (mu_envelope_sget_date (env, &p) == 0
+ && mu_parse_ctime_date_time (&p, &tm, &tz) == 0)
+ strftime (date, sizeof(date), "%a %b %e %H:%M", &tm);
+ }
+ return header_buf_string (args, date);
+}
+
+/* %f */
+static char *
+hdr_from (struct header_call_args *args, void *data)
+{
+ char *from = NULL;
+
if (mailvar_get (NULL, "fromfield", mailvar_type_boolean, 0) == 0)
{
- mu_message_get_header (msg, &hdr);
+ mu_header_t hdr;
+
+ mu_message_get_header (args->msg, &hdr);
if (mu_header_aget_value_unfold (hdr, MU_HEADER_FROM, &from) == 0)
{
mu_address_t address = NULL;
@@ -49,7 +242,8 @@ mail_from0 (msgset_t *mspec, mu_message_t msg, void *data)
if (mu_address_sget_email (address, 1, &email) == 0)
{
- if (mailvar_get (NULL, "showto", mailvar_type_boolean, 0) == 0
+ if (mailvar_get (NULL, "showto",
+ mailvar_type_boolean, 0) == 0
&& mail_is_my_name (email))
{
char *tmp;
@@ -86,87 +280,263 @@ mail_from0 (msgset_t *mspec, mu_message_t msg, void *data)
mu_envelope_t env = NULL;
const char *sender = "";
- if (mu_message_get_envelope (msg, &env) == 0)
+ if (mu_message_get_envelope (args->msg, &env) == 0)
mu_envelope_sget_sender (env, &sender);
from = strdup (sender);
}
+ header_buf_string (args, from);
+ free (from);
+ return args->buf;
+}
+
+/* %l */
+static char *
+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));
+}
+
+/* %m */
+static char *
+hdr_number (struct header_call_args *args, void *data)
+{
+ char buf[UINTMAX_STRSIZE_BOUND];
+ return header_buf_string (args, umaxtostr (args->mspec->msg_part[0], buf));
+}
+
+/* %o */
+static char *
+hdr_size (struct header_call_args *args, void *data)
+{
+ size_t m_size;
+ char buf[UINTMAX_STRSIZE_BOUND];
+ mu_message_size (args->msg, &m_size);
+
+ return header_buf_string (args, umaxtostr (m_size, buf));
+}
+
+/* %s */
+static char *
+hdr_subject (struct header_call_args *args, void *data)
+{
+ mu_header_t hdr;
+ char *subj = NULL;
+
+ mu_message_get_header (args->msg, &hdr);
mu_header_aget_value_unfold (hdr, MU_HEADER_SUBJECT, &subj);
util_rfc2047_decode (&subj);
- mu_message_get_attribute (msg, &attr);
+ header_buf_string (args, subj);
+ free (subj);
+ return args->buf;
+}
+
+/* %S */
+static char *
+hdr_q_subject (struct header_call_args *args, void *data)
+{
+ mu_header_t hdr;
+ char *subj = NULL;
+ size_t len;
+
+ if (args->cols_rest <= 2)
+ return "\"\"";
- if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_MBOXED))
- cflag = 'M';
- else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_PRESERVED))
- cflag = 'P';
- else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_SAVED))
- cflag = '*';
- else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_TAGGED))
- cflag = 'T';
- else if (mu_attribute_is_userflag (attr, MAIL_ATTRIBUTE_SHOWN))
- cflag = 'R';
- else if (mu_attribute_is_recent (attr))
- cflag = 'N';
- else if (!mu_attribute_is_read (attr))
- cflag = 'U';
- else
- cflag = ' ';
+ mu_message_get_header (args->msg, &hdr);
+ mu_header_aget_value_unfold (hdr, MU_HEADER_SUBJECT, &subj);
+ if (!subj)
+ return "";
+ util_rfc2047_decode (&subj);
- date[0] = 0;
- if (mailvar_get (NULL, "datefield", mailvar_type_boolean, 0) == 0
- && mu_header_get_value (hdr, MU_HEADER_DATE, date, sizeof (date), NULL) == 0)
+ len = strlen (subj);
+ if (len + 2 > args->cols_rest)
+ len = args->cols_rest - 2;
+ header_ensure_space (args, len + 3);
+ args->buf[0] = '"';
+ memcpy (args->buf + 1, subj, len);
+ args->buf[len+1] = '"';
+ args->buf[len+2] = 0;
+ free (subj);
+ return args->buf;
+}
+
+
+static struct header_segm *
+new_header_segment (int align, size_t width,
+ void *data,
+ char *(*get) (struct header_call_args *, void *))
+{
+ struct header_segm *seg = xmalloc (sizeof (*seg));
+ seg->next = NULL;
+ seg->align = align;
+ seg->width = width;
+ seg->data = data;
+ seg->get = get;
+ return seg;
+}
+
+struct header_segm *
+compile_headline (const char *str)
+{
+ struct header_segm *head = NULL, *tail = NULL;
+ char *text;
+ int align;
+ size_t width;
+
+#define ALIGN_STRING (align == ALIGN_UNDEF ? ALIGN_LEFT : ALIGN_RIGHT)
+#define ALIGN_NUMBER (align == ALIGN_UNDEF ? ALIGN_RIGHT : ALIGN_LEFT)
+#define ATTACH(p) \
+ do \
+ { \
+ if (!head) \
+ head = p; \
+ else \
+ tail->next = p; \
+ tail = p; \
+ } \
+ while (0)
+
+ while (*str)
{
- time_t t;
- if (mu_parse_date (date, &t, NULL) == 0)
+ struct header_segm *seg;
+ size_t len;
+ char *p = strchr (str, '%');
+ if (!p)
+ len = strlen (str);
+ else
+ len = p - str;
+ if (len)
{
- strftime (date, sizeof(date), "%a %b %e %H:%M", localtime (&t));
+ text = xmalloc (len + 1);
+ memcpy (text, str, len);
+ text[len] = 0;
+ seg = new_header_segment (ALIGN_LEFT, 0, text, hdr_text);
+ ATTACH (seg);
+ }
+ if (!p)
+ break;
+
+ str = ++p;
+
+ if (*str == '-')
+ {
+ str++;
+ align = ALIGN_LEFT;
+ }
+ else if (*str == '+')
+ {
+ str++;
+ align = ALIGN_RIGHT;
}
else
- date[0] = 0;
- }
+ align = ALIGN_UNDEF;
+
+ if (mu_isdigit (*str))
+ width = strtoul (str, (char**)&str, 10);
+ else
+ width = 0;
- if (date[0] == 0)
- {
- const char *p;
- struct tm tm;
- mu_timezone tz;
+ switch (*str++)
+ {
+ case '%':
+ seg = new_header_segment (ALIGN_LEFT, 0, xstrdup ("%"), hdr_text);
+ break;
+
+ case 'a': /* Message attributes. */
+ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_attr);
+ break;
- mu_message_get_envelope (msg, &env);
- if (mu_envelope_sget_date (env, &p) == 0
- && mu_parse_ctime_date_time (&p, &tm, &tz) == 0)
- strftime (date, sizeof(date), "%a %b %e %H:%M", &tm);
+ /* FIXME: %c The score of the message. */
+
+ case 'd': /* Message date */
+ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_date);
+ break;
+
+ /* FIXME: %e The indenting level in threaded mode. */
+
+ case 'f': /* Message sender */
+ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_from);
+ break;
+
+ /* FIXME: %i The message thread structure. */
+
+ case 'l': /* The number of lines of the message */
+ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_lines);
+ break;
+
+ case 'm': /* Message number */
+ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_number);
+ break;
+
+ case 'o': /* The number of octets (bytes) in the message */
+ seg = new_header_segment (ALIGN_NUMBER, width, NULL, hdr_size);
+ break;
+
+ case 's': /* Message subject (if any) */
+ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_subject);
+ break;
+
+ case 'S': /* Message subject (if any) in double quotes */
+ seg = new_header_segment (ALIGN_STRING, width, NULL, hdr_q_subject);
+ break;
+
+ /* FIXME: %t The position in threaded/sorted order. */
+
+ case '>': /* A `>' for the current message, otherwise ` ' */
+ seg = new_header_segment (ALIGN_STRING, width, xstrdup (">"), hdr_cur);
+ break;
+
+ case '<': /* A `<' for the current message, otherwise ` ' */
+ seg = new_header_segment (ALIGN_STRING, width, xstrdup ("<"), hdr_cur);
+ break;
+
+ default:
+ mu_error (_("unknown escape: %%%c"), str[-1]);
+ len = str - p;
+ text = xmalloc (len);
+ memcpy (text, p, len-1);
+ text[len-1] = 0;
+ seg = new_header_segment (ALIGN_STRING, width, text, hdr_text);
+ }
+ ATTACH (seg);
}
-
- mu_message_size (msg, &m_size);
- mu_message_lines (msg, &m_lines);
-
- snprintf (st, sizeof (st), "%3d/%-5d", m_lines, m_size);
-
- /* The "From" field will take a third of the screen.
- Subject will take the rest.
- FIXME: This is not quite correct that we use fixed sizes
- 18, 16 for the other fields.
- */
- froml = cols / 3;
- subjl = cols - froml - strlen (st) - 16;
-
- fromp = from ? from : "";
- subjp = subj ? subj : fromp;
- fprintf (ofile, "%c%c%4d %-18.18s %-16.16s %s %.*s\n",
- is_current_message (mspec->msg_part[0]) ? '>' : ' ', cflag,
- mspec->msg_part[0],
- fromp, date, st, (subjl < 0) ? 0 : subjl, subjp);
-
- free (from);
- free (subj);
+ return head;
+#undef ALIGN_STRING
+#undef ALIGN_NUMBER
+#undef ATTACH
+}
+
+/* FIXME: Should it be part of struct mailvar_variable for "headline"? */
+static struct header_segm *mail_header_line;
+
+void
+mail_compile_headline (struct mailvar_variable *var)
+{
+ free_headline (mail_header_line);
+ mail_header_line = compile_headline (var->value.string);
+}
+
+
+/*
+ * f[rom] [msglist]
+ */
+int
+mail_from0 (msgset_t *mspec, mu_message_t msg, void *data)
+{
+ format_headline (mail_header_line, mspec, msg);
return 0;
}
int
mail_from (int argc, char **argv)
{
- return util_foreach_msg (argc, argv, MSG_NODELETED|MSG_SILENT, mail_from0, NULL);
+ return util_foreach_msg (argc, argv, MSG_NODELETED|MSG_SILENT,
+ mail_from0, NULL);
}
diff --git a/mail/mail.c b/mail/mail.c
index d633b035a..805b0e34d 100644
--- a/mail/mail.c
+++ b/mail/mail.c
@@ -287,6 +287,7 @@ static char *default_setup[] = {
"set recursivealiases",
"set noinplacealiases",
"set fromfield",
+ "set headline=\"%>%a%4m %18f %16d %3l/%-5o %s\"",
/* Start in mail reading mode */
"setq mode=read",
@@ -364,7 +365,7 @@ main (int argc, char **argv)
/* set defaults for execution */
for (i = 0; i < sizeof (default_setup)/sizeof (default_setup[0]); i++)
- util_do_command (default_setup[i]);
+ util_do_command ("%s", default_setup[i]);
util_do_command ("set screen=%d", util_getlines ());
util_do_command ("set columns=%d", util_getcols ());
diff --git a/mail/mail.h b/mail/mail.h
index a600d4697..7eeb600a5 100644
--- a/mail/mail.h
+++ b/mail/mail.h
@@ -45,11 +45,7 @@
#endif
#include <sys/wait.h>
#include <sys/types.h>
-#ifdef HAVE_STDARG_H
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
+#include <stdarg.h>
#include <signal.h>
#include <confpaths.h>
@@ -200,6 +196,8 @@ extern int mail_folders (int argc, char **argv);
extern int mail_followup (int argc, char **argv);
extern int mail_from (int argc, char **argv);
extern int mail_from0 (msgset_t *mspec, mu_message_t msg, void *data);
+extern void mail_compile_headline (struct mailvar_variable *var);
+
extern int mail_headers (int argc, char **argv);
extern int mail_hold (int argc, char **argv);
extern int mail_help (int argc, char **argv);
diff --git a/mail/mailvar.c b/mail/mailvar.c
index d101ec83d..e5cc5ce93 100644
--- a/mail/mailvar.c
+++ b/mail/mailvar.c
@@ -130,6 +130,10 @@ struct mailvar_symbol mailvar_tab[] =
{ { "header", },
MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("run the `headers' command after entering interactive mode") },
+ { { "headline", },
+ MAILVAR_TYPEMASK (mailvar_type_string),
+ N_("format string to use for the header summary"),
+ mail_compile_headline },
{ { "hold", },
MAILVAR_TYPEMASK (mailvar_type_boolean),
N_("hold the read or saved messages in the system mailbox") },
diff --git a/mail/util.c b/mail/util.c
index 95ec9b61c..2f485cae1 100644
--- a/mail/util.c
+++ b/mail/util.c
@@ -468,7 +468,7 @@ util_get_homedir ()
char *
util_fullpath (const char *inpath)
{
- return mu_tilde_expansion(inpath, "/", NULL);
+ return mu_tilde_expansion (inpath, "/", NULL);
}
char *
@@ -661,7 +661,7 @@ util_slist_to_string (mu_list_t list, const char *delim)
}
void
-util_strcat(char **dest, const char *str)
+util_strcat (char **dest, const char *str)
{
if (!*dest)
*dest = strdup (str);
@@ -754,26 +754,13 @@ util_save_outgoing (mu_message_t msg, char *savefile)
}
}
-#ifdef HAVE_STDARG_H
void
util_error (const char *format, ...)
-#else
-void
-util_error (va_alist)
- va_dcl
-#endif
{
va_list ap;
-#ifdef HAVE_STDARG_H
- va_start(ap, format);
-#else
- char *format;
-
- va_start (ap);
- format = va_arg (ap, char *);
-#endif
-
+ va_start (ap, format);
+
vfprintf (stderr, format, ap);
fprintf (stderr, "\n");

Return to:

Send suggestions and report system problems to the System administrator.