/*
 * =================================================================
 * Filename:            m_objects.c
 * =================================================================
 * Description:		Designed to prints out lists of several
 *                      Unreal3.2 module objects. Currently supported
 *                      commands:
 *			/events -> Show events
 *			/hooks [<pointer address>] -> Show hooks
 *			/modules -> Show module names & flags
 * =================================================================
 * Author:		AngryWolf
 * Email:		angrywolf@flashmail.com
 * =================================================================
 * Feedback:
 *
 * I accept bugreports, ideas and opinions, and if you have any
 * questions, just send an email for me!
 *
 * Thank you for using my module!
 *
 * =================================================================
 * Requirements:
 * =================================================================
 *
 * o Unreal >=3.2-beta18
 * o One of the supported operating systems (see unreal32docs.html)
 *
 * =================================================================
 * Installation:
 * =================================================================
 *
 * See http://angrywolf.linktipp.org/compiling.php?lang=en
 *
 * =================================================================
 * Mirror files:
 * =================================================================
 *
 * http://angrywolf.linktipp.org/m_objects.c [Germany]
 * http://angrywolf.uw.hu/m_objects.c [Hungary]
 * http://angrywolf.fw.hu/m_objects.c [Hungary]
 *
 * =================================================================
 * Changes:
 * =================================================================
 *
 * $Log: m_objects.c,v $
 * Revision 1.3  2003/11/01 20:52:34  angrywolf
 * - Doc updates.
 *
 * Revision 1.2  2003/11/01 20:25:09  angrywolf
 * - Added command /modules (to print out flags of modules)
 *
 * Revision 1.1  2003/10/21 19:57:24  angrywolf
 * Initial revision
 *
 * =================================================================
 */

#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		EventStatus(aClient *);
extern Module		*Modules;

#define ADD_COMMAND(msg, tok, func) \
	if (CommandExists(msg)) \
	{ \
		config_error("Command " msg " already exists"); \
		ret = MOD_FAILED; \
	} \
	else if (CommandExists(tok)) \
	{ \
		config_error("Token " tok " already exists"); \
		ret = MOD_FAILED; \
	} \
	else \
		add_Command(msg, tok, func, MAXPARA);

#define DEL_COMMAND(msg, tok, func) \
	if (del_Command(msg, tok, func) < 0) \
	{ \
		sendto_realops("Failed to delete command " msg " when unloading %s", \
			MOD_HEADER(m_objects).name); \
		ret = MOD_FAILED; \
	}

#define MSG_EVENTS	"EVENTS"
#define TOK_EVENTS	"EV"
#define MSG_HOOKS	"HOOKS"
#define TOK_HOOKS	"HO"
#define MSG_MODULES	"MODULES"
#define TOK_MODULES	"MO"

DLLFUNC int		m_events(aClient *, aClient *, int, char *[]);
DLLFUNC int		m_hooks(aClient *, aClient *, int, char *[]);
DLLFUNC int		m_modules(aClient *, aClient *, int, char *[]);

ModuleHeader MOD_HEADER(m_objects)
  = {
	"m_objects",
	"$Id: m_objects.c,v 1.3 2003/11/01 20:52:34 angrywolf Exp $",
	"Objects dumper (commands /events, /hooks & /modules)",
	"3.2-b8-1",
	NULL 
    };

DLLFUNC int MOD_TEST(m_objects)(ModuleInfo *modinfo)
{
	return MOD_SUCCESS;
}

DLLFUNC int MOD_INIT(m_objects)(ModuleInfo *modinfo)
{
	int ret = MOD_SUCCESS;

	ADD_COMMAND(MSG_EVENTS, TOK_EVENTS, m_events)
	ADD_COMMAND(MSG_HOOKS, TOK_HOOKS, m_hooks)
	ADD_COMMAND(MSG_MODULES, TOK_MODULES, m_modules)

	return ret;
}

DLLFUNC int MOD_LOAD(m_objects)(int module_load)
{
	return MOD_SUCCESS;
}

DLLFUNC int MOD_UNLOAD(m_objects)(int module_unload)
{
	int ret = MOD_SUCCESS;

	DEL_COMMAND(MSG_EVENTS, TOK_EVENTS, m_events)
	DEL_COMMAND(MSG_HOOKS, TOK_HOOKS, m_hooks)
	DEL_COMMAND(MSG_MODULES, TOK_MODULES, m_modules)

	return ret;
}

typedef struct _objflag ObjFlag;	/* signed */
typedef struct _objflag_u ObjFlag_u;	/* unsigned */

struct _objflag
{
	char	*name;
	int	type;
};

struct _objflag_u
{
	char	*name;
	u_int	type;
};

