"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/main.c" (8 Aug 2018, 42612 Bytes) of package /linux/misc/s-nail-14.9.11.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.10_vs_14.9.11.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Startup and initialization.
    3  *@ This file is also used to materialize externals.
    4  *
    5  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    6  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    7  * SPDX-License-Identifier: BSD-3-Clause TODO ISC
    8  */
    9 /*
   10  * Copyright (c) 1980, 1993
   11  *      The Regents of the University of California.  All rights reserved.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  */
   37 #undef n_FILE
   38 #define n_FILE main
   39 #define n_MAIN_SOURCE
   40 
   41 #include "nail.h"
   42 
   43 #include <sys/ioctl.h>
   44 
   45 #include <pwd.h>
   46 
   47 struct a_arg{
   48    struct a_arg *aa_next;
   49    char const *aa_file;
   50 };
   51 
   52 /* (extern, but not with amalgamation, so define here) */
   53 VL char const n_weekday_names[7 + 1][4] = {
   54    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", ""
   55 };
   56 VL char const n_month_names[12 + 1][4] = {
   57    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   58    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", ""
   59 };
   60 VL char const n_uagent[sizeof VAL_UAGENT] = VAL_UAGENT;
   61 #ifdef HAVE_UISTRINGS
   62 VL char const n_error[sizeof n_ERROR] = N_(n_ERROR);
   63 #endif
   64 VL char const n_path_devnull[sizeof n_PATH_DEVNULL] = n_PATH_DEVNULL;
   65 VL char const n_reproducible_name[sizeof "reproducible_build"] =
   66       "reproducible_build";
   67 VL char const n_unirepl[sizeof n_UNIREPL] = n_UNIREPL;
   68 VL char const n_empty[1] = "";
   69 VL char const n_0[2] = "0";
   70 VL char const n_1[2] = "1";
   71 VL char const n_m1[3] = "-1";
   72 VL char const n_em[2] = "!";
   73 VL char const n_ns[2] = "#";
   74 VL char const n_star[2] = "*";
   75 VL char const n_hy[2] = "-";
   76 VL char const n_qm[2] = "?";
   77 VL char const n_at[2] = "@";
   78 VL ui16_t const n_class_char[1 + 0x7F] = {
   79 #define a_BC C_BLANK | C_CNTRL
   80 #define a_SC C_SPACE | C_CNTRL
   81 #define a_WC C_WHITE | C_CNTRL
   82 /* 000 nul  001 soh  002 stx  003 etx  004 eot  005 enq  006 ack  007 bel */
   83    C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL,
   84 /* 010 bs   011 ht   012 nl   013 vt   014 np   015 cr   016 so   017 si */
   85    C_CNTRL, a_BC,    a_WC,    a_SC,    a_SC,    a_SC,    C_CNTRL, C_CNTRL,
   86 /* 020 dle  021 dc1  022 dc2  023 dc3  024 dc4  025 nak  026 syn  027 etb */
   87    C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL,
   88 /* 030 can  031 em   032 sub  033 esc  034 fs   035 gs   036 rs   037 us */
   89    C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL, C_CNTRL,
   90 #undef a_WC
   91 #undef a_SC
   92 #undef a_BC
   93 /* 040 sp   041  !   042  "   043  #   044  $   045  %   046  &   047  ' */
   94    C_BLANK, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT,
   95 /* 050  (   051  )   052  *   053  +   054  ,    055  -   056  .   057  / */
   96    C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT,
   97 /* 060  0   061  1   062  2   063  3   064  4   065  5   066  6   067  7 */
   98    C_OCTAL, C_OCTAL, C_OCTAL, C_OCTAL, C_OCTAL, C_OCTAL, C_OCTAL, C_OCTAL,
   99 /* 070  8   071  9   072  :   073  ;   074  <   075  =   076  >   077  ? */
  100    C_DIGIT, C_DIGIT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT,
  101 /* 100  @   101  A   102  B   103  C   104  D   105  E   106  F   107  G */
  102    C_PUNCT, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER,
  103 /* 110  H   111  I   112  J   113  K   114  L   115  M   116  N   117  O */
  104    C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER,
  105 /* 120  P   121  Q   122  R   123  S   124  T   125  U   126  V   127  W */
  106    C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER, C_UPPER,
  107 /* 130  X   131  Y   132  Z   133  [   134  \   135  ]   136  ^   137  _ */
  108    C_UPPER, C_UPPER, C_UPPER, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT,
  109 /* 140  `   141  a   142  b   143  c   144  d   145  e   146  f   147  g */
  110    C_PUNCT, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER,
  111 /* 150  h   151  i   152  j   153  k   154  l   155  m   156  n   157  o */
  112    C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER,
  113 /* 160  p   161  q   162  r   163  s   164  t   165  u   166  v   167  w */
  114    C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER, C_LOWER,
  115 /* 170  x   171  y   172  z   173  {   174  |   175  }   176  ~   177 del */
  116    C_LOWER, C_LOWER, C_LOWER, C_PUNCT, C_PUNCT, C_PUNCT, C_PUNCT, C_CNTRL
  117 };
  118 
  119 /* Our own little getopt(3) */
  120 static char const *a_main_oarg;
  121 static int a_main_oind, /*_oerr,*/ a_main_oopt;
  122 
  123 /* A little getopt(3).  Note: --help/--version == -h/-v */
  124 static int a_main_getopt(int argc, char * const argv[], char const *optstring);
  125 
  126 /* */
  127 static void a_main_usage(FILE *fp);
  128 
  129 /* Perform basic startup initialization */
  130 static void a_main_startup(void);
  131 
  132 /* Grow a char** */
  133 static size_t a_main_grow_cpp(char const ***cpp, size_t newsize, size_t oldcnt);
  134 
  135 /* Setup some variables which we require to be valid / verified */
  136 static void a_main_setup_vars(void);
  137 
  138 /* We're in an interactive session - compute what the screen size for printing
  139  * headers etc. should be; notify tty upon resize if *is_sighdl* is not 0.
  140  * We use the following algorithm for the height:
  141  * If baud rate < 1200, use  9
  142  * If baud rate = 1200, use 14
  143  * If baud rate > 1200, use 24 or ws_row
  144  * Width is either 80 or ws_col */
  145 static void a_main_setscreensize(int is_sighdl);
  146 
  147 /* Ok, we are reading mail.  Decide whether we are editing a mailbox or reading
  148  * the system mailbox, and open up the right stuff */
  149 static int a_main_rcv_mode(bool_t had_A_arg, char const *folder,
  150             char const *Larg);
  151 
  152 /* Interrupt printing of the headers */
  153 static void a_main_hdrstop(int signo);
  154 
  155 static int
  156 a_main_getopt(int argc, char * const argv[], char const *optstring){
  157    static char const *lastp;
  158    char const *curp;
  159    int rv/*, colon*/;
  160    NYD2_ENTER;
  161 
  162    a_main_oarg = NULL;
  163    rv = -1;
  164 
  165    /*if((colon = (optstring[0] == ':')))
  166       ++optstring;*/
  167 
  168    if(lastp != NULL){
  169       curp = lastp;
  170       lastp = NULL;
  171    }else{
  172       if(a_main_oind >= argc || argv[a_main_oind] == NULL ||
  173             argv[a_main_oind][0] != '-' || argv[a_main_oind][1] == '\0')
  174          goto jleave;
  175       if(argv[a_main_oind][1] == '-' && argv[a_main_oind][2] == '\0'){
  176          /* We need this in for MTA arg detection (easier) ++a_main_oind;*/
  177          goto jleave;
  178       }
  179       curp = &argv[a_main_oind][1];
  180    }
  181 
  182    for(a_main_oopt = curp[0]; optstring[0] != '\0';){
  183       if(optstring[0] != a_main_oopt){
  184          optstring += 1 + (optstring[1] == ':');
  185          continue;
  186       }
  187 
  188       if(optstring[1] == ':'){
  189          if(curp[1] != '\0'){
  190             a_main_oarg = n_UNCONST(curp + 1);
  191             ++a_main_oind;
  192          }else{
  193             if((a_main_oind += 2) > argc){
  194                /*if(!colon *//*&& _oerr*//*)*/{
  195                   n_err(_("%s: option requires an argument -- %c\n"),
  196                      argv[0], (char)a_main_oopt);
  197                }
  198                rv = (/*colon ? ':' :*/ '?');
  199                goto jleave;
  200             }
  201             a_main_oarg = argv[a_main_oind - 1];
  202          }
  203       }else{
  204          if(curp[1] != '\0')
  205             lastp = curp + 1;
  206          else
  207             ++a_main_oind;
  208       }
  209       rv = a_main_oopt;
  210       goto jleave;
  211    }
  212 
  213    /* Special support for --help and --version, which are quite common */
  214    if(a_main_oopt == '-' && &curp[-1] == argv[a_main_oind]){
  215       ++a_main_oind;
  216       rv = 'h';
  217       if(!strcmp(curp, "-help"))
  218          goto jleave;
  219       rv = 'V';
  220       if(!strcmp(curp, "-version"))
  221          goto jleave;
  222       --a_main_oind;
  223    }
  224 
  225    /* Definitive error */
  226    /*if(!colon *//*&& opterr*//*)*/
  227       n_err(_("%s: invalid option -- %c\n"), argv[0], a_main_oopt);
  228    if(curp[1] != '\0')
  229       lastp = curp + 1;
  230    else
  231       ++a_main_oind;
  232    a_main_oarg = NULL;
  233    rv = '?';
  234 jleave:
  235    NYD2_LEAVE;
  236    return rv;
  237 }
  238 
  239 static void
  240 a_main_usage(FILE *fp){
  241    /* Stay in 24 lines */
  242    char buf[64];
  243    size_t i;
  244    NYD2_ENTER;
  245 
  246    i = strlen(n_progname);
  247    i = n_MIN(i, sizeof(buf) -1);
  248    if(i > 0)
  249       memset(buf, ' ', i);
  250    buf[i] = '\0';
  251 
  252    fprintf(fp, _("%s (%s %s): send and receive Internet mail\n"),
  253       n_progname, n_uagent, ok_vlook(version));
  254    if(fp != n_stderr)
  255       putc('\n', fp);
  256 
  257    fprintf(fp, _(
  258       "Send-only mode: send mail \"to-address\" receiver(s):\n"
  259       "  %s [-DdEFinv~#] [-: spec] [-A account] [:-C \"custom: header\":]\n"
  260       "  %s [:-a attachment:] [:-b bcc-address:] [:-c cc-address:]\n"
  261       "  %s [-M type | -m file | -q file | -t] [-r from-address]\n"
  262       "  %s [:-S var[=value]:] [-s subject] [:-X cmd:] [-.] :to-address:\n"),
  263       n_progname, buf, buf, buf);
  264    if(fp != n_stderr)
  265       putc('\n', fp);
  266 
  267    fprintf(fp, _(
  268       "\"Receive\" mode, starting on [-u user], primary *inbox* or [$MAIL]:\n"
  269       "  %s [-DdEeHiNnRv~#] [-: spec] [-A account] "
  270          "[:-C \"custom: header\":]\n"
  271       "  %s [-L spec] [-r from-address] [:-S var[=value]:] [-u user] "
  272          "[:-X cmd:]\n"),
  273       n_progname, buf);
  274    if(fp != n_stderr)
  275       putc('\n', fp);
  276 
  277    fprintf(fp, _(
  278       "\"Receive\" mode, starting on -f (secondary $MBOX or [file]):\n"
  279       "  %s [-DdEeHiNnRv~#] [-: spec] [-A account] "
  280          "[:-C \"custom: header\":] -f\n"
  281       "  %s [-L spec] [-r from-address] [:-S var[=value]:] [:-X cmd:] "
  282          "[file]\n"),
  283       n_progname, buf);
  284    if(fp != n_stderr)
  285       putc('\n', fp);
  286 
  287    fprintf(fp, _(
  288          ". -d sandbox, -:/ no .rc files, -. end options and force send-mode\n"
  289          ". -a attachment[=input-charset[#output-charset]]\n"
  290          ". -b, -c, to-address, (-r): ex@am.ple or '(Lovely) Ex <am@p.le>'\n"
  291          ". -[Mmqt]: special input data (-t: template message on stdin)\n"
  292          ". -e only mail check, -H header summary; "
  293             "both: message specification via -L\n"
  294          ". -S (un)sets variable, -X executes command(s), "
  295             "-# enters batch mode\n"
  296          ". Features via \"$ %s -Xversion -Xx\"\n"
  297          ". Bugs/Contact via "
  298             "\"$ %s -Sexpandaddr=shquote '\\$contact-mail'\"\n"),
  299          n_progname, n_progname);
  300    NYD2_LEAVE;
  301 }
  302 
  303 static void
  304 a_main_startup(void){
  305    char *cp;
  306    NYD2_ENTER;
  307 
  308    n_stdin = stdin;
  309    n_stdout = stdout;
  310    n_stderr = stderr;
  311    dflpipe = SIG_DFL;
  312 
  313    a_main_oind = /*_oerr =*/ 1;
  314 
  315    if((cp = strrchr(n_progname, '/')) != NULL)
  316       n_progname = ++cp;
  317 
  318 #ifdef HAVE_NYD
  319    safe_signal(SIGABRT, &_nyd_oncrash);
  320 # ifdef SIGBUS
  321    safe_signal(SIGBUS, &_nyd_oncrash);
  322 # endif
  323    safe_signal(SIGFPE, &_nyd_oncrash);
  324    safe_signal(SIGILL, &_nyd_oncrash);
  325    safe_signal(SIGSEGV, &_nyd_oncrash);
  326 #endif
  327 
  328    /* Initialize our input, loop and command machinery */
  329    n_go_init();
  330 
  331    /* Set up a reasonable environment */
  332 
  333    /* TODO This is wrong: interactive is STDIN/STDERR for a POSIX sh(1).
  334     * TODO For now we get this wrong, all over the place, as this software
  335     * TODO has always been developed with stdout as an output channel.
  336     * TODO Start doing it right for at least explicit terminal-related things,
  337     * TODO but v15 should use ONLY this, also for terminal input! */
  338    if(isatty(STDIN_FILENO)){
  339       n_psonce |= n_PSO_TTYIN;
  340 #if defined HAVE_MLE || defined HAVE_TERMCAP
  341       if((n_tty_fp = fdopen(fileno(n_stdin), "w")) != NULL)
  342          setvbuf(n_tty_fp, NULL, _IOLBF, 0);
  343 #endif
  344    }
  345    if(isatty(STDOUT_FILENO))
  346       n_psonce |= n_PSO_TTYOUT;
  347    if((n_psonce & (n_PSO_TTYIN | n_PSO_TTYOUT)) ==
  348          (n_PSO_TTYIN | n_PSO_TTYOUT)){
  349       n_psonce |= n_PSO_INTERACTIVE;
  350       safe_signal(SIGPIPE, dflpipe = SIG_IGN);
  351    }
  352 
  353    /* STDOUT is always line buffered from our point of view */
  354    setvbuf(n_stdout, NULL, _IOLBF, 0);
  355    if(n_tty_fp == NULL)
  356       n_tty_fp = n_stdout;
  357 
  358    /*  --  >8  --  8<  --  */
  359 
  360    /* We need the endianess, runtime detected due to OPT_CROSS_BUILD */
  361    /* C99 */{
  362       union {ui16_t bom; ui8_t buf[2];} volatile u;
  363 
  364       u.bom = 0xFEFFu;
  365       if(u.buf[1] != 0xFEu)
  366          n_psonce |= n_PSO_BIG_ENDIAN;
  367    }
  368 
  369    n_locale_init();
  370 
  371 #ifdef HAVE_ICONV
  372    iconvd = (iconv_t)-1;
  373 #endif
  374 
  375    /* Ensure some variables get loaded and/or verified */
  376 
  377    (void)ok_blook(POSIXLY_CORRECT);
  378    NYD2_LEAVE;
  379 }
  380 
  381 static size_t
  382 a_main_grow_cpp(char const ***cpp, size_t newsize, size_t oldcnt){
  383    /* Just use auto-reclaimed storage, it will be preserved */
  384    char const **newcpp;
  385    NYD2_ENTER;
  386 
  387    newcpp = n_autorec_alloc(sizeof(char*) * (newsize + 1));
  388 
  389    if(oldcnt > 0)
  390       memcpy(newcpp, *cpp, oldcnt * sizeof(char*));
  391    *cpp = newcpp;
  392    NYD2_LEAVE;
  393    return newsize;
  394 }
  395 
  396 static void
  397 a_main_setup_vars(void){
  398    struct passwd *pwuid;
  399    char const *cp;
  400    NYD2_ENTER;
  401 
  402    /* Detect, verify and fixate our invoking user (environment) */
  403    n_group_id = getgid();
  404    if((pwuid = getpwuid(n_user_id = getuid())) == NULL)
  405       n_panic(_("Cannot associate a name with uid %lu"), (ul_i)n_user_id);
  406    else{
  407       char const *ep;
  408       bool_t doenv;
  409 
  410       if(!(doenv = (ep = ok_vlook(LOGNAME)) == NULL) &&
  411             (doenv = (strcmp(pwuid->pw_name, ep) != 0)))
  412          n_err(_("Warning: $LOGNAME (%s) not identical to user (%s)!\n"),
  413             ep, pwuid->pw_name);
  414       if(doenv){
  415          n_pstate |= n_PS_ROOT;
  416          ok_vset(LOGNAME, pwuid->pw_name);
  417          n_pstate &= ~n_PS_ROOT;
  418       }
  419 
  420       /* BSD compat */
  421       if((ep = ok_vlook(USER)) != NULL && strcmp(pwuid->pw_name, ep)){
  422          n_err(_("Warning: $USER (%s) not identical to user (%s)!\n"),
  423             ep, pwuid->pw_name);
  424          n_pstate |= n_PS_ROOT;
  425          ok_vset(USER, pwuid->pw_name);
  426          n_pstate &= ~n_PS_ROOT;
  427       }
  428 
  429       /* XXX myfullname = pw->pw_gecos[OPTIONAL!] -> GUT THAT; TODO pw_shell */
  430    }
  431 
  432    /* Ensure some variables get loaded and/or verified.
  433     * While doing so, take special care for invocations as root */
  434 
  435    /* This is not automatized just as $TMPDIR is for the initial setting, since
  436     * we have the pwuid at hand and can simply use it!  See accmacvar.c! */
  437    if(n_user_id == 0 || (cp = ok_vlook(HOME)) == NULL){
  438       cp = pwuid->pw_dir;
  439       n_pstate |= n_PS_ROOT;
  440       ok_vset(HOME, cp);
  441       n_pstate &= ~n_PS_ROOT;
  442    }
  443 
  444    /* Do not honour TMPDIR if root */
  445    if(n_user_id == 0)
  446       ok_vset(TMPDIR, NULL);
  447    else
  448       (void)ok_vlook(TMPDIR);
  449 
  450    /* Are we in a reproducible-builds.org environment?
  451     * That special mode bends some settings (again) */
  452    if(ok_vlook(SOURCE_DATE_EPOCH) != NULL){
  453       n_psonce |= n_PSO_REPRODUCIBLE;
  454       n_pstate |= n_PS_ROOT;
  455       n_progname = n_reproducible_name;
  456       ok_vset(LOGNAME, n_reproducible_name);
  457       /* Do not care about USER at all in this special mode! */
  458       n_pstate &= ~n_PS_ROOT;
  459       cp = savecat(n_reproducible_name, ": ");
  460       ok_vset(log_prefix, cp);
  461    }
  462 
  463    if((n_psonce & n_PSO_INTERACTIVE) ||
  464          ((n_psonce & (n_PSO_TTYIN | n_PSO_TTYOUT)) &&
  465           (n_poption & n_PO_BATCH_FLAG))){
  466       a_main_setscreensize(FAL0);
  467       if(n_psonce & n_PSO_INTERACTIVE){
  468          /* XXX Yet WINCH after SIGWINCH/SIGCONT, but see POSIX TOSTOP flag */
  469 #ifdef SIGWINCH
  470 # ifndef TTY_WANTS_SIGWINCH
  471          if(safe_signal(SIGWINCH, SIG_IGN) != SIG_IGN)
  472 # endif
  473             safe_signal(SIGWINCH, &a_main_setscreensize);
  474 #endif
  475 #ifdef SIGCONT
  476          safe_signal(SIGCONT, &a_main_setscreensize);
  477 #endif
  478       }
  479    }else
  480       n_scrnheight = n_realscreenheight = 24, n_scrnwidth = 80;
  481    NYD2_LEAVE;
  482 }
  483 
  484 static void
  485 a_main_setscreensize(int is_sighdl){/* TODO globl policy; int wraps; minvals! */
  486    struct termios tbuf;
  487 #if defined HAVE_TCGETWINSIZE || defined TIOCGWINSZ
  488    struct winsize ws;
  489 #elif defined TIOCGSIZE
  490    struct ttysize ts;
  491 #endif
  492    NYD2_ENTER;
  493 
  494    n_scrnheight = n_realscreenheight = n_scrnwidth = 0;
  495 
  496    /* (Also) POSIX: LINES and COLUMNS always override.  Adjust this
  497     * a little bit to be able to honour resizes during our lifetime and
  498     * only honour it upon first run; abuse *is_sighdl* as an indicator */
  499    if(!is_sighdl){
  500       char const *cp;
  501 
  502       if((cp = ok_vlook(LINES)) != NULL){
  503          n_idec_ui32_cp(&n_scrnheight, cp, 0, NULL);
  504          n_realscreenheight = n_scrnheight;
  505       }
  506       if((cp = ok_vlook(COLUMNS)) != NULL)
  507          n_idec_ui32_cp(&n_scrnwidth, cp, 0, NULL);
  508 
  509       if(n_scrnwidth != 0 && n_scrnheight != 0)
  510          goto jleave;
  511 
  512       /* For batch mode without explicit request, stop now */
  513       if(!(n_psonce & n_PSO_INTERACTIVE)){
  514          n_scrnheight = n_realscreenheight = 24;
  515          n_scrnwidth = 80;
  516          goto jleave;
  517       }
  518    }
  519 
  520 #ifdef HAVE_TCGETWINSIZE
  521    if(tcgetwinsize(fileno(n_tty_fp), &ws) == -1)
  522       ws.ws_col = ws.ws_row = 0;
  523 #elif defined TIOCGWINSZ
  524    if(ioctl(fileno(n_tty_fp), TIOCGWINSZ, &ws) == -1)
  525       ws.ws_col = ws.ws_row = 0;
  526 #elif defined TIOCGSIZE
  527    if(ioctl(fileno(n_tty_fp), TIOCGSIZE, &ws) == -1)
  528       ts.ts_lines = ts.ts_cols = 0;
  529 #endif
  530 
  531    if(n_scrnheight == 0){
  532 #if defined HAVE_TCGETWINSIZE || defined TIOCGWINSZ
  533       if(ws.ws_row != 0)
  534          n_scrnheight = ws.ws_row;
  535 #elif defined TIOCGSIZE
  536       if(ts.ts_lines != 0)
  537          n_scrnheight = ts.ts_lines;
  538 #endif
  539       else{
  540          speed_t ospeed;
  541 
  542          ospeed = ((tcgetattr(fileno(n_tty_fp), &tbuf) == -1)
  543                ? B9600 : cfgetospeed(&tbuf));
  544 
  545          if(ospeed < B1200)
  546             n_scrnheight = 9;
  547          else if(ospeed == B1200)
  548             n_scrnheight = 14;
  549          else
  550             n_scrnheight = 24;
  551       }
  552 
  553 #if defined HAVE_TCGETWINSIZE || defined TIOCGWINSZ || defined TIOCGSIZE
  554       if(0 ==
  555 # if defined HAVE_TCGETWINSIZE || defined TIOCGWINSZ
  556             (n_realscreenheight = ws.ws_row)
  557 # else
  558             (n_realscreenheight = ts.ts_lines)
  559 # endif
  560       )
  561          n_realscreenheight = 24;
  562 #endif
  563    }
  564 
  565    if(n_scrnwidth == 0 && 0 ==
  566 #if defined HAVE_TCGETWINSIZE || defined TIOCGWINSZ
  567          (n_scrnwidth = ws.ws_col)
  568 #elif defined TIOCGSIZE
  569          (n_scrnwidth = ts.ts_cols)
  570 #endif
  571    )
  572       n_scrnwidth = 80;
  573 
  574    /**/
  575    n_pstate |= n_PS_SIGWINCH_PEND;
  576 jleave:
  577    NYD2_LEAVE;
  578 }
  579 
  580 static sigjmp_buf a_main__hdrjmp; /* XXX */
  581 
  582 static int
  583 a_main_rcv_mode(bool_t had_A_arg, char const *folder, char const *Larg){
  584    sighandler_type prevint;
  585    int i;
  586    NYD_ENTER;
  587 
  588    i = had_A_arg ? FEDIT_ACCOUNT : FEDIT_NONE;
  589    if(n_poption & n_PO_QUICKRUN_MASK)
  590       i |= FEDIT_RDONLY;
  591 
  592    if(folder == NULL){
  593       folder = "%";
  594       if(had_A_arg)
  595          i |= FEDIT_SYSBOX;
  596    }
  597 #ifdef HAVE_IMAP
  598    else if(*folder == '@'){
  599       /* This must be treated specially to make possible invocation like
  600        * -A imap -f @mailbox */
  601       char const *cp;
  602 
  603       cp = n_folder_query();
  604       if(which_protocol(cp, FAL0, FAL0, NULL) == PROTO_IMAP)
  605          n_strscpy(mailname, cp, sizeof mailname);
  606    }
  607 #endif
  608 
  609    i = setfile(folder, i);
  610    if(i < 0){
  611       n_exit_status = n_EXIT_ERR; /* error already reported */
  612       goto jquit;
  613    }
  614    temporary_folder_hook_check(FAL0);
  615    if(n_poption & n_PO_QUICKRUN_MASK){
  616       n_exit_status = i;
  617       if(i == n_EXIT_OK && (!(n_poption & n_PO_EXISTONLY) ||
  618             (n_poption & n_PO_HEADERLIST)))
  619          print_header_summary(Larg);
  620       goto jquit;
  621    }
  622 
  623    if(i > 0 && !ok_blook(emptystart)){
  624       n_exit_status = n_EXIT_ERR;
  625       goto jleave;
  626    }
  627 
  628    if(sigsetjmp(a_main__hdrjmp, 1) == 0){
  629       if((prevint = safe_signal(SIGINT, SIG_IGN)) != SIG_IGN)
  630          safe_signal(SIGINT, &a_main_hdrstop);
  631       if(!ok_blook(quiet))
  632          fprintf(n_stdout, _("%s version %s.  Type `?' for help\n"),
  633             n_uagent,
  634             (n_psonce & n_PSO_REPRODUCIBLE
  635                ? n_reproducible_name : ok_vlook(version)));
  636       n_folder_announce(n_ANNOUNCE_MAIN_CALL | n_ANNOUNCE_CHANGE);
  637       safe_signal(SIGINT, prevint);
  638    }
  639 
  640    /* Enter the command loop */
  641    if(n_psonce & n_PSO_INTERACTIVE)
  642       n_tty_init();
  643    n_go_main_loop();
  644    if(n_psonce & n_PSO_INTERACTIVE)
  645       n_tty_destroy((n_psonce & n_PSO_XIT) != 0);
  646 
  647    if(!(n_psonce & n_PSO_XIT)){
  648       if(mb.mb_type == MB_FILE || mb.mb_type == MB_MAILDIR){
  649          safe_signal(SIGHUP, SIG_IGN);
  650          safe_signal(SIGINT, SIG_IGN);
  651          safe_signal(SIGQUIT, SIG_IGN);
  652       }
  653 jquit:
  654       save_mbox_for_possible_quitstuff();
  655       quit(FAL0);
  656    }
  657 jleave:
  658    NYD_LEAVE;
  659    return n_exit_status;
  660 }
  661 
  662 static void
  663 a_main_hdrstop(int signo){
  664    NYD_X; /* Signal handler */
  665    n_UNUSED(signo);
  666 
  667    fflush(n_stdout);
  668    n_err_sighdl(_("\nInterrupt\n"));
  669    siglongjmp(a_main__hdrjmp, 1);
  670 }
  671 
  672 int
  673 main(int argc, char *argv[]){
  674    /* TODO Once v15 control flow/carrier rewrite took place main() should
  675     * TODO be rewritten and option parsing++ should be outsourced.
  676     * TODO Like so we can get rid of some stack locals etc. */
  677    /* Keep in SYNC: ./nail.1:"SYNOPSIS, main() */
  678    static char const optstr[] =
  679          "A:a:Bb:C:c:DdEeFfHhiL:M:m:NnO:q:Rr:S:s:tu:VvX:::~#.";
  680    int i;
  681    char *cp;
  682    enum{
  683       a_RF_NONE = 0,
  684       a_RF_SET = 1<<0,
  685       a_RF_SYSTEM = 1<<1,
  686       a_RF_USER = 1<<2,
  687       a_RF_ALL = a_RF_SYSTEM | a_RF_USER
  688    } resfiles;
  689    size_t Xargs_size, Xargs_cnt, smopts_size;
  690    char const *Aarg, *emsg, *folder, *Larg, *okey, *qf,
  691       *subject, *uarg, **Xargs;
  692    struct attachment *attach;
  693    struct name *to, *cc, *bcc;
  694    struct a_arg *a_head, *a_curr;
  695    NYD_ENTER;
  696 
  697    a_head = NULL;
  698    n_UNINIT(a_curr, NULL);
  699    to = cc = bcc = NULL;
  700    attach = NULL;
  701    Aarg = emsg = folder = Larg = okey = qf = subject = uarg = NULL;
  702    Xargs = NULL;
  703    Xargs_size = Xargs_cnt = smopts_size = 0;
  704    resfiles = a_RF_ALL;
  705 
  706    /*
  707     * Start our lengthy setup, finalize by setting n_PSO_STARTED
  708     */
  709 
  710    n_progname = argv[0];
  711    a_main_startup();
  712 
  713    /* Command line parsing
  714     * -S variable settings need to be done twice, since the user surely wants
  715     * the setting to take effect immediately, but also doesn't want it to be
  716     * overwritten from within resource files */
  717    while((i = a_main_getopt(argc, argv, optstr)) >= 0){
  718       switch(i){
  719       case 'A':
  720          /* Execute an account command later on */
  721          Aarg = a_main_oarg;
  722          break;
  723       case 'a':{
  724          /* Add an attachment */
  725          struct a_arg *nap;
  726 
  727          n_psonce |= n_PSO_SENDMODE;
  728          nap = n_autorec_alloc(sizeof(struct a_arg));
  729          if(a_head == NULL)
  730             a_head = nap;
  731          else
  732             a_curr->aa_next = nap;
  733          nap->aa_next = NULL;
  734          nap->aa_file = a_main_oarg;
  735          a_curr = nap;
  736          }break;
  737       case 'B':
  738          n_OBSOLETE(_("-B is obsolete, please use -# as necessary"));
  739          break;
  740       case 'b':
  741          /* Add (a) blind carbon copy recipient (list) */
  742          n_psonce |= n_PSO_SENDMODE;
  743          bcc = cat(bcc, lextract(a_main_oarg,
  744                GBCC | GFULL | GSHEXP_PARSE_HACK));
  745          break;
  746       case 'C':{
  747          /* Create custom header (at list tail) */
  748          struct n_header_field **hflpp;
  749 
  750          if(*(hflpp = &n_poption_arg_C) != NULL){
  751             while((*hflpp)->hf_next != NULL)
  752                *hflpp = (*hflpp)->hf_next;
  753             hflpp = &(*hflpp)->hf_next;
  754          }
  755          if(!n_header_add_custom(hflpp, a_main_oarg, FAL0)){
  756             emsg = N_("Invalid custom header data with -C");
  757             goto jusage;
  758          }
  759          }break;
  760       case 'c':
  761          /* Add (a) carbon copy recipient (list) */
  762          n_psonce |= n_PSO_SENDMODE;
  763          cc = cat(cc, lextract(a_main_oarg, GCC | GFULL | GSHEXP_PARSE_HACK));
  764          break;
  765       case 'D':
  766 #ifdef HAVE_IMAP
  767          ok_bset(disconnected);
  768 #endif
  769          break;
  770       case 'd':
  771          ok_bset(debug);
  772          break;
  773       case 'E':
  774          ok_bset(skipemptybody);
  775          break;
  776       case 'e':
  777          /* Check if mail (matching -L) exists in given box, exit status */
  778          n_poption |= n_PO_EXISTONLY;
  779          break;
  780       case 'F':
  781          /* Save msg in file named after local part of first recipient */
  782          n_poption |= n_PO_F_FLAG;
  783          n_psonce |= n_PSO_SENDMODE;
  784          break;
  785       case 'f':
  786          /* User is specifying file to "edit" with Mail, as opposed to reading
  787           * system mailbox.  If no argument is given, we read his mbox file.
  788           * Check for remaining arguments later */
  789          folder = "&";
  790          break;
  791       case 'H':
  792          /* Display summary of headers, exit */
  793          n_poption |= n_PO_HEADERSONLY;
  794          break;
  795       case 'h':
  796          a_main_usage(n_stdout);
  797          goto j_leave;
  798       case 'i':
  799          /* Ignore interrupts */
  800          ok_bset(ignore);
  801          break;
  802       case 'L':
  803          /* Display summary of headers which match given spec, exit.
  804           * In conjunction with -e, only test the given spec for existence */
  805          Larg = a_main_oarg;
  806          n_poption |= n_PO_HEADERLIST;
  807          if(*Larg == '"' || *Larg == '\''){ /* TODO list.c:listspec_check() */
  808             size_t j;
  809 
  810             j = strlen(++Larg);
  811             if(j > 0){
  812                cp = savestrbuf(Larg, --j);
  813                Larg = cp;
  814             }
  815          }
  816          break;
  817       case 'M':
  818          /* Flag message body (standard input) with given MIME type */
  819          if(qf != NULL && (!(n_poption & n_PO_Mm_FLAG) || qf != (char*)-1))
  820             goto jeMmq;
  821          n_poption_arg_Mm = a_main_oarg;
  822          qf = (char*)-1;
  823          if(0){
  824             /* FALLTHRU*/
  825       case 'm':
  826             /* Flag the given file with MIME type and use as message body */
  827             if(qf != NULL && (!(n_poption & n_PO_Mm_FLAG) || qf == (char*)-1))
  828                goto jeMmq;
  829             qf = a_main_oarg;
  830          }
  831          n_poption |= n_PO_Mm_FLAG;
  832          n_psonce |= n_PSO_SENDMODE;
  833          break;
  834       case 'N':
  835          /* Avoid initial header printing */
  836          ok_bclear(header);
  837          break;
  838       case 'n':
  839          /* Don't source "unspecified system start-up file" */
  840          if(resfiles & a_RF_SET){
  841             emsg = N_("-n cannot be used in conjunction with -:");
  842             goto jusage;
  843          }
  844          resfiles = a_RF_USER;
  845          break;
  846       case 'O':
  847          /* Additional options to pass-through to MTA TODO v15-compat legacy */
  848          if(n_smopts_cnt == smopts_size)
  849             smopts_size = a_main_grow_cpp(&n_smopts, smopts_size + 8,
  850                   n_smopts_cnt);
  851          n_smopts[n_smopts_cnt++] = a_main_oarg;
  852          break;
  853       case 'q':
  854          /* "Quote" file: use as message body (-t without headers etc.) */
  855          /* XXX Traditional.  Add -Q to initialize as *quote*d content? */
  856          if(qf != NULL && (n_poption & n_PO_Mm_FLAG)){
  857 jeMmq:
  858             emsg = N_("Only one of -M, -m or -q may be given");
  859             goto jusage;
  860          }
  861          n_psonce |= n_PSO_SENDMODE;
  862          /* Allow for now, we have to special check validity of -q- later on! */
  863          qf = (a_main_oarg[0] == '-' && a_main_oarg[1] == '\0')
  864                ? (char*)-1 : a_main_oarg;
  865          break;
  866       case 'R':
  867          /* Open folders read-only */
  868          n_poption |= n_PO_R_FLAG;
  869          break;
  870       case 'r':
  871          /* Set From address. */
  872          n_poption |= n_PO_r_FLAG;
  873          if(a_main_oarg[0] == '\0')
  874             break;
  875          else{
  876             struct name *fa;
  877 
  878             fa = nalloc(a_main_oarg, GSKIN | GFULL | GFULLEXTRA);
  879             if(is_addr_invalid(fa, EACM_STRICT | EACM_NOLOG)){
  880                emsg = N_("Invalid address argument with -r");
  881                goto jusage;
  882             }
  883             n_poption_arg_r = fa;
  884             /* TODO -r options is set in n_smopts, but may
  885              * TODO be overwritten by setting from= in
  886              * TODO an interactive session!
  887              * TODO Maybe disable setting of from?
  888              * TODO Warn user?  Update manual!! */
  889             a_main_oarg = savecat("from=", fa->n_fullname);
  890          }
  891          /* FALLTHRU */
  892       case 'S':
  893          {  struct str sin;
  894             struct n_string s, *sp;
  895             char const *a[2];
  896             bool_t b;
  897 
  898             if(!ok_blook(v15_compat)){
  899                okey = a[0] = a_main_oarg;
  900                sp = NULL;
  901             }else{
  902                enum n_shexp_state shs;
  903 
  904                n_autorec_relax_create();
  905                sp = n_string_creat_auto(&s);
  906                sin.s = n_UNCONST(a_main_oarg);
  907                sin.l = UIZ_MAX;
  908                shs = n_shexp_parse_token((n_SHEXP_PARSE_LOG |
  909                      n_SHEXP_PARSE_IGNORE_EMPTY |
  910                      n_SHEXP_PARSE_QUOTE_AUTO_FIXED |
  911                      n_SHEXP_PARSE_QUOTE_AUTO_DSQ), sp, &sin, NULL);
  912                if((shs & n_SHEXP_STATE_ERR_MASK) ||
  913                      !(shs & n_SHEXP_STATE_STOP)){
  914                   n_autorec_relax_gut();
  915                   goto je_S;
  916                }
  917                okey = a[0] = n_string_cp_const(sp);
  918             }
  919 
  920             a[1] = NULL;
  921             n_poption |= n_PO_S_FLAG_TEMPORARY;
  922             n_pstate |= n_PS_ROBOT;
  923             b = (c_set(a) == 0);
  924             n_pstate &= ~n_PS_ROBOT;
  925             n_poption &= ~n_PO_S_FLAG_TEMPORARY;
  926 
  927             if(sp != NULL)
  928                n_autorec_relax_gut();
  929             if(!b && (ok_blook(errexit) || ok_blook(posix))){
  930 je_S:
  931                emsg = N_("-S failed to set variable");
  932                goto jusage;
  933             }
  934          }
  935          break;
  936       case 's':
  937          /* Subject:; take care for Debian #419840 and strip any \r and \n */
  938          if(n_anyof_cp("\n\r", subject = a_main_oarg)){
  939             n_err(_("-s: normalizing away invalid ASCII NL / CR bytes\n"));
  940             for(subject = cp = savestr(a_main_oarg); *cp != '\0'; ++cp)
  941                if(*cp == '\n' || *cp == '\r')
  942                   *cp = ' ';
  943          }
  944          n_psonce |= n_PSO_SENDMODE;
  945          break;
  946       case 't':
  947          /* Use the given message as send template */
  948          n_poption |= n_PO_t_FLAG;
  949          n_psonce |= n_PSO_SENDMODE;
  950          break;
  951       case 'u':
  952          /* Open primary mailbox of the given user */
  953          uarg = savecat("%", a_main_oarg);
  954          break;
  955       case 'V':
  956          fprintf(n_stdout, _("%s version %s\n"), n_uagent, ok_vlook(version));
  957          n_exit_status = n_EXIT_OK;
  958          goto j_leave;
  959       case 'v':
  960          /* Be verbose */
  961          ok_bset(verbose);
  962          break;
  963       case 'X':
  964          /* Add to list of commands to exec before entering normal operation */
  965          if(Xargs_cnt == Xargs_size)
  966             Xargs_size = a_main_grow_cpp(&Xargs, Xargs_size + 8, Xargs_cnt);
  967          Xargs[Xargs_cnt++] = a_main_oarg;
  968          break;
  969       case ':':
  970          /* Control which resource files shall be loaded */
  971          if(!(resfiles & (a_RF_SET | a_RF_SYSTEM))){
  972             emsg = N_("-n cannot be used in conjunction with -:");
  973             goto jusage;
  974          }
  975          resfiles = a_RF_SET;
  976          while((i = *a_main_oarg++) != '\0')
  977             switch(i){
  978             case 'S': case 's': resfiles |= a_RF_SYSTEM; break;
  979             case 'U': case 'u': resfiles |= a_RF_USER; break;
  980             case ':': case '/': resfiles &= ~a_RF_ALL; break;
  981             default:
  982                emsg = N_("Invalid argument of -:");
  983                goto jusage;
  984             }
  985          break;
  986       case '~':
  987          /* Enable command escapes even in non-interactive mode */
  988          n_poption |= n_PO_TILDE_FLAG;
  989          break;
  990       case '#':
  991          /* Work in batch mode, even if non-interactive */
  992          if(!(n_psonce & n_PSO_INTERACTIVE))
  993             setvbuf(n_stdin, NULL, _IOLBF, 0);
  994          n_poption |= n_PO_TILDE_FLAG | n_PO_BATCH_FLAG;
  995          folder = n_path_devnull;
  996          n_pstate |= n_PS_ROBOT; /* (be silent unsetting undefined variables) */
  997          ok_vset(MAIL, folder);
  998          ok_vset(MBOX, folder);
  999          ok_bset(emptystart);
 1000          ok_bclear(errexit);
 1001          ok_bclear(header);
 1002          ok_vset(inbox, folder);
 1003          ok_bclear(posix);
 1004          ok_bset(quiet);
 1005          ok_bset(sendwait);
 1006          ok_bset(typescript_mode);
 1007          n_pstate &= ~n_PS_ROBOT;
 1008          break;
 1009       case '.':
 1010          /* Enforce send mode */
 1011          n_psonce |= n_PSO_SENDMODE;
 1012          goto jgetopt_done;
 1013       case '?':
 1014 jusage:
 1015          if(emsg != NULL)
 1016             n_err("%s\n", V_(emsg));
 1017          a_main_usage(n_stderr);
 1018          n_exit_status = n_EXIT_USE;
 1019          goto j_leave;
 1020       }
 1021    }
 1022 jgetopt_done:
 1023    ;
 1024 
 1025    /* The normal arguments may be followed by MTA arguments after a "--";
 1026     * however, -f may take off an argument, too, and before that.
 1027     * Since MTA arguments after "--" require *expandargv*, delay parsing off
 1028     * those options until after the resource files are loaded... */
 1029    if((cp = argv[i = a_main_oind]) == NULL)
 1030       ;
 1031    else if(cp[0] == '-' && cp[1] == '-' && cp[2] == '\0')
 1032       ++i;
 1033    /* n_PO_BATCH_FLAG sets to /dev/null, but -f can still be used and sets & */
 1034    else if(folder != NULL && /*folder[0] == '&' &&*/ folder[1] == '\0'){
 1035       folder = cp;
 1036       if((cp = argv[++i]) != NULL){
 1037          if(cp[0] != '-' || cp[1] != '-' || cp[2] != '\0'){
 1038             emsg = N_("More than one file given with -f");
 1039             goto jusage;
 1040          }
 1041          ++i;
 1042       }
 1043    }else{
 1044       n_psonce |= n_PSO_SENDMODE;
 1045       for(;;){
 1046          to = cat(to, lextract(cp, GTO | GFULL | GSHEXP_PARSE_HACK));
 1047          if((cp = argv[++i]) == NULL)
 1048             break;
 1049          if(cp[0] == '-' && cp[1] == '-' && cp[2] == '\0'){
 1050             ++i;
 1051             break;
 1052          }
 1053       }
 1054    }
 1055    a_main_oind = i;
 1056 
 1057    /* ...BUT, since we use n_autorec_alloc() for the MTA n_smopts storage we
 1058     * need to allocate the space for them before we fixate that storage! */
 1059    while(argv[i] != NULL)
 1060       ++i;
 1061    if(n_smopts_cnt + i > smopts_size)
 1062       DBG(smopts_size =)
 1063       a_main_grow_cpp(&n_smopts, n_smopts_cnt + i + 1, n_smopts_cnt);
 1064 
 1065    /* Check for inconsistent arguments, fix some temporaries */
 1066    if(n_psonce & n_PSO_SENDMODE){
 1067       /* XXX This is only because BATCH_FLAG sets *folder*=/dev/null
 1068        * XXX in order to function.  Ideally that would not be needed */
 1069       if(folder != NULL && !(n_poption & n_PO_BATCH_FLAG)){
 1070          emsg = N_("Cannot give -f and people to send to.");
 1071          goto jusage;
 1072       }
 1073       if(uarg != NULL){
 1074          emsg = N_("The -u option cannot be used in send mode");
 1075          goto jusage;
 1076       }
 1077       if(!(n_poption & n_PO_t_FLAG) && to == NULL){
 1078          emsg = N_("Send options without primary recipient specified.");
 1079          goto jusage;
 1080       }
 1081       if((n_poption & n_PO_t_FLAG) && qf != NULL){
 1082          emsg = N_("The -M, -m, -q and -t options are mutual exclusive.");
 1083          goto jusage;
 1084       }
 1085       if(n_poption & (n_PO_EXISTONLY | n_PO_HEADERSONLY | n_PO_HEADERLIST)){
 1086          emsg = N_("The -e, -H and -L options cannot be used in send mode.");
 1087          goto jusage;
 1088       }
 1089       if(n_poption & n_PO_R_FLAG){
 1090          emsg = N_("The -R option is meaningless in send mode.");
 1091          goto jusage;
 1092       }
 1093 
 1094       if(n_psonce & n_PSO_INTERACTIVE){
 1095          if(qf == (char*)-1){
 1096             if(!(n_poption & n_PO_Mm_FLAG))
 1097                emsg = N_("-q can't use standard input when interactive.\n");
 1098             goto jusage;
 1099          }
 1100       }
 1101    }else{
 1102       if(uarg != NULL && folder != NULL){
 1103          emsg = N_("The options -u and -f (and -#) are mutually exclusive");
 1104          goto jusage;
 1105       }
 1106       if((n_poption & (n_PO_EXISTONLY | n_PO_HEADERSONLY)) ==
 1107             (n_PO_EXISTONLY | n_PO_HEADERSONLY)){
 1108          emsg = N_("The options -e and -H are mutual exclusive");
 1109          goto jusage;
 1110       }
 1111       if((n_poption & (n_PO_HEADERSONLY | n_PO_HEADERLIST) /* TODO OBSOLETE */
 1112             ) == (n_PO_HEADERSONLY | n_PO_HEADERLIST))
 1113          n_OBSOLETE(_("please use \"-e -L xy\" instead of \"-H -L xy\""));
 1114 
 1115       if(uarg != NULL)
 1116          folder = uarg;
 1117    }
 1118 
 1119    /*
 1120     * We have reached our second program state, the command line options have
 1121     * been worked and verified a bit, we are likely to go, perform more setup
 1122     */
 1123    n_psonce |= n_PSO_STARTED_GETOPT;
 1124 
 1125    a_main_setup_vars();
 1126 
 1127    /* Create memory pool snapshot; Memory is auto-reclaimed from now on */
 1128    n_memory_pool_fixate();
 1129 
 1130    /* load() any resource files */
 1131    if(resfiles & a_RF_ALL){
 1132       /* *expand() returns a savestr(), but load() only uses the file name
 1133        * for fopen(), so it is safe to do this */
 1134       if(resfiles & a_RF_SYSTEM){
 1135          bool_t nload;
 1136 
 1137          if((nload = ok_blook(NAIL_NO_SYSTEM_RC)))
 1138             n_OBSOLETE(_("Please use $MAILX_NO_SYSTEM_RC instead of "
 1139                "$NAIL_NO_SYSTEM_RC"));
 1140          if(!nload && !ok_blook(MAILX_NO_SYSTEM_RC) &&
 1141                !n_go_load(ok_vlook(system_mailrc)))
 1142             goto j_leave;
 1143       }
 1144 
 1145       if((resfiles & a_RF_USER) &&
 1146             !n_go_load(fexpand(ok_vlook(MAILRC), FEXP_LOCAL | FEXP_NOPROTO)))
 1147          goto j_leave;
 1148 
 1149       if((cp = ok_vlook(NAIL_EXTRA_RC)) != NULL)
 1150          n_OBSOLETE(_("Please use *mailx-extra-rc*, not *NAIL_EXTRA_RC*"));
 1151       if((cp != NULL || (cp = ok_vlook(mailx_extra_rc)) != NULL) &&
 1152             !n_go_load(fexpand(cp, FEXP_LOCAL | FEXP_NOPROTO)))
 1153          goto j_leave;
 1154    }
 1155 
 1156    /* Cause possible umask(2) to be applied, now that any setting is
 1157     * established, and before we change accounts, evaluate commands etc. */
 1158    (void)ok_vlook(umask);
 1159 
 1160    /* Additional options to pass-through to MTA, and allowed to do so? */
 1161    i = a_main_oind;
 1162    if((cp = ok_vlook(expandargv)) != NULL){
 1163       bool_t isfail, isrestrict;
 1164 
 1165       isfail = !asccasecmp(cp, "fail");
 1166       isrestrict = (!isfail && !asccasecmp(cp, "restrict"));
 1167 
 1168       if((n_poption & n_PO_D_V) && !isfail && !isrestrict && *cp != '\0')
 1169          n_err(_("Unknown *expandargv* value: %s\n"), cp);
 1170 
 1171       if((cp = argv[i]) != NULL){
 1172          if(isfail || (isrestrict && (!(n_poption & n_PO_TILDE_FLAG) ||
 1173                   !(n_psonce & n_PSO_INTERACTIVE)))){
 1174 je_expandargv:
 1175             n_err(_("*expandargv* doesn't allow MTA arguments; consider "
 1176                "using *mta-arguments*\n"));
 1177             n_exit_status = n_EXIT_USE | n_EXIT_SEND_ERROR;
 1178             goto jleave;
 1179          }
 1180          do{
 1181             assert(n_smopts_cnt + 1 <= smopts_size);
 1182             n_smopts[n_smopts_cnt++] = cp;
 1183          }while((cp = argv[++i]) != NULL);
 1184       }
 1185    }else if(argv[i] != NULL)
 1186       goto je_expandargv;
 1187 
 1188    /* We had to wait until the resource files are loaded and any command line
 1189     * setting has been restored, but get the termcap up and going before we
 1190     * switch account or running commands */
 1191 #ifdef n_HAVE_TCAP
 1192    if((n_psonce & n_PSO_INTERACTIVE) && !(n_poption & n_PO_QUICKRUN_MASK))
 1193       n_termcap_init();
 1194 #endif
 1195 
 1196    /* Now we can set the account */
 1197    if(Aarg != NULL){
 1198       char const *a[2];
 1199 
 1200       a[0] = Aarg;
 1201       a[1] = NULL;
 1202       if(c_account(a) && (!(n_psonce & n_PSO_INTERACTIVE) ||
 1203             ok_blook(errexit) || ok_blook(posix))){
 1204          n_exit_status = n_EXIT_USE | n_EXIT_SEND_ERROR;
 1205          goto jleave;
 1206       }
 1207    }
 1208 
 1209    /*
 1210     * Almost setup, only -X commands are missing!
 1211     */
 1212    n_psonce |= n_PSO_STARTED_CONFIG;
 1213 
 1214    /* "load()" commands given on command line */
 1215    if(Xargs_cnt > 0){
 1216       if(!n_go_Xargs(Xargs, Xargs_cnt))
 1217          goto jleave;
 1218    }
 1219 
 1220    /* Final tests */
 1221    if(n_poption & n_PO_Mm_FLAG){
 1222       if(qf == (char*)-1){
 1223          if(!n_mimetype_check_mtname(n_poption_arg_Mm)){
 1224             n_err(_("Could not find `mimetype' for -M argument: %s\n"),
 1225                n_poption_arg_Mm);
 1226             n_exit_status = n_EXIT_ERR;
 1227             goto jleave;
 1228          }
 1229       }else if(/* XXX only to satisfy Coverity! */qf != NULL &&
 1230             (n_poption_arg_Mm = n_mimetype_classify_filename(qf)) == NULL){
 1231          n_err(_("Could not `mimetype'-classify -m argument: %s\n"),
 1232             n_shexp_quote_cp(qf, FAL0));
 1233          n_exit_status = n_EXIT_ERR;
 1234          goto jleave;
 1235       }else if(!asccasecmp(n_poption_arg_Mm, "text/plain")) /* TODO no: magic */
 1236          n_poption_arg_Mm = NULL;
 1237    }
 1238 
 1239    /*
 1240     * We're finally completely setup and ready to go!
 1241     */
 1242    n_psonce |= n_PSO_STARTED;
 1243 
 1244    if(!(n_psonce & n_PSO_SENDMODE))
 1245       n_exit_status = a_main_rcv_mode((Aarg != NULL), folder, Larg);
 1246    else{
 1247       /* Now that full mailx(1)-style file expansion is possible handle the
 1248        * attachments which we had delayed due to this.
 1249        * This may use savestr(), but since we won't enter the command loop we
 1250        * don't need to care about that */
 1251       for(; a_head != NULL; a_head = a_head->aa_next){
 1252          enum n_attach_error aerr;
 1253 
 1254          attach = n_attachment_append(attach, a_head->aa_file, &aerr, NULL);
 1255          if(aerr != n_ATTACH_ERR_NONE){
 1256             n_exit_status = n_EXIT_ERR;
 1257             goto jleave;
 1258          }
 1259       }
 1260 
 1261       if(n_psonce & n_PSO_INTERACTIVE)
 1262          n_tty_init();
 1263       n_mail((n_poption & n_PO_F_FLAG ? n_MAILSEND_RECORD_RECIPIENT : 0),
 1264          to, cc, bcc, subject, attach, qf);
 1265       if(n_psonce & n_PSO_INTERACTIVE)
 1266          n_tty_destroy((n_psonce & n_PSO_XIT) != 0);
 1267    }
 1268 
 1269 jleave:
 1270   /* Be aware of identical code for `exit' command! */
 1271 #ifdef n_HAVE_TCAP
 1272    if((n_psonce & n_PSO_INTERACTIVE) && !(n_poption & n_PO_QUICKRUN_MASK))
 1273       n_termcap_destroy();
 1274 #endif
 1275 
 1276 j_leave:
 1277 #if defined HAVE_MEMORY_DEBUG || defined HAVE_NOMEMDBG
 1278    n_memory_pool_pop(NULL, TRU1);
 1279 #endif
 1280 #if defined HAVE_DEBUG || defined HAVE_DEVEL || defined HAVE_NOMEMDBG
 1281    n_memory_reset();
 1282 #endif
 1283    NYD_LEAVE;
 1284    return n_exit_status;
 1285 }
 1286 
 1287 /* Source the others in that case! */
 1288 #ifdef HAVE_AMALGAMATION
 1289 # include <mk-config.h>
 1290 #endif
 1291 
 1292 /* s-it-mode */