inline void casefoldRange(char* dest, const char* begin, const char* end) { if (end - begin < 64) { // short string, don't bother optimizing for (const char* i = begin; i != end; ++i) *dest++ = casefold(*i); } else { // Shift 'A'..'Z' range ([65..90]) to [102..127] to use one signed comparison insn __m128i shiftAmount = _mm_set1_epi8(127 - 'Z'); __m128i lowerBound = _mm_set1_epi8(127 - ('Z' - 'A') - 1); __m128i upperBit = _mm_set1_epi8(0x20); const char* i = begin; for (; i + 16 < end; i += 16) { __m128i v = _mm_loadu_si128(reinterpret_cast<const __m128i*>(i)); __m128i upperMask = _mm_cmpgt_epi8(_mm_add_epi8(v, shiftAmount), lowerBound); __m128i cfv = _mm_or_si128(v, _mm_and_si128(upperMask, upperBit)); _mm_storeu_si128(reinterpret_cast<__m128i*>(dest), cfv); dest += 16; } for (; i != end; ++i) *dest++ = casefold(*i); } }
NgramString ngramExtract(const std::string& string) { NgramString result; for (size_t i = 3; i < string.length(); ++i) { char a = string[i - 3], b = string[i - 2], c = string[i - 1], d = string[i]; unsigned int n = ngram(casefold(a), casefold(b), casefold(c), casefold(d)); result.push_back(n); } return result; }
int been_here_check_fixed(BH_TABLE *dup_filter, const char *string) { VSTRING *folded_string; const char *lookup_key; int status; /* * Special processing: case insensitive lookup. */ if (dup_filter->flags & BH_FLAG_FOLD) { folded_string = vstring_alloc(100); lookup_key = casefold(folded_string, string); } else { folded_string = 0; lookup_key = string; } /* * Do the duplicate check. */ status = (htable_locate(dup_filter->table, lookup_key) != 0); if (msg_verbose) msg_info("been_here_check: %s: %d", string, status); /* * Cleanup. */ if (folded_string) vstring_free(folded_string); return (status); }
char *fold_addr(VSTRING *result, const char *addr, int flags) { char *cp; /* * Fold the address as appropriate. */ switch (flags & FOLD_ADDR_ALL) { case FOLD_ADDR_HOST: if ((cp = strrchr(addr, '@')) != 0) { cp += 1; vstring_strncpy(result, addr, cp - addr); casefold_append(result, cp); break; } /* FALLTHROUGH */ case 0: vstring_strcpy(result, addr); break; case FOLD_ADDR_USER: if ((cp = strrchr(addr, '@')) != 0) { casefold_len(result, addr, cp - addr); vstring_strcat(result, cp); break; } /* FALLTHROUGH */ case FOLD_ADDR_USER | FOLD_ADDR_HOST: casefold(result, addr); break; } return (STR(result)); }
static void *resolve_pagein(const char *addr, void *unused_context) { static VSTRING *query; RESOLVE_REPLY *reply; char *tmp; /* * Initialize on the fly. */ if (query == 0) query = vstring_alloc(10); /* * Initialize. */ reply = (RESOLVE_REPLY *) mymalloc(sizeof(*reply)); resolve_clnt_init(reply); /* * Resolve the address. */ rewrite_clnt_internal(MAIL_ATTR_RWR_LOCAL, addr, query); resolve_clnt_query(STR(query), reply); tmp = mystrdup(STR(reply->recipient)); casefold(reply->recipient, tmp); /* XXX */ myfree(tmp); /* * Save the result. */ return ((void *) reply); }
int deliver_recipient(LOCAL_STATE state, USER_ATTR usr_attr) { const char *myname = "deliver_recipient"; VSTRING *folded; int rcpt_stat; /* * Make verbose logging easier to understand. */ state.level++; if (msg_verbose) MSG_LOG_STATE(myname, state); /* * Set up the recipient-specific attributes. The recipient's lookup * handle is the full address. */ if (state.msg_attr.delivered == 0) state.msg_attr.delivered = state.msg_attr.rcpt.address; folded = vstring_alloc(100); state.msg_attr.user = casefold(folded, state.msg_attr.rcpt.address); /* * Deliver */ if (msg_verbose) deliver_attr_dump(&state.msg_attr); if (deliver_mailbox(state, usr_attr, &rcpt_stat) == 0) rcpt_stat = deliver_unknown(state); /* * Cleanup. */ vstring_free(folded); return (rcpt_stat); }
static bool transformRegexCasefold(const char* pattern, std::string& res, bool literal) { res.clear(); // Simple lexer intended to separate literals from non-literals; does not handle Unicode character classes // properly, so bail out if we have them for (const char* p = pattern; *p; ++p) { if (*p == '\\' && !literal) { if (p[1] == 'p' || p[1] == 'P') return false; res.push_back(*p); p++; res.push_back(*p); } else { res.push_back(casefold(*p)); } } return true; }
static int fnmatch_internal(const char *pat, size_t m, const char *str, size_t n, int flags) { const char *p, *ptail, *endpat; const char *s, *stail, *endstr; size_t pinc, sinc, tailcnt=0; int c, k, kfold; if (flags & FNM_PERIOD) { if (*str == '.' && *pat != '.') return FNM_NOMATCH; } for (;;) { switch ((c = pat_next(pat, m, &pinc, flags))) { case UNMATCHABLE: return FNM_NOMATCH; case STAR: pat++; m--; break; default: k = str_next(str, n, &sinc); if (k <= 0) return (c==END) ? 0 : FNM_NOMATCH; str += sinc; n -= sinc; kfold = flags & FNM_CASEFOLD ? casefold(k) : k; if (c == BRACKET) { if (!match_bracket(pat, k, kfold)) return FNM_NOMATCH; } else if (c != QUESTION && k != c && kfold != c) { return FNM_NOMATCH; } pat+=pinc; m-=pinc; continue; } break; } /* Compute real pat length if it was initially unknown/-1 */ m = strnlen(pat, m); endpat = pat + m; /* Find the last * in pat and count chars needed after it */ for (p=ptail=pat; p<endpat; p+=pinc) { switch (pat_next(p, endpat-p, &pinc, flags)) { case UNMATCHABLE: return FNM_NOMATCH; case STAR: tailcnt=0; ptail = p+1; break; default: tailcnt++; break; } } /* Past this point we need not check for UNMATCHABLE in pat, * because all of pat has already been parsed once. */ /* Compute real str length if it was initially unknown/-1 */ n = strnlen(str, n); endstr = str + n; if (n < tailcnt) return FNM_NOMATCH; /* Find the final tailcnt chars of str, accounting for UTF-8. * On illegal sequences we may get it wrong, but in that case * we necessarily have a matching failure anyway. */ for (s=endstr; s>str && tailcnt; tailcnt--) { if (s[-1] < 128U || MB_CUR_MAX==1) s--; else while ((unsigned char)*--s-0x80U<0x40 && s>str); } if (tailcnt) return FNM_NOMATCH; stail = s; /* Check that the pat and str tails match */ p = ptail; for (;;) { c = pat_next(p, endpat-p, &pinc, flags); p += pinc; if ((k = str_next(s, endstr-s, &sinc)) <= 0) { if (c != END) return FNM_NOMATCH; break; } s += sinc; kfold = flags & FNM_CASEFOLD ? casefold(k) : k; if (c == BRACKET) { if (!match_bracket(p-pinc, k, kfold)) return FNM_NOMATCH; } else if (c != QUESTION && k != c && kfold != c) { return FNM_NOMATCH; } } /* We're all done with the tails now, so throw them out */ endstr = stail; endpat = ptail; /* Match pattern components until there are none left */ while (pat<endpat) { p = pat; s = str; for (;;) { c = pat_next(p, endpat-p, &pinc, flags); p += pinc; /* Encountering * completes/commits a component */ if (c == STAR) { pat = p; str = s; break; } k = str_next(s, endstr-s, &sinc); if (!k) return FNM_NOMATCH; kfold = flags & FNM_CASEFOLD ? casefold(k) : k; if (c == BRACKET) { if (!match_bracket(p-pinc, k, kfold)) break; } else if (c != QUESTION && k != c && kfold != c) { break; } s += sinc; } if (c == STAR) continue; /* If we failed, advance str, by 1 char if it's a valid * char, or past all invalid bytes otherwise. */ k = str_next(str, endstr-str, &sinc); if (k > 0) str += sinc; else for (str++; str_next(str, endstr-str, &sinc)<0; str++); } return 0; }
inline void casefoldRange(char* dest, const char* begin, const char* end) { for (const char* i = begin; i != end; ++i) *dest++ = casefold(*i); }
static int forward_send(FORWARD_INFO *info, DELIVER_REQUEST *request, DELIVER_ATTR attr, char *delivered) { const char *myname = "forward_send"; VSTRING *buffer = vstring_alloc(100); VSTRING *folded; int status; int rec_type = 0; /* * Start the message content segment. Prepend our Delivered-To: header to * the message data. Stop at the first error. XXX Rely on the front-end * services to enforce record size limits. */ rec_fputs(info->cleanup, REC_TYPE_MESG, ""); vstring_strcpy(buffer, delivered); rec_fprintf(info->cleanup, REC_TYPE_NORM, "Received: by %s (%s)", var_myhostname, var_mail_name); rec_fprintf(info->cleanup, REC_TYPE_NORM, "\tid %s; %s", info->queue_id, mail_date(info->posting_time.tv_sec)); if (local_deliver_hdr_mask & DELIVER_HDR_FWD) { folded = vstring_alloc(100); rec_fprintf(info->cleanup, REC_TYPE_NORM, "Delivered-To: %s", casefold(folded, (STR(buffer)))); vstring_free(folded); } if ((status = vstream_ferror(info->cleanup)) == 0) if (vstream_fseek(attr.fp, attr.offset, SEEK_SET) < 0) msg_fatal("%s: seek queue file %s: %m:", myname, VSTREAM_PATH(attr.fp)); while (status == 0 && (rec_type = rec_get(attr.fp, buffer, 0)) > 0) { if (rec_type != REC_TYPE_CONT && rec_type != REC_TYPE_NORM) break; status = (REC_PUT_BUF(info->cleanup, rec_type, buffer) != rec_type); } if (status == 0 && rec_type != REC_TYPE_XTRA) { msg_warn("%s: bad record type: %d in message content", info->queue_id, rec_type); status |= mark_corrupt(attr.fp); } /* * Send the end-of-data marker only when there were no errors. */ if (status == 0) { rec_fputs(info->cleanup, REC_TYPE_XTRA, ""); rec_fputs(info->cleanup, REC_TYPE_END, ""); } /* * Retrieve the cleanup service completion status only if there are no * problems. */ if (status == 0) if (vstream_fflush(info->cleanup) || attr_scan(info->cleanup, ATTR_FLAG_MISSING, RECV_ATTR_INT(MAIL_ATTR_STATUS, &status), ATTR_TYPE_END) != 1) status = 1; /* * Log successful forwarding. * * XXX DSN alias and .forward expansion already report SUCCESS, so don't do * it again here. */ if (status == 0) { attr.rcpt.dsn_notify = (attr.rcpt.dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER : attr.rcpt.dsn_notify & ~DSN_NOTIFY_SUCCESS); dsb_update(attr.why, "2.0.0", "relayed", DSB_SKIP_RMTA, DSB_SKIP_REPLY, "forwarded as %s", info->queue_id); status = sent(BOUNCE_FLAGS(request), SENT_ATTR(attr)); } /* * Cleanup. */ vstring_free(buffer); return (status); }