/*
 * ignore.c: handles the ingore command for irc 
 *
 * Written By Michael Sandrof
 *
 * Copyright(c) 1990 
 *
 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
 */

#if 0
static	char	rcsid[] = "@(#)$Id: ignore.c,v 1.8 1994/07/02 02:32:13 mrg Exp $";
#endif

#include "irc.h"

#include "ignore.h"
#include "ircaux.h"
#include "list.h"
#include "vars.h"
#include "output.h"

#define NUMBER_OF_IGNORE_LEVELS 9

#define IGNORE_REMOVE 1
#define IGNORE_DONT 2
#define IGNORE_HIGH -1

char *highlight_char = NULL;

static	int	remove_ignore _((char *));
static  char *	cut_n_fix_glob _((char *));

/*
 * Ignore: the ignore list structure,  consists of the nickname, and the type
 * of ignorance which is to take place 
 */
typedef struct	IgnoreStru
{
	struct	IgnoreStru *next;
	char	*nick;
	int	type;
	int	dont;
	int	high;
}	Ignore;

/* ignored_nicks: pointer to the head of the ignore list */
static	Ignore *ignored_nicks = NULL;

/*
 * ignore_nickname: adds nick to the ignore list, using type as the type of
 * ignorance to take place.  
 */
#ifdef __STDC__
static void ignore_nickname (char *nick, int type, int flag)
#else
static	void ignore_nickname(nick, type, flag)
char	*nick;
int	type;
int	flag;
#endif
{
	Ignore	*new;
	char	*msg,
		*ptr;
	char 	*new_nick = NULL;
	char	buffer[BIG_BUFFER_SIZE+1];

	while (nick)
	{
		if ((ptr = index(nick, ',')) != NULL)
			*ptr = '\0';
		if (*nick)
		{
			new_nick = (is_channel(nick) ? m_strdup(nick) : cut_n_fix_glob(nick));

			if (!(new = (Ignore *) list_lookup((List **)&ignored_nicks, new_nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)))
			{
				if (flag == IGNORE_REMOVE)
				{
					say("%s is not on the ignorance list", nick);
					if (ptr)
						*(ptr++) = ',';
					nick = ptr;
					continue;
				}
				else
				{
					if ((new = (Ignore *) remove_from_list((List **)&ignored_nicks, new_nick)))
					{
						new_free(&(new->nick));
						new_free((char **)&new);
					}
					new = (Ignore *) new_malloc(sizeof(Ignore));
					new->type = 0;
					new->dont = 0;
					new->high = 0;
					new->nick = new_nick; /* already malloced */
					upper(new->nick);
					add_to_list((List **)&ignored_nicks, (List *)new);
				}
			}
			switch (flag)
			{
				case IGNORE_REMOVE:
					new->type &= (~type);
					new->high &= (~type);
					new->dont &= (~type);
					msg = "Not ignoring";
					break;
				case IGNORE_DONT:
					new->dont |= type;
					new->type &= (~type);
					new->high &= (~type);
					msg = "Never ignoring";
					break;
				case IGNORE_HIGH:
					new->high |= type;
					new->type &= (~type);
					new->dont &= (~type);
					msg = "Highlighting";
					break;
				default:
					new->type |= type;
					new->high &= (~type);
					new->dont &= (~type);
					msg = "Ignoring";
					break;
			}
			if (type == IGNORE_ALL)
			{
				switch (flag)
				{
					case IGNORE_REMOVE:
					    say("%s removed from ignorance list", new->nick);
					    remove_ignore(new->nick);
					    break;
					case IGNORE_HIGH:
					    say("Highlighting ALL messages from %s", new->nick);
					    break;
					case IGNORE_DONT:
					    say("Never ignoring messages from %s", new->nick);
					    break;
					default:
					    say("Ignoring ALL messages from %s", new->nick);
					    break;
				}
				return;
			}
			else if (type)
			{
				strcpy(buffer, msg);
				if (type & IGNORE_MSGS)
					strcat(buffer, " MSGS");
				if (type & IGNORE_PUBLIC)
					strcat(buffer, " PUBLIC");
				if (type & IGNORE_WALLS)
					strcat(buffer, " WALLS");
				if (type & IGNORE_WALLOPS)
					strcat(buffer, " WALLOPS");
				if (type & IGNORE_INVITES)
					strcat(buffer, " INVITES");
				if (type & IGNORE_NOTICES)
					strcat(buffer, " NOTICES");
				if (type & IGNORE_NOTES)
					strcat(buffer, " NOTES");
				if (type & IGNORE_CTCPS)
					strcat(buffer, " CTCPS");
				if (type & IGNORE_CRAP)
					strcat(buffer, " CRAP");
				say("%s from %s", buffer, new->nick);
			}
#if 0
/*
 * Why remove the ignore if the type == 0 or highlight is 0, Only remove
 * if expliclity asked to. (panasync)
 */
			if ((new->type == 0) && (new->high == 0))
				remove_ignore(new->nick);
#endif
		}
		if (ptr)
			*(ptr++) = ',';
		nick = ptr;
	}
}

