/* ----------------------------------------------------------------------- *
 *   
 *  nsswitch.c - module to call parser for nsswitch config and store
 *		result into a struct.
 *
 *   Copyright 2006 Ian Kent <raven@themaw.net>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
 *   USA; either version 2 of the License, or (at your option) any later
 *   version.
 *   
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 * ----------------------------------------------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <limits.h>
#include "automount.h"
#include "nsswitch.h"

int set_action(struct nss_action *act, char *status, char *action, int negated)
{
	enum nsswitch_action a;

	if (!strcasecmp(action, "continue"))
		a = NSS_ACTION_CONTINUE;
	else if (!strcasecmp(action, "return"))
		a = NSS_ACTION_RETURN;
	else
		return 0;

	if (!strcasecmp(status, "SUCCESS")) {
		act[NSS_STATUS_SUCCESS].action = a;
		act[NSS_STATUS_SUCCESS].negated = negated;
	} else if (!strcasecmp(status, "NOTFOUND")) {
		act[NSS_STATUS_NOTFOUND].action = a;
		act[NSS_STATUS_NOTFOUND].negated = negated;
	} else if (!strcasecmp(status, "UNAVAIL")) {
		act[NSS_STATUS_UNAVAIL].action = a;
		act[NSS_STATUS_UNAVAIL].negated = negated;
	} else if (!strcasecmp(status, "TRYAGAIN")) {
		act[NSS_STATUS_TRYAGAIN].action = a;
		act[NSS_STATUS_TRYAGAIN].negated = negated;
	} else
		return 0;

	return 1;
}

int check_nss_result(struct nss_source *this, enum nsswitch_status result)
{
	enum nsswitch_status status;
	struct nss_action a;

	/* Check if we have negated actions */
	for (status = 0; status < NSS_STATUS_MAX; status++) {
		a = this->action[status];
		if (a.action == NSS_ACTION_UNKNOWN)
			continue;

		if (a.negated && result != status) {
			if (a.action == NSS_ACTION_RETURN) {
				if (result == NSS_STATUS_SUCCESS)
					return 1;
				else
					return 0;
			}
		}
	}

	a = this->action[result];

	/* Check if we have other actions for this status */
	switch (result) {
	case NSS_STATUS_SUCCESS:
		if (a.action == NSS_ACTION_CONTINUE)
			break;
		return 1;

	case NSS_STATUS_NOTFOUND:
	case NSS_STATUS_UNAVAIL:
	case NSS_STATUS_TRYAGAIN:
		if (a.action == NSS_ACTION_RETURN) {
			return 0;
		}
		break;

	default:
		break;
	}

	return -1;
}

struct nss_source *add_source(struct list_head *head, char *source)
{
	struct nss_source *s;
	char *tmp;
	enum nsswitch_status status;

	s = malloc(sizeof(struct nss_source));
	if (!s)
		return NULL;

	memset(s, 0, sizeof(struct nss_source));
	INIT_LIST_HEAD(&s->list);

	tmp = strdup(source);
	if (!tmp) {
		free(s);
		return NULL;
	}
	s->source = tmp;

	for (status = 0; status < NSS_STATUS_MAX; status++)
		s->action[status].action = NSS_ACTION_UNKNOWN;

	list_add_tail(&s->list, head);

	return s;
}

int free_sources(struct list_head *list)
{
	struct nss_source *this;
	struct list_head *head, *next;

	if (list_empty(list))
		return 0;

	head = list;
	next = list->next;
	while (next != head) {
		this = list_entry(next, struct nss_source, list);
		next = next->next;

		list_del(&this->list);
		if (this->source)
			free(this->source);
		free(this);
	}
	return 1;
}

/*
int main(void)
{
	struct nss_source *this;
	struct list_head list;
	struct list_head *head, *next;
	int status;


	status = nsswitch_parse(&list);
	if (status) {
		printf("error exit from nss_parse\n");
		free_sources(&list);
		exit(1);
	}

	head = &list;
	next = head->next;
	while (next != head) {
		this = list_entry(next, struct nss_source, list);
		next = next->next;

		printf("list->source = %s", this->source);
		for (status = 0; status < NSS_STATUS_MAX; status++) {
			if (this->action[status].action != NSS_ACTION_UNKNOWN)
				printf(" .");
		}
		printf("\n");
	}
	free_sources(&list);

	exit(0);
}
*/
