Пример #1
0
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);
	}
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
0
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));
}
Пример #5
0
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);
}
Пример #6
0
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);
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
inline void casefoldRange(char* dest, const char* begin, const char* end)
{
	for (const char* i = begin; i != end; ++i)
		*dest++ = casefold(*i);
}
Пример #10
0
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);
}