"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.7/main.c" (16 Feb 2018, 41819 Bytes) of package /linux/misc/s-nail-14.9.7.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.6_vs_14.9.7.

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