/*
 * Copyright (C) 1995 Lars Fenneberg
 *
 * 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; 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/ip_acct_user.h>
#include "ipquota.h"

struct user_hash_s *hash_table[HASH_TABLE_SIZE];

void init_hash(void)
{
	int i;
	
	for(i = 0; i<HASH_TABLE_SIZE; i++) hash_table[i] = NULL;
}

int exist_user(uid_t uid)
{
        struct user_hash_s *p;

        for(p = hash_table[HASH_FUNC(uid)]; p; p = p->next)
         if (p->uid == uid) break;

	return (p != NULL);
}

struct user_hash_s *add_user(uid_t uid, signed long quota, int flags)
{
	int hashval = HASH_FUNC(uid);
	struct user_hash_s *p;
	
	if ((p = (struct user_hash_s *) malloc(sizeof (struct user_hash_s))) == NULL)
	{
		log(my_perror("add_user"));
		exit(1);
	}
	
	p->uid = uid;
	p->quota = quota;
	p->flags = (quota<=0)?(flags|IPAU_NO_ACCESS):flags;
	p->next	= hash_table[hashval];
	
	hash_table[hashval] = p;

	return p;
}

void ctrl_access(uid_t uid, int flags)
{
	struct ip_acct_user_ctrl_entry ct;

	ct.uid = uid;
	ct.flags = flags;

	if (ioctl(skfd, SIOCCTRLU, &ct) < 0) {
		log(my_perror("SIOCCTRLU"));
		exit(-1);
	}
}

void ctrl_access_all(void)
{
	struct user_hash_s *p;
	int i;
	
	for(i=0; i<HASH_TABLE_SIZE; i++)
	{
		p = hash_table[i];
		while (p)
		{
			ctrl_access(p->uid, p->flags);
			p = p->next;
		}
	}
}

void change_user(uid_t uid, signed long quota, int set)
{
	struct user_hash_s *p;
	
	for(p = hash_table[HASH_FUNC(uid)]; p; p = p->next)
		if (p->uid == uid) break;

	if (p)
	{
		if (!set) p->quota += quota; else p->quota = quota;
		if (p->quota <= 0)
			p->flags |= IPAU_NO_ACCESS;
		else
			p->flags &= ~IPAU_NO_ACCESS;
	}
	/* else user not in accouting file.. maybe add with a default? */
}

void change_all(signed long quota, int set)
{
	struct user_hash_s *p;
	int i;
	
	for(i=0; i<HASH_TABLE_SIZE; i++)
	{
		p = hash_table[i];
		while(p)	
		{
			if (!set) p->quota += quota; else p->quota = quota;
			if (p->quota <= 0)
				p->flags |= IPAU_NO_ACCESS;
			else
				p->flags &= ~IPAU_NO_ACCESS;
			p = p->next;
		}
	}
}
