summaryrefslogtreecommitdiffstats
path: root/src/macros.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/macros.h')
-rw-r--r--src/macros.h1111
1 files changed, 1111 insertions, 0 deletions
diff --git a/src/macros.h b/src/macros.h
new file mode 100644
index 0000000..b2f86ed
--- /dev/null
+++ b/src/macros.h
@@ -0,0 +1,1111 @@
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+
+/* These two macros make it possible to obtain the result of macro-expanding
+a string as a text string. This is sometimes useful for debugging output. */
+
+#define mac_string(s) # s
+#define mac_expanded_string(s) mac_string(s)
+
+/* Number of elements of an array */
+#define nelem(arr) (sizeof(arr) / sizeof(*arr))
+
+/* Maximum of two items */
+#ifndef MAX
+# define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+
+/* When running in the test harness, the load average is fudged. */
+
+#define OS_GETLOADAVG() \
+ (f.running_in_test_harness? (test_harness_load_avg += 10) : os_getloadavg())
+
+
+/* The address_item structure has a struct full of 1-bit flags. These macros
+manipulate them. */
+
+#define setflag(addr, flagname) addr->flags.flagname = TRUE
+#define clearflag(addr, flagname) addr->flags.flagname = FALSE
+
+#define testflag(addr, flagname) (addr->flags.flagname)
+
+#define copyflag(addrnew, addrold, flagname) \
+ addrnew->flags.flagname = addrold->flags.flagname
+
+
+/* For almost all calls to convert things to printing characters, we want to
+allow tabs & spaces. A macro just makes life a bit easier. */
+
+#define string_printing(s) string_printing2((s), 0)
+#define SP_TAB BIT(0)
+#define SP_SPACE BIT(1)
+
+
+/* We need a special return code for "no recipients and failed to send an error
+message". ANSI C defines only EXIT_FAILURE and EXIT_SUCCESS. On the assumption
+that these are always 1 and 0 on Unix systems ... */
+
+#define EXIT_NORECIPIENTS 2
+
+
+/* Character-handling macros. It seems that the set of standard functions in
+ctype.h aren't actually all that useful. One reason for this is that email is
+international, so the concept of using a locale to vary what they do is not
+helpful. Another problem is that in different operating systems, the libraries
+yield different results, even in the default locale. For example, Linux yields
+TRUE for iscntrl() for all characters > 127, whereas many other systems yield
+FALSE. For these reasons we define our own set of macros for a number of
+character testing functions. Ensure that all these tests treat their arguments
+as unsigned. */
+
+#define mac_iscntrl(c) \
+ ((uschar)(c) < 32 || (uschar)(c) == 127)
+
+#define mac_iscntrl_or_special(c) \
+ ((uschar)(c) < 32 || strchr(" ()<>@,;:\\\".[]\177", (uschar)(c)) != NULL)
+
+#define mac_isgraph(c) \
+ ((uschar)(c) > 32 && (uschar)(c) != 127)
+
+#define mac_isprint(c) \
+ (((uschar)(c) >= 32 && (uschar)(c) <= 126) || c == '\t' || \
+ ((uschar)(c) > 127 && print_topbitchars))
+
+
+/* Convenience for testing strings */
+
+#define streqic(Foo, Bar) (strcmpic(Foo, Bar) == 0)
+
+
+/* When built with TLS support, the act of flushing SMTP output becomes
+a no-op once an SSL session is in progress. */
+
+#ifndef DISABLE_TLS
+#define mac_smtp_fflush() if (tls_in.active.sock < 0) fflush(smtp_out);
+#else
+#define mac_smtp_fflush() fflush(smtp_out);
+#endif
+
+
+/* Define which ends of pipes are for reading and writing, as some systems
+don't make the file descriptors two-way. */
+
+#define pipe_read 0
+#define pipe_write 1
+
+/* The RFC 1413 ident port */
+
+#define IDENT_PORT 113
+
+/* A macro to simplify testing bits in lookup types */
+
+#define mac_islookup(a,b) ((lookup_list[a]->type & (b)) != 0)
+
+/* Debugging control */
+
+#define DEBUG(x) if (debug_selector & (x))
+#define HDEBUG(x) if (host_checking || (debug_selector & (x)))
+
+/* The default From: text for DSNs */
+
+#define DEFAULT_DSN_FROM "Mail Delivery System <Mailer-Daemon@$qualify_domain>"
+
+/* The size of the vector for saving/restoring address expansion pointers while
+verifying. This has to be explicit because it is referenced in more than one
+source module. */
+
+#define ADDRESS_EXPANSIONS_COUNT 19
+
+/* The maximum permitted number of command-line (-D) macro definitions. We
+need a limit only to make it easier to generate argument vectors for re-exec
+of Exim. */
+
+#define MAX_CLMACROS 10
+
+/* The number of integer variables available in filter files. If this is
+changed, then the tables in expand.c for accessing them must be changed too. */
+
+#define FILTER_VARIABLE_COUNT 10
+
+/* The size of the vector holding delay warning times */
+
+#define DELAY_WARNING_SIZE 12
+
+/* The size of the buffer holding the processing information string. */
+
+#define PROCESS_INFO_SIZE 384
+
+/* The size of buffer to get for constructing log entries. Make it big
+enough to hold all the headers from a normal kind of message. */
+
+#define LOG_BUFFER_SIZE 8192
+
+/* The size of the circular buffer that remembers recent SMTP commands */
+
+#define SMTP_HBUFF_SIZE 20
+#define SMTP_HBUFF_PREV(n) ((n) ? (n)-1 : SMTP_HBUFF_SIZE-1)
+
+/* The initial size of a big buffer for use in various places. It gets put
+into big_buffer_size and in some circumstances increased. It should be at least
+as long as the maximum path length PLUS room for string additions.
+Let's go with "at least twice as large as maximum path length".
+*/
+
+#ifdef AUTH_HEIMDAL_GSSAPI
+ /* RFC 4121 section 5.2, SHOULD support 64K input buffers */
+# define __BIG_BUFFER_SIZE 65536
+#else
+# define __BIG_BUFFER_SIZE 16384
+#endif
+
+#ifndef PATH_MAX
+/* exim.h will have ensured this exists before including us. */
+# error headers confusion, PATH_MAX missing in macros.h
+#endif
+#if (PATH_MAX*2) > __BIG_BUFFER_SIZE
+# define BIG_BUFFER_SIZE (PATH_MAX*2)
+#else
+# define BIG_BUFFER_SIZE __BIG_BUFFER_SIZE
+#endif
+
+/* header size of pipe content
+ currently: char id, char subid, char[5] length */
+#define PIPE_HEADER_SIZE 7
+
+/* This limits the length of data returned by local_scan(). Because it is
+written on the spool, it gets read into big_buffer. */
+
+#define LOCAL_SCAN_MAX_RETURN (BIG_BUFFER_SIZE - 24)
+
+/* The length of the base names of spool files, which consist of an internal
+message id with a trailing "-H" or "-D" added. */
+
+#define SPOOL_NAME_LENGTH (MESSAGE_ID_LENGTH+2)
+
+/* The maximum number of message ids to store in a waiting database
+record, and the max number of continuation records allowed. */
+
+#define WAIT_NAME_MAX 50
+#define WAIT_CONT_MAX 1000
+
+/* Wait this long before determining that a Proxy Protocol configured
+host isn't speaking the protocol, and so is disallowed. Can be moved to
+runtime configuration if per site settings become needed. */
+#ifdef SUPPORT_PROXY
+#define PROXY_NEGOTIATION_TIMEOUT_SEC 3
+#define PROXY_NEGOTIATION_TIMEOUT_USEC 0
+#endif
+
+/* Fixed option values for all PCRE functions */
+
+#define PCRE_COPT 0 /* compile */
+#define PCRE_EOPT 0 /* exec */
+
+/* Macros for trivial functions */
+
+#define mac_ismsgid(s) \
+ (pcre_exec(regex_ismsgid,NULL,CS s,Ustrlen(s),0,PCRE_EOPT,NULL,0) >= 0)
+
+
+/* Options for dns_next_rr */
+
+enum { RESET_NEXT, RESET_ANSWERS, RESET_AUTHORITY, RESET_ADDITIONAL };
+
+/* Argument values for the time-of-day function */
+
+enum { tod_log, tod_log_bare, tod_log_zone, tod_log_datestamp_daily,
+ tod_log_datestamp_monthly, tod_zone, tod_full, tod_bsdin,
+ tod_mbx, tod_epoch, tod_epoch_l, tod_zulu };
+
+/* For identifying types of driver */
+
+enum {
+ EXIM_DTYPE_NONE,
+ EXIM_DTYPE_ROUTER,
+ EXIM_DTYPE_TRANSPORT
+};
+
+/* Error numbers for generating error messages when reading a message on the
+standard input. */
+
+enum {
+ ERRMESS_BADARGADDRESS, /* Bad address via argument list */
+ ERRMESS_BADADDRESS, /* Bad address read via -t */
+ ERRMESS_NOADDRESS, /* Message has no addresses */
+ ERRMESS_IGADDRESS, /* All -t addresses ignored */
+ ERRMESS_BADNOADDRESS, /* Bad address via -t, leaving none */
+ ERRMESS_IOERR, /* I/O error while reading a message */
+ ERRMESS_VLONGHEADER, /* Excessively long message header */
+ ERRMESS_VLONGHDRLINE, /* Excessively long single line in header */
+ ERRMESS_TOOBIG, /* Message too big */
+ ERRMESS_TOOMANYRECIP, /* Too many recipients */
+ ERRMESS_LOCAL_SCAN, /* Rejected by local scan */
+ ERRMESS_LOCAL_ACL /* Rejected by non-SMTP ACL */
+#ifdef SUPPORT_DMARC
+ ,ERRMESS_DMARC_FORENSIC /* DMARC Forensic Report */
+#endif
+};
+
+/* Error handling styles - set by option, and apply only when receiving
+a local message not via SMTP. */
+
+enum {
+ ERRORS_SENDER, /* Return to sender (default) */
+ ERRORS_STDERR /* Write on stderr */
+};
+
+/* Exec control values when Exim execs itself via child_exec_exim. */
+
+enum {
+ CEE_RETURN_ARGV, /* Don't exec, just build and return argv */
+ CEE_EXEC_EXIT, /* Just exit if exec fails */
+ CEE_EXEC_PANIC /* Panic-die if exec fails */
+};
+
+/* Bit values for filter_test */
+
+#define FTEST_NONE 0 /* Not filter testing */
+#define FTEST_USER 1 /* Testing user filter */
+#define FTEST_SYSTEM 2 /* Testing system filter */
+
+/* Returns from the routing, transport and authentication functions (not all
+apply to all of them). Some other functions also use these convenient values,
+and some additional values are used only by non-driver functions.
+
+OK, FAIL, DEFER, ERROR, and FAIL_FORCED are also declared in local_scan.h for
+use in the local_scan() function and in ${dlfunc loaded functions. Do not
+change them unilaterally.
+
+Use rc_names[] for debug strings. */
+
+#define OK 0 /* Successful match */
+#define DEFER 1 /* Defer - some problem */
+#define FAIL 2 /* Matching failed */
+#define ERROR 3 /* Internal or config error */
+#define FAIL_FORCED 4 /* "Forced" failure */
+/***********/
+#define DECLINE 5 /* Declined to handle the address, pass to next
+ router unless no_more is set */
+#define PASS 6 /* Pass to next driver, or to pass_router,
+ even if no_more is set */
+#define DISCARD 7 /* Address routed to :blackhole: or "seen finish" */
+#define SKIP 8 /* Skip this router (used in route_address only) */
+#define REROUTED 9 /* Address was changed and child created*/
+#define PANIC 10 /* Hard failed with internal error */
+#define BAD64 11 /* Bad base64 data (auth) */
+#define UNEXPECTED 12 /* Unexpected initial auth data */
+#define CANCELLED 13 /* Authentication cancelled */
+#define FAIL_SEND 14 /* send() failed in authenticator */
+#define FAIL_DROP 15 /* Fail and drop connection (used in ACL) */
+#define DANE 16 /* Deferred for domain mismatch (used in transport) */
+
+/* Returns from the deliver_message() function */
+
+#define DELIVER_ATTEMPTED_NORMAL 0 /* Tried a normal delivery */
+#define DELIVER_MUA_SUCCEEDED 1 /* Success when mua_wrapper is set */
+#define DELIVER_MUA_FAILED 2 /* Failure when mua_wrapper is set */
+#define DELIVER_NOT_ATTEMPTED 3 /* Not tried (no msg or is locked */
+
+/* Returns from DNS lookup functions. */
+
+enum { DNS_SUCCEED, DNS_NOMATCH, DNS_NODATA, DNS_AGAIN, DNS_FAIL };
+
+/* Ending states when reading a message. The order is important. The test
+for having to swallow the rest of an SMTP message is whether the value is
+>= END_NOTENDED. */
+
+#define END_NOTSTARTED 0 /* Message not started */
+#define END_DOT 1 /* Message ended with '.' */
+#define END_EOF 2 /* Message ended with EOF (error for SMTP) */
+#define END_NOTENDED 3 /* Message reading not yet ended */
+#define END_SIZE 4 /* Reading ended because message too big */
+#define END_WERROR 5 /* Write error while reading the message */
+#define END_PROTOCOL 6 /* Protocol error in CHUNKING sequence */
+
+/* result codes for bdat_getc() (which can also return EOF) */
+
+#define EOD (-2)
+#define ERR (-3)
+
+
+/* Bit masks for debug and log selectors */
+
+/* Assume words are 32 bits wide. Tiny waste of space on 64 bit
+platforms, but this ensures bit vectors always work the same way. */
+#define BITWORDSIZE 32
+
+/* This macro is for single-word bit vectors: the debug selector,
+and the first word of the log selector. */
+#define BIT(n) (1UL << (n))
+
+/* And these are for multi-word vectors. */
+#define BITWORD(n) ( (n) / BITWORDSIZE)
+#define BITMASK(n) (1U << (n) % BITWORDSIZE)
+
+#define BIT_CLEAR(s,z,n) ((s)[BITWORD(n)] &= ~BITMASK(n))
+#define BIT_SET(s,z,n) ((s)[BITWORD(n)] |= BITMASK(n))
+#define BIT_TEST(s,z,n) (((s)[BITWORD(n)] & BITMASK(n)) != 0)
+
+/* Used in globals.c for initializing bit_table structures. T will be either
+D or L corresponding to the debug and log selector bits declared below. */
+
+#define BIT_TABLE(T,name) { US #name, T##i_##name }
+
+/* IOTA allows us to keep an implicit sequential count, like a simple enum,
+but we can have sequentially numbered identifiers which are not declared
+sequentially. We use this for more compact declarations of bit indexes and
+masks, alternating between sequential bit index and corresponding mask. */
+
+#define IOTA(iota) (__LINE__ - iota)
+#define IOTA_INIT(zero) (__LINE__ - zero + 1)
+
+/* Options bits for debugging. DEBUG_BIT() declares both a bit index and the
+corresponding mask. Di_all is a special value recognized by decode_bits().
+These must match the debug_options table in globals.c .
+
+Exim's code assumes in a number of places that the debug_selector is one
+word, and this is exposed in the local_scan ABI. The D_v and D_local_scan bit
+masks are part of the local_scan API so are #defined in local_scan.h */
+
+#define DEBUG_BIT(name) Di_##name = IOTA(Di_iota), D_##name = (int)BIT(Di_##name)
+
+enum {
+ Di_all = -1,
+ Di_v = 0,
+ Di_local_scan = 1,
+
+ Di_iota = IOTA_INIT(2),
+ DEBUG_BIT(acl), /* 2 */
+ DEBUG_BIT(auth),
+ DEBUG_BIT(deliver),
+ DEBUG_BIT(dns),
+ DEBUG_BIT(dnsbl),
+ DEBUG_BIT(exec), /* 7 */
+ DEBUG_BIT(expand),
+ DEBUG_BIT(filter),
+ DEBUG_BIT(hints_lookup),
+ DEBUG_BIT(host_lookup),
+ DEBUG_BIT(ident),
+ DEBUG_BIT(interface),
+ DEBUG_BIT(lists),
+ DEBUG_BIT(load), /* 15 */
+ DEBUG_BIT(lookup),
+ DEBUG_BIT(memory),
+ DEBUG_BIT(noutf8),
+ DEBUG_BIT(pid),
+ DEBUG_BIT(process_info),
+ DEBUG_BIT(queue_run),
+ DEBUG_BIT(receive),
+ DEBUG_BIT(resolver), /* 23 */
+ DEBUG_BIT(retry),
+ DEBUG_BIT(rewrite),
+ DEBUG_BIT(route),
+ DEBUG_BIT(timestamp),
+ DEBUG_BIT(tls),
+ DEBUG_BIT(transport),
+ DEBUG_BIT(uid),
+ DEBUG_BIT(verify), /* 31 */
+};
+
+/* Multi-bit debug masks */
+
+#define D_all 0xffffffff
+
+#define D_any (D_all & \
+ ~(D_v | \
+ D_noutf8 | \
+ D_pid | \
+ D_timestamp) )
+
+#define D_default (0xffffffff & \
+ ~(D_expand | \
+ D_filter | \
+ D_interface | \
+ D_load | \
+ D_local_scan | \
+ D_memory | \
+ D_noutf8 | \
+ D_pid | \
+ D_timestamp | \
+ D_resolver))
+
+/* Options bits for logging. Those that have values < BITWORDSIZE can be used
+in calls to log_write(). The others are put into later words in log_selector
+and are only ever tested independently, so they do not need bit mask
+declarations. The Li_all value is recognized specially by decode_bits().
+Add also to log_options[] when creating new ones. */
+
+#define LOG_BIT(name) Li_##name = IOTA(Li_iota), L_##name = BIT(Li_##name)
+
+enum logbit {
+ Li_all = -1,
+
+ Li_iota = IOTA_INIT(0),
+ LOG_BIT(address_rewrite),
+ LOG_BIT(all_parents),
+ LOG_BIT(connection_reject),
+ LOG_BIT(delay_delivery),
+ LOG_BIT(dnslist_defer),
+ LOG_BIT(etrn),
+ LOG_BIT(host_lookup_failed),
+ LOG_BIT(lost_incoming_connection),
+ LOG_BIT(queue_run),
+ LOG_BIT(retry_defer),
+ LOG_BIT(size_reject),
+ LOG_BIT(skip_delivery),
+ LOG_BIT(smtp_connection),
+ LOG_BIT(smtp_incomplete_transaction),
+ LOG_BIT(smtp_protocol_error),
+ LOG_BIT(smtp_syntax_error),
+
+ Li_8bitmime = BITWORDSIZE,
+ Li_acl_warn_skipped,
+ Li_arguments,
+ Li_deliver_time,
+ Li_delivery_size,
+ Li_dkim,
+ Li_dkim_verbose,
+ Li_dnssec,
+ Li_ident_timeout,
+ Li_incoming_interface,
+ Li_incoming_port,
+ Li_millisec,
+ Li_msg_id,
+ Li_msg_id_created,
+ Li_outgoing_interface,
+ Li_outgoing_port,
+ Li_pid,
+ Li_pipelining,
+ Li_proxy,
+ Li_queue_time,
+ Li_queue_time_overall,
+ Li_receive_time,
+ Li_received_sender,
+ Li_received_recipients,
+ Li_rejected_header,
+ Li_return_path_on_delivery,
+ Li_sender_on_delivery,
+ Li_sender_verify_fail,
+ Li_smtp_confirmation,
+ Li_smtp_mailauth,
+ Li_smtp_no_mail,
+ Li_subject,
+ Li_tls_certificate_verified,
+ Li_tls_cipher,
+ Li_tls_peerdn,
+ Li_tls_resumption,
+ Li_tls_sni,
+ Li_unknown_in_list,
+
+ log_selector_size = BITWORD(Li_unknown_in_list) + 1
+};
+
+#define LOGGING(opt) BIT_TEST(log_selector, log_selector_size, Li_##opt)
+
+/* Private error numbers for delivery failures, set negative so as not
+to conflict with system errno values. Take care to maintain the string
+table exim_errstrings[] in log.c */
+
+#define ERRNO_UNKNOWNERROR (-1)
+#define ERRNO_USERSLASH (-2)
+#define ERRNO_EXISTRACE (-3)
+#define ERRNO_NOTREGULAR (-4)
+#define ERRNO_NOTDIRECTORY (-5)
+#define ERRNO_BADUGID (-6)
+#define ERRNO_BADMODE (-7)
+#define ERRNO_INODECHANGED (-8)
+#define ERRNO_LOCKFAILED (-9)
+#define ERRNO_BADADDRESS2 (-10)
+#define ERRNO_FORBIDPIPE (-11)
+#define ERRNO_FORBIDFILE (-12)
+#define ERRNO_FORBIDREPLY (-13)
+#define ERRNO_MISSINGPIPE (-14)
+#define ERRNO_MISSINGFILE (-15)
+#define ERRNO_MISSINGREPLY (-16)
+#define ERRNO_BADREDIRECT (-17)
+#define ERRNO_SMTPCLOSED (-18)
+#define ERRNO_SMTPFORMAT (-19)
+#define ERRNO_SPOOLFORMAT (-20)
+#define ERRNO_NOTABSOLUTE (-21)
+#define ERRNO_EXIMQUOTA (-22) /* Exim-imposed quota */
+#define ERRNO_HELD (-23)
+#define ERRNO_FILTER_FAIL (-24) /* Delivery filter process failure */
+#define ERRNO_CHHEADER_FAIL (-25) /* Delivery add/remove header failure */
+#define ERRNO_WRITEINCOMPLETE (-26) /* Delivery write incomplete error */
+#define ERRNO_EXPANDFAIL (-27) /* Some expansion failed */
+#define ERRNO_GIDFAIL (-28) /* Failed to get gid */
+#define ERRNO_UIDFAIL (-29) /* Failed to get uid */
+#define ERRNO_BADTRANSPORT (-30) /* Unset or non-existent transport */
+#define ERRNO_MBXLENGTH (-31) /* MBX length mismatch */
+#define ERRNO_UNKNOWNHOST (-32) /* Lookup failed routing or in smtp tpt */
+#define ERRNO_FORMATUNKNOWN (-33) /* Can't match format in appendfile */
+#define ERRNO_BADCREATE (-34) /* Creation outside home in appendfile */
+#define ERRNO_LISTDEFER (-35) /* Can't check a list; lookup defer */
+#define ERRNO_DNSDEFER (-36) /* DNS lookup defer */
+#define ERRNO_TLSFAILURE (-37) /* Failed to start TLS session */
+#define ERRNO_TLSREQUIRED (-38) /* Mandatory TLS session not started */
+#define ERRNO_CHOWNFAIL (-39) /* Failed to chown a file */
+#define ERRNO_PIPEFAIL (-40) /* Failed to create a pipe */
+#define ERRNO_CALLOUTDEFER (-41) /* When verifying */
+#define ERRNO_AUTHFAIL (-42) /* When required by client */
+#define ERRNO_CONNECTTIMEOUT (-43) /* Used internally in smtp transport */
+#define ERRNO_RCPT4XX (-44) /* RCPT gave 4xx error */
+#define ERRNO_MAIL4XX (-45) /* MAIL gave 4xx error */
+#define ERRNO_DATA4XX (-46) /* DATA gave 4xx error */
+#define ERRNO_PROXYFAIL (-47) /* Negotiation failed for proxy configured host */
+#define ERRNO_AUTHPROB (-48) /* Authenticator "other" failure */
+#define ERRNO_UTF8_FWD (-49) /* target not supporting SMTPUTF8 */
+#define ERRNO_HOST_IS_LOCAL (-50) /* Transport refuses to talk to localhost */
+
+/* These must be last, so all retry deferments can easily be identified */
+
+#define ERRNO_RETRY_BASE (-51) /* Base to test against */
+#define ERRNO_RRETRY (-51) /* Not time for routing */
+
+#define ERRNO_WARN_BASE (-52) /* Base to test against */
+#define ERRNO_LRETRY (-52) /* Not time for local delivery */
+#define ERRNO_HRETRY (-53) /* Not time for any remote host */
+#define ERRNO_LOCAL_ONLY (-54) /* Local-only delivery */
+#define ERRNO_QUEUE_DOMAIN (-55) /* Domain in queue_domains */
+#define ERRNO_TRETRY (-56) /* Transport concurrency limit */
+#define ERRNO_EVENT (-57) /* Event processing request alternate response */
+
+
+
+/* Special actions to take after failure or deferment. */
+
+enum {
+ SPECIAL_NONE, /* No special action */
+ SPECIAL_FREEZE, /* Freeze message */
+ SPECIAL_FAIL, /* Fail the delivery */
+ SPECIAL_WARN /* Send a warning message */
+};
+
+/* Flags that get ORed into the more_errno field of an address to give more
+information about errors for retry purposes. They are greater than 256, because
+the bottom byte contains 'A' or 'M' for remote addresses, to indicate whether
+the name was looked up only via an address record or whether MX records were
+used, respectively. */
+
+#define RTEF_CTOUT 0x0100 /* Connection timed out */
+
+/* Permission and other options for parse_extract_addresses(),
+filter_interpret(), and rda_interpret(), i.e. what special things are allowed
+in redirection operations. Not all apply to all cases. Some of the bits allow
+and some forbid, reflecting the "allow" and "forbid" options in the redirect
+router, which were chosen to represent the standard situation for users'
+.forward files. */
+
+#define RDO_BLACKHOLE 0x00000001 /* Forbid :blackhole: */
+#define RDO_DEFER 0x00000002 /* Allow :defer: or "defer" */
+#define RDO_EACCES 0x00000004 /* Ignore EACCES */
+#define RDO_ENOTDIR 0x00000008 /* Ignore ENOTDIR */
+#define RDO_EXISTS 0x00000010 /* Forbid "exists" in expansion in filter */
+#define RDO_FAIL 0x00000020 /* Allow :fail: or "fail" */
+#define RDO_FILTER 0x00000040 /* Allow a filter script */
+#define RDO_FREEZE 0x00000080 /* Allow "freeze" */
+#define RDO_INCLUDE 0x00000100 /* Forbid :include: */
+#define RDO_LOG 0x00000200 /* Forbid "log" */
+#define RDO_LOOKUP 0x00000400 /* Forbid "lookup" in expansion in filter */
+#define RDO_PERL 0x00000800 /* Forbid "perl" in expansion in filter */
+#define RDO_READFILE 0x00001000 /* Forbid "readfile" in exp in filter */
+#define RDO_READSOCK 0x00002000 /* Forbid "readsocket" in exp in filter */
+#define RDO_RUN 0x00004000 /* Forbid "run" in expansion in filter */
+#define RDO_DLFUNC 0x00008000 /* Forbid "dlfunc" in expansion in filter */
+#define RDO_REALLOG 0x00010000 /* Really do log (not testing/verifying) */
+#define RDO_REWRITE 0x00020000 /* Rewrite generated addresses */
+#define RDO_EXIM_FILTER 0x00040000 /* Forbid Exim filters */
+#define RDO_SIEVE_FILTER 0x00080000 /* Forbid Sieve filters */
+#define RDO_PREPEND_HOME 0x00100000 /* Prepend $home to relative paths in Exim filter save commands */
+
+/* This is the set that apply to expansions in filters */
+
+#define RDO_FILTER_EXPANSIONS \
+ (RDO_EXISTS|RDO_LOOKUP|RDO_PERL|RDO_READFILE|RDO_READSOCK|RDO_RUN|RDO_DLFUNC)
+
+/* As well as the RDO bits themselves, we need the bit numbers in order to
+access (most of) the individual bits as separate options. This could be
+automated, but I haven't bothered. Keep this list in step with the above! */
+
+enum { RDON_BLACKHOLE, RDON_DEFER, RDON_EACCES, RDON_ENOTDIR, RDON_EXISTS,
+ RDON_FAIL, RDON_FILTER, RDON_FREEZE, RDON_INCLUDE, RDON_LOG, RDON_LOOKUP,
+ RDON_PERL, RDON_READFILE, RDON_READSOCK, RDON_RUN, RDON_DLFUNC, RDON_REALLOG,
+ RDON_REWRITE, RDON_EXIM_FILTER, RDON_SIEVE_FILTER, RDON_PREPEND_HOME };
+
+/* Results of filter or forward file processing. Some are only from a filter;
+some are only from a forward file. */
+
+enum {
+ FF_DELIVERED, /* Success, took significant action */
+ FF_NOTDELIVERED, /* Success, didn't take significant action */
+ FF_BLACKHOLE, /* Blackholing requested */
+ FF_DEFER, /* Defer requested */
+ FF_FAIL, /* Fail requested */
+ FF_INCLUDEFAIL, /* :include: failed */
+ FF_NONEXIST, /* Forward file does not exist */
+ FF_FREEZE, /* Freeze requested */
+ FF_ERROR /* We have a problem */
+};
+
+/* Values for identifying particular headers; printing characters are used, so
+they can be read in the spool file for those headers that are permanently
+marked. The lower case values don't get onto the spool; they are used only as
+return values from header_checkname(). */
+
+#define htype_other ' ' /* Unspecified header */
+#define htype_from 'F'
+#define htype_to 'T'
+#define htype_cc 'C'
+#define htype_bcc 'B'
+#define htype_id 'I' /* for message-id */
+#define htype_reply_to 'R'
+#define htype_received 'P' /* P for Postmark */
+#define htype_sender 'S'
+#define htype_old '*' /* Replaced header */
+
+#define htype_date 'd'
+#define htype_return_path 'p'
+#define htype_delivery_date 'x'
+#define htype_envelope_to 'e'
+#define htype_subject 's'
+
+/* These values are used only when adding new headers from an ACL; they too
+never get onto the spool. The type of the added header is set by reference
+to the header name, by calling header_checkname(). */
+
+#define htype_add_top 'a'
+#define htype_add_rec 'r'
+#define htype_add_bot 'z'
+#define htype_add_rfc 'f'
+
+/* Types of item in options lists. These are the bottom 8 bits of the "type"
+field, which is an int. The opt_void value is used for entries in tables that
+point to special types of value that are accessed only indirectly (e.g. the
+rewrite data that is built out of a string option.) We need to have some values
+visible in local_scan, so the following are declared there:
+
+ opt_stringptr, opt_int, opt_octint, opt_mkint, opt_Kint, opt_fixed, opt_time,
+ opt_bool
+
+To make sure we don't conflict, the local_scan.h values start from zero, and
+those defined here start from 32. The boolean ones must all be together so they
+can be easily tested as a group. That is the only use of opt_bool_last. */
+
+enum { opt_bit = 32, opt_bool_verify, opt_bool_set, opt_expand_bool,
+ opt_bool_last,
+ opt_rewrite, opt_timelist, opt_uid, opt_gid, opt_uidlist, opt_gidlist,
+ opt_expand_uid, opt_expand_gid, opt_func, opt_void };
+
+/* There's a high-ish bit which is used to flag duplicate options, kept
+for compatibility, which shouldn't be output. Also used for hidden options
+that are automatically maintained from others. Another high bit is used to
+flag driver options that although private (so as to be settable only on some
+drivers), are stored in the instance block so as to be accessible from outside.
+A third high bit is set when an option is read, so as to be able to give an
+error if any option is set twice. Finally, there's a bit which is set when an
+option is set with the "hide" prefix, to prevent -bP from showing it to
+non-admin callers. The next byte up in the int is used to keep the bit number
+for booleans that are kept in one bit. */
+
+#define opt_hidden 0x100 /* Private to Exim */
+#define opt_public 0x200 /* Stored in the main instance block */
+#define opt_set 0x400 /* Option is set */
+#define opt_secure 0x800 /* "hide" prefix used */
+#define opt_rep_con 0x1000 /* Can be appended to by a repeated line (condition) */
+#define opt_rep_str 0x2000 /* Can be appended to by a repeated line (string) */
+#define opt_mask 0x00ff
+
+/* Verify types when directing and routing */
+
+enum { v_none, v_sender, v_recipient, v_expn };
+
+/* Option flags for verify_address() */
+
+#define vopt_fake_sender 0x0001 /* for verify=sender=<address> */
+#define vopt_is_recipient 0x0002
+#define vopt_qualify 0x0004
+#define vopt_expn 0x0008
+#define vopt_callout_fullpm 0x0010 /* full postmaster during callout */
+#define vopt_callout_random 0x0020 /* during callout */
+#define vopt_callout_no_cache 0x0040 /* disable callout cache */
+#define vopt_callout_recipsender 0x0080 /* use real sender to verify recip */
+#define vopt_callout_recippmaster 0x0100 /* use postmaster to verify recip */
+#define vopt_callout_hold 0x0200 /* lazy close connection */
+#define vopt_success_on_redirect 0x0400
+
+/* Values for fields in callout cache records */
+
+#define ccache_unknown 0 /* test hasn't been done */
+#define ccache_accept 1
+#define ccache_reject 2 /* All rejections except */
+#define ccache_reject_mfnull 3 /* MAIL FROM:<> was rejected */
+
+/* Options for lookup functions */
+
+#define lookup_querystyle 1 /* query-style lookup */
+#define lookup_absfile 2 /* requires absolute file name */
+#define lookup_absfilequery 4 /* query-style starts with file name */
+
+/* Status values for host_item blocks. Require hstatus_unusable and
+hstatus_unusable_expired to be last. */
+
+enum { hstatus_unknown, hstatus_usable, hstatus_unusable,
+ hstatus_unusable_expired };
+
+/* Reasons why a host is unusable (for clearer log messages) */
+
+enum { hwhy_unknown, hwhy_retry, hwhy_insecure, hwhy_failed, hwhy_deferred,
+ hwhy_ignored };
+
+/* Domain lookup types for routers */
+
+#define LK_DEFAULT BIT(0)
+#define LK_BYNAME BIT(1)
+#define LK_BYDNS BIT(2) /* those 3 should be mutually exclusive */
+
+#define LK_IPV4_ONLY BIT(3)
+#define LK_IPV4_PREFER BIT(4)
+
+/* Values for the self_code fields */
+
+enum { self_freeze, self_defer, self_send, self_reroute, self_pass, self_fail };
+
+/* Flags for rewrite rules */
+
+#define rewrite_sender 0x0001
+#define rewrite_from 0x0002
+#define rewrite_to 0x0004
+#define rewrite_cc 0x0008
+#define rewrite_bcc 0x0010
+#define rewrite_replyto 0x0020
+#define rewrite_all_headers 0x003F /* all header flags */
+
+#define rewrite_envfrom 0x0040
+#define rewrite_envto 0x0080
+#define rewrite_all_envelope 0x00C0 /* all envelope flags */
+
+#define rewrite_all (rewrite_all_headers | rewrite_all_envelope)
+
+#define rewrite_smtp 0x0100 /* rewrite at SMTP time */
+#define rewrite_smtp_sender 0x0200 /* SMTP sender rewrite (allows <>) */
+#define rewrite_qualify 0x0400 /* qualify if necessary */
+#define rewrite_repeat 0x0800 /* repeat rewrite rule */
+
+#define rewrite_whole 0x1000 /* option bit for headers */
+#define rewrite_quit 0x2000 /* "no more" option */
+
+/* Flags for log_write(); LOG_MAIN, LOG_PANIC, and LOG_REJECT are also in
+local_scan.h */
+
+#define LOG_MAIN 1 /* Write to the main log */
+#define LOG_PANIC 2 /* Write to the panic log */
+#define LOG_PANIC_DIE 6 /* Write to the panic log and then die */
+#define LOG_REJECT 16 /* Write to the reject log, with headers */
+#define LOG_SENDER 32 /* Add raw sender to the message */
+#define LOG_RECIPIENTS 64 /* Add raw recipients to the message */
+#define LOG_CONFIG 128 /* Add "Exim configuration error" */
+#define LOG_CONFIG_FOR (256+128) /* Add " for" instead of ":\n" */
+#define LOG_CONFIG_IN (512+128) /* Add " in line x[ of file y]" */
+
+/* and for debug_bits() logging action control: */
+#define DEBUG_FROM_CONFIG 0x0001
+
+/* SMTP command identifiers for the smtp_connection_had field that records the
+most recent SMTP commands. Must be kept in step with the list of names in
+smtp_in.c that is used for creating the smtp_no_mail logging action. SCH_NONE
+is "empty". */
+
+enum { SCH_NONE, SCH_AUTH, SCH_DATA, SCH_BDAT,
+ SCH_EHLO, SCH_ETRN, SCH_EXPN, SCH_HELO,
+ SCH_HELP, SCH_MAIL, SCH_NOOP, SCH_QUIT, SCH_RCPT, SCH_RSET, SCH_STARTTLS,
+ SCH_VRFY };
+
+/* Returns from host_find_by{name,dns}() */
+
+enum {
+ HOST_FIND_FAILED, /* failed to find the host */
+ HOST_FIND_AGAIN, /* could not resolve at this time */
+ HOST_FIND_SECURITY, /* dnssec required but not acheived */
+ HOST_FOUND, /* found host */
+ HOST_FOUND_LOCAL, /* found, but MX points to local host */
+ HOST_IGNORED /* found but ignored - used internally only */
+};
+
+/* Flags for host_find_bydns() */
+
+#define HOST_FIND_BY_SRV BIT(0)
+#define HOST_FIND_BY_MX BIT(1)
+#define HOST_FIND_BY_A BIT(2)
+#define HOST_FIND_BY_AAAA BIT(3)
+#define HOST_FIND_QUALIFY_SINGLE BIT(4)
+#define HOST_FIND_SEARCH_PARENTS BIT(5)
+#define HOST_FIND_IPV4_FIRST BIT(6)
+#define HOST_FIND_IPV4_ONLY BIT(7)
+
+/* Actions applied to specific messages. */
+
+enum { MSG_DELIVER, MSG_FREEZE, MSG_REMOVE, MSG_THAW, MSG_ADD_RECIPIENT,
+ MSG_MARK_ALL_DELIVERED, MSG_MARK_DELIVERED, MSG_EDIT_SENDER,
+ MSG_SHOW_COPY, MSG_LOAD, MSG_SETQUEUE,
+ /* These ones must be last: a test for >= MSG_SHOW_BODY is used
+ to test for actions that list individual spool files. */
+ MSG_SHOW_BODY, MSG_SHOW_HEADER, MSG_SHOW_LOG };
+
+/* Returns from the spool_read_header() function */
+
+enum {
+ spool_read_OK, /* success */
+ spool_read_notopen, /* open failed */
+ spool_read_enverror, /* error in the envelope */
+ spool_read_hdrerror /* error in the headers */
+};
+
+/* Options for transport_write_message */
+
+#define topt_add_return_path 0x001
+#define topt_add_delivery_date 0x002
+#define topt_add_envelope_to 0x004
+#define topt_use_crlf 0x008 /* Terminate lines with CRLF */
+#define topt_end_dot 0x010 /* Send terminating dot line */
+#define topt_no_headers 0x020 /* Omit headers */
+#define topt_no_body 0x040 /* Omit body */
+#define topt_escape_headers 0x080 /* Apply escape check to headers */
+#define topt_use_bdat 0x100 /* prepend chunks with RFC3030 BDAT header */
+#define topt_output_string 0x200 /* create string rather than write to fd */
+#define topt_continuation 0x400 /* do not reset buffer */
+#define topt_not_socket 0x800 /* cannot do socket-only syscalls */
+
+/* Options for smtp_write_command */
+
+enum {
+ SCMD_FLUSH = 0, /* write to kernel */
+ SCMD_MORE, /* write to kernel, but likely more soon */
+ SCMD_BUFFER /* stash in application cmd output buffer */
+};
+
+/* Flags for recipient_block, used in DSN support */
+
+#define rf_dsnlasthop 0x01 /* Do not propagate DSN any further */
+#define rf_notify_never 0x02 /* NOTIFY= settings */
+#define rf_notify_success 0x04
+#define rf_notify_failure 0x08
+#define rf_notify_delay 0x10
+
+#define rf_dsnflags (rf_notify_never | rf_notify_success | \
+ rf_notify_failure | rf_notify_delay)
+
+/* DSN RET types */
+
+#define dsn_ret_full 1
+#define dsn_ret_hdrs 2
+
+#define dsn_support_unknown 0
+#define dsn_support_yes 1
+#define dsn_support_no 2
+
+
+/* Codes for the host_find_failed and host_all_ignored options. */
+
+#define hff_freeze 0
+#define hff_defer 1
+#define hff_pass 2
+#define hff_decline 3
+#define hff_fail 4
+#define hff_ignore 5
+
+/* Router information flags */
+
+#define ri_yestransport 0x0001 /* Must have a transport */
+#define ri_notransport 0x0002 /* Must not have a transport */
+
+/* Codes for match types in match_check_list; to any of them, MCL_NOEXPAND may
+be added */
+
+#define MCL_NOEXPAND 16
+
+enum { MCL_STRING, MCL_DOMAIN, MCL_HOST, MCL_ADDRESS, MCL_LOCALPART };
+
+/* Codes for the places from which ACLs can be called. These are cunningly
+ordered to make it easy to implement tests for certain ACLs when processing
+"control" modifiers, by means of a maximum "where" value. Do not modify this
+order without checking carefully!
+
+**** IMPORTANT***
+**** Furthermore, remember to keep these in step with the tables
+**** of names and response codes in globals.c.
+**** IMPORTANT ****
+*/
+
+enum { ACL_WHERE_RCPT, /* Some controls are for RCPT only */
+ ACL_WHERE_MAIL, /* ) */
+ ACL_WHERE_PREDATA, /* ) There are several tests for "in message", */
+ ACL_WHERE_MIME, /* ) implemented by <= WHERE_NOTSMTP */
+ ACL_WHERE_DKIM, /* ) */
+ ACL_WHERE_DATA, /* ) */
+#ifndef DISABLE_PRDR
+ ACL_WHERE_PRDR, /* ) */
+#endif
+ ACL_WHERE_NOTSMTP, /* ) */
+
+ ACL_WHERE_AUTH, /* These remaining ones are not currently */
+ ACL_WHERE_CONNECT, /* required to be in a special order so they */
+ ACL_WHERE_ETRN, /* are just alphabetical. */
+ ACL_WHERE_EXPN,
+ ACL_WHERE_HELO,
+ ACL_WHERE_MAILAUTH,
+ ACL_WHERE_NOTSMTP_START,
+ ACL_WHERE_NOTQUIT,
+ ACL_WHERE_QUIT,
+ ACL_WHERE_STARTTLS,
+ ACL_WHERE_VRFY,
+
+ ACL_WHERE_DELIVERY,
+ ACL_WHERE_UNKNOWN /* Currently used by a ${acl:name} expansion */
+ };
+
+#define ACL_BIT_RCPT BIT(ACL_WHERE_RCPT)
+#define ACL_BIT_MAIL BIT(ACL_WHERE_MAIL)
+#define ACL_BIT_PREDATA BIT(ACL_WHERE_PREDATA)
+#define ACL_BIT_MIME BIT(ACL_WHERE_MIME)
+#define ACL_BIT_DKIM BIT(ACL_WHERE_DKIM)
+#define ACL_BIT_DATA BIT(ACL_WHERE_DATA)
+#ifndef DISABLE_PRDR
+# define ACL_BIT_PRDR BIT(ACL_WHERE_PRDR)
+#endif
+#define ACL_BIT_NOTSMTP BIT(ACL_WHERE_NOTSMTP)
+#define ACL_BIT_AUTH BIT(ACL_WHERE_AUTH)
+#define ACL_BIT_CONNECT BIT(ACL_WHERE_CONNECT)
+#define ACL_BIT_ETRN BIT(ACL_WHERE_ETRN)
+#define ACL_BIT_EXPN BIT(ACL_WHERE_EXPN)
+#define ACL_BIT_HELO BIT(ACL_WHERE_HELO)
+#define ACL_BIT_MAILAUTH BIT(ACL_WHERE_MAILAUTH)
+#define ACL_BIT_NOTSMTP_START BIT(ACL_WHERE_NOTSMTP_START)
+#define ACL_BIT_NOTQUIT BIT(ACL_WHERE_NOTQUIT)
+#define ACL_BIT_QUIT BIT(ACL_WHERE_QUIT)
+#define ACL_BIT_STARTTLS BIT(ACL_WHERE_STARTTLS)
+#define ACL_BIT_VRFY BIT(ACL_WHERE_VRFY)
+#define ACL_BIT_DELIVERY BIT(ACL_WHERE_DELIVERY)
+#define ACL_BIT_UNKNOWN BIT(ACL_WHERE_UNKNOWN)
+
+
+/* Situations for spool_write_header() */
+
+enum { SW_RECEIVING, SW_DELIVERING, SW_MODIFYING };
+
+/* MX fields for hosts not obtained from MX records are always negative.
+MX_NONE is the default case; lesser values are used when the hosts are
+randomized in batches. */
+
+#define MX_NONE (-1)
+
+/* host_item.port defaults to PORT_NONE; the only current case where this
+is changed before running the transport is when an dnslookup router sets an
+explicit port number. */
+
+#define PORT_NONE (-1)
+
+/* Flags for single-key search defaults */
+
+#define SEARCH_STAR 0x01
+#define SEARCH_STARAT 0x02
+
+/* Filter types */
+
+enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE };
+
+/* Codes for ESMTP facilities offered by peer */
+
+#define OPTION_TLS BIT(0)
+#define OPTION_IGNQ BIT(1)
+#define OPTION_PRDR BIT(2)
+#define OPTION_UTF8 BIT(3)
+#define OPTION_DSN BIT(4)
+#define OPTION_PIPE BIT(5)
+#define OPTION_SIZE BIT(6)
+#define OPTION_CHUNKING BIT(7)
+#define OPTION_EARLY_PIPE BIT(8)
+
+/* Argument for *_getc */
+
+#define GETC_BUFFER_UNLIMITED UINT_MAX
+
+/* UTF-8 chars for line-drawing */
+
+#define UTF8_DOWN_RIGHT "\xE2\x95\xAD"
+#define UTF8_VERT "\xE2\x94\x82"
+#define UTF8_HORIZ "\xE2\x94\x80"
+#define UTF8_VERT_RIGHT "\xE2\x94\x9C"
+#define UTF8_UP_RIGHT "\xE2\x95\xB0"
+#define UTF8_VERT_2DASH "\xE2\x95\x8E"
+
+
+/* Options on tls_close */
+#define TLS_NO_SHUTDOWN 0
+#define TLS_SHUTDOWN_NOWAIT 1
+#define TLS_SHUTDOWN_WAIT 2
+
+
+#ifdef COMPILE_UTILITY
+# define ALARM(seconds) alarm(seconds);
+# define ALARM_CLR(seconds) alarm(seconds);
+#else
+/* For debugging of odd alarm-signal problems, stash caller info while the
+alarm is active. Clear it down on cancelling the alarm so we can tell there
+should not be one active. */
+
+# define ALARM(seconds) \
+ debug_selector & D_any \
+ ? (sigalarm_setter = CUS __FUNCTION__, alarm(seconds)) : alarm(seconds);
+# define ALARM_CLR(seconds) \
+ debug_selector & D_any \
+ ? (sigalarm_setter = NULL, alarm(seconds)) : alarm(seconds);
+#endif
+
+#define AUTHS_REGEX US"\\n250[\\s\\-]AUTH\\s+([\\-\\w \\t]+)(?:\\n|$)"
+
+#define EARLY_PIPE_FEATURE_NAME "PIPE_CONNECT"
+#define EARLY_PIPE_FEATURE_LEN 12
+
+
+/* Flags for auth_client_item() */
+
+#define AUTH_ITEM_FIRST BIT(0)
+#define AUTH_ITEM_LAST BIT(1)
+#define AUTH_ITEM_IGN64 BIT(2)
+
+
+/* Flags for tls_{in,out}_resumption */
+#define RESUME_SUPPORTED BIT(0)
+#define RESUME_CLIENT_REQUESTED BIT(1)
+#define RESUME_CLIENT_SUGGESTED BIT(2)
+#define RESUME_SERVER_TICKET BIT(3)
+#define RESUME_USED BIT(4)
+
+#define RESUME_DECODE_STRING \
+ US"not requested or offered : 0x02 :client requested, no server ticket" \
+ ": 0x04 : 0x05 : 0x06 :client offered session, no server action" \
+ ": 0x08 :no client request: 0x0A :client requested new ticket, server provided" \
+ ": 0x0C :client offered session, not used: 0x0E :client offered session, server only provided new ticket" \
+ ": 0x10 :session resumed unasked: 0x12 :session resumed unasked" \
+ ": 0x14 : 0x15 : 0x16 :session resumed" \
+ ": 0x18 :session resumed unasked: 0x1A :session resumed unasked" \
+ ": 0x1C :session resumed: 0x1E :session resumed, also new ticket"
+
+/* Flags for string_vformat */
+#define SVFMT_EXTEND BIT(0)
+#define SVFMT_REBUFFER BIT(1)
+#define SVFMT_TAINT_NOCHK BIT(2)
+
+
+#define NOTIFIER_SOCKET_NAME "exim_daemon_notify"
+#define NOTIFY_MSG_QRUN 1 /* Notify message types */
+#define NOTIFY_QUEUE_SIZE_REQ 2
+
+/* End of macros.h */