diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-07-12 18:09:57 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-07-12 18:09:57 +0300 |
commit | 0a7e59334332346755a05df5f85aafdba629d78d (patch) | |
tree | 178e39495c7165e4d119a9b3b1f6f07f9750138e | |
parent | 61295ae0e724c62ac016dfc374d6064c63270288 (diff) | |
download | mailutils-0a7e59334332346755a05df5f85aafdba629d78d.tar.gz mailutils-0a7e59334332346755a05df5f85aafdba629d78d.tar.bz2 |
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.
-rw-r--r-- | NEWS | 21 | ||||
-rw-r--r-- | doc/texinfo/programs.texi | 65 | ||||
-rw-r--r-- | mail/mail.c | 160 |
3 files changed, 154 insertions, 92 deletions
@@ -1,4 +1,4 @@ -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 diff --git a/doc/texinfo/programs.texi b/doc/texinfo/programs.texi index 1c21a5257..0267fd850 100644 --- a/doc/texinfo/programs.texi +++ b/doc/texinfo/programs.texi @@ -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}. diff --git a/mail/mail.c b/mail/mail.c index ff98d9cb5..7fe8a6960 100644 --- a/mail/mail.c +++ b/mail/mail.c @@ -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,32 +81,20 @@ 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; case 'e': 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 ((rc = mu_mailbox_create_default (&mbox, args.file)) != 0) { - 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); - } + if (args.file) + util_error (_("Cannot create mailbox %s: %s"), args.file, + mu_strerror (rc)); 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) - { - util_error (_("Cannot create mailbox %s: %s"), args.file, - mu_strerror (rc)); + 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" |