"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/main.c" (25 Mar 2018, 42039 Bytes) of package /linux/misc/s-nail-14.9.10.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.9_vs_14.9.10.

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