/*
 * m_handlers.c
 * (C) James Craig 1998, Email: jcraig@mad.scientist.com
 * (C) Christian Magnusson 1999, Email: d1mag@dtek.chalmers.se
 * This program is copyright, and covered by the Gnu Public License.
 * The Q bot.
 */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "settings.h"
#include "bottypes.h"
#include "globals.h"

#define UNKNOWN_OWNER "\02???\02"

void m_parse(char *command, char *a)
{
	dl_command_entry_t *cmd;
	int level;

	sender_au = find_yxx(sender);
	if (!sender_au) {
		log("ERROR: m_parse: Couldn't find sender's yxx code [%s]\n", sender);
		return;
	}
	level = userlevel_u(sender_au);

	cmd = findcommand(command);
	if (!cmd) {
		say_sender_("Unknown command. Type   \"/msg %s showcommands\"", BOT_NAME);
		return;
	}

	if (level >= cmd->level) {
		if (!cmd->func) {
			log("m_parse: func==NULL [%s]\n", command);
			return;
		}
		cmd->func(a);
	} else {
		say_sender("You don't have access to this command.");
		if (level == 0) {
			say_sender_("If you are known by %s type:  \"/msg %s@%s AUTH nickname password\"", BOT_NAME,
				BOT_NAME, VIRTUAL_SERVER_NAME);
			say_sender_("Otherwise introduce yourself with:  \"/msg %s HELLO\"", BOT_NAME);
		}
	}
	return;
}

void print_users_only(void)
{
	int i;
	ListElem *el;
	struct dbaseuser *u;
	i = 0;
	el = GetHead(dbuser_list);
	while (el) {
		u = (struct dbaseuser *) el->data;
		printf("%s\n", u->nick);
		el = GetSucc(el);
	}
}

void print_channel_few(void)
{
}

