Commit 9b0dee5f 9b0dee5fa917d5804aa2ca89a186ea8da64578ca by Sergey Poznyakoff

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.
1 parent f2eb56bb
GNU mailutils NEWS -- history of user-visible changes. 2009-08-03
GNU mailutils NEWS -- history of user-visible changes. 2009-08-14
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007,
2008, 2009 Free Software Foundation, Inc.
See the end of file for copying conditions.
......@@ -83,6 +83,12 @@ described.
For each variable, this command prints its name, data type, current
value and a short description.
** headline variable
The headline variable holds a format string to use for the header
summary. Its format is mostly compatible with that of the `nail'
mail reader.
** showenvelope variable
If the `showenvelope' variable is set, print command will include the
......@@ -90,7 +96,7 @@ SMTP envelope in its output.
** fromfield variable
The `fromenvelope' boolean variable, if set, instructs mail to obtain
The `fromfield' boolean variable, if set, instructs mail to obtain
the sender address from the `From:' header. This is the default.
If unset, the sender address is obtained from the SMTP envelope.
......
......@@ -2240,14 +2240,14 @@ but before opening the mailbox.
@itemx --file
Operate on the mailbox given by the first non-optional command line
argument. If there is no such argument, read messages from the
user's @file{mbox} file. @xref{Reading Mail} for more details about
user's @file{mbox} file. @xref{Reading Mail}, for more details about
using this option.
@item -F
@itemx --byname
Record outgoing messages in a file named after the first recipient.
The name is the login-name portion of the address found first on the
@samp{To:} line in the mail header. This option sets the @samp{byname}
variable, which see (@xref{byname}).
variable, which see (@pxref{byname}).
@item -H
@itemx --headers
Print header summary to stdout and exit.
......@@ -3482,6 +3482,7 @@ set
Following variables control the behavior of GNU @command{mail}:
@table @code
@kwindex append
@item append
@*Type: Boolean, Read-Only
@*Default: True
......@@ -3491,6 +3492,7 @@ Messages saved in mbox are appended to the end rather than prepended.
This is the default and cannot be changed. This variable exists only
for compatibility with other @command{mailx} implementations.
@kwindex appenddeadletter
@item appenddeadletter
@*Type: Boolean.
@*Default: False.
......@@ -3500,6 +3502,7 @@ If this variable is @code{True}, the contents of canceled letter is
appended to the user's @file{dead.letter} file. Otherwise it overwrites
its contents.
@kwindex askbcc
@item askbcc
@*Type: Boolean.
@*Default: False.
......@@ -3508,6 +3511,7 @@ its contents.
When set to @code{True} the user will be prompted to enter @code{Bcc}
field before composing the message.
@kwindex askcc
@item askcc
@*Type: Boolean.
@*Default: True.
......@@ -3516,6 +3520,7 @@ field before composing the message.
When set to @code{True} the user will be prompted to enter @code{Cc}
field before composing the message.
@kwindex asksub
@item asksub
@*Type: Boolean.
@*Default: True in interactive mode, False otherwise.
......@@ -3524,6 +3529,7 @@ field before composing the message.
When set to @code{True} the user will be prompted to enter @code{Subject}
field before composing the message.
@kwindex autoinc
@item autoinc
@*Type: Boolean.
@*Default: True.
......@@ -3531,6 +3537,7 @@ field before composing the message.
Automatically incorporate newly arrived messages.
@kwindex autoprint
@item autoprint
@*Type: Boolean.
@*Default: False.
......@@ -3539,6 +3546,7 @@ Automatically incorporate newly arrived messages.
Causes the delete command to behave like dp - thus, after deleting a
message, the next one will be typed automatically.
@kwindex bang
@item bang
@*Type: Boolean.
@*Default: False.
......@@ -3548,6 +3556,7 @@ When set, every occurrence of @code{!} in arguments to @code{!}
command is replaced with the last executed command.
@anchor{byname}
@kwindex byname
@item byname
@*Type: Boolean
@*Default: Unset
......@@ -3561,6 +3570,7 @@ The name is the login-name portion of the address found first on the
It is set by the @option{--byname} (@option{-F}) command line option.
@anchor{datefield}
@kwindex datefield
@item datefield
@*Type: Boolean.
@*Default: False.
......@@ -3574,6 +3584,7 @@ will fall back to using @acronym{SMTP} envelope.
@xref{fromfield}.
@kwindex charset
@item charset
@*Type: string
@*Default: @samp{auto}
......@@ -3586,6 +3597,7 @@ variable is set to @samp{auto}, @command{mail} tries to deduce the
name of the character set from the value of @code{LC_ALL} environment
variable. Otherwise, its value is taken as the name of the charset.
@kwindex cmd
@item cmd
@*Type: String.
@*Default: Unset.
......@@ -3593,6 +3605,7 @@ variable. Otherwise, its value is taken as the name of the charset.
Contains default shell command for @code{pipe}.
@kwindex columns
@item columns
@*Type: Numeric.
@*Default: Detected at startup by querying the terminal device. If this
......@@ -3601,6 +3614,7 @@ fails, the value of environment variable @code{COLUMNS} is used.
This variable contains the number of columns on terminal screen.
@kwindex crt
@item crt
@*Type: Boolean or Numeric
@*Default: True in interactive mode, False otherwise.
......@@ -3614,6 +3628,7 @@ if @code{crt} is set without a value, then the height of the terminal
screen is used to compute the threshold. The number of lines on
screen is controlled by @code{screen} variable.
@kwindex debug
@item debug
@*Type: String to boolean
@*Default: Not set
......@@ -3628,6 +3643,7 @@ information. If set to @samp{true} (i.e. @code{set debug}), sets
maximum debugging (@samp{<trace7}) on mailbox and its underlying
objects.
@kwindex decode-fallback
@item decode-fallback
@*Type: String.
@*Default: @samp{none}.
......@@ -3650,6 +3666,7 @@ Unprintable characters are represented by their octal codes. Printable
ones are printed @samp{as is}.
@end table
@kwindex debug
@item debug
@*Type: Boolean
@*Default: Unset
......@@ -3658,6 +3675,7 @@ ones are printed @samp{as is}.
This variable is not used. It exists for compatibility with other
@command{mailx} implementations and for future use.
@kwindex dot
@item dot
@*Type: Boolean.
@*Default: False.
......@@ -3666,6 +3684,7 @@ This variable is not used. It exists for compatibility with other
If @code{True}, causes @command{mail} to interpret a period alone on a line as the
terminator of a message you are sending.
@kwindex emptystart
@item emptystart
@*Type: Boolean.
@*Default: False.
......@@ -3675,6 +3694,7 @@ If the mailbox is empty, @command{mail} normally prints @samp{No mail for user}
exits immediately. If this option is set, @command{mail} will start no matter is
the mailbox empty or not.
@kwindex editheaders
@item editheaders
@*Type: Boolean.
@*Default: False.
......@@ -3684,6 +3704,7 @@ When set, @command{mail} will include message headers in the text to
be the @code{~e} and @code{~v} escapes, thus allowing you to customize
the headers.
@kwindex escape
@item escape
@*Type: String.
@*Default: ~
......@@ -3692,6 +3713,7 @@ the headers.
If defined, the first character of this option gives the character to
denoting escapes.
@kwindex flipr
@item flipr
@*Type: Boolean
@*Default: Unset
......@@ -3700,6 +3722,7 @@ denoting escapes.
If set, the variable @code{flipr} swaps the meanings of @code{reply}
and @code{Reply} commands (@pxref{Replying}).
@kwindex folder
@item folder
@*Type: String.
@*Default: Unset.
......@@ -3709,6 +3732,7 @@ The name of the directory to use for storing folders of messages. If
unset, @env{$HOME} is assumed.
@anchor{fromfield}
@kwindex fromfield
@item fromfield
@*Type: Boolean.
@*Default: True.
......@@ -3719,6 +3743,7 @@ Unsetting this variable tells @command{mail} to obtain it from the
@xref{datefield}.
@kwindex header
@item header
@*Type: Boolean.
@*Default: True, unless started with @option{--nosum} (@option{-N}) option.
......@@ -3727,6 +3752,56 @@ Unsetting this variable tells @command{mail} to obtain it from the
Whether to run @code{headers} command automatically after entering
interactive mode.
@kwindex headline
@item headline
@*Type: String
@*Default: @samp{%>%a%4m %18f %16d %3l/%-5o %s}
A format string to use for the header summary. The @samp{%} character
introduces a @dfn{format specifier}. Valid format specifiers are:
@multitable @columnfractions 0.2 0.8
@headitem Letter @tab Meaning
@item %a @tab Message attributes.
@item %d @tab The date when the message was received.
@item %f @tab The address of the message sender.
@item %l @tab The number of lines of the message.
@item %m @tab Message number.
@item %o @tab The number of octets (bytes) in the message.
@item %s @tab Message subject (if any).
@item %S @tab Message subject (if any) in double quotes.
@item %> @tab A @samp{>} for the current message, otherwise a space.
@item %< @tab A @samp{<} for the current message, otherwise a space.
@item %% @tab A `%' character.
@end multitable
Some additional symbols are allowed between @samp{%} and the specifier
letter. The @samp{-} character immediately following @samp{%}
indicates that this field should be left aligned. Similarly, the
@samp{+} character indicates right alignment. Default alignment
depends on the type of the specifier: the specifiers that produce
numeric values (@samp{%l}, @samp{%m}, and @samp{%o}) are aligned to
the right, whereas the ones producing string values are aligned to the
left.
A number following @samp{%} or the alignment flag, indicates the
field width. Consider, for example, the following specifiers:
@table @asis
@item %m
Print current message number. Take as much screen columns as necessary
to output it.
@item %4m
@itemx %+4m
Print current message number. Occupy 4 screen columns, truncate the
output if it does not fit that width. Align the output to the right.
@item %-4m
Same as above, but align to the left.
@end table
@kwindex hold
@item hold
@*Type: Boolean.
@*Default: False.
......@@ -3737,6 +3812,7 @@ user's mailbox (@file{$HOME/mbox}). Otherwise, they will be held in
system mailbox also. This option is in effect only when operating
upon user's system mailbox.
@kwindex ignore
@item ignore
@*Type: Boolean.
@*Default: False.
......@@ -3746,6 +3822,7 @@ When set to @code{True}, @command{mail} will ignore keyboard interrupts
when composing messages. Otherwise an interrupt will be taken as a
signal to abort composing.
@kwindex ignoreeof
@item ignoreeof
@*Type: Boolean.
@*Default: False.
......@@ -3754,6 +3831,7 @@ signal to abort composing.
Controls whether typing EOF character terminates the letter being
composed.
@kwindex indentprefix
@item indentprefix
@*Type: String.
@*Default: "\t" (a tab character).
......@@ -3761,6 +3839,7 @@ composed.
String used by the @code{~m} tilde escape for indenting quoted messages.
@kwindex inplacealiases
@item inplacealiases
@*Type: Boolean
@*Default: False
......@@ -3770,6 +3849,7 @@ before entering send mode (@pxref{Composing Mail}). By default, the
address header fields are left intact while composing, the alias
expansion takes place immediately before sending message.
@kwindex keep
@item keep
@*Type: Boolean, Read-Only
@*Default: True
......@@ -3779,6 +3859,7 @@ Truncate the user's system mailbox when it is empty, instead of
removing it. This is the default and cannot be changed. This variable
exists only for compatibility with other @command{mailx} implementations.
@kwindex keepsave
@item keepsave
@*Type: Boolean.
@*Default: False.
......@@ -3788,6 +3869,7 @@ Controls whether saved messages should be kept in system mailbox too.
This variable is in effect only when operating upon a user's system
mailbox.
@kwindex mailx
@item mailx
@*Type: Boolean.
@*Default: False.
......@@ -3807,6 +3889,7 @@ will exit with zero status. By default it exits with zero status only
if the message was sent successfully.
@end itemize
@kwindex metamail
@item metamail
@*Type: Boolean or String.
@*Default: True.
......@@ -3830,6 +3913,7 @@ set metamail
set metamail="metamail -m mail -p"
@end smallexample
@kwindex mimenoask
@item mimenoask
@*Type: String
@*Default: Empty
......@@ -3850,6 +3934,7 @@ will disable prompting before displaying any textual files, no
matter what their subtype is, and before displaying files with
type @samp{image/jpeg}.
@kwindex metoo
@item metoo
@*Type: Boolean.
@*Default: False.
......@@ -3859,6 +3944,7 @@ Usually, when an alias is expanded that contains the sender, the sender
is removed from the expansion. Setting this option causes the sender to
be included in the group.
@kwindex mode
@item mode
@*Type: String, Read-Only
@*Default: The name of current operation mode.
......@@ -3888,6 +3974,7 @@ The program operates in send mode. This means it was given one or more
recipient addresses in the command line.
@end table
@kwindex nullbody
@item nullbody
@* Type: Boolean
@* Default: True
......@@ -3912,6 +3999,7 @@ outputs something on its standard output or error:
@end group
@end smallexample
@kwindex showenvelope
@item showenvelope
@*Type: Boolean
@*Default: Unset
......@@ -3919,6 +4007,7 @@ outputs something on its standard output or error:
If this variable is set, the @code{print} command will include the
@acronym{STMP} envelope in its output.
@kwindex nullbodymsg
@item nullbodymsg
@*Type: String
@*Default: Null message body; hope that's ok
......@@ -3930,6 +4019,7 @@ this text, in accordance with the current locale, is displayed.
Unsetting this variable disables the warning.
@kwindex onehop
@item onehop
@*Type: Boolean
@*Default: Unset
......@@ -3938,6 +4028,7 @@ Unsetting this variable disables the warning.
This variable is not used. It exists for compatibility with other
@command{mailx} implementations and for future use.
@kwindex outfolder
@item outfolder
@*Type: String.
@*Default: Unset.
......@@ -3947,6 +4038,7 @@ Contains the directory in which files created by @code{save},
@code{write}, etc. commands will be stored. When unset, current
directory is assumed.
@kwindex page
@item page
@*Type: Boolean.
@*Default: False.
......@@ -3955,6 +4047,7 @@ directory is assumed.
If set to @code{True}, the @code{pipe} command will emit a linefeed
character after printing each message.
@kwindex prompt
@item prompt
@*Type: String.
@*Default: "? "
......@@ -3962,6 +4055,7 @@ character after printing each message.
Contains the command prompt sequence.
@kwindex quiet
@item quiet
@*Type: Boolean
@*Default: Unset
......@@ -3970,6 +4064,7 @@ Contains the command prompt sequence.
This variable is not used. It exists for compatibility with other
@command{mailx} implementations and for future use.
@kwindex quit
@item quit
@*Type: Boolean.
@*Default: False, unless started with @option{--quit} (@option{-q}) option.
......@@ -3977,6 +4072,7 @@ This variable is not used. It exists for compatibility with other
When set, causes keyboard interrupts to terminate the program.
@kwindex rc
@item rc
@*Type: Boolean.
@*Default: True, unless started with @option{--norc} (@option{-N}) option.
......@@ -3985,6 +4081,7 @@ When set, causes keyboard interrupts to terminate the program.
When this variable is set, @command{mail} will read the system-wide
configuration file upon startup. See @ref{Mail Configuration Files}.
@kwindex readonly
@item readonly
@*Type: Boolean
@*Default: False
......@@ -3995,6 +4092,7 @@ When set, mailboxes are opened in readonly mode. In this mode, any
disabled. These commands include, but are not limited to:
@code{delete}, @code{save} and @code{mbox}.
@kwindex record
@item record
@*Type: String.
@*Default: Unset.
......@@ -4002,12 +4100,14 @@ disabled. These commands include, but are not limited to:
When set, any outgoing message will be saved to the named file.
@kwindex recursivealiases
@item recursivealiases
@*Type: Boolean
@*Default: True
When set, @command{mail} will expand aliases recursively.
@kwindex regex
@item regex
@*Type: Boolean.
@*Default: True.
......@@ -4016,6 +4116,7 @@ When set, @command{mail} will expand aliases recursively.
Setting this to @code{True} enables use of regular expressions in
@samp{/.../} message specifications.
@kwindex replyprefix
@item replyprefix
@*Type: String
@*Default: @samp{Re: }
......@@ -4024,6 +4125,7 @@ Setting this to @code{True} enables use of regular expressions in
Sets the prefix that will be used when constructing the subject line
of a reply message.
@kwindex replyregex
@item replyregex
@*Type: String
@*Default: @samp{^re: *}
......@@ -4045,6 +4147,7 @@ set replyregex="^(re|odp|aw|ang)(\\[[0-9]+\\])?:[[:blank:]]"
@noindent
(Notice the quoting of backslash characters).
@kwindex save
@item save
@*Type: Boolean.
@*Default: True.
......@@ -4053,6 +4156,7 @@ set replyregex="^(re|odp|aw|ang)(\\[[0-9]+\\])?:[[:blank:]]"
When set, the aborted messages will be stored in the user's
@file{dead.file}. See also @code{appenddeadletter}.
@kwindex screen
@item screen
@*Type: Numeric.
@*Default: Detected at startup by querying the terminal device. If this
......@@ -4061,6 +4165,7 @@ fails, the value of environment variable @code{LINES} is used.
This variable contains the number of lines on terminal screen.
@kwindex sendmail
@item sendmail
@*Type: String.
@*Default: sendmail:/usr/lib/sendmail
......@@ -4068,6 +4173,7 @@ This variable contains the number of lines on terminal screen.
Contains URL of the mail transport agent.
@kwindex sendwait
@item sendwait
@*Type: Boolean
@*Default: Unset
......@@ -4076,6 +4182,7 @@ Contains URL of the mail transport agent.
This variable is not used. It exists for compatibility with other
@command{mailx} implementations and for future use.
@kwindex showto
@item showto
@*Type: Boolean
@*Default: False
......@@ -4084,6 +4191,7 @@ This variable is not used. It exists for compatibility with other
If the message was sent by the user, print its recipient address in
the header summary.
@kwindex Sign
@item Sign
@*Type: String.
@*Default: Unset.
......@@ -4093,6 +4201,7 @@ Contains the filename holding users signature. The contents of this
file is appended to the end of a message being composed by @code{~A}
escape.
@kwindex sign
@item sign
@*Type: String.
@*Default: Unset.
......@@ -4102,6 +4211,7 @@ Contains the user's signature. The contents of this variable is appended
to the end of a message being composed by @code{~a} escape. Use
@code{Sign} variable, if your signature occupies more than one line.
@kwindex showto
@item showto
@*Type: Boolean
@*Default: unset
......@@ -4111,6 +4221,7 @@ If this variable is set, @command{mail} will show @code{To:} addresses
instead of @code{From:} for all messages that come from the user that
invoked the program.
@kwindex subject
@item subject
@*Type: String.
@*Default: Unset.
......@@ -4119,6 +4230,7 @@ invoked the program.
Contains default subject line. This will be used when @code{asksub} is
off.
@kwindex toplines
@item toplines
@*Type: Numeric.
@*Default: 5
......@@ -4126,6 +4238,7 @@ off.
Number of lines to be displayed by @code{top} and @code{Top} commands.
@kwindex variable-strict
@item variable-strict
@itemx varstrict
@*Type: Boolean.
......@@ -4138,6 +4251,7 @@ variables. Also, if the user is trying to set an unknown variable,
@xref{Setting and Unsetting the Variables}.
@kwindex variable-pretty-print
@item variable-pretty-print
@itemx varpp
@*Type: Boolean.
......@@ -4146,6 +4260,7 @@ variables. Also, if the user is trying to set an unknown variable,
If this variable is set, the listing ouput by @command{set} contains short
descriptions before each variable. @xref{Setting and Unsetting the Variables}.
@kwindex verbose
@item verbose
@*Type: Boolean.
@*Default: False.
......@@ -4153,6 +4268,7 @@ descriptions before each variable. @xref{Setting and Unsetting the Variables}.
When set, the actual delivery of messages is displayed on the user's terminal.
@kwindex xmailer
@item xmailer
@*Type: Boolean.
@*Default: Set.
......
......@@ -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);
}
......
......@@ -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 ());
......
......@@ -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);
......
......@@ -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") },
......
......@@ -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");
......