/* * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. * * * $Id: rfc2821.h,v 1.37 2007/11/14 06:03:08 ca Exp $ */ #ifndef SM_RFC2821_H #define SM_RFC2821_H 1 #include "sm/generic.h" #include "sm/str.h" #include "sm/rdstr.h" #include "sm/queue.h" /* RFC 2821 4.1.2 Command Argument Syntax Path = "<" [ A-d-l ":" ] Mailbox ">" A-d-l = At-domain *( "," A-d-l ) At-domain = "@" Domain Domain = (sub-domain 1*("." sub-domain)) / address-literal sub-domain = Let-dig [Ldh-str] address-literal = "[" IPv4-address-literal / IPv6-address-literal / General-address-literal "]" Mailbox = Local-part "@" Domain Local-part = Dot-string / Quoted-string Dot-string = Atom *("." Atom) Atom = 1*atext Quoted-string = DQUOTE *qcontent DQUOTE atext = ALPHA / DIGIT / ; Any character except controls, "!" / "#" / ; SP, and specials. "$" / "%" / ; Used for atoms "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" 2821 doesn't allow \c in Atom, 821 does Let-dig = ALPHA / DIGIT Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig IPv4-address-literal = Snum 3("." Snum) IPv6-address-literal = "IPv6:" IPv6-addr General-address-literal = Standardized-tag ":" 1*dcontent Standardized-tag = Ldh-str Snum = 1*3DIGIT ; representing a decimal integer ; value in the range 0 through 255 IPv6-addr = IPv6-full / IPv6-comp / IPv6v4-full / IPv6v4-comp IPv6-hex = 1*4HEXDIG IPv6-full = IPv6-hex 7(":" IPv6-hex) IPv6-comp = [IPv6-hex *5(":" IPv6-hex)] "::" [IPv6-hex *5(":" IPv6-hex)] ; The "::" represents at least 2 16-bit groups of zeros ; No more than 6 groups in addition to the "::" may be ; present IPv6v4-full = IPv6-hex 5(":" IPv6-hex) ":" IPv4-address-literal IPv6v4-comp = [IPv6-hex *3(":" IPv6-hex)] "::" [IPv6-hex *3(":" IPv6-hex) ":"] IPv4-address-literal ; The "::" represents at least 2 16-bit groups of zeros ; No more than 4 groups in addition to the "::" and ; IPv4-address-literal may be present */ /* XXX define these as T2822 (or vice versa) for interchangeability? */ /* type of element, values below T2821_MIN stand for themselves */ #define T2821_MINTOK 256 #define T2821_ATOM 256 #define T2821_LITERAL 257 /* address literal */ #define T2821_QUOTED 258 /* quoted string */ #define T2821_COMMENT 259 /* comment */ #define T2821_ENDTOK 260 /* artificial end token */ #define T2821_COMMA ',' #define T2821_AT '@' #define T2821_DOT '.' #define T2821_LEFT '<' #define T2821_RIGHT '>' #define T2821_SEMI ';' #define T2821_COLON ':' /* RFC 2821 requirements/elements */ #define R2821_ANGLE 0x0001u #define R2821_AT 0x0002u #define R2821_HOST 0x0004u #define R2821_FQDN 0x0008u #define R2821_LOCAL 0x0010u #define R2821_DOMAIN 0x0020u /* valid domain syntax */ #define R2821_NO_TRLDOT 0x0040u /* no trailing dot */ #define R2821_STRICT 0x007fu /* all of the above... */ #define R2821_CORRECT 0x0077u /* all of the above but FQDN (see grammar) */ #define R2821_EMPTY 0x0080u /* <> is ok */ #define R2821__ 0x0100u /* _ is ok in domain */ #define R2821_ROUTE 0x1000u #define R2821_FREE 0x8000u #define HAS_R2821(flag, which) (((flag) & (which)) != 0) #define SET_R2821(flag, which) (flag) |= (which) #define T2821_FL_NOANGLE 0x0001u /* error codes from parser */ /* XXX sort these? */ /* missing '<' */ #define R2821_ERR_LEFT (R2821_BASE + 1) /* missing '>' */ #define R2821_ERR_RIGHT (R2821_BASE + 2) /* route address (but not allowed) */ #define R2821_ERR_ROUTE (R2821_BASE + 3) /* domain part does not start with an atom */ #define R2821_ERR_HOST (R2821_BASE + 4) /* domain part is not a FQDN */ #define R2821_ERR_FQDN (R2821_BASE + 5) /* missing local part */ #define R2821_ERR_LOCAL (R2821_BASE + 6) /* missing '@' */ #define R2821_ERR_AT (R2821_BASE + 7) /* <>, but not allowed */ #define R2821_ERR_EMPTY (R2821_BASE + 8) /* completely empty address */ #define R2821_ERR_MBOX (R2821_BASE + 9) /* missing ':' (unused) */ #define R2821_ERR_COLON (R2821_BASE + 10) /* "dotstr" syntax is wrong: expected atom after '.' */ #define R2821_ERR_DOTSTR (R2821_BASE + 11) /* domain part is empty */ #define R2821_ERR_DOMAIN (R2821_BASE + 12) /* expecting ':' (unused) */ #define R2821_ERR_DOT (R2821_BASE + 13) /* domain has trailing '.' */ #define R2821_ERR_TRAILDOT (R2821_BASE + 14) /* '@' in route address missing */ #define R2821_ERR_ATDOMAIN (R2821_BASE + 15) /* ',' in route address missing */ #define R2821_ERR_COMMA (R2821_BASE + 16) /* domain part has wrong syntax */ #define R2821_ERR_DOMSYNTAX (R2821_BASE + 17) /* tokens after end */ #define R2821_ERR_MORE (R2821_BASE + 18) /* domain doesn't end in delimiter */ #define R2821_ERR_DEL_MISS (R2821_BASE + 19) #define R2821_ERR_TOOLONG (R2821_BASE + 20) #define R2821_ERR_TRAILBACKSL (R2821_BASE + 21) /* too many closing brackets */ #define R2821_ERR_CLS_BRACKET (R2821_BASE + 22) /* too many closing parentheses */ #define R2821_ERR_CLS_PARENTH (R2821_BASE + 23) /* parenthesis in address not allowed */ #define R2821_ERR_PARENTHESIS (R2821_BASE + 24) /* character must be quoted but isn't */ #define R2821_ERR_MUSTQUOTE (R2821_BASE + 25) typedef struct sm_t2821_S sm_t2821_T, *sm_t2821_P; /* one token in an address */ struct sm_t2821_S { int sm_t2821_type; sm_str_P sm_t2821_val; CIRCLEQ_ENTRY(sm_t2821_S) sm_t2821_l; }; /* static in libmta/rfc2821.c extern sm_t2821_T sm_t2821_end; */ typedef struct sm_a2821_S sm_a2821_T, *sm_a2821_P; /* an address (list head) */ struct sm_a2821_S { CIRCLEQ_HEAD(, sm_t2821_S) sm_a2821_hd; sm_rpool_P sm_a2821_rpool; }; sm_ret_T t2821_scan(sm_rdstr_P _str, sm_a2821_T *_ta, int _off); sm_ret_T t2821_domain(sm_a2821_T *_addr, sm_t2821_P *_ptok, uint _flags); sm_ret_T t2821_parse(sm_a2821_T *_addrin, uint _flags); sm_ret_T t2821_str(sm_a2821_T *_addr, sm_str_P _str, uint _flags); void t2821_free(sm_rpool_P _rpool, sm_t2821_P _tok); void a2821_free(sm_a2821_T *_addr); sm_ret_T t2821_cp_token(sm_rpool_P _rpool, sm_t2821_P _src_tok,sm_t2821_P *_pdst_tok); sm_ret_T t2821_extract_domain(sm_rpool_P _rpool, sm_a2821_T *_addr, sm_a2821_T **_pdomain); sm_ret_T t2821_extract_local(sm_rpool_P _rpool, sm_a2821_T *_addr, int delim_type, sm_a2821_T **_plocal); #if 0 sm_ret_T t2821_locdet(sm_a2821_T *_addr, const uchar *_delim, bool _observequotes, sm_str_P _local, sm_str_P _detail); #endif sm_ret_T t2821_parts(sm_a2821_T *_addr, const uchar *_delim, bool _observequotes, sm_str_P _local, sm_str_P _detail, sm_str_P _domain, uchar *_pdelim); /* operations on addresses */ /* this shouldn't be used, see below for A2821_INIT_RP() instead */ #define A2821_INIT(addr) CIRCLEQ_INIT(&((addr)->sm_a2821_hd)) #define A2821_FIRST(addr) CIRCLEQ_FIRST(&((addr)->sm_a2821_hd)) #define A2821_LAST(addr) CIRCLEQ_LAST(&((addr)->sm_a2821_hd)) #define A2821_END(addr) CIRCLEQ_END(&((addr)->sm_a2821_hd)) #define A2821_INSERT_TAIL(addr, tok) CIRCLEQ_INSERT_TAIL(&((addr)->sm_a2821_hd), tok, sm_t2821_l) #define A2821_INSERT_HEAD(addr, tok) CIRCLEQ_INSERT_HEAD(&((addr)->sm_a2821_hd), tok, sm_t2821_l) #define A2821_REMOVE(addr, tok) CIRCLEQ_REMOVE(&((addr)->sm_a2821_hd), tok, sm_t2821_l) #define A2821_REMOVE_FREE(addr, tok) do { \ CIRCLEQ_REMOVE(&((addr)->sm_a2821_hd), tok, sm_t2821_l); \ t2821_free((addr)->sm_a2821_rpool, tok); \ } while (0) #define T2821_NEXT(tok) (SM_ASSERT((tok) != NULL && (tok)->sm_t2821_type != T2821_ENDTOK), CIRCLEQ_NEXT(tok, sm_t2821_l)) #define A2821_INIT_RP(addr, rpool) do { \ A2821_INIT(addr); \ (addr)->sm_a2821_rpool = (rpool); \ } while (0) /* ** If we stay with CIRCLEQ, then deletion can be simplified (really?): ** while (CIRCLEQ_FIRST(&head) != CIRCLEQ_END(&head)) ** CIRCLEQ_REMOVE(&head, CIRCLEQ_FIRST(&head), entries); */ #endif /* SM_RFC2821_H */