"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.22/include/mx/nail.h" (24 Feb 2021, 61260 Bytes) of package /linux/misc/s-nail-14.9.22.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 "nail.h" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 14.9.21_vs_14.9.22.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Header inclusion, macros, constants, types and the global var declarations.
    3  *@ TODO Should be split in myriads of FEATURE-GROUP.h headers.  Sort.  def.h.
    4  *
    5  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    6  * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    7  * SPDX-License-Identifier: BSD-3-Clause TODO ISC
    8  */
    9 /*
   10  * Copyright (c) 1980, 1993
   11  *      The Regents of the University of California.  All rights reserved.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  */
   37 #ifndef n_NAIL_H
   38 # define n_NAIL_H
   39 
   40 #include <mx/gen-config.h>
   41 
   42 #include <sys/stat.h>
   43 #include <sys/types.h>
   44 
   45 #ifdef mx_HAVE_GETTIMEOFDAY
   46 # include <sys/time.h>
   47 #endif
   48 
   49 #include <errno.h>
   50 #include <fcntl.h>
   51 #include <inttypes.h>
   52 #include <limits.h>
   53 #include <setjmp.h>
   54 #include <signal.h>
   55 #include <stdarg.h>
   56 #include <stdio.h>
   57 #include <stdlib.h>
   58 #include <string.h>
   59 #include <time.h>
   60 #include <unistd.h>
   61 
   62 #ifdef mx_HAVE_REGEX
   63 # include <regex.h>
   64 #endif
   65 
   66 /* Many things possibly of interest for adjustments have been outsourced */
   67 #include <mx/config.h>
   68 
   69 #include <su/code.h>
   70 #include <su/mem-bag.h> /* TODO should not be needed */
   71 
   72 /* TODO fake */
   73 #include "su/code-in.h"
   74 
   75 struct mx_dig_msg_ctx;
   76 struct mx_mimetype_handler;
   77 
   78 /*  */
   79 #define n_FROM_DATEBUF 64 /* Size of RFC 4155 From_ line date */
   80 #define n_DATE_DAYSYEAR 365u
   81 #define n_DATE_NANOSSEC (n_DATE_MICROSSEC * 1000)
   82 #define n_DATE_MICROSSEC (n_DATE_MILLISSEC * 1000)
   83 #define n_DATE_MILLISSEC 1000u
   84 #define n_DATE_SECSMIN 60u
   85 #define n_DATE_MINSHOUR 60u
   86 #define n_DATE_HOURSDAY 24u
   87 #define n_DATE_SECSHOUR (n_DATE_SECSMIN * n_DATE_MINSHOUR)
   88 #define n_DATE_SECSDAY (n_DATE_SECSHOUR * n_DATE_HOURSDAY)
   89 
   90 /* Network protocol newline */
   91 #define NETNL "\015\012"
   92 #define NETLINE(X) X NETNL
   93 
   94 /*
   95  * OS, CC support, generic macros etc. TODO remove -> SU!
   96  */
   97 
   98 /* CC */
   99 
  100 #undef mx_HAVE_NATCH_CHAR
  101 #if defined mx_HAVE_SETLOCALE && defined mx_HAVE_C90AMEND1 && \
  102       defined mx_HAVE_WCWIDTH
  103 # define mx_HAVE_NATCH_CHAR
  104 # define n_NATCH_CHAR(X) X
  105 #else
  106 # define n_NATCH_CHAR(X)
  107 #endif
  108 
  109 #define n_UNCONST(X) su_UNCONST(void*,X) /* TODO */
  110 
  111 /*
  112  * Types
  113  */
  114 
  115 enum n_announce_flags{
  116    n_ANNOUNCE_NONE = 0, /* Only housekeeping */
  117    n_ANNOUNCE_MAIN_CALL = 1u<<0, /* POSIX covered startup call */
  118    n_ANNOUNCE_STATUS = 1u<<1, /* Only print status */
  119    n_ANNOUNCE_CHANGE = 1u<<2, /* Folder changed */
  120 
  121    n__ANNOUNCE_HEADER = 1u<<6,
  122    n__ANNOUNCE_ANY = 1u<<7
  123 };
  124 
  125 enum expand_addr_flags{
  126    EAF_NONE = 0, /* -> EAF_NOFILE | EAF_NOPIPE */
  127    EAF_RESTRICT = 1u<<0, /* "restrict" (do unless interactive / -[~#]) */
  128    EAF_FAIL = 1u<<1, /* "fail" */
  129    EAF_FAILINVADDR = 1u<<2, /* "failinvaddr" */
  130    EAF_DOMAINCHECK = 1u<<3, /* "domaincheck" <-> *expandaddr-domaincheck* */
  131    EAF_NAMETOADDR = 1u<<4, /* "nametoaddr": expand valid name to NAME@HOST */
  132    EAF_SHEXP_PARSE = 1u<<5, /* shexp_parse() the address first is allowed */
  133    /* Bits reused by enum expand_addr_check_mode! */
  134    EAF_FCC = 1u<<8, /* +"fcc" umbrella */
  135    EAF_FILE = 1u<<9, /* +"file" targets */
  136    EAF_PIPE = 1u<<10, /* +"pipe" command pipe targets */
  137    EAF_NAME = 1u<<11, /* +"name"s (non-address) names / MTA aliases */
  138    EAF_ADDR = 1u<<12, /* +"addr" network address (contain "@") */
  139 
  140    EAF_TARGET_MASK = EAF_FCC | EAF_FILE | EAF_PIPE | EAF_NAME | EAF_ADDR,
  141    EAF_RESTRICT_TARGETS = EAF_NAME | EAF_ADDR /* (default set if not set) */
  142    /* TODO HACK!  In pre-v15 we have a control flow problem (it is a general
  143     * TODO design problem): if n_collect() calls makeheader(), e.g., for -t or
  144     * TODO because of ~e diting, then that will checkaddr() and that will
  145     * TODO remove invalid headers.  However, this code path does not know
  146     * TODO about keeping track of senderrors unless a pointer has been passed,
  147     * TODO but which it doesn't for ~e, and shall not, too.  Thus, invalid
  148     * TODO addresses may be automatically removed, silently, and no one will
  149     * TODO ever know, in particular not regarding "failinvaddr".
  150     * TODO The hacky solution is this bit -- which can ONLY be used for fields
  151     * TODO which will be subject to namelist_vaporise_head() later on!! --,
  152     * TODO if it is set (by n_header_extract()) then checkaddr() will NOT strip
  153     * TODO invalid headers off IF it deals with a NULL senderror pointer */
  154    ,EAF_MAYKEEP = 1u<<15
  155 };
  156 
  157 enum expand_addr_check_mode{
  158    EACM_NONE = 0u, /* Don't care about *expandaddr* */
  159    EACM_NORMAL = 1u<<0, /* Use our normal *expandaddr* checking */
  160    EACM_STRICT = 1u<<1, /* Never allow any file or pipe addressee */
  161    EACM_MODE_MASK = 0x3u, /* _NORMAL and _STRICT are mutual! */
  162 
  163    EACM_NOLOG = 1u<<2, /* Do not log check errors */
  164 
  165    /* Some special overwrites of EAF_TARGETs.
  166     * May NOT clash with EAF_* bits which may be ORd to these here! */
  167 
  168    EACM_NONAME = 1u<<16,
  169    EACM_NONAME_OR_FAIL = 1u<<17,
  170    EACM_DOMAINCHECK = 1u<<18 /* Honour it! */
  171 };
  172 
  173 enum conversion{
  174    CONV_NONE, /* no conversion */
  175    CONV_7BIT, /* no conversion, is 7bit */
  176    CONV_FROMQP, /* convert from quoted-printable */
  177    CONV_TOQP, /* convert to quoted-printable */
  178    CONV_8BIT, /* convert to 8bit (iconv) */
  179    CONV_FROMB64, /* convert from base64 */
  180    CONV_FROMB64_T, /* convert from base64/text */
  181    CONV_TOB64, /* convert to base64 */
  182    CONV_FROMHDR, /* convert from RFC1522 format */
  183    CONV_TOHDR, /* convert to RFC1522 format */
  184    CONV_TOHDR_A /* convert addresses for header */
  185 };
  186 
  187 enum cproto{
  188    CPROTO_NONE, /* Invalid.  But sometimes used to be able to parse an URL */
  189 CPROTO_IMAP,
  190    CPROTO_POP3,
  191    CPROTO_SMTP,
  192    CPROTO_CCRED, /* Special dummy credential proto (S/MIME etc.) */
  193    CPROTO_CERTINFO, /* Special dummy proto for TLS certificate info xxx */
  194    CPROTO_SOCKS /* Special dummy SOCKS5 proxy proto */
  195    /* We need a _DEDUCE, as default, for normal URL object */
  196 };
  197 
  198 /* enum n_err_number from gen-config.h, which is in sync with
  199  * su_err_doc(), su_err_name() and su_err_from_name() */
  200 
  201 enum n_exit_status{
  202    n_EXIT_OK = EXIT_SUCCESS,
  203    n_EXIT_ERR = EXIT_FAILURE,
  204    n_EXIT_USE = 64, /* sysexits.h:EX_USAGE */
  205    n_EXIT_NOUSER = 67, /* :EX_NOUSER */
  206    n_EXIT_COLL_ABORT = 1<<1, /* Message collection was aborted */
  207    n_EXIT_SEND_ERROR = 1<<2 /* Unspecified send error occurred */
  208 };
  209 
  210 enum fedit_mode{
  211    FEDIT_NONE = 0,
  212    FEDIT_SYSBOX = 1u<<0, /* %: prefix */
  213    FEDIT_RDONLY = 1u<<1, /* Readonly (per-box, n_OPT_R_FLAG is global) */
  214    FEDIT_NEWMAIL = 1u<<2, /* `newmail' operation TODO OBSOLETE THIS! */
  215    FEDIT_ACCOUNT = 1u<<3 /* setfile() called by `account' */
  216 };
  217 
  218 enum fexp_mode{
  219    FEXP_MOST,
  220    FEXP_NOPROTO = 1u<<0, /* TODO no which_protocol() to decide sh expansion */
  221    FEXP_SILENT = 1u<<1, /* Do not print but only return errors */
  222    FEXP_MULTIOK = 1u<<2, /* Expansion to many entries is ok */
  223    FEXP_LOCAL = 1u<<3, /* Result must be local file/maildir */
  224    FEXP_LOCAL_FILE = 1u<<4, /* ..must be a local file: strips protocol://! */
  225    FEXP_SHORTCUT = 1u<<5, /* Do expand shortcuts */
  226    FEXP_NSPECIAL = 1u<<6, /* No %,#,& specials */
  227    FEXP_NFOLDER = 1u<<7, /* NSPECIAL and no + folder, too */
  228    FEXP_NSHELL = 1u<<8, /* Do not do shell word exp. (but ~/, $VAR) */
  229    FEXP_NVAR = 1u<<9, /* ..not even $VAR expansion */
  230 
  231    /* Actually does expand ~/ etc. */
  232    FEXP_NONE = FEXP_NOPROTO | FEXP_NSPECIAL | FEXP_NFOLDER | FEXP_NVAR,
  233    FEXP_FULL = FEXP_SHORTCUT /* Full expansion */
  234 };
  235 
  236 enum n_go_input_flags{
  237    n_GO_INPUT_NONE,
  238    n_GO_INPUT_CTX_BASE = 0, /* Generic shared base: don't use! */
  239    n_GO_INPUT_CTX_DEFAULT = 1, /* Default input */
  240    n_GO_INPUT_CTX_COMPOSE = 2, /* Compose mode input */
  241    n__GO_INPUT_CTX_MASK = 3,
  242    /* _MASK is not a valid index here, but the lower bits are not misused,
  243     * therefore -- to save space! -- indexing is performed via "& _MASK".
  244     * This is CTA()d!  For actual spacing of arrays we use _MAX1 instead */
  245    n__GO_INPUT_CTX_MAX1 = n_GO_INPUT_CTX_COMPOSE + 1,
  246 
  247    n_GO_INPUT_HOLDALLSIGS = 1u<<8, /* sigs_all_hold() active TODO */
  248    /* `xcall' is `call' (at the level where this is set): to be set when
  249     * teardown of top level has undesired effects, e.g., for `account's and
  250     * folder hooks etc., if we do not want to loose `localopts' unroll list */
  251    n_GO_INPUT_NO_XCALL = 1u<<9,
  252 
  253    n_GO_INPUT_FORCE_STDIN = 1u<<10, /* Even in macro, use stdin (`read')! */
  254    n_GO_INPUT_DELAY_INJECTIONS = 1u<<11, /* Skip go_input_inject()ions */
  255    n_GO_INPUT_NL_ESC = 1u<<12, /* Support "\\$" line continuation */
  256    n_GO_INPUT_NL_FOLLOW = 1u<<13, /* ..on such a follow line */
  257    n_GO_INPUT_PROMPT_NONE = 1u<<14, /* Do not print prompt */
  258    n_GO_INPUT_PROMPT_EVAL = 1u<<15, /* Instead, evaluate *prompt* */
  259 
  260    /* XXX The remains are mostly hacks */
  261 
  262    n_GO_INPUT_HIST_ADD = 1u<<16, /* Add the result to history list */
  263    n_GO_INPUT_HIST_GABBY = 1u<<17, /* Consider history entry as gabby */
  264    /* Command was erroneous; only in combination with _HIST_GABBY! */
  265    n_GO_INPUT_HIST_ERROR = 1u<<18,
  266 
  267    n_GO_INPUT_IGNERR = 1u<<19, /* Imply `ignerr' command modifier */
  268 
  269    n__GO_FREEBIT = 24
  270 };
  271 
  272 enum n_go_input_inject_flags{
  273    n_GO_INPUT_INJECT_NONE = 0,
  274    n_GO_INPUT_INJECT_COMMIT = 1u<<0, /* Auto-commit input */
  275    n_GO_INPUT_INJECT_HISTORY = 1u<<1 /* Allow history addition */
  276 };
  277 
  278 enum n_header_extract_flags{
  279    n_HEADER_EXTRACT_NONE,
  280    n_HEADER_EXTRACT_EXTENDED = 1u<<0,
  281    n_HEADER_EXTRACT_FULL = 2u<<0,
  282    n_HEADER_EXTRACT__MODE_MASK = n_HEADER_EXTRACT_EXTENDED |
  283          n_HEADER_EXTRACT_FULL,
  284 
  285    /* Prefill the receivers with the already existing content of the given
  286     * struct header arguent */
  287    n_HEADER_EXTRACT_PREFILL_RECEIVERS = 1u<<8,
  288    /* Understand and ignore shell-style comments */
  289    n_HEADER_EXTRACT_IGNORE_SHELL_COMMENTS = 1u<<9,
  290    /* Ignore a MBOX From_ line _silently */
  291    n_HEADER_EXTRACT_IGNORE_FROM_ = 1u<<10
  292 };
  293 
  294 /* Special ignore (where _TYPE is covered by POSIX `ignore' / `retain').
  295  * _ALL is very special in that it doesn't have a backing object.
  296  * Go over enum to avoid cascads of (different) CC warnings for used CTA()s */
  297 #define n_IGNORE_ALL ((struct n_ignore*)n__IGNORE_ALL)
  298 #define n_IGNORE_TYPE ((struct n_ignore*)n__IGNORE_TYPE)
  299 #define n_IGNORE_SAVE ((struct n_ignore*)n__IGNORE_SAVE)
  300 #define n_IGNORE_FWD ((struct n_ignore*)n__IGNORE_FWD)
  301 #define n_IGNORE_TOP ((struct n_ignore*)n__IGNORE_TOP)
  302 
  303 enum{
  304    n__IGNORE_ALL = -2,
  305    n__IGNORE_TYPE = -3,
  306    n__IGNORE_SAVE = -4,
  307    n__IGNORE_FWD = -5,
  308    n__IGNORE_TOP = -6,
  309    n__IGNORE_ADJUST = 3,
  310    n__IGNORE_MAX = 6 - n__IGNORE_ADJUST
  311 };
  312 
  313 enum n_mailsend_flags{
  314    n_MAILSEND_NONE,
  315    n_MAILSEND_IS_FWD = 1u<<0,
  316    n_MAILSEND_HEADERS_PRINT = 1u<<2,
  317    n_MAILSEND_RECORD_RECIPIENT = 1u<<3,
  318    n_MAILSEND_ALTERNATES_NOSTRIP = 1u<<4,
  319 
  320    n_MAILSEND_ALL = n_MAILSEND_IS_FWD | n_MAILSEND_HEADERS_PRINT |
  321          n_MAILSEND_RECORD_RECIPIENT | n_MAILSEND_ALTERNATES_NOSTRIP
  322 };
  323 
  324 /* Content-Transfer-Encodings as defined in RFC 2045:
  325  * - Quoted-Printable, section 6.7
  326  * - Base64, section 6.8 */
  327 #define QP_LINESIZE (4 * 19) /* Max. compliant QP linesize */
  328 
  329 #define B64_LINESIZE (4 * 19) /* Max. compliant Base64 linesize */
  330 #define B64_ENCODE_INPUT_PER_LINE ((B64_LINESIZE / 4) * 3)
  331 
  332 enum mime_enc{
  333    MIMEE_NONE, /* message is not in MIME format */
  334    MIMEE_BIN, /* message is in binary encoding */
  335    MIMEE_8B, /* message is in 8bit encoding */
  336    MIMEE_7B, /* message is in 7bit encoding */
  337    MIMEE_QP, /* message is quoted-printable */
  338    MIMEE_B64 /* message is in base64 encoding */
  339 };
  340 
  341 /* xxx QP came later, maybe rewrite all to use mime_enc_flags directly? */
  342 enum mime_enc_flags{
  343    MIMEEF_NONE,
  344    MIMEEF_SALLOC = 1u<<0, /* Use n_autorec_alloc(), not n_realloc().. */
  345    /* ..result .s,.l point to user buffer of *_LINESIZE+[+[+]] bytes instead */
  346    MIMEEF_BUF = 1u<<1,
  347    MIMEEF_CRLF = 1u<<2, /* (encode) Append "\r\n" to lines */
  348    MIMEEF_LF = 1u<<3, /* (encode) Append "\n" to lines */
  349    /* (encode) If one of _CRLF/_LF is set, honour *_LINESIZE+[+[+]] and
  350     * inject the desired line-ending whenever a linewrap is desired */
  351    MIMEEF_MULTILINE = 1u<<4,
  352    /* (encode) Quote with header rules, do not generate soft NL breaks?
  353     * For mustquote(), specifies whether special RFC 2047 header rules
  354     * should be used instead */
  355    MIMEEF_ISHEAD = 1u<<5,
  356    /* (encode) Ditto; for mustquote() this furtherly fine-tunes behaviour in
  357     * that characters which would not be reported as "must-quote" when
  358     * detecting whether quoting is necessary at all will be reported as
  359     * "must-quote" if they have to be encoded in an encoded word */
  360    MIMEEF_ISENCWORD = 1u<<6,
  361    __MIMEEF_LAST = 6u
  362 };
  363 
  364 enum qpflags{
  365    QP_NONE = MIMEEF_NONE,
  366    QP_SALLOC = MIMEEF_SALLOC,
  367    QP_BUF = MIMEEF_BUF,
  368    QP_ISHEAD = MIMEEF_ISHEAD,
  369    QP_ISENCWORD = MIMEEF_ISENCWORD
  370 };
  371 
  372 enum b64flags{
  373    B64_NONE = MIMEEF_NONE,
  374    B64_SALLOC = MIMEEF_SALLOC,
  375    B64_BUF = MIMEEF_BUF,
  376    B64_CRLF = MIMEEF_CRLF,
  377    B64_LF = MIMEEF_LF,
  378    B64_MULTILINE = MIMEEF_MULTILINE,
  379    /* Not used, but for clarity only */
  380    B64_ISHEAD = MIMEEF_ISHEAD,
  381    B64_ISENCWORD = MIMEEF_ISENCWORD,
  382    /* Special version of Base64, "Base64URL", according to RFC 4648.
  383     * Only supported for encoding! */
  384    B64_RFC4648URL = 1u<<(__MIMEEF_LAST+1),
  385    /* Don't use any ("=") padding;
  386     * may NOT be used with any of _CRLF, _LF or _MULTILINE */
  387    B64_NOPAD = 1u<<(__MIMEEF_LAST+2)
  388 };
  389 
  390 enum mime_parse_flags{
  391    MIME_PARSE_NONE,
  392    MIME_PARSE_DECRYPT = 1u<<0,
  393    MIME_PARSE_PARTS = 1u<<1,
  394    MIME_PARSE_SHALLOW = 1u<<2,
  395    /* In effect we parse this message for user display or quoting purposes, so
  396     * relaxed rules regarding content inspection may be applicable */
  397    MIME_PARSE_FOR_USER_CONTEXT = 1u<<3
  398 };
  399 
  400 enum okay{
  401    STOP = 0,
  402    OKAY = 1
  403 };
  404 
  405 enum okey_xlook_mode{
  406    OXM_PLAIN = 1u<<0, /* Plain key always tested */
  407    OXM_H_P = 1u<<1, /* Check PLAIN-.url_h_p */
  408    OXM_U_H_P = 1u<<2, /* Check PLAIN-.url_u_h_p */
  409    OXM_ALL = 0x7u
  410 };
  411 
  412 /* <0 means "stop" unless *prompt* extensions are enabled. */
  413 enum prompt_exp{
  414    PROMPT_STOP = -1, /* \c */
  415    /* *prompt* extensions: \$, \@ etc. */
  416    PROMPT_DOLLAR = -2,
  417    PROMPT_AT = -3
  418 };
  419 
  420 enum protocol{
  421    n_PROTO_NONE,
  422    n_PROTO_EML, /* Local electronic mail file (single message, rdonly) */
  423    n_PROTO_FILE, /* refers to a local file */
  424 PROTO_FILE = n_PROTO_FILE,
  425    n_PROTO_POP3, /* is a pop3 server string */
  426 PROTO_POP3 = n_PROTO_POP3,
  427 n_PROTO_IMAP,
  428 PROTO_IMAP = n_PROTO_IMAP,
  429    n_PROTO_MAILDIR, /* refers to a maildir folder */
  430 PROTO_MAILDIR = n_PROTO_MAILDIR,
  431    n_PROTO_UNKNOWN, /* unknown protocol */
  432 PROTO_UNKNOWN = n_PROTO_UNKNOWN,
  433 
  434    n_PROTO_MASK = (1u << 5) - 1
  435 };
  436 
  437 enum sendaction{
  438    SEND_MBOX, /* no conversion to perform */
  439    SEND_RFC822, /* no conversion, no From_ line */
  440    SEND_TODISP, /* convert to displayable form */
  441    SEND_TODISP_ALL, /* same, include all MIME parts */
  442    SEND_TODISP_PARTS, /* same, but only interactive, user-selected parts */
  443    SEND_SHOW, /* convert to 'show' command form */
  444    SEND_TOSRCH, /* convert for IMAP SEARCH */
  445    SEND_TOFILE, /* convert for saving body to a file */
  446    SEND_TOPIPE, /* convert for pipe-content/subc. */
  447    SEND_QUOTE, /* convert for quoting */
  448    SEND_QUOTE_ALL, /* same, include all MIME parts */
  449    SEND_DECRYPT /* decrypt */
  450 };
  451 
  452 enum n_shexp_parse_flags{
  453    n_SHEXP_PARSE_NONE,
  454    /* Don't perform expansions or interpret reverse solidus escape sequences.
  455     * Output may be NULL, otherwise the possibly trimmed non-expanded input is
  456     * used as output (implies _PARSE_META_KEEP) */
  457    n_SHEXP_PARSE_DRYRUN = 1u<<0,
  458    n_SHEXP_PARSE_TRUNC = 1u<<1, /* Truncate result storage on entry */
  459    n_SHEXP_PARSE_TRIM_SPACE = 1u<<2, /* ..surrounding tokens */
  460    n_SHEXP_PARSE_TRIM_IFSSPACE = 1u<<3, /* " */
  461    n_SHEXP_PARSE_LOG = 1u<<4, /* Log errors */
  462    n_SHEXP_PARSE_LOG_D_V = 1u<<5, /* Log errors if n_PO_D_V */
  463    n_SHEXP_PARSE_IFS_VAR = 1u<<6, /* IFS is *ifs*, not su_cs_is_blank() */
  464    n_SHEXP_PARSE_IFS_ADD_COMMA = 1u<<7, /* Add comma , to normal "IFS" */
  465    n_SHEXP_PARSE_IFS_IS_COMMA = 1u<<8, /* Let comma , be the sole "IFS" */
  466    n_SHEXP_PARSE_IGNORE_EMPTY = 1u<<9, /* Ignore empty tokens, start over */
  467 
  468    /* Implicitly open quotes, and ditto closing.  _AUTO_FIXED may only be used
  469     * if an auto-quote-mode is enabled, implies _AUTO_CLOSE and causes the
  470     * quote mode to be permanently active (cannot be closed) */
  471    n_SHEXP_PARSE_QUOTE_AUTO_FIXED = 1u<<16,
  472    n_SHEXP_PARSE_QUOTE_AUTO_SQ = 1u<<17,
  473    n_SHEXP_PARSE_QUOTE_AUTO_DQ = 1u<<18,
  474    n_SHEXP_PARSE_QUOTE_AUTO_DSQ = 1u<<19,
  475    n_SHEXP_PARSE_QUOTE_AUTO_CLOSE = 1u<<20, /* Ignore an open quote at EOS */
  476    n__SHEXP_PARSE_QUOTE_AUTO_MASK = n_SHEXP_PARSE_QUOTE_AUTO_SQ |
  477          n_SHEXP_PARSE_QUOTE_AUTO_DQ | n_SHEXP_PARSE_QUOTE_AUTO_DSQ,
  478 
  479    /* Recognize metacharacters to separate tokens */
  480    n_SHEXP_PARSE_META_VERTBAR = 1u<<21,
  481    n_SHEXP_PARSE_META_AMPERSAND = 1u<<22,
  482    /* Interpret ; as a sequencing operator, go_input_inject() remainder */
  483    n_SHEXP_PARSE_META_SEMICOLON = 1u<<23,
  484    /* LPAREN, RPAREN, LESSTHAN, GREATERTHAN */
  485 
  486    n_SHEXP_PARSE_META_MASK = n_SHEXP_PARSE_META_VERTBAR |
  487          n_SHEXP_PARSE_META_AMPERSAND | n_SHEXP_PARSE_META_SEMICOLON,
  488 
  489    /* Keep the metacharacter (or IFS character), do not skip over it */
  490    n_SHEXP_PARSE_META_KEEP = 1u<<24,
  491 
  492    n__SHEXP_PARSE_LAST = 24
  493 };
  494 
  495 enum n_shexp_state{
  496    n_SHEXP_STATE_NONE,
  497    /* We have produced some output (or would have, with _PARSE_DRYRUN).
  498     * Note that empty quotes like '' produce no output but set this bit */
  499    n_SHEXP_STATE_OUTPUT = 1u<<0,
  500    /* Don't call the parser again (# comment seen; out of input).
  501     * Not (necessarily) mutual with _OUTPUT) */
  502    n_SHEXP_STATE_STOP = 1u<<1,
  503    n_SHEXP_STATE_UNICODE = 1u<<2, /* \[Uu] used */
  504    n_SHEXP_STATE_CONTROL = 1u<<3, /* Control characters seen */
  505    n_SHEXP_STATE_QUOTE = 1u<<4, /* Any quotes seen */
  506    n_SHEXP_STATE_WS_LEAD = 1u<<5, /* _TRIM_{IFS,}SPACE: seen.. */
  507    n_SHEXP_STATE_WS_TRAIL = 1u<<6, /* .. leading / trailing WS */
  508    n_SHEXP_STATE_META_VERTBAR = 1u<<7, /* Metacharacter | follows/ed */
  509    n_SHEXP_STATE_META_AMPERSAND = 1u<<8, /* Metacharacter & follows/ed */
  510    n_SHEXP_STATE_META_SEMICOLON = 1u<<9, /* Metacharacter ; follows/ed */
  511 
  512    n_SHEXP_STATE_META_MASK = n_SHEXP_STATE_META_VERTBAR |
  513          n_SHEXP_STATE_META_AMPERSAND | n_SHEXP_STATE_META_SEMICOLON,
  514 
  515    n_SHEXP_STATE_ERR_CONTROL = 1u<<16, /* \c notation with invalid arg. */
  516    n_SHEXP_STATE_ERR_UNICODE = 1u<<17, /* Valid \[Uu] and !n_PSO_UNICODE */
  517    n_SHEXP_STATE_ERR_NUMBER = 1u<<18, /* Bad number (\[UuXx]) */
  518    n_SHEXP_STATE_ERR_IDENTIFIER = 1u<<19, /* Invalid identifier */
  519    n_SHEXP_STATE_ERR_BADSUB = 1u<<20, /* Empty/bad ${}/[] substitution */
  520    n_SHEXP_STATE_ERR_GROUPOPEN = 1u<<21, /* _QUOTEOPEN + no }/]/)/ 4 ${/[/( */
  521    n_SHEXP_STATE_ERR_QUOTEOPEN = 1u<<22, /* Quote remains open at EOS */
  522 
  523    n_SHEXP_STATE_ERR_MASK = su_BITENUM_MASK(16, 22)
  524 };
  525 
  526 enum n_sigman_flags{
  527    n_SIGMAN_NONE = 0,
  528    n_SIGMAN_HUP = 1<<0,
  529    n_SIGMAN_INT = 1<<1,
  530    n_SIGMAN_QUIT = 1<<2,
  531    n_SIGMAN_TERM = 1<<3,
  532    n_SIGMAN_PIPE = 1<<4,
  533 
  534    n_SIGMAN_IGN_HUP = 1<<5,
  535    n_SIGMAN_IGN_INT = 1<<6,
  536    n_SIGMAN_IGN_QUIT = 1<<7,
  537    n_SIGMAN_IGN_TERM = 1<<8,
  538 
  539    n_SIGMAN_ALL = 0xFF,
  540    /* Mostly for _leave() reraise flags */
  541    n_SIGMAN_VIPSIGS = n_SIGMAN_HUP | n_SIGMAN_INT | n_SIGMAN_QUIT |
  542          n_SIGMAN_TERM,
  543    n_SIGMAN_NTTYOUT_PIPE = 1<<16,
  544    n_SIGMAN_VIPSIGS_NTTYOUT = n_SIGMAN_HUP | n_SIGMAN_INT | n_SIGMAN_QUIT |
  545          n_SIGMAN_TERM | n_SIGMAN_NTTYOUT_PIPE,
  546 
  547    n__SIGMAN_PING = 1<<17
  548 };
  549 
  550 enum n_str_trim_flags{
  551    n_STR_TRIM_FRONT = 1u<<0,
  552    n_STR_TRIM_END = 1u<<1,
  553    n_STR_TRIM_BOTH = n_STR_TRIM_FRONT | n_STR_TRIM_END
  554 };
  555 
  556 #ifdef mx_HAVE_TLS
  557 enum n_tls_verify_level{
  558    n_TLS_VERIFY_IGNORE,
  559    n_TLS_VERIFY_WARN,
  560    n_TLS_VERIFY_ASK,
  561    n_TLS_VERIFY_STRICT
  562 };
  563 #endif
  564 
  565 enum tdflags{
  566    TD_NONE, /* no display conversion */
  567    TD_ISPR = 1<<0, /* use isprint() checks */
  568    TD_ICONV = 1<<1, /* use iconv() */
  569    TD_DELCTRL = 1<<2, /* delete control characters */
  570 
  571    /* NOTE: _TD_EOF and _TD_BUFCOPY may be ORd with enum conversion and
  572     * enum sendaction, and may thus NOT clash with their bit range! */
  573    _TD_EOF = 1<<14, /* EOF seen, last round! */
  574    _TD_BUFCOPY = 1<<15 /* Buffer may be constant, copy it */
  575 };
  576 
  577 enum n_visual_info_flags{
  578    n_VISUAL_INFO_NONE,
  579    n_VISUAL_INFO_ONE_CHAR = 1u<<0, /* Step only one char, then return */
  580    n_VISUAL_INFO_SKIP_ERRORS = 1u<<1, /* Treat via replacement, step byte */
  581    n_VISUAL_INFO_WIDTH_QUERY = 1u<<2, /* Detect visual character widths */
  582 
  583    /* Rest only with mx_HAVE_C90AMEND1, mutual with _ONE_CHAR */
  584    n_VISUAL_INFO_WOUT_CREATE = 1u<<8, /* Use/create .vic_woudat */
  585    n_VISUAL_INFO_WOUT_SALLOC = 1u<<9, /* ..autorec_alloc() it first */
  586    /* Only visuals into .vic_woudat - implies _WIDTH_QUERY */
  587    n_VISUAL_INFO_WOUT_PRINTABLE = 1u<<10,
  588    n__VISUAL_INFO_FLAGS = n_VISUAL_INFO_WOUT_CREATE |
  589          n_VISUAL_INFO_WOUT_SALLOC | n_VISUAL_INFO_WOUT_PRINTABLE
  590 };
  591 
  592 enum n_program_option{
  593    n_PO_D = 1u<<0, /* -d / *debug* */
  594    n_PO_V = 1u<<1, /* -v / *verbose* */
  595    n_PO_VV = 1u<<2, /* .. more verbosity */
  596    n_PO_VVV = 1u<<3, /* .. most verbosity */
  597    n_PO_EXISTONLY = 1u<<4, /* -e */
  598    n_PO_HEADERSONLY = 1u<<5, /* -H */
  599    n_PO_HEADERLIST = 1u<<6, /* -L */
  600    n_PO_QUICKRUN_MASK = n_PO_EXISTONLY | n_PO_HEADERSONLY | n_PO_HEADERLIST,
  601    n_PO_E_FLAG = 1u<<7, /* -E / *skipemptybody* */
  602    n_PO_F_FLAG = 1u<<8, /* -F */
  603    n_PO_f_FLAG = 1u<<9, /* -f [and file on command line] */
  604    n_PO_Mm_FLAG = 1u<<10, /* -M or -m (plus n_poption_arg_Mm) */
  605    n_PO_R_FLAG = 1u<<11, /* -R */
  606    n_PO_r_FLAG = 1u<<12, /* -r (plus n_poption_arg_r) */
  607    n_PO_S_FLAG_TEMPORARY = 1u<<13, /* -S about to set a variable */
  608    n_PO_t_FLAG = 1u<<14, /* -t */
  609    n_PO_TILDE_FLAG = 1u<<15, /* -~ */
  610    n_PO_BATCH_FLAG = 1u<<16, /* -# */
  611 
  612    /* Some easy-access shortcut; the V bits must be contiguous! */
  613    n_PO_V_MASK = n_PO_V | n_PO_VV | n_PO_VVV,
  614    n_PO_D_V = n_PO_D | n_PO_V_MASK,
  615    n_PO_D_VV = n_PO_D | n_PO_VV | n_PO_VVV,
  616    n_PO_D_VVV = n_PO_D | n_PO_VVV
  617 };
  618 MCTA(n_PO_V << 1 == n_PO_VV, "PO_V* must be successive")
  619 MCTA(n_PO_VV << 1 == n_PO_VVV, "PO_V* must be successive")
  620 
  621 #define n_OBSOLETE(X) \
  622 do if(!su_state_has(su_STATE_REPRODUCIBLE)){\
  623    static boole su_CONCAT(a__warned__, __LINE__);\
  624    if(!su_CONCAT(a__warned__, __LINE__)){\
  625       su_CONCAT(a__warned__, __LINE__) = TRU1;\
  626       n_err("%s: %s\n", _("Obsoletion warning"), X);\
  627    }\
  628 }while(0)
  629 #define n_OBSOLETE2(X,Y) \
  630 do if(!su_state_has(su_STATE_REPRODUCIBLE)){\
  631    static boole su_CONCAT(a__warned__, __LINE__);\
  632    if(!su_CONCAT(a__warned__, __LINE__)){\
  633       su_CONCAT(a__warned__, __LINE__) = TRU1;\
  634       n_err("%s: %s: %s\n", _("Obsoletion warning"), X, Y);\
  635    }\
  636 }while(0)
  637 
  638 /* Program state bits which may regularly fluctuate */
  639 enum n_program_state{
  640    n_PS_ROOT = 1u<<30, /* Temporary "bypass any checks" bit */
  641 #define n_PS_ROOT_BLOCK(ACT) \
  642 do{\
  643    boole a___reset___ = !(n_pstate & n_PS_ROOT);\
  644    n_pstate |= n_PS_ROOT;\
  645    ACT;\
  646    if(a___reset___)\
  647       n_pstate &= ~n_PS_ROOT;\
  648 }while(0)
  649 
  650    /* XXX These are internal to the state machine and do not belong here,
  651     * XXX yet this was the easiest (accessible) approach */
  652    n_PS_ERR_XIT = 1u<<0, /* Unless `ignerr' seen -> n_PSO_XIT */
  653    n_PS_ERR_QUIT = 1u<<1, /* ..ditto: -> n_PSO_QUIT */
  654    n_PS_ERR_EXIT_MASK = n_PS_ERR_XIT | n_PS_ERR_QUIT,
  655 
  656    n_PS_SOURCING = 1u<<2, /* During load() or `source' */
  657    n_PS_ROBOT = 1u<<3, /* .. even more robotic */
  658    n_PS_COMPOSE_MODE = 1u<<4, /* State machine recursed */
  659    n_PS_COMPOSE_FORKHOOK = 1u<<5, /* A hook running in a subprocess */
  660 
  661    n_PS_HOOK_NEWMAIL = 1u<<7,
  662    n_PS_HOOK = 1u<<8,
  663    n_PS_HOOK_MASK = n_PS_HOOK_NEWMAIL | n_PS_HOOK,
  664 
  665    n_PS_EDIT = 1u<<9, /* Current mailbox no "system mailbox" */
  666    n_PS_SETFILE_OPENED = 1u<<10, /* (hack) setfile() opened a new box */
  667    n_PS_SAW_COMMAND = 1u<<11, /* ..after mailbox switch */
  668    n_PS_DID_PRINT_DOT = 1u<<12, /* Current message has been printed */
  669 
  670    n_PS_SIGWINCH_PEND = 1u<<13, /* Need update of $COLUMNS/$LINES */
  671    n_PS_PSTATE_PENDMASK = n_PS_SIGWINCH_PEND, /* pstate housekeeping needed */
  672 
  673    n_PS_ARGLIST_MASK = su_BITENUM_MASK(14, 16),
  674    n_PS_ARGMOD_LOCAL = 1u<<14, /* "local" modifier TODO struct CmdCtx */
  675    n_PS_ARGMOD_VPUT = 1u<<15, /* "vput" modifier TODO struct CmdCtx */
  676    n_PS_ARGMOD_WYSH = 1u<<16, /* "wysh" modifier TODO struct CmdCtx */
  677    n_PS_MSGLIST_GABBY = 1u<<14, /* n_getmsglist() saw something gabby */
  678    n_PS_MSGLIST_DIRECT = 1u<<15, /* A msg was directly chosen by number */
  679 
  680    n_PS_EXPAND_MULTIRESULT = 1u<<17, /* Last fexpand() with MULTIOK had .. */
  681    n_PS_ERRORS_PROMPT = 1u<<18, /* New error to be reported in prompt */
  682    /* In the interactive mainloop, we want any error to appear once for each
  683     * tick, even if it is the same as in the tick before and would normally be
  684     * suppressed */
  685    n_PS_ERRORS_NEED_PRINT_ONCE = 1u<<19,
  686 
  687    /* Bad hacks */
  688    n_PS_HEADER_NEEDED_MIME = 1u<<24, /* mime_write_tohdr() not ASCII clean */
  689    n_PS_READLINE_NL = 1u<<25, /* readline_input()+ saw a \n */
  690    n_PS_BASE64_STRIP_CR = 1u<<26 /* Go for text output, strip CR's */
  691 };
  692 
  693 /* Various states set once, and first time messages or initializers */
  694 enum n_program_state_once{
  695    /* We have four program states: (0) pre getopt() done, (_GETOPT) pre rcfile
  696     * loaded etc., (_CONFIG) only -X evaluation missing still, followed by
  697     * _STARTED when we are fully setup */
  698    n_PSO_STARTED_GETOPT = 1u<<0,
  699    n_PSO_STARTED_CONFIG = 1u<<1,
  700    n_PSO_STARTED = 1u<<2,
  701 
  702    /* Exit request pending (quick) */
  703    n_PSO_XIT = 1u<<3,
  704    n_PSO_QUIT = 1u<<4,
  705    n_PSO_EXIT_MASK = n_PSO_XIT | n_PSO_QUIT,
  706 
  707    /* Pre _STARTED */
  708    /* 1u<<5, */
  709    n_PSO_UNICODE = 1u<<6,
  710    n_PSO_ENC_MBSTATE = 1u<<7,
  711 
  712    n_PSO_SENDMODE = 1u<<9,
  713    n_PSO_INTERACTIVE = 1u<<10,
  714    n_PSO_TTYIN = 1u<<11,
  715    n_PSO_TTYOUT = 1u<<12, /* TODO should be TTYERR! */
  716    n_PSO_TTYANY = n_PSO_TTYIN | n_PSO_TTYOUT, /* mx_tty_fp = TTY */
  717    n_PSO_TTYERR = 1u<<13,
  718 
  719    /* "Later" */
  720    n_PSO_t_FLAG_DONE = 1u<<15,
  721    n_PSO_GETFILENAME_QUOTE_NOTED = 1u<<16,
  722    n_PSO_ERRORS_NOTED = 1u<<17,
  723    n_PSO_LINE_EDITOR_INIT = 1u<<18,
  724    n_PSO_RANDOM_INIT = 1u<<19,
  725    n_PSO_TERMCAP_DISABLE = 1u<<20,
  726    n_PSO_TERMCAP_CA_MODE = 1u<<21,
  727    n_PSO_TERMCAP_FULLWIDTH = 1u<<22, /* !am or am+xn (right margin wrap) */
  728    n_PSO_PS_DOTLOCK_NOTED = 1u<<23
  729 };
  730 
  731 /* {{{ A large enum with all the boolean and value options a.k.a their keys.
  732  * Only the constant keys are in here, to be looked up via ok_[bv]look(),
  733  * ok_[bv]set() and ok_[bv]clear().
  734  * Variable properties are placed in {PROP=VALUE[:,PROP=VALUE:]} comments,
  735  * a {\} comment causes the next line to be read for (overlong) properties.
  736  * Notes:
  737  * - see the introductional source comments before changing *anything* in here!
  738  * - virt= implies rdonly,nodel
  739  * - import= implies env
  740  * - num and posnum are mutual exclusive
  741  * - most default VAL_ues come from in from build system via ./make.rc
  742  * - Other i3val=s and/or defval=s are imposed by POSIX: we do not (or only
  743  *   additionally "trust" the system-wide RC file to establish the settings
  744  * - code assumes (in conjunction with make-okey-map.pl) case-insensitive sort!
  745  * (Keep in SYNC: nail.h:okeys, nail.rc, nail.1:"Initial settings") */
  746 enum okeys {
  747    /* This is used for all macro(-local) variables etc., i.e.,
  748     * [*@#]|[1-9][0-9]*, in order to have something with correct properties.
  749     * It is also used for the ${^.+} multiplexer */
  750    ok_v___special_param, /* {nolopts=1,rdonly=1,nodel=1} */
  751    /*__qm/__em aka ?/! should be num=1 but that more expensive than what now */
  752    ok_v___qm, /* {name=?,nolopts=1,rdonly=1,nodel=1} */
  753    ok_v___em, /* {name=!,nolopts=1,rdonly=1,nodel=1} */
  754 
  755    ok_v_account, /* {nolopts=1,rdonly=1,nodel=1} */
  756    ok_b_add_file_recipients,
  757 ok_v_agent_shell_lookup, /* {obsolete=1} */
  758    ok_b_allnet,
  759    ok_b_append,
  760    /* *ask* is auto-mapped to *asksub* as imposed by standard! */
  761    ok_b_ask, /* {vip=1} */
  762    ok_b_askatend,
  763    ok_b_askattach,
  764    ok_b_askbcc,
  765    ok_b_askcc,
  766    ok_b_asksign,
  767    ok_b_asksend,
  768    ok_b_asksub, /* {i3val=TRU1} */
  769    ok_v_attrlist,
  770    ok_v_autobcc,
  771    ok_v_autocc,
  772    ok_b_autocollapse,
  773    ok_b_autoprint,
  774 ok_b_autothread, /* {obsolete=1} */
  775    ok_v_autosort,
  776 
  777    ok_b_bang,
  778 ok_b_batch_exit_on_error, /* {obsolete=1} */
  779 ok_v_bind_timeout, /* {vip=1,obsolete=1,notempty=1,posnum=1} */
  780    ok_v_bind_inter_byte_timeout, /* {\ } */
  781       /* {notempty=1,posnum=1,defval=mx_BIND_INTER_BYTE_TIMEOUT} */
  782    ok_v_bind_inter_key_timeout, /* {notempty=1,posnum=1} */
  783 ok_b_bsdannounce, /* {obsolete=1} */
  784    ok_b_bsdcompat,
  785    ok_b_bsdflags,
  786    ok_b_bsdheadline,
  787    ok_b_bsdmsgs,
  788    ok_b_bsdorder,
  789    ok_v_build_cc, /* {virt=VAL_BUILD_CC_ARRAY} */
  790    ok_v_build_ld, /* {virt=VAL_BUILD_LD_ARRAY} */
  791    ok_v_build_os, /* {virt=VAL_BUILD_OS} */
  792    ok_v_build_rest, /* {virt=VAL_BUILD_REST_ARRAY} */
  793 
  794    ok_v_COLUMNS, /* {notempty=1,posnum=1,env=1} */
  795    /* Charset lowercase conversion handled via vip= */
  796    ok_v_charset_7bit, /* {vip=1,notempty=1,defval=CHARSET_7BIT} */
  797    /* But unused without mx_HAVE_ICONV, we use ok_vlook(CHARSET_8BIT_OKEY)! */
  798    ok_v_charset_8bit, /* {vip=1,notempty=1,defval=CHARSET_8BIT} */
  799    ok_v_charset_unknown_8bit, /* {vip=1} */
  800    ok_v_cmd,
  801    ok_b_colour_disable,
  802    ok_b_colour_pager,
  803    ok_v_contact_mail, /* {virt=VAL_CONTACT_MAIL} */
  804    ok_v_contact_web, /* {virt=VAL_CONTACT_WEB} */
  805    ok_v_content_description_forwarded_message, /* {\ } */
  806       /* {defval=mx_CONTENT_DESC_FORWARDED_MESSAGE} */
  807    ok_v_content_description_quote_attachment, /* {\ } */
  808       /* {defval=mx_CONTENT_DESC_QUOTE_ATTACHMENT} */
  809    ok_v_content_description_smime_message, /* {\ } */
  810       /* {defval=mx_CONTENT_DESC_SMIME_MESSAGE} */
  811    ok_v_content_description_smime_signature, /* {\ } */
  812       /* {defval=mx_CONTENT_DESC_SMIME_SIG} */
  813 
  814    ok_v_crt, /* {posnum=1} */
  815    ok_v_customhdr, /* {vip=1} */
  816 
  817    ok_v_DEAD, /* {notempty=1,env=1,defval=VAL_DEAD} */
  818    ok_v_datefield, /* {i3val="%Y-%m-%d %H:%M"} */
  819    ok_v_datefield_markout_older, /* {i3val="%Y-%m-%d"} */
  820    ok_b_debug, /* {vip=1} */
  821    ok_b_disposition_notification_send,
  822    ok_b_dot,
  823    ok_b_dotlock_disable,
  824 ok_b_dotlock_ignore_error, /* {obsolete=1} */
  825 
  826    ok_v_EDITOR, /* {env=1,notempty=1,defval=VAL_EDITOR} */
  827    ok_v_editalong,
  828    ok_b_editheaders,
  829    ok_b_emptystart,
  830 ok_v_encoding, /* {obsolete=1} */
  831    ok_b_errexit,
  832    ok_v_errors_limit, /* {notempty=1,posnum=1,defval=VAL_ERRORS_LIMIT} */
  833    ok_v_escape, /* {defval=n_ESCAPE} */
  834    ok_v_expandaddr,
  835    ok_v_expandaddr_domaincheck, /* {notempty=1} */
  836    ok_v_expandargv,
  837 
  838    ok_v_features, /* {virt=VAL_FEATURES} */
  839    ok_b_flipr,
  840    ok_v_folder, /* {vip=1} */
  841    ok_v_folder_resolved, /* {rdonly=1,nodel=1} */
  842    ok_v_folder_hook,
  843    ok_b_followup_to,
  844    ok_b_followup_to_add_cc,
  845    ok_v_followup_to_honour,
  846    ok_b_forward_add_cc,
  847    ok_b_forward_as_attachment,
  848    ok_v_forward_inject_head,
  849    ok_v_forward_inject_tail,
  850    ok_v_from, /* {vip=1} */
  851    ok_b_fullnames,
  852 ok_v_fwdheading, /* {obsolete=1} */
  853 
  854    ok_v_HOME, /* {vip=1,nodel=1,notempty=1,import=1} */
  855    ok_b_header, /* {i3val=TRU1} */
  856    ok_v_headline,
  857    ok_v_headline_bidi,
  858    ok_b_headline_plain,
  859    ok_v_history_file,
  860    ok_v_history_gabby,
  861    ok_b_history_gabby_persist,
  862    ok_v_history_size, /* {notempty=1,posnum=1} */
  863    ok_b_hold,
  864    ok_v_hostname, /* {vip=1} */
  865 
  866    ok_b_idna_disable,
  867    ok_v_ifs, /* {vip=1,defval=" \t\n"} */
  868    ok_v_ifs_ws, /* {vip=1,rdonly=1,nodel=1,i3val=" \t\n"} */
  869    ok_b_ignore,
  870    ok_b_ignoreeof,
  871    ok_v_inbox,
  872    ok_v_indentprefix, /* {defval="\t"} */
  873 
  874    ok_b_keep,
  875    ok_b_keep_content_length,
  876    ok_b_keepsave,
  877 
  878    ok_v_LANG, /* {vip=1,env=1,notempty=1} */
  879    ok_v_LC_ALL, /* {name=LC_ALL,vip=1,env=1,notempty=1} */
  880    ok_v_LC_CTYPE, /* {name=LC_CTYPE,vip=1,env=1,notempty=1} */
  881    ok_v_LINES, /* {notempty=1,posnum=1,env=1} */
  882    ok_v_LISTER, /* {env=1,notempty=1,defval=VAL_LISTER} */
  883    ok_v_LOGNAME, /* {rdonly=1,import=1} */
  884    ok_v_line_editor_cpl_word_breaks, /* {\ } */
  885       /* {defval=n_LINE_EDITOR_CPL_WORD_BREAKS} */
  886    ok_b_line_editor_disable,
  887    ok_b_line_editor_no_defaults,
  888    ok_v_log_prefix, /* {nodel=1,i3val=VAL_UAGENT ": "} */
  889 
  890    ok_v_MAIL, /* {env=1} */
  891    ok_v_MAILCAPS, /* {import=1,defval=VAL_MAILCAPS} */
  892    ok_v_MAILRC, /* {import=1,notempty=1,defval=VAL_MAILRC} */
  893    ok_b_MAILX_NO_SYSTEM_RC, /* {name=MAILX_NO_SYSTEM_RC,import=1} */
  894    ok_v_MBOX, /* {env=1,notempty=1,defval=VAL_MBOX} */
  895    ok_v_mailbox_resolved, /* {nolopts=1,rdonly=1,nodel=1} */
  896    ok_v_mailbox_display, /* {nolopts=1,rdonly=1,nodel=1} */
  897    ok_b_mailcap_disable,
  898    ok_v_mailx_extra_rc, /* {notempty=1} */
  899    /* TODO drop all those _v_mailx which are now accessible via `digmsg'!
  900     * TODO Documentation yet removed, n_temporary_compose_hook_varset() not */
  901 ok_v_mailx_command, /* {rdonly=1,nodel=1} */
  902 ok_v_mailx_subject, /* {rdonly=1,nodel=1} */
  903 ok_v_mailx_from, /* {rdonly=1,nodel=1} */
  904 ok_v_mailx_sender, /* {rdonly=1,nodel=1} */
  905 ok_v_mailx_to, /* {rdonly=1,nodel=1} */
  906 ok_v_mailx_cc, /* {rdonly=1,nodel=1} */
  907 ok_v_mailx_bcc, /* {rdonly=1,nodel=1} */
  908 ok_v_mailx_raw_to, /* {rdonly=1,nodel=1} */
  909 ok_v_mailx_raw_cc, /* {rdonly=1,nodel=1} */
  910 ok_v_mailx_raw_bcc, /* {rdonly=1,nodel=1} */
  911 ok_v_mailx_orig_from, /* {rdonly=1,nodel=1} */
  912 ok_v_mailx_orig_to, /* {rdonly=1,nodel=1} */
  913 ok_v_mailx_orig_cc, /* {rdonly=1,nodel=1} */
  914 ok_v_mailx_orig_bcc, /* {rdonly=1,nodel=1} */
  915    ok_b_markanswered,
  916    ok_b_mbox_fcc_and_pcc, /* {i3val=1} */
  917    ok_b_mbox_rfc4155,
  918    ok_b_memdebug, /* {vip=1} */
  919    ok_b_message_id_disable,
  920    ok_v_message_inject_head,
  921    ok_v_message_inject_tail,
  922    ok_b_metoo,
  923    ok_b_mime_allow_text_controls,
  924    ok_b_mime_alternative_favour_rich,
  925    ok_v_mime_counter_evidence, /* {posnum=1} */
  926    ok_v_mime_encoding,
  927    ok_b_mime_force_sendout,
  928    ok_v_mimetypes_load_control,
  929    ok_v_mta, /* {notempty=1,defval=VAL_MTA} */
  930    ok_v_mta_aliases, /* {notempty=1} */
  931    ok_v_mta_arguments,
  932    ok_b_mta_no_default_arguments,
  933    ok_b_mta_no_receiver_arguments,
  934    ok_v_mta_argv0, /* {notempty=1,defval=VAL_MTA_ARGV0} */
  935    ok_b_mta_bcc_ok,
  936 
  937 ok_v_NAIL_EXTRA_RC, /* {name=NAIL_EXTRA_RC,env=1,notempty=1,obsolete=1} */
  938 ok_b_NAIL_NO_SYSTEM_RC, /* {name=NAIL_NO_SYSTEM_RC,import=1,obsolete=1} */
  939 ok_v_NAIL_HEAD, /* {name=NAIL_HEAD,obsolete=1} */
  940 ok_v_NAIL_HISTFILE, /* {name=NAIL_HISTFILE,obsolete=1} */
  941 ok_v_NAIL_HISTSIZE, /* {name=NAIL_HISTSIZE,notempty=1,num=1,obsolete=1} */
  942 ok_v_NAIL_TAIL, /* {name=NAIL_TAIL,obsolete=1} */
  943    ok_v_NETRC, /* {env=1,notempty=1,defval=VAL_NETRC} */
  944    ok_b_netrc_lookup, /* {chain=1} */
  945    ok_v_netrc_pipe,
  946    ok_v_newfolders,
  947    ok_v_newmail,
  948 
  949    ok_v_on_account_cleanup, /* {notempty=1} */
  950    ok_v_on_compose_cleanup, /* {notempty=1} */
  951    ok_v_on_compose_enter, /* {notempty=1} */
  952    ok_v_on_compose_leave, /* {notempty=1} */
  953    ok_v_on_compose_splice, /* {notempty=1} */
  954    ok_v_on_compose_splice_shell, /* {notempty=1} */
  955    ok_v_on_history_addition, /* {notempty=1} */
  956    ok_v_on_main_loop_tick, /* {notempty=1} */
  957    ok_v_on_program_exit, /* {notempty=1} */
  958    ok_v_on_resend_cleanup, /* {notempty=1} */
  959    ok_v_on_resend_enter, /* {notempty=1} */
  960    ok_b_outfolder,
  961 
  962    ok_v_PAGER, /* {env=1,notempty=1,defval=VAL_PAGER} */
  963    ok_v_PATH, /* {nodel=1,import=1} */
  964    /* XXX POSIXLY_CORRECT->posix: needs initial call via main()! */
  965    ok_b_POSIXLY_CORRECT, /* {vip=1,import=1,name=POSIXLY_CORRECT} */
  966    ok_b_page,
  967    ok_v_password, /* {chain=1} */
  968    ok_b_piperaw,
  969    ok_v_pop3_auth, /* {chain=1} */
  970    ok_b_pop3_bulk_load,
  971    ok_v_pop3_keepalive, /* {notempty=1,posnum=1} */
  972    ok_b_pop3_no_apop, /* {chain=1} */
  973    ok_b_pop3_use_starttls, /* {chain=1} */
  974    ok_b_posix, /* {vip=1} */
  975    ok_b_print_alternatives,
  976    ok_v_prompt, /* {i3val="? "} */
  977    ok_v_prompt2, /* {i3val=".. "} */
  978 
  979    ok_b_quiet,
  980    ok_v_quote,
  981    ok_b_quote_add_cc,
  982    ok_b_quote_as_attachment,
  983    ok_v_quote_chars, /* {vip=1,notempty=1,defval=">|}:"} */
  984    ok_v_quote_fold,
  985    ok_v_quote_inject_head,
  986    ok_v_quote_inject_tail,
  987 
  988    ok_b_r_option_implicit,
  989    ok_b_recipients_in_cc,
  990    ok_v_record,
  991    ok_b_record_files,
  992    ok_b_record_resent,
  993    ok_b_reply_in_same_charset,
  994    ok_v_reply_strings,
  995 ok_v_replyto, /* {obsolete=1,notempty=1} */
  996    ok_v_reply_to, /* {notempty=1} */
  997    ok_v_reply_to_honour,
  998    ok_v_reply_to_swap_in,
  999    ok_b_rfc822_body_from_, /* {name=rfc822-body-from_} */
 1000 
 1001    ok_v_SHELL, /* {import=1,notempty=1,defval=VAL_SHELL} */
 1002 ok_b_SYSV3, /* {env=1,obsolete=1} */
 1003    ok_b_save, /* {i3val=TRU1} */
 1004    ok_v_screen, /* {notempty=1,posnum=1} */
 1005    ok_b_searchheaders,
 1006    /* Charset lowercase conversion handled via vip= */
 1007    ok_v_sendcharsets, /* {vip=1} */
 1008    ok_b_sendcharsets_else_ttycharset,
 1009    ok_v_sender, /* {vip=1} */
 1010 ok_v_sendmail, /* {obsolete=1} */
 1011 ok_v_sendmail_arguments, /* {obsolete=1} */
 1012 ok_b_sendmail_no_default_arguments, /* {obsolete=1} */
 1013 ok_v_sendmail_progname, /* {obsolete=1} */
 1014    ok_v_sendwait, /* {i3val=""} */
 1015    ok_b_showlast,
 1016    ok_b_showname,
 1017    ok_b_showto,
 1018    ok_v_Sign,
 1019    ok_v_sign,
 1020 ok_v_signature, /* {obsolete=1} */
 1021    ok_b_skipemptybody, /* {vip=1} */
 1022    ok_v_smime_ca_dir,
 1023    ok_v_smime_ca_file,
 1024    ok_v_smime_ca_flags,
 1025    ok_b_smime_ca_no_defaults,
 1026    ok_v_smime_cipher, /* {chain=1} */
 1027    ok_v_smime_crl_dir,
 1028    ok_v_smime_crl_file,
 1029    ok_v_smime_encrypt, /* {chain=1} */
 1030    ok_b_smime_force_encryption,
 1031 ok_b_smime_no_default_ca, /* {obsolete=1} */
 1032    ok_b_smime_sign,
 1033    ok_v_smime_sign_cert, /* {chain=1} */
 1034    ok_v_smime_sign_digest, /* {chain=1} */
 1035    ok_v_smime_sign_include_certs, /* {chain=1} */
 1036 ok_v_smime_sign_message_digest, /* {chain=1,obsolete=1} */
 1037 ok_v_smtp, /* {obsolete=1} */
 1038    ok_v_smtp_auth,                     /* {chain=1} */
 1039 ok_v_smtp_auth_password, /* {obsolete=1} */
 1040 ok_v_smtp_auth_user, /* {obsolete=1} */
 1041    ok_v_smtp_hostname,                 /* {vip=1} */
 1042    ok_b_smtp_use_starttls,             /* {chain=1} */
 1043    ok_v_SOCKS5_PROXY, /* {vip=1,import=1,notempty=1,name=SOCKS5_PROXY} */
 1044    ok_v_SOURCE_DATE_EPOCH,             /* {\ } */
 1045       /* {name=SOURCE_DATE_EPOCH,rdonly=1,import=1,notempty=1,posnum=1} */
 1046    ok_v_socket_connect_timeout, /* {posnum=1} */
 1047    ok_v_socks_proxy, /* {vip=1,chain=1,notempty=1} */
 1048    ok_v_spam_interface,
 1049    ok_v_spam_maxsize, /* {notempty=1,posnum=1} */
 1050    ok_v_spamc_command,
 1051    ok_v_spamc_arguments,
 1052    ok_v_spamc_user,
 1053    ok_v_spamfilter_ham,
 1054    ok_v_spamfilter_noham,
 1055    ok_v_spamfilter_nospam,
 1056    ok_v_spamfilter_rate,
 1057    ok_v_spamfilter_rate_scanscore,
 1058    ok_v_spamfilter_spam,
 1059 ok_v_ssl_ca_dir, /* {chain=1,obsolete=1} */
 1060 ok_v_ssl_ca_file, /* {chain=1,obsolete=1} */
 1061 ok_v_ssl_ca_flags, /* {chain=1,obsolete=1} */
 1062 ok_b_ssl_ca_no_defaults, /* {chain=1,obsolete=1} */
 1063 ok_v_ssl_cert, /* {chain=1,obsolete=1} */
 1064 ok_v_ssl_cipher_list, /* {chain=1,obsolete=1} */
 1065 ok_v_ssl_config_file, /* {obsolete=1} */
 1066 ok_v_ssl_config_module, /* {chain=1,obsolete=1} */
 1067 ok_v_ssl_config_pairs, /* {chain=1,obsolete=1} */
 1068 ok_v_ssl_curves, /* {chain=1,obsolete=1} */
 1069 ok_v_ssl_crl_dir, /* {obsolete=1} */
 1070 ok_v_ssl_crl_file, /* {obsolete=1} */
 1071 ok_v_ssl_features, /* {virt=VAL_TLS_FEATURES,obsolete=1} */
 1072 ok_v_ssl_key, /* {chain=1,obsolete=1} */
 1073 ok_v_ssl_method, /* {chain=1,obsolete=1} */
 1074 ok_b_ssl_no_default_ca, /* {obsolete=1} */
 1075 ok_v_ssl_protocol, /* {chain=1,obsolete=1} */
 1076 ok_v_ssl_rand_egd, /* {obsolete=1} */
 1077 ok_v_ssl_rand_file, /* {obsolete=1}*/
 1078 ok_v_ssl_verify, /* {chain=1,obsolete=1} */
 1079    ok_v_stealthmua,
 1080    ok_v_system_mailrc, /* {virt=VAL_SYSCONFDIR "/" VAL_SYSCONFRC} */
 1081 
 1082    ok_v_TERM, /* {env=1} */
 1083    ok_v_TMPDIR, /* {import=1,vip=1,notempty=1,defval=VAL_TMPDIR} */
 1084    ok_v_termcap,
 1085    ok_b_termcap_ca_mode,
 1086    ok_b_termcap_disable,
 1087    ok_v_tls_ca_dir, /* {chain=1} */
 1088    ok_v_tls_ca_file, /* {chain=1} */
 1089    ok_v_tls_ca_flags, /* {chain=1} */
 1090    ok_b_tls_ca_no_defaults, /* {chain=1} */
 1091    ok_v_tls_config_file,
 1092    ok_v_tls_config_module, /* {chain=1} */
 1093    ok_v_tls_config_pairs, /* {chain=1} */
 1094    ok_v_tls_crl_dir,
 1095    ok_v_tls_crl_file,
 1096    ok_v_tls_features, /* {virt=VAL_TLS_FEATURES} */
 1097    ok_v_tls_fingerprint, /* {chain=1} */
 1098    ok_v_tls_fingerprint_digest, /* {chain=1} */
 1099    ok_v_tls_rand_file,
 1100    ok_v_tls_verify, /* {chain=1} */
 1101    ok_v_toplines, /* {notempty=1,num=1,defval="5"} */
 1102    ok_b_topsqueeze,
 1103    /* Charset lowercase conversion handled via vip= */
 1104    ok_v_ttycharset, /* {vip=1,notempty=1,defval=CHARSET_8BIT} */
 1105    ok_b_typescript_mode, /* {vip=1} */
 1106 
 1107    ok_v_USER, /* {rdonly=1,import=1} */
 1108    ok_v_umask, /* {vip=1,nodel=1,posnum=1,i3val="0077"} */
 1109    ok_v_user, /* {notempty=1,chain=1} */
 1110 
 1111    ok_v_VISUAL, /* {env=1,notempty=1,defval=VAL_VISUAL} */
 1112    ok_v_v15_compat,
 1113    ok_v_verbose, /* {vip=1,posnum=1} */
 1114    ok_v_version, /* {virt=mx_VERSION} */
 1115    ok_v_version_date, /* {virt=mx_VERSION_DATE} */
 1116    ok_v_version_hexnum, /* {virt=mx_VERSION_HEXNUM,posnum=1} */
 1117    ok_v_version_major, /* {virt=mx_VERSION_MAJOR,posnum=1} */
 1118    ok_v_version_minor, /* {virt=mx_VERSION_MINOR,posnum=1} */
 1119    ok_v_version_update, /* {virt=mx_VERSION_UPDATE,posnum=1} */
 1120 
 1121    ok_b_writebackedited
 1122 
 1123 ,  /* Obsolete IMAP related non-sorted */
 1124 ok_b_disconnected, /* {chain=1} */
 1125 ok_v_imap_auth, /* {chain=1} */
 1126 ok_v_imap_cache,
 1127 ok_v_imap_delim, /* {chain=1} */
 1128 ok_v_imap_keepalive, /* {chain=1} */
 1129 ok_v_imap_list_depth,
 1130 ok_b_imap_use_starttls /* {chain=1} */
 1131 }; /* }}} */
 1132 enum {n_OKEYS_MAX = ok_b_imap_use_starttls};
 1133 
 1134 /* Forwards */
 1135 struct mx_attachment;
 1136 struct mx_name;
 1137 
 1138 struct str{
 1139    char *s; /* the string's content */
 1140    uz l; /* the stings's length */
 1141 };
 1142 
 1143 struct n_string{
 1144    char *s_dat; /*@ May contain NULs, not automatically terminated */
 1145    u32 s_len; /*@ gth of string */
 1146    u32 s_auto : 1; /* Stored in auto-reclaimed storage? */
 1147    u32 s_size : 31; /* of .s_dat, -1 */
 1148 };
 1149 
 1150 struct n_strlist{
 1151    struct n_strlist *sl_next;
 1152    uz sl_len;
 1153    char sl_dat[VFIELD_SIZE(0)];
 1154 };
 1155 #define n_STRLIST_ALLOC(SZ) /* XXX -> nailfuns.h (and pimp interface) */\
 1156    n_alloc(VSTRUCT_SIZEOF(struct n_strlist, sl_dat) + (SZ) +1)
 1157 #define n_STRLIST_AUTO_ALLOC(SZ) \
 1158    n_autorec_alloc(VSTRUCT_SIZEOF(struct n_strlist, sl_dat) + (SZ) +1)
 1159 #define n_STRLIST_LOFI_ALLOC(SZ) \
 1160    n_lofi_alloc(VSTRUCT_SIZEOF(struct n_strlist, sl_dat) + (SZ) +1)
 1161 #define n_STRLIST_PLAIN_SIZE() VSTRUCT_SIZEOF(struct n_strlist, sl_dat)
 1162 
 1163 struct n_go_data_ctx{
 1164    struct su_mem_bag *gdc_membag;
 1165    void *gdc_ifcond; /* Saved state of conditional stack */
 1166 #ifdef mx_HAVE_COLOUR
 1167    struct mx_colour_env *gdc_colour;
 1168    boole gdc_colour_active;
 1169    u8 gdc__colour_pad[7];
 1170 # define mx_COLOUR_IS_ACTIVE() \
 1171    (/*n_go_data->gc_data.gdc_colour != su_NIL &&*/\
 1172     /*n_go_data->gc_data.gdc_colour->ce_enabled*/ n_go_data->gdc_colour_active)
 1173 #endif
 1174    struct su_mem_bag gdc__membag_buf[1];
 1175 };
 1176 
 1177 struct search_expr{
 1178    /* XXX Type of search should not be evaluated but be enum */
 1179    boole ss_field_exists; /* Only check whether field spec. exists */
 1180    boole ss_skin; /* Shall work on (skin()ned) addresses */
 1181    u8 ss__pad[6];
 1182    char const *ss_field; /* Field spec. where to search (not always used) */
 1183    char const *ss_body; /* Field body search expression */
 1184 #ifdef mx_HAVE_REGEX
 1185    regex_t *ss_fieldre; /* Could be instead of .ss_field */
 1186    regex_t *ss_bodyre; /* Ditto, .ss_body */
 1187    regex_t ss__fieldre_buf;
 1188    regex_t ss__bodyre_buf;
 1189 #endif
 1190 };
 1191 
 1192 struct n_timespec{
 1193    s64 ts_sec;
 1194    sz ts_nsec;
 1195 };
 1196 
 1197 struct time_current{ /* TODO s64, etc. */
 1198    time_t tc_time;
 1199    struct tm tc_gm;
 1200    struct tm tc_local;
 1201    char tc_ctime[32];
 1202 };
 1203 
 1204 struct mailbox{
 1205    enum{
 1206       MB_NONE = 000, /* no reply expected */
 1207       MB_COMD = 001, /* command reply expected */
 1208       MB_MULT = 002, /* multiline reply expected */
 1209       MB_PREAUTH = 004, /* not in authenticated state */
 1210       MB_BYE = 010, /* may accept a BYE state */
 1211       MB_BAD_FROM_ = 1<<4 /* MBOX with invalid From_ seen & logged */
 1212    } mb_active;
 1213    FILE *mb_itf; /* temp file with messages, read open */
 1214    FILE *mb_otf; /* same, write open */
 1215    char *mb_sorted; /* sort method */
 1216    enum{
 1217       MB_VOID, /* no type (e. g. connection failed) */
 1218       MB_FILE, /* local file */
 1219       MB_POP3, /* POP3 mailbox */
 1220 MB_IMAP, /* IMAP mailbox */
 1221 MB_CACHE, /* IMAP cache */
 1222       MB_MAILDIR /* maildir folder */
 1223    } mb_type; /* type of mailbox */
 1224    enum{
 1225       MB_DELE = 01, /* may delete messages in mailbox */
 1226       MB_EDIT = 02 /* may edit messages in mailbox */
 1227    } mb_perm;
 1228    int mb_threaded; /* mailbox has been threaded */
 1229 #ifdef mx_HAVE_IMAP
 1230    enum mbflags{
 1231       MB_NOFLAGS = 000,
 1232       MB_UIDPLUS = 001, /* supports IMAP UIDPLUS */
 1233       MB_SASL_IR = 002  /* supports RFC 4959 SASL-IR */
 1234    } mb_flags;
 1235    u64 mb_uidvalidity; /* IMAP unique identifier validity */
 1236    char *mb_imap_account; /* name of current IMAP account */
 1237    char *mb_imap_pass; /* xxx v15-compat URL workaround */
 1238    char *mb_imap_mailbox; /* name of current IMAP mailbox */
 1239    char *mb_cache_directory; /* name of cache directory */
 1240    char mb_imap_delim[8]; /* Directory separator(s), [0] += replacer */
 1241 #endif
 1242    /* XXX mailbox.mb_accmsg is a hack in so far as the mailbox object should
 1243     * XXX have an on_close event to which that machinery should connect */
 1244    struct mx_dig_msg_ctx *mb_digmsg; /* Open `digmsg' connections */
 1245    struct mx_socket *mb_sock; /* socket structure */
 1246 };
 1247 
 1248 enum needspec{
 1249    NEED_UNSPEC, /* unspecified need, don't fetch */
 1250    NEED_HEADER, /* need the header of a message */
 1251    NEED_BODY /* need header and body of a message */
 1252 };
 1253 
 1254 enum content_info{
 1255    CI_NOTHING, /* Nothing downloaded yet */
 1256    CI_HAVE_HEADER = 1u<<0, /* Header is downloaded */
 1257    CI_HAVE_BODY = 1u<<1, /* Entire message is downloaded */
 1258    CI_HAVE_MASK = CI_HAVE_HEADER | CI_HAVE_BODY,
 1259    CI_MIME_ERRORS = 1u<<2, /* Defective MIME structure */
 1260    CI_EXPANDED = 1u<<3, /* Container part (pk7m) exploded into X */
 1261    CI_SIGNED = 1u<<4, /* Has a signature.. */
 1262    CI_SIGNED_OK = 1u<<5, /* ..verified ok.. */
 1263    CI_SIGNED_BAD = 1u<<6, /* ..verified bad (missing key).. */
 1264    CI_ENCRYPTED = 1u<<7, /* Is encrypted.. */
 1265    CI_ENCRYPTED_OK = 1u<<8, /* ..decryption possible/ok.. */
 1266    CI_ENCRYPTED_BAD = 1u<<9 /* ..not possible/ok */
 1267 };
 1268 
 1269 /* Note: flags that are used in obs-imap-cache.c may not change */
 1270 enum mflag{
 1271    MUSED = 1u<<0, /* entry is used, but this bit isn't */
 1272    MDELETED = 1u<<1, /* entry has been deleted */
 1273    MSAVED = 1u<<2, /* entry has been saved */
 1274    MTOUCH = 1u<<3, /* entry has been noticed */
 1275    MPRESERVE = 1u<<4, /* keep entry in sys mailbox */
 1276    MMARK = 1u<<5, /* message is marked! */
 1277    MODIFY = 1u<<6, /* message has been modified */
 1278    MNEW = 1u<<7, /* message has never been seen */
 1279    MREAD = 1u<<8, /* message has been read sometime. */
 1280    MSTATUS = 1u<<9, /* message status has changed */
 1281    MBOX = 1u<<10, /* Send this to mbox, regardless */
 1282    MNOFROM = 1u<<11, /* no From line */
 1283    MHIDDEN = 1u<<12, /* message is hidden to user */
 1284 MFULLYCACHED = 1u<<13, /* IMAP cached */
 1285    MBOXED = 1u<<14, /* message has been sent to mbox */
 1286 MUNLINKED = 1u<<15, /* Unlinked from IMAP cache */
 1287    MNEWEST = 1u<<16, /* message is very new (newmail) */
 1288    MFLAG = 1u<<17, /* message has been flagged recently */
 1289    MUNFLAG = 1u<<18, /* message has been unflagged */
 1290    MFLAGGED = 1u<<19, /* message is `flagged' */
 1291    MANSWER = 1u<<20, /* message has been answered recently */
 1292    MUNANSWER = 1u<<21, /* message has been unanswered */
 1293    MANSWERED = 1u<<22, /* message is `answered' */
 1294    MDRAFT = 1u<<23, /* message has been drafted recently */
 1295    MUNDRAFT = 1u<<24, /* message has been undrafted */
 1296    MDRAFTED = 1u<<25, /* message is marked as `draft' */
 1297    MOLDMARK = 1u<<26, /* messages was marked previously */
 1298    MSPAM = 1u<<27, /* message is classified as spam */
 1299    MSPAMUNSURE = 1u<<28, /* message may be spam, but it is unsure */
 1300 
 1301    /* The following are hacks in so far as they let imagine what the future
 1302     * will bring, without doing this already today */
 1303    MBADFROM_ = 1u<<29, /* From_ line must be replaced */
 1304    MDISPLAY = 1u<<30 /* Display content of this part */
 1305 };
 1306 #define MMNORM (MDELETED | MSAVED | MHIDDEN)
 1307 #define MMNDEL (MDELETED | MHIDDEN)
 1308 
 1309 #define visible(mp) (((mp)->m_flag & MMNDEL) == 0)
 1310 
 1311 struct mimepart{
 1312    enum mflag m_flag;
 1313    enum content_info m_content_info;
 1314 #ifdef mx_HAVE_SPAM
 1315    u32 m_spamscore; /* Spam score as int, 24:8 bits */
 1316 #else
 1317    u8 m__pad1[4];
 1318 #endif
 1319    int m_block; /* Block number of this part */
 1320    uz m_offset; /* Offset in block of part */
 1321    uz m_size; /* Bytes in the part */
 1322    uz m_xsize; /* Bytes in the full part */
 1323    long m_lines; /* Lines in the message; wire format! */
 1324    long m_xlines; /* Lines in the full message; ditto */
 1325    time_t m_time; /* Time the message was sent */
 1326    char const *m_from; /* Message sender */
 1327    struct mimepart *m_nextpart; /* Next part at same level */
 1328    struct mimepart *m_multipart; /* Parts of multipart */
 1329    struct mimepart *m_parent; /* Enclosing multipart part */
 1330    char const *m_ct_type; /* Content-type */
 1331    char const *m_ct_type_plain; /* Content-type without specs */
 1332    char const *m_ct_type_usr_ovwr; /* Forcefully overwritten one */
 1333    char const *m_charset;
 1334    char const *m_ct_enc; /* Content-Transfer-Encoding */
 1335    u32 m_mimetype; /* enum mx_mimetype */
 1336    enum mime_enc m_mime_enc; /* ..in enum */
 1337    char *m_partstring; /* Part level string */
 1338    char *m_filename; /* ..of attachment */
 1339    char const *m_content_description;
 1340    char const *m_external_body_url; /* message/external-body:access-type=URL */
 1341    struct mx_mimetype_handler *m_handler; /* MIME handler if yet classified */
 1342 };
 1343 
 1344 struct message{
 1345    enum mflag m_flag; /* flags */
 1346    enum content_info m_content_info;
 1347 #ifdef mx_HAVE_SPAM
 1348    u32 m_spamscore; /* Spam score as int, 24:8 bits */
 1349 #else
 1350    u8 m__pad1[4];
 1351 #endif
 1352    int m_block; /* block number of this message */
 1353    uz m_offset; /* offset in block of message */
 1354    uz m_size; /* Bytes in the message */
 1355    uz m_xsize; /* Bytes in the full message */
 1356    long m_lines; /* Lines in the message */
 1357    long m_xlines; /* Lines in the full message */
 1358    time_t m_time; /* time the message was sent */
 1359    time_t m_date; /* time in the 'Date' field */
 1360 #ifdef mx_HAVE_IMAP
 1361    u64 m_uid; /* IMAP unique identifier */
 1362 #endif
 1363 #ifdef mx_HAVE_MAILDIR
 1364    char const *m_maildir_file; /* original maildir file of msg */
 1365    u32 m_maildir_hash; /* hash of file name in maildir sub */
 1366 #endif
 1367    int m_collapsed; /* collapsed thread information */
 1368    unsigned m_idhash; /* hash on Message-ID for threads */
 1369    unsigned m_level; /* thread level of message */
 1370    long m_threadpos; /* position in threaded display */
 1371    struct message *m_child; /* first child of this message */
 1372    struct message *m_younger; /* younger brother of this message */
 1373    struct message *m_elder; /* elder brother of this message */
 1374    struct message *m_parent; /* parent of this message */
 1375 };
 1376 
 1377 /* Given a file address, determine the block number it represents */
 1378 #define mailx_blockof(off) S(int,(off) / 4096)
 1379 #define mailx_offsetof(off) S(int,(off) % 4096)
 1380 #define mailx_positionof(block, offset) (S(off_t,block) * 4096 + (offset))
 1381 
 1382 enum gfield{ /* TODO -> enum m_grab_head, m_GH_xy */
 1383    GNONE,
 1384    GTO = 1u<<0, /* Grab To: line */
 1385    GSUBJECT = 1u<<1, /* Likewise, Subject: line */
 1386    GCC = 1u<<2, /* And the Cc: line */
 1387    GBCC = 1u<<3, /* And also the Bcc: line */
 1388 
 1389    GNL = 1u<<4, /* Print blank line after */
 1390    GDEL = 1u<<5, /* Entity removed from list */
 1391    GCOMMA = 1u<<6, /* detract() puts in commas */
 1392    GUA = 1u<<7, /* User-Agent field */
 1393    GMIME = 1u<<8, /* MIME 1.0 fields */
 1394    GMSGID = 1u<<9, /* a Message-ID */
 1395    GNAMEONLY = 1u<<10, /* detract() does NOT use fullnames */
 1396 
 1397    GIDENT = 1u<<11, /* From:, Reply-To:, MFT: (user headers) */
 1398    GREF = 1u<<12, /* References:, In-Reply-To:, (Message-ID:) */
 1399    GREF_IRT = 1u<<30, /* XXX Hack; only In-Reply-To: -> n_run_editor() */
 1400    GDATE = 1u<<13, /* Date: field */
 1401    GFULL = 1u<<14, /* Include full names, comments etc. */
 1402    GSKIN = 1u<<15, /* Skin names */
 1403    GEXTRA = 1u<<16, /* Extra fields (mostly like GIDENT XXX) */
 1404    GFILES = 1u<<17, /* Include filename and pipe addresses */
 1405    GFULLEXTRA = 1u<<18, /* Only with GFULL: GFULL less address */
 1406    GBCC_IS_FCC = 1u<<19, /* This GBCC is (or was) indeed a Fcc: */
 1407    GSHEXP_PARSE_HACK = 1u<<20, /* lextract()+: *expandaddr*=shquote */
 1408    /* All given input (nalloc() etc.) to be interpreted as a single address */
 1409    GNOT_A_LIST = 1u<<21,
 1410    GNULL_OK = 1u<<22, /* NULL return OK for nalloc()+ */
 1411    /* HACK: support "|bla", i.e., anything enclosed in quotes; e.g., used for
 1412     * MTA alias parsing */
 1413    GQUOTE_ENCLOSED_OK = 1u<<23
 1414 };
 1415 #define GMASK (GTO | GSUBJECT | GCC | GBCC)
 1416 
 1417 enum header_flags{
 1418    HF_NONE = 0,
 1419    HF_LIST_REPLY = 1u<<0,
 1420    HF_MFT_SENDER = 1u<<1, /* Add ourselves to Mail-Followup-To: */
 1421    HF_RECIPIENT_RECORD = 1u<<10, /* Save message in file named after rec. */
 1422    HF_USER_EDITED = 1u<<11,
 1423    HF__NEXT_SHIFT = 16u
 1424 };
 1425 
 1426 /* Structure used to pass about the current state of a message (header) */
 1427 struct n_header_field{
 1428    struct n_header_field *hf_next;
 1429    u32 hf_nl; /* Field-name length */
 1430    u32 hf_bl; /* Field-body length*/
 1431    char hf_dat[VFIELD_SIZE(0)];
 1432 };
 1433 
 1434 struct header{
 1435    u32 h_flags; /* enum header_flags bits */
 1436    u32 h_dummy;
 1437    char *h_subject; /* Subject string */
 1438    char const *h_charset; /* preferred charset */
 1439    struct mx_name *h_from; /* overridden "From:" field */
 1440    struct mx_name *h_sender; /* overridden "Sender:" field */
 1441    struct mx_name *h_to; /* Dynamic "To:" string */
 1442    struct mx_name *h_cc; /* Carbon copies string */
 1443    struct mx_name *h_bcc; /* Blind carbon copies */
 1444    struct mx_name *h_fcc; /* Fcc: file carbon copies to */
 1445    struct mx_name *h_ref; /* References (possibly overridden) */
 1446    struct mx_attachment *h_attach; /* MIME attachments */
 1447    struct mx_name *h_reply_to; /* overridden "Reply-To:" field */
 1448    struct mx_name *h_message_id; /* overridden "Message-ID:" field */
 1449    struct mx_name *h_in_reply_to;/* overridden "In-Reply-To:" field */
 1450    struct mx_name *h_mft; /* Mail-Followup-To */
 1451    char const *h_list_post; /* Address from List-Post:, for `Lreply' */
 1452    struct n_header_field *h_user_headers;
 1453    struct n_header_field *h_custom_headers; /* (Cached result) */
 1454    /* Raw/original versions of the header(s). If any */
 1455    char const *h_mailx_command;
 1456    struct mx_name *h_mailx_raw_to;
 1457    struct mx_name *h_mailx_raw_cc;
 1458    struct mx_name *h_mailx_raw_bcc;
 1459    struct mx_name *h_mailx_orig_sender;
 1460    struct mx_name *h_mailx_orig_from;
 1461    struct mx_name *h_mailx_orig_to;
 1462    struct mx_name *h_mailx_orig_cc;
 1463    struct mx_name *h_mailx_orig_bcc;
 1464 };
 1465 
 1466 struct n_addrguts{
 1467    /* Input string as given (maybe replaced with a fixed one!) */
 1468    char const *ag_input;
 1469    uz ag_ilen; /* su_cs_len() of input */
 1470    uz ag_iaddr_start; /* Start of *addr-spec* in .ag_input */
 1471    uz ag_iaddr_aend; /* ..and one past its end */
 1472    char *ag_skinned; /* Output (alloced if !=.ag_input) */
 1473    uz ag_slen; /* su_cs_len() of .ag_skinned */
 1474    uz ag_sdom_start; /* Start of domain in .ag_skinned, */
 1475    u32 ag_n_flags; /* enum mx_name_flags of .ag_skinned */
 1476 };
 1477 
 1478 struct sendbundle{
 1479    struct header *sb_hp;
 1480    struct mx_name *sb_to;
 1481    FILE *sb_input;
 1482    struct mx_url *sb_urlp; /* Or NIL for file-based MTA */
 1483    struct mx_cred_ctx *sb_credp; /* cred-auth.h not included */
 1484    struct str sb_signer; /* USER@HOST for signing+ */
 1485 };
 1486 
 1487 /* For saving the current directory and later returning */
 1488 struct cw{
 1489 #ifdef mx_HAVE_FCHDIR
 1490    int cw_fd;
 1491 #else
 1492    char cw_wd[PATH_MAX];
 1493 #endif
 1494 };
 1495 
 1496 /*
 1497  * Global variable declarations
 1498  *
 1499  * These become instantiated in main.c.
 1500  */
 1501 
 1502 #undef VL
 1503 #ifdef mx_SOURCE_MASTER
 1504 # ifndef mx_HAVE_AMALGAMATION
 1505 #  define VL
 1506 # else
 1507 #  define VL static
 1508 # endif
 1509 #else
 1510 # define VL extern
 1511 #endif
 1512 
 1513 #define n_empty su_empty
 1514 #ifndef mx_HAVE_AMALGAMATION
 1515 VL char const n_month_names[12 + 1][4];
 1516 VL char const n_weekday_names[7 + 1][4];
 1517 
 1518 VL char const n_uagent[sizeof VAL_UAGENT];
 1519 # ifdef mx_HAVE_UISTRINGS
 1520 VL char const n_error[sizeof n_ERROR];
 1521 # endif
 1522 VL char const n_path_devnull[sizeof n_PATH_DEVNULL];
 1523 VL char const n_0[2];
 1524 VL char const n_1[2];
 1525 VL char const n_m1[3]; /* -1 */
 1526 VL char const n_em[2]; /* Exclamation-mark ! */
 1527 VL char const n_ns[2]; /* Number sign # */
 1528 VL char const n_star[2]; /* Asterisk * */
 1529 VL char const n_hy[2]; /* Hyphen-Minus - */
 1530 VL char const n_qm[2]; /* Question-mark ? */
 1531 VL char const n_at[2]; /* Commercial at @ */
 1532 #endif /* mx_HAVE_AMALGAMATION */
 1533 
 1534 VL FILE *n_stdin;
 1535 VL FILE *n_stdout;
 1536 VL FILE *n_stderr;
 1537 /* XXX Plus mx_tty_fp in tty.h */
 1538 /* XXX *_read_overlay and dig_msg_compose_ctx are hacks caused by missing
 1539  * XXX event driven nature of individual program parts */
 1540 VL void *n_readctl_read_overlay; /* `readctl' XXX HACK */
 1541 
 1542 VL u32 n_mb_cur_max; /* Value of MB_CUR_MAX */
 1543 
 1544 VL gid_t n_group_id; /* getgid() and getuid() */
 1545 VL uid_t n_user_id;
 1546 VL pid_t n_pid; /* getpid() (lazy initialized) */
 1547 
 1548 VL int n_exit_status; /* Program exit status TODO long term: ex_no */
 1549 VL u32 n_poption; /* Bits of enum n_program_option */
 1550 VL struct n_header_field *n_poption_arg_C; /* -C custom header list */
 1551 VL char const *n_poption_arg_Mm; /* Argument for -[Mm] aka n_PO_[Mm]_FLAG */
 1552 VL struct mx_name *n_poption_arg_r; /* Argument to -r option */
 1553 VL char const **n_smopts; /* MTA options from command line */
 1554 VL uz n_smopts_cnt; /* Entries in n_smopts */
 1555 
 1556 /* The current execution data context */
 1557 VL struct n_go_data_ctx *n_go_data;
 1558 VL u32 n_psonce; /* Bits of enum n_program_state_once */
 1559 VL u32 n_pstate; /* Bits of enum n_program_state */
 1560 /* TODO "cmd_tab.h ARG_EM set"-storage (n_[01..]) as long as we don't have a
 1561  * TODO struct CmdCtx where each command has its own ARGC/ARGV, errno and exit
 1562  * TODO status and may-place-in-history bit, need to manage global bypass.. */
 1563 
 1564 #ifdef mx_HAVE_ERRORS
 1565 VL u32 n_pstate_err_cnt; /* What backs $^ERRQUEUE-xy */
 1566 #endif
 1567 
 1568 /* TODO n_pstate_err_no: this should contain the error number in the lower
 1569  * TODO bits, and a suberror in the high bits: offer accessor/setter macros.
 1570  * TODO Like this we could use $^ERR-SUBNO or so to access these from outer
 1571  * TODO space, and could perform much better testing; e.g., too many failures
 1572  * TODO simply result in _INVAL, but what has it been exactly?
 1573  * TODO This will furthermore allow better testing, in that even without
 1574  * TODO uistrings we can test error conditions _exactly_!
 1575  * TODO And change the tests accordingly, even support a mode where our
 1576  * TODO error output is entirely suppressed, so that we _really_ can test
 1577  * TODO and only based upon the subnumber!! */
 1578 VL s32 n_pstate_err_no; /* What backs $! su_ERR_* TODO ..HACK */
 1579 VL s32 n_pstate_ex_no; /* What backs $? n_EX_* TODO ..HACK ->64-bit */
 1580 
 1581 /* XXX stylish sorting */
 1582 VL int msgCount; /* Count of messages read in */
 1583 VL struct mailbox mb; /* Current mailbox */
 1584 VL char mailname[PATH_MAX]; /* Name of current file TODO URL/object*/
 1585 VL char displayname[80 - 16]; /* Prettyfied for display TODO URL/obj*/
 1586 VL char prevfile[PATH_MAX]; /* Name of previous file TODO URL/obj */
 1587 VL off_t mailsize; /* Size of system mailbox */
 1588 VL struct message *dot; /* Pointer to current message */
 1589 VL struct message *prevdot; /* Previous current message */
 1590 VL struct message *message; /* The actual message structure */
 1591 VL struct message *threadroot; /* first threaded message */
 1592 /* getmsglist() 1st marked (for e.g. `Reply') HACK TODO (should be in a ctx) */
 1593 VL struct message *n_msgmark1;
 1594 VL int *n_msgvec; /* Folder setmsize(), list.c res. store */
 1595 #ifdef mx_HAVE_IMAP
 1596 VL int imap_created_mailbox; /* hack to get feedback from imap */
 1597 #endif
 1598 
 1599 VL struct n_header_field *n_customhdr_list; /* *customhdr* list */
 1600 
 1601 VL struct time_current time_current; /* time(3); send: mail1() XXXcarrier */
 1602 
 1603 #ifdef mx_HAVE_TLS
 1604 VL enum n_tls_verify_level n_tls_verify_level; /* TODO local per-context! */
 1605 #endif
 1606 
 1607 VL volatile int interrupts; /* TODO rid! */
 1608 
 1609 /*
 1610  * Finally, let's include the function prototypes XXX embed
 1611  */
 1612 
 1613 #ifndef mx_SOURCE_PS_DOTLOCK_MAIN
 1614 # include "mx/nailfuns.h"
 1615 #endif
 1616 
 1617 #include "su/code-ou.h"
 1618 #endif /* n_NAIL_H */
 1619 /* s-it-mode */