ObjFlag hooktypes[] =
{
	{ "LOCAL_QUIT",			HOOKTYPE_LOCAL_QUIT		},
	{ "LOCAL_NICKCHANGE",		HOOKTYPE_LOCAL_NICKCHANGE	},
	{ "LOCAL_CONNECT",		HOOKTYPE_LOCAL_CONNECT		},
	{ "REHASHFLAG",			HOOKTYPE_REHASHFLAG		},
	{ "CONFIGPOSTTEST",		HOOKTYPE_CONFIGPOSTTEST		},
	{ "REHASH",			HOOKTYPE_REHASH			},
	{ "PRE_LOCAL_CONNECT",		HOOKTYPE_PRE_LOCAL_CONNECT	},
	{ "HTTPD_URL",			HOOKTYPE_HTTPD_URL		},
	{ "GUEST",			HOOKTYPE_GUEST			},
	{ "SERVER_CONNECT",		HOOKTYPE_SERVER_CONNECT		},
	{ "SERVER_QUIT",		HOOKTYPE_SERVER_QUIT		},
	{ "STATS",			HOOKTYPE_STATS			},
	{ "LOCAL_JOIN",			HOOKTYPE_LOCAL_JOIN		},
	{ "CONFIGTEST",			HOOKTYPE_CONFIGTEST		},
	{ "CONFIGRUN",			HOOKTYPE_CONFIGRUN		},
	{ "USERMSG",			HOOKTYPE_USERMSG		},
	{ "CHANMSG",			HOOKTYPE_CHANMSG		},
	{ "LOCAL_PART",			HOOKTYPE_LOCAL_PART		},
	{ "LOCAL_KICK",			HOOKTYPE_LOCAL_KICK		},
	{ "LOCAL_CHANMODE",		HOOKTYPE_LOCAL_CHANMODE		},
	{ "LOCAL_TOPIC",		HOOKTYPE_LOCAL_TOPIC		},
	{ "LOCAL_OPER",			HOOKTYPE_LOCAL_OPER		},
	{ "UNKUSER_QUIT",		HOOKTYPE_UNKUSER_QUIT		},
	{ "LOCAL_PASS",			HOOKTYPE_LOCAL_PASS		},
	{ "REMOTE_CONNECT",		HOOKTYPE_REMOTE_CONNECT		},
	{ "REMOTE_QUIT",		HOOKTYPE_REMOTE_QUIT		},
	{ "PRE_LOCAL_JOIN",		HOOKTYPE_PRE_LOCAL_JOIN		},
	{ "PRE_LOCAL_KICK",		HOOKTYPE_PRE_LOCAL_KICK		},
	{ "PRE_LOCAL_TOPIC",		HOOKTYPE_PRE_LOCAL_TOPIC	},
	{ NULL,				0				},
};

ObjFlag_u modflags[] =
{
	{ "NONE",			MODFLAG_NONE			},
	{ "LOADED",			MODFLAG_LOADED			},
	{ "TESTING",			MODFLAG_TESTING			},
	{ "INIT",			MODFLAG_INIT			},
	{ "DELAYED",			MODFLAG_DELAYED			},
	{ NULL,				0				},
};

ObjFlag *find_HookType(int type)
{
	ObjFlag *of;

	for (of = hooktypes; of->name; of++)
		if (of->type == type)
			return of;

	return NULL;
}

ObjFlag_u *find_ModFlag(int type)
{
	ObjFlag_u *of;

	for (of = modflags; of->name; of++)
		if (of->type == type)
			return of;

	return NULL;
}

char *get_modflag_names(short flags)
{
	ObjFlag_u	*of;
	static char	mybuf[BUFSIZE+1];
        int     	found = 0;

	memset(&mybuf, 0, sizeof mybuf);

	for (of = modflags; of->name; of++)
                if (flags & of->type)
                {
                        if (found)
                                strcat(mybuf, ", ");
                        else
                                found = 1;
                        strcat(mybuf, of->name);
                }

        if (!strlen(mybuf))
                strcpy(mybuf, "<None>");

        return mybuf;
}

int m_events(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	if (!MyConnect(sptr) || !IsPerson(sptr))
		return -1;

	if (!IsAdmin(sptr))
	{
    		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
            		parv[0]);
                return 0;
	}

	EventStatus(sptr);

	return 0;
}


int m_hooks(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	ObjFlag		*of;
        Hook		*h;
	u_long		count = 0;
	long		hookaddr = 0;

	if (parc > 1 && !BadPtr(parv[1]))
		hookaddr = atol(parv[1]);

	if (!MyConnect(sptr) || !IsPerson(sptr))
		return -1;

	if (!IsAdmin(sptr))
	{
    		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
            		parv[0]);
                return 0;
	}

	for (of = hooktypes; of->name; of++)
    		for (h = Hooks[of->type]; h; h = h->next)
		{
			if (hookaddr && hookaddr != (long) h)
				continue;
			count++;
			if (h->owner)
            			sendto_one(sptr, ":%s NOTICE %s :*** Hook %s: o/%s a/%ld",
					me.name, sptr->name, of->name, h->owner->header->name, (long) h);
			else
            			sendto_one(sptr, ":%s NOTICE %s :*** Hook %s",
					me.name, sptr->name, of->name);
		}

        if (!count)
                sendto_one(sptr, ":%s NOTICE %s :*** No hooks",
                        me.name, sptr->name);
        else
                sendto_one(sptr, ":%s NOTICE %s :*** %ld hooks",
                        me.name, sptr->name, count);

	return 0;
}

int m_modules(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	Module		*m;
	u_long		count = 0;

	if (!MyConnect(sptr) || !IsPerson(sptr))
		return -1;

	if (!IsAdmin(sptr))
	{
    		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name,
            		parv[0]);
                return 0;
	}

	for (m = Modules; m; m = m->next)
	{
		count++;
            	sendto_one(sptr, ":%s NOTICE %s :*** Module %s: %s",
			me.name, sptr->name,
			m->header ? m->header->name : "<unknown>",
			get_modflag_names(m->flags));
	}

        if (!count)
                sendto_one(sptr, ":%s NOTICE %s :*** No modules",
                        me.name, sptr->name);
        else
                sendto_one(sptr, ":%s NOTICE %s :*** %ld modules",
                        me.name, sptr->name, count);

	return 0;
}
