/* NeoStats - IRC Statistical Services 
** Copyright (c) 1999-2004 Adam Rutter, Justin Hammond
** http://www.neostats.net/
**
**  Portions Copyright (c) 2000-2001 ^Enigma^
**
**  Portions Copyright (c) 1999 Johnathan George net@lite.net
**
**  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307
**  USA
**
** NeoStats CVS Identification
** $Id: services.c 1800 2004-05-28 09:38:31Z Fish $
*/

#include "stats.h"
#include "dl.h"
#include "log.h"
#include "sock.h"
#include "ns_help.h"
#include "users.h"
#include "server.h"
#include "chans.h"
#include "ircd.h"
#include "hash.h"
#include "exclude.h"
#include "bans.h"

static int ns_set_debug (User * u, char **av, int ac);
static int ns_shutdown (User * u, char **av, int ac);
static int ns_reload (User * u, char **av, int ac);
static int ns_logs (User * u, char **av, int ac);
static int ns_jupe (User * u, char **av, int ac);
static int ns_exclude (User * u, char **av, int ac);
#ifdef USE_RAW
static int ns_raw (User * u, char **av, int ac);
#endif
static int ns_userdump (User * u, char **av, int ac);
static int ns_serverdump (User * u, char **av, int ac);
static int ns_bandump(User * u, char **av, int ac);
static int ns_chandump (User * u, char **av, int ac);
static int ns_status (User * u, char **av, int ac);
static int ns_version (User * u, char **av, int ac);
static int ns_level (User * u, char **av, int ac);
static int ns_load (User * u, char **av, int ac);
static int ns_unload (User * u, char **av, int ac);

static char quitmsg[BUFSIZE];
static char no_reason[]="no reason given";

static bot_cmd ns_commands[]=
{
	{"LEVEL",		ns_level,		0, 	0,					ns_help_level, 		ns_help_level_oneline},
	{"STATUS",		ns_status,		0, 	0,					ns_help_status, 	ns_help_status_oneline},
	{"VERSION",		ns_version,		0, 	0,					ns_help_version, 	ns_help_version_oneline},
	{"SHUTDOWN",	ns_shutdown,	0, 	NS_ULEVEL_ADMIN, 	ns_help_shutdown, 	ns_help_shutdown_oneline},
	{"RELOAD",		ns_reload,		0, 	NS_ULEVEL_ADMIN, 	ns_help_reload,		ns_help_reload_oneline},
	{"LOGS",		ns_logs,		0, 	NS_ULEVEL_OPER, 	ns_help_logs,		ns_help_logs_oneline},
	{"MODLIST",		list_modules,	0, 	NS_ULEVEL_ADMIN,  	ns_help_modlist, 	ns_help_modlist_oneline},
	{"LOAD",		ns_load,		1, 	NS_ULEVEL_ADMIN, 	ns_help_load, 		ns_help_load_oneline},
	{"UNLOAD",		ns_unload,		1,	NS_ULEVEL_ADMIN, 	ns_help_unload, 	ns_help_unload_oneline},
	{"JUPE",		ns_jupe,		1, 	NS_ULEVEL_ADMIN, 	ns_help_jupe,		ns_help_jupe_oneline},
	{"EXCLUDE",		ns_exclude,		0,	NS_ULEVEL_ADMIN,	ns_help_exclude,	ns_help_exclude_oneline},
#ifdef USE_RAW																
	{"RAW",			ns_raw,			0, 	NS_ULEVEL_ADMIN, 	ns_help_raw, 		ns_help_raw_oneline},
#endif																	
	{"DEBUG",		ns_set_debug,	1, 	NS_ULEVEL_ROOT,  	ns_help_debug,		ns_help_debug_oneline},
	{"BOTLIST",		list_bots,		0, 	NS_ULEVEL_ROOT,  	ns_help_botlist,	ns_help_botlist_oneline},
	{"SOCKLIST",	list_sockets,	0, 	NS_ULEVEL_ROOT,  	ns_help_socklist, 	ns_help_socklist_oneline},
	{"TIMERLIST",	list_timers,	0, 	NS_ULEVEL_ROOT,  	ns_help_timerlist, 	ns_help_timerlist_oneline},
	{"BOTCHANLIST",	list_bot_chans,	0, 	NS_ULEVEL_ROOT,  	ns_help_botchanlist,ns_help_botchanlist_oneline},
	{"USERDUMP",	ns_userdump,	0, 	NS_ULEVEL_ROOT,  	ns_help_userdump, 	ns_help_userdump_oneline},
	{"CHANDUMP",	ns_chandump,	0, 	NS_ULEVEL_ROOT,  	ns_help_chandump, 	ns_help_chandump_oneline},
	{"SERVERDUMP",	ns_serverdump,	0, 	NS_ULEVEL_ROOT,  	ns_help_serverdump, ns_help_serverdump_oneline},
	{"BANDUMP",	ns_bandump, 	0,	NS_ULEVEL_ROOT,		ns_help_bandump, ns_help_bandump_oneline},
	{NULL,			NULL,			0, 	0,					NULL, 				NULL}
};

