/* Small pieces for scanning forward on a buffer of RFC-821/822 compliant addresses */ /* (c) Matti Aarnio 1993-2000 */ /* All these routines scan over the lexical elements they are after, and if successfull, return pointer just AFTER such element. If they fail, they return their input -- thus no scan forward.. */ #ifndef __STDC__ #define const #endif #include const char *rfc821_error = 0; /* Error text */ const char *rfc821_error_ptr = 0; /* scan position of the error */ extern char *rfc821_domain(); /* Entry point */ extern char *rfc821_path(); /* Entry point */ extern char *rfc821_path2(); /* Entry point */ extern char *rfc821_adl(); /* Entry point */ static char *rfc821_localpart(); /* static forward definition */ static char *rfc821_dotnum(); /* static forward definition */ static const char *premature_end = "Premature end of input"; static const char *no_input = "No input"; /* ================================================================ */ #define CHAR_ALPHA 0x0001 #define CHAR_ALNUM 0x0002 #define CHAR_SPECL 0x0004 #define CHAR_DIGIT 0x0008 #define CHAR_C 0x0010 #define CHAR_X 0x0020 #define CHAR_Q 0x0040 #define CHAR_XDIGIT 0x0080 #define CHAR_822ATM 0x0100 #define CHAR_XCHAR 0x0200 #define CHR_ENT(a,b,c,d,e,f,g,h,i,j) \ (a?CHAR_ALPHA:0)|(b?CHAR_ALNUM:0)|(c?CHAR_SPECL:0)| \ (d?CHAR_DIGIT:0)|(e?CHAR_C:0)|(f?CHAR_X:0)|(g?CHAR_Q:0)| \ (h?CHAR_XDIGIT:0)|(i?CHAR_822ATM:0)|(j?CHAR_XCHAR:0) /* Could use 'unsigned short' here, but the Alpha machines dislike anything smaller than int (32 bit) */ static #if defined(__alpha)||defined(__alpha__) int #else short #endif char_array[] = { /* /------------------------------ CHAR_ALPHA | /--------------------------- CHAR_ALNUM | | /------------------------ CHAR_SPECL | | | /--------------------- CHAR_DIGIT | | | | /------------------ CHAR_C | | | | | /--------------- CHAR_X | | | | | | /------------ CHAR_Q | | | | | | | /--------- CHAR_XDIGIT | | | | | | | | /------ CHAR_822ATM | | | | | | | | | /--- CHAR_XCHAR | | | | | | | | | | */ /* 0: `^@' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 1: `^A' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 2: `^B' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 3: `^C' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 4: `^D' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 5: `^E' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 6: `^F' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 7: `^G' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 8: `^H' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 9: `^I' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 10: `^J' */ CHR_ENT(0, 0, 1, 0, 0, 1, 0, 0, 0, 0), /* 11: `^K' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 12: `^L' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 13: `^M' */ CHR_ENT(0, 0, 1, 0, 0, 1, 0, 0, 0, 0), /* 14: `^N' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 15: `^O' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 16: `^P' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 17: `^Q' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 18: `^R' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 19: `^S' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 20: `^T' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 21: `^U' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 22: `^V' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 23: `^W' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 24: `^X' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 25: `^Y' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 26: `^Z' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 27: `^[' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 28: `^\' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 29: `^]' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 30: `^^' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 31: `^_' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 0), /* 32: ` ' */ CHR_ENT(0, 0, 0, 0, 0, 1, 1, 0, 0, 0), /* 33: `!' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 34: `"' */ CHR_ENT(0, 0, 1, 0, 0, 1, 0, 0, 1, 1), /* 35: `#' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 36: `$' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 37: `%' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 38: `&' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 39: `'' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 40: `(' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 1), /* 41: `)' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 1), /* 42: `*' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 43: `+' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 0), /* 44: `,' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 1), /* 45: `-' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 46: `.' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 1, 1), /* 47: `/' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 48: `0' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 49: `1' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 50: `2' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 51: `3' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 52: `4' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 53: `5' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 54: `6' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 55: `7' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 56: `8' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 57: `9' */ CHR_ENT(0, 1, 0, 1, 1, 1, 1, 1, 1, 1), /* 58: `:' */ CHR_ENT(0, 0, 0, 0, 0, 1, 1, 0, 0, 1), /* 59: `;' */ CHR_ENT(0, 0, 0, 0, 0, 1, 1, 0, 0, 1), /* 60: `<' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 1), /* 61: `=' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 0), /* 62: `>' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 1), /* 63: `?' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 64: `@' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 1, 1), /* 65: `A' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 66: `B' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 67: `C' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 68: `D' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 69: `E' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 70: `F' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 71: `G' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 72: `H' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 73: `I' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 74: `J' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 75: `K' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 76: `L' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 77: `M' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 78: `N' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 79: `O' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 80: `P' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 81: `Q' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 82: `R' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 83: `S' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 84: `T' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 85: `U' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 86: `V' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 87: `W' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 88: `X' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 89: `Y' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 90: `Z' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 91: `[' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 1), /* 92: `\' */ CHR_ENT(0, 0, 1, 0, 0, 1, 0, 0, 0, 1), /* 93: `]' */ CHR_ENT(0, 0, 1, 0, 0, 1, 1, 0, 0, 1), /* 94: `^' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 95: `_' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 96: ``' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 97: `a' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 98: `b' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 99: `c' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 100: `d' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 101: `e' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 102: `f' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 1, 1, 1), /* 103: `g' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 104: `h' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 105: `i' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 106: `j' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 107: `k' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 108: `l' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 109: `m' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 110: `n' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 111: `o' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 112: `p' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 113: `q' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 114: `r' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 115: `s' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 116: `t' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 117: `u' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 118: `v' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 119: `w' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 120: `x' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 121: `y' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 122: `z' */ CHR_ENT(1, 1, 0, 0, 1, 1, 1, 0, 1, 1), /* 123: `{' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 124: `|' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 125: `}' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 126: `~' */ CHR_ENT(0, 0, 0, 0, 1, 1, 1, 0, 1, 1), /* 127: `DEL' */ CHR_ENT(0, 0, 0, 0, 0, 1, 1, 0, 0, 0), /* 128: `\200' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 129: `\201' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 130: `\202' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 131: `\203' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 132: `\204' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 133: `\205' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 134: `\206' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 135: `\207' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 136: `\210' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 137: `\211' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 138: `\212' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 139: `\213' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 140: `\214' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 141: `\215' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 142: `\216' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 143: `\217' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 144: `\220' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 145: `\221' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 146: `\222' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 147: `\223' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 148: `\224' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 149: `\225' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 150: `\226' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 151: `\227' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 152: `\230' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 153: `\231' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 154: `\232' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 155: `\233' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 156: `\234' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 157: `\235' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 158: `\236' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 159: `\237' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 160: `\240' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 161: `\241' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 162: `\242' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 163: `\243' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 164: `\244' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 165: `\245' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 166: `\246' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 167: `\247' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 168: `\250' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 169: `\251' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 170: `\252' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 171: `\253' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 172: `\254' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 173: `\255' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 174: `\256' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 175: `\257' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 176: `\260' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 177: `\261' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 178: `\262' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 179: `\263' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 180: `\264' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 181: `\265' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 182: `\266' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 183: `\267' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 184: `\270' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 185: `\271' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 186: `\272' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 187: `\273' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 188: `\274' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 189: `\275' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 190: `\276' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 191: `\277' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 192: `\300' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 193: `\301' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 194: `\302' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 195: `\303' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 196: `\304' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 197: `\305' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 198: `\306' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 199: `\307' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 200: `\310' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 201: `\311' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 202: `\312' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 203: `\313' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 204: `\314' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 205: `\315' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 206: `\316' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 207: `\317' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 208: `\320' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 209: `\321' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 210: `\322' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 211: `\323' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 212: `\324' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 213: `\325' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 214: `\326' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 215: `\327' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 216: `\330' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 217: `\331' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 218: `\332' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 219: `\333' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 220: `\334' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 221: `\335' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 222: `\336' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 223: `\337' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 224: `\340' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 225: `\341' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 226: `\342' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 227: `\343' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 228: `\344' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 229: `\345' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 230: `\346' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 231: `\347' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 232: `\350' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 233: `\351' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 234: `\352' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 235: `\353' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 236: `\354' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 237: `\355' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 238: `\356' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 239: `\357' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 240: `\360' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 241: `\361' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 242: `\362' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 243: `\363' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 244: `\364' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 245: `\365' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 246: `\366' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 247: `\367' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 248: `\370' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 249: `\371' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 250: `\372' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 251: `\373' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 252: `\374' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 253: `\375' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 254: `\376' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* 255: `\377' */ CHR_ENT(0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }; #ifdef __GNUC__ #define __MY_INLINE__ static __inline__ #else #define __MY_INLINE__ static #endif __MY_INLINE__ int is_821_alpha(chr) unsigned int chr; { return (char_array[chr] & CHAR_ALPHA); } __MY_INLINE__ int is_821_alnum(chr) unsigned int chr; { return (char_array[chr] & CHAR_ALNUM); } __MY_INLINE__ int is_821_specl(chr) unsigned int chr; { return (char_array[chr] & CHAR_SPECL); } __MY_INLINE__ int is_821_digit(chr) unsigned int chr; { return (char_array[chr] & CHAR_DIGIT); } __MY_INLINE__ int is_821_xdigit(chr) unsigned int chr; { return (char_array[chr] & CHAR_XDIGIT); } __MY_INLINE__ int is_821_C(chr) unsigned int chr; { return (char_array[chr] & CHAR_C); } __MY_INLINE__ int is_821_X(chr) unsigned int chr; { return (char_array[chr] & CHAR_X); } __MY_INLINE__ int is_821_Q(chr) unsigned int chr; { return (char_array[chr] & CHAR_Q); } __MY_INLINE__ int is_822_atomchar(chr) unsigned int chr; { return (char_array[chr] & CHAR_822ATM); } /* ================================================================ */ char *rfc822atom(str) char *str; { char *str0 = str; while (*str != 0) { if (!is_822_atomchar(*(unsigned char *) str)) { if (str > str0) /* Stop on ';', for example */ return str; goto err; } ++str; } if (str == str0) { err: rfc821_error_ptr = str; rfc821_error = "Invalid RFC822 atom"; return str0; } return str; } char *xtext_string(str) char *str; { /* Verify that the input is valid RFC 1981 XTEXT string! */ char *str0 = str; while (*str) { unsigned char c = *str; if (c == ' ' || c == '\t') break; if (char_array[c] & CHAR_XCHAR) /* ('!' <= c && c <= '~' && c != '+' && c != '=') */ ; /* is ok! */ else if (c == '+') { c = *++str; if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F'))) { goto err; } c = *++str; if (!(('0' <= c && c <= '9') || ('A' <= c && c <= 'F'))) { goto err; } } else { goto err; } ++str; } if (str == str0) { err: rfc821_error_ptr = str; rfc821_error = "Invalid character in XTEXT string"; return str0; } return str; } static char *rfc821_at_domain(s, strict) /* "@" */ char *s; int strict; { char *p; if (!s || !*s) return s; /* Pathological termination */ if (*s != '@') { rfc821_error = " missing initial \"@\""; rfc821_error_ptr = s; return s; } p = rfc821_domain(s + 1, strict); if (!p || p == s + 1) { rfc821_error_ptr = s + 1; rfc821_error = "missing domain entry"; return s; } return p; } char *rfc821_adl(s, strict) /* | "," */ char *s; int strict; { char *p = s, *q; if (!s || !*s) return s; /* Pathological termination */ while ((q = rfc821_at_domain(p, strict)) && (q > p)) { /* Scanned over an "@"+ */ p = q; if (*p != ',') return p; ++p; } return s; } static char *rfc821_v6dotnum(s, strict) char *s; int strict; { /* rfc821_v6dotnum() -- rather heavily mutated from BIND 4.9.4 inet_pton6() * routine by Matti Aarnio , 1997 */ /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ #ifndef IN6ADDRSZ /* Probably these all set at the same time.. */ #define IN6ADDRSZ 16 #define INADDRSZ 4 #define INT16SZ 2 #endif const char *curtok; int ch, saw_xdigit; int tpcnt, colonidx; unsigned int val; char *src = s; tpcnt = 0; colonidx = -1; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') { rfc821_error_ptr = s; rfc821_error = "Leading double-colon must have a pair in "; return (s); } curtok = src; saw_xdigit = 0; val = 0; for ( ;((ch = *src) != '\0' && ch != ']'); ++src) { if (is_821_xdigit(ch)) { val <<= 4; if (ch >= 'a') ch -= ('a' - 'A'); if (ch >= 'A') ch -= ('A' + 1 - '9'); val |= (ch - '0'); if (val > 0xffff) { rfc821_error_ptr = src - 1; rfc821_error = "Too big value for element"; return (s); } saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonidx >= 0) { rfc821_error_ptr = src - 2; rfc821_error = "Illegal intermediate double-colon in "; return (s); } colonidx = tpcnt; continue; } if (tpcnt + INT16SZ > IN6ADDRSZ) { rfc821_error_ptr = src - 1; rfc821_error = "Too many colon-separated components in "; return (s); } tpcnt += 2; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tpcnt + INADDRSZ) <= IN6ADDRSZ)) { src = rfc821_dotnum(curtok, strict); if (src == curtok) { /* The plain dotnum reported its own errors.. */ return (s); } tpcnt += INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } rfc821_error_ptr = src - 1; rfc821_error = " error ?"; return (s); } if (saw_xdigit) { if (tpcnt + INT16SZ > IN6ADDRSZ) { rfc821_error_ptr = src - 1; rfc821_error = "Too many colon-separated components in "; return (s); } tpcnt += 2; } if (colonidx >= 0) { tpcnt = IN6ADDRSZ; } if (tpcnt != IN6ADDRSZ) { rfc821_error_ptr = src - 1; /* XX: Really this diagnostics ? */ rfc821_error = "Too few colon-separated components in "; return (s); } return (src); } static char *rfc821_dotnum(s, strict) /* "." "." "." */ char *s; int strict; { int i, val, cnt; char *p = s - 1; if (*s == 'i' || *s == 'I') { /* Wow! Possibly IPv6 prefix! */ if (strncasecmp(s, "IPv6:", 5) == 0 /* || strncasecmp(s, "IPv6.", 5) == 0 */ ) { p = rfc821_v6dotnum(s + 5, strict); if (p == s + 5) return s; return p; } else { rfc821_error_ptr = s; rfc821_error = "Bad syntax of value"; return s; } } for (i = 0; i < 4; ++i) { val = cnt = 0; ++p; while (*p && is_821_digit(*p)) { val *= 10; val += (*p - '0'); ++cnt; ++p; } if (val > 255 || cnt < 1 || cnt > 3) { rfc821_error_ptr = p; rfc821_error = "Bad syntax of value"; return s; } if (i < 3 && (!*p || *p != '.')) { rfc821_error_ptr = p; rfc821_error = "Bad syntax of , missing '.'"; return s; } } return p; } static char *rfc821_name(s, strict, allnump) char *s; int strict; int *allnump; /* Return a flag about all-numeric field.. */ { char c; char *p = s; char *bad_name = "RFC821 bad syntax"; int has_alpha = 0; if (!s || !*s) return s; /* Pathological termination */ /* The first test should be is_821_alpha(), as per RFC821 we should accept only A-Z,a-Z in the begining, but 3COM spoiled that... Grumble... */ /* So now we allow chars: 0-9, A-Z, a-z, and '-' for valid at the domain name segment -- but '-' is not ok at the begin. */ /* To note futher; the underscore is not allowed at the DNS, and thus it should not be allowed at email addresses either. */ /* Our caller will do deeper analysis, wether or not ALL of the input was numeric: foo@12.34.56.78 If yes, special error message is reported. For that purpose we count '-' as an alpha */ c = *p; if (!is_821_alnum(c)) { rfc821_error_ptr = p; rfc821_error = bad_name; return s; /* Don't advance, leave! */ } while (is_821_alnum(c) || (c == '-')) { has_alpha |= (is_821_alpha(c) || c == '-'); c = *(++p); } *allnump &= !has_alpha; return p; /* Name ok, return advanced pointer */ } char *rfc821_domain(s, strict) /* "#" | "[" "]" | | "." */ char *s; int strict; { char *p = s, *q; int allnum; /* If all fields are numeric, it isn't domain.. */ if (!s || !*s) { rfc821_error = "RFC821: No input"; return s; /* Pathological termination */ } if (*p == '[') { q = rfc821_dotnum(p + 1, strict); if (q == p + 1) return s; if (*q != ']') { rfc821_error_ptr = q - 1; rfc821_error = "RFC821 element missing terminating \"]\""; return s; } return q + 1; } if (*p == '#') { /* Deprecated "#1234234324" -format */ ++p; while (is_821_digit(*p)) ++p; if (p > s + 1) return p; rfc821_error_ptr = s; rfc821_error = "RFC821 Domain \"#numbers\" has inadequate count of numbers"; return s; /* Failure, don't advance */ } allnum = 1; /* Collect info about all fields being numeric.. To accept "1302.watstar.waterloo.edu" et.al. but not something which looks like all numbers.. */ if (*p == '.') { rfc821_error = "A domain-name does not start with a dot (.)"; rfc821_error_ptr = p; return s; } q = rfc821_name(p, strict, &allnum); while (p && q > p && *q == '.') { p = q + 1; if (*p == 0 || *p == '>') { rfc821_error = "Spurious dot (.) at the end of the domain name"; rfc821_error_ptr = q; return s; } q = rfc821_name(p, strict, &allnum); } if (allnum) { rfc821_error = "Should this be of format ? ( [nn.nn.nn.nn] )"; return s; } if (!rfc821_error) rfc821_error = "bad syntax on domain"; if (!q || p == q) return s; /* Report whatever reports */ return q; /* Ok */ } static char *rfc821_mailbox(s, strict) /* "@" */ char *s; /* Report error */ int strict; { char *p = s, *q; if (!s || !*s) { /* rfc821_error_ptr = s; rfc821_error = no_input; */ return s; /* Pathological termination */ } p = rfc821_localpart(p, strict); if (p == s) { /*rfc821_error_ptr = s; */ /*rfc821_error = "No mailbox definition"; */ return s; } if (!strict) { if (*p == 0 || *p == '>') /* If it terminates here, it is only the */ return p; } if (*p == ':') { rfc821_error_ptr = p; rfc821_error = "Perhaps this should have been a dot (.) instead of colon (:) ?"; return s; } if (*p != '@') { rfc821_error_ptr = p; rfc821_error = "Missing \"@\" from mailbox definition"; return s; } ++p; q = rfc821_domain(p, strict); if (q == p) { /* Error report from domain.. */ return s; } return q; } static char *rfc821_char(s) char *s; { if (!s || !*s) return s; if (*s == '\\') { if (!is_821_X(*(s + 1))) return s; return s + 2; } if (is_821_C(*s)) return s + 1; return s; } static char *rfc821_string(s, strict) char *s; int strict; { char *p = s, *q; if (!s || !*s) return s; while ((q = rfc821_char(p)) && (q > p)) { p = q; } if (*(unsigned char *) q > 127) { rfc821_error_ptr = q; rfc821_error = "Improper 8-bit character in string"; return s; } if (q == s) { rfc821_error_ptr = s; rfc821_error = "Had characters unsuitable for an rfc821-string"; } return q; /* Advanced or not.. */ } static char *rfc821_dot_string(s, strict) char *s; int strict; { char *p = s, *q; if (!s || !*s) return s; /* Pathological termination */ q = rfc821_string(p, strict); if (q == p) return s; /* Missing string */ while (*q == '.') { /* Well, intermediate dot.. */ p = q + 1; #if 0 if (!is_821_alnum(*p)) { rfc821_error_ptr = q; rfc821_error = "After a dot, something which is not alphanumeric"; return s; } #endif q = rfc821_string(p, strict); if (q == p) { if (*q == '@') { rfc821_error = "Localpart must not end with unquoted dot!"; } return s; /* Missing string */ } } return q; } static char *rfc821_qtext(s, strict) char *s; int strict; { char *p = s; int fail = 0; if (!s || !*s) return s; while (*p && !fail) { if (*p == '\\') { ++p; if (is_821_X(*p)) ++p; else fail = 1; } else if (is_821_Q(*p)) ++p; else break; } if ((unsigned char) *p > 127) { rfc821_error_ptr = p; rfc821_error = "Improper 8-bit character in qtext"; return s; } if (fail || p == s) { rfc821_error_ptr = p; rfc821_error = "RFC821 qtext data failure"; return s; } return p; } static char *rfc821_quoted_string(s, strict) char *s; int strict; { char *p = s, *q; if (!s || !*s) return s; /* Pathological termination */ if (*p != '"') { rfc821_error_ptr = p; rfc821_error = "Quoted string w/o initial quote (\")"; return s; } ++p; q = rfc821_qtext(p, strict); if (p == q) { /* rfc821_error_ptr = q; rfc821_error = "Quoted string of 0 length :-("; */ return s; } if (*q != '"') { rfc821_error_ptr = q; rfc821_error = "Quoted string w/o final quote (\")"; return s; } return q + 1; } static char *rfc821_localpart(s, strict) /* | */ char *s; /* Stretched RFC821 a bit here.. !%-hacks */ int strict; { char *p = s, *q; /* int _ok = 0; */ if (!s || !*s) return s; /* Pathological termination */ while (*p) { if (*p == '"') { q = rfc821_quoted_string(p, strict); if (q == p) return s; /* Uh... */ #if 0 /* RFC 2821 -- local part internal hack-syntax interpretation shall not be done, unless domain is known to be local */ if (*q == '%' || *q == '!') { p = q + 1; _ok = (*q == '!' && *p == '_'); if (!is_821_alnum(*p) && !_ok && *p != '"') { rfc821_error_ptr = q; if (*q == '%') { rfc821_error = "After a '%', a non alphanumeric element"; } else { rfc821_error = "After a '!', a non alphanumeric element"; } return s; } continue; } #endif return q; } q = rfc821_dot_string(p, strict); if (q == p) return s; /* Uh... */ #if 0 /* RFC 2821 -- local part internal hack-syntax interpretation shall not be done, unless domain is known to be local */ if (*q == '%' || *q == '!') { p = q + 1; _ok = (*q == '!' && *p == '_'); if (!is_821_alnum(*p) && !_ok && *p != '"') { rfc821_error_ptr = q; if (*q == '%') { rfc821_error = "After a '%', a non alphanumeric element"; } else { rfc821_error = "After a '!', a non alphanumeric element"; } return s; } continue; } #endif return q; } return p; /* Run to end of string.. */ } char *rfc821_path2(s, strict) /* [ ":" ] */ char *s; int strict; { char *p = s, *q; if (!s || !*s) { rfc821_error_ptr = s; rfc821_error = no_input; return s; /* Pathological termination */ } if (*p == '@' && (q = rfc821_adl(p, strict)) && (q > p)) { p = q; if (*p == '>' || *p == ' ') { rfc821_error_ptr = p; rfc821_error = "No local part before leading @-character ?"; return s; } if (*p != ':') { rfc821_error_ptr = p; rfc821_error = "Missing colon (:) from <@xxx:yyy@zzz>"; return s; } ++p; } q = rfc821_mailbox(p, strict); if (q == p) { /* Report whatever mailbox() reports as an error */ return s; } return q; } char *rfc821_path(s, strict) /* "<" [ ":" ] ">" */ char *s; int strict; { char *p = s, *q; if (!s || !*s) { rfc821_error_ptr = s; rfc821_error = no_input; return s; /* Pathological termination */ } if (*p != '<') { rfc821_error = "Missing \"<\" from begining"; rfc821_error_ptr = p; return s; } ++p; if (!*p) { rfc821_error = premature_end; rfc821_error_ptr = p; return s; } if (*p == '>') { return p + 1; /* Termination ok */ } q = rfc821_path2(p, strict); if (q == p) { /* Report whatever path2() reports as an error */ return s; } if (*q == ' ' || *q == '\t') { /* Sometimes sending systems have: , painfull.. */ p = q; while (*p == ' ' || *p == '\t') ++p; /* Ok, copy down the rest of the input, and thus save the day.. Purist would just report an error, but lets be lenient, when it is fairly easy, and painless to do.. */ if (p > q) strcpy(q, p); } if (*q != '>') { rfc821_error = "Missing \">\" at end"; if (*q) rfc821_error = "Extra garbage before terminating \">\""; rfc821_error_ptr = q; return s; } return q + 1; }