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
1 GNU mailutils NEWS -- history of user-visible changes. 2009-07-11 1 GNU mailutils NEWS -- history of user-visible changes. 2009-07-12
2 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2 Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007,
3 2008, 2009 Free Software Foundation, Inc. 3 2008, 2009 Free Software Foundation, Inc.
4 See the end of file for copying conditions. 4 See the end of file for copying conditions.
...@@ -29,6 +29,25 @@ information. ...@@ -29,6 +29,25 @@ information.
29 29
30 * Mail 30 * Mail
31 31
32 ** The -f option
33
34 The semantics of -f (--file) option fully complies to the POSIX
35 standard. Namely, this option instructs mail to read messages
36 from the file named by the first non-optional command line
37 argument. Therefore, the following four usage patterns are
38 entirely equivalent:
39
40 mail -fin mymbox
41 mail -f mymbox -in
42 mail --file -in mymbox
43 mail --file -i mymbox -n
44
45 In addition, the form
46
47 mail --file=mymbox
48
49 is also allowed.
50
32 ** envelope command 51 ** envelope command
33 52
34 The env[elope] command displays the SMTP envelopes of the messages 53 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. ...@@ -2189,9 +2189,8 @@ See @ref{Composing Mail}, for a detailed description of this behavior.
2189 2189
2190 If the command line contained no email addresses, @command{mail} switches 2190 If the command line contained no email addresses, @command{mail} switches
2191 to reading mode. In this mode it allows to read and manipulate the 2191 to reading mode. In this mode it allows to read and manipulate the
2192 contents of a mailbox. The URL of the mailbox to operate upon is 2192 contents of the user system mailbox. The @option{--file} (@option{-f})
2193 taken from the argument of @option{--file} command line option. If it 2193 command line option allows to specify another mailbox name. For more
2194 is not specified, the user's system mailbox is assumed. For more
2195 detail, see @ref{Reading Mail}. 2194 detail, see @ref{Reading Mail}.
2196 2195
2197 In contrast to other GNU Mailutils programs, @command{mail} does not 2196 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 ...@@ -2237,16 +2236,12 @@ Execute @var{command} before opening the mailbox. Any number of
2237 @option{--exec} options can be given. The commands will be executed 2236 @option{--exec} options can be given. The commands will be executed
2238 after sourcing configuration files (@pxref{Mail Configuration Files}), 2237 after sourcing configuration files (@pxref{Mail Configuration Files}),
2239 but before opening the mailbox. 2238 but before opening the mailbox.
2240 @item --exec 2239 @item -f
2241 @item -f[@var{file}] 2240 @itemx --file
2242 @itemx --file[=@var{file}] 2241 Operate on the mailbox given by the first non-optional command line
2243 Operate on mailbox @var{file}. If this option is not specified, the default 2242 argument. If there is no such argument, read messages from the
2244 is user's system mailbox. If it is specified without argument, the 2243 user's @file{mbox} file. @xref{Reading Mail} for more details about
2245 default is @file{$HOME/mbox}. 2244 using this option.
2246 @emph{Please note}, that there should be no whitespace between the
2247 short variant of the option (@option{-f}), and its parameter. Similarly,
2248 when using long option (@option{--file}), its argument must be preceded by
2249 equal sign.
2250 @item -F 2245 @item -F
2251 @itemx --byname 2246 @itemx --byname
2252 Save messages according to sender. Currently this option is not implemented. 2247 Save messages according to sender. Currently this option is not implemented.
...@@ -2628,10 +2623,15 @@ invoking @command{mail}: ...@@ -2628,10 +2623,15 @@ invoking @command{mail}:
2628 @table @code 2623 @table @code
2629 @item mail 2624 @item mail
2630 To read messages from your system mailbox. 2625 To read messages from your system mailbox.
2631 @item mail --file 2626 @item mail -f
2632 To read messages from your mailbox (@file{$HOME/mbox}). 2627 @itemx mail --file
2633 @item mail --file=@var{path_to_mailbox} 2628 To read messages from your mailbox (@file{$HOME/mbox}). If the
2629 @option{--user} option (see below) is also given, read messages
2630 from that user's @file{mbox}.
2631 @item mail -f @var{path_to_mailbox}
2632 @itemx mail --file @var{path_to_mailbox}
2634 To read messages from the specified mailbox. 2633 To read messages from the specified mailbox.
2634 @itemx mail -u @var{user}
2635 @item mail --user=@var{user} 2635 @item mail --user=@var{user}
2636 To read messages from the system mailbox belonging to @var{user}. 2636 To read messages from the system mailbox belonging to @var{user}.
2637 @end table 2637 @end table
...@@ -2641,6 +2641,25 @@ to use the last variant of invocation, unless you are a super-user. ...@@ -2641,6 +2641,25 @@ to use the last variant of invocation, unless you are a super-user.
2641 Similarly, the last but one variant is also greatly affected by the 2641 Similarly, the last but one variant is also greatly affected by the
2642 permissions the target mailbox has. 2642 permissions the target mailbox has.
2643 2643
2644 Notice that @var{path_to_mailbox} is not an argument to
2645 @option{--file} (@option{-f}) option, but rather the first
2646 non-optional argument on the command line. Therefore, the
2647 following three invocations are equivalent:
2648
2649 @smallexample
2650 $ mail -fin mymbox
2651 $ mail -f mymbox -in
2652 $ mail --file -in mymbox
2653 $ mail --file -i mymbox -n
2654 @end smallexample
2655
2656 Additionally, for conformance to the GNU standards, the
2657 following form is also accepted:
2658
2659 @smallexample
2660 $ mail --file=mymbox -i -n
2661 @end smallexample
2662
2644 Unless you have started mail with @option{--norc} command line option, 2663 Unless you have started mail with @option{--norc} command line option,
2645 it will read the contents of the system-wide configuration file. 2664 it will read the contents of the system-wide configuration file.
2646 Then it reads the contents of user configuration file, if any. 2665 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 ...@@ -3563,6 +3582,20 @@ if @code{crt} is set without a value, then the height of the terminal
3563 screen is used to compute the threshold. The number of lines on 3582 screen is used to compute the threshold. The number of lines on
3564 screen is controlled by @code{screen} variable. 3583 screen is controlled by @code{screen} variable.
3565 3584
3585 @item debug
3586 @*Type: String to boolean
3587 @*Default: Not set
3588 @vrindex debug, mail variable
3589
3590 Sets mailutils debug level. If set to string, the value must be a
3591 valid Mailutils debugging specification. @xref{Debug Statement}, for
3592 a description.
3593
3594 If unset (i.e. @code{set nodebug}), clears and disables all debugging
3595 information. If set to @samp{true} (i.e. @code{set debug}), sets
3596 maximum debugging (@samp{<trace7}) on mailbox and its underlying
3597 objects.
3598
3566 @item decode-fallback 3599 @item decode-fallback
3567 @*Type: String. 3600 @*Type: String.
3568 @*Default: @samp{none}. 3601 @*Default: @samp{none}.
......
...@@ -30,13 +30,18 @@ static mu_list_t command_list; /* List of commands to be executed after parsin ...@@ -30,13 +30,18 @@ static mu_list_t command_list; /* List of commands to be executed after parsin
30 command line */ 30 command line */
31 31
32 const char *program_version = "mail (" PACKAGE_STRING ")"; 32 const char *program_version = "mail (" PACKAGE_STRING ")";
33 static char doc[] = N_("GNU mail -- the standard /bin/mail interface"); 33 static char doc[] = N_("GNU mail -- process mail messages.\n"
34 static char args_doc[] = N_("[address...]"); 34 "If -f or --file is given, mail operates on the mailbox named "
35 "by the first argument, or the user's mbox, if no argument given.\n");
36 static char args_doc[] = N_("[address...]\n-f [OPTION...] [file]\n--file [OPTION...] [file]\n--file=file [OPTION...]");
37
38 #define F_OPTION 256
35 39
36 static struct argp_option options[] = { 40 static struct argp_option options[] = {
41 { NULL, 'f', 0, OPTION_HIDDEN, NULL, 0 },
42 {"file", F_OPTION, "FILE", OPTION_ARG_OPTIONAL|OPTION_HIDDEN, 0},
43
37 {"exist", 'e', 0, 0, N_("Return true if mail exists"), 0}, 44 {"exist", 'e', 0, 0, N_("Return true if mail exists"), 0},
38 {"file", 'f', N_("URL"), OPTION_ARG_OPTIONAL,
39 N_("Operate on given mailbox URL (default ~/mbox)"), 0},
40 {"byname", 'F', 0, 0, N_("Save messages according to sender"), 0}, 45 {"byname", 'F', 0, 0, N_("Save messages according to sender"), 0},
41 {"headers", 'H', 0, 0, N_("Write a header summary and exit"), 0}, 46 {"headers", 'H', 0, 0, N_("Write a header summary and exit"), 0},
42 {"ignore", 'i', 0, 0, N_("Ignore interrupts"), 0}, 47 {"ignore", 'i', 0, 0, N_("Ignore interrupts"), 0},
...@@ -56,12 +61,16 @@ static struct argp_option options[] = { ...@@ -56,12 +61,16 @@ static struct argp_option options[] = {
56 }; 61 };
57 62
58 63
64 #define HINT_SEND_MODE 0x1
65 #define HINT_FILE_OPTION 0x2
66
59 struct arguments 67 struct arguments
60 { 68 {
61 char **args; 69 int argc;
70 char **argv;
62 char *file; 71 char *file;
63 char *user; 72 char *user;
64 int send_mode; 73 int hint;
65 }; 74 };
66 75
67 static error_t 76 static error_t
...@@ -72,7 +81,7 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -72,7 +81,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
72 switch (key) 81 switch (key)
73 { 82 {
74 case 'a': 83 case 'a':
75 args->send_mode = 1; 84 args->hint |= HINT_SEND_MODE;
76 send_append_header (arg); 85 send_append_header (arg);
77 break; 86 break;
78 87
...@@ -80,24 +89,12 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -80,24 +89,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
80 util_cache_command (&command_list, "setq mode=exist"); 89 util_cache_command (&command_list, "setq mode=exist");
81 break; 90 break;
82 91
83 case 'f': 92 case F_OPTION:
84 if (arg != NULL) 93 if (arg)
85 args->file = arg; 94 args->file = arg;
86 /* People often tend to separate -f option from its argument 95 /* fall through */
87 with a whitespace. This heuristics tries to catch the 96 case 'f':
88 error: */ 97 args->hint |= HINT_FILE_OPTION;
89 else if (state->next < state->argc
90 && state->argv[state->next][0] != '-')
91 args->file = state->argv[state->next++];
92 else
93 {
94 int len;
95 char *home = getenv("HOME");
96 len = strlen (home) + strlen ("/mbox") + 1;
97 args->file = xmalloc(len * sizeof (char));
98 strcpy (args->file, home);
99 strcat (args->file, "/mbox");
100 }
101 break; 98 break;
102 99
103 case 'p': 100 case 'p':
...@@ -130,9 +127,9 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -130,9 +127,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
130 break; 127 break;
131 128
132 case 's': 129 case 's':
130 args->hint |= HINT_SEND_MODE;
133 send_append_header2 (MU_HEADER_SUBJECT, arg, COMPOSE_REPLACE); 131 send_append_header2 (MU_HEADER_SUBJECT, arg, COMPOSE_REPLACE);
134 util_cache_command (&command_list, "set noasksub"); 132 util_cache_command (&command_list, "set noasksub");
135 args->send_mode = 1;
136 break; 133 break;
137 134
138 case 'u': 135 case 'u':
...@@ -149,15 +146,39 @@ parse_opt (int key, char *arg, struct argp_state *state) ...@@ -149,15 +146,39 @@ parse_opt (int key, char *arg, struct argp_state *state)
149 break; 146 break;
150 147
151 case ARGP_KEY_ARG: 148 case ARGP_KEY_ARG:
152 args->args = realloc (args->args, 149 args->argv = realloc (args->argv,
153 sizeof (char *) * (state->arg_num + 2)); 150 sizeof (char *) * (state->arg_num + 2));
154 args->args[state->arg_num] = arg; 151 args->argv[state->arg_num] = arg;
155 args->args[state->arg_num + 1] = NULL; 152 args->argv[state->arg_num + 1] = NULL;
156 args->send_mode = 1; 153 args->argc = state->arg_num + 1;
157 break; 154 break;
158 155
159 case ARGP_KEY_FINI: 156 case ARGP_KEY_FINI:
160 if (args->send_mode) 157 if ((args->hint & (HINT_SEND_MODE|HINT_FILE_OPTION)) ==
158 (HINT_SEND_MODE|HINT_FILE_OPTION))
159 argp_error (state, _("conflicting options"));
160 else if (args->hint & HINT_FILE_OPTION)
161 {
162 if (args->file)
163 {
164 if (args->argc > 1)
165 argp_error (state,
166 _("-f requires at most one command line argument"));
167 }
168 else if (args->argc)
169 {
170 args->file = args->argv[0];
171
172 if (args->argc > 1)
173 argp_error (state,
174 _("-f requires at most one command line argument"));
175 }
176 else if (args->user)
177 asprintf (&args->file, "~/%s/mbox", args->user);
178 else
179 args->file = "~/mbox";
180 }
181 else if (args->argc || (args->hint & HINT_SEND_MODE))
161 util_cache_command (&command_list, "setq mode=send"); 182 util_cache_command (&command_list, "setq mode=send");
162 break; 183 break;
163 184
...@@ -230,7 +251,7 @@ static char *default_setup[] = { ...@@ -230,7 +251,7 @@ static char *default_setup[] = {
230 "set noautoprint", 251 "set noautoprint",
231 "set nobang", 252 "set nobang",
232 "set nocmd", 253 "set nocmd",
233 "set nodebug", 254 /* "set nodebug",*/
234 "set nodot", 255 "set nodot",
235 "set escape=~", 256 "set escape=~",
236 "set noflipr", 257 "set noflipr",
...@@ -281,11 +302,19 @@ static char *default_setup[] = { ...@@ -281,11 +302,19 @@ static char *default_setup[] = {
281 "set nullbodymsg=\"" N_("Null message body; hope that's ok") "\"", 302 "set nullbodymsg=\"" N_("Null message body; hope that's ok") "\"",
282 303
283 /* These settings are not yet used */ 304 /* These settings are not yet used */
284 "set nodebug",
285 "set noonehop", 305 "set noonehop",
286 "set nosendwait", 306 "set nosendwait",
287 }; 307 };
288 308
309 static int
310 mail_diag_stderr_printer (void *data, mu_log_level_t level, const char *buf)
311 {
312 if (level != MU_DIAG_ERROR)
313 fprintf (stderr, "%s: ", mu_diag_level_to_string (level));
314 fputs (buf, stderr);
315 return 0;
316 }
317
289 int 318 int
290 main (int argc, char **argv) 319 main (int argc, char **argv)
291 { 320 {
...@@ -345,14 +374,15 @@ main (int argc, char **argv) ...@@ -345,14 +374,15 @@ main (int argc, char **argv)
345 char *mailer_name = alloca (strlen ("sendmail:") 374 char *mailer_name = alloca (strlen ("sendmail:")
346 + strlen (PATH_SENDMAIL) + 1); 375 + strlen (PATH_SENDMAIL) + 1);
347 sprintf (mailer_name, "sendmail:%s", PATH_SENDMAIL); 376 sprintf (mailer_name, "sendmail:%s", PATH_SENDMAIL);
348 mailvar_set ("sendmail", mailer_name, mailvar_type_string, MOPTF_OVERWRITE); 377 mailvar_set ("sendmail", mailer_name, mailvar_type_string,
378 MOPTF_OVERWRITE);
349 } 379 }
350 380
351 381 args.argc = 0;
352 args.args = NULL; 382 args.argv = NULL;
353 args.file = NULL; 383 args.file = NULL;
354 args.user = NULL; 384 args.user = NULL;
355 args.send_mode = 0; 385 args.hint = 0;
356 386
357 /* argument parsing */ 387 /* argument parsing */
358 #ifdef WITH_TLS 388 #ifdef WITH_TLS
...@@ -369,7 +399,14 @@ main (int argc, char **argv) ...@@ -369,7 +399,14 @@ main (int argc, char **argv)
369 399
370 util_run_cached_commands (&command_list); 400 util_run_cached_commands (&command_list);
371 401
372 if (!interactive) 402 if (interactive)
403 {
404 mu_debug_t debug;
405
406 mu_diag_get_debug (&debug);
407 mu_debug_set_print (debug, mail_diag_stderr_printer, NULL);
408 }
409 else
373 { 410 {
374 util_do_command ("set nocrt"); 411 util_do_command ("set nocrt");
375 util_do_command ("set noasksub"); 412 util_do_command ("set noasksub");
...@@ -384,60 +421,33 @@ main (int argc, char **argv) ...@@ -384,60 +421,33 @@ main (int argc, char **argv)
384 /* Interactive mode */ 421 /* Interactive mode */
385 422
386 ml_readline_init (); 423 ml_readline_init ();
387 mail_set_my_name(args.user); 424 mail_set_my_name (args.user);
388 425
389 /* Mode is just sending */ 426 /* Mode is just sending */
390 if (strcmp (mode, "send") == 0) 427 if (strcmp (mode, "send") == 0)
391 { 428 {
392 /* FIXME: set cmd to "mail [add1...]" */ 429 /* FIXME: set cmd to "mail [add1...]" */
393 char *buf = NULL; 430 char *buf = NULL;
394 int num = 0;
395 int rc; 431 int rc;
396 if (args.args != NULL) 432
397 while (args.args[num] != NULL) 433 mu_argcv_string (args.argc, args.argv, &buf);
398 num++;
399 mu_argcv_string (num, args.args, &buf);
400 rc = util_do_command ("mail %s", buf); 434 rc = util_do_command ("mail %s", buf);
401 return mailvar_get (NULL, "mailx", mailvar_type_boolean, 0) ? rc : 0; 435 return mailvar_get (NULL, "mailx", mailvar_type_boolean, 0) ? rc : 0;
402 } 436 }
403 /* Or acting as a normal reader */ 437 /* Or acting as a normal reader */
404 else 438 else
405 { 439 {
406 /* open the mailbox */ 440 if ((rc = mu_mailbox_create_default (&mbox, args.file)) != 0)
407 if (args.file == NULL)
408 {
409 if (args.user)
410 {
411 char *p = xmalloc (strlen (args.user) + 2);
412 p[0] = '%';
413 strcpy (p + 1, args.user);
414 rc = mu_mailbox_create_default (&mbox, p);
415 free (p);
416 }
417 else
418 rc = mu_mailbox_create_default (&mbox, NULL);
419 if (rc != 0)
420 {
421 util_error (_("Cannot create mailbox for %s: %s"), args.user,
422 mu_strerror (rc));
423 exit (EXIT_FAILURE);
424 }
425 }
426 else if ((rc = mu_mailbox_create_default (&mbox, args.file)) != 0)
427 { 441 {
442 if (args.file)
428 util_error (_("Cannot create mailbox %s: %s"), args.file, 443 util_error (_("Cannot create mailbox %s: %s"), args.file,
429 mu_strerror (rc)); 444 mu_strerror (rc));
445 else
446 util_error (_("Cannot create mailbox: %s"),
447 mu_strerror (rc));
430 exit (EXIT_FAILURE); 448 exit (EXIT_FAILURE);
431 } 449 }
432 450
433 /* Could we enable this at runtime, via the a set environment? */
434 if (0)
435 {
436 mu_debug_t debug = NULL;
437 mu_mailbox_get_debug (mbox, &debug);
438 mu_debug_set_level (debug, MU_DEBUG_LEVEL_UPTO (MU_DEBUG_PROT));
439 }
440
441 if ((rc = mu_mailbox_open (mbox, MU_STREAM_RDWR|MU_STREAM_CREAT)) != 0) 451 if ((rc = mu_mailbox_open (mbox, MU_STREAM_RDWR|MU_STREAM_CREAT)) != 0)
442 { 452 {
443 mu_url_t url = NULL; 453 mu_url_t url = NULL;
...@@ -547,7 +557,7 @@ mail_warranty (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED) ...@@ -547,7 +557,7 @@ mail_warranty (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
547 { 557 {
548 fputs (_("GNU Mailutils -- a suite of utilities for electronic mail\n" 558 fputs (_("GNU Mailutils -- a suite of utilities for electronic mail\n"
549 "Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,\n" 559 "Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,\n"
550 "2007 Free Software Foundation, Inc.\n\n"), 560 "2007, 2009 Free Software Foundation, Inc.\n\n"),
551 ofile); 561 ofile);
552 fputs ( 562 fputs (
553 _(" GNU Mailutils is free software; you can redistribute it and/or modify\n" 563 _(" GNU Mailutils is free software; you can redistribute it and/or modify\n"
......