void print_channel_unused(void)
{
	int i;
	ListElem *el, *el2;
	struct chanpriv *p;
	struct chanopts *c;
	struct dbaseuser *u;
	struct chanpriv *cp;
	char channel[CHANNELLEN + 1];
	char tmp[100];
	int chan_stat1, chan_stat2, chan_stat3, chan_stat4;
	int no_owner;
	int nr = 0, chan_deleted = 0;
	int chan_deleted_old = 0;
	long from_age = 0L;
	long to_age = 0L;
	time_t tnow;
	char delete_it = 0;

	i = 0;

	from_age = 0L;
	to_age = 40 * 3600 * 24;
	tnow = time(NULL);
	tnow -= to_age;
	to_age = tnow;

	el = GetHead(dbuser_list);
	while (el) {
		u = (struct dbaseuser *) el->data;
		if (from_age && to_age) {
			if (u->last_auth > from_age && u->last_auth < to_age) {
				delete_it = 1;
			}
		} else if (from_age) {
			if (u->last_auth > from_age) {
				delete_it = 1;
			}
		} else if (to_age) {
			if (u->last_auth < to_age) {
				delete_it = 1;
			}
		}
		if (delete_it) {
			nr++;
			delete_it = 0;
			p = u->privs;
			while (p) {
				strncpy(channel, p->channel, CHANNELLEN);
				channel[CHANNELLEN] = '\0';
				u->privs = p->next;
				Free(p);
				p = u->privs;
				/* eventually remove the channel if last user on it */
				if (is_empty_channel(channel)) {
					chan_deleted++;
					sprintf(tmp, "Delete [%s]\n", channel);
					printf(tmp);
					delchannel(channel);
				}
			}

			/* 
			   find the successor here, since it will be deallocated later */
			el2 = GetSucc(el);
			printf("remove [%s]\n", u->nick);
			if (u->h_elem_nick) {
				Remove(u->h_elem_nick);
				FreeElem(u->h_elem_nick);
				u->h_elem_nick = NULL;
			}
			if (u->h_elem_lastyxx) {
				Remove(u->h_elem_lastyxx);	/* this cause coredump ? */
				FreeElem(u->h_elem_lastyxx);
				u->h_elem_lastyxx = NULL;
			}
			if (u->h_elem_userid) {
				Remove(u->h_elem_userid);
				FreeElem(u->h_elem_userid);
				u->h_elem_userid = NULL;
			}
			/* 
			   Last of all... remove it from the list, and the the whole object will be de-allocated. */
			Remove(u->l_elem);
			FreeElem(u->l_elem);
			/* 
			   next object is el2 */
			el = el2;
		} else {
			el = GetSucc(el);
		}
	}

	chan_deleted_old = 0;
	tnow = time(NULL);
	el = GetHead(channel_list);
	while (el) {
		c = (struct chanopts *) el->data;
		el = GetSucc(el);
		if (c->last_joined && ((tnow - 40 * 3600 * 24) > c->last_joined)) {
			printf("Delete [%s] (old)\n", c->channel);
			delchannel(c->channel);
			chan_deleted_old++;
		}
	}

	sprintf(tmp, "%d users deleted. (older than 40 days)", nr);
	printf(tmp);
	printf("\n");
	sprintf(tmp, "%d channels removed (empty)", chan_deleted);
	printf(tmp);
	printf("\n");
	sprintf(tmp, "%d channels removed (old)", chan_deleted_old);
	printf(tmp);
	printf("\n");

	nr = 0;
	chan_stat1 = 0;
	chan_stat2 = 0;
	chan_stat3 = 0;
	chan_stat4 = 0;

	el = GetHead(channel_list);
	while (el) {
		c = (struct chanopts *) el->data;
		c->nr_members = 0;
		c->nr_owners = 0;
		c->nr_masters = 0;
		c->nr_opers = 0;
		c->nr_voice = 0;
		el = GetSucc(el);
	}

	el2 = GetHead(dbuser_list);
	while (el2) {
		cp = ((struct dbaseuser *) el2->data)->privs;
		p = NULL;
		while (cp) {
			c = findchannel(cp->channel);
			if (c) {
				c->nr_members++;
				if (cp->chanlevel & CHAN_OWNER) {
					c->nr_owners++;
				} else if (cp->chanlevel & CHAN_MASTER) {
					c->nr_masters++;
				} else if (cp->chanlevel & CHAN_OPER) {
					c->nr_opers++;
				} else if (cp->chanlevel & CHAN_VOICE) {
					c->nr_voice++;
				}
				p = cp;
				cp = cp->next;
			} else {
				log("Can't find: [%s]\n", cp->channel);
				/* for some reason there could be some ghost channels */
				if (p) {
					printf("del1\n");
					p->next = cp->next;
					Free(cp);
					cp = p->next;
				} else {
					printf("del2\n");
					((struct dbaseuser *) el2->data)->privs = cp->next;
					Free(cp);
					cp = ((struct dbaseuser *) el2->data)->privs;
				}
			}
		}
		el2 = GetSucc(el2);
	}

	no_owner = 0;
	el = GetHead(channel_list);
	while (el) {
		c = (struct chanopts *) el->data;
		u = finduserfromid(c->owner);
		if (!u) {
			no_owner++;
		}
		if (c->nr_owners == 0) {
			sprintf(tmp, "without owner [%s] ", c->channel);
			printf(tmp);
			printf("(%dv %do %dm %dn)", c->nr_voice, c->nr_opers, c->nr_masters, c->nr_owners);
			if (c->nr_masters == 0) {
				sprintf(tmp, "\t(NO MASTER)");
				printf(tmp);
				if (u) {
					sprintf(tmp, "\t(old owner [%s])", u->nick);
					printf(tmp);
					if (userlevelonchan_d(u, c->channel)) {
						sprintf(tmp, "\t(flags)");
						printf(tmp);
					}
				}
			}
			{
				struct tm *tm_;
				char buffer[100];
				tm_ = localtime(&c->last_joined);
				strftime(buffer, 60, "\tLast: %c", tm_);
				printf(buffer);
			}
			printf("\n");
		} else {
			if (c->nr_masters == 0 && c->nr_opers == 0 && c->nr_voice) {
				printf("single  owner [%s]", c->channel);
				{
					struct tm *tm_;
					char buffer[100];
					tm_ = localtime(&c->last_joined);
					strftime(buffer, 60, "\tLast: %c", tm_);
					printf(buffer);
				}
				printf("\n");
			}
		}
		if (c->nr_members <= 1) {
			chan_stat1++;
		} else if (c->nr_members <= 2) {
			chan_stat2++;
		} else if (c->nr_members <= 3) {
			chan_stat3++;
		} else if (c->nr_members <= 4) {
			chan_stat4++;
		}
		el = GetSucc(el);
	}

	sprintf(tmp, "%d channels without primary owner", no_owner);
	printf(tmp);
	printf("\n");
	sprintf(tmp, "%d channels with <=4 users.", chan_stat4);
	printf(tmp);
	printf("\n");
	sprintf(tmp, "%d channels with <=3 users.", chan_stat3);
	printf(tmp);
	printf("\n");
	sprintf(tmp, "%d channels with <=2 users.", chan_stat2);
	printf(tmp);
	printf("\n");
	sprintf(tmp, "%d channels with <=1 users.", chan_stat1);
	printf(tmp);
	printf("\n");
	return;
}






