mutt stable branch with some hacks
at jcs 1400 lines 33 kB view raw
1/* 2 * Copyright (C) 1996-2007,2010,2013 Michael R. Elkins <me@mutt.org> 3 * Copyright (C) 1999-2007 Thomas Roessler <roessler@does-not-exist.org> 4 * Copyright (C) 2004 g10 Code GmbH 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 */ 20 21#define MAIN_C 1 22 23#if HAVE_CONFIG_H 24# include "config.h" 25#endif 26 27#include "mutt.h" 28#include "mutt_curses.h" 29#include "keymap.h" 30#include "mailbox.h" 31#include "url.h" 32#include "mutt_crypt.h" 33#include "mutt_idna.h" 34#ifdef USE_SIDEBAR 35#include "sidebar.h" 36#endif 37 38#ifdef USE_SASL 39#include "mutt_sasl.h" 40#endif 41 42#ifdef USE_IMAP 43#include "imap/imap.h" 44#endif 45 46#ifdef USE_HCACHE 47#include "hcache.h" 48#endif 49 50#ifdef USE_INOTIFY 51#include "monitor.h" 52#endif 53 54#ifdef USE_AUTOCRYPT 55#include "autocrypt/autocrypt.h" 56#endif 57 58#include <string.h> 59#include <stdlib.h> 60#include <locale.h> 61#include <unistd.h> 62#include <errno.h> 63#include <sys/stat.h> 64#include <sys/utsname.h> 65 66#ifdef HAVE_GETOPT_H 67#include <getopt.h> 68#endif 69 70#ifdef HAVE_STRINGPREP_H 71#include <stringprep.h> 72#elif defined(HAVE_IDN_STRINGPREP_H) 73#include <idn/stringprep.h> 74#endif 75 76static const char *ReachingUs = N_("\ 77To contact the developers, please mail to <mutt-dev@mutt.org>.\n\ 78To report a bug, please contact the Mutt maintainers via gitlab:\n\ 79 https://gitlab.com/muttmua/mutt/issues\n"); 80 81static const char *Notice = N_("\ 82Copyright (C) 1996-2016 Michael R. Elkins and others.\n\ 83Mutt comes with ABSOLUTELY NO WARRANTY; for details type `mutt -vv'.\n\ 84Mutt is free software, and you are welcome to redistribute it\n\ 85under certain conditions; type `mutt -vv' for details.\n"); 86 87static const char Copyright[] = "\ 88Copyright (C) 1996-2016 Michael R. Elkins <me@mutt.org>\n\ 89Copyright (C) 1996-2002 Brandon Long <blong@fiction.net>\n\ 90Copyright (C) 1997-2009 Thomas Roessler <roessler@does-not-exist.org>\n\ 91Copyright (C) 1998-2005 Werner Koch <wk@isil.d.shuttle.de>\n\ 92Copyright (C) 1999-2017 Brendan Cully <brendan@kublai.com>\n\ 93Copyright (C) 1999-2002 Tommi Komulainen <Tommi.Komulainen@iki.fi>\n\ 94Copyright (C) 2000-2004 Edmund Grimley Evans <edmundo@rano.org>\n\ 95Copyright (C) 2006-2009 Rocco Rutte <pdmef@gmx.net>\n\ 96Copyright (C) 2014-2020 Kevin J. McCarthy <kevin@8t8.us>\n"; 97 98static const char *Thanks = N_("\ 99Many others not mentioned here contributed code, fixes,\n\ 100and suggestions.\n"); 101 102static const char *Licence = N_("\ 103 This program is free software; you can redistribute it and/or modify\n\ 104 it under the terms of the GNU General Public License as published by\n\ 105 the Free Software Foundation; either version 2 of the License, or\n\ 106 (at your option) any later version.\n\ 107\n\ 108 This program is distributed in the hope that it will be useful,\n\ 109 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ 110 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ 111 GNU General Public License for more details.\n"); 112static const char *Obtaining = N_("\ 113 You should have received a copy of the GNU General Public License\n\ 114 along with this program; if not, write to the Free Software\n\ 115 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\ 116"); 117 118char **envlist; 119 120void mutt_exit (int code) 121{ 122 mutt_endwin (NULL); 123 exit (code); 124} 125 126static void mutt_usage (void) 127{ 128 puts (mutt_make_version ()); 129 130 puts _( 131"usage: mutt [<options>] [-z] [-f <file> | -yZ]\n\ 132 mutt [<options>] [-Ex] [-Hi <file>] [-s <subj>] [-bc <addr>] [-a <file> [...] --] <addr> [...]\n\ 133 mutt [<options>] [-x] [-s <subj>] [-bc <addr>] [-a <file> [...] --] <addr> [...] < message\n\ 134 mutt [<options>] -p\n\ 135 mutt [<options>] -A <alias> [...]\n\ 136 mutt [<options>] -Q <query> [...]\n\ 137 mutt [<options>] -D\n\ 138 mutt -v[v]\n"); 139 140 puts _("\ 141options:\n\ 142 -A <alias>\texpand the given alias\n\ 143 -a <file> [...] --\tattach file(s) to the message\n\ 144\t\tthe list of files must be terminated with the \"--\" sequence\n\ 145 -b <address>\tspecify a blind carbon-copy (BCC) address\n\ 146 -c <address>\tspecify a carbon-copy (CC) address\n\ 147 -D\t\tprint the value of all variables to stdout"); 148#if DEBUG 149 puts _(" -d <level>\tlog debugging output to ~/.muttdebug0"); 150#endif 151 puts _( 152" -E\t\tedit the draft (-H) or include (-i) file\n\ 153 -e <command>\tspecify a command to be executed after initialization\n\ 154 -f <file>\tspecify which mailbox to read\n\ 155 -F <file>\tspecify an alternate muttrc file\n\ 156 -H <file>\tspecify a draft file to read header and body from\n\ 157 -i <file>\tspecify a file which Mutt should include in the body\n\ 158 -m <type>\tspecify a default mailbox type\n\ 159 -n\t\tcauses Mutt not to read the system Muttrc\n\ 160 -p\t\trecall a postponed message"); 161 162 puts _("\ 163 -Q <variable>\tquery a configuration variable\n\ 164 -R\t\topen mailbox in read-only mode\n\ 165 -s <subj>\tspecify a subject (must be in quotes if it has spaces)\n\ 166 -v\t\tshow version and compile-time definitions\n\ 167 -x\t\tsimulate the mailx send mode\n\ 168 -y\t\tselect a mailbox specified in your `mailboxes' list\n\ 169 -z\t\texit immediately if there are no messages in the mailbox\n\ 170 -Z\t\topen the first folder with new message, exit immediately if none\n\ 171 -h\t\tthis help message"); 172 173 exit (0); 174} 175 176extern unsigned char cc_version[]; 177extern unsigned char cc_cflags[]; 178extern unsigned char configure_options[]; 179 180static char * 181rstrip_in_place(char *s) 182{ 183 char *p; 184 185 p = &s[strlen(s)]; 186 if (p == s) 187 return s; 188 p--; 189 while (p >= s && (*p == '\n' || *p == '\r')) 190 *p-- = '\0'; 191 return s; 192} 193 194static void show_version (void) 195{ 196 struct utsname uts; 197 198 puts (mutt_make_version()); 199 puts (_(Notice)); 200 201 uname (&uts); 202 203#ifdef _AIX 204 printf ("System: %s %s.%s", uts.sysname, uts.version, uts.release); 205#elif defined (SCO) 206 printf ("System: SCO %s", uts.release); 207#else 208 printf ("System: %s %s", uts.sysname, uts.release); 209#endif 210 211 printf (" (%s)", uts.machine); 212 213#ifdef NCURSES_VERSION 214 printf ("\nncurses: %s (compiled with %s)", curses_version(), NCURSES_VERSION); 215#elif defined(USE_SLANG_CURSES) 216 printf ("\nslang: %d", SLANG_VERSION); 217#endif 218 219#ifdef _LIBICONV_VERSION 220 printf ("\nlibiconv: %d.%d", _LIBICONV_VERSION >> 8, 221 _LIBICONV_VERSION & 0xff); 222#endif 223 224#ifdef HAVE_LIBIDN 225 printf ("\nlibidn: %s (compiled with %s)", stringprep_check_version (NULL), 226 STRINGPREP_VERSION); 227#endif 228 229#ifdef HAVE_LIBIDN2 230 printf ("\nlibidn2: %s (compiled with %s)", idn2_check_version (NULL), 231 IDN2_VERSION); 232#endif 233 234#ifdef USE_HCACHE 235 printf ("\nhcache backend: %s", mutt_hcache_backend ()); 236#endif 237 238 puts ("\n\nCompiler:"); 239 rstrip_in_place((char *)cc_version); 240 puts ((char *)cc_version); 241 242 rstrip_in_place((char *)configure_options); 243 printf ("\nConfigure options: %s\n", (char *)configure_options); 244 245 rstrip_in_place((char *)cc_cflags); 246 printf ("\nCompilation CFLAGS: %s\n", (char *)cc_cflags); 247 248 puts (_("\nCompile options:")); 249 250#ifdef DOMAIN 251 printf ("DOMAIN=\"%s\"\n", DOMAIN); 252#else 253 puts ("-DOMAIN"); 254#endif 255 256#ifdef DEBUG 257 puts ("+DEBUG"); 258#else 259 puts ("-DEBUG"); 260#endif 261 262 263 264 puts ( 265 266#ifdef HOMESPOOL 267 "+HOMESPOOL " 268#else 269 "-HOMESPOOL " 270#endif 271 272#ifdef USE_SETGID 273 "+USE_SETGID " 274#else 275 "-USE_SETGID " 276#endif 277 278#ifdef USE_DOTLOCK 279 "+USE_DOTLOCK " 280#else 281 "-USE_DOTLOCK " 282#endif 283 284#ifdef DL_STANDALONE 285 "+DL_STANDALONE " 286#else 287 "-DL_STANDALONE " 288#endif 289 290#ifdef USE_FCNTL 291 "+USE_FCNTL " 292#else 293 "-USE_FCNTL " 294#endif 295 296#ifdef USE_FLOCK 297 "+USE_FLOCK " 298#else 299 "-USE_FLOCK " 300#endif 301 ); 302 puts ( 303#ifdef USE_POP 304 "+USE_POP " 305#else 306 "-USE_POP " 307#endif 308 309#ifdef USE_IMAP 310 "+USE_IMAP " 311#else 312 "-USE_IMAP " 313#endif 314 315#ifdef USE_SMTP 316 "+USE_SMTP " 317#else 318 "-USE_SMTP " 319#endif 320 "\n" 321 322#ifdef USE_SSL_OPENSSL 323 "+USE_SSL_OPENSSL " 324#else 325 "-USE_SSL_OPENSSL " 326#endif 327 328#ifdef USE_SSL_GNUTLS 329 "+USE_SSL_GNUTLS " 330#else 331 "-USE_SSL_GNUTLS " 332#endif 333 334#ifdef USE_SASL 335 "+USE_SASL " 336#else 337 "-USE_SASL " 338#endif 339#ifdef USE_GSS 340 "+USE_GSS " 341#else 342 "-USE_GSS " 343#endif 344 345#if HAVE_GETADDRINFO 346 "+HAVE_GETADDRINFO " 347#else 348 "-HAVE_GETADDRINFO " 349#endif 350 ); 351 352 puts ( 353#ifdef HAVE_REGCOMP 354 "+HAVE_REGCOMP " 355#else 356 "-HAVE_REGCOMP " 357#endif 358 359#ifdef USE_GNU_REGEX 360 "+USE_GNU_REGEX " 361#else 362 "-USE_GNU_REGEX " 363#endif 364 365 "\n" 366 367#ifdef HAVE_COLOR 368 "+HAVE_COLOR " 369#else 370 "-HAVE_COLOR " 371#endif 372 373#ifdef HAVE_START_COLOR 374 "+HAVE_START_COLOR " 375#else 376 "-HAVE_START_COLOR " 377#endif 378 379#ifdef HAVE_TYPEAHEAD 380 "+HAVE_TYPEAHEAD " 381#else 382 "-HAVE_TYPEAHEAD " 383#endif 384 385#ifdef HAVE_BKGDSET 386 "+HAVE_BKGDSET " 387#else 388 "-HAVE_BKGDSET " 389#endif 390 391 "\n" 392 393#ifdef HAVE_CURS_SET 394 "+HAVE_CURS_SET " 395#else 396 "-HAVE_CURS_SET " 397#endif 398 399#ifdef HAVE_META 400 "+HAVE_META " 401#else 402 "-HAVE_META " 403#endif 404 405#ifdef HAVE_RESIZETERM 406 "+HAVE_RESIZETERM " 407#else 408 "-HAVE_RESIZETERM " 409#endif 410 411#ifdef HAVE_FUTIMENS 412 "+HAVE_FUTIMENS " 413#else 414 "-HAVE_FUTIMENS " 415#endif 416 ); 417 418 puts ( 419#ifdef CRYPT_BACKEND_CLASSIC_PGP 420 "+CRYPT_BACKEND_CLASSIC_PGP " 421#else 422 "-CRYPT_BACKEND_CLASSIC_PGP " 423#endif 424#ifdef CRYPT_BACKEND_CLASSIC_SMIME 425 "+CRYPT_BACKEND_CLASSIC_SMIME " 426#else 427 "-CRYPT_BACKEND_CLASSIC_SMIME " 428#endif 429#ifdef CRYPT_BACKEND_GPGME 430 "+CRYPT_BACKEND_GPGME " 431#else 432 "-CRYPT_BACKEND_GPGME " 433#endif 434 ); 435 436 puts ( 437#ifdef EXACT_ADDRESS 438 "+EXACT_ADDRESS " 439#else 440 "-EXACT_ADDRESS " 441#endif 442 443#ifdef SUN_ATTACHMENT 444 "+SUN_ATTACHMENT " 445#else 446 "-SUN_ATTACHMENT " 447#endif 448 449 "\n" 450 451#ifdef ENABLE_NLS 452 "+ENABLE_NLS " 453#else 454 "-ENABLE_NLS " 455#endif 456 457#ifdef LOCALES_HACK 458 "+LOCALES_HACK " 459#else 460 "-LOCALES_HACK " 461#endif 462 463#ifdef HAVE_WC_FUNCS 464 "+HAVE_WC_FUNCS " 465#else 466 "-HAVE_WC_FUNCS " 467#endif 468 469#ifdef HAVE_LANGINFO_CODESET 470 "+HAVE_LANGINFO_CODESET " 471#else 472 "-HAVE_LANGINFO_CODESET " 473#endif 474 475 476#ifdef HAVE_LANGINFO_YESEXPR 477 "+HAVE_LANGINFO_YESEXPR " 478#else 479 "-HAVE_LANGINFO_YESEXPR " 480#endif 481 482 "\n" 483 484#if HAVE_ICONV 485 "+HAVE_ICONV " 486#else 487 "-HAVE_ICONV " 488#endif 489 490#if ICONV_NONTRANS 491 "+ICONV_NONTRANS " 492#else 493 "-ICONV_NONTRANS " 494#endif 495 496#if HAVE_LIBIDN 497 "+HAVE_LIBIDN " 498#else 499 "-HAVE_LIBIDN " 500#endif 501 502#if HAVE_LIBIDN2 503 "+HAVE_LIBIDN2 " 504#else 505 "-HAVE_LIBIDN2 " 506#endif 507 508#if HAVE_GETSID 509 "+HAVE_GETSID " 510#else 511 "-HAVE_GETSID " 512#endif 513 514#if USE_HCACHE 515 "+USE_HCACHE " 516#else 517 "-USE_HCACHE " 518#endif 519 520 "\n" 521 522#ifdef USE_SIDEBAR 523 "+USE_SIDEBAR " 524#else 525 "-USE_SIDEBAR " 526#endif 527 528#ifdef USE_COMPRESSED 529 "+USE_COMPRESSED " 530#else 531 "-USE_COMPRESSED " 532#endif 533 534#ifdef USE_INOTIFY 535 "+USE_INOTIFY " 536#else 537 "-USE_INOTIFY " 538#endif 539 540 ); 541 542#ifdef ISPELL 543 printf ("ISPELL=\"%s\"\n", ISPELL); 544#else 545 puts ("-ISPELL"); 546#endif 547 548 printf ("SENDMAIL=\"%s\"\n", SENDMAIL); 549 printf ("MAILPATH=\"%s\"\n", MAILPATH); 550 printf ("PKGDATADIR=\"%s\"\n", PKGDATADIR); 551 printf ("SYSCONFDIR=\"%s\"\n", SYSCONFDIR); 552 printf ("EXECSHELL=\"%s\"\n", EXECSHELL); 553#ifdef MIXMASTER 554 printf ("MIXMASTER=\"%s\"\n", MIXMASTER); 555#else 556 puts ("-MIXMASTER"); 557#endif 558 559 putchar ('\n'); 560 561 puts(_(ReachingUs)); 562 563 mutt_print_patchlist(); 564 565 exit (0); 566} 567 568static void start_curses (void) 569{ 570 km_init (); /* must come before mutt_init */ 571 572#ifdef USE_SLANG_CURSES 573 SLtt_Ignore_Beep = 1; /* don't do that #*$@^! annoying visual beep! */ 574 SLsmg_Display_Eight_Bit = 128; /* characters above this are printable */ 575 SLtt_set_color(0, NULL, "default", "default"); 576#if SLANG_VERSION >= 20000 577 SLutf8_enable(-1); 578#endif 579#else 580 /* should come before initscr() so that ncurses 4.2 doesn't try to install 581 its own SIGWINCH handler */ 582 mutt_signal_init (); 583#endif 584 if (initscr () == NULL) 585 { 586 puts _("Error initializing terminal."); 587 exit (1); 588 } 589#if 1 /* USE_SLANG_CURSES - commenting out suggested in #455. */ 590 /* slang requires the signal handlers to be set after initializing */ 591 mutt_signal_init (); 592#endif 593 ci_start_color (); 594 keypad (stdscr, TRUE); 595 cbreak (); 596 noecho (); 597#if HAVE_TYPEAHEAD 598 typeahead (-1); /* simulate smooth scrolling */ 599#endif 600#if HAVE_META 601 meta (stdscr, TRUE); 602#endif 603 init_extended_keys(); 604 mutt_reflow_windows (); 605} 606 607#define MUTT_IGNORE (1<<0) /* -z */ 608#define MUTT_BUFFY (1<<1) /* -Z */ 609#define MUTT_NOSYSRC (1<<2) /* -n */ 610#define MUTT_RO (1<<3) /* -R */ 611#define MUTT_SELECT (1<<4) /* -y */ 612 613int main (int argc, char **argv, char **environ) 614{ 615 BUFFER *folder = NULL; 616 BUFFER *expanded_infile = NULL; 617 BUFFER *tempfile = NULL; 618 char *subject = NULL; 619 char *includeFile = NULL; 620 char *draftFile = NULL; 621 char *newMagic = NULL; 622 HEADER *msg = NULL; 623 LIST *attach = NULL; 624 LIST *commands = NULL; 625 LIST *queries = NULL; 626 LIST *alias_queries = NULL; 627 int sendflags = 0; 628 int flags = 0; 629 int version = 0; 630 int i; 631 int explicit_folder = 0; 632 int dump_variables = 0; 633 int edit_infile = 0; 634 extern char *optarg; 635 extern int optind; 636 int double_dash = argc, nargc = 1; 637 int exit_code = 1; 638 const char *exit_endwin_msg = NULL; 639 640 /* sanity check against stupid administrators */ 641 642 if (getegid() != getgid()) 643 { 644 fprintf(stderr, "%s: I don't want to run with privileges!\n", 645 argv[0]); 646 exit(1); 647 } 648 649 setlocale (LC_ALL, ""); 650 651#ifdef ENABLE_NLS 652 /* FIXME what about the LOCALES_HACK in mutt_init() [init.c] ? */ 653 { 654 char *domdir = getenv ("TEXTDOMAINDIR"); 655 if (domdir && domdir[0]) 656 bindtextdomain (PACKAGE, domdir); 657 else 658 bindtextdomain (PACKAGE, MUTTLOCALEDIR); 659 textdomain (PACKAGE); 660 } 661#endif 662 663 mutt_error = mutt_nocurses_error; 664 mutt_message = mutt_nocurses_error; 665 SRAND (time (NULL)); 666 umask (077); 667 668 memset (Options, 0, sizeof (Options)); 669 memset (QuadOptions, 0, sizeof (QuadOptions)); 670 671 /* Init envlist */ 672 { 673 char **srcp, **dstp; 674 int count = 0; 675 for (srcp = environ; srcp && *srcp; srcp++) 676 count++; 677 envlist = safe_calloc(count+1, sizeof(char *)); 678 for (srcp = environ, dstp = envlist; srcp && *srcp; srcp++, dstp++) 679 *dstp = safe_strdup(*srcp); 680 } 681 682 for (optind = 1; optind < double_dash; ) 683 { 684 /* We're getopt'ing POSIXLY, so we'll be here every time getopt() 685 * encounters a non-option. That could be a file to attach 686 * (all non-options between -a and --) or it could be an address 687 * (which gets collapsed to the front of argv). 688 */ 689 for (; optind < argc; optind++) 690 { 691 if (argv[optind][0] == '-' && argv[optind][1] != '\0') 692 { 693 if (argv[optind][1] == '-' && argv[optind][2] == '\0') 694 double_dash = optind; /* quit outer loop after getopt */ 695 break; /* drop through to getopt */ 696 } 697 698 /* non-option, either an attachment or address */ 699 if (attach) 700 attach = mutt_add_list (attach, argv[optind]); 701 else 702 argv[nargc++] = argv[optind]; 703 } 704 705 if ((i = getopt (argc, argv, "+A:a:b:F:f:c:Dd:Ee:H:s:i:hm:npQ:RvxyzZ")) != EOF) 706 switch (i) 707 { 708 case 'A': 709 alias_queries = mutt_add_list (alias_queries, optarg); 710 break; 711 case 'a': 712 attach = mutt_add_list (attach, optarg); 713 break; 714 715 case 'F': 716 mutt_str_replace (&Muttrc, optarg); 717 break; 718 719 case 'f': 720 if (!folder) 721 folder = mutt_buffer_new (); 722 mutt_buffer_strcpy (folder, optarg); 723 explicit_folder = 1; 724 break; 725 726 case 'b': 727 case 'c': 728 if (!msg) 729 msg = mutt_new_header (); 730 if (!msg->env) 731 msg->env = mutt_new_envelope (); 732 if (i == 'b') 733 msg->env->bcc = rfc822_parse_adrlist (msg->env->bcc, optarg); 734 else 735 msg->env->cc = rfc822_parse_adrlist (msg->env->cc, optarg); 736 break; 737 738 case 'D': 739 dump_variables = 1; 740 break; 741 742 case 'd': 743#ifdef DEBUG 744 if (mutt_atoi (optarg, &debuglevel) < 0 || debuglevel <= 0) 745 { 746 fprintf (stderr, _("Error: value '%s' is invalid for -d.\n"), optarg); 747 return 1; 748 } 749 printf (_("Debugging at level %d.\n"), debuglevel); 750#else 751 printf ("%s", _("DEBUG was not defined during compilation. Ignored.\n")); 752#endif 753 break; 754 755 case 'E': 756 edit_infile = 1; 757 break; 758 759 case 'e': 760 commands = mutt_add_list (commands, optarg); 761 break; 762 763 case 'H': 764 draftFile = optarg; 765 break; 766 767 case 'i': 768 includeFile = optarg; 769 break; 770 771 case 'm': 772 /* should take precedence over .muttrc setting, so save it for later */ 773 newMagic = optarg; 774 break; 775 776 case 'n': 777 flags |= MUTT_NOSYSRC; 778 break; 779 780 case 'p': 781 sendflags |= SENDPOSTPONED; 782 break; 783 784 case 'Q': 785 queries = mutt_add_list (queries, optarg); 786 break; 787 788 case 'R': 789 flags |= MUTT_RO; /* read-only mode */ 790 break; 791 792 case 's': 793 subject = optarg; 794 break; 795 796 case 'v': 797 version++; 798 break; 799 800 case 'x': /* mailx compatible send mode */ 801 sendflags |= SENDMAILX; 802 break; 803 804 case 'y': /* My special hack mode */ 805 flags |= MUTT_SELECT; 806 break; 807 808 case 'z': 809 flags |= MUTT_IGNORE; 810 break; 811 812 case 'Z': 813 flags |= MUTT_BUFFY | MUTT_IGNORE; 814 break; 815 816 default: 817 mutt_usage (); 818 } 819 } 820 821#ifdef USE_SASL 822 { 823 int ret; 824 if ((ret = mutt_sasl_start()) != SASL_OK) { 825 fprintf(stderr, "%s: mutt_sasl_start: %d\n", argv[0], ret); 826 exit(1); 827 } 828 } 829#endif 830 831#ifdef __OpenBSD__ 832#ifdef CRYPT_BACKEND_GPGME 833 if (pledge("stdio rpath wpath cpath flock fattr getpw tty inet dns " 834 "proc exec sendfd recvfd", NULL) == -1) { 835 fprintf(stderr, "%s: pledge: %s\n", argv[0], strerror(errno)); 836 exit(1); 837 } 838#else 839 if (pledge("stdio rpath wpath cpath flock fattr getpw tty inet dns " 840 "proc exec", NULL) == -1) { 841 fprintf(stderr, "%s: pledge: %s\n", argv[0], strerror(errno)); 842 exit(1); 843 } 844#endif /* CRYPT_BACKEND_GPGME */ 845#endif 846 847 /* collapse remaining argv */ 848 while (optind < argc) 849 argv[nargc++] = argv[optind++]; 850 optind = 1; 851 argc = nargc; 852 853 switch (version) 854 { 855 case 0: 856 break; 857 case 1: 858 show_version (); 859 break; 860 default: 861 puts (mutt_make_version ()); 862 puts (Copyright); 863 puts (_(Thanks)); 864 puts (_(Licence)); 865 puts (_(Obtaining)); 866 puts (_(ReachingUs)); 867 mutt_buffer_free (&folder); 868 exit (0); 869 } 870 871 /* Check for a batch send. */ 872 if (!isatty (0) || queries || alias_queries || dump_variables) 873 { 874 set_option (OPTNOCURSES); 875 sendflags = SENDBATCH; 876 } 877 878 /* Always create the mutt_windows because batch mode has some shared code 879 * paths that end up referencing them. */ 880 mutt_init_windows (); 881 882 /* This must come before mutt_init() because curses needs to be started 883 before calling the init_pair() function to set the color scheme. */ 884 if (!option (OPTNOCURSES)) 885 { 886 start_curses (); 887 888 /* check whether terminal status is supported (must follow curses init) */ 889 TSSupported = mutt_ts_capability(); 890 } 891 892 /* set defaults and read init files */ 893 mutt_init (flags & MUTT_NOSYSRC, commands); 894 mutt_free_list (&commands); 895 896 /* Initialize crypto backends. */ 897 crypt_init (); 898 899 if (newMagic) 900 mx_set_magic (newMagic); 901 902 if (queries) 903 { 904 for (; optind < argc; optind++) 905 queries = mutt_add_list (queries, argv[optind]); 906 exit_code = mutt_query_variables (queries); 907 mutt_free_list (&queries); 908 goto cleanup_and_exit; 909 } 910 if (dump_variables) 911 { 912 exit_code = mutt_dump_variables(); 913 goto cleanup_and_exit; 914 } 915 916 if (alias_queries) 917 { 918 ADDRESS *a; 919 920 exit_code = 0; 921 for (; optind < argc; optind++) 922 alias_queries = mutt_add_list (alias_queries, argv[optind]); 923 for (; alias_queries; alias_queries = alias_queries->next) 924 { 925 if ((a = mutt_lookup_alias (alias_queries->data))) 926 { 927 /* output in machine-readable form */ 928 mutt_addrlist_to_intl (a, NULL); 929 mutt_write_address_list (a, stdout, 0, 0); 930 } 931 else 932 { 933 exit_code = 1; 934 printf ("%s\n", alias_queries->data); 935 } 936 } 937 mutt_free_list (&alias_queries); 938 goto cleanup_and_exit; 939 } 940 941 if (!option (OPTNOCURSES)) 942 { 943 SETCOLOR (MT_COLOR_NORMAL); 944 clear (); 945 mutt_error = mutt_curses_error; 946 mutt_message = mutt_curses_message; 947 } 948 949 /* Initialize autocrypt after curses messages are working, 950 * because of the initial account setup screens. */ 951#ifdef USE_AUTOCRYPT 952 if (option (OPTAUTOCRYPT)) 953 mutt_autocrypt_init (!(sendflags & SENDBATCH)); 954#endif 955 956 /* Create the Maildir directory if it doesn't exist. */ 957 if (!option (OPTNOCURSES) && Maildir) 958 { 959 struct stat sb; 960 BUFFER *fpath; 961 char msg[STRING]; 962 963 fpath = mutt_buffer_pool_get (); 964 mutt_buffer_strcpy (fpath, Maildir); 965 mutt_buffer_expand_path (fpath); 966#ifdef USE_IMAP 967 /* we're not connected yet - skip mail folder creation */ 968 if (!mx_is_imap (mutt_b2s (fpath))) 969#endif 970 if (stat (mutt_b2s (fpath), &sb) == -1 && errno == ENOENT) 971 { 972 snprintf (msg, sizeof (msg), _("%s does not exist. Create it?"), Maildir); 973 if (mutt_yesorno (msg, MUTT_YES) == MUTT_YES) 974 { 975 if (mkdir (mutt_b2s (fpath), 0700) == -1 && errno != EEXIST) 976 mutt_error ( _("Can't create %s: %s."), Maildir, strerror (errno)); 977 } 978 } 979 mutt_buffer_pool_release (&fpath); 980 } 981 982 if (sendflags & SENDPOSTPONED) 983 { 984 if (!option (OPTNOCURSES)) 985 mutt_flushinp (); 986 ci_send_message (SENDPOSTPONED, NULL, NULL, NULL, NULL); 987 } 988 else if (subject || msg || sendflags || draftFile || includeFile || attach || 989 optind < argc) 990 { 991 FILE *fin = NULL; 992 FILE *fout = NULL; 993 char *infile = NULL; 994 char *bodytext = NULL; 995 const char *bodyfile = NULL; 996 int rv = 0; 997 998 if (!option (OPTNOCURSES)) 999 mutt_flushinp (); 1000 1001 if (!msg) 1002 msg = mutt_new_header (); 1003 if (!msg->env) 1004 msg->env = mutt_new_envelope (); 1005 1006 for (i = optind; i < argc; i++) 1007 { 1008 if (url_check_scheme (argv[i]) == U_MAILTO) 1009 { 1010 if (url_parse_mailto (msg->env, &bodytext, argv[i]) < 0) 1011 { 1012 if (!option (OPTNOCURSES)) 1013 { 1014 mutt_endwin (NULL); 1015 set_option (OPTNOCURSES); 1016 } 1017 fputs (_("Failed to parse mailto: link\n"), stderr); 1018 goto cleanup_and_exit; 1019 } 1020 } 1021 else 1022 msg->env->to = rfc822_parse_adrlist (msg->env->to, argv[i]); 1023 } 1024 1025 if (!draftFile && option (OPTAUTOEDIT) && !msg->env->to && !msg->env->cc) 1026 { 1027 if (!option (OPTNOCURSES)) 1028 { 1029 mutt_endwin (NULL); 1030 set_option (OPTNOCURSES); 1031 } 1032 fputs (_("No recipients specified.\n"), stderr); 1033 goto cleanup_and_exit; 1034 } 1035 1036 if (subject) 1037 msg->env->subject = safe_strdup (subject); 1038 1039 if (draftFile) 1040 { 1041 infile = draftFile; 1042 includeFile = NULL; 1043 } 1044 else if (includeFile) 1045 infile = includeFile; 1046 else 1047 edit_infile = 0; 1048 1049 if (infile || bodytext) 1050 { 1051 /* Prepare fin and expanded_infile. */ 1052 if (infile) 1053 { 1054 if (mutt_strcmp ("-", infile) == 0) 1055 { 1056 if (edit_infile) 1057 { 1058 fputs (_("Cannot use -E flag with stdin\n"), stderr); 1059 goto cleanup_and_exit; 1060 } 1061 fin = stdin; 1062 } 1063 else 1064 { 1065 expanded_infile = mutt_buffer_new (); 1066 mutt_buffer_strcpy (expanded_infile, infile); 1067 mutt_buffer_expand_path (expanded_infile); 1068 if ((fin = fopen (mutt_b2s (expanded_infile), "r")) == NULL) 1069 { 1070 if (!option (OPTNOCURSES)) 1071 { 1072 mutt_endwin (NULL); 1073 set_option (OPTNOCURSES); 1074 } 1075 perror (mutt_b2s (expanded_infile)); 1076 goto cleanup_and_exit; 1077 } 1078 } 1079 } 1080 1081 /* Copy input to a tempfile, and re-point fin to the tempfile. 1082 * Note: stdin is always copied to a tempfile, ensuring draftFile 1083 * can stat and get the correct st_size below. 1084 */ 1085 if (!edit_infile) 1086 { 1087 tempfile = mutt_buffer_new (); 1088 mutt_buffer_mktemp (tempfile); 1089 1090 if ((fout = safe_fopen (mutt_b2s (tempfile), "w")) == NULL) 1091 { 1092 if (!option (OPTNOCURSES)) 1093 { 1094 mutt_endwin (NULL); 1095 set_option (OPTNOCURSES); 1096 } 1097 perror (mutt_b2s (tempfile)); 1098 safe_fclose (&fin); 1099 goto cleanup_and_exit; 1100 } 1101 if (fin) 1102 { 1103 mutt_copy_stream (fin, fout); 1104 if (fin != stdin) 1105 safe_fclose (&fin); 1106 } 1107 else if (bodytext) 1108 fputs (bodytext, fout); 1109 safe_fclose (&fout); 1110 1111 if ((fin = fopen (mutt_b2s (tempfile), "r")) == NULL) 1112 { 1113 if (!option (OPTNOCURSES)) 1114 { 1115 mutt_endwin (NULL); 1116 set_option (OPTNOCURSES); 1117 } 1118 perror (mutt_b2s (tempfile)); 1119 goto cleanup_and_exit; 1120 } 1121 } 1122 /* If editing the infile, keep it around afterwards so 1123 * it doesn't get unlinked, and we can rebuild the draftFile 1124 */ 1125 else 1126 sendflags |= SENDNOFREEHEADER; 1127 1128 /* Parse the draftFile into the full HEADER/BODY structure. 1129 * Set SENDDRAFTFILE so ci_send_message doesn't overwrite 1130 * our msg->content. 1131 */ 1132 if (draftFile) 1133 { 1134 HEADER *context_hdr = NULL; 1135 ENVELOPE *opts_env = msg->env; 1136 struct stat st; 1137 LIST *uh, **last_uhp; 1138 1139 sendflags |= SENDDRAFTFILE; 1140 1141 /* Set up a "context" header with just enough information so that 1142 * mutt_prepare_template() can parse the message in fin. 1143 */ 1144 context_hdr = mutt_new_header (); 1145 context_hdr->offset = 0; 1146 context_hdr->content = mutt_new_body (); 1147 if (fstat (fileno (fin), &st)) 1148 { 1149 perror (draftFile); 1150 goto cleanup_and_exit; 1151 } 1152 context_hdr->content->length = st.st_size; 1153 1154 mutt_prepare_template (fin, NULL, msg, context_hdr, 0); 1155 1156 /* Scan for mutt header to set OPTRESUMEDRAFTFILES */ 1157 for (last_uhp = &msg->env->userhdrs, uh = *last_uhp; 1158 uh; uh = *last_uhp) 1159 { 1160 if (ascii_strncasecmp ("X-Mutt-Resume-Draft:", uh->data, 20) == 0) 1161 { 1162 if (option (OPTRESUMEEDITEDDRAFTFILES)) 1163 set_option (OPTRESUMEDRAFTFILES); 1164 1165 *last_uhp = uh->next; 1166 uh->next = NULL; 1167 mutt_free_list (&uh); 1168 } 1169 else 1170 last_uhp = &uh->next; 1171 } 1172 1173 rfc822_append (&msg->env->to, opts_env->to, 0); 1174 rfc822_append (&msg->env->cc, opts_env->cc, 0); 1175 rfc822_append (&msg->env->bcc, opts_env->bcc, 0); 1176 if (opts_env->subject) 1177 mutt_str_replace (&msg->env->subject, opts_env->subject); 1178 1179 mutt_free_envelope (&opts_env); 1180 mutt_free_header (&context_hdr); 1181 } 1182 /* Editing the includeFile: pass it directly in. 1183 * Note that SENDNOFREEHEADER is set above so it isn't unlinked. 1184 */ 1185 else if (edit_infile) 1186 bodyfile = mutt_b2s (expanded_infile); 1187 /* For bodytext and unedited includeFile: use the tempfile. 1188 */ 1189 else 1190 bodyfile = mutt_b2s (tempfile); 1191 1192 if (fin) 1193 safe_fclose (&fin); 1194 } 1195 1196 FREE (&bodytext); 1197 1198 if (attach) 1199 { 1200 LIST *t = attach; 1201 BODY *a = msg->content; 1202 1203 while (a && a->next) 1204 a = a->next; 1205 1206 while (t) 1207 { 1208 if (a) 1209 { 1210 a->next = mutt_make_file_attach (t->data); 1211 a = a->next; 1212 } 1213 else 1214 msg->content = a = mutt_make_file_attach (t->data); 1215 if (!a) 1216 { 1217 if (!option (OPTNOCURSES)) 1218 { 1219 mutt_endwin (NULL); 1220 set_option (OPTNOCURSES); 1221 } 1222 fprintf (stderr, _("%s: unable to attach file.\n"), t->data); 1223 mutt_free_list (&attach); 1224 goto cleanup_and_exit; 1225 } 1226 t = t->next; 1227 } 1228 mutt_free_list (&attach); 1229 } 1230 1231 rv = ci_send_message (sendflags, msg, bodyfile, NULL, NULL); 1232 1233 if (edit_infile) 1234 { 1235 if (includeFile) 1236 msg->content->unlink = 0; 1237 else if (draftFile) 1238 { 1239 if (truncate (mutt_b2s (expanded_infile), 0) == -1) 1240 { 1241 if (!option (OPTNOCURSES)) 1242 { 1243 mutt_endwin (NULL); 1244 set_option (OPTNOCURSES); 1245 } 1246 perror (mutt_b2s (expanded_infile)); 1247 goto cleanup_and_exit; 1248 } 1249 if ((fout = safe_fopen (mutt_b2s (expanded_infile), "a")) == NULL) 1250 { 1251 if (!option (OPTNOCURSES)) 1252 { 1253 mutt_endwin (NULL); 1254 set_option (OPTNOCURSES); 1255 } 1256 perror (mutt_b2s (expanded_infile)); 1257 goto cleanup_and_exit; 1258 } 1259 1260 /* If the message was sent or postponed, these will already 1261 * have been done. 1262 */ 1263 if (rv < 0) 1264 { 1265 if (msg->content->next) 1266 msg->content = mutt_make_multipart_mixed (msg->content); 1267 mutt_encode_descriptions (msg->content, 1); 1268 mutt_prepare_envelope (msg->env, 0); 1269 mutt_env_to_intl (msg->env, NULL, NULL); 1270 } 1271 1272 mutt_write_rfc822_header (fout, msg->env, msg->content, 1273 MUTT_WRITE_HEADER_POSTPONE, 0, 1274 option (OPTCRYPTPROTHDRSREAD) && 1275 mutt_should_hide_protected_subject (msg)); 1276 if (option (OPTRESUMEEDITEDDRAFTFILES)) 1277 fprintf (fout, "X-Mutt-Resume-Draft: 1\n"); 1278 fputc ('\n', fout); 1279 if ((mutt_write_mime_body (msg->content, fout) == -1)) 1280 { 1281 safe_fclose (&fout); 1282 goto cleanup_and_exit; 1283 } 1284 safe_fclose (&fout); 1285 } 1286 1287 mutt_free_header (&msg); 1288 } 1289 1290 /* !edit_infile && draftFile will leave the tempfile around */ 1291 if (tempfile) 1292 unlink (mutt_b2s (tempfile)); 1293 1294 if (rv) 1295 goto cleanup_and_exit; 1296 } 1297 else 1298 { 1299 if (!folder) 1300 folder = mutt_buffer_new (); 1301 1302 if (flags & MUTT_BUFFY) 1303 { 1304#ifdef USE_IMAP 1305 int passive = option (OPTIMAPPASSIVE); 1306 if (passive) 1307 unset_option (OPTIMAPPASSIVE); 1308#endif 1309 if (!mutt_buffy_check (0)) 1310 { 1311 exit_endwin_msg = _("No mailbox with new mail."); 1312 goto cleanup_and_exit; 1313 } 1314 mutt_buffer_clear (folder); 1315 mutt_buffer_buffy (folder); 1316#ifdef USE_IMAP 1317 if (passive) 1318 set_option (OPTIMAPPASSIVE); 1319#endif 1320 } 1321 else if (flags & MUTT_SELECT) 1322 { 1323 if (!Incoming) 1324 { 1325 exit_endwin_msg = _("No incoming mailboxes defined."); 1326 goto cleanup_and_exit; 1327 } 1328 mutt_buffer_clear (folder); 1329 mutt_buffer_select_file (folder, MUTT_SEL_FOLDER | MUTT_SEL_BUFFY); 1330 if (!mutt_buffer_len (folder)) 1331 { 1332 exit_code = 0; 1333 goto cleanup_and_exit; 1334 } 1335 } 1336 1337 if (!mutt_buffer_len (folder)) 1338 mutt_buffer_strcpy (folder, NONULL(Spoolfile)); 1339 mutt_buffer_expand_path (folder); 1340 1341 mutt_str_replace (&CurrentFolder, mutt_b2s (folder)); 1342 mutt_str_replace (&LastFolder, mutt_b2s (folder)); 1343 1344 if (flags & MUTT_IGNORE) 1345 { 1346 /* check to see if there are any messages in the folder */ 1347 switch (mx_check_empty (mutt_b2s (folder))) 1348 { 1349 case -1: 1350 exit_endwin_msg = strerror (errno); 1351 goto cleanup_and_exit; 1352 case 1: 1353 exit_endwin_msg = _("Mailbox is empty."); 1354 goto cleanup_and_exit; 1355 } 1356 } 1357 1358 mutt_folder_hook (mutt_b2s (folder)); 1359 1360 Context = mx_open_mailbox (mutt_b2s (folder), 1361 ((flags & MUTT_RO) || option (OPTREADONLY)) ? MUTT_READONLY : 0, 1362 NULL); 1363 mutt_buffer_free (&folder); 1364 1365 if (Context || !explicit_folder) 1366 { 1367#ifdef USE_SIDEBAR 1368 mutt_sb_set_open_buffy (); 1369#endif 1370 mutt_index_menu (); 1371 if (Context) 1372 FREE (&Context); 1373 } 1374 1375 exit_endwin_msg = Errorbuf; 1376 } 1377 1378 exit_code = 0; 1379 1380cleanup_and_exit: 1381 mutt_buffer_free (&folder); 1382 mutt_buffer_free (&expanded_infile); 1383 mutt_buffer_free (&tempfile); 1384#ifdef USE_IMAP 1385 imap_logout_all (); 1386#endif 1387#ifdef USE_SASL 1388 mutt_sasl_done (); 1389#endif 1390#ifdef USE_AUTOCRYPT 1391 mutt_autocrypt_cleanup (); 1392#endif 1393 mutt_browser_cleanup (); 1394 mutt_free_opts (); 1395 mutt_free_windows (); 1396 mutt_buffer_pool_free (); 1397 if (!option (OPTNOCURSES)) 1398 mutt_endwin (exit_endwin_msg); 1399 exit (exit_code); 1400}