int rfc822_parse_phrase(struct rfc822_parser_context *ctx, string_t *str) { int ret; /* phrase = 1*word / obs-phrase word = atom / quoted-string obs-phrase = word *(word / "." / CFWS) */ if (ctx->data == ctx->end) return 0; if (*ctx->data == '.') return -1; for (;;) { if (*ctx->data == '"') ret = rfc822_parse_quoted_string(ctx, str); else ret = rfc822_parse_atom_or_dot(ctx, str); if (ret <= 0) return ret; if (!IS_ATEXT(*ctx->data) && *ctx->data != '"' && *ctx->data != '.') break; str_append_c(str, ' '); } return rfc822_skip_lwsp(ctx); }
/* * [RFC2822] * atext = ALPHA / DIGIT / ; Any character except controls, * "!" / "#" / ; SP, and specials. * "$" / "%" / ; Used for atoms * "&" / "'" / * "*" / "+" / * "-" / "/" / * "=" / "?" / * "^" / "_" / * "`" / "{" / * "|" / "}" / * "~" */ int XSkip_atextBlock(const char *head, const char *tail, const char **nextp) { const char *p; for (p = head; p < tail && IS_ATEXT(*p); ++p); *nextp = p; return *nextp - head; } // end function : XSkip_atextBlock
int rfc822_parse_dot_atom(struct rfc822_parser_context *ctx, string_t *str) { const unsigned char *start; int ret; /* dot-atom = [CFWS] dot-atom-text [CFWS] dot-atom-text = 1*atext *("." 1*atext) atext = ; Any character except controls, SP, and specials. For RFC-822 compatibility allow LWSP around '.' */ if (ctx->data == ctx->end || !IS_ATEXT(*ctx->data)) return -1; for (start = ctx->data++; ctx->data != ctx->end; ) { if (IS_ATEXT(*ctx->data)) { ctx->data++; continue; } str_append_n(str, start, ctx->data - start); if ((ret = rfc822_skip_lwsp(ctx)) <= 0) return ret; if (*ctx->data != '.') return 1; ctx->data++; str_append_c(str, '.'); if ((ret = rfc822_skip_lwsp(ctx)) <= 0) return ret; start = ctx->data; } str_append_n(str, start, ctx->data - start); return 0; }
int valid_localpart(const char *s) { #define IS_ATEXT(c) (isalnum((unsigned char)(c)) || strchr(MAILADDR_ALLOWED, (c))) nextatom: if (!IS_ATEXT(*s) || *s == '\0') return 0; while (*(++s) != '\0') { if (*s == '.') break; if (IS_ATEXT(*s)) continue; return 0; } if (*s == '.') { s++; goto nextatom; } return 1; }
int valid_localpart(char *s) { #define IS_ATEXT(c) (isalnum((int)(c)) || strchr("!#$%&'*+-/=?^_`{|}~", (c))) nextatom: if (! IS_ATEXT(*s) || *s == '\0') return 0; while (*(++s) != '\0') { if (*s == '.') break; if (IS_ATEXT(*s)) continue; return 0; } if (*s == '.') { s++; goto nextatom; } return 1; }
int rfc822_parse_atom(struct rfc822_parser_context *ctx, string_t *str) { const unsigned char *start; /* atom = [CFWS] 1*atext [CFWS] atext = ; Any character except controls, SP, and specials. */ if (ctx->data == ctx->end || !IS_ATEXT(*ctx->data)) return -1; for (start = ctx->data++; ctx->data != ctx->end; ctx->data++) { if (IS_ATEXT(*ctx->data)) continue; str_append_n(str, start, ctx->data - start); return rfc822_skip_lwsp(ctx); } str_append_n(str, start, ctx->data - start); return 0; }
int valid_localpart(const char *s) { /* * RFC 5322 defines theses characters as valid: !#$%&'*+-/=?^_`{|}~ * some of them are potentially dangerous, and not so used after all. */ #define IS_ATEXT(c) (isalnum((int)(c)) || strchr("*!%+-/=_", (c))) nextatom: if (! IS_ATEXT(*s) || *s == '\0') return 0; while (*(++s) != '\0') { if (*s == '.') break; if (IS_ATEXT(*s)) continue; return 0; } if (*s == '.') { s++; goto nextatom; } return 1; }
static int rfc822_parse_atom_or_dot(struct rfc822_parser_context *ctx, string_t *str) { const unsigned char *start; /* atom = [CFWS] 1*atext [CFWS] atext = ; Any character except controls, SP, and specials. The difference between this function and rfc822_parse_dot_atom() is that this doesn't just silently skip over all the whitespace. */ for (start = ctx->data; ctx->data != ctx->end; ctx->data++) { if (IS_ATEXT(*ctx->data) || *ctx->data == '.') continue; str_append_n(str, start, ctx->data - start); return rfc822_skip_lwsp(ctx); } str_append_n(str, start, ctx->data - start); return 0; }
static bool DkimWildcard_matchPubkeyGranularityImpl(const char *pattern_head, const char *pattern_tail, const char *target_head, const char *target_tail, bool accept_wildcard) { /* * the ABNF of key-g-tag-lpart says only one wildcard is acceptable. * But '*' itself is included in dot-atom-text. * So this function treats the first occurrence of '*' as wildcard, * and next or later occurrence of '*' as character. * * [RFC4871] 3.6.1. * key-g-tag = %x67 [FWS] "=" [FWS] key-g-tag-lpart * key-g-tag-lpart = [dot-atom-text] ["*" [dot-atom-text] ] */ const char *pattern; const char *target; for (pattern = pattern_head, target = target_head; pattern < pattern_tail; ++pattern, ++target) { if ('*' == *pattern) { if (accept_wildcard) { // treat '*' as wildcard ++pattern; for (const char *bq = target_tail; target <= bq; --bq) { if (DkimWildcard_matchPubkeyGranularityImpl (pattern, pattern_tail, bq, target_tail, false)) { return true; } // end if } // end for return false; } else { // treat '*' as (not wildcard but) character if (target_tail <= target || '*' != *target) { return false; } // end if } // end if } else if (IS_ATEXT(*pattern) || '.' == *pattern) { /* * compare case-sensitively. * * [RFC6376] 3.2. * Values MUST be * processed as case sensitive unless the specific tag description of * semantics specifies case insensitivity. * * And the local-part of mailbox is essentially treated as case-sensitive. * * [RFC5321] 2.4. * ... The * local-part of a mailbox MUST BE treated as case sensitive. */ if (target_tail <= target || *pattern != *target) { return false; } // end if } else { // neither atext nor '.' (included in dot-atom-text) return false; } // end if } // end for return bool_cast(pattern == pattern_tail && target == target_tail); } // end function: DkimWildcard_matchPubkeyGranularityImpl