1 /* rfc822valid.c -- validators for RFC-822 syntax
2 * (C) Copyright 2007 Matthias Andree <matthias.andree@gmx.de>
3 * GNU General Public License v2 */
5 /* This works only on ASCII-based computers. */
10 /* CHAR except specials, SPACE, CTLs */
11 static const char *atomchar = "!#$%&'*+-/0123456789=?ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz{|}~";
13 static int quotedpair(unsigned char const **x) {
14 if (**x != '\\') return 0;
16 if ((int)* *x > 127 || * *x == '\0')
17 /* XXX FIXME: 0 is a legal CHAR, so the == '\0' is sort of bogus
18 * above, but fetchmail does not currently deal with NUL inputs
19 * so we don't need to make the distinction between
20 * end-of-string and quoted NUL. */
27 static int quotedstring(unsigned char const **x) {
28 if (* *x != '"') return 0;
36 if (quotedpair(x) == 0) return 0;
42 if ((int)* *x >= 128) {
49 static int atom(unsigned char const **x) {
51 if (strchr(atomchar, (char)**x)) {
52 *x += strspn((const char *)*x, atomchar);
55 /* invalid character */
59 static int word(unsigned char const **x) {
61 return quotedstring(x);
65 static int domain_literal(unsigned char const **x) {
66 if (**x != '[') return 0;
78 if (quotedpair(x) == 0) return 0;
81 if ((int)* *x > 127) return 0;
86 static int subdomain(unsigned char const **x) {
87 if (* *x == '[') return domain_literal(x);
91 int rfc822_valid_msgid(const unsigned char *x) {
93 if (*x != '<') return 0;
96 /* expect local-part = word *("." word)
98 * word = atom/quoted-string
100 * quoted-string = <"> *(qtext/quoted-pair) <">
101 * qtext = CHAR except ", \, CR
102 * quoted-pair = "\" CHAR
105 if (word(&x) == 0) return 0;
106 if (*x == '.') { ++x; continue; }
107 if (*x == '@') break;
112 if (*x != '@') return 0;
115 /* expect domain = sub-domain *("." sub-domain)
116 * sub-domain = domain-ref/domain-literal
118 * domain-literal = "[" *(dtext/quoted-pair) "]" */
120 if (subdomain(&x) == 0) return 0;
121 if (*x == '.') { ++x; continue; }
122 if (*x == '>') break;
126 if (*x != '>') return 0;
133 int main(int argc, char **argv) {
135 for (i = 1; i < argc; i++) {
136 printf("%s: %s\n", argv[i], rfc822_valid_msgid((unsigned char *)argv[i]) ? "OK" : "INVALID");