1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 1999-2021 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "mail.h"
18 #include "mailutils/cli.h"
19 #include "mailutils/mu_auth.h"
20
21 /* Global variables and constants*/
22 mu_mailbox_t mbox; /* Mailbox being operated upon */
23 size_t total; /* Total number of messages in the mailbox */
24 int interactive; /* Is the session interactive */
25 int read_recipients; /* Read recipients from the message (mail -t) */
26 mu_url_t secondary_url; /* URL of the mailbox given with the -f option */
27 static mu_list_t command_list;/* List of commands to be executed after parsing
28 command line */
29 const char *program_version = "mail (" PACKAGE_STRING ")";
30
31
32 #define HINT_SEND_MODE 0x1
33 #define HINT_FILE_OPTION 0x2
34 #define HINT_BYNAME 0x4
35
36 int hint;
37 char *file;
38 char *user;
39
40 int mime_option;
41 int skip_empty_attachments;
42 char *default_encoding;
43 char *default_content_type;
44 static char *content_name;
45 static char *content_filename;
46
47 static void
cli_f_option(struct mu_parseopt * po,struct mu_option * opt,char const * arg)48 cli_f_option (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
49 {
50 hint |= HINT_FILE_OPTION;
51 }
52
53 static void
cli_file_option(struct mu_parseopt * po,struct mu_option * opt,char const * arg)54 cli_file_option (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
55 {
56 if (arg)
57 file = mu_strdup (arg);
58 hint |= HINT_FILE_OPTION;
59 }
60
61 static void
cli_command_option(struct mu_parseopt * po,struct mu_option * opt,char const * arg)62 cli_command_option (struct mu_parseopt *po, struct mu_option *opt,
63 char const *arg)
64 {
65 switch (opt->opt_short)
66 {
67 case 'e':
68 util_cache_command (&command_list, "setq mode=exist");
69 break;
70
71 case 'p':
72 util_cache_command (&command_list, "setq mode=print");
73 break;
74
75 case 'r':
76 util_cache_command (&command_list, "set return-address=%s", arg);
77 hint |= HINT_SEND_MODE;
78 break;
79
80 case 'q':
81 util_cache_command (&command_list, "set quit");
82 break;
83
84 case 't':
85 read_recipients = 1;
86 util_cache_command (&command_list, "set editheaders");
87 hint |= HINT_SEND_MODE;
88 break;
89
90 case 'H':
91 util_cache_command (&command_list, "setq mode=headers");
92 break;
93
94 case 'i':
95 util_cache_command (&command_list, "set ignore");
96 break;
97
98 case 'n':
99 util_do_command ("set norc");
100 break;
101
102 case 'N':
103 util_cache_command (&command_list, "set noheader");
104 break;
105
106 case 'E':
107 util_cache_command (&command_list, "%s", arg);
108 break;
109
110 case 'F':
111 hint |= HINT_SEND_MODE;
112 hint |= HINT_BYNAME;
113 break;
114
115 case 0:
116 mu_parseopt_error (po, _("--%s: option should have been recognized"),
117 opt->opt_long);
118 exit (po->po_exit_error);
119
120 default:
121 mu_parseopt_error (po, _("-%c: option should have been recognized"),
122 opt->opt_short);
123 exit (po->po_exit_error);
124 }
125 }
126
127 static void
cli_subject(struct mu_parseopt * po,struct mu_option * opt,char const * arg)128 cli_subject (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
129 {
130 hint |= HINT_SEND_MODE;
131 send_append_header2 (MU_HEADER_SUBJECT, arg, COMPOSE_REPLACE);
132 util_cache_command (&command_list, "set noasksub");
133 }
134
135 static void
cli_append(struct mu_parseopt * po,struct mu_option * opt,char const * arg)136 cli_append (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
137 {
138 hint |= HINT_SEND_MODE;
139 send_append_header (arg);
140 }
141
142 static void
cli_attach(struct mu_parseopt * po,struct mu_option * opt,char const * arg)143 cli_attach (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
144 {
145 int fd = -1;
146
147 hint |= HINT_SEND_MODE;
148 if (strcmp (arg, "-") == 0)
149 {
150 arg = NULL;
151 fd = 0;
152 }
153 if (send_attach_file (fd, arg, content_filename, content_name,
154 default_content_type, default_encoding))
155 exit (po->po_exit_error);
156
157 mime_option = 1;
158
159 free (content_name);
160 content_name = NULL;
161 free (content_filename);
162 content_filename = NULL;
163 }
164
165 static void
cli_attach_fd(struct mu_parseopt * po,struct mu_option * opt,char const * arg)166 cli_attach_fd (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
167 {
168 int rc, fd;
169
170 hint |= HINT_SEND_MODE;
171 rc = mu_str_to_c (arg, mu_c_int, &fd, NULL);
172 if (rc)
173 {
174 mu_parseopt_error (po, _("%s: bad descriptor"), arg);
175 exit (po->po_exit_error);
176 }
177
178 send_attach_file (fd, NULL, content_filename, content_name,
179 default_content_type, default_encoding);
180
181 free (content_name);
182 content_name = NULL;
183 free (content_filename);
184 content_filename = NULL;
185 }
186
187 static struct mu_option mail_options[] = {
188 { NULL, 'f', NULL, MU_OPTION_HIDDEN,
189 NULL,
190 mu_c_string, NULL, cli_f_option },
191 { "file", 0, N_("FILE"), MU_OPTION_ARG_OPTIONAL|MU_OPTION_HIDDEN,
192 NULL,
193 mu_c_string, NULL, cli_file_option },
194
195 { "exist", 'e', NULL, MU_OPTION_DEFAULT,
196 N_("return true if mail exists"),
197 mu_c_string, NULL, cli_command_option },
198
199 { "byname", 'F', NULL, MU_OPTION_DEFAULT,
200 N_("save messages according to sender"),
201 mu_c_string, NULL, cli_command_option },
202
203 { "headers", 'H', NULL, MU_OPTION_DEFAULT,
204 N_("write a header summary and exit"),
205 mu_c_string, NULL, cli_command_option },
206
207 { "ignore", 'i', NULL, MU_OPTION_DEFAULT,
208 N_("ignore interrupts"),
209 mu_c_string, NULL, cli_command_option },
210
211 { "norc", 'n', NULL, MU_OPTION_DEFAULT,
212 N_("do not read the system mailrc file"),
213 mu_c_string, NULL, cli_command_option },
214
215 { "nosum", 'N', NULL, MU_OPTION_DEFAULT,
216 N_("do not display initial header summary"),
217 mu_c_string, NULL, cli_command_option },
218
219 { "print", 'p', NULL, MU_OPTION_DEFAULT,
220 N_("print all mail to standard output"),
221 mu_c_string, NULL, cli_command_option },
222 { "read", 0, NULL, MU_OPTION_ALIAS },
223
224 { "return-address", 'r', N_("ADDRESS"), MU_OPTION_DEFAULT,
225 N_("use address as the return address when sending mail"),
226 mu_c_string, NULL, cli_command_option },
227
228 { "quit", 'q', NULL, MU_OPTION_DEFAULT,
229 N_("cause interrupts to terminate program"),
230 mu_c_string, NULL, cli_command_option },
231
232 { "subject", 's', N_("SUBJ"), MU_OPTION_DEFAULT,
233 N_("send a message with the given SUBJECT"),
234 mu_c_string, NULL, cli_subject },
235
236 { "to", 't', NULL, MU_OPTION_DEFAULT,
237 N_("read recipients from the message header"),
238 mu_c_string, NULL, cli_command_option },
239
240 { "user", 'u', N_("USER"), MU_OPTION_DEFAULT,
241 N_("operate on USER's mailbox"),
242 mu_c_string, &user },
243
244 { "append", 'a', N_("HEADER: VALUE"), MU_OPTION_DEFAULT,
245 N_("append given header to the message being sent"),
246 mu_c_string, NULL, cli_append },
247
248 { "alternative", 0, NULL, MU_OPTION_DEFAULT,
249 N_("force multipart/alternative content type"),
250 mu_c_bool, &multipart_alternative },
251
252 { "skip-empty-attachments", 0, NULL, MU_OPTION_DEFAULT,
253 N_("skip attachments with empty body"),
254 mu_c_bool, &skip_empty_attachments },
255
256 { "exec" , 'E', N_("COMMAND"), MU_OPTION_DEFAULT,
257 N_("execute COMMAND"),
258 mu_c_string, NULL, cli_command_option },
259
260 { "encoding", 0, N_("NAME"), MU_OPTION_DEFAULT,
261 N_("set encoding for subsequent --attach options"),
262 mu_c_string, &default_encoding },
263
264 { "content-type", 0, N_("TYPE"), MU_OPTION_DEFAULT,
265 N_("set content type for subsequent --attach options"),
266 mu_c_string, &default_content_type },
267
268 { "content-name", 0, N_("NAME"), MU_OPTION_DEFAULT,
269 /* TRANSLATORS: Don't translate "Content-Type" and "name"! */
270 N_("set the Content-Type name parameter for the next --attach option"),
271 mu_c_string, &content_name },
272 { "content-filename", 0, N_("NAME"), MU_OPTION_DEFAULT,
273 /* TRANSLATORS: Don't translate "Content-Disposition" and "filename"! */
274 N_("set the Content-Disposition filename parameter for the next --attach option"),
275 mu_c_string, &content_filename },
276
277 { "attach", 'A', N_("FILE"), MU_OPTION_DEFAULT,
278 N_("attach FILE"),
279 mu_c_string, NULL, cli_attach },
280
281 { "attach-fd", 0, N_("FD"), MU_OPTION_DEFAULT,
282 N_("attach from file descriptor FD"),
283 mu_c_string, NULL, cli_attach_fd },
284
285 { "mime", 'M', NULL, MU_OPTION_DEFAULT,
286 N_("compose MIME messages"),
287 mu_c_bool, &mime_option },
288
289 MU_OPTION_END
290 }, *options[] = { mail_options, NULL };
291
292 static const char *alt_args[] = {
293 N_("[OPTION...] [file]"),
294 N_("--file [OPTION...] [file]"),
295 N_("--file=file [OPTION...]"),
296 NULL
297 };
298
299 static struct mu_cli_setup cli = {
300 options,
301 NULL,
302 /* TRANSLATORS: "mail" is the name of the program. Don't translate it. */
303 N_("GNU mail -- process mail messages.\n"
304 "If -f or --file is given, mail operates on the mailbox named "
305 "by the first argument, or the user's mbox, if no argument given."),
306 N_("[address...]"),
307 alt_args,
308 NULL,
309 1,
310 1
311 };
312
313 static char *mail_capa[] = {
314 "address",
315 "debug",
316 "mailbox",
317 "locking",
318 NULL
319 };
320
321 static char *
mail_cmdline(void * closure,int cont MU_ARG_UNUSED)322 mail_cmdline (void *closure, int cont MU_ARG_UNUSED)
323 {
324 char *prompt = (char*) closure;
325 char *rc;
326
327 while (1)
328 {
329 if (mailvar_is_true (mailvar_name_autoinc)
330 && !mu_mailbox_is_updated (mbox))
331 {
332 mu_mailbox_messages_count (mbox, &total);
333 page_invalidate (0);
334 mu_printf (_("New mail has arrived.\n"));
335 }
336
337 rc = ml_readline (prompt);
338
339 if (ml_got_interrupt ())
340 {
341 mu_error (_("Interrupt"));
342 continue;
343 }
344
345 if (!rc && mailvar_is_true (mailvar_name_ignoreeof))
346 {
347 mu_error (_("Use \"quit\" to quit."));
348 continue;
349 }
350
351 break;
352 }
353 return rc;
354 }
355
356 static char *default_setup[] = {
357 /* "set noallnet", */
358 "setq append",
359 "set asksub",
360 "set crt",
361 "set noaskbcc",
362 "set askcc",
363 "set noautoprint",
364 "set nobang",
365 "set nocmd",
366 /* "set nodebug",*/
367 "set nodot",
368 "set escape=~",
369 "set noflipr",
370 "set nofolder",
371 "set header",
372 "set nohold",
373 "set noignore",
374 "set noignoreeof",
375 "set indentprefix=\"\t\"",
376 "setq keep",
377 "set nokeepsave",
378 "set nometoo",
379 "set noonehop",
380 "set nooutfolder",
381 "set nopage",
382 "set prompt=\"? \"",
383 "set norecord",
384 "set save",
385 "set nosendmail",
386 "set nosendwait",
387 "set noshowto",
388 "set nosign",
389 "set noSign",
390 "set toplines=5",
391 "set autoinc",
392 "set regex",
393 "set replyprefix=\"Re: \"",
394 "set charset=auto",
395 "set useragent",
396 "unfold subject",
397 "sender mail-followup-to reply-to from",
398 "set nocmd",
399 "set metamail",
400 "set recursivealiases",
401 "set noinplacealiases",
402 "set fromfield",
403 "set headline=\"%>%a%4m %18f %16d %3L/%-5o %s\"",
404 "unset folder",
405 "set fullnames",
406 "set outfilename=local",
407
408 /* Start in mail reading mode */
409 "setq mode=read",
410 "set noquit",
411 "set rc",
412
413 "set noflipr",
414 "set noshowto",
415 "set nobang",
416
417 "set nullbody", /* Null message body is traditionally allowed */
418 "set nullbodymsg=\"" N_("Null message body; hope that's ok") "\"",
419
420 /* These settings are not yet used */
421 "set noonehop",
422 "set nosendwait",
423 };
424
425 static void
do_and_quit(const char * command)426 do_and_quit (const char *command)
427 {
428 int rc = util_do_command ("%s", command);
429 mu_mailbox_close (mbox);
430 exit (rc != 0);
431 }
432
433 int
main(int argc,char ** argv)434 main (int argc, char **argv)
435 {
436 char *mode = NULL, *prompt = NULL, *p;
437 int i, rc;
438
439 mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
440 set_cursor (1);
441
442 /* Native Language Support */
443 MU_APP_INIT_NLS ();
444
445 /* Register the desired formats. */
446 mu_register_all_formats ();
447
448 mu_auth_register_module (&mu_auth_tls_module);
449
450 interactive = isatty (fileno (stdin));
451 #ifdef HAVE_SIGACTION
452 {
453 struct sigaction act;
454 act.sa_handler = SIG_IGN;
455 sigemptyset (&act.sa_mask);
456 act.sa_flags = 0;
457 sigaction (SIGPIPE, &act, NULL);
458 }
459 #else
460 signal (SIGPIPE, SIG_IGN);
461 #endif
462
463 /* set up the default environment */
464 if (!getenv ("HOME"))
465 setenv ("HOME", util_get_homedir (), 0);
466
467 /* Set up the default environment */
468 setenv ("DEAD", util_fullpath ("~/dead.letter"), 0);
469 setenv ("EDITOR", "ed", 0);
470 setenv ("LISTER", "ls", 0);
471 setenv ("MAILRC", util_fullpath ("~/.mailrc"), 0);
472 setenv ("MBOX", util_fullpath ("~/mbox"), 0);
473 setenv ("PAGER", "more", 0);
474 setenv ("SHELL", "sh", 0);
475 setenv ("VISUAL", "vi", 0);
476
477 /* set defaults for execution */
478 util_do_command ("setq PID=\"%lu\"", (unsigned long) getpid ());
479 for (i = 0; i < sizeof (default_setup)/sizeof (default_setup[0]); i++)
480 util_do_command ("%s", default_setup[i]);
481
482 p = getenv ("LINES");
483 if (p && p[strspn (p, "0123456789")] == 0)
484 util_do_command ("set screen=%s", p);
485 else
486 util_do_command ("set screen=%d", util_getlines ());
487
488 p = getenv ("COLUMNS");
489 if (p && p[strspn (p, "0123456789")] == 0)
490 util_do_command ("set columns=%s", p);
491 else
492 util_do_command ("set columns=%d", util_getcols ());
493
494 /* Set the default mailer to sendmail. FIXME: Minor memory leak. */
495 mailvar_set (mailvar_name_sendmail,
496 mu_strdup ("sendmail:" PATH_SENDMAIL), mailvar_type_string,
497 MOPTF_OVERWRITE);
498
499 /* argument parsing */
500 mu_cli (argc, argv, &cli, mail_capa, NULL, &argc, &argv);
501
502 if (default_content_type || default_encoding)
503 mime_option = 1;
504 if (mime_option)
505 util_cache_command (&command_list, "set mime");
506
507 if (read_recipients)
508 {
509 argv += argc;
510 argc = 0;
511 }
512
513 if ((hint & (HINT_SEND_MODE|HINT_FILE_OPTION)) ==
514 (HINT_SEND_MODE|HINT_FILE_OPTION))
515 {
516 mu_error (_("conflicting options"));
517 exit (1);
518 }
519 else if (hint & HINT_FILE_OPTION)
520 {
521 if (file)
522 {
523 if (argc)
524 {
525 mu_error (_("-f requires at most one command line argument"));
526 exit (1);
527 }
528 }
529 else if (argc)
530 {
531 if (argc > 1)
532 {
533 mu_error (_("-f requires at most one command line argument"));
534 exit (1);
535 }
536 file = mu_strdup (argv[0]);
537 }
538 else if (user)
539 mu_asprintf (&file, "~/%s/mbox", user);
540 else
541 file = mu_strdup ("~/mbox");
542 }
543 else if (argc || (hint & HINT_SEND_MODE))
544 util_cache_command (&command_list, "setq mode=send");
545 else if (user)
546 mu_asprintf (&file, "%%%s", user);
547
548
549 /* read system-wide mail.rc and user's .mailrc */
550 if (mailvar_is_true (mailvar_name_rc))
551 util_do_command ("source %s", SITE_MAIL_RC);
552 if ((p = getenv ("MAILRC")) && *p)
553 util_do_command ("source %s", getenv ("MAILRC"));
554
555 util_run_cached_commands (&command_list);
556
557 if (interactive)
558 {
559 /* Reset standard error stream so that it does not print program
560 name before the actual diagnostic message. */
561 mu_stream_t errstr;
562 int rc = mu_stdstream_strerr_create (&errstr, MU_STRERR_STDERR, 0, 0,
563 NULL, NULL);
564 if (rc == 0)
565 {
566 mu_stream_destroy (&mu_strerr);
567 mu_strerr = errstr;
568 }
569 }
570 else
571 {
572 util_do_command ("set nocrt");
573 util_do_command ("set noasksub");
574 util_do_command ("set noaskcc");
575 util_do_command ("set noaskbcc");
576 }
577
578 /* how should we be running? */
579 if (mailvar_get (&mode, mailvar_name_mode, mailvar_type_string, 1))
580 exit (EXIT_FAILURE);
581
582 /* Interactive mode */
583
584 ml_readline_init ();
585 mail_set_my_name (user);
586
587 /* Mode is just sending */
588 if (strcmp (mode, "send") == 0)
589 {
590 --argv;
591 ++argc;
592 if (hint & HINT_BYNAME)
593 argv[0] = "Mail";
594 else
595 argv[0] = "mail";
596 return mail_send (argc, argv)
597 ? (mailvar_is_true (mailvar_name_mailx) ? 0 : EXIT_FAILURE)
598 : 0;
599 }
600 /* Or acting as a normal reader */
601 else
602 {
603 if ((rc = mu_mailbox_create_default (&mbox, file)) != 0)
604 {
605 if (file)
606 mu_error (_("Cannot create mailbox %s: %s"), file,
607 mu_strerror (rc));
608 else
609 mu_error (_("Cannot create mailbox: %s"),
610 mu_strerror (rc));
611 exit (EXIT_FAILURE);
612 }
613
614 if (file)
615 {
616 /* Save URL of the file for further use */
617 mu_url_t url;
618
619 if (mu_mailbox_get_url (mbox, &url) == 0)
620 {
621 rc = mu_url_dup (url, &secondary_url);
622 if (rc)
623 {
624 mu_diag_funcall (MU_DIAG_ERROR, "mu_url_dup", NULL, rc);
625 exit (EXIT_FAILURE);
626 }
627 }
628 /* Destroy the content of file prior to freeing it: it can contain
629 password, although such usage is discouraged */
630 memset (file, 0, strlen (file));
631 free (file);
632 }
633
634 if ((rc = mu_mailbox_open (mbox, MU_STREAM_RDWR|MU_STREAM_CREAT)) != 0)
635 {
636 if (rc == EACCES)
637 {
638 rc = mu_mailbox_open (mbox, MU_STREAM_READ);
639 if (rc == 0)
640 mu_diag_output (MU_DIAG_WARNING, _("mailbox opened read-only"));
641 //FIXME: Disable 'q' and similar commands
642 }
643 if (rc)
644 {
645 mu_url_t url = NULL;
646 mu_mailbox_get_url (mbox, &url);
647 mu_error (_("Cannot open mailbox %s: %s"),
648 mu_url_to_string (url), mu_strerror (rc));
649 mu_mailbox_destroy (&mbox);
650 }
651 }
652
653 if (rc)
654 total = 0;
655 else
656 {
657 if ((rc = mu_mailbox_scan (mbox, 1, &total)) != 0)
658 {
659 mu_url_t url = NULL;
660 mu_mailbox_get_url (mbox, &url);
661 mu_error (_("Cannot read mailbox %s: %s"),
662 mu_url_to_string (url), mu_strerror (rc));
663 exit (EXIT_FAILURE);
664 }
665
666 if (strcmp (mode, "exist") == 0)
667 {
668 mu_mailbox_close (mbox);
669 return (total < 1) ? 1 : 0;
670 }
671 else if (strcmp (mode, "print") == 0)
672 do_and_quit ("print *");
673 else if (strcmp (mode, "headers") == 0)
674 do_and_quit ("from *");
675 else if (strcmp (mode, "read"))
676 {
677 mu_error (_("Unknown mode `%s'"), mode);
678 util_do_command (mailvar_name_quit);
679 return 1;
680 }
681 }
682
683 if (total == 0
684 && (strcmp (mode, "read")
685 || !mailvar_is_true (mailvar_name_emptystart)))
686 {
687 if (secondary_url)
688 mail_summary (0, NULL);
689 else
690 mu_printf (_("No mail for %s\n"), user ? user : mail_whoami ());
691 return 1;
692 }
693
694 /* initial commands */
695 if (mailvar_is_true (mailvar_name_header))
696 {
697 util_do_command ("summary");
698 util_do_command ("headers");
699 }
700
701 mailvar_get (&prompt, mailvar_name_prompt, mailvar_type_string, 0);
702 mail_mainloop (mail_cmdline, (void*) prompt, 1);
703 mu_printf ("\n");
704 util_do_command (mailvar_name_quit);
705 return 0;
706 }
707 /* We should never reach this point */
708 return 1;
709 }
710
711
712 void
mail_mainloop(char * (* input)(void *,int),void * closure,int do_history)713 mail_mainloop (char *(*input) (void *, int),
714 void *closure, int do_history)
715 {
716 char *command, *cmd;
717
718 while ((command = (*input) (closure, 0)) != NULL)
719 {
720 int len = strlen (command);
721 while (len > 0 && command[len-1] == '\\')
722 {
723 char *buf;
724 char *command2 = (*input) (closure, 1);
725
726 if (!command2)
727 {
728 command[len-1] = 0;
729 break;
730 }
731 command[len-1] = '\0';
732 buf = mu_alloc ((len + strlen (command2)) * sizeof (char));
733 strcpy (buf, command);
734 strcat (buf, command2);
735 free (command);
736 command = buf;
737 len = strlen (command);
738 }
739 cmd = mu_str_stripws (command);
740 util_do_command ("%s", cmd);
741 #ifdef WITH_READLINE
742 if (do_history && !(mu_isspace (cmd[0]) || cmd[0] == '#'))
743 add_history (cmd);
744 #endif
745 free (command);
746 }
747 }
748
749 int
mail_warranty(int argc MU_ARG_UNUSED,char ** argv MU_ARG_UNUSED)750 mail_warranty (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
751 {
752 mu_version_print (mu_strout);
753 return 0;
754 }
755