/*
 * Copyright (c) 2001, 2002, 2003, 2004, 2005  Netli, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $Id: ncnf_vr_constr.c,v 1.1 2005/05/26 12:08:19 vlm Exp $
 */
#include "headers.h"
#include "ncnf_int.h"
#include "ncnf_vr.h"

static void _vr_entity_free(void *);
static void _vr_rule_free(void *);

static int _vr_entity_cmpf(const void *ap, const void *bp);
static int _vr_entity_hashf(const void *ap);

static int
_vr_entity_cmpf(const void *ap, const void *bp) {
	const struct vr_entity *a = ap;
	const struct vr_entity *b = bp;

	if(strcmp(a->type, b->type))
		return -1;

	if(a->name && b->name) {
		if(strcmp(a->name, b->name) == 0)
			return 0;
		else
			return -1;
	}

	if(a->name || b->name)
		return -1;

	return 0;
}

static int
_vr_entity_hashf(const void *ap) {
	const struct vr_entity *a = ap;
	return hashf_string(a->type);
}

static void
_vr_entity_free(void *p) {
	struct vr_entity *e = (struct vr_entity *)p;
	struct vr_rule *rule;

	if(e->type) {
		free(e->type);
		e->type = NULL;
	}
	if(e->name) {
		free(e->name);
		e->name = NULL;
	}

	while(e->rules) {
		rule = e->rules;
		e->rules = rule->next;
		_vr_rule_free(rule);
	}

	free(e);
}

static void
_vr_rule_free(void *p) {
	struct vr_rule *r = (struct vr_rule *)p;
	if(r) {
		if(r->name) {
			free(r->name);
			r->name = NULL;
		}
		if(r->type && r->type->standalone) {
			_vr_destroy_type(r->type);
		}
		free(r);
	}
}

void
_vr_destroy_type(void *p) {
	struct vr_type *ty = (struct vr_type *)p;
	if(ty) {
		if(ty->name) {
			free(ty->name);
			ty->name = NULL;
		}
		if(ty->regex) {
			free(ty->regex);
			ty->regex = NULL;
		}
#ifdef	HAVE_LIBSTRFUNC
		sed_free(ty->regex_compiled);
#endif	/* HAVE_LIBSTRFUNC */
		free(ty);
	}
}

struct vr_entity *
_vr_get_entity(struct vr_config *vc, char *type, char *name, int create) {
	struct vr_entity static_entity;
	struct vr_entity *e;

	if(vc->entities) {
		static_entity.type = type;	
		static_entity.name = name;

		e = genhash_get(vc->entities, &static_entity);
		if(e) return e;

		if(name && create == 0) {
			static_entity.name = NULL;

			e = genhash_get(vc->entities, &static_entity);
			if(e) return e;
		}

		if(create == 0)
			return NULL;
		e = (struct vr_entity *)calloc(1, sizeof(struct vr_entity));
		if(e == NULL)
			return NULL;

		e->type = strdup(type);
		if(e->type == NULL) {
			_vr_entity_free(e);
			return NULL;
		}

		if(name) {
			e->name = strdup(name);
			if(e->name == NULL) {
				_vr_entity_free(e);
				return NULL;
			}
		}

		if(genhash_addunique(vc->entities, e, e)) {
			_vr_entity_free(e);
			return NULL;
		}
	} else {
		if(create == 0)
			return NULL;

		vc->entities = genhash_new(
			_vr_entity_cmpf,
			_vr_entity_hashf,
			NULL,
			_vr_entity_free);
		if(vc->entities)
			return _vr_get_entity(vc, type, name, create);
		else
			return NULL;
	}
	return e;
}

