static const char * const zonenames[] = { "UT","GMT", "EST","EDT", "CST","CDT", "MST","MDT", "PST","PDT", "Z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", NULL}; #define ZH(n) ( (n) * 60 * 60 ) static int zoneoffset[] = { 0, 0, ZH(-5), ZH(-4), ZH(-6), ZH(-5), ZH(-7), ZH(-6), ZH(-8), ZH(-7), 0, ZH(-1), ZH(-2), ZH(-3), ZH(-4), ZH(-5), ZH(-6), ZH(-7), ZH(-8), ZH(-9), ZH(-10), ZH(-11), ZH(-12), ZH(1), ZH(2), ZH(3), ZH(4), ZH(5), ZH(6), ZH(7), ZH(8), ZH(9), ZH(10), ZH(11), ZH(12) }; static unsigned parsekey(const char **mon, const char * const *ary) { unsigned m, j; for (m=0; ary[m]; m++) { for (j=0; ary[m][j]; j++)
namespace acl { #define STR acl_vstring_str #define LEN ACL_VSTRING_LEN static const char * const months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL }; static const char * const wdays[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static unsigned parsedig(const char **p) { unsigned i = 0; while (isdigit((int) (unsigned char) **p)) { i = i * 10 + **p - '0'; ++*p; } return (i); } #define leap(y) (((y) % 400) == 0 || (((y) % 4) == 0 && (y) % 100) ) static const unsigned mlength[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; #define mdays(m,y) ( (m) != 2 ? mlength[(m) - 1] : leap(y) ? 29 : 28) static const char *const zonenames[] = { "UT", "GMT", "EST", "EDT", "CST", "CDT", "MST", "MDT", "PST", "PDT", "Z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", NULL }; #define ZH(n) ( (n) * 60 * 60 ) static const int zoneoffset[] = { 0, 0, ZH(-5), ZH(-4), ZH(+8), ZH(-5), ZH(-7), ZH(-6), ZH(-8), ZH(-7), 0, ZH(-1), ZH(-2), ZH(-3), ZH(-4), ZH(-5), ZH(-6), ZH(-7), ZH(-8), ZH(-9), ZH(-10), ZH(-11), ZH(-12), ZH(1), ZH(2), ZH(3), ZH(4), ZH(5), ZH(6), ZH(7), ZH(8), ZH(9), ZH(10), ZH(11), ZH(12) }; static unsigned parsekey(const char **mon, const char * const *ary) { unsigned m = 0, j = 0; for (m = 0; ary[m]; m++) { for (j = 0; ary[m][j]; j++) { if (tolower(ary[m][j]) != tolower((*mon)[j])) break; } if (!ary[m][j]) { *mon += j; return (m + 1); } } return (0); } static int parsetime(const char **t) { unsigned h = 0, m = 0, s = 0; if (!isdigit((int)(unsigned char) **t)) return (-1); h = parsedig(t); if (h > 23) return (-1); if (**t != ':') return (-1); ++*t; if (!isdigit((int) (unsigned char) **t)) return (-1); m = parsedig(t); if (**t == ':') { ++*t; if (!isdigit((int) (unsigned char) **t)) return (-1); s = parsedig(t); } if (m > 59 || s > 59) return (-1); return (h * 60 * 60 + m * 60 + s); } rfc822::rfc822() { } rfc822::~rfc822() { reset(); } time_t rfc822::parse_date(const char *rfcdt) { unsigned day = 0, mon = 0, year = 0; int secs = 0; int offset = 0; time_t t = 0; unsigned y = 0; int sign = 1; unsigned n = 0; /* Ignore day of the week. Tolerate "Tue, 25 Feb 1997 ... " ** without the comma. Tolerate "Feb 25 1997 ...". */ while (!day || !mon) { if (!*rfcdt) return (0); if (isalpha((int)(unsigned char)*rfcdt)) { if (mon) return (0); mon = parsekey(&rfcdt, months); if (!mon) while (*rfcdt && isalpha((int)(unsigned char)*rfcdt)) ++rfcdt; continue; } if (isdigit((int)(unsigned char)*rfcdt)) { if (day) return (0); day = parsedig(&rfcdt); if (!day) return (0); continue; } ++rfcdt; } while (*rfcdt && isspace((int)(unsigned char)*rfcdt)) ++rfcdt; if (!isdigit((int)(unsigned char)*rfcdt)) return (0); year = parsedig(&rfcdt); if (year < 70) year += 2000; if (year < 100) year += 1900; while (*rfcdt && isspace((int)(unsigned char)*rfcdt)) ++rfcdt; if (day == 0 || mon == 0 || mon > 12 || day > mdays(mon, year)) return (0); secs = parsetime(&rfcdt); if (secs < 0) return (0); offset = 0; /* RFC822 sez no parenthesis, but I've seen (EST) */ while ( *rfcdt ) { if (isalnum((int)(unsigned char)*rfcdt) || *rfcdt == '+' || *rfcdt == '-') { break; } ++rfcdt; } if (isalpha((int)(unsigned char)*rfcdt)) { n = parsekey(&rfcdt, zonenames); if (n > 0) offset = zoneoffset[n - 1]; } else { switch (*rfcdt) { case '-': sign = -1; case '+': ++rfcdt; } if (isdigit((int)(unsigned char)*rfcdt)) { n = parsedig(&rfcdt); if (n > 2359 || (n % 100) > 59) n = 0; offset = sign * ( (n % 100) * 60 + n / 100 * 60 * 60); } } if (year < 1970) { printf("%s(%d)\n", __FUNCTION__, __LINE__); return (0); } t = 0; for (y = 1970; y < year; y++) { if ( leap(y) ) { if (year - y >= 4) { y += 3; t += ( 365 * 3 + 366 ) * 24 * 60 * 60; continue; } t += 24 * 60 * 60; } t += 365 * 24 * 60 * 60; } for (y = 1; y < mon; y++) t += mdays(y, year) * 24 * 60 * 60; return (t + (day - 1) * 24 * 60 * 60 + secs - offset); } void rfc822::mkdate(time_t t, char* buf, size_t size, tzone_t zone) { if (zone == tzone_cst) mkdate_cst(t, buf, size); else mkdate_gmt(t, buf, size); } void rfc822::mkdate_gmt(time_t t, char *buf, size_t size) { struct tm *p; #ifdef WIN32 # if _MSC_VER >= 1500 struct tm gmt_buf; p = &gmt_buf; if (gmtime_s(p, &t) != 0) p = NULL; # else p = gmtime(&t); # endif #else struct tm tm_buf; p = gmtime_r(&t, &tm_buf); #endif snprintf(buf, size, "%s, %02d %s %04d %02d:%02d:%02d (GMT)", wdays[p->tm_wday], p->tm_mday, months[p->tm_mon], p->tm_year + 1900, p->tm_hour, p->tm_min, p->tm_sec); } #define USE_TIME_DAYLIGHT 1 void rfc822::mkdate_cst(time_t t, char *buf, size_t size) { struct tm *p; int offset = 0; #ifdef WIN32 # if _MSC_VER >= 1500 struct tm tm_buf; long s; p = &tm_buf; if (localtime_s(p, &t) != 0) p = NULL; # else p = localtime(&t); # endif #else struct tm tm_buf; p = localtime_r(&t, &tm_buf); #endif buf[0] = 0; if (p == NULL) return; #if USE_TIME_ALTZONE offset = -_timezone; if (p->tm_isdst > 0) offset = -altzone; if (offset % 60) { offset = 0; #ifdef WIN32 # if _MSC_VER >= 1500 p = &tm_buf; if (gmtime_s(p, &t) != 0) p = NULL; # else p = gmtime(&t); # endif #else p = gmtime_r(&t, &tm_buf); #endif } offset /= 60; #else #if USE_TIME_DAYLIGHT #ifdef WIN32 # if _MSC_VER >= 1500 if ( _get_timezone(&s) != 0) s = 0; offset =- s; # else offset = - _timezone; # endif #elif !defined(ACL_FREEBSD) // XXX -zsx offset = - timezone; #endif if (p == NULL) return; if (p->tm_isdst > 0) offset += 60 * 60; if (offset % 60) { offset = 0; #ifdef WIN32 # if _MSC_VER >= 1500 p = &tm_buf; if (gmtime_s(p, &t) != 0) p = NULL; # else p = gmtime(&t); # endif #else p = gmtime_r(&t, &tm_buf); #endif } offset /= 60; #else #if USE_TIME_GMTOFF offset = p->tm_gmtoff; if (offset % 60) { offset = 0; #ifdef WIN32 # if _MSC_VER >= 1500 p = &tm_buf; if (gmtime_s(p, &t) != 0) p = NULL; # else p = gmtime(&t); # endif #else p = gmtime_r(&t, &tm_buf); #endif } offset /= 60; #else #ifdef WIN32 # if _MSC_VER >= 1500 p = &tm_buf; if (gmtime_s(p, &t) != 0) p = NULL; # else p = gmtime(&t); # endif #else p = gmtime_r(&t, &tm_buf); #endif offset = 0; #endif #endif #endif offset = (offset % 60) + offset / 60 * 100; #if defined(WIN32) && _MSC_VER >= 1500 _snprintf_s(buf, size, size, "%s, %02d %s %04d %02d:%02d:%02d %+05d (CST)", wdays[p->tm_wday], p->tm_mday, months[p->tm_mon], p->tm_year + 1900, p->tm_hour, p->tm_min, p->tm_sec, offset); #else snprintf(buf, size, "%s, %02d %s %04d %02d:%02d:%02d %+05d (CST)", wdays[p->tm_wday], p->tm_mday, months[p->tm_mon], p->tm_year + 1900, p->tm_hour, p->tm_min, p->tm_sec, offset); #endif } const std::list<rfc822_addr*>& rfc822::parse_addrs(const char* in) { reset(); if (in == NULL || *in == 0) { logger_error("input invalid"); return (addrs_); } TOK822 *tree = tok822_parse(in); if (tree == NULL) { logger_error("tok822_parse(%s) error", in); return (addrs_); } const ACL_VSTRING* comment_prev = NULL; string buf; for (TOK822 *tp = tree; tp; tp = tp->next) { if (tp->type == TOK822_ATOM || tp->type == TOK822_COMMENT || tp->type == TOK822_QSTRING || tp->vstr != NULL) { comment_prev = tp->vstr; } if (tp->type != TOK822_ADDR || tp->head == NULL) continue; ACL_VSTRING* addrp = acl_vstring_alloc(32); (void) tok822_internalize(addrp, tp->head, TOK822_STR_DEFL); rfc822_addr* addr = (rfc822_addr*) acl_mymalloc(sizeof(rfc822_addr)); addr->addr = acl_vstring_export(addrp); if (comment_prev) { buf.clear(); rfc2047::decode(STR(comment_prev), LEN(comment_prev), &buf, "gb18030"); addr->comment = acl_mystrdup(buf.c_str()); comment_prev = NULL; } else addr->comment = NULL; addrs_.push_back(addr); } tok822_free_tree(tree); return (addrs_); } const rfc822_addr* rfc822::parse_addr(const char* in) { const std::list<rfc822_addr*> addr_list = parse_addrs(in); if (addr_list.empty()) return (NULL); std::list<rfc822_addr*>::const_iterator cit = addr_list.begin(); acl_assert(cit != addr_list.end()); return (*cit); } bool rfc822::check_addr(const char* in) { #define VALID1(x) (((x) >= '0' && (x) <= '9') \ || ((x) >= 'a' && (x) <= 'z') \ || ((x) >= 'A' && (x) <= 'Z')) #define VALID2(x) (((x) >= '0' && (x) <= '9') \ || ((x) >= 'a' && (x) <= 'z') \ || ((x) >= 'A' && (x) <= 'Z') \ || (x) == '-' \ || (x) == '_' \ || (x) == '.') while (*in == ' ' || *in == '\t') in++; if (*in == ';' || *in == ',') return false; const rfc822_addr* addr = parse_addr(in); if (addr == NULL || addr->addr == NULL) return false; const char* at = addr->addr; //printf(">>%s, %s\r\n", addr->comment ? addr->comment : "null", addr->addr); if (!VALID1(*at)) return false; at++; while (*at) { if (*at == '@') { // 必须保证 @ 前一个字符的有效性遵守 VALID1 if (!VALID1(*(at - 1))) return false; break; } if (!VALID2(*at)) return false; at++; } if (*at != '@') return false; at++; int dot = 0; bool first = true; while (*at) { if (first) { // at: [a-z]|[A-Z]|[0-9] if (!VALID1(*at)) return false; first = false; } else if (*at == '.') { dot++; first = true; } else if (!VALID2(*at)) return false; at++; } if (!VALID1(*(at - 1)) || dot == 0) return false; return true; } void rfc822::reset() { std::list<rfc822_addr*>::iterator it = addrs_.begin(); for (; it != addrs_.end(); ++it) { acl_myfree((*it)->addr); if ((*it)->comment) acl_myfree((*it)->comment); acl_myfree(*it); } addrs_.clear(); } } // namespace acl