"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.7/nailfuns.h" (16 Feb 2018, 108350 Bytes) of package /linux/misc/s-nail-14.9.7.tar.xz:


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

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Function prototypes and function-alike macros.
    3  *
    4  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    5  * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    6  */
    7 /*
    8  * Copyright (c) 1980, 1993
    9  *      The Regents of the University of California.  All rights reserved.
   10  *
   11  * Redistribution and use in source and binary forms, with or without
   12  * modification, are permitted provided that the following conditions
   13  * are met:
   14  * 1. Redistributions of source code must retain the above copyright
   15  *    notice, this list of conditions and the following disclaimer.
   16  * 2. Redistributions in binary form must reproduce the above copyright
   17  *    notice, this list of conditions and the following disclaimer in the
   18  *    documentation and/or other materials provided with the distribution.
   19  * 3. Neither the name of the University nor the names of its contributors
   20  *    may be used to endorse or promote products derived from this software
   21  *    without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33  * SUCH DAMAGE.
   34  */
   35 
   36 /*
   37  * TODO Convert optional utility+ functions to n_*(); ditto
   38  * TODO else use generic module-specific prefixes: str_(), am[em]_, sm[em]_, ..
   39  */
   40 /* TODO s-it-mode: not really (docu, funnames, funargs, etc) */
   41 
   42 #undef FL
   43 #ifndef HAVE_AMALGAMATION
   44 # define FL                      extern
   45 #else
   46 # define FL                      static
   47 #endif
   48 
   49 /* Memory allocation routines from memory.c offer some debug support */
   50 #ifdef HAVE_MEMORY_DEBUG
   51 # define n_MEMORY_DEBUG_ARGS     , char const *mdbg_file, int mdbg_line
   52 # define n_MEMORY_DEBUG_ARGSCALL , mdbg_file, mdbg_line
   53 #else
   54 # define n_MEMORY_DEBUG_ARGS
   55 # define n_MEMORY_DEBUG_ARGSCALL
   56 #endif
   57 
   58 /*
   59  * Macro-based generics
   60  */
   61 
   62 /* ASCII char classification */
   63 #define n__ischarof(C, FLAGS)  \
   64    (asciichar(C) && (n_class_char[(ui8_t)(C)] & (FLAGS)) != 0)
   65 
   66 #define n_uasciichar(U) ((size_t)(U) <= 0x7F)
   67 #define asciichar(c) ((uc_i)(c) <= 0x7F)
   68 #define alnumchar(c) n__ischarof(c, C_DIGIT | C_OCTAL | C_UPPER | C_LOWER)
   69 #define alphachar(c) n__ischarof(c, C_UPPER | C_LOWER)
   70 #define blankchar(c) n__ischarof(c, C_BLANK)
   71 #define blankspacechar(c) n__ischarof(c, C_BLANK | C_SPACE)
   72 #define cntrlchar(c) n__ischarof(c, C_CNTRL)
   73 #define digitchar(c) n__ischarof(c, C_DIGIT | C_OCTAL)
   74 #define lowerchar(c) n__ischarof(c, C_LOWER)
   75 #define punctchar(c) n__ischarof(c, C_PUNCT)
   76 #define spacechar(c) n__ischarof(c, C_BLANK | C_SPACE | C_WHITE)
   77 #define upperchar(c) n__ischarof(c, C_UPPER)
   78 #define whitechar(c) n__ischarof(c, C_BLANK | C_WHITE)
   79 #define octalchar(c) n__ischarof(c, C_OCTAL)
   80 #define hexchar(c) /* TODO extend bits, add C_HEX */\
   81    (n__ischarof(c, C_DIGIT | C_OCTAL) || ((c) >= 'A' && (c) <= 'F') ||\
   82     ((c) >= 'a' && (c) <= 'f'))
   83 
   84 #define upperconv(c) \
   85    (lowerchar(c) ? (char)((uc_i)(c) - 'a' + 'A') : (char)(c))
   86 #define lowerconv(c) \
   87    (upperchar(c) ? (char)((uc_i)(c) - 'A' + 'a') : (char)(c))
   88 /* RFC 822, 3.2. */
   89 #define fieldnamechar(c) \
   90    (asciichar(c) && (c) > 040 && (c) != 0177 && (c) != ':')
   91 
   92 /* Could the string contain a regular expression?
   93  * NOTE: on change: manual contains several occurrences of this string! */
   94 #define n_is_maybe_regex(S) n_is_maybe_regex_buf(S, UIZ_MAX)
   95 #define n_is_maybe_regex_buf(D,L) n_anyof_buf("^[]*+?|$", D, L)
   96 
   97 /* Single-threaded, use unlocked I/O */
   98 #ifdef HAVE_PUTC_UNLOCKED
   99 # undef getc
  100 # define getc(c)        getc_unlocked(c)
  101 # undef putc
  102 # define putc(c, f)     putc_unlocked(c, f)
  103 #endif
  104 
  105 /* There are problems with dup()ing of file-descriptors for child processes.
  106  * We have to somehow accomplish that the FILE* fp makes itself comfortable
  107  * with the *real* offset of the underlaying file descriptor.
  108  * POSIX Issue 7 overloaded fflush(3): if used on a readable stream, then
  109  *
  110  *    if the file is not already at EOF, and the file is one capable of
  111  *    seeking, the file offset of the underlying open file description shall
  112  *    be set to the file position of the stream */
  113 #if defined _POSIX_VERSION && _POSIX_VERSION + 0 >= 200809L
  114 # define n_real_seek(FP,OFF,WH) (fseek(FP, OFF, WH) != -1 && fflush(FP) != EOF)
  115 # define really_rewind(stream) \
  116 do{\
  117    rewind(stream);\
  118    fflush(stream);\
  119 }while(0)
  120 
  121 #else
  122 # define n_real_seek(FP,OFF,WH) \
  123    (fseek(FP, OFF, WH) != -1 && fflush(FP) != EOF &&\
  124       lseek(fileno(FP), OFF, WH) != -1)
  125 # define really_rewind(stream) \
  126 do{\
  127    rewind(stream);\
  128    fflush(stream);\
  129    lseek(fileno(stream), 0, SEEK_SET);\
  130 }while(0)
  131 #endif
  132 
  133 /* fflush() and rewind() */
  134 #define fflush_rewind(stream) \
  135 do{\
  136    fflush(stream);\
  137    rewind(stream);\
  138 }while(0)
  139 
  140 /* Truncate a file to the last character written.  This is useful just before
  141  * closing an old file that was opened for read/write */
  142 #define ftrunc(stream) \
  143 do{\
  144    off_t off;\
  145    fflush(stream);\
  146    off = ftell(stream);\
  147    if(off >= 0)\
  148       ftruncate(fileno(stream), off);\
  149 }while(0)
  150 
  151 # define n_fd_cloexec_set(FD) \
  152 do{\
  153       int a__fd = (FD)/*, a__fl*/;\
  154       /*if((a__fl = fcntl(a__fd, F_GETFD)) != -1 && !(a__fl & FD_CLOEXEC))*/\
  155          (void)fcntl(a__fd, F_SETFD, FD_CLOEXEC);\
  156 }while(0)
  157 
  158 /*
  159  * accmacvar.c
  160  */
  161 
  162 /* Macros: `define', `undefine', `call', `call_if' */
  163 FL int c_define(void *v);
  164 FL int c_undefine(void *v);
  165 FL int c_call(void *v);
  166 FL int c_call_if(void *v);
  167 
  168 /* Accounts: `account', `unaccount' */
  169 FL int c_account(void *v);
  170 FL int c_unaccount(void *v);
  171 
  172 /* `localopts', `shift', `return' */
  173 FL int c_localopts(void *vp);
  174 FL int c_shift(void *vp);
  175 FL int c_return(void *vp);
  176 
  177 /* TODO Check whether a *folder-hook* exists for the currently active mailbox */
  178 FL bool_t temporary_folder_hook_check(bool_t nmail);
  179 FL void temporary_folder_hook_unroll(void); /* XXX im. hack */
  180 
  181 /* TODO v15 drop Invoke compose hook macname */
  182 FL void temporary_compose_mode_hook_call(char const *macname,
  183             void (*hook_pre)(void *), void *hook_arg);
  184 FL void temporary_compose_mode_hook_unroll(void);
  185 
  186 /* Can name freely be used as a variable by users? */
  187 FL bool_t n_var_is_user_writable(char const *name);
  188 
  189 /* Don't use n_var_* unless you *really* have to! */
  190 
  191 /* Constant option key look/(un)set/clear */
  192 FL char *n_var_oklook(enum okeys okey);
  193 #define ok_blook(C) (n_var_oklook(n_CONCAT(ok_b_, C)) != NULL)
  194 #define ok_vlook(C) n_var_oklook(n_CONCAT(ok_v_, C))
  195 
  196 FL bool_t n_var_okset(enum okeys okey, uintptr_t val);
  197 #define ok_bset(C) \
  198    n_var_okset(n_CONCAT(ok_b_, C), (uintptr_t)TRU1)
  199 #define ok_vset(C,V) \
  200    n_var_okset(n_CONCAT(ok_v_, C), (uintptr_t)(V))
  201 
  202 FL bool_t n_var_okclear(enum okeys okey);
  203 #define ok_bclear(C) n_var_okclear(n_CONCAT(ok_b_, C))
  204 #define ok_vclear(C) n_var_okclear(n_CONCAT(ok_v_, C))
  205 
  206 /* Variable option key lookup/(un)set/clear.
  207  * If try_getenv is true we'll getenv(3) _if_ vokey is not a known enum okey.
  208  * _vexplode() is to be used by the shell expansion stuff when encountering
  209  * ${@} in double-quotes, in order to provide sh(1)ell compatible behaviour;
  210  * it returns whether there are any elements in argv (*cookie) */
  211 FL char const *n_var_vlook(char const *vokey, bool_t try_getenv);
  212 FL bool_t n_var_vexplode(void const **cookie);
  213 FL bool_t n_var_vset(char const *vokey, uintptr_t val);
  214 FL bool_t n_var_vclear(char const *vokey);
  215 
  216 /* Special case to handle the typical [xy-USER@HOST,] xy-HOST and plain xy
  217  * variable chains; oxm is a bitmix which tells which combinations to test */
  218 #ifdef HAVE_SOCKETS
  219 FL char *n_var_xoklook(enum okeys okey, struct url const *urlp,
  220             enum okey_xlook_mode oxm);
  221 # define xok_BLOOK(C,URL,M) (n_var_xoklook(C, URL, M) != NULL)
  222 # define xok_VLOOK(C,URL,M) n_var_xoklook(C, URL, M)
  223 # define xok_blook(C,URL,M) xok_BLOOK(n_CONCAT(ok_b_, C), URL, M)
  224 # define xok_vlook(C,URL,M) xok_VLOOK(n_CONCAT(ok_v_, C), URL, M)
  225 #endif
  226 
  227 /* User variable access: `set', `local' and `unset' */
  228 FL int c_set(void *vp);
  229 FL int c_local(void *vp);
  230 FL int c_unset(void *vp);
  231 
  232 /* `varshow' */
  233 FL int c_varshow(void *v);
  234 
  235 /* Ditto: `varedit' */
  236 FL int c_varedit(void *v);
  237 
  238 /* `environ' */
  239 FL int c_environ(void *v);
  240 
  241 /* `vexpr' */
  242 FL int c_vexpr(void *v);
  243 
  244 /* `vpospar' */
  245 FL int c_vpospar(void *v);
  246 
  247 /*
  248  * attachment.c
  249  * xxx Interface quite sick
  250  */
  251 
  252 /* Try to add an attachment for file, fexpand(_LOCAL|_NOPROTO)ed.
  253  * Return the new aplist aphead.
  254  * The newly created attachment may be stored in *newap, or NULL on error */
  255 FL struct attachment *n_attachment_append(struct attachment *aplist,
  256                         char const *file, enum n_attach_error *aerr_or_null,
  257                         struct attachment **newap_or_null);
  258 
  259 /* Shell-token parse names, and append resulting file names to aplist, return
  260  * (new) aplist head */
  261 FL struct attachment *n_attachment_append_list(struct attachment *aplist,
  262                         char const *names);
  263 
  264 /* Remove ap from aplist, and return the new aplist head */
  265 FL struct attachment *n_attachment_remove(struct attachment *aplist,
  266                         struct attachment *ap);
  267 
  268 /* Find by file-name.  If any path component exists in name then an exact match
  269  * of the creation-path is used directly; if instead the basename of that path
  270  * matches all attachments are traversed to find an exact match first, the
  271  * first of all basename matches is returned as a last resort;
  272  * If no path component exists the filename= parameter is searched (and also
  273  * returned) in preference over the basename, otherwise likewise.
  274  * If name is in fact a message number the first match is taken.
  275  * If stat_or_null is given: FAL0 on NULL return, TRU1 for exact/single match,
  276  * TRUM1 for ambiguous matches */
  277 FL struct attachment *n_attachment_find(struct attachment *aplist,
  278                         char const *name, bool_t *stat_or_null);
  279 
  280 /* Interactively edit the attachment list, return updated list */
  281 FL struct attachment *n_attachment_list_edit(struct attachment *aplist,
  282                         enum n_go_input_flags gif);
  283 
  284 /* Print all attachments to fp, return number of lines written, -1 on error */
  285 FL ssize_t n_attachment_list_print(struct attachment const *aplist, FILE *fp);
  286 
  287 /*
  288  * auxlily.c
  289  */
  290 
  291 /* setlocale(3), *ttycharset* etc. */
  292 FL void n_locale_init(void);
  293 
  294 /* Compute screen size */
  295 FL size_t n_screensize(void);
  296 
  297 /* Get our $PAGER; if env_addon is not NULL it is checked whether we know about
  298  * some environment variable that supports colour+ and set *env_addon to that,
  299  * e.g., "LESS=FRSXi" */
  300 FL char const *n_pager_get(char const **env_addon);
  301 
  302 /* Use a pager or STDOUT to print *fp*; if *lines* is 0, they'll be counted */
  303 FL void        page_or_print(FILE *fp, size_t lines);
  304 
  305 /* Parse name and guess at the required protocol.
  306  * If check_stat is true then stat(2) will be consulted - a TODO c..p hack
  307  * TODO that together with *newfolders*=maildir adds Maildir support; sigh!
  308  * If try_hooks is set check_stat is implied and if the stat(2) fails all
  309  * file-hook will be tried in order to find a supported version of name.
  310  * If adjusted_or_null is not NULL it will be set to the final version of name
  311  * this function knew about: a %: FEDIT_SYSBOX prefix is forgotten, in case
  312  * a hook is needed the "real" filename will be placed.
  313  * TODO This c..p should be URL::from_string()->protocol() or something! */
  314 FL enum protocol  which_protocol(char const *name, bool_t check_stat,
  315                      bool_t try_hooks, char const **adjusted_or_null);
  316 
  317 /* Hexadecimal itoa (NUL terminates) / atoi (-1 on error) */
  318 FL char *      n_c_to_hex_base16(char store[3], char c);
  319 FL si32_t      n_c_from_hex_base16(char const hex[2]);
  320 
  321 /* Decode clen (or strlen() if UIZ_MAX) bytes of cbuf into an integer
  322  * according to idm, store a/the result in *resp (in _EINVAL case an overflow
  323  * constant is assigned, for signed types it depends on parse state w. MIN/MAX),
  324  * which must point to storage of the correct type, and return the result state.
  325  * If endptr_or_null is set it will be set to the byte where parsing stopped */
  326 FL enum n_idec_state n_idec_buf(void *resp, char const *cbuf, uiz_t clen,
  327                         ui8_t base, enum n_idec_mode idm,
  328                         char const **endptr_or_null);
  329 #define n_idec_cp(RP,CBP,B,M,CLP) n_idec_buf(RP, CBP, UIZ_MAX, B, M, CLP)
  330 
  331 #define n_idec_ui8_cp(RP,CBP,B,CLP) \
  332    n_idec_buf(RP, CBP, UIZ_MAX, B, (n_IDEC_MODE_LIMIT_8BIT), CLP)
  333 #define n_idec_si8_cp(RP,CBP,B,CLP) \
  334    n_idec_buf(RP, CBP, UIZ_MAX, B,\
  335       (n_IDEC_MODE_SIGNED_TYPE | n_IDEC_MODE_LIMIT_8BIT), CLP)
  336 #define n_idec_ui16_cp(RP,CBP,B,CLP) \
  337    n_idec_buf(RP, CBP, UIZ_MAX, B, (n_IDEC_MODE_LIMIT_16BIT), CLP)
  338 #define n_idec_si16_cp(RP,CBP,B,CLP) \
  339    n_idec_buf(RP, CBP, UIZ_MAX, B,\
  340       (n_IDEC_MODE_SIGNED_TYPE | n_IDEC_MODE_LIMIT_16BIT), CLP)
  341 #define n_idec_ui32_cp(RP,CBP,B,CLP) \
  342    n_idec_buf(RP, CBP, UIZ_MAX, B, (n_IDEC_MODE_LIMIT_32BIT), CLP)
  343 #define n_idec_si32_cp(RP,CBP,B,CLP) \
  344    n_idec_buf(RP, CBP, UIZ_MAX, B,\
  345       (n_IDEC_MODE_SIGNED_TYPE | n_IDEC_MODE_LIMIT_32BIT), CLP)
  346 #define n_idec_ui64_cp(RP,CBP,B,CLP) \
  347    n_idec_buf(RP, CBP, UIZ_MAX, B, 0, CLP)
  348 #define n_idec_si64_cp(RP,CBP,B,CLP) \
  349    n_idec_buf(RP, CBP, UIZ_MAX, B, (n_IDEC_MODE_SIGNED_TYPE), CLP)
  350 #if UIZ_MAX == UI32_MAX
  351 # define n_idec_uiz_cp(RP,CBP,B,CLP) \
  352    n_idec_buf(RP, CBP, UIZ_MAX, B, (n_IDEC_MODE_LIMIT_32BIT), CLP)
  353 # define n_idec_siz_cp(RP,CBP,B,CLP) \
  354    n_idec_buf(RP, CBP, UIZ_MAX, B,\
  355       (n_IDEC_MODE_SIGNED_TYPE | n_IDEC_MODE_LIMIT_32BIT), CLP)
  356 #else
  357 # define n_idec_uiz_cp(RP,CBP,B,CLP) \
  358    n_idec_buf(RP, CBP, UIZ_MAX, B, 0, CLP)
  359 # define n_idec_siz_cp(RP,CBP,B,CLP) \
  360    n_idec_buf(RP, CBP, UIZ_MAX, B, (n_IDEC_MODE_SIGNED_TYPE), CLP)
  361 #endif
  362 
  363 /* Encode an integer value according to base (2-36) and mode iem, return
  364  * pointer to starting byte or NULL on error */
  365 FL char *n_ienc_buf(char cbuf[n_IENC_BUFFER_SIZE], ui64_t value, ui8_t base,
  366             enum n_ienc_mode iem);
  367 
  368 /* Hash the passed string -- uses Chris Torek's hash algorithm.
  369  * i*() hashes case-insensitively (ASCII), and *n() uses maximally len bytes;
  370  * if len is UIZ_MAX, we go .), since we anyway stop for NUL */
  371 FL ui32_t n_torek_hash(char const *name);
  372 FL ui32_t n_torek_ihashn(char const *dat, size_t len);
  373 #define n_torek_ihash(CP) n_torek_ihashn(CP, UIZ_MAX)
  374 
  375 /* Find a prime greater than n */
  376 FL ui32_t n_prime_next(ui32_t n);
  377 
  378 /* Return the name of the dead.letter file */
  379 FL char const * n_getdeadletter(void);
  380 
  381 /* Detect and query the hostname to use */
  382 FL char *n_nodename(bool_t mayoverride);
  383 
  384 /* Convert from / to *ttycharset* */
  385 #ifdef HAVE_IDNA
  386 FL bool_t n_idna_to_ascii(struct n_string *out, char const *ibuf, size_t ilen);
  387 /*TODO FL bool_t n_idna_from_ascii(struct n_string *out, char const *ibuf,
  388             size_t ilen);*/
  389 #endif
  390 
  391 /* Get a (pseudo) random string of *len* bytes, _not_ counting the NUL
  392  * terminator, the second returns an n_autorec_alloc()ed buffer.
  393  * If n_PSO_REPRODUCIBLE and reprocnt_or_null not NULL then we produce
  394  * a reproducable string by using and managing that counter instead */
  395 FL char *n_random_create_buf(char *dat, size_t len, ui32_t *reprocnt_or_null);
  396 FL char *n_random_create_cp(size_t len, ui32_t *reprocnt_or_null);
  397 
  398 /* Check whether the argument string is a true (1) or false (0) boolean, or an
  399  * invalid string, in which case -1 is returned; if emptyrv is not -1 then it,
  400  * treated as a boolean, is used as the return value shall inbuf be empty.
  401  * inlen may be UIZ_MAX to force strlen() detection */
  402 FL si8_t       boolify(char const *inbuf, uiz_t inlen, si8_t emptyrv);
  403 
  404 /* Dig a "quadoption" in inbuf (possibly going through getapproval() in
  405  * interactive mode).  Returns a boolean or -1 if inbuf content is invalid;
  406  * if emptyrv is not -1 then it,  treated as a boolean, is used as the return
  407  * value shall inbuf be empty.  If prompt is set it is printed first if intera.
  408  * inlen may be UIZ_MAX to force strlen() detection */
  409 FL si8_t       quadify(char const *inbuf, uiz_t inlen, char const *prompt,
  410                   si8_t emptyrv);
  411 
  412 /* Is the argument "all" (case-insensitive) or "*" */
  413 FL bool_t n_is_all_or_aster(char const *name);
  414 
  415 /* Get seconds since epoch, return pointer to static struct.
  416  * Unless force_update is true we may use the event-loop tick time */
  417 FL struct n_timespec const *n_time_now(bool_t force_update);
  418 #define n_time_epoch() ((time_t)n_time_now(FAL0)->ts_sec)
  419 
  420 /* Update *tc* to now; only .tc_time updated unless *full_update* is true */
  421 FL void        time_current_update(struct time_current *tc,
  422                   bool_t full_update);
  423 
  424 /* ctime(3), but do ensure 26 byte limit, do not crash XXX static buffer.
  425  * NOTE: no trailing newline */
  426 FL char *n_time_ctime(si64_t secsepoch, struct tm const *localtime_or_nil);
  427 
  428 /* Returns 0 if fully slept, number of millis left if ignint is true and we
  429  * were interrupted.  Actual resolution may be second or less.
  430  * Note in case of HAVE_SLEEP this may be SIGALARM based. */
  431 FL uiz_t n_msleep(uiz_t millis, bool_t ignint);
  432 
  433 /* Our error print series..  Note: these reverse scan format in order to know
  434  * whether a newline was included or not -- this affects the output! */
  435 FL void        n_err(char const *format, ...);
  436 FL void        n_verr(char const *format, va_list ap);
  437 
  438 /* ..(for use in a signal handler; to be obsoleted..).. */
  439 FL void        n_err_sighdl(char const *format, ...);
  440 
  441 /* Our perror(3); if errval is 0 n_err_no is used; newline appended */
  442 FL void        n_perr(char const *msg, int errval);
  443 
  444 /* Announce a fatal error (and die); newline appended */
  445 FL void        n_alert(char const *format, ...);
  446 FL void        n_panic(char const *format, ...);
  447 
  448 /* `errors' */
  449 #ifdef HAVE_ERRORS
  450 FL int c_errors(void *vp);
  451 #endif
  452 
  453 /* strerror(3), and enum n_err_number <-> error name conversions */
  454 FL char const *n_err_to_doc(si32_t eno);
  455 FL char const *n_err_to_name(si32_t eno);
  456 FL si32_t n_err_from_name(char const *name);
  457 
  458 /* */
  459 #ifdef HAVE_REGEX
  460 FL char const *n_regex_err_to_doc(const regex_t *rep, int e);
  461 #endif
  462 
  463 /*
  464  * cmd-cnd.c
  465  */
  466 
  467 /* if.elif.else.endif conditional execution.
  468  * _isskip() tests whether current state doesn't allow execution of commands */
  469 FL int c_if(void *v);
  470 FL int c_elif(void *v);
  471 FL int c_else(void *v);
  472 FL int c_endif(void *v);
  473 
  474 FL bool_t n_cnd_if_isskip(void);
  475 
  476 /* An execution context is teared down, and it finds to have an if stack */
  477 FL void n_cnd_if_stack_del(struct n_go_data_ctx *gdcp);
  478 
  479 /*
  480  * cmd-folder.c
  481  */
  482 
  483 /* `file' (`folder') and `File' (`Folder') */
  484 FL int c_file(void *v);
  485 FL int c_File(void *v);
  486 
  487 /* 'newmail' command: Check for new mail without writing old mail back */
  488 FL int c_newmail(void *v);
  489 
  490 /* noop */
  491 FL int c_noop(void *v);
  492 
  493 /* Remove mailbox */
  494 FL int c_remove(void *v);
  495 
  496 /* Rename mailbox */
  497 FL int c_rename(void *v);
  498 
  499 /* List the folders the user currently has */
  500 FL int c_folders(void *v);
  501 
  502 /*
  503  * cmd-headers.c
  504  */
  505 
  506 /* `headers' (show header group, possibly after setting dot) */
  507 FL int c_headers(void *v);
  508 
  509 /* Like c_headers(), but pre-prepared message vector */
  510 FL int print_header_group(int *vector);
  511 
  512 /* Scroll to the next/previous screen */
  513 FL int c_scroll(void *v);
  514 FL int c_Scroll(void *v);
  515 
  516 /* Move the dot up or down by one message */
  517 FL int c_dotmove(void *v);
  518 
  519 /* Print out the headlines for each message in the passed message list */
  520 FL int c_from(void *v);
  521 
  522 /* Print all message in between and including bottom and topx if they are
  523  * visible and either only_marked is false or they are MMARKed */
  524 FL void print_headers(size_t bottom, size_t topx, bool_t only_marked);
  525 
  526 /*
  527  * cmd-message.c
  528  */
  529 
  530 /* Paginate messages, honour/don't honour ignored fields, respectively */
  531 FL int c_more(void *v);
  532 FL int c_More(void *v);
  533 
  534 /* Type out messages, honour/don't honour ignored fields, respectively */
  535 FL int c_type(void *v);
  536 FL int c_Type(void *v);
  537 
  538 /* Show raw message content */
  539 FL int c_show(void *v);
  540 
  541 /* `mimeview' */
  542 FL int c_mimeview(void *vp);
  543 
  544 /* Pipe messages, honour/don't honour ignored fields, respectively */
  545 FL int c_pipe(void *v);
  546 FL int c_Pipe(void *v);
  547 
  548 /* Print the first *toplines* of each desired message */
  549 FL int c_top(void *v);
  550 FL int c_Top(void *v);
  551 
  552 /* If any arguments were given, go to the next applicable argument following
  553  * dot, otherwise, go to the next applicable message.  If given as first
  554  * command with no arguments, print first message */
  555 FL int c_next(void *v);
  556 
  557 /* Print out the value of dot */
  558 FL int c_pdot(void *v);
  559 
  560 /* Print the size of each message */
  561 FL int c_messize(void *v);
  562 
  563 /* Delete messages */
  564 FL int c_delete(void *v);
  565 
  566 /* Delete messages, then type the new dot */
  567 FL int c_deltype(void *v);
  568 
  569 /* Undelete the indicated messages */
  570 FL int c_undelete(void *v);
  571 
  572 /* Touch all the given messages so that they will get mboxed */
  573 FL int c_stouch(void *v);
  574 
  575 /* Make sure all passed messages get mboxed */
  576 FL int c_mboxit(void *v);
  577 
  578 /* Preserve messages, so that they will be sent back to the system mailbox */
  579 FL int c_preserve(void *v);
  580 
  581 /* Mark all given messages as unread */
  582 FL int c_unread(void *v);
  583 
  584 /* Mark all given messages as read */
  585 FL int c_seen(void *v);
  586 
  587 /* Message flag manipulation */
  588 FL int c_flag(void *v);
  589 FL int c_unflag(void *v);
  590 FL int c_answered(void *v);
  591 FL int c_unanswered(void *v);
  592 FL int c_draft(void *v);
  593 FL int c_undraft(void *v);
  594 
  595 /*
  596  * cmd-misc.c
  597  */
  598 
  599 /* `sleep' */
  600 FL int c_sleep(void *v);
  601 
  602 /* `!': process a shell escape by saving signals, ignoring signals and sh -c */
  603 FL int c_shell(void *v);
  604 
  605 /* `shell': fork an interactive shell */
  606 FL int c_dosh(void *v);
  607 
  608 /* `cwd': print user's working directory */
  609 FL int c_cwd(void *v);
  610 
  611 /* `chdir': change user's working directory */
  612 FL int c_chdir(void *v);
  613 
  614 /* `echo' series: expand file names like echo (to stdout/stderr, with/out
  615  * trailing newline) */
  616 FL int c_echo(void *v);
  617 FL int c_echoerr(void *v);
  618 FL int c_echon(void *v);
  619 FL int c_echoerrn(void *v);
  620 
  621 /* `read' */
  622 FL int c_read(void *vp);
  623 
  624 /* `readall' */
  625 FL int c_readall(void *vp);
  626 
  627 /* `version' */
  628 FL int c_version(void *vp);
  629 
  630 /*
  631  * cmd-resend.c
  632  */
  633 
  634 /* All thinkable sorts of `reply' / `respond' and `followup'.. */
  635 FL int c_reply(void *vp);
  636 FL int c_replyall(void *vp);
  637 FL int c_replysender(void *vp);
  638 FL int c_Reply(void *vp);
  639 FL int c_followup(void *vp);
  640 FL int c_followupall(void *vp);
  641 FL int c_followupsender(void *vp);
  642 FL int c_Followup(void *vp);
  643 
  644 /* ..and a mailing-list reply */
  645 FL int c_Lreply(void *vp);
  646 
  647 /* The 'forward' command */
  648 FL int c_forward(void *vp);
  649 
  650 /* Similar to forward, saving the message in a file named after the first
  651  * recipient */
  652 FL int c_Forward(void *vp);
  653 
  654 /* Resend a message list to a third person */
  655 FL int c_resend(void *vp);
  656 
  657 /* Resend a message list to a third person without adding headers */
  658 FL int c_Resend(void *vp);
  659 
  660 /*
  661  * cmd-tab.c
  662  * Actual command table, `help', `list', etc., and the n_cmd_arg() parser.
  663  */
  664 
  665 /* Isolate the command from the arguments, return pointer to end of cmd name */
  666 FL char const *n_cmd_isolate(char const *cmd);
  667 
  668 /* First command which fits for cmd, or NULL */
  669 FL struct n_cmd_desc const *n_cmd_firstfit(char const *cmd);
  670 
  671 /* Get the default command for the empty line */
  672 FL struct n_cmd_desc const *n_cmd_default(void);
  673 
  674 /* Scan an entire command argument line, return whether result can be used,
  675  * otherwise no resources are allocated (in ->cac_arg).
  676  * For _WYSH arguments the flags _TRIM_SPACE (v15 _not_ _TRIM_IFSSPACE) and
  677  * _LOG are implicit, _META_SEMICOLON is starting with the last (non-optional)
  678  * argument, and then a trailing empty argument is ignored, too */
  679 FL bool_t n_cmd_arg_parse(struct n_cmd_arg_ctx *cacp);
  680 
  681 /* Save away the data from autorec memory, and restore it to that.
  682  * The heap storage is a single pointer to be n_free() by users */
  683 FL void *n_cmd_arg_save_to_heap(struct n_cmd_arg_ctx const *cacp);
  684 FL struct n_cmd_arg_ctx *n_cmd_arg_restore_from_heap(void *vp);
  685 
  686 /* Scan out the list of string arguments according to rm, return -1 on error;
  687  * res_dat is NULL terminated unless res_size is 0 or error occurred */
  688 FL int /* TODO v15*/ getrawlist(bool_t wysh, char **res_dat, size_t res_size,
  689                   char const *line, size_t linesize);
  690 
  691 /*
  692  * cmd-write.c
  693  */
  694 
  695 /* Save a message in a file.  Mark the message as saved so we can discard when
  696  * the user quits */
  697 FL int c_save(void *v);
  698 FL int c_Save(void *v);
  699 
  700 /* Copy a message to a file without affected its saved-ness */
  701 FL int c_copy(void *v);
  702 FL int c_Copy(void *v);
  703 
  704 /* Move a message to a file */
  705 FL int c_move(void *v);
  706 FL int c_Move(void *v);
  707 
  708 /* Decrypt and copy a message to a file.  Like plain `copy' at times */
  709 FL int c_decrypt(void *v);
  710 FL int c_Decrypt(void *v);
  711 
  712 /* Write the indicated messages at the end of the passed file name, minus
  713  * header and trailing blank line.  This is the MIME save function */
  714 FL int c_write(void *v);
  715 
  716 /*
  717  * collect.c
  718  */
  719 
  720 /* temporary_compose_mode_hook_call() etc. setter hook */
  721 FL void n_temporary_compose_hook_varset(void *arg);
  722 
  723 /* If quotefile is (char*)-1, stdin will be used, caller has to verify that
  724  * we're not running in interactive mode */
  725 FL FILE *      collect(struct header *hp, int printheaders, struct message *mp,
  726                   char const *quotefile, int doprefix, si8_t *checkaddr_err);
  727 
  728 /*
  729  * colour.c
  730  */
  731 
  732 #ifdef HAVE_COLOUR
  733 /* `(un)?colour' */
  734 FL int c_colour(void *v);
  735 FL int c_uncolour(void *v);
  736 
  737 /* An execution context is teared down, and it finds to have a colour stack.
  738  * Signals are blocked */
  739 FL void n_colour_stack_del(struct n_go_data_ctx *gdcp);
  740 
  741 /* We want coloured output (in this salloc() cycle), pager_used is used to
  742  * test whether *colour-pager* is to be inspected, if fp is given, the reset
  743  * sequence will be written as necessary by _stack_del()
  744  * env_gut() will reset() as necessary if fp is not NULL */
  745 FL void n_colour_env_create(enum n_colour_ctx cctx, FILE *fp,
  746          bool_t pager_used);
  747 FL void n_colour_env_gut(void);
  748 
  749 /* Putting anything (for pens: including NULL) resets current state first */
  750 FL void n_colour_put(enum n_colour_id cid, char const *ctag);
  751 FL void n_colour_reset(void);
  752 
  753 /* Of course temporary only and may return NULL.  Doesn't affect state! */
  754 FL struct str const *n_colour_reset_to_str(void);
  755 
  756 /* A pen is bound to its environment and automatically reclaimed; it may be
  757  * NULL but that can be used anyway for simplicity.
  758  * This includes pen_to_str() -- which doesn't affect state! */
  759 FL struct n_colour_pen *n_colour_pen_create(enum n_colour_id cid,
  760                            char const *ctag);
  761 FL void n_colour_pen_put(struct n_colour_pen *self);
  762 
  763 FL struct str const *n_colour_pen_to_str(struct n_colour_pen *self);
  764 #endif /* HAVE_COLOUR */
  765 
  766 /*
  767  * dotlock.c
  768  */
  769 
  770 /* Aquire a flt lock and create a dotlock file; upon success a registered
  771  * control-pipe FILE* is returned that keeps the link in between us and the
  772  * lock-holding fork(2)ed subprocess (which conditionally replaced itself via
  773  * execv(2) with the privilege-separated dotlock helper program): the lock file
  774  * will be removed once the control pipe is closed via Pclose().
  775  * Will try FILE_LOCK_TRIES times if pollmsecs > 0 (once otherwise).
  776  * If pollmsecs is UIZ_MAX, FILE_LOCK_MILLIS is used.
  777  * If *dotlock_ignore_error* is set (FILE*)-1 will be returned if at least the
  778  * normal file lock could be established, otherwise n_err_no is usable on err */
  779 FL FILE *      n_dotlock(char const *fname, int fd, enum n_file_lock_type flt,
  780                   off_t off, off_t len, size_t pollmsecs);
  781 
  782 /*
  783  * edit.c
  784  */
  785 
  786 /* Edit a message list */
  787 FL int         c_editor(void *v);
  788 
  789 /* Invoke the visual editor on a message list */
  790 FL int         c_visual(void *v);
  791 
  792 /* Run an editor on either size bytes of the file fp (or until EOF if size is
  793  * negative) or on the message mp, and return a new file or NULL on error of if
  794  * the user didn't perform any edits.
  795  * For now we assert that mp==NULL if hp!=NULL, treating this as a special call
  796  * from within compose mode, and giving TRUM1 to puthead().
  797  * Signals must be handled by the caller.  viored is 'e' for ed, 'v' for vi */
  798 FL FILE *      run_editor(FILE *fp, off_t size, int viored, int readonly,
  799                   struct header *hp, struct message *mp,
  800                   enum sendaction action, sighandler_type oldint);
  801 
  802 /*
  803  * filter.c
  804  */
  805 
  806 /* Quote filter */
  807 FL struct quoteflt * quoteflt_dummy(void); /* TODO LEGACY */
  808 FL void        quoteflt_init(struct quoteflt *self, char const *prefix);
  809 FL void        quoteflt_destroy(struct quoteflt *self);
  810 FL void        quoteflt_reset(struct quoteflt *self, FILE *f);
  811 FL ssize_t     quoteflt_push(struct quoteflt *self, char const *dat,
  812                   size_t len);
  813 FL ssize_t     quoteflt_flush(struct quoteflt *self);
  814 
  815 /* (Primitive) HTML tagsoup filter */
  816 #ifdef HAVE_FILTER_HTML_TAGSOUP
  817 /* TODO Because we don't support filter chains yet this filter will be run
  818  * TODO in a dedicated subprocess, driven via a special Popen() mode */
  819 FL int         htmlflt_process_main(void);
  820 
  821 FL void        htmlflt_init(struct htmlflt *self);
  822 FL void        htmlflt_destroy(struct htmlflt *self);
  823 FL void        htmlflt_reset(struct htmlflt *self, FILE *f);
  824 FL ssize_t     htmlflt_push(struct htmlflt *self, char const *dat, size_t len);
  825 FL ssize_t     htmlflt_flush(struct htmlflt *self);
  826 #endif
  827 
  828 /*
  829  * fio.c
  830  */
  831 
  832 /* fgets() replacement to handle lines of arbitrary size and with embedded \0
  833  * characters.
  834  * line - line buffer.  *line may be NULL.
  835  * linesize - allocated size of line buffer.
  836  * count - maximum characters to read.  May be NULL.
  837  * llen - length_of_line(*line).
  838  * fp - input FILE.
  839  * appendnl - always terminate line with \n, append if necessary.
  840  * Manages the n_PS_READLINE_NL hack */
  841 FL char *      fgetline(char **line, size_t *linesize, size_t *count,
  842                   size_t *llen, FILE *fp, int appendnl n_MEMORY_DEBUG_ARGS);
  843 #ifdef HAVE_MEMORY_DEBUG
  844 # define fgetline(A,B,C,D,E,F)   \
  845    fgetline(A, B, C, D, E, F, __FILE__, __LINE__)
  846 #endif
  847 
  848 /* Read up a line from the specified input into the linebuffer.
  849  * Return the number of characters read.  Do not include the newline at EOL.
  850  * n is the number of characters already read and present in *linebuf; it'll be
  851  * treated as _the_ line if no more (successful) reads are possible.
  852  * Manages the n_PS_READLINE_NL hack */
  853 FL int         readline_restart(FILE *ibuf, char **linebuf, size_t *linesize,
  854                   size_t n n_MEMORY_DEBUG_ARGS);
  855 #ifdef HAVE_MEMORY_DEBUG
  856 # define readline_restart(A,B,C,D) \
  857    readline_restart(A, B, C, D, __FILE__, __LINE__)
  858 #endif
  859 
  860 /* Set up the input pointers while copying the mail file into /tmp */
  861 FL void        setptr(FILE *ibuf, off_t offset);
  862 
  863 /* Determine the size of the file possessed by the passed buffer */
  864 FL off_t       fsize(FILE *iob);
  865 
  866 /* Will retry FILE_LOCK_RETRIES times if pollmsecs > 0.
  867  * If pollmsecs is UIZ_MAX, FILE_LOCK_MILLIS is used */
  868 FL bool_t      n_file_lock(int fd, enum n_file_lock_type flt,
  869                   off_t off, off_t len, size_t pollmsecs);
  870 
  871 /*
  872  * folder.c
  873  */
  874 
  875 /* Set up editing on the given file name.
  876  * If the first character of name is %, we are considered to be editing the
  877  * file, otherwise we are reading our mail which has signficance for mbox and
  878  * so forth */
  879 FL int         setfile(char const *name, enum fedit_mode fm);
  880 
  881 FL int         newmailinfo(int omsgCount);
  882 
  883 /* Set the size of the message vector used to construct argument lists to
  884  * message list functions */
  885 FL void        setmsize(int sz);
  886 
  887 /* Logic behind -H / -L invocations */
  888 FL void        print_header_summary(char const *Larg);
  889 
  890 /* Announces the current folder as indicated.
  891  * Is responsible for updating "dot" (after a folder change). */
  892 FL void n_folder_announce(enum n_announce_flags af);
  893 
  894 FL int         getmdot(int nmail);
  895 
  896 FL void        initbox(char const *name);
  897 
  898 /* Determine and expand the current *folder* name, return it (with trailing
  899  * solidus) or the empty string also in case of errors: since POSIX mandates
  900  * a default of CWD if not set etc., that seems to be a valid fallback, then */
  901 FL char const *n_folder_query(void);
  902 
  903 /* Prepare the seekable O_APPEND MBOX fout for appending of another message.
  904  * If st_or_null is not NULL it is assumed to point to an up-to-date status of
  905  * fout, otherwise an internal fstat(2) is performed as necessary.
  906  * Returns n_err_no of error */
  907 FL int n_folder_mbox_prepare_append(FILE *fout, struct stat *st_or_null);
  908 
  909 /*
  910  * go.c
  911  * Program input of all sorts, input lexing, event loops, command evaluation.
  912  * Also alias handling.
  913  */
  914 
  915 /* Setup the run environment; this i *only* for main() */
  916 FL void n_go_init(void);
  917 
  918 /* Interpret user commands.  If stdin is not a tty, print no prompt; return
  919  * whether last processed command returned error; this is *only* for main()! */
  920 FL bool_t n_go_main_loop(void);
  921 
  922 /* Actual cmd input */
  923 
  924 /* */
  925 FL void n_go_input_clearerr(void);
  926 
  927 /* Force n_go_input() to read EOF next */
  928 FL void n_go_input_force_eof(void);
  929 
  930 /* Returns true if force_eof() has been set -- it is set automatically if
  931  * an input context enters EOF state (rather than error, as in ferror(3)) */
  932 FL bool_t n_go_input_is_eof(void);
  933 
  934 /* Force n_go_input() to read that buffer next -- for `history', and the MLE.
  935  * If commit is not true then we'll reenter the line editor with buf as default
  936  * line content.  Only to be used in interactive and non-robot mode! */
  937 FL void n_go_input_inject(enum n_go_input_inject_flags giif, char const *buf,
  938             size_t len);
  939 
  940 /* Read a complete line of input, with editing if interactive and possible.
  941  * If string is set it is used as the initial line content if in interactive
  942  * mode, otherwise this argument is ignored for reproducibility.
  943  * If histok_or_null is set it will be updated to FAL0 if input shall not be
  944  * placed in history.
  945  * Return number of octets or a value <0 on error.
  946  * Note: may use the currently `source'd file stream instead of stdin!
  947  * Manages the n_PS_READLINE_NL hack
  948  * TODO We need an OnReadLineCompletedEvent and drop this function */
  949 FL int n_go_input(enum n_go_input_flags gif, char const *prompt,
  950          char **linebuf, size_t *linesize, char const *string,
  951          bool_t *histok_or_null n_MEMORY_DEBUG_ARGS);
  952 #ifdef HAVE_MEMORY_DEBUG
  953 # define n_go_input(A,B,C,D,E,F) n_go_input(A,B,C,D,E,F,__FILE__,__LINE__)
  954 #endif
  955 
  956 /* Read a line of input, with editing if interactive and possible, return it
  957  * savestr()d or NULL in case of errors or if an empty line would be returned.
  958  * This may only be called from toplevel (not during n_PS_ROBOT).
  959  * If string is set it is used as the initial line content if in interactive
  960  * mode, otherwise this argument is ignored for reproducibility */
  961 FL char *n_go_input_cp(enum n_go_input_flags gif, char const *prompt,
  962             char const *string);
  963 
  964 /* Deal with loading of resource files and dealing with a stack of files for
  965  * the source command */
  966 
  967 /* Load a file of user system startup resources.
  968  * *Only* for main(), returns whether program shall continue */
  969 FL bool_t n_go_load(char const *name);
  970 
  971 /* "Load" all the -X command line definitions in order.
  972  * *Only* for main(), returns whether program shall continue */
  973 FL bool_t n_go_Xargs(char const **lines, size_t cnt);
  974 
  975 /* Pushdown current input file and switch to a new one.  Set the global flag
  976  * n_PS_SOURCING so that others will realize that they are no longer reading
  977  * from a tty (in all probability) */
  978 FL int c_source(void *v);
  979 FL int c_source_if(void *v);
  980 
  981 /* Evaluate a complete macro / a single command.  For the former lines will
  982  * always be free()d, for the latter cmd will always be duplicated internally */
  983 FL bool_t n_go_macro(enum n_go_input_flags gif, char const *name, char **lines,
  984             void (*on_finalize)(void*), void *finalize_arg);
  985 FL bool_t n_go_command(enum n_go_input_flags gif, char const *cmd);
  986 
  987 /* XXX See a_GO_SPLICE in source */
  988 FL void n_go_splice_hack(char const *cmd, FILE *new_stdin, FILE *new_stdout,
  989          ui32_t new_psonce, void (*on_finalize)(void*), void *finalize_arg);
  990 FL void n_go_splice_hack_remove_after_jump(void);
  991 
  992 /* XXX Hack: may we release our (interactive) (terminal) control to a different
  993  * XXX program, e.g., a $PAGER? */
  994 FL bool_t n_go_may_yield_control(void);
  995 
  996 /* `eval' */
  997 FL int c_eval(void *vp);
  998 
  999 /* `xcall' */
 1000 FL int c_xcall(void *vp);
 1001 
 1002 /* `exit' and `quit' commands */
 1003 FL int c_exit(void *vp);
 1004 FL int c_quit(void *vp);
 1005 
 1006 /* `readctl' */
 1007 FL int c_readctl(void *vp);
 1008 
 1009 /*
 1010  * head.c
 1011  */
 1012 
 1013 /* Return the user's From: address(es) */
 1014 FL char const * myaddrs(struct header *hp);
 1015 
 1016 /* Boil the user's From: addresses down to a single one, or use *sender* */
 1017 FL char const * myorigin(struct header *hp);
 1018 
 1019 /* See if the passed line buffer, which may include trailing newline (sequence)
 1020  * is a mail From_ header line according to POSIX ("From ").
 1021  * If check_rfc4155 is true we'll return TRUM1 instead if the From_ line
 1022  * matches POSIX but is _not_ compatible to RFC 4155 */
 1023 FL bool_t      is_head(char const *linebuf, size_t linelen,
 1024                   bool_t check_rfc4155);
 1025 
 1026 /* Savage extract date field from From_ line.  linelen is convenience as line
 1027  * must be terminated (but it may end in a newline [sequence]).
 1028  * Return whether the From_ line was parsed successfully (-1 if the From_ line
 1029  * wasn't really RFC 4155 compliant) */
 1030 FL int         extract_date_from_from_(char const *line, size_t linelen,
 1031                   char datebuf[n_FROM_DATEBUF]);
 1032 
 1033 /* Extract some header fields (see e.g. -t documentation) from a message.
 1034  * If n_poption&n_PO_t_FLAG *and* n_psonce&n_PSO_t_FLAG are both set a number
 1035  * of additional header fields are understood and address joining is performed
 1036  * as necessary, and the subject is treated with additional care, too.
 1037  * If n_psonce&n_PSO_t_FLAG is set but n_PO_t_FLAG is no more, From: will not
 1038  * be assigned no more.
 1039  * This calls expandaddr() on some headers and sets checkaddr_err if that is
 1040  * not NULL -- note it explicitly allows EAF_NAME because aliases are not
 1041  * expanded when this is called! */
 1042 FL void        extract_header(FILE *fp, struct header *hp,
 1043                   si8_t *checkaddr_err);
 1044 
 1045 /* Return the desired header line from the passed message
 1046  * pointer (or NULL if the desired header field is not available).
 1047  * If mult is zero, return the content of the first matching header
 1048  * field only, the content of all matching header fields else */
 1049 FL char *      hfield_mult(char const *field, struct message *mp, int mult);
 1050 #define hfieldX(a, b)            hfield_mult(a, b, 1)
 1051 #define hfield1(a, b)            hfield_mult(a, b, 0)
 1052 
 1053 /* Check whether the passed line is a header line of the desired breed.
 1054  * Return the field body, or 0 */
 1055 FL char const * thisfield(char const *linebuf, char const *field);
 1056 
 1057 /* Get sender's name from this message.  If the message has a bunch of arpanet
 1058  * stuff in it, we may have to skin the name before returning it */
 1059 FL char *      nameof(struct message *mp, int reptype);
 1060 
 1061 /* Start of a "comment".  Ignore it */
 1062 FL char const * skip_comment(char const *cp);
 1063 
 1064 /* Return the start of a route-addr (address in angle brackets), if present */
 1065 FL char const * routeaddr(char const *name);
 1066 
 1067 /* Query *expandaddr*, parse it and return flags.
 1068  * The flags are already adjusted for n_PSO_INTERACTIVE, n_PO_TILDE_FLAG etc. */
 1069 FL enum expand_addr_flags expandaddr_to_eaf(void);
 1070 
 1071 /* Check if an address is invalid, either because it is malformed or, if not,
 1072  * according to eacm.  Return FAL0 when it looks good, TRU1 if it is invalid
 1073  * but the error condition wasn't covered by a 'hard "fail"ure', -1 otherwise */
 1074 FL si8_t       is_addr_invalid(struct name *np,
 1075                   enum expand_addr_check_mode eacm);
 1076 
 1077 /* Does *NP* point to a file or pipe addressee? */
 1078 #define is_fileorpipe_addr(NP)   \
 1079    (((NP)->n_flags & NAME_ADDRSPEC_ISFILEORPIPE) != 0)
 1080 
 1081 /* Return skinned version of *NP*s name */
 1082 #define skinned_name(NP)         \
 1083    (assert((NP)->n_flags & NAME_SKINNED), \
 1084    ((struct name const*)NP)->n_name)
 1085 
 1086 /* Skin an address according to the RFC 822 interpretation of "host-phrase" */
 1087 FL char *      skin(char const *name);
 1088 
 1089 /* Skin *name* and extract the *addr-spec* according to RFC 5322.
 1090  * Store the result in .ag_skinned and also fill in those .ag_ fields that have
 1091  * actually been seen.
 1092  * Return NULL on error, or name again, but which may have been replaced by
 1093  * a version with fixed quotation etc.!
 1094  * issingle_hack is a HACK that allows usage for `addrcodec' */
 1095 FL char const *n_addrspec_with_guts(struct n_addrguts *agp, char const *name,
 1096                   bool_t doskin, bool_t issingle_hack);
 1097 
 1098 /* Fetch the real name from an internet mail address field */
 1099 FL char *      realname(char const *name);
 1100 
 1101 /* Fetch the sender's name from the passed message.  reptype can be
 1102  * 0 -- get sender's name for display purposes
 1103  * 1 -- get sender's name for reply
 1104  * 2 -- get sender's name for Reply */
 1105 FL char *      name1(struct message *mp, int reptype);
 1106 
 1107 /* Trim away all leading Re: etc., return pointer to plain subject.
 1108  * Note it doesn't perform any MIME decoding by itself */
 1109 FL char const *subject_re_trim(char const *cp);
 1110 
 1111 FL int         msgidcmp(char const *s1, char const *s2);
 1112 
 1113 /* Fake Sender for From_ lines if missing, e. g. with POP3 */
 1114 FL char const * fakefrom(struct message *mp);
 1115 
 1116 /* From username Fri Jan  2 20:13:51 2004
 1117  *               |    |    |    |    |
 1118  *               0    5   10   15   20 */
 1119 #if defined HAVE_IMAP_SEARCH || defined HAVE_IMAP
 1120 FL time_t      unixtime(char const *from);
 1121 #endif
 1122 
 1123 FL time_t      rfctime(char const *date);
 1124 
 1125 FL time_t      combinetime(int year, int month, int day,
 1126                   int hour, int minute, int second);
 1127 
 1128 FL void        substdate(struct message *m);
 1129 
 1130 /* TODO Weird thing that tries to fill in From: and Sender: */
 1131 FL void        setup_from_and_sender(struct header *hp);
 1132 
 1133 /* Note: returns 0x1 if both args were NULL */
 1134 FL struct name const * check_from_and_sender(struct name const *fromfield,
 1135                         struct name const *senderfield);
 1136 
 1137 #ifdef HAVE_XSSL
 1138 FL char *      getsender(struct message *m);
 1139 #endif
 1140 
 1141 /* Fill in / reedit the desired header fields */
 1142 FL int         grab_headers(enum n_go_input_flags gif, struct header *hp,
 1143                   enum gfield gflags, int subjfirst);
 1144 
 1145 /* Check whether sep->ss_sexpr (or ->ss_sregex) matches any header of mp.
 1146  * If sep->s_where (or >s_where_wregex) is set, restrict to given headers */
 1147 FL bool_t n_header_match(struct message *mp, struct search_expr const *sep);
 1148 
 1149 /* Verify whether len (UIZ_MAX=strlen) bytes of name form a standard or
 1150  * otherwise known header name (that must not be used as a custom header).
 1151  * Return the (standard) header name, or NULL */
 1152 FL char const *n_header_is_standard(char const *name, size_t len);
 1153 
 1154 /* Add a custom header to the given list, in auto-reclaimed or heap memory */
 1155 FL bool_t n_header_add_custom(struct n_header_field **hflp, char const *dat,
 1156             bool_t heap);
 1157 
 1158 /*
 1159  * ignore.c
 1160  */
 1161 
 1162 /* `(un)?headerpick' */
 1163 FL int c_headerpick(void *vp);
 1164 FL int c_unheaderpick(void *vp);
 1165 
 1166 /* TODO Compat variants of the c_(un)?h*() series,
 1167  * except for `retain' and `ignore', which are standardized */
 1168 FL int c_retain(void *vp);
 1169 FL int c_ignore(void *vp);
 1170 FL int c_unretain(void *vp);
 1171 FL int c_unignore(void *vp);
 1172 
 1173 FL int         c_saveretain(void *v);
 1174 FL int         c_saveignore(void *v);
 1175 FL int         c_unsaveretain(void *v);
 1176 FL int         c_unsaveignore(void *v);
 1177 
 1178 FL int         c_fwdretain(void *v);
 1179 FL int         c_fwdignore(void *v);
 1180 FL int         c_unfwdretain(void *v);
 1181 FL int         c_unfwdignore(void *v);
 1182 
 1183 /* Ignore object lifecycle.  (Most of the time this interface deals with
 1184  * special n_IGNORE_* objects, e.g., n_IGNORE_TYPE, though.)
 1185  * isauto: whether auto-reclaimed storage is to be used for allocations;
 1186  * if so, _del() needn't be called */
 1187 FL struct n_ignore *n_ignore_new(bool_t isauto);
 1188 FL void n_ignore_del(struct n_ignore *self);
 1189 
 1190 /* Are there just _any_ user settings covered by self? */
 1191 FL bool_t n_ignore_is_any(struct n_ignore const *self);
 1192 
 1193 /* Set an entry to retain (or ignore).
 1194  * Returns FAL0 if dat is not a valid header field name or an invalid regular
 1195  * expression, TRU1 if insertion took place, and TRUM1 if already set */
 1196 FL bool_t n_ignore_insert(struct n_ignore *self, bool_t retain,
 1197             char const *dat, size_t len);
 1198 #define n_ignore_insert_cp(SELF,RT,CP) n_ignore_insert(SELF, RT, CP, UIZ_MAX)
 1199 
 1200 /* Returns TRU1 if retained, TRUM1 if ignored, FAL0 if not covered */
 1201 FL bool_t n_ignore_lookup(struct n_ignore const *self, char const *dat,
 1202             size_t len);
 1203 #define n_ignore_lookup_cp(SELF,CP) n_ignore_lookup(SELF, CP, UIZ_MAX)
 1204 #define n_ignore_is_ign(SELF,FDAT,FLEN) \
 1205    (n_ignore_lookup(SELF, FDAT, FLEN) == TRUM1)
 1206 
 1207 /*
 1208  * imap-search.c
 1209  */
 1210 
 1211 /* Return -1 on invalid spec etc., the number of matches otherwise */
 1212 #ifdef HAVE_IMAP_SEARCH
 1213 FL ssize_t     imap_search(char const *spec, int f);
 1214 #endif
 1215 
 1216 /*
 1217  * message.c
 1218  */
 1219 
 1220 /* Return a file buffer all ready to read up the passed message pointer */
 1221 FL FILE *      setinput(struct mailbox *mp, struct message *m,
 1222                   enum needspec need);
 1223 
 1224 /*  */
 1225 FL enum okay   get_body(struct message *mp);
 1226 
 1227 /* Reset (free) the global message array */
 1228 FL void        message_reset(void);
 1229 
 1230 /* Append the passed message descriptor onto the message array; if mp is NULL,
 1231  * NULLify the entry at &[msgCount-1] */
 1232 FL void        message_append(struct message *mp);
 1233 
 1234 /* Append a NULL message */
 1235 FL void        message_append_null(void);
 1236 
 1237 /* Check whether sep->ss_sexpr (or ->ss_sregex) matches mp.  If with_headers is
 1238  * true then the headers will also be searched (as plain text) */
 1239 FL bool_t      message_match(struct message *mp, struct search_expr const *sep,
 1240                bool_t with_headers);
 1241 
 1242 /*  */
 1243 FL struct message * setdot(struct message *mp);
 1244 
 1245 /* Touch the named message by setting its MTOUCH flag.  Touched messages have
 1246  * the effect of not being sent back to the system mailbox on exit */
 1247 FL void        touch(struct message *mp);
 1248 
 1249 /* Convert user string of message numbers and store the numbers into vector.
 1250  * Returns the count of messages picked up or -1 on error */
 1251 FL int         getmsglist(char const *buf, int *vector, int flags);
 1252 
 1253 /* Find the first message whose flags&m==f and return its message number */
 1254 FL int         first(int f, int m);
 1255 
 1256 /* Mark the named message by setting its mark bit */
 1257 FL void        mark(int mesg, int f);
 1258 
 1259 /*
 1260  * maildir.c
 1261  */
 1262 
 1263 FL int         maildir_setfile(char const *name, enum fedit_mode fm);
 1264 
 1265 FL bool_t      maildir_quit(bool_t hold_sigs_on);
 1266 
 1267 FL enum okay   maildir_append(char const *name, FILE *fp, long offset);
 1268 
 1269 FL enum okay   maildir_remove(char const *name);
 1270 
 1271 /*
 1272  * memory.c
 1273  * Heap memory and automatically reclaimed storage, plus pseudo "alloca"
 1274  */
 1275 
 1276 /* Called from the (main)loops upon tick and break-off time to perform debug
 1277  * checking and memory cleanup, including stack-top of auto-reclaimed storage */
 1278 FL void n_memory_reset(void);
 1279 
 1280 /* Fixate the current snapshot of our global auto-reclaimed storage instance,
 1281  * so that further allocations become auto-reclaimed.
 1282  * This is only called from main.c for the global arena */
 1283 FL void n_memory_pool_fixate(void);
 1284 
 1285 /* Lifetime management of a per-execution level arena (to be found in
 1286  * n_go_data_ctx.gdc_mempool, lazy initialized).
 1287  * _push() can be used by anyone to create a new stack layer in the current
 1288  * per-execution level arena, which is layered upon the normal one (usually
 1289  * provided by .gdc__mempool_buf, initialized as necessary).
 1290  * This can be pop()ped again: popping a stack will remove all stacks "above"
 1291  * it, i.e., those which have been pushed thereafter.
 1292  * If NULL is popped then this means that the current per-execution level is
 1293  * left and n_go_data_ctx.gdc_mempool is not NULL; an event loop tick also
 1294  * causes all _push()ed stacks to be dropped (via n_memory_reset()) */
 1295 FL void n_memory_pool_push(void *vp);
 1296 FL void n_memory_pool_pop(void *vp);
 1297 
 1298 /* Generic heap memory */
 1299 
 1300 FL void *n_alloc(size_t s n_MEMORY_DEBUG_ARGS);
 1301 FL void *n_realloc(void *v, size_t s n_MEMORY_DEBUG_ARGS);
 1302 FL void *n_calloc(size_t nmemb, size_t size n_MEMORY_DEBUG_ARGS);
 1303 FL void n_free(void *vp n_MEMORY_DEBUG_ARGS);
 1304 
 1305 /* TODO obsolete c{m,re,c}salloc -> n_* */
 1306 #ifdef HAVE_MEMORY_DEBUG
 1307 # define n_alloc(S) (n_alloc)(S, __FILE__, __LINE__)
 1308 # define n_realloc(P,S) (n_realloc)(P, S, __FILE__, __LINE__)
 1309 # define n_calloc(N,S) (n_calloc)(N, S, __FILE__, __LINE__)
 1310 # define n_free(P) (n_free)(P, __FILE__, __LINE__)
 1311 # define free(P) (n_free)(P, __FILE__, __LINE__)
 1312 #else
 1313 # define n_free(P) free(P)
 1314 #endif
 1315 #define smalloc(SZ) n_alloc(SZ)
 1316 #define srealloc(P,SZ) n_realloc(P, SZ)
 1317 #define scalloc(N,SZ) n_calloc(N, SZ)
 1318 
 1319 /* Fluctuating heap memory (supposed to exist for one command loop tick) */
 1320 
 1321 #define n_flux_alloc(S) n_alloc(S)
 1322 #define n_flux_realloc(P,S) n_realloc(P, S)
 1323 #define n_flux_calloc(N,S) n_calloc(N, S)
 1324 #define n_flux_free(P) n_free(P)
 1325 
 1326 /* Auto-reclaimed storage */
 1327 
 1328 /* Lower memory pressure on auto-reclaimed storage for code which has
 1329  * a sinus-curve looking style of memory usage, i.e., peak followed by release,
 1330  * like, e.g., doing a task on all messages of a box in order.
 1331  * Such code should call _create(), successively call _unroll() after
 1332  * a single message has been handled, and finally _gut() */
 1333 FL void n_autorec_relax_create(void);
 1334 FL void n_autorec_relax_gut(void);
 1335 FL void n_autorec_relax_unroll(void);
 1336 
 1337 /* TODO obsolete srelax -> n_autorec_relax_* */
 1338 #define srelax_hold() n_autorec_relax_create()
 1339 #define srelax_rele() n_autorec_relax_gut()
 1340 #define srelax() n_autorec_relax_unroll()
 1341 
 1342 /* Allocate size more bytes of space and return the address of the first byte
 1343  * to the caller.  An even number of bytes are always allocated so that the
 1344  * space will always be on a word boundary */
 1345 FL void *n_autorec_alloc_from_pool(void *vp, size_t size n_MEMORY_DEBUG_ARGS);
 1346 FL void *n_autorec_calloc_from_pool(void *vp, size_t nmemb, size_t size
 1347             n_MEMORY_DEBUG_ARGS);
 1348 #ifdef HAVE_MEMORY_DEBUG
 1349 # define n_autorec_alloc_from_pool(VP,SZ) \
 1350    (n_autorec_alloc_from_pool)(VP, SZ, __FILE__, __LINE__)
 1351 # define n_autorec_calloc_from_pool(VP,NM,SZ) \
 1352    (n_autorec_calloc_from_pool)(VP, NM, SZ, __FILE__, __LINE__)
 1353 #endif
 1354 #define n_autorec_alloc(SZ) n_autorec_alloc_from_pool(NULL, SZ)
 1355 #define n_autorec_calloc(NM,SZ) n_autorec_calloc_from_pool(NULL, NM, SZ)
 1356 
 1357 /* TODO obsolete c?salloc -> n_autorec_* */
 1358 #define salloc(SZ) n_autorec_alloc_from_pool(NULL, SZ)
 1359 #define csalloc(NM,SZ) n_autorec_calloc_from_pool(NULL, NM, SZ)
 1360 
 1361 /* Pseudo alloca (and also auto-reclaimed in _memory_reset()/_pool_pop()) */
 1362 FL void *n_lofi_alloc(size_t size n_MEMORY_DEBUG_ARGS);
 1363 FL void n_lofi_free(void *vp n_MEMORY_DEBUG_ARGS);
 1364 
 1365 #ifdef HAVE_MEMORY_DEBUG
 1366 # define n_lofi_alloc(SZ) (n_lofi_alloc)(SZ, __FILE__, __LINE__)
 1367 # define n_lofi_free(P) (n_lofi_free)(P, __FILE__, __LINE__)
 1368 #endif
 1369 
 1370 /* The snapshot can be used in a local context, in order to free many
 1371  * allocations in one go */
 1372 FL void *n_lofi_snap_create(void);
 1373 FL void n_lofi_snap_unroll(void *cookie);
 1374 
 1375 /* TODO obsolete ac_alloc / ac_free -> n_lofi_* */
 1376 #define ac_alloc(SZ) n_lofi_alloc(SZ)
 1377 #define ac_free(P) n_lofi_free(P)
 1378 
 1379 /* */
 1380 #ifdef HAVE_MEMORY_DEBUG
 1381 FL int c_memtrace(void *v);
 1382 
 1383 /* For immediate debugging purposes, it is possible to check on request */
 1384 FL bool_t n__memory_check(char const *file, int line);
 1385 # define n_memory_check() n__memory_check(__FILE__, __LINE__)
 1386 #else
 1387 # define n_memory_check() do{;}while(0)
 1388 #endif
 1389 
 1390 /*
 1391  * mime.c
 1392  */
 1393 
 1394 /* *sendcharsets* .. *charset-8bit* iterator; *a_charset_to_try_first* may be
 1395  * used to prepend a charset to this list (e.g., for *reply-in-same-charset*).
 1396  * The returned boolean indicates charset_iter_is_valid().
 1397  * Without HAVE_ICONV, this "iterates" over *ttycharset* only */
 1398 FL bool_t      charset_iter_reset(char const *a_charset_to_try_first);
 1399 FL bool_t      charset_iter_next(void);
 1400 FL bool_t      charset_iter_is_valid(void);
 1401 FL char const * charset_iter(void);
 1402 
 1403 /* And this is (xxx temporary?) which returns the iterator if that is valid and
 1404  * otherwise either *charset-8bit* or *ttycharset*, dep. on HAVE_ICONV */
 1405 FL char const * charset_iter_or_fallback(void);
 1406 
 1407 FL void        charset_iter_recurse(char *outer_storage[2]); /* TODO LEGACY */
 1408 FL void        charset_iter_restore(char *outer_storage[2]); /* TODO LEGACY */
 1409 
 1410 /* Check whether our headers will need MIME conversion */
 1411 #ifdef HAVE_ICONV
 1412 FL char const * need_hdrconv(struct header *hp);
 1413 #endif
 1414 
 1415 /* Convert header fields from RFC 1522 format */
 1416 FL void        mime_fromhdr(struct str const *in, struct str *out,
 1417                   enum tdflags flags);
 1418 
 1419 /* Interpret MIME strings in parts of an address field */
 1420 FL char *      mime_fromaddr(char const *name);
 1421 
 1422 /* fwrite(3) performing the given MIME conversion */
 1423 FL ssize_t     mime_write(char const *ptr, size_t size, FILE *f,
 1424                   enum conversion convert, enum tdflags dflags,
 1425                   struct quoteflt *qf, struct str *outrest,
 1426                   struct str *inrest);
 1427 FL ssize_t     xmime_write(char const *ptr, size_t size, /* TODO LEGACY */
 1428                   FILE *f, enum conversion convert, enum tdflags dflags,
 1429                   struct str *outrest, struct str *inrest);
 1430 
 1431 /*
 1432  * mime-enc.c
 1433  * Content-Transfer-Encodings as defined in RFC 2045 (and RFC 2047):
 1434  * - Quoted-Printable, section 6.7
 1435  * - Base64, section 6.8
 1436  * TODO For now this is pretty mixed up regarding this external interface
 1437  * TODO (and due to that the code is, too).
 1438  * TODO In v15.0 CTE will be filter based, and explicit conversion will
 1439  * TODO gain clear error codes
 1440  */
 1441 
 1442 /* Default MIME Content-Transfer-Encoding: as via *mime-encoding* */
 1443 FL enum mime_enc mime_enc_target(void);
 1444 
 1445 /* Map from a Content-Transfer-Encoding: header body (which may be NULL) */
 1446 FL enum mime_enc mime_enc_from_ctehead(char const *hbody);
 1447 
 1448 /* XXX Try to get rid of that */
 1449 FL char const * mime_enc_from_conversion(enum conversion const convert);
 1450 
 1451 /* How many characters of (the complete body) ln need to be quoted.
 1452  * Only MIMEEF_ISHEAD and MIMEEF_ISENCWORD are understood */
 1453 FL size_t      mime_enc_mustquote(char const *ln, size_t lnlen,
 1454                   enum mime_enc_flags flags);
 1455 
 1456 /* How much space is necessary to encode len bytes in QP, worst case.
 1457  * Includes room for terminator, UIZ_MAX on overflow */
 1458 FL size_t      qp_encode_calc_size(size_t len);
 1459 
 1460 /* If flags includes QP_ISHEAD these assume "word" input and use special
 1461  * quoting rules in addition; soft line breaks are not generated.
 1462  * Otherwise complete input lines are assumed and soft line breaks are
 1463  * generated as necessary.  Return NULL on error (overflow) */
 1464 FL struct str * qp_encode(struct str *out, struct str const *in,
 1465                   enum qpflags flags);
 1466 #ifdef notyet
 1467 FL struct str * qp_encode_cp(struct str *out, char const *cp,
 1468                   enum qpflags flags);
 1469 FL struct str * qp_encode_buf(struct str *out, void const *vp, size_t vp_len,
 1470                   enum qpflags flags);
 1471 #endif
 1472 
 1473 /* The buffers of out and *rest* will be managed via srealloc().
 1474  * If inrest_or_null is needed but NULL an error occurs, otherwise tolerant.
 1475  * Return FAL0 on error; caller is responsible to free buffers */
 1476 FL bool_t      qp_decode_header(struct str *out, struct str const *in);
 1477 FL bool_t      qp_decode_part(struct str *out, struct str const *in,
 1478                   struct str *outrest, struct str *inrest_or_null);
 1479 
 1480 /* How much space is necessary to encode len bytes in Base64, worst case.
 1481  * Includes room for (CR/LF/CRLF and) terminator, UIZ_MAX on overflow */
 1482 FL size_t      b64_encode_calc_size(size_t len);
 1483 
 1484 /* Note these simply convert all the input (if possible), including the
 1485  * insertion of NL sequences if B64_CRLF or B64_LF is set (and multiple thereof
 1486  * if B64_MULTILINE is set).
 1487  * Thus, in the B64_BUF case, better call b64_encode_calc_size() first.
 1488  * Return NULL on error (overflow; cannot happen for B64_BUF) */
 1489 FL struct str * b64_encode(struct str *out, struct str const *in,
 1490                   enum b64flags flags);
 1491 FL struct str * b64_encode_buf(struct str *out, void const *vp, size_t vp_len,
 1492                   enum b64flags flags);
 1493 #ifdef notyet
 1494 FL struct str * b64_encode_cp(struct str *out, char const *cp,
 1495                   enum b64flags flags);
 1496 #endif
 1497 
 1498 /* The _{header,part}() variants are failure tolerant, the latter requires
 1499  * outrest to be set; due to the odd 4:3 relation inrest_or_null should be
 1500  * given, _then_, it is an error if it is needed but not set.
 1501  * TODO pre v15 callers should ensure that no endless loop is entered because
 1502  * TODO the inrest cannot be converted and ends up as inrest over and over:
 1503  * TODO give NULL to stop such loops.
 1504  * The buffers of out and possibly *rest* will be managed via srealloc().
 1505  * Returns FAL0 on error; caller is responsible to free buffers.
 1506  * XXX FAL0 is effectively not returned for _part*() variants,
 1507  * XXX (instead replacement characters are produced for invalid data.
 1508  * XXX _Unless_ operation could EOVERFLOW.)
 1509  * XXX I.e. this is bad and is tolerant for text and otherwise not */
 1510 FL bool_t      b64_decode(struct str *out, struct str const *in);
 1511 FL bool_t      b64_decode_header(struct str *out, struct str const *in);
 1512 FL bool_t      b64_decode_part(struct str *out, struct str const *in,
 1513                   struct str *outrest, struct str *inrest_or_null);
 1514 
 1515 /*
 1516  * mime-param.c
 1517  */
 1518 
 1519 /* Get a mime style parameter from a header body */
 1520 FL char *      mime_param_get(char const *param, char const *headerbody);
 1521 
 1522 /* Format parameter name to have value, salloc() it or NULL (error) in result.
 1523  * 0 on error, 1 or -1 on success: the latter if result contains \n newlines,
 1524  * which it will if the created param requires more than MIME_LINELEN bytes;
 1525  * there is never a trailing newline character */
 1526 /* TODO mime_param_create() should return a StrList<> or something.
 1527  * TODO in fact it should take a HeaderField* and append a HeaderFieldParam*! */
 1528 FL si8_t       mime_param_create(struct str *result, char const *name,
 1529                   char const *value);
 1530 
 1531 /* Get the boundary out of a Content-Type: multipart/xyz header field, return
 1532  * salloc()ed copy of it; store strlen() in *len if set */
 1533 FL char *      mime_param_boundary_get(char const *headerbody, size_t *len);
 1534 
 1535 /* Create a salloc()ed MIME boundary */
 1536 FL char *      mime_param_boundary_create(void);
 1537 
 1538 /*
 1539  * mime-parse.c
 1540  */
 1541 
 1542 /* Create MIME part object tree for and of mp */
 1543 FL struct mimepart * mime_parse_msg(struct message *mp,
 1544                         enum mime_parse_flags mpf);
 1545 
 1546 /*
 1547  * mime-types.c
 1548  */
 1549 
 1550 /* `(un)?mimetype' commands */
 1551 FL int         c_mimetype(void *v);
 1552 FL int         c_unmimetype(void *v);
 1553 
 1554 /* Check whether the Content-Type name is internally known */
 1555 FL bool_t n_mimetype_check_mtname(char const *name);
 1556 
 1557 /* Return a Content-Type matching the name, or NULL if none could be found */
 1558 FL char *n_mimetype_classify_filename(char const *name);
 1559 
 1560 /* Classify content of *fp* as necessary and fill in arguments; **charset* is
 1561  * set to *charset-7bit* or charset_iter_or_fallback() if NULL */
 1562 FL enum conversion n_mimetype_classify_file(FILE *fp, char const **contenttype,
 1563                      char const **charset, int *do_iconv);
 1564 
 1565 /* Dependend on *mime-counter-evidence* mpp->m_ct_type_usr_ovwr will be set,
 1566  * but otherwise mpp is const.  for_user_context rather maps 1:1 to
 1567  * MIME_PARSE_FOR_USER_CONTEXT */
 1568 FL enum mimecontent n_mimetype_classify_part(struct mimepart *mpp,
 1569                         bool_t for_user_context);
 1570 
 1571 /* Query handler for a part, return the plain type (& MIME_HDL_TYPE_MASK).
 1572  * mhp is anyway initialized (mh_flags, mh_msg) */
 1573 FL enum mime_handler_flags n_mimetype_handler(struct mime_handler *mhp,
 1574                               struct mimepart const *mpp,
 1575                               enum sendaction action);
 1576 
 1577 /*
 1578  * nam-a-grp.c
 1579  */
 1580 
 1581 /* Allocate a single element of a name list, initialize its name field to the
 1582  * passed name and return it */
 1583 FL struct name * nalloc(char const *str, enum gfield ntype);
 1584 
 1585 /* Like nalloc(), but initialize from content of np */
 1586 FL struct name * ndup(struct name *np, enum gfield ntype);
 1587 
 1588 /* Concatenate the two passed name lists, return the result */
 1589 FL struct name * cat(struct name *n1, struct name *n2);
 1590 
 1591 /* Duplicate np */
 1592 FL struct name * namelist_dup(struct name const *np, enum gfield ntype);
 1593 
 1594 /* Determine the number of undeleted elements in a name list and return it;
 1595  * the latter also doesn't count file and pipe addressees in addition */
 1596 FL ui32_t      count(struct name const *np);
 1597 FL ui32_t      count_nonlocal(struct name const *np);
 1598 
 1599 /* Extract a list of names from a line, and make a list of names from it.
 1600  * Return the list or NULL if none found */
 1601 FL struct name * extract(char const *line, enum gfield ntype);
 1602 
 1603 /* Like extract() unless line contains anyof ",\"\\(<|", in which case
 1604  * comma-separated list extraction is used instead */
 1605 FL struct name * lextract(char const *line, enum gfield ntype);
 1606 
 1607 /* Turn a list of names into a string of the same names */
 1608 FL char *      detract(struct name *np, enum gfield ntype);
 1609 
 1610 /* Get a lextract() list via n_go_input_cp(), reassigning to *np* */
 1611 FL struct name * grab_names(enum n_go_input_flags gif, char const *field,
 1612                      struct name *np, int comma, enum gfield gflags);
 1613 
 1614 /* Check whether n1 n2 share the domain name */
 1615 FL bool_t      name_is_same_domain(struct name const *n1,
 1616                   struct name const *n2);
 1617 
 1618 /* Check all addresses in np and delete invalid ones; if set_on_error is not
 1619  * NULL it'll be set to TRU1 for error or -1 for "hard fail" error */
 1620 FL struct name * checkaddrs(struct name *np, enum expand_addr_check_mode eacm,
 1621                   si8_t *set_on_error);
 1622 
 1623 /* Vaporise all duplicate addresses in hp (.h_(to|cc|bcc)) so that an address
 1624  * that "first" occurs in To: is solely in there, ditto Cc:, after expanding
 1625  * aliases etc.  eacm and set_on_error are passed to checkaddrs(), metoo is
 1626  * passed to usermap().  After updating hp to the new state this returns
 1627  * a flat list of all addressees, which may be NULL */
 1628 FL struct name * namelist_vaporise_head(struct header *hp,
 1629                   enum expand_addr_check_mode eacm, bool_t metoo,
 1630                   si8_t *set_on_error);
 1631 
 1632 /* Map all of the aliased users in the invoker's mailrc file and insert them
 1633  * into the list */
 1634 FL struct name * usermap(struct name *names, bool_t force_metoo);
 1635 
 1636 /* Remove all of the duplicates from the passed name list by insertion sorting
 1637  * them, then checking for dups.  Return the head of the new list */
 1638 FL struct name * elide(struct name *names);
 1639 
 1640 /* `(un)?alternates' deal with the list of alternate names */
 1641 FL int c_alternates(void *v);
 1642 FL int c_unalternates(void *v);
 1643 
 1644 /* If keep_single is set one alternates member will be allowed in np */
 1645 FL struct name *n_alternates_remove(struct name *np, bool_t keep_single);
 1646 
 1647 /* Likewise, is name an alternate in broadest sense? */
 1648 FL bool_t n_is_myname(char const *name);
 1649 
 1650 /* `addrcodec' */
 1651 FL int c_addrcodec(void *vp);
 1652 
 1653 /* `(un)?commandalias'.
 1654  * And whether a `commandalias' name exists, returning name or NULL, pointing
 1655  * expansion_or_null to expansion if set: both point into internal storage */
 1656 FL int c_commandalias(void *vp);
 1657 FL int c_uncommandalias(void *vp);
 1658 
 1659 FL char const *n_commandalias_exists(char const *name,
 1660                   struct str const **expansion_or_null);
 1661 
 1662 /* Is name a valid alias */
 1663 FL bool_t n_alias_is_valid_name(char const *name);
 1664 
 1665 /* `(un)?alias' */
 1666 FL int         c_alias(void *v);
 1667 FL int         c_unalias(void *v);
 1668 
 1669 /* `(un)?ml(ist|subscribe)', and a check whether a name is a (wanted) list;
 1670  * give MLIST_OTHER to the latter to search for any, in which case all
 1671  * receivers are searched until EOL or MLIST_SUBSCRIBED is seen */
 1672 FL int         c_mlist(void *v);
 1673 FL int         c_unmlist(void *v);
 1674 FL int         c_mlsubscribe(void *v);
 1675 FL int         c_unmlsubscribe(void *v);
 1676 
 1677 FL enum mlist_state is_mlist(char const *name, bool_t subscribed_only);
 1678 FL enum mlist_state is_mlist_mp(struct message *mp, enum mlist_state what);
 1679 
 1680 /* `(un)?shortcut', and check if str is one, return expansion or NULL */
 1681 FL int         c_shortcut(void *v);
 1682 FL int         c_unshortcut(void *v);
 1683 
 1684 FL char const * shortcut_expand(char const *str);
 1685 
 1686 /* `(un)?charsetalias', and try to expand a charset, return mapping or itself */
 1687 FL int c_charsetalias(void *vp);
 1688 FL int c_uncharsetalias(void *vp);
 1689 
 1690 FL char const *n_charsetalias_expand(char const *cp);
 1691 
 1692 /* `(un)?filetype', and check whether file has a known (stat(2)ed) "equivalent",
 1693  * as well as check whether (extension of) file is known, respectively;
 1694  * res_or_null can be NULL, otherwise on success result data must be copied */
 1695 FL int c_filetype(void *vp);
 1696 FL int c_unfiletype(void *vp);
 1697 
 1698 FL bool_t n_filetype_trial(struct n_file_type *res_or_null, char const *file);
 1699 FL bool_t n_filetype_exists(struct n_file_type *res_or_null, char const *file);
 1700 
 1701 /*
 1702  * path.c
 1703  */
 1704 
 1705 /* Test to see if the passed file name is a directory, return true if it is.
 1706  * If check_access is set, we also access(2): if it is TRUM1 only X_OK|R_OK is
 1707  * tested, otherwise X_OK|R_OK|W_OK. */
 1708 FL bool_t n_is_dir(char const *name, bool_t check_access);
 1709 
 1710 /* Recursively create a directory */
 1711 FL bool_t n_path_mkdir(char const *name);
 1712 
 1713 /* Delete a file, but only if the file is a plain file; return FAL0 on system
 1714  * error and TRUM1 if name is not a plain file, return TRU1 on success */
 1715 FL bool_t n_path_rm(char const *name);
 1716 
 1717 /* A get-wd..restore-wd approach */
 1718 FL enum okay   cwget(struct cw *cw);
 1719 FL enum okay   cwret(struct cw *cw);
 1720 FL void        cwrelse(struct cw *cw);
 1721 
 1722 /*
 1723  * pop3.c
 1724  */
 1725 
 1726 #ifdef HAVE_POP3
 1727 /*  */
 1728 FL enum okay   pop3_noop(void);
 1729 
 1730 /*  */
 1731 FL int         pop3_setfile(char const *server, enum fedit_mode fm);
 1732 
 1733 /*  */
 1734 FL enum okay   pop3_header(struct message *m);
 1735 
 1736 /*  */
 1737 FL enum okay   pop3_body(struct message *m);
 1738 
 1739 /*  */
 1740 FL bool_t      pop3_quit(bool_t hold_sigs_on);
 1741 #endif /* HAVE_POP3 */
 1742 
 1743 /*
 1744  * popen.c
 1745  * Subprocesses, popen, but also file handling with registering
 1746  */
 1747 
 1748 /* For program startup in main.c: initialize process manager */
 1749 FL void        n_child_manager_start(void);
 1750 
 1751 /* Notes: OF_CLOEXEC is implied in oflags, xflags may be NULL */
 1752 FL FILE *      safe_fopen(char const *file, char const *oflags, int *xflags);
 1753 
 1754 /* Notes: OF_CLOEXEC|OF_REGISTER are implied in oflags!
 1755  * Exception is Fdopen() if nocloexec is TRU1, but otherwise even for it the fd
 1756  * creator has to take appropriate steps in order to ensure this is true! */
 1757 FL FILE *      Fopen(char const *file, char const *oflags);
 1758 FL FILE *      Fdopen(int fd, char const *oflags, bool_t nocloexec);
 1759 
 1760 FL int         Fclose(FILE *fp);
 1761 
 1762 /* TODO: Should be Mailbox::create_from_url(URL::from_string(DATA))!
 1763  * Open file according to oflags (see popen.c).  Handles compressed files,
 1764  * maildir etc.  If ft_or_null is given it will be filled accordingly */
 1765 FL FILE * n_fopen_any(char const *file, char const *oflags,
 1766             enum n_fopen_state *fs_or_null);
 1767 
 1768 /* Create a temporary file in *TMPDIR*, use namehint for its name (prefix
 1769  * unless OF_SUFFIX is set, in which case namehint is an extension that MUST be
 1770  * part of the resulting filename, otherwise Ftmp() will fail), store the
 1771  * unique name in fn (unless OF_UNLINK is set in oflags), and return a stdio
 1772  * FILE pointer with access oflags.  OF_CLOEXEC is implied in oflags.
 1773  * One of OF_WRONLY and OF_RDWR must be set.  Mode of 0600 is implied */
 1774 FL FILE *      Ftmp(char **fn, char const *namehint, enum oflags oflags);
 1775 
 1776 /* If OF_HOLDSIGS was set when calling Ftmp(), then hold_all_sigs() had been
 1777  * called: call this to unlink(2) and free *fn and to rele_all_sigs() */
 1778 FL void        Ftmp_release(char **fn);
 1779 
 1780 /* Free the resources associated with the given filename.  To be called after
 1781  * unlink() */
 1782 FL void        Ftmp_free(char **fn);
 1783 
 1784 /* Create a pipe and ensure CLOEXEC bit is set in both descriptors */
 1785 FL bool_t      pipe_cloexec(int fd[2]);
 1786 
 1787 /*
 1788  * env_addon may be NULL, otherwise it is expected to be a NULL terminated
 1789  * array of "K=V" strings to be placed into the childs environment.
 1790  * If cmd==(char*)-1 then shell is indeed expected to be a PTF :P that will be
 1791  * called from within the child process.
 1792  * n_psignal() takes a FILE* returned by Popen, and returns <0 if no process
 1793  * can be found, 0 on success, and an errno number on kill(2) failure */
 1794 FL FILE *Popen(char const *cmd, char const *mode, char const *shell,
 1795             char const **env_addon, int newfd1);
 1796 FL bool_t Pclose(FILE *fp, bool_t dowait);
 1797 VL int n_psignal(FILE *fp, int sig);
 1798 
 1799 /* In n_PSO_INTERACTIVE, we want to go over $PAGER.
 1800  * These are specialized version of Popen()/Pclose() which also encapsulate
 1801  * error message printing, terminal handling etc. additionally */
 1802 FL FILE *      n_pager_open(void);
 1803 FL bool_t      n_pager_close(FILE *fp);
 1804 
 1805 /*  */
 1806 FL void        close_all_files(void);
 1807 
 1808 /* Run a command without a shell, with optional arguments and splicing of stdin
 1809  * and stdout.  FDs may also be n_CHILD_FD_NULL and n_CHILD_FD_PASS, meaning
 1810  * to redirect from/to /dev/null or pass through our own set of FDs; in the
 1811  * latter case terminal capabilities are saved/restored if possible.
 1812  * The command name can be a sequence of words.
 1813  * Signals must be handled by the caller.  "Mask" contains the signals to
 1814  * ignore in the new process.  SIGINT is enabled unless it's in the mask.
 1815  * If env_addon_or_null is set, it is expected to be a NULL terminated
 1816  * array of "K=V" strings to be placed into the childs environment.
 1817  * wait_status_or_null is set to waitpid(2) status if given */
 1818 FL int n_child_run(char const *cmd, sigset_t *mask, int infd, int outfd,
 1819          char const *a0_or_null, char const *a1_or_null, char const *a2_or_null,
 1820          char const **env_addon_or_null, int *wait_status_or_null);
 1821 
 1822 /* Like n_child_run(), but don't wait for the command to finish (use
 1823  * n_child_wait() for waiting on a successful return value).
 1824  * Also it is usually an error to use n_CHILD_FD_PASS for this one */
 1825 FL int n_child_start(char const *cmd, sigset_t *mask, int infd, int outfd,
 1826          char const *a0_or_null, char const *a1_or_null, char const *a2_or_null,
 1827          char const **env_addon_or_null);
 1828 
 1829 /* Fork a child process, enable the other three:
 1830  * - in-child image preparation
 1831  * - mark a child as don't care
 1832  * - wait for child pid, return whether we've had a normal n_EXIT_OK exit.
 1833  *   If wait_status_or_null is set, it is set to the waitpid(2) status */
 1834 FL int n_child_fork(void);
 1835 FL void n_child_prepare(sigset_t *nset, int infd, int outfd);
 1836 FL void n_child_free(int pid);
 1837 FL bool_t n_child_wait(int pid, int *wait_status_or_null);
 1838 
 1839 /*
 1840  * quit.c
 1841  */
 1842 
 1843 /* Save all of the undetermined messages at the top of "mbox".  Save all
 1844  * untouched messages back in the system mailbox.  Remove the system mailbox,
 1845  * if none saved there.
 1846  * TODO v15 Note: assumes hold_sigs() has been called _and_ can be temporarily
 1847  * TODO dropped via a single rele_sigs() if hold_sigs_on */
 1848 FL bool_t      quit(bool_t hold_sigs_on);
 1849 
 1850 /* Adjust the message flags in each message */
 1851 FL int         holdbits(void);
 1852 
 1853 /* Create another temporary file and copy user's mbox file darin.  If there is
 1854  * no mbox, copy nothing.  If he has specified "append" don't copy his mailbox,
 1855  * just copy saveable entries at the end */
 1856 FL enum okay   makembox(void);
 1857 
 1858 FL void        save_mbox_for_possible_quitstuff(void); /* TODO DROP IF U CAN */
 1859 
 1860 FL int         savequitflags(void);
 1861 
 1862 FL void        restorequitflags(int);
 1863 
 1864 /*
 1865  * send.c
 1866  */
 1867 
 1868 /* Send message described by the passed pointer to the passed output buffer.
 1869  * Return -1 on error.  Adjust the status: field if need be.  If doitp is
 1870  * given, suppress ignored header fields.  prefix is a string to prepend to
 1871  * each output line.   action = data destination
 1872  * (SEND_MBOX,_TOFILE,_TODISP,_QUOTE,_DECRYPT).  stats[0] is line count,
 1873  * stats[1] is character count.  stats may be NULL.  Note that stats[0] is
 1874  * valid for SEND_MBOX only */
 1875 FL int         sendmp(struct message *mp, FILE *obuf,
 1876                   struct n_ignore const *doitp,
 1877                   char const *prefix, enum sendaction action, ui64_t *stats);
 1878 
 1879 /*
 1880  * sendout.c
 1881  */
 1882 
 1883 /* Interface between the argument list and the mail1 routine which does all the
 1884  * dirty work */
 1885 FL int         mail(struct name *to, struct name *cc, struct name *bcc,
 1886                   char const *subject, struct attachment *attach,
 1887                   char const *quotefile, int recipient_record);
 1888 
 1889 /* `mail' and `Mail' commands, respectively */
 1890 FL int         c_sendmail(void *v);
 1891 FL int         c_Sendmail(void *v);
 1892 
 1893 /* Mail a message on standard input to the people indicated in the passed
 1894  * header.  (Internal interface) */
 1895 FL enum okay   mail1(struct header *hp, int printheaders,
 1896                   struct message *quote, char const *quotefile,
 1897                   int recipient_record, int doprefix);
 1898 
 1899 /* Create a Date: header field.
 1900  * We compare the localtime() and gmtime() results to get the timezone, because
 1901  * numeric timezones are easier to read and because $TZ isn't always set */
 1902 FL int         mkdate(FILE *fo, char const *field);
 1903 
 1904 /* Dump the to, subject, cc header on the passed file buffer.
 1905  * nosend_msg tells us not to dig to deep but to instead go for compose mode or
 1906  * editing a message (yet we're stupid and cannot do it any better) - if it is
 1907  * TRUM1 then we're really in compose mode and will produce some fields for
 1908  * easier filling in */
 1909 FL int         puthead(bool_t nosend_msg, struct header *hp, FILE *fo,
 1910                   enum gfield w, enum sendaction action,
 1911                   enum conversion convert, char const *contenttype,
 1912                   char const *charset);
 1913 
 1914 /*  */
 1915 FL enum okay   resend_msg(struct message *mp, struct header *hp,
 1916                   bool_t add_resent);
 1917 
 1918 /* $DEAD */
 1919 FL void        savedeadletter(FILE *fp, bool_t fflush_rewind_first);
 1920 
 1921 /*
 1922  * shexp.c
 1923  */
 1924 
 1925 /* Evaluate the string given as a new mailbox name. Supported meta characters:
 1926  * . %  for my system mail box
 1927  * . %user for user's system mail box
 1928  * . #  for previous file
 1929  * . &  invoker's mbox file
 1930  * . +file file in folder directory
 1931  * . any shell meta character (except for FEXP_NSHELL).
 1932  * a poor man's vis(3), on name before calling this (and showing the user).
 1933  * If FEXP_MULTIOK is set we return an array of terminated strings, the (last)
 1934  * result string is terminated via \0\0 and n_PS_EXPAND_MULTIRESULT is set.
 1935  * Returns the file name as an auto-reclaimed string */
 1936 FL char *fexpand(char const *name, enum fexp_mode fexpm);
 1937 
 1938 /* Parse the next shell token from input (->s and ->l are adjusted to the
 1939  * remains, data is constant beside that; ->s may be NULL if ->l is 0, if ->l
 1940  * EQ UIZ_MAX strlen(->s) is used) and append the resulting output to store.
 1941  * If cookie is not NULL and we're in double-quotes then ${@} will be exploded
 1942  * just as known from the sh(1)ell in that case */
 1943 FL enum n_shexp_state n_shexp_parse_token(enum n_shexp_parse_flags flags,
 1944                         struct n_string *store, struct str *input,
 1945                         void const **cookie);
 1946 
 1947 /* Quick+dirty simplified : if an error occurs, returns a copy of *cp and set
 1948  * *cp to NULL, otherwise advances *cp to over the parsed token */
 1949 FL char *n_shexp_parse_token_cp(enum n_shexp_parse_flags flags,
 1950             char const **cp);
 1951 
 1952 /* Quote input in a way that can, in theory, be fed into parse_token() again.
 1953  * ->s may be NULL if ->l is 0, if ->l EQ UIZ_MAX strlen(->s) is used.
 1954  * If rndtrip is true we try to make the resulting string "portable" (by
 1955  * converting Unicode to \u etc.), otherwise we produce something to be
 1956  * consumed "now", i.e., to display for the user.
 1957  * Resulting output is _appended_ to store.
 1958  * TODO Note: last resort, since \u and $ expansions etc. are necessarily
 1959  * TODO already expanded and can thus not be reverted, but ALL we have */
 1960 FL struct n_string *n_shexp_quote(struct n_string *store,
 1961                      struct str const *input, bool_t rndtrip);
 1962 FL char *n_shexp_quote_cp(char const *cp, bool_t rndtrip);
 1963 
 1964 /* Can name be used as a variable name?  I.e., this returns false for special
 1965  * parameter names like $# etc. */
 1966 FL bool_t n_shexp_is_valid_varname(char const *name);
 1967 
 1968 /* `shcodec' */
 1969 FL int c_shcodec(void *vp);
 1970 
 1971 /*
 1972  * signal.c
 1973  */
 1974 
 1975 #ifdef HAVE_DEVEL
 1976 FL int         c_sigstate(void *);
 1977 #endif
 1978 
 1979 FL void        n_raise(int signo);
 1980 
 1981 /* Provide BSD-like signal() on all systems TODO v15 -> SysV -> n_signal() */
 1982 FL sighandler_type safe_signal(int signum, sighandler_type handler);
 1983 
 1984 /* Provide reproducable non-restartable signal handler installation */
 1985 FL n_sighdl_t  n_signal(int signo, n_sighdl_t hdl);
 1986 
 1987 /* Hold *all* signals but SIGCHLD, and release that total block again */
 1988 FL void        hold_all_sigs(void);
 1989 FL void        rele_all_sigs(void);
 1990 
 1991 /* Hold HUP/QUIT/INT */
 1992 FL void        hold_sigs(void);
 1993 FL void        rele_sigs(void);
 1994 
 1995 /* Call _ENTER_SWITCH() with the according flags, it'll take care for the rest
 1996  * and also set the jump buffer - it returns 0 if anything went fine and
 1997  * a signal number if a jump occurred, in which case all handlers requested in
 1998  * flags are temporarily SIG_IGN.
 1999  * _cleanup_ping() informs the condome that no jumps etc. shall be performed
 2000  * until _leave() is called in the following -- to be (optionally) called right
 2001  * before the local jump label is reached which is jumped to after a long jump
 2002  * occurred, straight code flow provided, e.g., to avoid destructors to be
 2003  * called twice.  _leave() must always be called last, reraise_flags will be
 2004  * used to decide how signal handling has to continue
 2005  */
 2006 #define n_SIGMAN_ENTER_SWITCH(S,F) do{\
 2007    int __x__;\
 2008    hold_sigs();\
 2009    if(sigsetjmp((S)->sm_jump, 1))\
 2010       __x__ = -1;\
 2011    else\
 2012       __x__ = F;\
 2013    n__sigman_enter(S, __x__);\
 2014 }while(0); switch((S)->sm_signo)
 2015 FL int         n__sigman_enter(struct n_sigman *self, int flags);
 2016 FL void        n_sigman_cleanup_ping(struct n_sigman *self);
 2017 FL void        n_sigman_leave(struct n_sigman *self, enum n_sigman_flags flags);
 2018 
 2019 /* Pending signal or 0? */
 2020 FL int         n_sigman_peek(void);
 2021 FL void        n_sigman_consume(void);
 2022 
 2023 /* Not-Yet-Dead debug information (handler installation in main.c) */
 2024 #if defined HAVE_DEBUG || defined HAVE_DEVEL
 2025 FL void        _nyd_chirp(ui8_t act, char const *file, ui32_t line,
 2026                   char const *fun);
 2027 FL void        _nyd_oncrash(int signo);
 2028 
 2029 # define HAVE_NYD
 2030 # define NYD_ENTER               _nyd_chirp(1, __FILE__, __LINE__, __FUN__)
 2031 # define NYD_LEAVE               _nyd_chirp(2, __FILE__, __LINE__, __FUN__)
 2032 # define NYD                     _nyd_chirp(0, __FILE__, __LINE__, __FUN__)
 2033 # define NYD_X                   _nyd_chirp(0, __FILE__, __LINE__, __FUN__)
 2034 # ifdef HAVE_NYD2
 2035 #  define NYD2_ENTER             _nyd_chirp(1, __FILE__, __LINE__, __FUN__)
 2036 #  define NYD2_LEAVE             _nyd_chirp(2, __FILE__, __LINE__, __FUN__)
 2037 #  define NYD2                   _nyd_chirp(0, __FILE__, __LINE__, __FUN__)
 2038 # endif
 2039 #else
 2040 # undef HAVE_NYD
 2041 #endif
 2042 #ifndef NYD
 2043 # define NYD_ENTER               do {} while (0)
 2044 # define NYD_LEAVE               do {} while (0)
 2045 # define NYD                     do {} while (0)
 2046 # define NYD_X                   do {} while (0) /* XXX LEGACY */
 2047 #endif
 2048 #ifndef NYD2
 2049 # define NYD2_ENTER              do {} while (0)
 2050 # define NYD2_LEAVE              do {} while (0)
 2051 # define NYD2                    do {} while (0)
 2052 #endif
 2053 
 2054 /*
 2055  * smtp.c
 2056  */
 2057 
 2058 #ifdef HAVE_SMTP
 2059 /* Send a message via SMTP */
 2060 FL bool_t      smtp_mta(struct sendbundle *sbp);
 2061 #endif
 2062 
 2063 /*
 2064  * socket.c
 2065  */
 2066 
 2067 #ifdef HAVE_SOCKETS
 2068 FL bool_t      sopen(struct sock *sp, struct url *urlp);
 2069 FL int         sclose(struct sock *sp);
 2070 FL enum okay   swrite(struct sock *sp, char const *data);
 2071 FL enum okay   swrite1(struct sock *sp, char const *data, int sz,
 2072                   int use_buffer);
 2073 
 2074 /*  */
 2075 FL int         sgetline(char **line, size_t *linesize, size_t *linelen,
 2076                   struct sock *sp n_MEMORY_DEBUG_ARGS);
 2077 # ifdef HAVE_MEMORY_DEBUG
 2078 #  define sgetline(A,B,C,D)      sgetline(A, B, C, D, __FILE__, __LINE__)
 2079 # endif
 2080 #endif
 2081 
 2082 /*
 2083  * spam.c
 2084  */
 2085 
 2086 #ifdef HAVE_SPAM
 2087 /* Direct mappings of the various spam* commands */
 2088 FL int c_spam_clear(void *v);
 2089 FL int c_spam_set(void *v);
 2090 FL int c_spam_forget(void *v);
 2091 FL int c_spam_ham(void *v);
 2092 FL int c_spam_rate(void *v);
 2093 FL int c_spam_spam(void *v);
 2094 #endif
 2095 
 2096 /*
 2097  * ssl.c
 2098  */
 2099 
 2100 #ifdef HAVE_SSL
 2101 /*  */
 2102 FL void        ssl_set_verify_level(struct url const *urlp);
 2103 
 2104 /*  */
 2105 FL enum okay   ssl_verify_decide(void);
 2106 
 2107 /*  */
 2108 FL enum okay   smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount,
 2109                   int keep);
 2110 
 2111 /* */
 2112 FL FILE *      smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp,
 2113                   char const *message_digest);
 2114 
 2115 /*  */
 2116 FL FILE *      smime_encrypt_assemble(FILE *hp, FILE *yp);
 2117 
 2118 /*  */
 2119 FL struct message * smime_decrypt_assemble(struct message *m, FILE *hp,
 2120                      FILE *bp);
 2121 
 2122 /*  */
 2123 FL int         c_certsave(void *v);
 2124 
 2125 /*  */
 2126 FL enum okay   rfc2595_hostname_match(char const *host, char const *pattern);
 2127 #endif
 2128 
 2129 /*
 2130  * strings.c
 2131  */
 2132 
 2133 /* Return a pointer to a dynamic copy of the argument */
 2134 FL char *      savestr(char const *str n_MEMORY_DEBUG_ARGS);
 2135 FL char *      savestrbuf(char const *sbuf, size_t slen n_MEMORY_DEBUG_ARGS);
 2136 #ifdef HAVE_MEMORY_DEBUG
 2137 # define savestr(CP)             savestr(CP, __FILE__, __LINE__)
 2138 # define savestrbuf(CBP,CBL)     savestrbuf(CBP, CBL, __FILE__, __LINE__)
 2139 #endif
 2140 
 2141 /* Concatenate cp2 onto cp1 (if not NULL), separated by sep (if not '\0') */
 2142 FL char *      savecatsep(char const *cp1, char sep, char const *cp2
 2143                   n_MEMORY_DEBUG_ARGS);
 2144 #ifdef HAVE_MEMORY_DEBUG
 2145 # define savecatsep(S1,SEP,S2)   savecatsep(S1, SEP, S2, __FILE__, __LINE__)
 2146 #endif
 2147 
 2148 /* Make copy of argument incorporating old one, if set, separated by space */
 2149 #define save2str(S,O)            savecatsep(O, ' ', S)
 2150 
 2151 /* strcat */
 2152 #define savecat(S1,S2)           savecatsep(S1, '\0', S2)
 2153 
 2154 /* Create duplicate, lowercasing all characters along the way */
 2155 FL char *      i_strdup(char const *src n_MEMORY_DEBUG_ARGS);
 2156 #ifdef HAVE_MEMORY_DEBUG
 2157 # define i_strdup(CP)            i_strdup(CP, __FILE__, __LINE__)
 2158 #endif
 2159 
 2160 /*  */
 2161 FL struct str * str_concat_csvl(struct str *self, ...);
 2162 
 2163 /*  */
 2164 FL struct str * str_concat_cpa(struct str *self, char const * const *cpa,
 2165                   char const *sep_o_null n_MEMORY_DEBUG_ARGS);
 2166 #ifdef HAVE_MEMORY_DEBUG
 2167 # define str_concat_cpa(S,A,N)   str_concat_cpa(S, A, N, __FILE__, __LINE__)
 2168 #endif
 2169 
 2170 /* Plain char* support, not auto-reclaimed (unless noted) */
 2171 
 2172 /* Are any of the characters in template contained in dat? */
 2173 FL bool_t n_anyof_buf(char const *template, char const *dat, size_t len);
 2174 #define n_anyof_cp(S1,S2) n_anyof_buf(S1, S2, UIZ_MAX)
 2175 
 2176 /* Treat *iolist as a sep separated list of strings; find and return the
 2177  * next entry, trimming surrounding whitespace, and point *iolist to the next
 2178  * entry or to NULL if no more entries are contained.  If ignore_empty is
 2179  * set empty entries are started over.
 2180  * strsep_esc() is identical but allows reverse solidus escaping of sep, too.
 2181  * Return NULL or an entry */
 2182 FL char *n_strsep(char **iolist, char sep, bool_t ignore_empty);
 2183 FL char *n_strsep_esc(char **iolist, char sep, bool_t ignore_empty);
 2184 
 2185 /* Copy a string, lowercasing it as we go; *size* is buffer size of *dest*;
 2186  * *dest* will always be terminated unless *size* is 0 */
 2187 FL void        i_strcpy(char *dest, char const *src, size_t size);
 2188 
 2189 /* Is *as1* a valid prefix of *as2*? */
 2190 FL bool_t is_prefix(char const *as1, char const *as2);
 2191 
 2192 /* Reverse solidus quote (" and \) v'alue, and return salloc()ed result */
 2193 FL char *      string_quote(char const *v);
 2194 
 2195 /* Get (and isolate) the last, possibly quoted part of linebuf, set *needs_list
 2196  * to indicate whether getmsglist() et al need to be called to collect
 2197  * additional args that remain in linebuf.  If strip is true possibly
 2198  * surrounding quote characters are removed.  Return NULL on "error" */
 2199 FL char *      laststring(char *linebuf, bool_t *needs_list, bool_t strip);
 2200 
 2201 /* Convert a string to lowercase, in-place and with multibyte-aware */
 2202 FL void        makelow(char *cp);
 2203 
 2204 /* Is *sub* a substring of *str*, case-insensitive and multibyte-aware? */
 2205 FL bool_t      substr(char const *str, char const *sub);
 2206 
 2207 /*  */
 2208 FL char *      sstpcpy(char *dst, char const *src);
 2209 FL char *      sstrdup(char const *cp n_MEMORY_DEBUG_ARGS);
 2210 FL char *      sbufdup(char const *cp, size_t len n_MEMORY_DEBUG_ARGS);
 2211 #ifdef HAVE_MEMORY_DEBUG
 2212 # define sstrdup(CP)             sstrdup(CP, __FILE__, __LINE__)
 2213 # define sbufdup(CP,L)           sbufdup(CP, L, __FILE__, __LINE__)
 2214 #endif
 2215 
 2216 /* Copy at most dstsize bytes of src to dst and return string length.
 2217  * Returns -E2BIG if dst is not large enough; dst will always be terminated
 2218  * unless dstsize was 0 on entry */
 2219 FL ssize_t     n_strscpy(char *dst, char const *src, size_t dstsize);
 2220 
 2221 /* Case-independent ASCII comparisons */
 2222 FL int         asccasecmp(char const *s1, char const *s2);
 2223 FL int         ascncasecmp(char const *s1, char const *s2, size_t sz);
 2224 
 2225 /* Case-independent ASCII string find s2 in s1, return it or NULL */
 2226 FL char const *asccasestr(char const *s1, char const *s2);
 2227 
 2228 /* Case-independent ASCII check whether as1 is the initial substring of as2 */
 2229 FL bool_t      is_asccaseprefix(char const *as1, char const *as2);
 2230 FL bool_t      is_ascncaseprefix(char const *as1, char const *as2, size_t sz);
 2231 
 2232 /* struct str related support funs TODO _cp->_cs! */
 2233 
 2234 /* *self->s* is srealloc()ed */
 2235 #define n_str_dup(S, T)          n_str_assign_buf((S), (T)->s, (T)->l)
 2236 
 2237 /* *self->s* is srealloc()ed; if buflen==UIZ_MAX strlen() is called unless buf
 2238  * is NULL; buf may be NULL if buflen is 0 */
 2239 FL struct str * n_str_assign_buf(struct str *self,
 2240                   char const *buf, uiz_t buflen n_MEMORY_DEBUG_ARGS);
 2241 #define n_str_assign(S, T)       n_str_assign_buf(S, (T)->s, (T)->l)
 2242 #define n_str_assign_cp(S, CP)   n_str_assign_buf(S, CP, UIZ_MAX)
 2243 
 2244 /* *self->s* is srealloc()ed, *self->l* incremented; if buflen==UIZ_MAX
 2245  * strlen() is called unless buf is NULL; buf may be NULL if buflen is 0 */
 2246 FL struct str * n_str_add_buf(struct str *self, char const *buf, uiz_t buflen
 2247                   n_MEMORY_DEBUG_ARGS);
 2248 #define n_str_add(S, T)          n_str_add_buf(S, (T)->s, (T)->l)
 2249 #define n_str_add_cp(S, CP)      n_str_add_buf(S, CP, UIZ_MAX)
 2250 
 2251 #ifdef HAVE_MEMORY_DEBUG
 2252 # define n_str_assign_buf(S,B,BL) n_str_assign_buf(S, B, BL, __FILE__, __LINE__)
 2253 # define n_str_add_buf(S,B,BL)   n_str_add_buf(S, B, BL, __FILE__, __LINE__)
 2254 #endif
 2255 
 2256 /* Remove leading and trailing spacechar()s and *ifs-ws*, respectively.
 2257  * The ->s and ->l of the string will be adjusted, but no NUL termination will
 2258  * be applied to a possibly adjusted buffer!
 2259  * If dofaults is set, " \t\n" is always trimmed (in addition) */
 2260 FL struct str *n_str_trim(struct str *self, enum n_str_trim_flags stf);
 2261 FL struct str *n_str_trim_ifs(struct str *self, bool_t dodefaults);
 2262 
 2263 /* struct n_string
 2264  * May have NULL buffer, may contain embedded NULs */
 2265 
 2266 /* Lifetime.  n_string_gut() is optional for _creat_auto() strings */
 2267 #define n_string_creat(S) \
 2268    ((S)->s_dat = NULL, (S)->s_len = (S)->s_auto = (S)->s_size = 0, (S))
 2269 #define n_string_creat_auto(S) \
 2270    ((S)->s_dat = NULL, (S)->s_len = (S)->s_size = 0, (S)->s_auto = TRU1, (S))
 2271 #define n_string_gut(S) ((S)->s_size != 0 ? (void)n_string_clear(S) : (void)0)
 2272 
 2273 /* Truncate to size, which must be LE current length */
 2274 #define n_string_trunc(S,L) \
 2275    (assert(UICMP(z, L, <=, (S)->s_len)), (S)->s_len = (ui32_t)(L), (S))
 2276 
 2277 /* Check whether a buffer of Len bytes can be inserted into Self */
 2278 #define n_string_can_swallow(S,L) \
 2279    (UICMP(z, SI32_MAX - n_ALIGN(1), >=, L) &&\
 2280     UICMP(z, SI32_MAX - n_ALIGN(1) - (L), >, (S)->s_len))
 2281 
 2282 /* Take/Release buffer ownership */
 2283 #define n_string_take_ownership(SP,B,S,L) \
 2284    (assert((SP)->s_dat == NULL), assert((S) == 0 || (B) != NULL),\
 2285     assert((L) < (S) || (L) == 0),\
 2286     (SP)->s_dat = (B), (SP)->s_len = (L), (SP)->s_size = (S), (SP))
 2287 #define n_string_drop_ownership(SP) \
 2288    ((SP)->s_dat = NULL, (SP)->s_len = (SP)->s_size = 0, (SP))
 2289 
 2290 /* Release all memory */
 2291 FL struct n_string *n_string_clear(struct n_string *self n_MEMORY_DEBUG_ARGS);
 2292 
 2293 #ifdef HAVE_MEMORY_DEBUG
 2294 # define n_string_clear(S) \
 2295    ((S)->s_size != 0 ? (n_string_clear)(S, __FILE__, __LINE__) : (S))
 2296 #else
 2297 # define n_string_clear(S)       ((S)->s_size != 0 ? (n_string_clear)(S) : (S))
 2298 #endif
 2299 
 2300 /* Reserve room for noof additional bytes, but don't adjust length (yet) */
 2301 FL struct n_string *n_string_reserve(struct n_string *self, size_t noof
 2302                      n_MEMORY_DEBUG_ARGS);
 2303 
 2304 /* Resize to exactly nlen bytes; any new storage isn't initialized */
 2305 FL struct n_string *n_string_resize(struct n_string *self, size_t nlen
 2306                      n_MEMORY_DEBUG_ARGS);
 2307 
 2308 #ifdef HAVE_MEMORY_DEBUG
 2309 # define n_string_reserve(S,N)   (n_string_reserve)(S, N, __FILE__, __LINE__)
 2310 # define n_string_resize(S,N)    (n_string_resize)(S, N, __FILE__, __LINE__)
 2311 #endif
 2312 
 2313 /* */
 2314 FL struct n_string *n_string_push_buf(struct n_string *self, char const *buf,
 2315                      size_t buflen n_MEMORY_DEBUG_ARGS);
 2316 #define n_string_push(S, T)       n_string_push_buf(S, (T)->s_len, (T)->s_dat)
 2317 #define n_string_push_cp(S,CP)    n_string_push_buf(S, CP, UIZ_MAX)
 2318 FL struct n_string *n_string_push_c(struct n_string *self, char c
 2319                      n_MEMORY_DEBUG_ARGS);
 2320 
 2321 #define n_string_assign(S,T)     ((S)->s_len = 0, n_string_push(S, T))
 2322 #define n_string_assign_c(S,C)   ((S)->s_len = 0, n_string_push_c(S, C))
 2323 #define n_string_assign_cp(S,CP) ((S)->s_len = 0, n_string_push_cp(S, CP))
 2324 #define n_string_assign_buf(S,B,BL) \
 2325    ((S)->s_len = 0, n_string_push_buf(S, B, BL))
 2326 
 2327 #ifdef HAVE_MEMORY_DEBUG
 2328 # define n_string_push_buf(S,B,BL) \
 2329    n_string_push_buf(S, B, BL, __FILE__, __LINE__)
 2330 # define n_string_push_c(S,C)    n_string_push_c(S, C, __FILE__, __LINE__)
 2331 #endif
 2332 
 2333 /* */
 2334 FL struct n_string *n_string_unshift_buf(struct n_string *self, char const *buf,
 2335                      size_t buflen n_MEMORY_DEBUG_ARGS);
 2336 #define n_string_unshift(S,T) \
 2337    n_string_unshift_buf(S, (T)->s_len, (T)->s_dat)
 2338 #define n_string_unshift_cp(S,CP) \
 2339       n_string_unshift_buf(S, CP, UIZ_MAX)
 2340 FL struct n_string *n_string_unshift_c(struct n_string *self, char c
 2341                      n_MEMORY_DEBUG_ARGS);
 2342 
 2343 #ifdef HAVE_MEMORY_DEBUG
 2344 # define n_string_unshift_buf(S,B,BL) \
 2345    n_string_unshift_buf(S,B,BL, __FILE__, __LINE__)
 2346 # define n_string_unshift_c(S,C) n_string_unshift_c(S, C, __FILE__, __LINE__)
 2347 #endif
 2348 
 2349 /* */
 2350 FL struct n_string *n_string_insert_buf(struct n_string *self, size_t idx,
 2351                      char const *buf, size_t buflen n_MEMORY_DEBUG_ARGS);
 2352 #define n_string_insert(S,I,T) \
 2353    n_string_insert_buf(S, I, (T)->s_len, (T)->s_dat)
 2354 #define n_string_insert_cp(S,I,CP) \
 2355       n_string_insert_buf(S, I, CP, UIZ_MAX)
 2356 FL struct n_string *n_string_insert_c(struct n_string *self, size_t idx,
 2357                      char c n_MEMORY_DEBUG_ARGS);
 2358 
 2359 #ifdef HAVE_MEMORY_DEBUG
 2360 # define n_string_insert_buf(S,I,B,BL) \
 2361    n_string_insert_buf(S, I, B, BL, __FILE__, __LINE__)
 2362 # define n_string_insert_c(S,I,C) n_string_insert_c(S, I, C, __FILE__, __LINE__)
 2363 #endif
 2364 
 2365 /* */
 2366 FL struct n_string *n_string_cut(struct n_string *self, size_t idx, size_t len);
 2367 
 2368 /* Ensure self has a - NUL terminated - buffer, and return that.
 2369  * The latter may return the pointer to an internal empty RODATA instead */
 2370 FL char *      n_string_cp(struct n_string *self n_MEMORY_DEBUG_ARGS);
 2371 FL char const *n_string_cp_const(struct n_string const *self);
 2372 
 2373 #ifdef HAVE_MEMORY_DEBUG
 2374 # define n_string_cp(S)          n_string_cp(S, __FILE__, __LINE__)
 2375 #endif
 2376 
 2377 #ifdef HAVE_INLINE
 2378 n_INLINE struct n_string *
 2379 (n_string_creat)(struct n_string *self){
 2380    return n_string_creat(self);
 2381 }
 2382 # undef n_string_creat
 2383 
 2384 n_INLINE struct n_string *
 2385 (n_string_creat_auto)(struct n_string *self){
 2386    return n_string_creat_auto(self);
 2387 }
 2388 # undef n_string_creat_auto
 2389 
 2390 n_INLINE void
 2391 (n_string_gut)(struct n_string *self){
 2392    n_string_gut(self);
 2393 }
 2394 # undef n_string_gut
 2395 
 2396 n_INLINE struct n_string *
 2397 (n_string_trunc)(struct n_string *self, size_t l){
 2398    return n_string_trunc(self, l);
 2399 }
 2400 # undef n_string_trunc
 2401 
 2402 n_INLINE struct n_string *
 2403 (n_string_drop_ownership)(struct n_string *self){
 2404    return n_string_drop_ownership(self);
 2405 }
 2406 # undef n_string_drop_ownership
 2407 #endif /* HAVE_INLINE */
 2408 
 2409 /* UTF-8 / UTF-32 stuff */
 2410 
 2411 /* ..and update arguments to point after range; returns UI32_MAX on error, in
 2412  * which case the arguments will have been stepped one byte */
 2413 FL ui32_t      n_utf8_to_utf32(char const **bdat, size_t *blen);
 2414 
 2415 /* buf must be large enough also for NUL, it's new length will be returned */
 2416 FL size_t      n_utf32_to_utf8(ui32_t c, char *buf);
 2417 
 2418 /* Our iconv(3) wrappers */
 2419 
 2420 #ifdef HAVE_ICONV
 2421 FL iconv_t     n_iconv_open(char const *tocode, char const *fromcode);
 2422 /* If *cd* == *iconvd*, assigns -1 to the latter */
 2423 FL void        n_iconv_close(iconv_t cd);
 2424 
 2425 /* Reset encoding state */
 2426 FL void        n_iconv_reset(iconv_t cd);
 2427 
 2428 /* iconv(3), but return n_err_no or 0 upon success.
 2429  * The err_no may be ERR_NOENT unless n_ICONV_IGN_NOREVERSE is set in icf.
 2430  * iconv_str() auto-grows on ERR_2BIG errors; in and in_rest_or_null may be
 2431  * the same object.
 2432  * Note: ERR_INVAL (incomplete sequence at end of input) is NOT handled, so the
 2433  * replacement character must be added manually if that happens at EOF!
 2434  * TODO These must be contexts.  For now we duplicate n_err_no into
 2435  * TODO n_iconv_err_no in order to be able to access it when stuff happens
 2436  * TODO "in between"! */
 2437 FL int         n_iconv_buf(iconv_t cd, enum n_iconv_flags icf,
 2438                   char const **inb, size_t *inbleft,
 2439                   char **outb, size_t *outbleft);
 2440 FL int         n_iconv_str(iconv_t icp, enum n_iconv_flags icf,
 2441                   struct str *out, struct str const *in,
 2442                   struct str *in_rest_or_null);
 2443 
 2444 /* If tocode==NULL, uses *ttycharset*.  If fromcode==NULL, uses UTF-8.
 2445  * Returns a salloc()ed buffer or NULL */
 2446 FL char *      n_iconv_onetime_cp(enum n_iconv_flags icf,
 2447                   char const *tocode, char const *fromcode, char const *input);
 2448 #endif
 2449 
 2450 /*
 2451  * termcap.c
 2452  * This is a little bit hairy since it provides some stuff even if HAVE_TERMCAP
 2453  * is false due to encapsulation desire
 2454  */
 2455 
 2456 #ifdef n_HAVE_TCAP
 2457 /* termcap(3) / xy lifetime handling -- only called if we're n_PSO_INTERACTIVE
 2458  * but not doing something in n_PO_QUICKRUN_MASK */
 2459 FL void        n_termcap_init(void);
 2460 FL void        n_termcap_destroy(void);
 2461 
 2462 /* enter_ca_mode / enable keypad (both if possible).
 2463  * TODO When complete is not set we won't enter_ca_mode, for example: we don't
 2464  * TODO want a complete screen clearance after $PAGER returned after displaying
 2465  * TODO a mail, because otherwise the screen would look differently for normal
 2466  * TODO stdout display messages.  Etc. */
 2467 # ifdef HAVE_TERMCAP
 2468 FL void        n_termcap_resume(bool_t complete);
 2469 FL void        n_termcap_suspend(bool_t complete);
 2470 
 2471 #  define n_TERMCAP_RESUME(CPL)  do{ n_termcap_resume(CPL); }while(0)
 2472 #  define n_TERMCAP_SUSPEND(CPL) do{ n_termcap_suspend(CPL); }while(0)
 2473 # endif
 2474 
 2475 /* Command multiplexer, returns FAL0 on I/O error, TRU1 on success and TRUM1
 2476  * for commands which are not available and have no built-in fallback.
 2477  * For query options the return represents a true value and -1 error.
 2478  * Will return FAL0 directly unless we've been initialized.
 2479  * By convention unused argument slots are given as -1 */
 2480 FL ssize_t     n_termcap_cmd(enum n_termcap_cmd cmd, ssize_t a1, ssize_t a2);
 2481 # define n_termcap_cmdx(CMD)     n_termcap_cmd(CMD, -1, -1)
 2482 
 2483 /* Query multiplexer.  If query is n__TERMCAP_QUERY_MAX1 then
 2484  * tvp->tv_data.tvd_string must contain the name of the query to look up; this
 2485  * is used to lookup just about *any* (string) capability.
 2486  * Returns TRU1 on success and TRUM1 for queries for which a built-in default
 2487  * is returned; FAL0 is returned on non-availability */
 2488 FL bool_t      n_termcap_query(enum n_termcap_query query,
 2489                   struct n_termcap_value *tvp);
 2490 
 2491 /* Get a n_termcap_query for name or -1 if it is not known, and -2 if
 2492  * type wasn't _NONE and the type doesn't match. */
 2493 # ifdef HAVE_KEY_BINDINGS
 2494 FL si32_t      n_termcap_query_for_name(char const *name,
 2495                   enum n_termcap_captype type);
 2496 FL char const *n_termcap_name_of_query(enum n_termcap_query query);
 2497 # endif
 2498 #endif /* n_HAVE_TCAP */
 2499 
 2500 #ifndef n_TERMCAP_RESUME
 2501 # define n_TERMCAP_RESUME(CPL) do{;}while(0)
 2502 # define n_TERMCAP_SUSPEND(CPL) do{;}while(0);
 2503 #endif
 2504 
 2505 /*
 2506  * thread.c
 2507  */
 2508 
 2509 /*  */
 2510 FL int         c_thread(void *vp);
 2511 
 2512 /*  */
 2513 FL int         c_unthread(void *vp);
 2514 
 2515 /*  */
 2516 FL struct message * next_in_thread(struct message *mp);
 2517 FL struct message * prev_in_thread(struct message *mp);
 2518 FL struct message * this_in_thread(struct message *mp, long n);
 2519 
 2520 /* Sorted mode is internally just a variant of threaded mode with all m_parent
 2521  * and m_child links being NULL */
 2522 FL int         c_sort(void *vp);
 2523 
 2524 /*  */
 2525 FL int         c_collapse(void *v);
 2526 FL int         c_uncollapse(void *v);
 2527 
 2528 /*  */
 2529 FL void        uncollapse1(struct message *mp, int always);
 2530 
 2531 /*
 2532  * tty.c
 2533  */
 2534 
 2535 /* Return whether user says yes, on STDIN if interactive.
 2536  * Uses noninteract_default, the return value for non-interactive use cases,
 2537  * as a hint for boolify() and chooses the yes/no string to append to prompt
 2538  * accordingly.  If prompt is NULL "Continue" is used instead.
 2539  * Handles+reraises SIGINT */
 2540 FL bool_t getapproval(char const *prompt, bool_t noninteract_default);
 2541 
 2542 #ifdef HAVE_SOCKETS
 2543 /* Get a password the expected way, return termios_state.ts_linebuf on
 2544  * success or NULL on error */
 2545 FL char *getuser(char const *query);
 2546 
 2547 /* Get a password the expected way, return termios_state.ts_linebuf on
 2548  * success or NULL on error.  SIGINT is temporarily blocked, *not* reraised.
 2549  * termios_state_reset() (def.h) must be called anyway */
 2550 FL char *getpassword(char const *query);
 2551 #endif
 2552 
 2553 /* Create the prompt and return its visual width in columns, which may be 0
 2554  * if evaluation is disabled etc.  The data is placed in store.
 2555  * xprompt is inspected only if prompt is enabled and no *prompt* evaluation
 2556  * takes place */
 2557 FL ui32_t n_tty_create_prompt(struct n_string *store, char const *xprompt,
 2558             enum n_go_input_flags gif);
 2559 
 2560 /* Overall interactive terminal life cycle for command line editor library */
 2561 #ifdef HAVE_MLE
 2562 FL void n_tty_init(void);
 2563 FL void n_tty_destroy(bool_t xit_fastpath);
 2564 #else
 2565 # define n_tty_init() do{;}while(0)
 2566 # define n_tty_destroy(B) do{;}while(0)
 2567 #endif
 2568 
 2569 /* Read a line after printing prompt (if set and non-empty).
 2570  * If n>0 assumes that *linebuf has n bytes of default content.
 2571  * histok_or_null like for n_go_input().
 2572  * Only the _CTX_ bits in lif are used */
 2573 FL int n_tty_readline(enum n_go_input_flags gif, char const *prompt,
 2574          char **linebuf, size_t *linesize, size_t n, bool_t *histok_or_null
 2575          n_MEMORY_DEBUG_ARGS);
 2576 #ifdef HAVE_MEMORY_DEBUG
 2577 # define n_tty_readline(A,B,C,D,E,F) \
 2578    (n_tty_readline)(A,B,C,D,E,F,__FILE__,__LINE__)
 2579 #endif
 2580 
 2581 /* Add a line (most likely as returned by n_tty_readline()) to the history.
 2582  * Whether and how an entry is added for real depends on gif, e.g.,
 2583  * n_GO_INPUT_HIST_GABBY / *history-gabby* relation.
 2584  * Empty strings are never stored */
 2585 FL void n_tty_addhist(char const *s, enum n_go_input_flags gif);
 2586 
 2587 #ifdef HAVE_HISTORY
 2588 FL int c_history(void *v);
 2589 #endif
 2590 
 2591 /* `bind' and `unbind' */
 2592 #ifdef HAVE_KEY_BINDINGS
 2593 FL int c_bind(void *v);
 2594 FL int c_unbind(void *v);
 2595 #endif
 2596 
 2597 /*
 2598  * ui-str.c
 2599  */
 2600 
 2601 /* Parse (onechar of) a given buffer, and generate infos along the way.
 2602  * If _WOUT_CREATE is set in vif, .vic_woudat will be NUL terminated!
 2603  * vicp must be zeroed before first use */
 2604 FL bool_t      n_visual_info(struct n_visual_info_ctx *vicp,
 2605                   enum n_visual_info_flags vif);
 2606 
 2607 /* Check (multibyte-safe) how many bytes of buf (which is blen byts) can be
 2608  * safely placed in a buffer (field width) of maxlen bytes */
 2609 FL size_t      field_detect_clip(size_t maxlen, char const *buf, size_t blen);
 2610 
 2611 /* Place cp in a salloc()ed buffer, column-aligned; for header display only */
 2612 FL char *      colalign(char const *cp, int col, int fill,
 2613                   int *cols_decr_used_or_null);
 2614 
 2615 /* Convert a string to a displayable one;
 2616  * prstr() returns the result savestr()d, prout() writes it */
 2617 FL void        makeprint(struct str const *in, struct str *out);
 2618 FL size_t      delctrl(char *cp, size_t len);
 2619 FL char *      prstr(char const *s);
 2620 FL int         prout(char const *s, size_t sz, FILE *fp);
 2621 
 2622 /* Print out a Unicode character or a substitute for it, return 0 on error or
 2623  * wcwidth() (or 1) on success */
 2624 FL size_t      putuc(int u, int c, FILE *fp);
 2625 
 2626 /* Check whether bidirectional info maybe needed for blen bytes of bdat */
 2627 FL bool_t      bidi_info_needed(char const *bdat, size_t blen);
 2628 
 2629 /* Create bidirectional text encapsulation information; without HAVE_NATCH_CHAR
 2630  * the strings are always empty */
 2631 FL void        bidi_info_create(struct bidi_info *bip);
 2632 
 2633 /*
 2634  * urlcrecry.c
 2635  */
 2636 
 2637 /* URL en- and decoding according to (enough of) RFC 3986 (RFC 1738).
 2638  * These return a newly salloc()ated result, or NULL on length excess */
 2639 FL char *      urlxenc(char const *cp, bool_t ispath n_MEMORY_DEBUG_ARGS);
 2640 FL char *      urlxdec(char const *cp n_MEMORY_DEBUG_ARGS);
 2641 #ifdef HAVE_MEMORY_DEBUG
 2642 # define urlxenc(CP,P)           urlxenc(CP, P, __FILE__, __LINE__)
 2643 # define urlxdec(CP)             urlxdec(CP, __FILE__, __LINE__)
 2644 #endif
 2645 
 2646 /* `urlcodec' */
 2647 FL int c_urlcodec(void *vp);
 2648 
 2649 FL int c_urlencode(void *v); /* TODO obsolete*/
 2650 FL int c_urldecode(void *v); /* TODO obsolete */
 2651 
 2652 /* Parse a RFC 6058 'mailto' URI to a single to: (TODO yes, for now hacky).
 2653  * Return NULL or something that can be converted to a struct name */
 2654 FL char *      url_mailto_to_address(char const *mailtop);
 2655 
 2656 /* Return port for proto (and set irv_or_null), or NULL if unknown.
 2657  * For file:// this returns an empty string */
 2658 FL char const *n_servbyname(char const *proto, ui16_t *irv_or_null);
 2659 
 2660 #ifdef HAVE_SOCKETS
 2661 /* Parse data, which must meet the criteria of the protocol cproto, and fill
 2662  * in the URL structure urlp (URL rather according to RFC 3986) */
 2663 FL bool_t      url_parse(struct url *urlp, enum cproto cproto,
 2664                   char const *data);
 2665 
 2666 /* Zero ccp and lookup credentials for communicating with urlp.
 2667  * Return whether credentials are available and valid (for chosen auth) */
 2668 FL bool_t      ccred_lookup(struct ccred *ccp, struct url *urlp);
 2669 FL bool_t      ccred_lookup_old(struct ccred *ccp, enum cproto cproto,
 2670                   char const *addr);
 2671 #endif /* HAVE_SOCKETS */
 2672 
 2673 /* `netrc' */
 2674 #ifdef HAVE_NETRC
 2675 FL int c_netrc(void *v);
 2676 #endif
 2677 
 2678 /* MD5 (RFC 1321) related facilities */
 2679 #ifdef HAVE_MD5
 2680 # ifdef HAVE_XSSL_MD5
 2681 #  define md5_ctx                  MD5_CTX
 2682 #  define md5_init              MD5_Init
 2683 #  define md5_update                MD5_Update
 2684 #  define md5_final             MD5_Final
 2685 # else
 2686    /* The function definitions are instantiated in main.c */
 2687 #  include "rfc1321.h"
 2688 # endif
 2689 
 2690 /* Store the MD5 checksum as a hexadecimal string in *hex*, *not* terminated,
 2691  * using lowercase ASCII letters as defined in RFC 2195 */
 2692 # define MD5TOHEX_SIZE           32
 2693 FL char *      md5tohex(char hex[MD5TOHEX_SIZE], void const *vp);
 2694 
 2695 /* CRAM-MD5 encode the *user* / *pass* / *b64* combo; NULL on overflow error */
 2696 FL char *      cram_md5_string(struct str const *user, struct str const *pass,
 2697                   char const *b64);
 2698 
 2699 /* RFC 2104: HMAC: Keyed-Hashing for Message Authentication.
 2700  * unsigned char *text: pointer to data stream
 2701  * int text_len       : length of data stream
 2702  * unsigned char *key : pointer to authentication key
 2703  * int key_len        : length of authentication key
 2704  * caddr_t digest     : caller digest to be filled in */
 2705 FL void        hmac_md5(unsigned char *text, int text_len, unsigned char *key,
 2706                   int key_len, void *digest);
 2707 #endif /* HAVE_MD5 */
 2708 
 2709 /*
 2710  * xssl.c
 2711  */
 2712 
 2713 #ifdef HAVE_XSSL
 2714 /* Our wrapper for RAND_bytes(3) */
 2715 # if n_RANDOM_USE_XSSL
 2716 FL void ssl_rand_bytes(void *buf, size_t blen);
 2717 # endif
 2718 
 2719 /*  */
 2720 FL enum okay   ssl_open(struct url const *urlp, struct sock *sp);
 2721 
 2722 /*  */
 2723 FL void        ssl_gen_err(char const *fmt, ...);
 2724 
 2725 /*  */
 2726 FL int         c_verify(void *vp);
 2727 
 2728 /*  */
 2729 FL FILE *      smime_sign(FILE *ip, char const *addr);
 2730 
 2731 /*  */
 2732 FL FILE *      smime_encrypt(FILE *ip, char const *certfile, char const *to);
 2733 
 2734 FL struct message * smime_decrypt(struct message *m, char const *to,
 2735                      char const *cc, bool_t is_a_verify_call);
 2736 
 2737 /*  */
 2738 FL enum okay   smime_certsave(struct message *m, int n, FILE *op);
 2739 
 2740 #endif /* HAVE_XSSL */
 2741 
 2742 /*
 2743  * obs-imap.c
 2744  */
 2745 
 2746 #ifdef HAVE_IMAP
 2747 FL void n_go_onintr_for_imap(void);
 2748 
 2749 /* The former returns the input again if no conversion is necessary */
 2750 FL char const *imap_path_encode(char const *path, bool_t *err_or_null);
 2751 FL char *imap_path_decode(char const *path, bool_t *err_or_null);
 2752 
 2753 FL char const * imap_fileof(char const *xcp);
 2754 FL enum okay   imap_noop(void);
 2755 FL enum okay   imap_select(struct mailbox *mp, off_t *size, int *count,
 2756                   const char *mbx, enum fedit_mode fm);
 2757 FL int         imap_setfile(const char *xserver, enum fedit_mode fm);
 2758 FL enum okay   imap_header(struct message *m);
 2759 FL enum okay   imap_body(struct message *m);
 2760 FL void        imap_getheaders(int bot, int top);
 2761 FL bool_t      imap_quit(bool_t hold_sigs_on);
 2762 FL enum okay   imap_undelete(struct message *m, int n);
 2763 FL enum okay   imap_unread(struct message *m, int n);
 2764 FL int         c_imapcodec(void *vp);
 2765 FL int         c_imap_imap(void *vp);
 2766 FL int         imap_newmail(int nmail);
 2767 FL enum okay   imap_append(const char *xserver, FILE *fp, long offset);
 2768 FL int         imap_folders(const char *name, int strip);
 2769 FL enum okay   imap_copy(struct message *m, int n, const char *name);
 2770 # ifdef HAVE_IMAP_SEARCH
 2771 FL enum okay   imap_search1(const char *spec, int f);
 2772 # endif
 2773 FL int         imap_thisaccount(const char *cp);
 2774 FL enum okay   imap_remove(const char *name);
 2775 FL enum okay   imap_rename(const char *old, const char *new);
 2776 FL enum okay   imap_dequeue(struct mailbox *mp, FILE *fp);
 2777 FL int         c_connect(void *vp);
 2778 FL int         c_disconnect(void *vp);
 2779 FL int         c_cache(void *vp);
 2780 FL int         disconnected(const char *file);
 2781 FL void        transflags(struct message *omessage, long omsgCount,
 2782                   int transparent);
 2783 FL time_t      imap_read_date_time(const char *cp);
 2784 FL const char * imap_make_date_time(time_t t);
 2785 
 2786 /* Extract the protocol base and return a duplicate */
 2787 FL char *      protbase(char const *cp n_MEMORY_DEBUG_ARGS);
 2788 # ifdef HAVE_MEMORY_DEBUG
 2789 #  define protbase(CP)           protbase(CP, __FILE__, __LINE__)
 2790 # endif
 2791 #endif /* HAVE_IMAP */
 2792 
 2793 /*
 2794  * obs-imap-cache.c
 2795  */
 2796 
 2797 #ifdef HAVE_IMAP
 2798 FL enum okay   getcache1(struct mailbox *mp, struct message *m,
 2799                   enum needspec need, int setflags);
 2800 FL enum okay   getcache(struct mailbox *mp, struct message *m,
 2801                   enum needspec need);
 2802 FL void        putcache(struct mailbox *mp, struct message *m);
 2803 FL void        initcache(struct mailbox *mp);
 2804 FL void        purgecache(struct mailbox *mp, struct message *m, long mc);
 2805 FL void        delcache(struct mailbox *mp, struct message *m);
 2806 FL enum okay   cache_setptr(enum fedit_mode fm, int transparent);
 2807 FL enum okay   cache_list(struct mailbox *mp, char const *base, int strip,
 2808                   FILE *fp);
 2809 FL enum okay   cache_remove(char const *name);
 2810 FL enum okay   cache_rename(char const *old, char const *new);
 2811 FL unsigned long cached_uidvalidity(struct mailbox *mp);
 2812 FL FILE *      cache_queue(struct mailbox *mp);
 2813 FL enum okay   cache_dequeue(struct mailbox *mp);
 2814 #endif /* HAVE_IMAP */
 2815 
 2816 /*
 2817  * obs-lzw.c
 2818  */
 2819 #ifdef HAVE_IMAP
 2820 FL int         zwrite(void *cookie, const char *wbp, int num);
 2821 FL int         zfree(void *cookie);
 2822 FL int         zread(void *cookie, char *rbp, int num);
 2823 FL void *      zalloc(FILE *fp);
 2824 #endif /* HAVE_IMAP */
 2825 
 2826 #ifndef HAVE_AMALGAMATION
 2827 # undef FL
 2828 # define FL
 2829 #endif
 2830 
 2831 /* s-it-mode */