"Fossies" - the Fresh Open Source Software Archive

Member "s-nail-14.9.19/include/mx/nailfuns.h" (26 Apr 2020, 67555 Bytes) of package /linux/misc/s-nail-14.9.19.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.18_vs_14.9.19.

    1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
    2  *@ Function prototypes and function-alike macros.
    3  *@ TODO Should be split in myriads of FEATURE-GROUP.h headers.
    4  *
    5  * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
    6  * Copyright (c) 2012 - 2020 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
    7  * SPDX-License-Identifier: BSD-3-Clause TODO ISC
    8  */
    9 /*
   10  * Copyright (c) 1980, 1993
   11  *      The Regents of the University of California.  All rights reserved.
   12  *
   13  * Redistribution and use in source and binary forms, with or without
   14  * modification, are permitted provided that the following conditions
   15  * are met:
   16  * 1. Redistributions of source code must retain the above copyright
   17  *    notice, this list of conditions and the following disclaimer.
   18  * 2. Redistributions in binary form must reproduce the above copyright
   19  *    notice, this list of conditions and the following disclaimer in the
   20  *    documentation and/or other materials provided with the distribution.
   21  * 3. Neither the name of the University nor the names of its contributors
   22  *    may be used to endorse or promote products derived from this software
   23  *    without specific prior written permission.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  */
   37 
   38 struct mx_attachment;
   39 struct mx_cmd_arg;
   40 struct su_cs_dict;
   41 struct quoteflt;
   42 
   43 /*
   44  * TODO Convert optional utility+ functions to n_*(); ditto
   45  * TODO else use generic module-specific prefixes: str_(), am[em]_, sm[em]_, ..
   46  */
   47 /* TODO s-it-mode: not really (docu, funnames, funargs, etc) */
   48 
   49 #undef FL
   50 #ifndef mx_HAVE_AMALGAMATION
   51 # define FL extern
   52 #else
   53 # define FL static
   54 #endif
   55 
   56 /*
   57  * Macro-based generics
   58  */
   59 
   60 /* RFC 822, 3.2. */
   61 #define fieldnamechar(c) \
   62    (su_cs_is_ascii(c) && (c) > 040 && (c) != 0177 && (c) != ':')
   63 
   64 /* Single-threaded, use unlocked I/O */
   65 #ifdef mx_HAVE_PUTC_UNLOCKED
   66 # undef getc
   67 # define getc(c) getc_unlocked(c)
   68 # undef putc
   69 # define putc(c, f) putc_unlocked(c, f)
   70 #endif
   71 
   72 /* There are problems with dup()ing of file-descriptors for child processes.
   73  * We have to somehow accomplish that the FILE* fp makes itself comfortable
   74  * with the *real* offset of the underlying file descriptor.
   75  * POSIX Issue 7 overloaded fflush(3): if used on a readable stream, then
   76  *
   77  *    if the file is not already at EOF, and the file is one capable of
   78  *    seeking, the file offset of the underlying open file description shall
   79  *    be set to the file position of the stream */
   80 #if !su_OS_OPENBSD &&\
   81    defined _POSIX_VERSION && _POSIX_VERSION + 0 >= 200809L
   82 # define n_real_seek(FP,OFF,WH) (fseek(FP, OFF, WH) != -1 && fflush(FP) != EOF)
   83 # define really_rewind(stream) \
   84 do{\
   85    rewind(stream);\
   86    fflush(stream);\
   87 }while(0)
   88 
   89 #else
   90 # define n_real_seek(FP,OFF,WH) \
   91    (fseek(FP, OFF, WH) != -1 && fflush(FP) != EOF &&\
   92       lseek(fileno(FP), OFF, WH) != -1)
   93 # define really_rewind(stream) \
   94 do{\
   95    rewind(stream);\
   96    fflush(stream);\
   97    lseek(fileno(stream), 0, SEEK_SET);\
   98 }while(0)
   99 #endif
  100 
  101 /* fflush() and rewind() */
  102 #define fflush_rewind(stream) \
  103 do{\
  104    fflush(stream);\
  105    rewind(stream);\
  106 }while(0)
  107 
  108 /* Truncate a file to the last character written.  This is useful just before
  109  * closing an old file that was opened for read/write */
  110 #define ftrunc(stream) \
  111 do{\
  112    off_t off;\
  113    fflush(stream);\
  114    off = ftell(stream);\
  115    if(off >= 0)\
  116       ftruncate(fileno(stream), off);\
  117 }while(0)
  118 
  119 /*
  120  * accmacvar.c
  121  */
  122 
  123 /* Macros: `define', `undefine', `call', `call_if' */
  124 FL int c_define(void *v);
  125 FL int c_undefine(void *v);
  126 FL int c_call(void *v);
  127 FL int c_call_if(void *v);
  128 
  129 /* Accounts: `account', `unaccount' */
  130 FL void mx_account_leave(void);
  131 FL int c_account(void *v);
  132 FL int c_unaccount(void *v);
  133 
  134 /* `localopts', `shift', `return' */
  135 FL int c_localopts(void *vp);
  136 FL int c_shift(void *vp);
  137 FL int c_return(void *vp);
  138 
  139 /* TODO - Main loop on tick event: mx_sigs_all_holdx() is active
  140  * TODO - main.c *on-program-exit*
  141  * mac must not be NIL */
  142 FL void temporary_on_xy_hook_caller(char const *hname, char const *mac,
  143       boole sigs_held);
  144 
  145 /* TODO Check whether a *folder-hook* exists for currently active mailbox */
  146 FL boole temporary_folder_hook_check(boole nmail);
  147 FL void temporary_folder_hook_unroll(void); /* XXX im. hack */
  148 
  149 /* TODO v15 drop Invoke compose hook macname */
  150 FL void temporary_compose_mode_hook_call(char const *macname,
  151             void (*hook_pre)(void *), void *hook_arg);
  152 FL void temporary_compose_mode_hook_unroll(void);
  153 
  154 #ifdef mx_HAVE_HISTORY
  155 /* TODO *on-history-addition* */
  156 FL boole temporary_addhist_hook(char const *ctx, char const *gabby_type,
  157             char const *histent);
  158 #endif
  159 
  160 /* TODO v15 drop: let shexp_parse_token take a carrier with positional
  161  * TODO params, then let callers use that as such!!
  162  * Call hook in a recursed environment named name where positional params are
  163  * setup according to argv/argc.  NOTE: all signals blocked! */
  164 #ifdef mx_HAVE_REGEX
  165 FL char *temporary_pospar_access_hook(char const *name, char const **argv,
  166       u32 argc, char *(*hook)(void *uservp), void *uservp);
  167 #endif
  168 
  169 /* Setting up batch mode, variable-handling side */
  170 FL void n_var_setup_batch_mode(void);
  171 
  172 /* Can name freely be used as a variable by users? */
  173 FL boole n_var_is_user_writable(char const *name);
  174 
  175 /* Don't use n_var_* unless you *really* have to! */
  176 
  177 /* Constant option key look/(un)set/clear */
  178 FL char *n_var_oklook(enum okeys okey);
  179 #define ok_blook(C) (n_var_oklook(su_CONCAT(ok_b_, C)) != NULL)
  180 #define ok_vlook(C) n_var_oklook(su_CONCAT(ok_v_, C))
  181 
  182 FL boole n_var_okset(enum okeys okey, up val);
  183 #define ok_bset(C) \
  184    n_var_okset(su_CONCAT(ok_b_, C), (up)TRU1)
  185 #define ok_vset(C,V) \
  186    n_var_okset(su_CONCAT(ok_v_, C), (up)(V))
  187 
  188 FL boole n_var_okclear(enum okeys okey);
  189 #define ok_bclear(C) n_var_okclear(su_CONCAT(ok_b_, C))
  190 #define ok_vclear(C) n_var_okclear(su_CONCAT(ok_v_, C))
  191 
  192 /* Variable option key lookup/(un)set/clear.
  193  * If try_getenv is true we will getenv(3) _if_ vokey is not a known enum okey;
  194  * it will also cause obsoletion messages only for doing lookup (once).
  195  * _vexplode() is to be used by the shell expansion stuff when encountering
  196  * ${@} in double-quotes, in order to provide sh(1)ell compatible behaviour;
  197  * it returns whether there are any elements in argv (*cookie) */
  198 FL char const *n_var_vlook(char const *vokey, boole try_getenv);
  199 FL boole n_var_vexplode(void const **cookie);
  200 FL boole n_var_vset(char const *vokey, up val);
  201 FL boole n_var_vclear(char const *vokey);
  202 
  203 /* Special case to handle the typical [xy-USER@HOST,] xy-HOST and plain xy
  204  * variable chains; oxm is a bitmix which tells which combinations to test */
  205 #ifdef mx_HAVE_NET
  206 FL char *n_var_xoklook(enum okeys okey, struct mx_url const *urlp,
  207             enum okey_xlook_mode oxm);
  208 # define xok_BLOOK(C,URL,M) (n_var_xoklook(C, URL, M) != NULL)
  209 # define xok_VLOOK(C,URL,M) n_var_xoklook(C, URL, M)
  210 # define xok_blook(C,URL,M) xok_BLOOK(su_CONCAT(ok_b_, C), URL, M)
  211 # define xok_vlook(C,URL,M) xok_VLOOK(su_CONCAT(ok_v_, C), URL, M)
  212 #endif
  213 
  214 /* User variable access: `set', `local' and `unset' */
  215 FL int c_set(void *vp);
  216 FL int c_unset(void *vp);
  217 
  218 /* `varshow' */
  219 FL int c_varshow(void *v);
  220 
  221 /* `environ' */
  222 FL int c_environ(void *v);
  223 
  224 /* `vpospar' */
  225 FL int c_vpospar(void *v);
  226 
  227 /*
  228  * auxlily.c
  229  */
  230 
  231 /* Compute *screen* size */
  232 FL uz n_screensize(void);
  233 
  234 /* In n_PSO_INTERACTIVE, we want to go over $PAGER.
  235  * These are specialized version of fs_pipe_open()/fs_pipe_close() which also
  236  * encapsulate error message printing, terminal handling etc. additionally */
  237 FL FILE *mx_pager_open(void);
  238 FL boole mx_pager_close(FILE *fp);
  239 
  240 /* Use a pager or STDOUT to print *fp*; if *lines* is 0, they'll be counted */
  241 FL void        page_or_print(FILE *fp, uz lines);
  242 
  243 /* Parse name and guess at the required protocol.
  244  * If check_stat is true then stat(2) will be consulted - a TODO c..p hack
  245  * TODO that together with *newfolders*=maildir adds Maildir support; sigh!
  246  * If try_hooks is set check_stat is implied and if the stat(2) fails all
  247  * file-hook will be tried in order to find a supported version of name.
  248  * If adjusted_or_null is not NULL it will be set to the final version of name
  249  * this function knew about: a %: FEDIT_SYSBOX prefix is forgotten, in case
  250  * a hook is needed the "real" filename will be placed.
  251  * TODO This c..p should be URL::from_string()->protocol() or something! */
  252 FL enum protocol  which_protocol(char const *name, boole check_stat,
  253                      boole try_hooks, char const **adjusted_or_null);
  254 
  255 /* Hexadecimal itoa (NUL terminates) / atoi (-1 on error) */
  256 FL char *      n_c_to_hex_base16(char store[3], char c);
  257 FL s32      n_c_from_hex_base16(char const hex[2]);
  258 
  259 /* Return the name of the dead.letter file */
  260 FL char const * n_getdeadletter(void);
  261 
  262 /* Detect and query the hostname to use */
  263 FL char *n_nodename(boole mayoverride);
  264 
  265 /* Convert from / to *ttycharset* */
  266 #ifdef mx_HAVE_IDNA
  267 FL boole n_idna_to_ascii(struct n_string *out, char const *ibuf, uz ilen);
  268 /*TODO FL boole n_idna_from_ascii(struct n_string *out, char const *ibuf,
  269             uz ilen);*/
  270 #endif
  271 
  272 /* Check whether the argument string is a TRU1 or FAL0 boolean, or an invalid
  273  * string, in which case TRUM1 is returned.
  274  * If the input buffer is empty emptyrv is used as the return: if it is GE
  275  * FAL0 it will be made a binary boolean, otherwise TRU2 is returned.
  276  * inlen may be UZ_MAX to force su_cs_len() detection */
  277 FL boole n_boolify(char const *inbuf, uz inlen, boole emptyrv);
  278 
  279 /* Dig a "quadoption" in inbuf, possibly going through getapproval() in
  280  * interactive mode, in which case prompt is printed first if set.
  281 .  Just like n_boolify() otherwise */
  282 FL boole n_quadify(char const *inbuf, uz inlen, char const *prompt,
  283             boole emptyrv);
  284 
  285 /* Is the argument "all" (case-insensitive) or "*" */
  286 FL boole n_is_all_or_aster(char const *name);
  287 
  288 /* Get seconds since epoch, return pointer to static struct.
  289  * Unless force_update is true we may use the event-loop tick time */
  290 FL struct n_timespec const *n_time_now(boole force_update);
  291 #define n_time_epoch() ((time_t)n_time_now(FAL0)->ts_sec)
  292 
  293 /* Update *tc* to now; only .tc_time updated unless *full_update* is true */
  294 FL void        time_current_update(struct time_current *tc,
  295                   boole full_update);
  296 
  297 /* ctime(3), but do ensure 26 byte limit, do not crash XXX static buffer.
  298  * NOTE: no trailing newline */
  299 FL char *n_time_ctime(s64 secsepoch, struct tm const *localtime_or_nil);
  300 
  301 /* Returns 0 if fully slept, number of millis left if ignint is true and we
  302  * were interrupted.  Actual resolution may be second or less.
  303  * Note in case of mx_HAVE_SLEEP this may be SIGALARM based. */
  304 FL uz n_msleep(uz millis, boole ignint);
  305 
  306 /* Our error print series..  Note: these reverse scan format in order to know
  307  * whether a newline was included or not -- this affects the output!
  308  * xxx Prototype changes to be reflected in src/su/core-code. (for now) */
  309 FL void n_err(char const *format, ...);
  310 FL void n_errx(boole allow_multiple, char const *format, ...);
  311 FL void n_verr(char const *format, va_list ap);
  312 FL void n_verrx(boole allow_multiple, char const *format, va_list ap);
  313 
  314 /* ..(for use in a signal handler; to be obsoleted..).. */
  315 FL void        n_err_sighdl(char const *format, ...);
  316 
  317 /* Our perror(3); if errval is 0 su_err_no() is used; newline appended */
  318 FL void        n_perr(char const *msg, int errval);
  319 
  320 /* Announce a fatal error (and die); newline appended */
  321 FL void        n_alert(char const *format, ...);
  322 FL void        n_panic(char const *format, ...);
  323 
  324 /* `errors' */
  325 #ifdef mx_HAVE_ERRORS
  326 FL int c_errors(void *vp);
  327 #endif
  328 
  329 /* */
  330 #ifdef mx_HAVE_REGEX
  331 FL char const *n_regex_err_to_doc(const regex_t *rep, int e);
  332 #endif
  333 
  334 /* Shared code for c_unxy() which base upon su_cs_dict, e.g., `shortcut' */
  335 FL su_boole mx_unxy_dict(char const *cmdname, struct su_cs_dict *dp, void *vp);
  336 
  337 /* Sort all keys of dp, iterate over them, call the given hook ptf for each
  338  * key/data pair, place any non-NIL returned in the *result list.
  339  * A non-NIL *result will not be updated, but be appended to.
  340  * tailpp_or_nil can be set to speed up follow runs.
  341  * The boole return states error, *result may be NIL even upon success,
  342  * e.g., if dp is NIL or empty */
  343 FL boole mx_xy_dump_dict(char const *cmdname, struct su_cs_dict *dp,
  344       struct n_strlist **result, struct n_strlist **tailpp_or_nil,
  345       struct n_strlist *(*ptf)(char const *cmdname, char const *key,
  346          void const *dat));
  347 
  348 /* Default callback which can be used when dat is in fact a char const* */
  349 FL struct n_strlist *mx_xy_dump_dict_gen_ptf(char const *cmdname,
  350       char const *key, void const *dat);
  351 
  352 /* page_or_print() all members of slp, one line per node.
  353  * If slp is NIL print a line that no cmdname are registered.
  354  * If cnt_lines is FAL0 then each slp entry is assumed to be one line without
  355  * a trailing newline character, otherwise these characters are counted and
  356  * a trailing such is put as necessary */
  357 FL boole mx_page_or_print_strlist(char const *cmdname,
  358       struct n_strlist *slp, boole cnt_lines);
  359 
  360 /*
  361  * cmd-cnd.c
  362  */
  363 
  364 /* if.elif.else.endif conditional execution */
  365 FL int c_if(void *v);
  366 FL int c_elif(void *v);
  367 FL int c_else(void *v);
  368 FL int c_endif(void *v);
  369 
  370 /* Whether an `if' block exists (TRU1) / is in a whiteout condition (TRUM1) */
  371 FL boole n_cnd_if_exists(void);
  372 
  373 /* An execution context is teared down, and it finds to have an if stack */
  374 FL void n_cnd_if_stack_del(struct n_go_data_ctx *gdcp);
  375 
  376 /*
  377  * cmd-folder.c
  378  */
  379 
  380 /* `file' (`folder') and `File' (`Folder') */
  381 FL int c_file(void *v);
  382 FL int c_File(void *v);
  383 
  384 /* 'newmail' command: Check for new mail without writing old mail back */
  385 FL int c_newmail(void *v);
  386 
  387 /* noop */
  388 FL int c_noop(void *v);
  389 
  390 /* Remove mailbox */
  391 FL int c_remove(void *v);
  392 
  393 /* Rename mailbox */
  394 FL int c_rename(void *v);
  395 
  396 /* List the folders the user currently has */
  397 FL int c_folders(void *v);
  398 
  399 /*
  400  * cmd-head.c
  401  */
  402 
  403 /* `headers' (show header group, possibly after setting dot) */
  404 FL int c_headers(void *v);
  405 
  406 /* Like c_headers(), but pre-prepared message vector */
  407 FL int print_header_group(int *vector);
  408 
  409 /* Scroll to the next/previous screen */
  410 FL int c_scroll(void *v);
  411 FL int c_Scroll(void *v);
  412 
  413 /* Move the dot up or down by one message */
  414 FL int c_dotmove(void *v);
  415 
  416 /* Print out the headlines for each message in the passed message list */
  417 FL int c_from(void *v);
  418 
  419 /* Print all messages in msgvec visible and either only_marked is false or they
  420  * are MMARKed.
  421  * TODO If subject_thread_compress is true then a subject will not be printed
  422  * TODO if it equals the subject of the message "above"; as this only looks
  423  * TODO in the thread neighbour and NOT in the "visible" neighbour, the caller
  424  * TODO has to ensure the result will look sane; DROP + make it work (tm) */
  425 FL void print_headers(int const *msgvec, boole only_marked,
  426          boole subject_thread_compress);
  427 
  428 /*
  429  * cmd-msg.c
  430  */
  431 
  432 /* Paginate messages, honour/don't honour ignored fields, respectively */
  433 FL int c_more(void *v);
  434 FL int c_More(void *v);
  435 
  436 /* Type out messages, honour/don't honour ignored fields, respectively */
  437 FL int c_type(void *v);
  438 FL int c_Type(void *v);
  439 
  440 /* Show raw message content */
  441 FL int c_show(void *v);
  442 
  443 /* `mimeview' */
  444 FL int c_mimeview(void *vp);
  445 
  446 /* Pipe messages, honour/don't honour ignored fields, respectively */
  447 FL int c_pipe(void *vp);
  448 FL int c_Pipe(void *vp);
  449 
  450 /* Print the first *toplines* of each desired message */
  451 FL int c_top(void *v);
  452 FL int c_Top(void *v);
  453 
  454 /* If any arguments were given, go to the next applicable argument following
  455  * dot, otherwise, go to the next applicable message.  If given as first
  456  * command with no arguments, print first message */
  457 FL int c_next(void *v);
  458 
  459 /* `=': print out the value(s) of <msglist> (or dot) */
  460 FL int c_pdot(void *vp);
  461 
  462 /* Print the size of each message */
  463 FL int c_messize(void *v);
  464 
  465 /* Delete messages */
  466 FL int c_delete(void *v);
  467 
  468 /* Delete messages, then type the new dot */
  469 FL int c_deltype(void *v);
  470 
  471 /* Undelete the indicated messages */
  472 FL int c_undelete(void *v);
  473 
  474 /* Touch all the given messages so that they will get mboxed */
  475 FL int c_stouch(void *v);
  476 
  477 /* Make sure all passed messages get mboxed */
  478 FL int c_mboxit(void *v);
  479 
  480 /* Preserve messages, so that they will be sent back to the system mailbox */
  481 FL int c_preserve(void *v);
  482 
  483 /* Mark all given messages as unread */
  484 FL int c_unread(void *v);
  485 
  486 /* Mark all given messages as read */
  487 FL int c_seen(void *v);
  488 
  489 /* Message flag manipulation */
  490 FL int c_flag(void *v);
  491 FL int c_unflag(void *v);
  492 FL int c_answered(void *v);
  493 FL int c_unanswered(void *v);
  494 FL int c_draft(void *v);
  495 FL int c_undraft(void *v);
  496 
  497 /*
  498  * cmd-misc.c
  499  */
  500 
  501 /* `!': process a shell escape by saving signals, ignoring signals and sh -c */
  502 FL int c_shell(void *v);
  503 
  504 /* `shell': fork an interactive shell */
  505 FL int c_dosh(void *v);
  506 
  507 /* `cwd': print user's working directory */
  508 FL int c_cwd(void *v);
  509 
  510 /* `chdir': change user's working directory */
  511 FL int c_chdir(void *v);
  512 
  513 /* `echo' series: expand file names like echo (to stdout/stderr, with/out
  514  * trailing newline) */
  515 FL int c_echo(void *v);
  516 FL int c_echoerr(void *v);
  517 FL int c_echon(void *v);
  518 FL int c_echoerrn(void *v);
  519 
  520 /* `read', `readsh' */
  521 FL int c_read(void *vp);
  522 FL int c_readsh(void *vp);
  523 
  524 /* `readall' */
  525 FL int c_readall(void *vp);
  526 
  527 /* `version', and generic support for the shared initial version line, which
  528  * appends to sp the UA name, version etc., and a \n LF */
  529 FL struct n_string *n_version(struct n_string *sp);
  530 FL int c_version(void *vp);
  531 
  532 /*
  533  * cmd-resend.c
  534  */
  535 
  536 /* All thinkable sorts of `reply' / `respond' and `followup'.. */
  537 FL int c_reply(void *vp);
  538 FL int c_replyall(void *vp); /* v15-compat */
  539 FL int c_replysender(void *vp); /* v15-compat */
  540 FL int c_Reply(void *vp);
  541 FL int c_followup(void *vp);
  542 FL int c_followupall(void *vp); /* v15-compat */
  543 FL int c_followupsender(void *vp); /* v15-compat */
  544 FL int c_Followup(void *vp);
  545 
  546 /* ..and a mailing-list reply and followup */
  547 FL int c_Lreply(void *vp);
  548 FL int c_Lfollowup(void *vp);
  549 
  550 /* 'forward' / `Forward' */
  551 FL int c_forward(void *vp);
  552 FL int c_Forward(void *vp);
  553 
  554 /* Resend a message list to a third person.
  555  * The latter does not add the Resent-* header series */
  556 FL int c_resend(void *vp);
  557 FL int c_Resend(void *vp);
  558 
  559 /*
  560  * cmd-write.c
  561  */
  562 
  563 /* Save a message in a file.  Mark the message as saved so we can discard when
  564  * the user quits */
  565 FL int c_save(void *vp);
  566 FL int c_Save(void *vp);
  567 
  568 /* Copy a message to a file without affected its saved-ness */
  569 FL int c_copy(void *vp);
  570 FL int c_Copy(void *vp);
  571 
  572 /* Move a message to a file */
  573 FL int c_move(void *vp);
  574 FL int c_Move(void *vp);
  575 
  576 /* Decrypt and copy a message to a file.  Like plain `copy' at times */
  577 FL int c_decrypt(void *vp);
  578 FL int c_Decrypt(void *vp);
  579 
  580 /* Write the indicated messages at the end of the passed file name, minus
  581  * header and trailing blank line.  This is the MIME save function */
  582 FL int c_write(void *vp);
  583 
  584 /*
  585  * collect.c
  586  */
  587 
  588 /* temporary_compose_mode_hook_call() etc. setter hook */
  589 FL void n_temporary_compose_hook_varset(void *arg);
  590 
  591 /* If quotefile is (char*)-1, stdin will be used, caller has to verify that
  592  * we're not running in interactive mode */
  593 FL FILE *n_collect(enum n_mailsend_flags msf, struct header *hp,
  594             struct message *mp, char const *quotefile, s8 *checkaddr_err);
  595 
  596 /*
  597  * folder.c
  598  */
  599 
  600 /* Set up editing on the given file name.
  601  * If the first character of name is %, we are considered to be editing the
  602  * file, otherwise we are reading our mail which has signficance for mbox and
  603  * so forth */
  604 FL int         setfile(char const *name, enum fedit_mode fm);
  605 
  606 FL int         newmailinfo(int omsgCount);
  607 
  608 /* Set the size of the message vector used to construct argument lists to
  609  * message list functions */
  610 FL void        setmsize(int sz);
  611 
  612 /* Logic behind -H / -L invocations */
  613 FL void        print_header_summary(char const *Larg);
  614 
  615 /* Announces the current folder as indicated.
  616  * Is responsible for updating "dot" (after a folder change). */
  617 FL void n_folder_announce(enum n_announce_flags af);
  618 
  619 FL int         getmdot(int nmail);
  620 
  621 FL void        initbox(char const *name);
  622 
  623 /* Determine and expand the current *folder* name, return it (with trailing
  624  * solidus) or the empty string also in case of errors: since POSIX mandates
  625  * a default of CWD if not set etc., that seems to be a valid fallback, then */
  626 FL char const *n_folder_query(void);
  627 
  628 /* Prepare the seekable O_APPEND MBOX fout for appending of another message.
  629  * If st_or_null is not NULL it is assumed to point to an up-to-date status of
  630  * fout, otherwise an internal fstat(2) is performed as necessary.
  631  * Returns su_err_no() of error */
  632 FL int n_folder_mbox_prepare_append(FILE *fout, struct stat *st_or_null);
  633 
  634 /*
  635  * go.c
  636  * Program input of all sorts, input lexing, event loops, command evaluation.
  637  * Also alias handling.
  638  */
  639 
  640 /* Setup the run environment; this i *only* for main() */
  641 FL void n_go_init(void);
  642 
  643 /* Interpret user commands.  If stdin is not a tty, print no prompt; return
  644  * whether last processed command returned error; this is *only* for main()! */
  645 FL boole n_go_main_loop(void);
  646 
  647 /* Actual cmd input */
  648 
  649 /* */
  650 FL void n_go_input_clearerr(void);
  651 
  652 /* Force n_go_input() to read EOF next */
  653 FL void n_go_input_force_eof(void);
  654 
  655 /* Returns true if force_eof() has been set -- it is set automatically if
  656  * an input context enters EOF state (rather than error, as in ferror(3)) */
  657 FL boole n_go_input_is_eof(void);
  658 
  659 /* Are there any go_input_inject()ions pending? */
  660 FL boole n_go_input_have_injections(void);
  661 
  662 /* Force n_go_input() to read that buffer next.
  663  * If n_GO_INPUT_INJECT_COMMIT is not set the line editor is reentered with buf
  664  * as the default/initial line content */
  665 FL void n_go_input_inject(enum n_go_input_inject_flags giif, char const *buf,
  666             uz len);
  667 
  668 /* Read a complete line of input, with editing if interactive and possible.
  669  * string_or_nil is the optional initial line content if in interactive
  670  * mode, otherwise this argument is ignored for reproducibility.
  671  * If histok_or_nil is set it will be updated to FAL0 if input shall not be
  672  * placed in history.
  673  * Return number of octets or a value <0 on error.
  674  * Note: may use the currently `source'd file stream instead of stdin!
  675  * Manages the n_PS_READLINE_NL hack
  676  * TODO We need an OnReadLineCompletedEvent and drop this function */
  677 FL int n_go_input(enum n_go_input_flags gif, char const *prompt_or_nil,
  678          char **linebuf, uz *linesize, char const *string_or_nil,
  679          boole *histok_or_nil  su_DBG_LOC_ARGS_DECL);
  680 #ifdef su_HAVE_DBG_LOC_ARGS
  681 # define n_go_input(A,B,C,D,E,F) n_go_input(A,B,C,D,E,F  su_DBG_LOC_ARGS_INJ)
  682 #endif
  683 
  684 /* Like go_input(), but return savestr()d result or NIL in case of errors or if
  685  * an empty line would be returned.
  686  * This may only be called from toplevel (not during n_PS_ROBOT) */
  687 FL char *n_go_input_cp(enum n_go_input_flags gif, char const *prompt_or_nil,
  688             char const *string_or_nil);
  689 
  690 /* Deal with loading of resource files and dealing with a stack of files for
  691  * the source command */
  692 
  693 /* Load a file of user system startup resources.
  694  * *Only* for main(), returns whether program shall continue */
  695 FL boole n_go_load_rc(char const *name);
  696 
  697 /* "Load" or go_inject() command line option "cmd" arguments in order.
  698  * *Only* for main(), returns whether program shall continue unless injectit is
  699  * set, in which case this function does not fail.
  700  * If lines is NIL the builtin RC file is used, and errors are ignored */
  701 FL boole n_go_load_lines(boole injectit, char const **lines, uz cnt);
  702 
  703 /* Pushdown current input file and switch to a new one. */
  704 FL int c_source(void *v);
  705 FL int c_source_if(void *v);
  706 
  707 /* Evaluate a complete macro / a single command.  For the former lines will
  708  * always be free()d, for the latter cmd will always be duplicated internally */
  709 FL boole n_go_macro(enum n_go_input_flags gif, char const *name, char **lines,
  710             void (*on_finalize)(void*), void *finalize_arg);
  711 FL boole n_go_command(enum n_go_input_flags gif, char const *cmd);
  712 
  713 /* XXX See a_GO_SPLICE in source */
  714 FL void n_go_splice_hack(char const *cmd, FILE *new_stdin, FILE *new_stdout,
  715          u32 new_psonce, void (*on_finalize)(void*), void *finalize_arg);
  716 FL void n_go_splice_hack_remove_after_jump(void);
  717 
  718 /* XXX Hack: may we release our (interactive) (terminal) control to a different
  719  * XXX program, e.g., a $PAGER? */
  720 FL boole n_go_may_yield_control(void);
  721 
  722 /* `eval' */
  723 FL int c_eval(void *vp);
  724 
  725 /* `xcall' */
  726 FL int c_xcall(void *vp);
  727 
  728 /* `exit' and `quit' commands */
  729 FL int c_exit(void *vp);
  730 FL int c_quit(void *vp);
  731 
  732 /* `readctl' */
  733 FL int c_readctl(void *vp);
  734 
  735 /*
  736  * header.c
  737  */
  738 
  739 /* Return the user's From: address(es) */
  740 FL char const * myaddrs(struct header *hp);
  741 
  742 /* Boil the user's From: addresses down to a single one, or use *sender* */
  743 FL char const * myorigin(struct header *hp);
  744 
  745 /* See if the passed line buffer, which may include trailing newline (sequence)
  746  * is a mail From_ header line according to POSIX ("From ").
  747  * If check_rfc4155 is true we'll return TRUM1 instead if the From_ line
  748  * matches POSIX but is _not_ compatible to RFC 4155 */
  749 FL boole      is_head(char const *linebuf, uz linelen,
  750                   boole check_rfc4155);
  751 
  752 /* Return pointer to first non-header, non-space character, or NIL if invalid.
  753  * If lead_ws is true leading whitespace is allowed and skipped.
  754  * If cramp_or_nil is not NIL it will be set to the valid header name itself */
  755 FL char const *mx_header_is_valid(char const *name, boole lead_ws,
  756       struct str *cramp_or_nil);
  757 
  758 /* Print hp "to user interface" fp for composing purposes xxx what a sigh */
  759 FL boole n_header_put4compose(FILE *fp, struct header *hp);
  760 
  761 /* Extract some header fields (see e.g. -t documentation) from a message.
  762  * This calls expandaddr() on some headers and sets checkaddr_err_or_null if
  763  * that is set -- note it explicitly allows EAF_NAME because aliases are not
  764  * expanded when this is called! */
  765 FL void n_header_extract(enum n_header_extract_flags hef, FILE *fp,
  766          struct header *hp, s8 *checkaddr_err_or_null);
  767 
  768 /* Return the desired header line from the passed message
  769  * pointer (or NULL if the desired header field is not available).
  770  * If mult is zero, return the content of the first matching header
  771  * field only, the content of all matching header fields else */
  772 FL char *      hfield_mult(char const *field, struct message *mp, int mult);
  773 #define hfieldX(a, b)            hfield_mult(a, b, 1)
  774 #define hfield1(a, b)            hfield_mult(a, b, 0)
  775 
  776 /* Check whether the passed line is a header line of the desired breed.
  777  * If qm_suffix_or_nil is set then the field?[MOD]: syntax is supported, the
  778  * suffix substring range of linebuf will be stored in there, then, or NIL;
  779  * this logically casts away the const.
  780  * Return the field body, or NULL */
  781 FL char const *n_header_get_field(char const *linebuf, char const *field,
  782       struct str *qm_suffix_or_nil);
  783 
  784 /* Start of a "comment".  Ignore it */
  785 FL char const * skip_comment(char const *cp);
  786 
  787 /* Return the start of a route-addr (address in angle brackets), if present */
  788 FL char const * routeaddr(char const *name);
  789 
  790 /* Query *expandaddr*, parse it and return flags.
  791  * The flags are already adjusted for n_PSO_INTERACTIVE, n_PO_TILDE_FLAG etc. */
  792 FL enum expand_addr_flags expandaddr_to_eaf(void);
  793 
  794 /* Check if an address is invalid, either because it is malformed or, if not,
  795  * according to eacm.  Return FAL0 when it looks good, TRU1 if it is invalid
  796  * but the error condition wasn't covered by a 'hard "fail"ure', -1 otherwise */
  797 FL s8       is_addr_invalid(struct mx_name *np,
  798                   enum expand_addr_check_mode eacm);
  799 
  800 /* Does *NP* point to a file or pipe addressee? */
  801 #define is_fileorpipe_addr(NP)   \
  802    (((NP)->n_flags & mx_NAME_ADDRSPEC_ISFILEORPIPE) != 0)
  803 
  804 /* Skin an address according to the RFC 822 interpretation of "host-phrase" */
  805 FL char *      skin(char const *name);
  806 
  807 /* Skin *name* and extract *addr-spec* according to RFC 5322 and enum gfield.
  808  * Store the result in .ag_skinned and also fill in those .ag_ fields that have
  809  * actually been seen.
  810  * Return NULL on error, or name again, but which may have been replaced by
  811  * a version with fixed quotation etc.! */
  812 FL char const *n_addrspec_with_guts(struct n_addrguts *agp, char const *name,
  813       u32 gfield);
  814 
  815 /* `addrcodec' */
  816 FL int c_addrcodec(void *vp);
  817 
  818 /* Fetch the real name from an internet mail address field */
  819 FL char *      realname(char const *name);
  820 
  821 /* Look for a RFC 2369 List-Post: header, return NIL if none was found, -1 if
  822  * the one found forbids posting to the list, a header otherwise.
  823  * .n_type needs to be set to something desired still */
  824 FL struct mx_name *mx_header_list_post_of(struct message *mp);
  825 
  826 /* Get the sender (From: or Sender:) of this message, or NIL.
  827  * If gf is 0 GFULL|GSKIN is used (no senderfield beside that) */
  828 FL struct mx_name *mx_header_sender_of(struct message *mp, u32 gf);
  829 
  830 /* Get header_sender_of(), or From_ line from this message.
  831  * The return value may be empty and needs lextract()ion */
  832 FL char *n_header_senderfield_of(struct message *mp);
  833 
  834 /* Trim away all leading Re: etc., return pointer to plain subject.
  835  * Note it doesn't perform any MIME decoding by itself */
  836 FL char const *subject_re_trim(char const *cp);
  837 
  838 FL int         msgidcmp(char const *s1, char const *s2);
  839 
  840 /* Fake Sender for From_ lines if missing, e. g. with POP3 */
  841 FL char const * fakefrom(struct message *mp);
  842 
  843 /* From username Fri Jan  2 20:13:51 2004
  844  *               |    |    |    |    |
  845  *               0    5   10   15   20 */
  846 #if defined mx_HAVE_IMAP_SEARCH || defined mx_HAVE_IMAP
  847 FL time_t      unixtime(char const *from);
  848 #endif
  849 
  850 FL time_t      rfctime(char const *date);
  851 
  852 FL time_t      combinetime(int year, int month, int day,
  853                   int hour, int minute, int second);
  854 
  855 /* Determine the date to print in faked 'From ' lines */
  856 FL void        substdate(struct message *m);
  857 
  858 /* Create ready-to-go environment taking into account *datefield* etc.,
  859  * and return a result in auto-reclaimed storage.
  860  * TODO hack *color_tag_or_null could be set to n_COLOUR_TAG_SUM_OLDER.
  861  * time_current is used for comparison and must thus be up-to-date */
  862 FL char *n_header_textual_date_info(struct message *mp,
  863             char const **color_tag_or_null);
  864 
  865 /* Create ready-to-go sender name of a message in *cumulation_or_null, the
  866  * addresses only in *addr_or_null, the real names only in *name_real_or_null,
  867  * and the full names in *name_full_or_null, taking account for *showname*.
  868  * If *is_to_or_null is set, *showto* and n_is_myname() are taken into account
  869  * when choosing which names to use.
  870  * The list as such is returned, or NULL if there is really none (empty strings
  871  * will be stored, then).
  872  * All results are in auto-reclaimed storage, but may point to the same string.
  873  * TODO *is_to_or_null could be set to whether we actually used To:, or not.
  874  * TODO n_header_textual_sender_info(): should only create a list of matching
  875  * TODO name objects, which the user can iterate over and o->to_str().. */
  876 FL struct mx_name *n_header_textual_sender_info(struct message *mp,
  877                   char **cumulation_or_null, char **addr_or_null,
  878                   char **name_real_or_null, char **name_full_or_null,
  879                   boole *is_to_or_null);
  880 
  881 /* TODO Weird thing that tries to fill in From: and Sender: */
  882 FL void        setup_from_and_sender(struct header *hp);
  883 
  884 /* Note: returns 0x1 if both args were NULL */
  885 FL struct mx_name const *check_from_and_sender(struct mx_name const *fromfield,
  886                         struct mx_name const *senderfield);
  887 
  888 #ifdef mx_HAVE_XTLS
  889 FL char *      getsender(struct message *m);
  890 #endif
  891 
  892 /* This returns NULL if hp is NULL or when no information is available.
  893  * hp remains unchanged (->h_in_reply_to is not set!)  */
  894 FL struct mx_name *n_header_setup_in_reply_to(struct header *hp);
  895 
  896 /* Fill in / reedit the desired header fields */
  897 FL int         grab_headers(enum n_go_input_flags gif, struct header *hp,
  898                   enum gfield gflags, int subjfirst);
  899 
  900 /* Check whether sep->ss_sexpr (or ->ss_sregex) matches any header of mp.
  901  * If sep->s_where (or >s_where_wregex) is set, restrict to given headers */
  902 FL boole n_header_match(struct message *mp, struct search_expr const *sep);
  903 
  904 /* Verify whether len (UZ_MAX=su_cs_len) bytes of name form a standard or
  905  * otherwise known header name (that must not be used as a custom header).
  906  * Return the (standard) header name, or NULL */
  907 FL char const *n_header_is_known(char const *name, uz len);
  908 
  909 /* Add a custom header to the given list, in auto-reclaimed or heap memory */
  910 FL boole n_header_add_custom(struct n_header_field **hflp, char const *dat,
  911             boole heap);
  912 
  913 /*
  914  * ignore.c
  915  */
  916 
  917 /* `(un)?headerpick' */
  918 FL int c_headerpick(void *vp);
  919 FL int c_unheaderpick(void *vp);
  920 
  921 /* TODO Compat variants of the c_(un)?h*() series,
  922  * except for `retain' and `ignore', which are standardized */
  923 FL int c_retain(void *vp);
  924 FL int c_ignore(void *vp);
  925 FL int c_unretain(void *vp);
  926 FL int c_unignore(void *vp);
  927 
  928 FL int         c_saveretain(void *v);
  929 FL int         c_saveignore(void *v);
  930 FL int         c_unsaveretain(void *v);
  931 FL int         c_unsaveignore(void *v);
  932 
  933 FL int         c_fwdretain(void *v);
  934 FL int         c_fwdignore(void *v);
  935 FL int         c_unfwdretain(void *v);
  936 FL int         c_unfwdignore(void *v);
  937 
  938 /* Ignore object lifecycle.  (Most of the time this interface deals with
  939  * special n_IGNORE_* objects, e.g., n_IGNORE_TYPE, though.)
  940  * isauto: whether auto-reclaimed storage is to be used for allocations;
  941  * if so, _del() needn't be called */
  942 FL struct n_ignore *n_ignore_new(boole isauto);
  943 FL void n_ignore_del(struct n_ignore *self);
  944 
  945 /* Are there just _any_ user settings covered by self? */
  946 FL boole n_ignore_is_any(struct n_ignore const *self);
  947 
  948 /* Set an entry to retain (or ignore).
  949  * Returns FAL0 if dat is not a valid header field name or an invalid regular
  950  * expression, TRU1 if insertion took place, and TRUM1 if already set */
  951 FL boole n_ignore_insert(struct n_ignore *self, boole retain,
  952             char const *dat, uz len);
  953 #define n_ignore_insert_cp(SELF,RT,CP) n_ignore_insert(SELF, RT, CP, UZ_MAX)
  954 
  955 /* Returns TRU1 if retained, TRUM1 if ignored, FAL0 if not covered */
  956 FL boole n_ignore_lookup(struct n_ignore const *self, char const *dat,
  957             uz len);
  958 #define n_ignore_lookup_cp(SELF,CP) n_ignore_lookup(SELF, CP, UZ_MAX)
  959 #define n_ignore_is_ign(SELF,FDAT,FLEN) \
  960    (n_ignore_lookup(SELF, FDAT, FLEN) == TRUM1)
  961 
  962 /*
  963  * imap-search.c
  964  */
  965 
  966 /* Return -1 on invalid spec etc., the number of matches otherwise */
  967 #ifdef mx_HAVE_IMAP_SEARCH
  968 FL sz     imap_search(char const *spec, int f);
  969 #endif
  970 
  971 /*
  972  * maildir.c
  973  */
  974 
  975 #ifdef mx_HAVE_MAILDIR
  976 FL int maildir_setfile(char const *who, char const *name, enum fedit_mode fm);
  977 
  978 FL boole maildir_quit(boole hold_sigs_on);
  979 
  980 FL enum okay maildir_append(char const *name, FILE *fp, long offset);
  981 
  982 FL enum okay maildir_remove(char const *name);
  983 #endif /* mx_HAVE_MAILDIR */
  984 
  985 /*
  986  * (Former memory.c, now SU TODO get rid of compat macros)
  987  * Heap memory and automatically reclaimed storage, plus pseudo "alloca"
  988  *
  989  */
  990 
  991 /* Generic heap memory */
  992 #define n_alloc su_MEM_ALLOC
  993 #define n_realloc su_MEM_REALLOC
  994 #define n_calloc(NO,SZ) su_MEM_CALLOC_N(SZ, NO)
  995 #define n_free su_MEM_FREE
  996 
  997 /* Auto-reclaimed storage */
  998 #define n_autorec_relax_create() \
  999       su_mem_bag_auto_relax_create(n_go_data->gdc_membag)
 1000 #define n_autorec_relax_gut() \
 1001       su_mem_bag_auto_relax_gut(n_go_data->gdc_membag)
 1002 #define n_autorec_relax_unroll() \
 1003       su_mem_bag_auto_relax_unroll(n_go_data->gdc_membag)
 1004 /* (Even older obsolete names!) */
 1005 #define srelax_hold n_autorec_relax_create
 1006 #define srelax_rele n_autorec_relax_gut
 1007 #define srelax n_autorec_relax_unroll
 1008 
 1009 #define n_autorec_alloc su_MEM_BAG_SELF_AUTO_ALLOC
 1010 #define n_autorec_calloc(NO,SZ) su_MEM_BAG_SELF_AUTO_CALLOC_N(SZ, NO)
 1011 
 1012 /* Pseudo alloca (and also auto-reclaimed) */
 1013 #define n_lofi_alloc su_MEM_BAG_SELF_LOFI_ALLOC
 1014 #define n_lofi_calloc su_MEM_BAG_SELF_LOFI_CALLOC
 1015 #define n_lofi_free su_MEM_BAG_SELF_LOFI_FREE
 1016 
 1017 #define n_lofi_snap_create() su_mem_bag_lofi_snap_create(n_go_data->gdc_membag)
 1018 #define n_lofi_snap_unroll(COOKIE) \
 1019    su_mem_bag_lofi_snap_unroll(n_go_data->gdc_membag, COOKIE)
 1020 
 1021 /*
 1022  * message.c
 1023  */
 1024 
 1025 /* Return a file buffer all ready to read up the passed message pointer */
 1026 FL FILE *      setinput(struct mailbox *mp, struct message *m,
 1027                   enum needspec need);
 1028 
 1029 /*  */
 1030 FL enum okay   get_body(struct message *mp);
 1031 
 1032 /* Reset (free) the global message array */
 1033 FL void        message_reset(void);
 1034 
 1035 /* Append the passed message descriptor onto the message array; if mp is NULL,
 1036  * NULLify the entry at &[msgCount-1] */
 1037 FL void        message_append(struct message *mp);
 1038 
 1039 /* Append a NULL message */
 1040 FL void        message_append_null(void);
 1041 
 1042 /* Check whether sep->ss_sexpr (or ->ss_sregex) matches mp.  If with_headers is
 1043  * true then the headers will also be searched (as plain text) */
 1044 FL boole      message_match(struct message *mp, struct search_expr const *sep,
 1045                boole with_headers);
 1046 
 1047 /*  */
 1048 FL struct message * setdot(struct message *mp);
 1049 
 1050 /* Touch the named message by setting its MTOUCH flag.  Touched messages have
 1051  * the effect of not being sent back to the system mailbox on exit */
 1052 FL void        touch(struct message *mp);
 1053 
 1054 /* Convert user message spec. to message numbers and store them in vector,
 1055  * which should be capable to hold msgCount+1 entries (n_msgvec ASSERTs this).
 1056  * flags is cmd_arg_ctx.cac_msgflag==cmd_desc.cd_mflags_o_minargs==enum mflag.
 1057  * If capp_or_null is not NULL then the last (string) token is stored in here
 1058  * and not interpreted as a message specification; in addition, if only one
 1059  * argument remains and this is the empty string, 0 is returned (*vector=0;
 1060  * this is used to implement CMD_ARG_DESC_MSGLIST_AND_TARGET).
 1061  * A NUL *buf input results in a 0 return, *vector=0, [*capp_or_null=NULL].
 1062  * Returns the count of messages picked up or -1 on error */
 1063 FL int n_getmsglist(char const *buf, int *vector, int flags,
 1064          struct mx_cmd_arg **capp_or_null);
 1065 
 1066 /* Find the first message whose flags&m==f and return its message number */
 1067 FL int         first(int f, int m);
 1068 
 1069 /* Mark the named message by setting its mark bit */
 1070 FL void        mark(int mesg, int f);
 1071 
 1072 /*
 1073  * mime.c
 1074  */
 1075 
 1076 /* *sendcharsets* .. *charset-8bit* iterator; *a_charset_to_try_first* may be
 1077  * used to prepend a charset to this list (e.g., for *reply-in-same-charset*).
 1078  * The returned boolean indicates charset_iter_is_valid().
 1079  * Without mx_HAVE_ICONV, this "iterates" over *ttycharset* only */
 1080 FL boole      charset_iter_reset(char const *a_charset_to_try_first);
 1081 FL boole      charset_iter_next(void);
 1082 FL boole      charset_iter_is_valid(void);
 1083 FL char const * charset_iter(void);
 1084 
 1085 /* And this is (xxx temporary?) which returns the iterator if that is valid and
 1086  * otherwise either *charset-8bit* or *ttycharset*, dep. on mx_HAVE_ICONV */
 1087 FL char const * charset_iter_or_fallback(void);
 1088 
 1089 FL void        charset_iter_recurse(char *outer_storage[2]); /* TODO LEGACY */
 1090 FL void        charset_iter_restore(char *outer_storage[2]); /* TODO LEGACY */
 1091 
 1092 /* Check whether our headers will need MIME conversion */
 1093 #ifdef mx_HAVE_ICONV
 1094 FL char const * need_hdrconv(struct header *hp);
 1095 #endif
 1096 
 1097 /* Convert header fields from RFC 1522 format */
 1098 FL void        mime_fromhdr(struct str const *in, struct str *out,
 1099                   enum tdflags flags);
 1100 
 1101 /* Interpret MIME strings in parts of an address field */
 1102 FL char *      mime_fromaddr(char const *name);
 1103 
 1104 /* fwrite(3) performing the given MIME conversion */
 1105 FL sz     mime_write(char const *ptr, uz size, FILE *f,
 1106                   enum conversion convert, enum tdflags dflags,
 1107                   struct quoteflt *qf, struct str *outrest,
 1108                   struct str *inrest);
 1109 FL sz     xmime_write(char const *ptr, uz size, /* TODO LEGACY */
 1110                   FILE *f, enum conversion convert, enum tdflags dflags,
 1111                   struct str *outrest, struct str *inrest);
 1112 
 1113 /*
 1114  * mime-enc.c
 1115  * Content-Transfer-Encodings as defined in RFC 2045 (and RFC 2047):
 1116  * - Quoted-Printable, section 6.7
 1117  * - Base64, section 6.8
 1118  * TODO For now this is pretty mixed up regarding this external interface
 1119  * TODO (and due to that the code is, too).
 1120  * TODO In v15.0 CTE will be filter based, and explicit conversion will
 1121  * TODO gain clear error codes
 1122  */
 1123 
 1124 /* Default MIME Content-Transfer-Encoding: as via *mime-encoding*.
 1125  * Cannot be MIMEE_BIN nor MIMEE_7B (i.e., only B64, QP, 8B) */
 1126 FL enum mime_enc mime_enc_target(void);
 1127 
 1128 /* Map from a Content-Transfer-Encoding: header body (which may be NULL) */
 1129 FL enum mime_enc mime_enc_from_ctehead(char const *hbody);
 1130 
 1131 /* XXX Try to get rid of that */
 1132 FL char const * mime_enc_from_conversion(enum conversion const convert);
 1133 
 1134 /* How many characters of (the complete body) ln need to be quoted.
 1135  * Only MIMEEF_ISHEAD and MIMEEF_ISENCWORD are understood */
 1136 FL uz      mime_enc_mustquote(char const *ln, uz lnlen,
 1137                   enum mime_enc_flags flags);
 1138 
 1139 /* How much space is necessary to encode len bytes in QP, worst case.
 1140  * Includes room for terminator, UZ_MAX on overflow */
 1141 FL uz      qp_encode_calc_size(uz len);
 1142 
 1143 /* If flags includes QP_ISHEAD these assume "word" input and use special
 1144  * quoting rules in addition; soft line breaks are not generated.
 1145  * Otherwise complete input lines are assumed and soft line breaks are
 1146  * generated as necessary.  Return NULL on error (overflow) */
 1147 FL struct str * qp_encode(struct str *out, struct str const *in,
 1148                   enum qpflags flags);
 1149 #ifdef notyet
 1150 FL struct str * qp_encode_cp(struct str *out, char const *cp,
 1151                   enum qpflags flags);
 1152 FL struct str * qp_encode_buf(struct str *out, void const *vp, uz vp_len,
 1153                   enum qpflags flags);
 1154 #endif
 1155 
 1156 /* The buffers of out and *rest* will be managed via n_realloc().
 1157  * If inrest_or_null is needed but NULL an error occurs, otherwise tolerant.
 1158  * Return FAL0 on error; caller is responsible to free buffers */
 1159 FL boole      qp_decode_header(struct str *out, struct str const *in);
 1160 FL boole      qp_decode_part(struct str *out, struct str const *in,
 1161                   struct str *outrest, struct str *inrest_or_null);
 1162 
 1163 /* How much space is necessary to encode len bytes in Base64, worst case.
 1164  * Includes room for (CR/LF/CRLF and) terminator, UZ_MAX on overflow */
 1165 FL uz      b64_encode_calc_size(uz len);
 1166 
 1167 /* Note these simply convert all the input (if possible), including the
 1168  * insertion of NL sequences if B64_CRLF or B64_LF is set (and multiple thereof
 1169  * if B64_MULTILINE is set).
 1170  * Thus, in the B64_BUF case, better call b64_encode_calc_size() first.
 1171  * Return NULL on error (overflow; cannot happen for B64_BUF) */
 1172 FL struct str * b64_encode(struct str *out, struct str const *in,
 1173                   enum b64flags flags);
 1174 FL struct str * b64_encode_buf(struct str *out, void const *vp, uz vp_len,
 1175                   enum b64flags flags);
 1176 #ifdef notyet
 1177 FL struct str * b64_encode_cp(struct str *out, char const *cp,
 1178                   enum b64flags flags);
 1179 #endif
 1180 
 1181 /* The _{header,part}() variants are failure tolerant, the latter requires
 1182  * outrest to be set; due to the odd 4:3 relation inrest_or_null should be
 1183  * given, _then_, it is an error if it is needed but not set.
 1184  * TODO pre v15 callers should ensure that no endless loop is entered because
 1185  * TODO the inrest cannot be converted and ends up as inrest over and over:
 1186  * TODO give NULL to stop such loops.
 1187  * The buffers of out and possibly *rest* will be managed via n_realloc().
 1188  * Returns FAL0 on error; caller is responsible to free buffers.
 1189  * XXX FAL0 is effectively not returned for _part*() variants,
 1190  * XXX (instead replacement characters are produced for invalid data.
 1191  * XXX _Unless_ operation could EOVERFLOW.)
 1192  * XXX I.e. this is bad and is tolerant for text and otherwise not */
 1193 FL boole      b64_decode(struct str *out, struct str const *in);
 1194 FL boole      b64_decode_header(struct str *out, struct str const *in);
 1195 FL boole      b64_decode_part(struct str *out, struct str const *in,
 1196                   struct str *outrest, struct str *inrest_or_null);
 1197 
 1198 /*
 1199  * mime-param.c
 1200  */
 1201 
 1202 /* Get a mime style parameter from a header body */
 1203 FL char *      mime_param_get(char const *param, char const *headerbody);
 1204 
 1205 /* Format parameter name to have value, autorec_alloc() it or NULL in result.
 1206  * 0 on error, 1 or -1 on success: the latter if result contains \n newlines,
 1207  * which it will if the created param requires more than MIME_LINELEN bytes;
 1208  * there is never a trailing newline character */
 1209 /* TODO mime_param_create() should return a StrList<> or something.
 1210  * TODO in fact it should take a HeaderField* and append a HeaderFieldParam*! */
 1211 FL s8       mime_param_create(struct str *result, char const *name,
 1212                   char const *value);
 1213 
 1214 /* Get the boundary out of a Content-Type: multipart/xyz header field, return
 1215  * autorec_alloc()ed copy of it; store su_cs_len() in *len if set */
 1216 FL char *      mime_param_boundary_get(char const *headerbody, uz *len);
 1217 
 1218 /* Create a autorec_alloc()ed MIME boundary */
 1219 FL char *      mime_param_boundary_create(void);
 1220 
 1221 /*
 1222  * mime-parse.c
 1223  */
 1224 
 1225 /* Create MIME part object tree for and of mp */
 1226 FL struct mimepart * mime_parse_msg(struct message *mp,
 1227                         enum mime_parse_flags mpf);
 1228 
 1229 /*
 1230  * path.c
 1231  */
 1232 
 1233 /* Test to see if the passed file name is a directory, return true if it is.
 1234  * If check_access is set, we also access(2): if it is TRUM1 only X_OK|R_OK is
 1235  * tested, otherwise X_OK|R_OK|W_OK. */
 1236 FL boole n_is_dir(char const *name, boole check_access);
 1237 
 1238 /* Recursively create a directory */
 1239 FL boole n_path_mkdir(char const *name);
 1240 
 1241 /* Delete a file, but only if the file is a plain file; return FAL0 on system
 1242  * error and TRUM1 if name is not a plain file, return TRU1 on success */
 1243 FL boole n_path_rm(char const *name);
 1244 
 1245 /* A get-wd..restore-wd approach */
 1246 FL enum okay   cwget(struct cw *cw);
 1247 FL enum okay   cwret(struct cw *cw);
 1248 FL void        cwrelse(struct cw *cw);
 1249 
 1250 /*
 1251  * quit.c
 1252  */
 1253 
 1254 /* Save all of the undetermined messages at the top of "mbox".  Save all
 1255  * untouched messages back in the system mailbox.  Remove the system mailbox,
 1256  * if none saved there.
 1257  * TODO v15 Note: assumes hold_sigs() has been called _and_ can be temporarily
 1258  * TODO dropped via a single rele_sigs() if hold_sigs_on */
 1259 FL boole      quit(boole hold_sigs_on);
 1260 
 1261 /* Adjust the message flags in each message */
 1262 FL int         holdbits(void);
 1263 
 1264 /* Create another temporary file and copy user's mbox file darin.  If there is
 1265  * no mbox, copy nothing.  If he has specified "append" don't copy his mailbox,
 1266  * just copy saveable entries at the end */
 1267 FL enum okay   makembox(void);
 1268 
 1269 FL void        save_mbox_for_possible_quitstuff(void); /* TODO DROP IF U CAN */
 1270 
 1271 FL int         savequitflags(void);
 1272 
 1273 FL void        restorequitflags(int);
 1274 
 1275 /*
 1276  * send.c
 1277  */
 1278 
 1279 /* Send message described by the passed pointer to the passed output buffer.
 1280  * Return -1 on error.  Adjust the status: field if need be.  If doitp is
 1281  * given, suppress ignored header fields.  prefix is a string to prepend to
 1282  * each output line.   action = data destination
 1283  * (SEND_MBOX,_TOFILE,_TODISP,_QUOTE,_DECRYPT).  stats[0] is line count,
 1284  * stats[1] is character count.  stats may be NULL.  Note that stats[0] is
 1285  * valid for SEND_MBOX only */
 1286 FL int         sendmp(struct message *mp, FILE *obuf,
 1287                   struct n_ignore const *doitp,
 1288                   char const *prefix, enum sendaction action, u64 *stats);
 1289 
 1290 /*
 1291  * sendout.c
 1292  */
 1293 
 1294 /* Check whether outgoing transport is via SMTP/SUBMISSION etc.
 1295  * It handles all the *mta* (v15-compat: +*smtp*) cases.
 1296  * Returns TRU1 if yes and URL parsing succeeded, TRUM1 if *mta* is file:// or
 1297  * test:// based, and FAL0 on failure.
 1298  * TODO It will assign CPROTO_NONE and only set urlp->url_input for file-based
 1299  * TODO and test protos, .url_portno is 0 for the former, U16_MAX for latter.
 1300  * TODO Should simply leave all that up to URL, is URL_PROTO_FILExy then). */
 1301 FL boole mx_sendout_mta_url(struct mx_url *urlp);
 1302 
 1303 /* For main() only: interface between the command line argument list and the
 1304  * mail1 routine which does all the dirty work */
 1305 FL int n_mail(enum n_mailsend_flags msf, struct mx_name *to,
 1306       struct mx_name *cc, struct mx_name *bcc, char const *subject,
 1307       struct mx_attachment *attach, char const *quotefile);
 1308 
 1309 /* `mail' and `Mail' commands, respectively */
 1310 FL int c_sendmail(void *v);
 1311 FL int c_Sendmail(void *v);
 1312 
 1313 /* Mail a message on standard input to the people indicated in the passed
 1314  * header, applying all the address massages first.  (Internal interface) */
 1315 FL enum okay n_mail1(enum n_mailsend_flags flags, struct header *hp,
 1316                struct message *quote, char const *quotefile);
 1317 
 1318 /* Create a Date: header field.
 1319  * We compare the localtime() and gmtime() results to get the timezone, because
 1320  * numeric timezones are easier to read and because $TZ isn't always set.
 1321  * Return number of bytes written of -1 */
 1322 FL int mkdate(FILE *fo, char const *field);
 1323 
 1324 /* Dump the to, subject, cc header on the passed file buffer.
 1325  * nosend_msg tells us not to dig to deep but to instead go for compose mode or
 1326  * editing a message (yet we're stupid and cannot do it any better) - if it is
 1327  * TRUM1 then we're really in compose mode and will produce some fields for
 1328  * easier filling in (see n_run_editor() proto for this hack) */
 1329 FL boole n_puthead(boole nosend_msg, struct header *hp, FILE *fo,
 1330                   enum gfield w, enum sendaction action,
 1331                   enum conversion convert, char const *contenttype,
 1332                   char const *charset);
 1333 
 1334 /* Note: hp->h_to must already have undergone address massage(s), it is taken
 1335  * as-is; h_cc and h_bcc are asserted to be NIL.  urlp must have undergone
 1336  * mx_sendout_mta_url() processing */
 1337 FL enum okay n_resend_msg(struct message *mp, struct mx_url *urlp,
 1338       struct header *hp, boole add_resent);
 1339 
 1340 /* *save* / $DEAD */
 1341 FL void        savedeadletter(FILE *fp, boole fflush_rewind_first);
 1342 
 1343 /*
 1344  * shexp.c
 1345  */
 1346 
 1347 /* Evaluate the string given as a new mailbox name. Supported meta characters:
 1348  * . %  for my system mail box
 1349  * . %user for user's system mail box
 1350  * . #  for previous file
 1351  * . &  invoker's mbox file
 1352  * . +file file in folder directory
 1353  * . any shell meta character (except for FEXP_NSHELL).
 1354  * a poor man's vis(3), on name before calling this (and showing the user).
 1355  * If FEXP_MULTIOK is set we return an array of terminated strings, the (last)
 1356  * result string is terminated via \0\0 and n_PS_EXPAND_MULTIRESULT is set.
 1357  * Returns the file name as an auto-reclaimed string */
 1358 FL char *fexpand(char const *name, BITENUM_IS(u32,fexp_mode) fexpm);
 1359 
 1360 /* Parse the next shell token from input (->s and ->l are adjusted to the
 1361  * remains, data is constant beside that; ->s may be NULL if ->l is 0, if ->l
 1362  * EQ UZ_MAX su_cs_len(->s) is used) and append the resulting output to store.
 1363  * If cookie is not NULL and we're in double-quotes then ${@} will be exploded
 1364  * just as known from the sh(1)ell in that case */
 1365 FL BITENUM_IS(u32,n_shexp_state) n_shexp_parse_token(
 1366       BITENUM_IS(u32,n_shexp_parse_flags) flags, struct n_string *store,
 1367       struct str *input, void const **cookie);
 1368 
 1369 /* Quick+dirty simplified : if an error occurs, returns a copy of *cp and set
 1370  * *cp to NULL, otherwise advances *cp to over the parsed token */
 1371 FL char *n_shexp_parse_token_cp(BITENUM_IS(u32,n_shexp_parse_flags) flags,
 1372       char const **cp);
 1373 
 1374 /* Another variant of parse_token_cp(): unquote the argument, ensure the result
 1375  * is "alone": after WS/IFS trimming STATE_STOP must be set, returns TRUM1 if
 1376  * not, TRU1 if STATE_OUTPUT is set, TRU2 if not, FAL0 on error */
 1377 FL boole n_shexp_unquote_one(struct n_string *store, char const *input);
 1378 
 1379 /* Quote input in a way that can, in theory, be fed into parse_token() again.
 1380  * ->s may be NULL if ->l is 0, if ->l EQ UZ_MAX su_cs_len(->s) is used.
 1381  * If rndtrip is true we try to make the resulting string "portable" (by
 1382  * converting Unicode to \u etc.), otherwise we produce something to be
 1383  * consumed "now", i.e., to display for the user.
 1384  * Resulting output is _appended_ to store.
 1385  * TODO Note: last resort, since \u and $ expansions etc. are necessarily
 1386  * TODO already expanded and can thus not be reverted, but ALL we have */
 1387 FL struct n_string *n_shexp_quote(struct n_string *store,
 1388                      struct str const *input, boole rndtrip);
 1389 FL char *n_shexp_quote_cp(char const *cp, boole rndtrip);
 1390 
 1391 /* Can name be used as a variable name (for the process environment)?
 1392  * I.e., this returns false for special parameter names like $# etc. */
 1393 FL boole n_shexp_is_valid_varname(char const *name, boole forenviron);
 1394 
 1395 /* `shcodec' */
 1396 FL int c_shcodec(void *vp);
 1397 
 1398 /*
 1399  * spam.c
 1400  */
 1401 
 1402 #ifdef mx_HAVE_SPAM
 1403 /* Direct mappings of the various spam* commands */
 1404 FL int c_spam_clear(void *v);
 1405 FL int c_spam_set(void *v);
 1406 FL int c_spam_forget(void *v);
 1407 FL int c_spam_ham(void *v);
 1408 FL int c_spam_rate(void *v);
 1409 FL int c_spam_spam(void *v);
 1410 #endif
 1411 
 1412 /*
 1413  * strings.c
 1414  */
 1415 
 1416 /* Return a pointer to a dynamic copy of the argument */
 1417 FL char *savestr(char const *str  su_DBG_LOC_ARGS_DECL);
 1418 FL char *savestrbuf(char const *sbuf, uz slen  su_DBG_LOC_ARGS_DECL);
 1419 #ifdef su_HAVE_DBG_LOC_ARGS
 1420 # define savestr(CP) savestr(CP  su_DBG_LOC_ARGS_INJ)
 1421 # define savestrbuf(CBP,CBL) savestrbuf(CBP, CBL  su_DBG_LOC_ARGS_INJ)
 1422 #endif
 1423 
 1424 /* Concatenate cp2 onto cp1 (if not NULL), separated by sep (if not '\0') */
 1425 FL char *savecatsep(char const *cp1, char sep, char const *cp2
 1426    su_DBG_LOC_ARGS_DECL);
 1427 #ifdef su_HAVE_DBG_LOC_ARGS
 1428 # define savecatsep(S1,SEP,S2) savecatsep(S1, SEP, S2  su_DBG_LOC_ARGS_INJ)
 1429 #endif
 1430 
 1431 /* Make copy of argument incorporating old one, if set, separated by space */
 1432 #define save2str(S,O)            savecatsep(O, ' ', S)
 1433 
 1434 /* strcat */
 1435 #define savecat(S1,S2)           savecatsep(S1, '\0', S2)
 1436 
 1437 /*  */
 1438 FL struct str * str_concat_csvl(struct str *self, ...);
 1439 
 1440 /*  */
 1441 FL struct str *str_concat_cpa(struct str *self, char const * const *cpa,
 1442    char const *sep_o_null  su_DBG_LOC_ARGS_DECL);
 1443 #ifdef su_HAVE_DBG_LOC_ARGS
 1444 # define str_concat_cpa(S,A,N) str_concat_cpa(S, A, N  su_DBG_LOC_ARGS_INJ)
 1445 #endif
 1446 
 1447 /* Plain char* support, not auto-reclaimed (unless noted) */
 1448 
 1449 /* Could the string contain a regular expression?
 1450  * NOTE: on change: manual contains several occurrences of this string! */
 1451 #define n_is_maybe_regex(S) n_is_maybe_regex_buf(S, su_UZ_MAX)
 1452 FL boole n_is_maybe_regex_buf(char const *buf, uz len);
 1453 
 1454 /* Convert a string to lowercase, in-place and with multibyte-aware */
 1455 FL void        makelow(char *cp);
 1456 
 1457 /* Is *sub* a substring of *str*, case-insensitive and multibyte-aware? */
 1458 FL boole      substr(char const *str, char const *sub);
 1459 
 1460 /* struct str related support funs TODO _cp->_cs! */
 1461 
 1462 /* *self->s* is n_realloc()ed */
 1463 #define n_str_dup(S, T)          n_str_assign_buf((S), (T)->s, (T)->l)
 1464 
 1465 /* *self->s* is n_realloc()ed; if buflen==UZ_MAX su_cs_len() is called unless
 1466  * buf is NULL; buf may be NULL if buflen is 0 */
 1467 FL struct str *n_str_assign_buf(struct str *self, char const *buf, uz buflen
 1468       su_DBG_LOC_ARGS_DECL);
 1469 #define n_str_assign(S, T)       n_str_assign_buf(S, (T)->s, (T)->l)
 1470 #define n_str_assign_cp(S, CP)   n_str_assign_buf(S, CP, UZ_MAX)
 1471 
 1472 /* *self->s* is n_realloc()ed, *self->l* incremented; if buflen==UZ_MAX
 1473  * su_cs_len() is called unless buf is NULL; buf may be NULL if buflen is 0 */
 1474 FL struct str *n_str_add_buf(struct str *self, char const *buf, uz buflen
 1475       su_DBG_LOC_ARGS_DECL);
 1476 #define n_str_add(S, T)          n_str_add_buf(S, (T)->s, (T)->l)
 1477 #define n_str_add_cp(S, CP)      n_str_add_buf(S, CP, UZ_MAX)
 1478 
 1479 #ifdef su_HAVE_DBG_LOC_ARGS
 1480 # define n_str_assign_buf(S,B,BL) \
 1481    n_str_assign_buf(S, B, BL  su_DBG_LOC_ARGS_INJ)
 1482 # define n_str_add_buf(S,B,BL) n_str_add_buf(S, B, BL  su_DBG_LOC_ARGS_INJ)
 1483 #endif
 1484 
 1485 /* Remove leading and trailing su_cs_is_space()s and *ifs-ws*, respectively.
 1486  * The ->s and ->l of the string will be adjusted, but no NUL termination will
 1487  * be applied to a possibly adjusted buffer!
 1488  * If dofaults is set, " \t\n" is always trimmed (in addition).
 1489  * Note trimming does not copy, it only adjusts the pointer/length */
 1490 FL struct str *n_str_trim(struct str *self, enum n_str_trim_flags stf);
 1491 FL struct str *n_str_trim_ifs(struct str *self, boole dodefaults);
 1492 
 1493 /* struct n_string
 1494  * May have NIL buffer, may contain embedded NULs */
 1495 
 1496 FL struct n_string *n__string_clear(struct n_string *self);
 1497 
 1498 /* Lifetime.  n_string_gut() is optional for _creat_auto() strings */
 1499 INLINE struct n_string *
 1500 n_string_creat(struct n_string *self){
 1501    self->s_dat = NIL;
 1502    self->s_len = self->s_auto = self->s_size = 0;
 1503    return self;
 1504 }
 1505 
 1506 INLINE struct n_string *
 1507 n_string_creat_auto(struct n_string *self){
 1508    self->s_dat = NIL;
 1509    self->s_len = self->s_auto = self->s_size = 0;
 1510    self->s_auto = TRU1;
 1511    return self;
 1512 }
 1513 
 1514 INLINE void n_string_gut(struct n_string *self){
 1515    if(self->s_dat != NIL)
 1516       n__string_clear(self);
 1517 }
 1518 
 1519 INLINE struct n_string *
 1520 n_string_trunc(struct n_string *self, uz len){
 1521    ASSERT(UCMP(z, len, <=, self->s_len));
 1522    self->s_len = S(u32,len);
 1523    return self;
 1524 }
 1525 
 1526 INLINE struct n_string *
 1527 n_string_take_ownership(struct n_string *self, char *buf, u32 size, u32 len){
 1528    ASSERT(self->s_dat == NIL);
 1529    ASSERT(size == 0 || buf != NIL);
 1530    ASSERT(len == 0 || len < size);
 1531    self->s_dat = buf;
 1532    self->s_size = size;
 1533    self->s_len = len;
 1534    return self;
 1535 }
 1536 
 1537 INLINE struct n_string *
 1538 n_string_drop_ownership(struct n_string *self){
 1539    self->s_dat = NIL;
 1540    self->s_len = self->s_size = 0;
 1541    return self;
 1542 }
 1543 
 1544 INLINE struct n_string *
 1545 n_string_clear(struct n_string *self){
 1546    if(self->s_size > 0)
 1547       self = n__string_clear(self);
 1548    return self;
 1549 }
 1550 
 1551 /* Check whether a buffer of Len bytes can be inserted into S(elf) */
 1552 INLINE boole n_string_get_can_book(uz len){
 1553    return (S(uz,S32_MAX) - Z_ALIGN(1) > len);
 1554 }
 1555 
 1556 INLINE boole n_string_can_book(struct n_string *self, uz len){
 1557    return (n_string_get_can_book(len) &&
 1558       S(uz,S32_MAX) - Z_ALIGN(1) - len > self->s_len);
 1559 }
 1560 
 1561 /* Reserve room for noof additional bytes, but don't adjust length (yet) */
 1562 FL struct n_string *n_string_reserve(struct n_string *self, uz noof
 1563       su_DBG_LOC_ARGS_DECL);
 1564 #define n_string_book n_string_reserve
 1565 
 1566 /* Resize to exactly nlen bytes; any new storage isn't initialized */
 1567 FL struct n_string *n_string_resize(struct n_string *self, uz nlen
 1568       su_DBG_LOC_ARGS_DECL);
 1569 
 1570 #ifdef su_HAVE_DBG_LOC_ARGS
 1571 # define n_string_reserve(S,N)   (n_string_reserve)(S, N  su_DBG_LOC_ARGS_INJ)
 1572 # define n_string_resize(S,N)    (n_string_resize)(S, N  su_DBG_LOC_ARGS_INJ)
 1573 #endif
 1574 
 1575 /* */
 1576 FL struct n_string *n_string_push_buf(struct n_string *self, char const *buf,
 1577       uz buflen  su_DBG_LOC_ARGS_DECL);
 1578 #define n_string_push(S, T)       n_string_push_buf(S, (T)->s_len, (T)->s_dat)
 1579 #define n_string_push_cp(S,CP)    n_string_push_buf(S, CP, UZ_MAX)
 1580 FL struct n_string *n_string_push_c(struct n_string *self, char c
 1581       su_DBG_LOC_ARGS_DECL);
 1582 
 1583 #define n_string_assign(S,T)     ((S)->s_len = 0, n_string_push(S, T))
 1584 #define n_string_assign_c(S,C)   ((S)->s_len = 0, n_string_push_c(S, C))
 1585 #define n_string_assign_cp(S,CP) ((S)->s_len = 0, n_string_push_cp(S, CP))
 1586 #define n_string_assign_buf(S,B,BL) \
 1587    ((S)->s_len = 0, n_string_push_buf(S, B, BL))
 1588 
 1589 #ifdef su_HAVE_DBG_LOC_ARGS
 1590 # define n_string_push_buf(S,B,BL) \
 1591    (n_string_push_buf)(S, B, BL  su_DBG_LOC_ARGS_INJ)
 1592 # define n_string_push_c(S,C) (n_string_push_c)(S, C  su_DBG_LOC_ARGS_INJ)
 1593 #endif
 1594 
 1595 /* */
 1596 FL struct n_string *n_string_unshift_buf(struct n_string *self,
 1597       char const *buf, uz buflen  su_DBG_LOC_ARGS_DECL);
 1598 #define n_string_unshift(S,T) \
 1599    n_string_unshift_buf(S, (T)->s_len, (T)->s_dat)
 1600 #define n_string_unshift_cp(S,CP) \
 1601    n_string_unshift_buf(S, CP, UZ_MAX)
 1602 FL struct n_string *n_string_unshift_c(struct n_string *self, char c
 1603       su_DBG_LOC_ARGS_DECL);
 1604 
 1605 #ifdef su_HAVE_DBG_LOC_ARGS
 1606 # define n_string_unshift_buf(S,B,BL) \
 1607    (n_string_unshift_buf)(S, B, BL  su_DBG_LOC_ARGS_INJ)
 1608 # define n_string_unshift_c(S,C) \
 1609    (n_string_unshift_c)(S, C  su_DBG_LOC_ARGS_INJ)
 1610 #endif
 1611 
 1612 /* */
 1613 FL struct n_string *n_string_insert_buf(struct n_string *self, uz idx,
 1614       char const *buf, uz buflen  su_DBG_LOC_ARGS_DECL);
 1615 #define n_string_insert(S,I,T) \
 1616    n_string_insert_buf(S, I, (T)->s_len, (T)->s_dat)
 1617 #define n_string_insert_cp(S,I,CP) \
 1618    n_string_insert_buf(S, I, CP, UZ_MAX)
 1619 FL struct n_string *n_string_insert_c(struct n_string *self, uz idx,
 1620       char c  su_DBG_LOC_ARGS_DECL);
 1621 
 1622 #ifdef su_HAVE_DBG_LOC_ARGS
 1623 # define n_string_insert_buf(S,I,B,BL) \
 1624    (n_string_insert_buf)(S, I, B, BL  su_DBG_LOC_ARGS_INJ)
 1625 # define n_string_insert_c(S,I,C) \
 1626    (n_string_insert_c)(S, I, C  su_DBG_LOC_ARGS_INJ)
 1627 #endif
 1628 
 1629 /* */
 1630 FL struct n_string *n_string_cut(struct n_string *self, uz idx,
 1631       uz len);
 1632 
 1633 /* Ensure self has a - NUL terminated - buffer, and return that.
 1634  * The latter may return the pointer to an internal empty RODATA instead */
 1635 FL char *n_string_cp(struct n_string *self  su_DBG_LOC_ARGS_DECL);
 1636 FL char const *n_string_cp_const(struct n_string const *self);
 1637 
 1638 #ifdef su_HAVE_DBG_LOC_ARGS
 1639 # define n_string_cp(S) (n_string_cp)(S  su_DBG_LOC_ARGS_INJ)
 1640 #endif
 1641 
 1642 /*
 1643  * thread.c
 1644  */
 1645 
 1646 /*  */
 1647 FL int         c_thread(void *vp);
 1648 
 1649 /*  */
 1650 FL int         c_unthread(void *vp);
 1651 
 1652 /*  */
 1653 FL struct message * next_in_thread(struct message *mp);
 1654 FL struct message * prev_in_thread(struct message *mp);
 1655 FL struct message * this_in_thread(struct message *mp, long n);
 1656 
 1657 /* Sorted mode is internally just a variant of threaded mode with all m_parent
 1658  * and m_child links being NULL */
 1659 FL int         c_sort(void *vp);
 1660 
 1661 /*  */
 1662 FL int         c_collapse(void *v);
 1663 FL int         c_uncollapse(void *v);
 1664 
 1665 /*  */
 1666 FL void        uncollapse1(struct message *mp, int always);
 1667 
 1668 /*
 1669  * tls.c
 1670  */
 1671 
 1672 #ifdef mx_HAVE_TLS
 1673 /*  */
 1674 FL void n_tls_set_verify_level(struct mx_url const *urlp);
 1675 
 1676 /* */
 1677 FL boole n_tls_verify_decide(void);
 1678 
 1679 /*  */
 1680 FL boole mx_smime_split(FILE *ip, FILE **hp, FILE **bp, long xcount,
 1681       boole keep);
 1682 
 1683 /* */
 1684 FL FILE *      smime_sign_assemble(FILE *hp, FILE *bp, FILE *sp,
 1685                   char const *message_digest);
 1686 
 1687 /*  */
 1688 FL FILE *      smime_encrypt_assemble(FILE *hp, FILE *yp);
 1689 
 1690 /* hp and bp are NOT closed */
 1691 FL struct message *mx_smime_decrypt_assemble(struct message *mp, FILE *hp,
 1692       FILE *bp);
 1693 
 1694 /* `certsave' */
 1695 FL int c_certsave(void *vp);
 1696 
 1697 /* */
 1698 FL boole n_tls_rfc2595_hostname_match(char const *host, char const *pattern);
 1699 
 1700 /* `tls' */
 1701 FL int c_tls(void *vp);
 1702 #endif /* mx_HAVE_TLS */
 1703 
 1704 /*
 1705  * xtls.c
 1706  */
 1707 
 1708 #ifdef mx_HAVE_XTLS
 1709 /* Our wrapper for RAND_bytes(3); the implementation exists only when
 1710  * HAVE_RANDOM is RANDOM_IMPL_TLS, though */
 1711 FL void mx_tls_rand_bytes(void *buf, uz blen);
 1712 
 1713 /* Will fill in a non-NULL *urlp->url_cert_fprint with auto-reclaimed
 1714  * buffer on success, otherwise urlp is constant */
 1715 FL boole n_tls_open(struct mx_url *urlp, struct mx_socket *sp);
 1716 
 1717 /*  */
 1718 FL void        ssl_gen_err(char const *fmt, ...);
 1719 
 1720 /*  */
 1721 FL int         c_verify(void *vp);
 1722 
 1723 /*  */
 1724 FL FILE *      smime_sign(FILE *ip, char const *addr);
 1725 
 1726 /*  */
 1727 FL FILE *      smime_encrypt(FILE *ip, char const *certfile, char const *to);
 1728 
 1729 FL struct message * smime_decrypt(struct message *m, char const *to,
 1730                      char const *cc, boole is_a_verify_call);
 1731 
 1732 /*  */
 1733 FL enum okay   smime_certsave(struct message *m, int n, FILE *op);
 1734 
 1735 #endif /* mx_HAVE_XTLS */
 1736 
 1737 /*
 1738  * obs-imap.c
 1739  */
 1740 
 1741 #ifdef mx_HAVE_IMAP
 1742 FL void n_go_onintr_for_imap(void);
 1743 
 1744 /* The former returns the input again if no conversion is necessary */
 1745 FL char const *imap_path_encode(char const *path, boole *err_or_null);
 1746 FL char *imap_path_decode(char const *path, boole *err_or_null);
 1747 
 1748 FL char const * imap_fileof(char const *xcp);
 1749 FL enum okay   imap_noop(void);
 1750 FL enum okay   imap_select(struct mailbox *mp, off_t *size, int *count,
 1751                   const char *mbx, enum fedit_mode fm);
 1752 FL int imap_setfile(char const *who, const char *xserver, enum fedit_mode fm);
 1753 FL enum okay   imap_header(struct message *m);
 1754 FL enum okay   imap_body(struct message *m);
 1755 FL void        imap_getheaders(int bot, int top);
 1756 FL boole      imap_quit(boole hold_sigs_on);
 1757 FL enum okay   imap_undelete(struct message *m, int n);
 1758 FL enum okay   imap_unread(struct message *m, int n);
 1759 FL int         c_imapcodec(void *vp);
 1760 FL int         c_imap_imap(void *vp);
 1761 FL int         imap_newmail(int nmail);
 1762 FL enum okay   imap_append(const char *xserver, FILE *fp, long offset);
 1763 FL int         imap_folders(const char *name, int strip);
 1764 FL enum okay   imap_copy(struct message *m, int n, const char *name);
 1765 # ifdef mx_HAVE_IMAP_SEARCH
 1766 FL sz     imap_search1(const char *spec, int f);
 1767 # endif
 1768 FL int         imap_thisaccount(const char *cp);
 1769 FL enum okay   imap_remove(const char *name);
 1770 FL enum okay   imap_rename(const char *old, const char *new);
 1771 FL enum okay   imap_dequeue(struct mailbox *mp, FILE *fp);
 1772 FL int         c_connect(void *vp);
 1773 FL int         c_disconnect(void *vp);
 1774 FL int         c_cache(void *vp);
 1775 FL int         disconnected(const char *file);
 1776 FL void        transflags(struct message *omessage, long omsgCount,
 1777                   int transparent);
 1778 FL time_t      imap_read_date_time(const char *cp);
 1779 FL const char * imap_make_date_time(time_t t);
 1780 
 1781 /* Extract the protocol base and return a duplicate */
 1782 FL char *protbase(char const *cp  su_DBG_LOC_ARGS_DECL);
 1783 # ifdef su_HAVE_DBG_LOC_ARGS
 1784 #  define protbase(CP) (protbase)(CP  su_DBG_LOC_ARGS_INJ)
 1785 # endif
 1786 #endif /* mx_HAVE_IMAP */
 1787 
 1788 /*
 1789  * obs-imap-cache.c
 1790  */
 1791 
 1792 #ifdef mx_HAVE_IMAP
 1793 FL enum okay   getcache1(struct mailbox *mp, struct message *m,
 1794                   enum needspec need, int setflags);
 1795 FL enum okay   getcache(struct mailbox *mp, struct message *m,
 1796                   enum needspec need);
 1797 FL void        putcache(struct mailbox *mp, struct message *m);
 1798 FL void        initcache(struct mailbox *mp);
 1799 FL void        purgecache(struct mailbox *mp, struct message *m, long mc);
 1800 FL void        delcache(struct mailbox *mp, struct message *m);
 1801 FL enum okay   cache_setptr(enum fedit_mode fm, int transparent);
 1802 FL enum okay   cache_list(struct mailbox *mp, char const *base, int strip,
 1803                   FILE *fp);
 1804 FL enum okay   cache_remove(char const *name);
 1805 FL enum okay   cache_rename(char const *old, char const *new);
 1806 FL u64 cached_uidvalidity(struct mailbox *mp);
 1807 FL FILE *      cache_queue(struct mailbox *mp);
 1808 FL enum okay   cache_dequeue(struct mailbox *mp);
 1809 #endif /* mx_HAVE_IMAP */
 1810 
 1811 /*
 1812  * obs-lzw.c
 1813  */
 1814 #ifdef mx_HAVE_IMAP
 1815 FL int         zwrite(void *cookie, const char *wbp, int num);
 1816 FL int         zfree(void *cookie);
 1817 FL int         zread(void *cookie, char *rbp, int num);
 1818 FL void *      zalloc(FILE *fp);
 1819 #endif /* mx_HAVE_IMAP */
 1820 
 1821 #ifndef mx_HAVE_AMALGAMATION
 1822 # undef FL
 1823 # define FL
 1824 #endif
 1825 
 1826 /* s-it-mode */