"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.11/nailfuns.h" (8 Aug 2018, 110373 Bytes) of package /linux/misc/s-nail-14.9.11.tar.xz:


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

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