Commit 0a7e5933 0a7e59334332346755a05df5f85aafdba629d78d by Sergey Poznyakoff

Improve mail compliance to POSIX standard

* mail/mail.c: Redo -f option handling to fully comply to POSIX
Set default diagnostics printer for interactive mode.
* NEWS, doc/texinfo/programs.texi: Document the use of -f option.
1 parent 61295ae0
GNU mailutils NEWS -- history of user-visible changes. 2009-07-11
GNU mailutils NEWS -- history of user-visible changes. 2009-07-12
Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007,
2008, 2009 Free Software Foundation, Inc.
See the end of file for copying conditions.
......@@ -29,6 +29,25 @@ information.
* Mail
** The -f option
The semantics of -f (--file) option fully complies to the POSIX
standard. Namely, this option instructs mail to read messages
from the file named by the first non-optional command line
argument. Therefore, the following four usage patterns are
entirely equivalent:
mail -fin mymbox
mail -f mymbox -in
mail --file -in mymbox
mail --file -i mymbox -n
In addition, the form
mail --file=mymbox
is also allowed.
** envelope command
The env[elope] command displays the SMTP envelopes of the messages
......
......@@ -2189,9 +2189,8 @@ See @ref{Composing Mail}, for a detailed description of this behavior.
If the command line contained no email addresses, @command{mail} switches
to reading mode. In this mode it allows to read and manipulate the
contents of a mailbox. The URL of the mailbox to operate upon is
taken from the argument of @option{--file} command line option. If it
is not specified, the user's system mailbox is assumed. For more
contents of the user system mailbox. The @option{--file} (@option{-f})
command line option allows to specify another mailbox name. For more
detail, see @ref{Reading Mail}.
In contrast to other GNU Mailutils programs, @command{mail} does not
......@@ -2237,16 +2236,12 @@ Execute @var{command} before opening the mailbox. Any number of
@option{--exec} options can be given. The commands will be executed
after sourcing configuration files (@pxref{Mail Configuration Files}),
but before opening the mailbox.
@item --exec
@item -f[@var{file}]
@itemx --file[=@var{file}]
Operate on mailbox @var{file}. If this option is not specified, the default
is user's system mailbox. If it is specified without argument, the
default is @file{$HOME/mbox}.
@emph{Please note}, that there should be no whitespace between the
short variant of the option (@option{-f}), and its parameter. Similarly,
when using long option (@option{--file}), its argument must be preceded by
equal sign.
@item -f
@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
using this option.
@item -F
@itemx --byname
Save messages according to sender. Currently this option is not implemented.
......@@ -2628,10 +2623,15 @@ invoking @command{mail}:
@table @code
@item mail
To read messages from your system mailbox.
@item mail --file
To read messages from your mailbox (@file{$HOME/mbox}).
@item mail --file=@var{path_to_mailbox}
@item mail -f
@itemx mail --file
To read messages from your mailbox (@file{$HOME/mbox}). If the
@option{--user} option (see below) is also given, read messages
from that user's @file{mbox}.
@item mail -f @var{path_to_mailbox}
@itemx mail --file @var{path_to_mailbox}
To read messages from the specified mailbox.
@itemx mail -u @var{user}
@item mail --user=@var{user}
To read messages from the system mailbox belonging to @var{user}.
@end table
......@@ -2641,6 +2641,25 @@ to use the last variant of invocation, unless you are a super-user.
Similarly, the last but one variant is also greatly affected by the
permissions the target mailbox has.
Notice that @var{path_to_mailbox} is not an argument to
@option{--file} (@option{-f}) option, but rather the first
non-optional argument on the command line. Therefore, the
following three invocations are equivalent:
@smallexample
$ mail -fin mymbox
$ mail -f mymbox -in
$ mail --file -in mymbox
$ mail --file -i mymbox -n
@end smallexample
Additionally, for conformance to the GNU standards, the
following form is also accepted:
@smallexample
$ mail --file=mymbox -i -n
@end smallexample
Unless you have started mail with @option{--norc} command line option,
it will read the contents of the system-wide configuration file.
Then it reads the contents of user configuration file, if any.
......@@ -3563,6 +3582,20 @@ 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.
@item debug
@*Type: String to boolean
@*Default: Not set
@vrindex debug, mail variable
Sets mailutils debug level. If set to string, the value must be a
valid Mailutils debugging specification. @xref{Debug Statement}, for
a description.
If unset (i.e. @code{set nodebug}), clears and disables all debugging
information. If set to @samp{true} (i.e. @code{set debug}), sets
maximum debugging (@samp{<trace7}) on mailbox and its underlying
objects.
@item decode-fallback
@*Type: String.
@*Default: @samp{none}.
......
......@@ -30,13 +30,18 @@ static mu_list_t command_list; /* List of commands to be executed after parsin
command line */
const char *program_version = "mail (" PACKAGE_STRING ")";
static char doc[] = N_("GNU mail -- the standard /bin/mail interface");
static char args_doc[] = N_("[address...]");
static char doc[] = N_("GNU mail -- process mail messages.\n"
"If -f or --file is given, mail operates on the mailbox named "
"by the first argument, or the user's mbox, if no argument given.\n");
static char args_doc[] = N_("[address...]\n-f [OPTION...] [file]\n--file [OPTION...] [file]\n--file=file [OPTION...]");
#define F_OPTION 256
static struct argp_option options[] = {
{ NULL, 'f', 0, OPTION_HIDDEN, NULL, 0 },
{"file", F_OPTION, "FILE", OPTION_ARG_OPTIONAL|OPTION_HIDDEN, 0},
{"exist", 'e', 0, 0, N_("Return true if mail exists"), 0},
{"file", 'f', N_("URL"), OPTION_ARG_OPTIONAL,
N_("Operate on given mailbox URL (default ~/mbox)"), 0},
{"byname", 'F', 0, 0, N_("Save messages according to sender"), 0},
{"headers", 'H', 0, 0, N_("Write a header summary and exit"), 0},
{"ignore", 'i', 0, 0, N_("Ignore interrupts"), 0},
......@@ -56,12 +61,16 @@ static struct argp_option options[] = {
};
#define HINT_SEND_MODE 0x1
#define HINT_FILE_OPTION 0x2
struct arguments
{
char **args;
int argc;
char **argv;
char *file;
char *user;
int send_mode;
int hint;
};
static error_t
......@@ -72,7 +81,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
switch (key)
{
case 'a':
args->send_mode = 1;
args->hint |= HINT_SEND_MODE;
send_append_header (arg);
break;
......@@ -80,24 +89,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
util_cache_command (&command_list, "setq mode=exist");
break;
case 'f':
if (arg != NULL)
case F_OPTION:
if (arg)
args->file = arg;
/* People often tend to separate -f option from its argument
with a whitespace. This heuristics tries to catch the
error: */
else if (state->next < state->argc
&& state->argv[state->next][0] != '-')
args->file = state->argv[state->next++];
else
{
int len;
char *home = getenv("HOME");
len = strlen (home) + strlen ("/mbox") + 1;
args->file = xmalloc(len * sizeof (char));
strcpy (args->file, home);
strcat (args->file, "/mbox");
}
/* fall through */
case 'f':
args->hint |= HINT_FILE_OPTION;
break;
case 'p':
......@@ -130,9 +127,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case 's':
args->hint |= HINT_SEND_MODE;
send_append_header2 (MU_HEADER_SUBJECT, arg, COMPOSE_REPLACE);
util_cache_command (&command_list, "set noasksub");
args->send_mode = 1;
break;
case 'u':
......@@ -149,15 +146,39 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case ARGP_KEY_ARG:
args->args = realloc (args->args,
args->argv = realloc (args->argv,
sizeof (char *) * (state->arg_num + 2));
args->args[state->arg_num] = arg;
args->args[state->arg_num + 1] = NULL;
args->send_mode = 1;
args->argv[state->arg_num] = arg;
args->argv[state->arg_num + 1] = NULL;
args->argc = state->arg_num + 1;
break;
case ARGP_KEY_FINI:
if (args->send_mode)
if ((args->hint & (HINT_SEND_MODE|HINT_FILE_OPTION)) ==
(HINT_SEND_MODE|HINT_FILE_OPTION))
argp_error (state, _("conflicting options"));
else if (args->hint & HINT_FILE_OPTION)
{
if (args->file)
{
if (args->argc > 1)
argp_error (state,
_("-f requires at most one command line argument"));
}
else if (args->argc)
{
args->file = args->argv[0];
if (args->argc > 1)
argp_error (state,
_("-f requires at most one command line argument"));
}
else if (args->user)
asprintf (&args->file, "~/%s/mbox", args->user);
else
args->file = "~/mbox";
}
else if (args->argc || (args->hint & HINT_SEND_MODE))
util_cache_command (&command_list, "setq mode=send");
break;
......@@ -230,7 +251,7 @@ static char *default_setup[] = {
"set noautoprint",
"set nobang",
"set nocmd",
"set nodebug",
/* "set nodebug",*/
"set nodot",
"set escape=~",
"set noflipr",
......@@ -281,11 +302,19 @@ static char *default_setup[] = {
"set nullbodymsg=\"" N_("Null message body; hope that's ok") "\"",
/* These settings are not yet used */
"set nodebug",
"set noonehop",
"set nosendwait",
};
static int
mail_diag_stderr_printer (void *data, mu_log_level_t level, const char *buf)
{
if (level != MU_DIAG_ERROR)
fprintf (stderr, "%s: ", mu_diag_level_to_string (level));
fputs (buf, stderr);
return 0;
}
int
main (int argc, char **argv)
{
......@@ -345,14 +374,15 @@ main (int argc, char **argv)
char *mailer_name = alloca (strlen ("sendmail:")
+ strlen (PATH_SENDMAIL) + 1);
sprintf (mailer_name, "sendmail:%s", PATH_SENDMAIL);
mailvar_set ("sendmail", mailer_name, mailvar_type_string, MOPTF_OVERWRITE);
mailvar_set ("sendmail", mailer_name, mailvar_type_string,
MOPTF_OVERWRITE);
}
args.args = NULL;
args.argc = 0;
args.argv = NULL;
args.file = NULL;
args.user = NULL;
args.send_mode = 0;
args.hint = 0;
/* argument parsing */
#ifdef WITH_TLS
......@@ -369,7 +399,14 @@ main (int argc, char **argv)
util_run_cached_commands (&command_list);
if (!interactive)
if (interactive)
{
mu_debug_t debug;
mu_diag_get_debug (&debug);
mu_debug_set_print (debug, mail_diag_stderr_printer, NULL);
}
else
{
util_do_command ("set nocrt");
util_do_command ("set noasksub");
......@@ -384,60 +421,33 @@ main (int argc, char **argv)
/* Interactive mode */
ml_readline_init ();
mail_set_my_name(args.user);
mail_set_my_name (args.user);
/* Mode is just sending */
if (strcmp (mode, "send") == 0)
{
/* FIXME: set cmd to "mail [add1...]" */
char *buf = NULL;
int num = 0;
int rc;
if (args.args != NULL)
while (args.args[num] != NULL)
num++;
mu_argcv_string (num, args.args, &buf);
mu_argcv_string (args.argc, args.argv, &buf);
rc = util_do_command ("mail %s", buf);
return mailvar_get (NULL, "mailx", mailvar_type_boolean, 0) ? rc : 0;
}
/* Or acting as a normal reader */
else
{
/* open the mailbox */
if (args.file == NULL)
{
if (args.user)
{
char *p = xmalloc (strlen (args.user) + 2);
p[0] = '%';
strcpy (p + 1, args.user);
rc = mu_mailbox_create_default (&mbox, p);
free (p);
}
else
rc = mu_mailbox_create_default (&mbox, NULL);
if (rc != 0)
{
util_error (_("Cannot create mailbox for %s: %s"), args.user,
mu_strerror (rc));
exit (EXIT_FAILURE);
}
}
else if ((rc = mu_mailbox_create_default (&mbox, args.file)) != 0)
if ((rc = mu_mailbox_create_default (&mbox, args.file)) != 0)
{
if (args.file)
util_error (_("Cannot create mailbox %s: %s"), args.file,
mu_strerror (rc));
else
util_error (_("Cannot create mailbox: %s"),
mu_strerror (rc));
exit (EXIT_FAILURE);
}
/* Could we enable this at runtime, via the a set environment? */
if (0)
{
mu_debug_t debug = NULL;
mu_mailbox_get_debug (mbox, &debug);
mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
}
if ((rc = mu_mailbox_open (mbox, MU_STREAM_RDWR|MU_STREAM_CREAT)) != 0)
{
mu_url_t url = NULL;
......@@ -547,7 +557,7 @@ mail_warranty (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
{
fputs (_("GNU Mailutils -- a suite of utilities for electronic mail\n"
"Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,\n"
"2007 Free Software Foundation, Inc.\n\n"),
"2007, 2009 Free Software Foundation, Inc.\n\n"),
ofile);
fputs (
_(" GNU Mailutils is free software; you can redistribute it and/or modify\n"
......