struct vr_type * _vr_new_type(struct vr_config *vc, char *name, char *type, char *value, int line);
struct vr_type *
_vr_new_type(struct vr_config *vc, char *name, char *type, char *value, int line) {
	struct vr_type *ty;

	ty = (struct vr_type *)calloc(1, sizeof(struct vr_type));
	if(ty == NULL)
		return NULL;

	ty->name = strdup(name);
	if(ty->name == NULL) {
		_vr_destroy_type(ty);
		return NULL;
	}


	if(strcmp(type, VR_STR_TYPE) == 0) {
		_vr_destroy_type(ty);
		ty = NULL;
		if(vc->types)
			ty = genhash_get(vc->types, name);
		if(ty == NULL) {
			_ncnf_debug_print(1, "Can't find type \"%s\" for rule at line %d", value, line);
			return NULL;
		} else {
			return ty;
		}
	} else if(strcmp(type, VR_STR_REGEX) == 0) {
#ifdef	HAVE_LIBSTRFUNC
		ty->regex = strdup(value);
		if(ty->regex == NULL) {
			_vr_destroy_type(ty);
			return NULL;
		}
		ty->regex_compiled = sed_compile(value);
		if(ty->regex_compiled == NULL) {
			_ncnf_debug_print(1,
			"Invalid regular expression \"%s\" at line %d",
				value, line);

			_vr_destroy_type(ty);
			return NULL;
		}
#else	/* !HAVE_LIBSTRFUNC */
		_ncnf_debug_print(1, "\"%s\" at line %d not supported: libstrfunc is not compiled in", type, line);
		_vr_destroy_type(ty);
		return NULL;
#endif	/* HAVE_LIBSTRFUNC */
	} else if(strcmp(type, VR_STR_RANGE) == 0) {
		char *p = strchr(value, ':');
		if(p == NULL) {
			_ncnf_debug_print(1, "Range should be specified as min:max at line %d", line);
			_vr_destroy_type(ty);
			return NULL;
		}
		*p++ = '\0';
		ty->range_defined = 1;
		ty->range_start = atof(value);
		ty->range_end = atof(p);
	} else if(strcmp(type, VR_STR_IP) == 0) {
		ty->ip_required = 1;
	} else if(strcmp(type, VR_STR_IP_MASK) == 0) {
#ifdef	HAVE_LIBSTRFUNC
		ty->ip_mask_required = 1;
#else
		_ncnf_debug_print(1, "\"%s\" at line %d not supported: libstrfunc is not compiled in", type, line);
		_vr_destroy_type(ty);
		return NULL;
#endif
	} else if(strcmp(type, VR_STR_IP_MASKLEN) == 0) {
#ifdef	HAVE_LIBSTRFUNC
		ty->ip_masklen_required = 1;
#else
		_ncnf_debug_print(1, "\"%s\" at line %d not supported: libstrfunc is not compiled in", type, line);
		_vr_destroy_type(ty);
		return NULL;
#endif
	} else if(strcmp(type, VR_STR_IP_PORT) == 0) {
		ty->ip_port_required = 1;
	} else {
		_ncnf_debug_print(1, "Unknown type: \"%s\" at line %d", type, line);
		_vr_destroy_type(ty);
		return NULL;
	}

	ty->standalone = 1;

	return ty;
}

struct vr_type *
_vr_add_type(struct vr_config *vc, char *name, char *type, char *value, int line) {
	struct vr_type *ty;

	if(vc->types == NULL) {
		vc->types = genhash_new(
			cmpf_string, hashf_string,
			NULL, _vr_destroy_type);
		if(vc->types == NULL)
			return NULL;
	}

	ty = _vr_new_type(vc, name ? name : value, type, value, line);
	if(ty == NULL)
		return NULL;

	if(name == NULL)
		return ty;

	if(genhash_addunique(vc->types, ty->name, ty)) {
		_vr_destroy_type(ty);
		return NULL;
	} else {
		ty->standalone = 0;
	}

	return ty;
}


int
_vr_add_rule(int line, struct vr_config *vc, struct vr_entity *e,
	char *mo, char *sm, char *ea, char *name, char *a, char *v) {
	struct vr_rule *r, *prev;

	r = (struct vr_rule *)calloc(1, sizeof(struct vr_rule));
	if(r == NULL) {
		_ncnf_debug_print(1, "Memory allocation error");
		return -1;
	}

	/* mandatory | optional */
	if(strcmp(mo, VR_STR_MANDATORY) == 0) {
		r->mandatory = 1;
	} else if(strcmp(mo, VR_STR_OPTIONAL) == 0) {
		r->mandatory = 0;
	} else {
		_ncnf_debug_print(1, "%s or %s token expected at line %d",
			VR_STR_MANDATORY, VR_STR_OPTIONAL, line);
		goto fail;
	}

	/* single | multiple */
	if(strcmp(sm, VR_STR_SINGLE) == 0) {
		r->multiple = 0;
	} else if(strcmp(sm, VR_STR_MULTIPLE) == 0) {
		r->multiple = 1;
	} else {
		_ncnf_debug_print(1, "%s or %s token expected at line %d",
			VR_STR_SINGLE, VR_STR_MULTIPLE, line);
		goto fail;
	}

	/* entity | attribute | ... */
	if(strcmp(ea, VR_STR_ATTRIBUTE) == 0) {
		r->vr_obj_class = VR_CLASS_ATTRIBUTE;
	} else if(strcmp(ea, VR_STR_ENTITY) == 0) {
		r->vr_obj_class = VR_CLASS_ENTITY;
	} else if(strcmp(ea, VR_STR_REFERENCE) == 0) {
		r->vr_obj_class = VR_CLASS_REFERENCE;
	} else if(strcmp(ea, VR_STR_ATTACH) == 0) {
		r->vr_obj_class = VR_CLASS_ATTACHMENT;
	} else {
		_ncnf_debug_print(1, "%s or %s token expected at line %d",
			VR_STR_ENTITY, VR_STR_ATTRIBUTE, line);
		goto fail;
	}

	r->name = strdup(name);
	if(r->name == NULL)
		goto fail;

	if(strcmp(r->name, VR_STR_VALIDATOR_ENTITY) == 0)
		r->_entity_reference = 1;

	if(a) {
		r->type = _vr_add_type(vc, NULL, a, v, line);
		if(r->type == NULL)
			goto fail;
	}

	prev = e->rules;
	while(prev && prev->next)
		prev = prev->next;

	if(prev)
		prev->next = r;
	else
		e->rules = r;

	return 0;
fail:
	_vr_rule_free(r);

	return -1;
}


syntax highlighted by Code2HTML, v. 0.9.1