/*
 * =================================================================
 * Filename:      m_huh.c
 * =================================================================

 * =================================================================
 * Author:        Hurricane
 * Email:         fogelsan37766@msn.com
 * =================================================================
 * Feedback:
 *
 * I accept bugreports, ideas and opinions, and if you have any
 * questions, just send an email to me!
 *
 * Thank you for using my module!
 *
 * =================================================================
 * Requirements:
 * =================================================================
 *
 * o Unreal >=3.2-beta18
 * o One of the supported operating systems (see unreal32docs.html)
 *
 * =================================================================
 * Installation:
 * =================================================================
 *
 * put this file in src/modules dir
 * compile by typing make custommodule MODULEFILE=m_huh
 *
 * =================================================================
 * Usage:
 * =================================================================
 *
 * Command huh:
 * --------------
 *
 * Syntax: /huh [+|-]<nickname>
 *
 * Examples:
 *
 * - To make someone confused:
 *       /huh SomeNick
 * - To remove the previous setting from someone:
 *       /huh -SomeNick
 *
 * =================================================================
 */

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif

extern void		sendto_one(aClient *to, char *pattern, ...);
extern void		sendto_realops(char *pattern, ...);

#define MyMod		Modhuh->handle
#define MSG_huh	"huh"
#define TOK_huh	"HU"
#define IsParam(x)      (parc > (x) && !BadPtr(parv[(x)]))
#define IsNotParam(x)   (parc <= (x) || BadPtr(parv[(x)]))
#define DelHook(x)	if (x) HookDel(x); x = NULL
#define DelCommand(x)	if (x) CommandDel(x); x = NULL

static Command		*AddCommand(char *msg, char *token, iFP func);
static int		m_huh(aClient *, aClient *, int, char *[]);
static char		*cb_privmsg(aClient *, aClient *, aClient *, char *, int);
static char		*cb_chanmsg(aClient *, aClient *, aChannel *, char *, int);
static int		cb_quit(aClient *, char *);
static void		free_huhflags();

static ModuleInfo	*Modhuh;
static Command		*Cmdhuh;
static Hook		*HookPrivMsg, *HookChanMsg, *HookQuit;

/*
 * Unoccupied flags are not trustable, they may become used anytime.
 * Therefore I use a separate list.
 */

typedef struct _huhflag huhFlag;

struct _huhflag
{
	huhFlag	*prev, *next;
	aClient		*cptr;
};

static huhFlag *huhFlags;

ModuleHeader MOD_HEADER(m_huh)
  = {
	"m_huh",
	"$Id: m_huh.c,v 1.4 2004/02/23 17:37:34 angrywolf Exp $",
	"Command /huh",
	"3.2-b8-1",
	NULL 
    };

DLLFUNC int MOD_TEST(m_huh)(ModuleInfo *modinfo)
{
	Modhuh = modinfo;

	return MOD_SUCCESS;
}

DLLFUNC int MOD_INIT(m_huh)(ModuleInfo *modinfo)
{
	Modhuh	= modinfo;
	huhFlags	= NULL;

	if (!(Cmdhuh = AddCommand(MSG_huh, TOK_huh, m_huh)))
		return MOD_FAILED;

	return MOD_SUCCESS;
}

DLLFUNC int MOD_LOAD(m_huh)(int module_load)
{
	HookPrivMsg	= HookAddPCharEx(MyMod, HOOKTYPE_USERMSG, cb_privmsg);
	HookChanMsg	= HookAddPCharEx(MyMod, HOOKTYPE_CHANMSG, cb_chanmsg);
        HookQuit	= HookAddEx(MyMod, HOOKTYPE_LOCAL_QUIT, cb_quit);

	return MOD_SUCCESS;
}

DLLFUNC int MOD_UNLOAD(m_huh)(int module_unload)
{
	free_huhflags();

	DelHook(HookQuit);
	DelHook(HookChanMsg);
	DelHook(HookPrivMsg);
	DelCommand(Cmdhuh);

	return MOD_SUCCESS;
}

static Command *AddCommand(char *msg, char *token, iFP func)
{
	Command *cmd;

	if (CommandExists(msg))
    	{
		config_error("Command %s already exists", msg);
		return NULL;
    	}
    	if (CommandExists(token))
	{
		config_error("Token %s already exists", token);
		return NULL;
    	}

	cmd = CommandAdd(MyMod, msg, token, func, MAXPARA, 0);

#ifndef _WIN32
	if (ModuleGetError(MyMod) != MODERR_NOERROR || !cmd)
#else
	if (!cmd)
#endif
	{
#ifndef _WIN32
		config_error("Error adding command %s: %s", msg,
			ModuleGetErrorStr(MyMod));
#else
		config_error("Error adding command %s", msg);
#endif
		return NULL; /* just to be sure */
	}

	return cmd;
}

static huhFlag *find_huh(aClient *cptr)
{
	huhFlag *e;

	for (e = huhFlags; e; e = e->next)
		if (e->cptr == cptr)
			break;

	return e;
}

static void set_huh(aClient *cptr)
{
	huhFlag *e;

	e = (huhFlag *) MyMalloc(sizeof(cptr));
	e->cptr = cptr;
	AddListItem(e, huhFlags);
}

