Beispiel #1
0
static var_t *
exp_not(var_t *v)
{
	var_t *r;
	
	// NULL returns NULL
	if (v == NULL)
	{
		return EXP_EMPTY;
	}
	if (v->v_data == NULL)
	{
		return EXP_EMPTY;
	}

	if (var_true(v))
	{
		r = EXP_FALSE;
	}
	else
	{
		r = EXP_TRUE;
	}

	exp_free(v);

	return r;
}
Beispiel #2
0
/**
 * connector() -- make a node for a connector or dictionary word.
 *
 * Assumes the current token is a connector or dictionary word.
 */
static Exp * connector(Dictionary dict)
{
	Exp * n;
	Dict_node *dn, *dn_head;
	int i;

	i = strlen(dict->token) - 1;  /* this must be + or - if a connector */
	if ((dict->token[i] != '+') && (dict->token[i] != '-'))
	{
		/* If we are here, token is a word */
		dn_head = abridged_lookup_list(dict, dict->token);
		dn = dn_head;
		while ((dn != NULL) && (strcmp(dn->string, dict->token) != 0))
		{
			dn = dn->right;
		}
		if (dn == NULL)
		{
			free_lookup_list(dn_head);
			dict_error(dict, "\nPerhaps missing + or - in a connector.\n"
			                 "Or perhaps you forgot the suffix on a word.\n"
			                 "Or perhaps a word is used before it is defined.\n");
			return NULL;
		}
		n = make_unary_node(dict, dn->exp);
		free_lookup_list(dn_head);
	} 
	else
	{
		/* If we are here, token is a connector */
		if (!check_connector(dict, dict->token))
		{
			return NULL;
		}
		n = Exp_create(dict);
		n->dir = dict->token[i];
		dict->token[i] = '\0';				   /* get rid of the + or - */
		if (dict->token[0] == '@')
		{
			n->u.string = string_set_add(dict->token+1, dict->string_set);
			n->multi = TRUE;
		}
		else
		{
			n->u.string = string_set_add(dict->token, dict->string_set);
			n->multi = FALSE;
		}
		n->type = CONNECTOR_type;
		n->cost = 0.0f;
	}

	if (!link_advance(dict))
	{
		exp_free(n);
		return NULL;
	}
	return n;
}
Beispiel #3
0
static void free_Exp_list(Exp * e)
{
	Exp * e1;
	for (; e != NULL; e = e1)
	{
		e1 = e->next;
		if (e->type != CONNECTOR_type)
		{
		   free_Elist(e->u.l);
		}
		exp_free(e);
	}
}
Beispiel #4
0
var_t *
exp_is_null(var_t *v)
{
	var_t *result = &exp_false;

	if (v == NULL)
	{
		result = &exp_true;
	}
	else if (v->v_data == NULL)
	{
		result = &exp_true;
	}

	exp_free(v);

	return result;
}
Beispiel #5
0
int
exp_is_true(exp_t *exp, var_t *mailspec)
{
	var_t *v;
	int r;

	if (exp == NULL)
	{
		return 1;
	}

	v = exp_eval(exp, mailspec);
	if (v == NULL)
	{
		log_notice("exp_is_true: evaluation failed");
		return -1;
	}

	r = var_true(v);

	exp_free(v);

	return r;
}
Beispiel #6
0
static var_t *
exp_eval_ternary_condition(exp_t *exp, var_t *mailspec)
{
	exp_ternary_condition_t *etc = exp->ex_data;
	var_t *v = NULL;
	int result;

	v = exp_eval(etc->etc_condition, mailspec);
	if (v == NULL)
	{
		log_error("exp_eval_ternary_condition: evaluation failed");
		return NULL;
	}

	result = var_true(v);
	exp_free(v);

	if (result)
	{
		return exp_eval(etc->etc_true, mailspec);
	}

	return exp_eval(etc->etc_false, mailspec);
}
Beispiel #7
0
static var_t *
exp_bool(var_t *mailspec, int op, exp_t *left_exp, exp_t *right_exp)
{
	int known_value, left_known, right_known, result;
	int left_true = 0;
	int right_true = 0;
	var_t *left = NULL;
	var_t *right = NULL;

	if (op != OR && op != AND)
	{
		log_error("exp_bool: bad operation");
		return NULL;
	}

	if (left_exp == NULL || right_exp == NULL)
	{
		log_error("exp_bool: operand is NULL");
		return NULL;
	}

	// Evaluate left operand
	left = exp_eval(left_exp, mailspec);
	if (left == NULL)
	{
		log_error("exp_bool: exp_eval for lefthand operator failed");
		return NULL;
	}

	left_known = left->v_data != NULL;
	if (left_known)
	{
		left_true = var_true(left);
	}
	
	// Short-Circuit Operator (like Perl)
	if (op == OR && left_known && left_true)
	{
		return left;
	}

	exp_free(left);

	// AND operation with left value known and false.
	if (op == AND && left_known && !left_true)
	{
		return &exp_false;
	}

	// Evaluate right operand
	right = exp_eval(right_exp, mailspec);
	if (right == NULL)
	{
		log_error("exp_bool: exp_eval for righthand operator failed");
		return NULL;
	}

	right_known = right->v_data != NULL;
	if (right_known)
	{
		right_true = var_true(right);
	}

	// Short-Circuit Operator (like Perl)
	if (op == OR && !left_true)
	{
		return right;
	}

	exp_free(right);

	// Both sides are unknown
	if (!left_known && !right_known)
	{
		return &exp_empty;
	}

	// One side is unknown
	if (!left_known || !right_known)
	{
		known_value = left_known ? left_true: right_true;

		if (op == AND && !known_value)
		{
			return &exp_false;
		}

		// This case should be handled by the shortcut logic above!
		if (op == OR && known_value)
		{
			log_error("exp_bool: logic error");
			return NULL;
		}

		return &exp_empty;
	}

	// Both sides are known
	if (op == AND)
	{
		result = left_true && right_true;
	}
	else
	{
		result = left_true || right_true;
	}

	if (result)
	{
		return  &exp_true;
	}

	return &exp_false;
}
Beispiel #8
0
static var_t *
exp_eval_function(exp_t *exp, var_t *mailspec)
{
	exp_function_t *ef = exp->ex_data;
	acl_function_t *af;
	var_t *args = NULL;
	ll_t *single = NULL;
	var_t *v = NULL;

	af = acl_function_lookup(ef->ef_name);
	if (af == NULL)
	{
		log_error("exp_eval_function: unknown function \"%s\"",
		    ef->ef_name);
		goto error;
	}

	/*
	 * Function has arguments
	 */
	if (ef->ef_args)
	{
		args = exp_eval(ef->ef_args, mailspec);
		if (args == NULL)
		{
			log_error("exp_eval_function: exp_eval failed");
			goto error;
		}

		/*
		 * Convert single argument into list.
		 */
		if (args->v_type != VT_LIST)
		{
			single = ll_create();
			if (single == NULL)
			{
				log_error("exp_eval_function: ll_create failed");
				goto error;
			}

			if (LL_INSERT(single, args) == -1)
			{
				log_error("exp_eval_function: LL_INSERT failed");
				goto error;
			}
		}
	}
	else
	{
		/*
		 * Function has no arguments -> empty list
		 */
		single = ll_create();
		if (single == NULL)
		{
			log_error("exp_eval_function: ll_create failed");
			goto error;
		}
	}

	if (af->af_type == AF_SIMPLE)
	{
		v = exp_eval_function_simple(ef->ef_name, af,
		    single ? single : args->v_data);
	}
	else
	{
		v = exp_eval_function_complex(ef->ef_name, af,
		    single ? single : args->v_data);
	}

	if (v == NULL)
	{
		log_error("exp_eval_function: function \"%s\" failed",
		    ef->ef_name);
		goto error;
	}

error:
	if (single)
	{
		ll_delete(single, NULL);
	}

	if (args)
	{
		exp_free(args);
	}

	return v;
}
Beispiel #9
0
var_t *
exp_eval_operation(exp_t *exp, var_t *mailspec)
{
	var_t *left = NULL, *right = NULL, *copy;
	exp_operation_t *eo = exp->ex_data;
	var_t *result = NULL;
	var_type_t type;

	/*
	 * Variable assigment
	 */
	if (eo->eo_operator == '=')
	{
		return exp_assign(eo->eo_operand[0], eo->eo_operand[1],
		    mailspec);
	}

	/*
	 * isset operator
	 */
	if (eo->eo_operator == IS_SET)
	{
		return exp_isset(mailspec, eo->eo_operand[0]);
	}

	/*
	 * Do not load unneccessary symbols in boolean operations
	 */
	if (eo->eo_operator == AND || eo->eo_operator == OR)
	{
		result = exp_bool(mailspec, eo->eo_operator, eo->eo_operand[0],
			eo->eo_operand[1]);
		goto exit;
	}

	/*
 	 * Load left operand
 	 */
	left = exp_eval(eo->eo_operand[0], mailspec);

	/*
	 * ! operator
	 */
	if (eo->eo_operator == '!')
	{
		return exp_not(left);
	}

	/*
	 * Hack: IS_NULL operator
	 */
	if (eo->eo_operator == IS_NULL)
	{
		result = exp_is_null(left);
		goto exit;
	}

	/*
 	 * Evaluate right operand
 	 */
	if (eo->eo_operand[1])
	{
		right = exp_eval(eo->eo_operand[1], mailspec);
	}

	switch(eo->eo_operator)
	{
	// Comparator
	case '<':
	case '>':
	case LE:
	case GE:
	case EQ:
	case NE:
		result = exp_compare(eo->eo_operator, left, right);
		goto exit;

	// Regex
	case '~':
	case NR:
		result = exp_eval_regex(eo->eo_operator, left, right);
		goto exit;

	// In
	case IN:
		result = exp_eval_in(left, right);
		goto exit;



	// Address prefix operator
	case '/':
		if (left == NULL || right == NULL)
		{
			break;
		}
		if (!(left->v_type == VT_ADDR && right->v_type == VT_INT))
		{
			break;
		}

		result = exp_addr_prefix(left, right);
		goto exit;

	default:
		break;
	}

	// Math operators need left and right to be set
	if (left == NULL || right ==  NULL)
	{
		result = EXP_EMPTY;
		goto exit;
	}

	// Make sure we work with the same types
	if (left->v_type != right->v_type)
	{
		/*
		 * The biggest type has precedence (see exp.h)
		 * STRING > FLOAT > INT
		 */
		type = VAR_MAX_TYPE(left, right);

		if (type == left->v_type)
		{
			copy = var_cast_copy(type, right);
		}
		else
		{
			copy = var_cast_copy(type, left);
		}

		if (copy == NULL)
		{
			log_error("exp_eval_operation: var_cast_copy "
			    "failed");
			goto exit;
		}

		if (type == left->v_type)
		{
			exp_free(right);
			right = copy;
			right->v_flags |= VF_EXP_FREE;
		}
		else
		{
			exp_free(left);
			left = copy;
			left->v_flags |= VF_EXP_FREE;
		}
	}

	switch (left->v_type)
	{
	case VT_INT:
		result = exp_math_int(eo->eo_operator, left, right);
		break;

	case VT_FLOAT:
		result = exp_math_float(eo->eo_operator, left, right);
		break;

	case VT_STRING:
		result = exp_math_string(eo->eo_operator, left, right);
		break;

	default:
		log_error("exp_eval_operation: bad type");
		goto exit;
	}

exit:
	if (left)
	{
		exp_free(left);
	}

	if (right)
	{
		exp_free(right);
	}

	return result;
}
Beispiel #10
0
acl_action_type_t
msgmod(milter_stage_t stage, char *stagename, var_t *mailspec, void *data,
	int depth)
{
	msgmod_t *mm = data;
	void *ctx;
	acl_action_type_t action = ACL_ERROR;
	var_t **args = NULL;
	int argc;
	int size;
	var_t *v, *copy;
	int i;
	exp_t *exp;
	ll_t *ll;
	ll_entry_t *pos;

	/*
	 * Get milter ctx pointer
	 */
	ctx = vtable_get(mailspec, "milter_ctx");
	if (ctx == NULL)
	{
		log_error("msgmod: ctx not set");
		goto error;
	}

	/*
	 * Evaluate arguments
	 */
	argc = mm->mm_args->ll_size;
	size = (argc + 1) * sizeof (var_t *);

	args = (var_t **) malloc(size);
	if (args == NULL)
	{
		log_sys_error("msgmod: malloc");
		goto error;
	}

	memset(args, 0, size);

	ll = mm->mm_args;
	pos = LL_START(ll);

	for (i = 0; i < argc; ++i)
	{
		exp = ll_next(ll, &pos);
		if (exp == NULL)
		{
			log_die(EX_SOFTWARE, "msgmod: empty argument");
		}

		v = exp_eval(exp, mailspec);
		if (v == NULL)
		{
			log_error("msgmod: exp_eval failed");
			goto error;
		}

		// Cast all aruments to VT_STRING
		if (v->v_type != VT_STRING)
		{
			copy = var_cast_copy(VT_STRING, v);
			if (copy == NULL)
			{
				log_error("msgmod: var_cast_copy failed");
				goto error;
			}

			exp_free(v);

			/*
			 * args are freed using exp_free. Set VF_EXP_FREE to
			 * free copy.
			 */
			copy->v_flags |= VF_EXP_FREE;
			
			v = copy;
		}
		
		args[i] = v;
	}

	if (mm->mm_callback(ctx, argc, args))
	{
		log_error("msgmod: mm_callback failed");
		goto error;
	}

	action = ACL_NONE;

error:

	/*
	 * Free args
	 */
	for (i = 0; args[i]; ++i)
	{
		exp_free(args[i]);
	}

	if (args)
	{
		free(args);
	}

	return action;
}