mutt stable branch with some hacks
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}