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