static void clear_huh(huhFlag *e)
{
	DelListItem(e, huhFlags);
	free(e);
}

static void free_huhflags()
{
	huhFlag	*e;
	ListStruct	*next;

	for (e = huhFlags; e; e = (huhFlag *) next)
	{
		next = (ListStruct *) e->next;
		DelListItem(e, huhFlags);
		free(e);
	}
}

static char *convert_to_huh(char *str)
{
	char *p;

	for (p = str; *p; p++)
		switch(*p)
		{
			case 'a':
			case 'b':
                        case 'c':
			case 'd':
                        case 'e':
			case 'f':
                        case 'g':
			case 'h':
                        case 'i':
			case 'j':
                        case 'k':
			case 'l':
                        case 'm':
			case 'n':
                        case 'o':
			case 'p':
                        case 'q':
			case 'r':
                        case 's':
			case 't':
                        case 'u':
			case 'v':
                        case 'w':
			case 'x':
                        case 'y':
			case 'z':
				*p = '?';
				break;
			case 'A':
			case 'B':
                        case 'C':
			case 'D':
                        case 'E':
			case 'F':
                        case 'G':
			case 'H':
                        case 'I':
			case 'J':
                        case 'K':
			case 'L':
                        case 'M':
			case 'N':
                        case 'O':
			case 'P':
                        case 'Q':
			case 'R':
                        case 'S':
			case 'T':
                        case 'U':
			case 'V':
                        case 'W':
			case 'X':
                        case 'Y':
			case 'Z':
				*p = '?';
		}

	return str;
}

static int cb_quit(aClient *sptr, char *comment)
{
	huhFlag *e;

	if ((e = find_huh(sptr)))
		clear_huh(e);

	return 0;
}

static char *cb_privmsg(aClient *cptr, aClient *from, aClient *to, char *str, int notice)
{
	return find_huh(cptr) ? convert_to_huh(str) : str;
}

static char *cb_chanmsg(aClient *cptr, aClient *from, aChannel *to, char *str, int notice)
{
	return find_huh(cptr) ? convert_to_huh(str) : str;
}

static int m_huh(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	aClient		*acptr		= NULL;
	huhFlag	*is_huh	= NULL;
	char		*nick		= NULL;
	int		add		= 1;

	if (IsPerson(sptr) && !IsAnOper(sptr))
	{
    		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
            		parv[0]);
                return -1;
	}

	nick = IsParam(1) ? parv[1] : NULL;

	if (nick)
	{
		if (*nick == '+')
			nick++;
		else if (*nick == '-')
		{
			nick++;
			add = 0;
		}
		if (!*nick)
			nick = NULL;
	}

        if (!nick)
	{
	        if (!IsServer(sptr))
	    		sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
				me.name, sptr->name, MSG_huh);
		return -1;
	}

	acptr = find_person(nick, NULL);

	if (!acptr)
	{
		if (!IsServer(sptr))
	    		sendto_one(sptr, err_str(ERR_NOSUCHNICK),
				me.name, sptr->name, nick);
	        return 0;
	}

	if (!MyConnect(acptr))
	{
		sendto_one(acptr->from, ":%s %s %c%s",
			sptr->name, IsToken(cptr) ? TOK_huh : MSG_huh,
			add ? '+' : '-', acptr->name);
		return 0;
	}

	is_huh = find_huh(acptr);

	if (add)
	{
		if (is_huh)
		{
			if (!IsServer(sptr))
				sendto_one(sptr,
					":%s %s %s :*** %s is already confused",
					me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE",
					sptr->name, acptr->name);
			return 0;
		}

		set_huh(acptr);

		sendto_realops("*** %s added a confusion on %s!%s@%s ",
			sptr->name, acptr->name, acptr->user->username,
			GetHost(acptr));
		sendto_serv_butone(&me,
            		":%s SMO o :*** %s added a confusion on %s!%s@%s ",
			me.name, sptr->name, acptr->name, acptr->user->username,
			GetHost(acptr));

				if (MyConnect(sptr) && acptr != sptr)
			sendto_one(sptr,
				":%s %s %s :*** %s is now huhd",
				me.name, IsWebTV(acptr) ? "PRIVMSG" : "NOTICE",
				sptr->name, acptr->name);
	}
	else
	{
		if (!is_huh)
		{
			if (!IsServer(sptr))
				sendto_one(sptr,
					":%s %s %s :*** %s is not confused",
					me.name, IsWebTV(sptr) ? "PRIVMSG" : "NOTICE",
					sptr->name, acptr->name);
			return 0;
		}

		clear_huh(is_huh);

		sendto_realops("*** %s made %s!%s@%s no longer confused",
			sptr->name, acptr->name,
			acptr->user->username, GetHost(acptr));
		sendto_serv_butone(&me,
            		":%s SMO o :*** %s made %s!%s@%s no longer confused",
			me.name, sptr->name, acptr->name,
			acptr->user->username, GetHost(acptr));

				if (MyConnect(sptr) && acptr != sptr)
			sendto_one(sptr,
				":%s %s %s :*** %s is no longer huhd",
				me.name, IsWebTV(acptr) ? "PRIVMSG" : "NOTICE",
				sptr->name, acptr->name);
	}

	return 0;
}
