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