char getword_buffer[BIGBUF + 1];
char *getword(char *a, int *ip)
{
	int j = 0;
	int i = *ip;

	while (a[i] == ' ')
		i++;
	while ((!isspace((int) a[i])) && (a[i]) && (i < BIGBUF)) {
		getword_buffer[j] = a[i];
		i++;
		j++;
	}
	getword_buffer[j] = '\0';
	*ip = i;
	return getword_buffer;
}


#define MAX_PATTERN BIGBUF

#ifdef NEW_MATCH

#include "common.h"

/*
  returns 0 if pattern match the name
  otherwise 1
  BUG: match2() function could return some strange result once in a while???
       therefor I check it with a match() (slower function) as long as we 
       haven't fixed it!
*/
int match_ignore_ctrlchar(char *pattern, char *name)
{
	char tmp[2 * BIGBUF + 1];
	int ret, i, len = 0;
	ret = match2(pattern, name);
	if (ret == 0) {
		/* for some reason match2() doesn't work correct */
		for (i = 0; name[i] && (i < MAX_PATTERN); i++) {
			/* remove all un-printable characters like Ctrl-B I etc.. */
			if (isprint(name[i])) {
				tmp[len++] = name[i];
			}
		}
		tmp[len] = '\0';
		ret = match(pattern, tmp);
		if (ret) {
		        /* the seconed test return something else!!!! */
			log("Warning: match_ignore_ctrlchar() returned strange result [%s] [%s] [%s]\n", pattern,
				name, tmp);
			return ret;
		}
	}
	return ret;
}

#else

/*
  returns 0 if pattern match the name
  otherwise 1
*/
int match_ignore_ctrlchar(char *pattern, char *name)
{
	char tmp[MAX_PATTERN + 1];		/* I'm not sure about size of the input... */
	int i, len = 0;

	for (i = 0; name[i] && (i < MAX_PATTERN); i++) {
		/* remove all un-printable characters like Ctrl-B I etc.. */
		if (isprint(name[i])) {
			tmp[len++] = name[i];
		}
		/* if(i >= MAX_PATTERN) break; */
	}
	tmp[len] = '\0';
	return match(pattern, tmp);
}

#endif

/*
  returns 0 if pattern match the name
  otherwise 1
*/
int match_include_ctrlchar(char *pattern, char *name)
{
	return match(pattern, name);
}
