Example #1
0
File: mail.c Project: avkrotov/fdm
void
mail_free(struct mail *m)
{
	if (m->attach != NULL)
		attach_free(m->attach);
	if (m->tags != NULL)
		strb_destroy(&m->tags);
	ARRAY_FREE(&m->wrapped);
	m->wrapchar = '\0';

	if (m->auxfree != NULL && m->auxdata != NULL)
		m->auxfree(m->auxdata);
}
Example #2
0
/* Check mail against next rule or part of expression. */
int
mail_match(struct mail_ctx *mctx, struct msg *msg, struct msgbuf *msgbuf)
{
	struct account	*a = mctx->account;
	struct mail	*m = mctx->mail;
	struct expritem	*ei;
	struct replstrs	*users;
	int		 should_free, this = -1, error = MAIL_CONTINUE;
	char		 desc[DESCBUFSIZE];

	set_wrapped(m, ' ');

	/* If blocked, check for msgs from parent. */
	if (mctx->msgid != 0) {
		if (msg == NULL || msg->id != mctx->msgid)
			return (MAIL_BLOCKED);
		mctx->msgid = 0;

		if (msg->type != MSG_DONE)
			fatalx("unexpected message");
		if (msgbuf->buf != NULL && msgbuf->len != 0) {
			strb_destroy(&m->tags);
			m->tags = msgbuf->buf;
			reset_tags(&m->tags);
		}

		ei = mctx->expritem;
		switch (msg->data.error) {
		case MATCH_ERROR:
			return (MAIL_ERROR);
		case MATCH_TRUE:
			this = 1;
			break;
		case MATCH_FALSE:
			this = 0;
			break;
		default:
			fatalx("unexpected response");
		}
		apply_result(ei, &mctx->result, this);

		goto next_expritem;
	}

	/* Check for completion and end of ruleset. */
	if (mctx->done)
		return (MAIL_DONE);
	if (mctx->rule == NULL) {
		switch (conf.impl_act) {
		case DECISION_NONE:
			log_warnx("%s: reached end of ruleset. no "
			    "unmatched-mail option; keeping mail",  a->name);
			m->decision = DECISION_KEEP;
			break;
		case DECISION_KEEP:
			log_debug2("%s: reached end of ruleset. keeping mail",
			    a->name);
			m->decision = DECISION_KEEP;
			break;
		case DECISION_DROP:
			log_debug2("%s: reached end of ruleset. dropping mail",
			    a->name);
			m->decision = DECISION_DROP;
			break;
		}
		return (MAIL_DONE);
	}

	/* Expression not started. Start it. */
	if (mctx->expritem == NULL) {
		/* Start the expression. */
		mctx->result = 0;
		mctx->expritem = TAILQ_FIRST(mctx->rule->expr);
	}

	/* Check this expression item and adjust the result. */
	ei = mctx->expritem;

	/* Handle short-circuit evaluation. */
	switch (ei->op) {
	case OP_NONE:
		break;
	case OP_AND:
		/* And and the result is already false. */
		if (!mctx->result)
			goto next_expritem;
		break;
	case OP_OR:
		/* Or and the result is already true. */
		if (mctx->result)
			goto next_expritem;
		break;
	}

	switch (ei->match->match(mctx, ei)) {
	case MATCH_ERROR:
		return (MAIL_ERROR);
	case MATCH_PARENT:
		return (MAIL_BLOCKED);
	case MATCH_TRUE:
		this = 1;
		break;
	case MATCH_FALSE:
		this = 0;
		break;
	default:
		fatalx("unexpected op");
	}
	apply_result(ei, &mctx->result, this);

	ei->match->desc(ei, desc, sizeof desc);
	log_debug3("%s: tried %s, result now %d", a->name, desc, mctx->result);

next_expritem:
	/* Move to the next item. If there is one, then return. */
	mctx->expritem = TAILQ_NEXT(mctx->expritem, entry);
	if (mctx->expritem != NULL)
		return (MAIL_CONTINUE);

	log_debug3("%s: finished rule %u, result %d", a->name, mctx->rule->idx,
	    mctx->result);

	/* If the result was false, skip to find the next rule. */
	if (!mctx->result)
		goto next_rule;
	log_debug2("%s: matched to rule %u", a->name, mctx->rule->idx);

	/*
	 * If this rule is stop, mark the context so when we get back after
	 * delivery we know to stop.
	 */
	if (mctx->rule->stop)
		mctx->done = 1;

	/* Handle nested rules. */
	if (!TAILQ_EMPTY(&mctx->rule->rules)) {
		log_debug2("%s: entering nested rules", a->name);

		/*
		 * Stack the current rule (we are at the end of it so the
		 * the expritem must be NULL already).
		 */
		ARRAY_ADD(&mctx->stack, mctx->rule);

		/* Continue with the first rule of the nested list. */
		mctx->rule = TAILQ_FIRST(&mctx->rule->rules);
		return (MAIL_CONTINUE);
	}
	mctx->matched = 1;

	/* Handle lambda actions. */
	if (mctx->rule->lambda != NULL) {
		users = find_delivery_users(mctx, NULL, &should_free);

		chained = MAXACTIONCHAIN;
		if (fill_from_action(mctx,
		    mctx->rule, mctx->rule->lambda, users) != 0) {
			if (should_free)
				ARRAY_FREEALL(users);
			return (MAIL_ERROR);
		}

		if (should_free)
			ARRAY_FREEALL(users);
		error = MAIL_DELIVER;
	}

	/* Fill the delivery action queue. */
	if (!ARRAY_EMPTY(mctx->rule->actions)) {
		chained = MAXACTIONCHAIN;
		if (fill_from_strings(mctx,
		    mctx->rule, mctx->rule->actions) != 0)
			return (MAIL_ERROR);
		error = MAIL_DELIVER;
	}

next_rule:
	/* Move to the next rule. */
	mctx->ruleidx = mctx->rule->idx;	/* save last index */
	mctx->rule = TAILQ_NEXT(mctx->rule, entry);

	/* If no more rules, try to move up the stack. */
	while (mctx->rule == NULL) {
		if (ARRAY_EMPTY(&mctx->stack))
			break;
		log_debug2("%s: exiting nested rules", a->name);
		mctx->rule = ARRAY_LAST(&mctx->stack);
		mctx->rule = TAILQ_NEXT(mctx->rule, entry);
		ARRAY_TRUNC(&mctx->stack, 1);
	}

	return (error);
}