/*
 * remove_ignore: removes the given nick from the ignore list and returns 0.
 * If the nick wasn't in the ignore list to begin with, 1 is returned. 
 */
#ifdef __STDC__
static int remove_ignore (char *nick)
#else
static	int	remove_ignore(nick)
char	*nick;
#endif
{
	Ignore	*tmp;
	char *new_nick = NULL;

	new_nick = (is_channel(nick) ? m_strdup(nick) : cut_n_fix_glob(nick));

	if ((tmp = (Ignore *) list_lookup((List **)&ignored_nicks, new_nick, !USE_WILDCARDS,
			REMOVE_FROM_LIST)) != NULL)
	{
		new_free(&(tmp->nick));
		new_free((char **)&tmp);
		new_free(&new_nick);
		return (0);
	}
	new_free(&new_nick);
	return (1);
}

/* ignore_list: shows the entired ignorance list */
#ifdef __STDC__
void	ignore_list (char *nick)
#else
void	ignore_list(nick)
char	*nick;
#endif
{
	Ignore	*tmp;
	int	len = 0;
	char buffer[BIG_BUFFER_SIZE + 1];

	if (ignored_nicks)
	{
		say("Ignorance List:");
		if (nick)
		{
			len = strlen(nick);
			upper(nick);
		}
		for (tmp = ignored_nicks; tmp; tmp = tmp->next)
		{
			if (nick)
			{
				if (strncmp(nick, tmp->nick, len))
					continue;
			}
			*buffer = (char) 0;
			if (tmp->type == IGNORE_ALL)
				strmcat(buffer," ALL",BIG_BUFFER_SIZE);
			else if (tmp->high == IGNORE_ALL)
				sprintf(buffer, " %sALL%s", highlight_char, highlight_char);
			else if (tmp->dont == IGNORE_ALL)
				strmcat(buffer," DONT-ALL", BIG_BUFFER_SIZE);
			else
			{

	if (tmp->type & IGNORE_PUBLIC)
		strmcat(buffer, " PUBLIC", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_PUBLIC)
		sprintf(buffer, " %sPUBLIC%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_PUBLIC)
		strmcat(buffer, " DONT-PUBLIC", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_MSGS)
		strmcat(buffer, " MSGS", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_MSGS)
		sprintf(buffer, " %sMSGS%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_MSGS)
		strmcat(buffer, " DONT-MSGS", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_WALLS)
		strmcat(buffer, " WALLS", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_WALLS)
		sprintf(buffer, " %sWALLS%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_WALLS)
		strmcat(buffer, " DONT-WALLS", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_WALLOPS)
		strmcat(buffer, " WALLOPS", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_WALLOPS)
		sprintf(buffer, " %sWALLOPS%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_WALLOPS)
		strmcat(buffer, " DONT-WALLOPS", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_INVITES)
		strmcat(buffer, " INVITES", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_INVITES)
		sprintf(buffer, " %sINVITES%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_INVITES)
		strmcat(buffer, " DONT-INVITES", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_NOTICES)
		strmcat(buffer, " NOTICES", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_NOTICES)
		sprintf(buffer, " %sNOTICES%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_NOTICES)
		strmcat(buffer, " DONT-NOTICES", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_NOTES)
		strmcat(buffer, " NOTES", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_NOTES)
		sprintf(buffer, " %sNOTES%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_NOTES)
		strmcat(buffer, " DONT-NOTES", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_CTCPS)
		strmcat(buffer, " CTCPS", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_CTCPS)
		sprintf(buffer, " %sCTCPS%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_CTCPS)
		strmcat(buffer, " DONT-CTCPS", BIG_BUFFER_SIZE);

	if (tmp->type & IGNORE_CRAP)
		strmcat(buffer, " CRAP", BIG_BUFFER_SIZE);
	else if (tmp->high & IGNORE_CRAP)
		sprintf(buffer, " %sCRAP%s", highlight_char, highlight_char);
	else if (tmp->dont & IGNORE_CRAP)
		strmcat(buffer, " DONT-CRAP", BIG_BUFFER_SIZE);

			}
			say("\t%s:\t%s", tmp->nick, buffer);
		}
	}
	else
		say("There are no nicknames being ignored");
}

/*
 * ignore: does the /IGNORE command.  Figures out what type of ignoring the
 * user wants to do and calls the proper ignorance command to do it. 
 */
#ifdef __STDC__
void	ignore (char *command, char *args, char *subargs)
#else
void	ignore(command, args, subargs)
char	*command,
	*args;
char	*subargs;
#endif
{
	char	*nick,
		*type;
	int	len;
	int	flag,
		no_flags;
	char	nick_buffer[127];

	if ((nick = next_arg(args, &args)) != NULL)
	{
		strcpy(nick_buffer, nick);
		no_flags = 1;

		while ((type = next_arg(args, &args)) != NULL)
		{
			nick = nick_buffer;

			no_flags = 0;
			upper(type);
			switch (*type)
			{
				case '!':
				case '^':
					flag = IGNORE_DONT;
					type++;
					break;
				case '-':
					flag = IGNORE_REMOVE;
					type++;
					break;
				case '+':
					flag = IGNORE_HIGH;
					type++;
					break;
				default:
					flag = 0;
					break;
			}
			if ((len = strlen(type)) == 0)
			{
				say("You must specify one of the following:");
				say("\tALL MSGS PUBLIC WALLS WALLOPS INVITES NOTICES NOTES NONE");
				return;
			}
			if (strncmp(type, "ALL", len) == 0)
				ignore_nickname(nick, IGNORE_ALL, flag);
			else if (strncmp(type, "MSGS", len) == 0)
				ignore_nickname(nick, IGNORE_MSGS, flag);
			else if (strncmp(type, "PUBLIC", len) == 0)
				ignore_nickname(nick, IGNORE_PUBLIC, flag);
			else if (strncmp(type, "WALLS", len) == 0)
				ignore_nickname(nick, IGNORE_WALLS, flag);
			else if (strncmp(type, "WALLOPS", len) == 0)
				ignore_nickname(nick, IGNORE_WALLOPS, flag);
			else if (strncmp(type, "INVITES", len) == 0)
				ignore_nickname(nick, IGNORE_INVITES, flag);
			else if (strncmp(type, "NOTICES", len) == 0)
				ignore_nickname(nick, IGNORE_NOTICES, flag);
			else if (strncmp(type, "NOTES", len) == 0)
				ignore_nickname(nick, IGNORE_NOTES, flag);
			else if (strncmp(type, "CTCPS", len) == 0)
				ignore_nickname(nick, IGNORE_CTCPS, flag);
			else if (strncmp(type, "CRAP", len) == 0)
				ignore_nickname(nick, IGNORE_CRAP, flag);
			else if (strncmp(type, "NONE", len) == 0)
			{
				char	*ptr;

				while (nick)
				{
					if ((ptr = index(nick, ',')) != NULL)
						*ptr = (char) 0;
					if (*nick)
					{
						char *new_nick = cut_n_fix_glob(nick);
						char *stupid_new_nick_copy = m_strdup(new_nick);
						if (remove_ignore(new_nick))
							say("%s is not in the ignorance list!", stupid_new_nick_copy);
						else
							say("%s removed from ignorance list", stupid_new_nick_copy);
						new_free(&new_nick);
					}
					if (ptr)
						*(ptr++) = ',';
					nick = ptr;
				}
			}
			else
			{
				say("You must specify one of the following:");
				say("\tALL MSGS PUBLIC WALLS WALLOPS INVITES NOTICES NOTES CTCPS CRAP NONE");
			}
		}
		if (no_flags)
			ignore_list(nick);
	} else
		ignore_list((char *) 0);
}

/*
 * set_highlight_char: what the name says..  the character to use
 * for highlighting..  either BOLD, INVERSE, or UNDERLINE..
 *
 * This does *not* belong here.
 */
#ifdef __STDC__
void	set_highlight_char (char *s)
#else
void	set_highlight_char(s)
char	*s;
#endif
{
	int	len;

	len = strlen(s);

	if (!my_strnicmp(s, "BOLD", len))
		malloc_strcpy(&highlight_char, BOLD_TOG_STR);
	else if (!my_strnicmp(s, "INVERSE", len))
		malloc_strcpy(&highlight_char, REV_TOG_STR);
	else if (!my_strnicmp(s, "UNDERLINE", len))
		malloc_strcpy(&highlight_char, UND_TOG_STR);
	else
		malloc_strcpy(&highlight_char, s);
}

/* 
 * check_ignore -- replaces the old double_ignore
 *   Why did i change the name?
 *      * double_ignore isnt really applicable any more becuase it doesnt
 *        do two ignore lookups, it only does one.
 *      * This function doesnt look anything like the old double_ignore
 *      * This function works for the new *!*@* patterns stored by
 *        ignore instead of the old nick and userhost patterns.
 * (jfn may 1995)
 */
#ifdef __STDC__
int	check_ignore (char *nick, char *userhost, int type)
#else
int	check_ignore(nick, userhost, type)
char	*nick,
	*userhost;
int	type;
#endif
{
	return check_ignore_channel(nick, userhost, NULL, type);
}

/*
 * "check_ignore_channel" is kind of a bad name for this function, but
 * i was not inspired with a better name.  This function is simply the
 * old 'check_ignore', only it has an additional check for a channel target.
 */
#ifdef __STDC__
int	check_ignore_channel (char *nick, char *userhost, char *channel, int type)
#else
int	check_ignore_channel (nick, userhost, channel, type)
char	*nick,
	*userhost,
	*channel;
int	type;
#endif
{
	char *nickuserhost = (char *) 0;
	Ignore	*tmp;

	malloc_strcpy(&nickuserhost, nick ? nick : "*");
	malloc_strcat(&nickuserhost, "!");
	malloc_strcat(&nickuserhost, userhost ? userhost : "*");

	if (ignored_nicks)
	{
		if ((tmp = (Ignore *) list_lookup((List **)&ignored_nicks, nickuserhost,
				USE_WILDCARDS, !REMOVE_FROM_LIST)) != NULL)
		{
			new_free(&nickuserhost); /* so i did forget to free
							this! >;-) */
			if (tmp->dont & type)
				return(DONT_IGNORE);
			if (tmp->type & type)
				return (IGNORED);
			if (tmp->high & type)
				return (HIGHLIGHTED);
		}
		new_free(&nickuserhost);
		if (channel && is_channel(channel) &&
			(tmp = (Ignore *)list_lookup((List **)&ignored_nicks, channel,
				USE_WILDCARDS, !REMOVE_FROM_LIST)) != NULL)
		{
			if (tmp->dont & type)
				return(DONT_IGNORE);
			if (tmp->type & type)
				return (IGNORED);
			if (tmp->high & type)
				return (HIGHLIGHTED);
		}
	}
	new_free(&nickuserhost);
	return (DONT_IGNORE);
}

/* Written by hop in April 1995 -- taken from SIRP */
/* MALLOCED */
#ifdef __STDC__
static char *cut_n_fix_glob ( char *nickuserhost )
#else
static char *cut_n_fix_glob (nickuserhost)
char *nickuserhost;
#endif
{
	char *nick, *userhost = (char *) 0,
	     *user = (char *) 0, *host = (char *) 0;
	char *final_stuff;
	char	*copy = NULL;
	
	/* Dont bother with channels, theyre ok. */
	if (*nickuserhost == '#' || *nickuserhost == '&')
		return m_strdup(nickuserhost);

	/* patch by texaco makes this work right */
	copy = m_strdup(nickuserhost);
	nick = copy;

	if ((userhost = index(copy, '!')))
	{
		/* NICK IS CORRECT HERE */

		*userhost++ = 0;

		/* doh! */
		user = userhost;

		if ((host = sindex(userhost, "@")))
			/* USER IS CORRECT HERE */
			*host++ = 0;

		else if (sindex(userhost, "."))
		{
			user = "*";
			host = userhost;
		}
		/* fixed by sheik */
		if (!user)
			user = "*";
		if (!host)
			host = "*";
	}
	else
	{
		user = copy;
		if ((host = sindex(user, "@")))
		{
			nick = "*";
			*host++ = 0;
		}
		else
		{
			if (sindex(user, "."))
			{
				nick = "*";
				host = user;
				user = "*";
			}
			else
			{
				nick = user;
				user = "*";
				host = "*";
			}
		}
	}

	final_stuff = (char *)new_malloc(strlen(nick) + strlen(user) + strlen(host) + 3);
	strcpy(final_stuff, nick);
	strcat(final_stuff, "!");
	strcat(final_stuff, user);
	strcat(final_stuff, "@");
	strcat(final_stuff, host);
	new_free(&copy);
	return final_stuff;
}