/** @brief init services
 *
 *  Setup command list for main services bot
 *   
 *  @param none
 *  @returns NS_SUCCESS or NS_FAILURE
 */ 
int  
init_services(void) 
{
	ModUser* bot_ptr;

	SET_SEGV_LOCATION();
	/* Add command list to services bot */
	bot_ptr = add_neostats_mod_user (s_Services);
	bot_ptr->flags = me.onlyopers ? BOT_FLAG_ONLY_OPERS : 0;
	bot_ptr->flags |= BOT_FLAG_DEAF;
	add_bot_cmd_list(bot_ptr, ns_commands);
	return NS_SUCCESS;
}

/** @brief EXCLUDE command handler
 *
 *  maintain global exclusion list, which modules can take advantage off
 *   
 *  @param u user
 *  @param av list of arguments
 *  @param ac number of arguments
 *  @returns none
 */

static int
ns_exclude (User *u, char **av, int ac) 
{
	if (ac < 3) {
		prefmsg(u->nick, s_Services, "Invalid Syntax. /msg %s help exclude", s_Services);
		return NS_FAILURE;
	}
	if (!ircstrcasecmp(av[2], "ADD")) {
		if (ac < 5) {
			prefmsg(u->nick, s_Services, "Invalid Syntax. /msg %s help exclude", s_Services);
			return NS_FAILURE;
		}
		ns_do_exclude_add(u, av[3], av[4]);
	} else if (!ircstrcasecmp(av[2], "DEL")) {
		if (ac < 4) {
			prefmsg(u->nick, s_Services, "Invalid Syntax. /msg %s help exclude", s_Services);
			return NS_FAILURE;
		}
		ns_do_exclude_del(u, av[3]);
	} else if (!ircstrcasecmp(av[2], "LIST")) {
		ns_do_exclude_list(u, s_Services);
	} else {
		prefmsg(u->nick, s_Services, "Invalid Syntax. /msg %s help exclude", s_Services);
	}
	return 1;
}
/** @brief SHUTDOWN command handler
 *
 *  Shutdown NeoStats
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_shutdown (User * u, char **av, int ac)
{
	char *tmp;

	SET_SEGV_LOCATION();
	if (ac <= 2) {
		ircsnprintf (quitmsg, BUFSIZE, "%s [%s](%s) requested SHUTDOWN for %s.", 
			u->nick, u->username, u->hostname, no_reason);
	} else {
		tmp = joinbuf (av, ac, 2);
		chanalert (s_Services, "%s Wants me to SHUTDOWN for %s", u->nick, tmp);
		ircsnprintf (quitmsg, BUFSIZE, "%s [%s](%s) requested SHUTDOWN for %s.", 
			u->nick, u->username, u->hostname, tmp);
		free (tmp);
	}
	globops (s_Services, "%s", quitmsg);
	nlog (LOG_NOTICE, LOG_CORE, "%s", quitmsg);
	do_exit (NS_EXIT_NORMAL, quitmsg);
   	return 1;
}

/** @brief RELOAD command handler
 *
 *  Reload NeoStats
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_reload (User * u, char **av, int ac)
{
	char *tmp;

	SET_SEGV_LOCATION();
	if (ac <= 2) {
		prefmsg (u->nick, s_Services, "You must supply a Reason to Reload");
		return 0;
	}
	tmp = joinbuf (av, ac, 2);
	chanalert (s_Services, "%s Wants me to RELOAD! for %s", u->nick, tmp);
	ircsnprintf (quitmsg, BUFSIZE, "%s [%s](%s) requested RELOAD for %s.", 
		u->nick, u->username, u->hostname, tmp);
	free (tmp);
	globops (s_Services, "%s", quitmsg);
	nlog (LOG_NOTICE, LOG_CORE, "%s", quitmsg);
	do_exit (NS_EXIT_RELOAD, quitmsg);
   	return 1;
}

/** @brief LOGS command handler
 *
 *  Send logs to nick
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_logs (User * u, char **av, int ac)
{
#ifdef DEBUG
	prefmsg (u->nick, s_Services, "This command is disabled while in DEBUG.");
#else
	FILE *fp;
	char buf[BUFSIZE];

	SET_SEGV_LOCATION();
	fp = fopen ("logs/NeoStats.log", "r");
	if (!fp) {
		prefmsg (u->nick, s_Services, "Unable to open neostats.log");
		return 1;
	}
	while (fgets (buf, BUFSIZE, fp)) {
		buf[strlen (buf)] = '\0';
		prefmsg (u->nick, s_Services, buf);
	}
	fclose (fp);
#endif
   	return 1;
}

/** @brief JUPE command handler
 *
 *  Jupiter a server
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_jupe (User * u, char **av, int ac)
{
	char infoline[255];

	SET_SEGV_LOCATION();
	ircsnprintf (infoline, 255, "[Jupitered by %s]", u->nick);
	sserver_cmd (av[2], 1, infoline);
	nlog (LOG_NOTICE, LOG_CORE, "%s!%s@%s jupitered %s", u->nick, u->username, u->hostname, av[2]);
	chanalert (s_Services, "%s Wants to JUPE this Server %s", u->nick, av[2]);
	prefmsg(u->nick, s_Services, "%s has been Jupitered", av[2]);
   	return 1;
}

/** @brief DEBUG command handler
 *
 *  Set debug mode on/off 
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_set_debug (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if ((!ircstrcasecmp(av[2], "YES")) || (!ircstrcasecmp(av[2], "ON"))) {
		me.debug_mode = 1;
		globops (me.name, "\2DEBUG MODE\2 Activated by %s", u->nick);
		prefmsg (u->nick, s_Services, "Debuging Mode Enabled!");
	} else if ((!ircstrcasecmp(av[2], "NO")) || (!ircstrcasecmp(av[2], "OFF"))) {
		me.debug_mode = 0;
		globops (me.name, "\2DEBUG MODE\2 Deactivated by %s", u->nick);
		prefmsg (u->nick, s_Services, "Debuging Mode Disabled");
	} else {
		prefmsg(u->nick, s_Services,
			"Syntax Error: /msg %s HELP DEBUG for more info",
			s_Services);
		   	return 0;
	}
   	return 1;
}

/** @brief USERDUMP command handler
 *
 *  Dump user list
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_userdump (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if (!me.debug_mode) {
		prefmsg (u->nick, s_Services, "\2Error:\2 Debug Mode Disabled");
	   	return 0;
	}
	if(ac < 3) {
		chanalert (s_Services, "\2DEBUG\2 \2%s\2 Requested a UserDump!", u->nick);
		UserDump (NULL);
	} else {
		chanalert (s_Services, "\2DEBUG\2 \2%s\2 Requested a UserDump for %s!", u->nick, av[2]);
		UserDump (av[2]);
	}
   	return 1;
}

/** @brief SERVERDUMP command handler
 *
 *  Dump server list
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_serverdump (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if (!me.debug_mode) {
		prefmsg (u->nick, s_Services, "\2Error:\2 Debug Mode Disabled");
	   	return 0;
	}
	if(ac < 3) {
		chanalert (s_Services, "\2DEBUG\2 \2%s\2 Requested a ServerDump!", u->nick);
		ServerDump (NULL);
	} else {
		chanalert (s_Services, "\2DEBUG\2 \2%s\2 Requested a ServerDump for %s!", u->nick, av[2]);
		ServerDump (av[2]);
	}
   	return 1;
}

/** @brief BANDUMP command handler
 *
 *  Dump ban list
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_bandump (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if (!me.debug_mode) {
		prefmsg (u->nick, s_Services, "\2Error:\2 Debug Mode Disabled");
	   	return 0;
	}
	chanalert (s_Services, "\2DEBUG\2 \2%s\2 Requested a BanDump!", u->nick);
	BanDump();
   	return 1;
}

/** @brief CHANDUMP command handler
 *
 *  Dump channel list
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_chandump (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if (!me.debug_mode) {
		prefmsg (u->nick, s_Services, "\2Error:\2 Debug Mode Disabled");
	   	return 0;
	}
	if(ac < 3) {
		chanalert (s_Services, "\2DEBUG\2 \2%s\2 Requested a ChannelDump!", u->nick);
		ChanDump (NULL);
	} else {
		chanalert (s_Services, "\2DEBUG\2 \2%s\2 Requested a ChannelDump for %s!", u->nick, av[2]);
		ChanDump (av[2]);
	}
   	return 1;
}

/** @brief STATUS command handler
 *
 *  Display NeoStats status
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int 
ns_status (User * u, char **av, int ac)
{
	int uptime = me.now - me.t_start;

	SET_SEGV_LOCATION();
	prefmsg (u->nick, s_Services, "%s Status:", s_Services);
	if (uptime > 86400) {
		prefmsg (u->nick, s_Services, "%s up \2%d\2 day%s, \2%02d:%02d\2", s_Services, uptime / 86400, (uptime / 86400 == 1) ? "" : "s", (uptime / 3600) % 24, (uptime / 60) % 60);
	} else if (uptime > 3600) {
		prefmsg (u->nick, s_Services, "%s up \2%d hour%s, %d minute%s\2", s_Services, uptime / 3600, uptime / 3600 == 1 ? "" : "s", (uptime / 60) % 60, (uptime / 60) % 60 == 1 ? "" : "s");
	} else if (uptime > 60) {
		prefmsg (u->nick, s_Services, "%s up \2%d minute%s, %d second%s\2", s_Services, uptime / 60, uptime / 60 == 1 ? "" : "s", uptime % 60, uptime % 60 == 1 ? "" : "s");
	} else {
		prefmsg (u->nick, s_Services, "%s up \2%d second%s\2", s_Services, uptime, uptime == 1 ? "" : "s");
	}
	prefmsg (u->nick, s_Services, "Sent %ld Messages Totaling %ld Bytes", me.SendM, me.SendBytes);
	prefmsg (u->nick, s_Services, "Received %ld Messages, Totaling %ld Bytes", me.RcveM, me.RcveBytes);
	prefmsg (u->nick, s_Services, "Reconnect Time: %d", me.r_time);
	prefmsg (u->nick, s_Services, "Statistic Requests: %d", me.requests);
	prefmsg (u->nick, s_Services, "Max Sockets: %d (in use: %d)", me.maxsocks, me.cursocks);
	if (me.debug_mode)
		prefmsg (u->nick, s_Services, "Debugging Mode is \2ON!\2");
	else
		prefmsg (u->nick, s_Services, "Debugging Mode is Disabled!");
	return 0;
}

/** @brief VERSION command handler
 *
 *  NeoStats Version
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int
ns_version (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	prefmsg (u->nick, s_Services, "\2NeoStats Version\2");
	prefmsg (u->nick, s_Services, "NeoStats Version: %s", me.versionfull);
	prefmsg (u->nick, s_Services, "http://www.neostats.net");
   	return 1;
}

/** @brief LEVEL command handler
 *
 *  Display user level
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int 
ns_level (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if(ac > 2) {
		User * otheruser;
		otheruser = finduser(av[2]);
		if(otheruser) {
			prefmsg (u->nick, s_Services, "User Level for %s is %d", otheruser->nick, UserLevel (otheruser));
		}
	} else {
		prefmsg (u->nick, s_Services, "Your Level is %d", UserLevel (u));
	}
	return 1;
}

/** @brief LOAD command handler
 *
 *  Load module
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int 
ns_load (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if (load_module (av[2], u) == NS_SUCCESS) {
		chanalert (s_Services, "%s Loaded Module %s", u->nick, av[2]);
	} else {
		chanalert (s_Services, "%s Tried to Load Module %s, but Failed", u->nick, av[2]);
	}
   	return 1;
}

/** @brief UNLOAD command handler
 *
 *  Unload module
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
static int 
ns_unload (User * u, char **av, int ac)
{
	SET_SEGV_LOCATION();
	if (unload_module (av[2], u) > 0) {
		chanalert (s_Services, "%s Unloaded Module %s", u->nick, av[2]);
	}
   	return 1;
}

/** @brief RAW command handler
 *
 *  issue a RAW command
 *   
 *  @param user
 *  @param list of arguments
 *  @param number of arguments
 *  @returns none
 */
#ifdef USE_RAW
static int
ns_raw (User * u, char **av, int ac)
{
	char *message;

	SET_SEGV_LOCATION();
	message = joinbuf (av, ac, 2);
	chanalert (s_Services, "\2RAW COMMAND\2 \2%s\2 Issued a Raw Command!(%s)", u->nick, message);
	nlog (LOG_INFO, LOG_CORE, "RAW COMMAND %sIssued a Raw Command!(%s)", u->nick, message);
	send_cmd ("%s", message);
	free (message);
   	return 1;
}
#endif
