/*
* 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 */
syntax highlighted by Code2HTML, v. 0.9.1