"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.10/nailfuns.h" (25 Mar 2018, 108516 Bytes) of package /linux/misc/s-nail-14.9.10.tar.xz:


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

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