/* Shared routines

   OperStats - Copyright (c) 2000-2003 Darcy Grexton
   Contact: skold@habber.net, skold @ HabberNet

   See doc/LICENSE for licensing details.
 */

#include "../inc/operstats.h"

/* Authenticate for SRA access. */
void do_auth (User *u)
{
    char *whoami = authserv ();
    char *nick = strtok (NULL, " ");
    char *pass = strtok (NULL, " ");
    SRA *sra;
         
    if (!nick || !pass)
    {
	notice (whoami, u->nick, RPL_SYNTAX, "AUTH NickName Password");
	errmoreinfo (whoami, u->nick, "AUTH");
	return;
    }

    sra = findsra (nick);

    if (!sra)
    {
	notice (whoami, u->nick, RPL_NOT_SRA);
	return;
    }

    /* Avoid excessive globals/logging. */
    if (is_sra (u))
    {
	notice (whoami, u->nick, RPL_ALREADY_SRA);
	return;
    }

    if (stricmp (sra->nick, nick) || strcmp (sra->pass, pass))
    {
	notice (whoami, u->nick, RPL_NOT_SRA);
	globops (whoami, SH_FAILED_AUTH, u->nick, u->user, u->host);
	log ("Failed AUTH for %s from %s!%s@%s", sra->nick,
		u->nick, u->user, u->host);
	return;
    }
    else
    {
	u->flags |= UF_SRA;
	notice (whoami, u->nick, SH_NOW_SRA);

	if (globalonauth_on == TRUE)
	    globops (whoami, SH_NOW_SRA_GLOBOP, u->nick, u->user, u->host);

	/* Send it out to Services */
	if (sharesras_on == TRUE)
	    svssend ("3 %s", u->nick);

	if (ircdtype == UNREAL3 || ircdtype == UNREAL3_2)
	    send_cmd (whoami, "%s %s :is a Services Root Admin", me.token ? "BA" :
		"SWHOIS", u->nick);

	return;
    }
}

/* De-Authenticate from SRA access. */
void do_deauth (User *u)
{
    char *whoami = authserv ();

    if (u->flags & UF_SRA)
    {
	u->flags &= ~UF_SRA;
	notice (whoami, u->nick, SH_NO_LONGER_SRA);

	/* Send it out to Services */
	if (sharesras_on == TRUE)
	    svssend ("4 %s", u->nick);

	return;
    }

    /* We shouldn't get here, but just in case. */
    notice (whoami, u->nick, RPL_NOT_SRA);
}

#ifdef RAWINJECT
/* Send raw info to the uplink */
void do_raw (User *u)
{
    char *whoami = authserv ();
    char *text = strtok (NULL, "");

    if (!text)
    {
	notice (whoami, u->nick, RPL_SYNTAX, "RAW Command");
	errmoreinfo (whoami, u->nick, "RAW");
    }
    else
	send_cmd (NULL, text);
}

/* Throw something into the inbuf and process it. */
void do_inject (User *u)
{
    char *whoami = authserv ();
    char *text = strtok (NULL, "");

    if (!text)
    {
	notice (whoami, u->nick, RPL_SYNTAX, "INJECT Data");
	errmoreinfo (whoami, u->nick, "INJECT");
    }
    else
    {
	strscpy (inbuf, text, BUFSIZE);
	process();
    }
}
#endif /* RAWINJECT */

/* Toggle debug mode. */
void do_debug (User *u)
{
    char *whoami = authserv ();
    char *param = strtok (NULL, " ");
        
    if (!param)
    {
	notice (whoami, u->nick, RPL_SYNTAX, "DEBUG Level");
	errmoreinfo (whoami, u->nick, "DEBUG");
	return;
    }

    if (atoi (param) > 0)
    {
	debuglevel = atoi (param);
	open_debug();
	debug ("-----------------------------------------------------");
	notice (whoami, u->nick, SH_DEBUG_LEVEL, atoi (param),
	    debuglevel == 1 ? "Server<->Server traffic" :
	    debuglevel == 2 ? "Some function calls" :
	    debuglevel == 3 ? "Server<->Server traffic and some function calls"
	    : "Unknown");
    }
    else
    {
	notice (whoami, u->nick, SH_DEBUG_LEVEL, atoi (param), "Off");
	debug ("%s turned debug mode off.", u->nick);
	debuglevel = 0;
	close_debug();
    }
}

/* Terminate operstats permanently. */
void do_shutdown (User *u)
{
    char *whoami = authserv ();
    char reason[BUFSIZE], orig[BUFSIZE], *param;

    param = strtok (NULL, "");

    if (!param)
	memcpy (reason, "No reason given", sizeof (reason));
    else
	memcpy (reason, param, sizeof (reason));

    strscpy (orig, reason, sizeof (orig));

    param = strtok (reason, " ");

    /* Should we skip the DB save? */
    if (!stricmp (param, "NOSAVE"))
    {
	/* Yep. */
	param = strtok (NULL, "");

	if (param)
	    snprintf (quitmsg, BUFSIZE, param);
	else
	    snprintf (quitmsg, BUFSIZE, "No reason given");

	globops (whoami, SH_SHUTTING_DOWN, u->nick, quitmsg);
	runflags |= RUN_SHUTDOWN;
    }
    else
    {
	/* Nope. Save the DBs. */
	snprintf (quitmsg, BUFSIZE, orig);

	if (statserv_on == TRUE)
	    save_ss_dbase ();

	/* Check for any expired AKills */
	if (operserv_on == TRUE)
	{
	    expire_akills ();
	    save_os_dbase ();
	}

	globops (whoami, SH_SHUTTING_DOWN, u->nick, quitmsg);
	runflags |= RUN_SHUTDOWN;
    }
}

/* Restart OperStats. */
void do_restart (User *u)
{
    char *whoami = authserv ();
    char reason[BUFSIZE], orig[BUFSIZE], *param;

    param = strtok (NULL, "");

    if (!param)
	memcpy (reason, "No reason given", sizeof (reason));
    else
	memcpy (reason, param, sizeof (reason));

    strscpy (orig, reason, sizeof (orig));

    param = strtok (reason, " ");

    /* If wait_restart isn't set, OperStats won't restart. But if we're
       using this function, we want them to restart, so we set
       wait_restart to 5 seconds here. This change is wiped out when
       they restart.
     */
    wait_restart = 5;

    /* Should we skip the DB save? */
    if (!stricmp (param, "NOSAVE"))
    {
	/* Yep. */
	param = strtok (NULL, "");
	snprintf (quitmsg, BUFSIZE, param);

	if (!quitmsg)
	    snprintf (quitmsg, BUFSIZE, "No reason given");

	globops (whoami, SH_RESTARTING, duration (wait_restart, 1), u->nick,
	    quitmsg);
	runflags |= RUN_RESTART;
    }
    else
    {
	/* Nope. Save the DBs. */
	snprintf (quitmsg, BUFSIZE, orig);

	if (statserv_on == TRUE)
	    save_ss_dbase ();

	/* Check for any expired AKills */
	if (operserv_on == TRUE)
	{
	    expire_akills ();
	    save_os_dbase ();
	}

	globops (whoami, SH_RESTARTING, duration (wait_restart, 1), u->nick, quitmsg);
	runflags |= RUN_RESTART;
    }
}

/* Show various OperStats settings */
void do_settings (User *u)
{
    char *whoami = authserv ();

    notice (whoami, u->nick, SH_SETTINGS_START);
    notice (whoami, u->nick, " ");

    if (ircdtype == UNREAL3 || ircdtype == UNREAL3_2)
	notice (whoami, u->nick, SH_SETTINGS, "Unreal Numeric", itoa (unreal_numeric));

    notice (whoami, u->nick, SH_SETTINGS, "DataBase Sync Time", duration (update_timeout, 1));

    if (strlen (snoopchan))
	notice (whoami, u->nick, SH_SETTINGS, "Logging Channel", snoopchan);

    if (strlen (joinchan))
	notice (whoami, u->nick, SH_SETTINGS, "Join Channel", joinchan);

    if (floodmsgs)
    {
	notice (whoami, u->nick, SH_SETTINGS_MULTI, "Flood Trigger", itoa (floodmsgs),
	    " messages in ", duration (floodtime, 1));
	notice (whoami, u->nick, SH_SETTINGS, "Noisy Flood", noisyflood_on == TRUE ?
	    "On" : "Off");
    }

    notice (whoami, u->nick, SH_SETTINGS, "WaitRestart Delay", duration (wait_restart, 1));

    if (debuglevel)
	notice (whoami, u->nick, SH_SETTINGS, "Debug Level", itoa (debuglevel));

    notice (whoami, u->nick, SH_SETTINGS, "LogUpdates", logupdates_on == TRUE ? "On" : "Off");
    notice (whoami, u->nick, SH_SETTINGS, "GlobalOnAuth", globalonauth_on == TRUE ? "On" : "Off");

    notice (whoami, u->nick, SH_SETTINGS, "SecuritySetting", securitysetting == 1 ? "All" : 
	securitysetting == 2 ? "Passwords" : "None");

    notice (whoami, u->nick, SH_SETTINGS, "Help Index", helpindex == 1 ? "Short" : helpindex == 2 ?
	"Medium" : helpindex == 3 ? "Long" : "Unknown!");

    if (operserv_on == TRUE)
    {
	notice (whoami, u->nick, SH_SETTINGS, "Default AKill Expiry", duration (def_akill_time, 1));
	notice (whoami, u->nick, SH_SETTINGS, "Default AKill Reason", def_akill_reason);
	notice (whoami, u->nick, SH_SETTINGS, "GlobalOnAkill", globalonakill_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "Share AKills", shareakills_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "Share SRAs", sharesras_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "Non-Wild Chars Required", itoa (nonwildreq));

	if (maxclones)
	{
	    notice (whoami, u->nick, SH_SETTINGS, "Maximum Allowed Clones", itoa (maxclones));
	    notice (whoami, u->nick, SH_SETTINGS, "Maximum Clone Kills", itoa (maxclonekills));
	}

	if (globalnoticer_on == TRUE)
	{
	    notice (whoami, u->nick, SH_SETTINGS, "Top Level Domains", tlds);
	    notice (whoami, u->nick, SH_SETTINGS, "StampLogons", stamplogons_on == TRUE ? "On" : "Off");

	    if (strlen (globalmsg))
		notice (whoami, u->nick, SH_SETTINGS, "Global Message Prefix", globalmsg);
	}
    }

    if (statserv_on == TRUE)
    {
	notice (whoami, u->nick, SH_SETTINGS, "Ping Delay", duration (ping_delay, 1));
	notice (whoami, u->nick, SH_SETTINGS, "Create channels.html", dumpchans_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "Channel List JavaClient", javaclient_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "Create stats.js", dumpstats_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "GlobalOnLag", globalonlag_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "Lag Threshold", duration (lagthreshold, 1));
	notice (whoami, u->nick, SH_SETTINGS, "Ignore U:Lines", ignoreulines_on == TRUE ? "On" : "Off");
	notice (whoami, u->nick, SH_SETTINGS, "GlobalOnSpeed", globalonspeed_on == TRUE ? "On" : "Off");
    }

    notice (whoami, u->nick, " ");
    notice (whoami, u->nick, SH_SETTINGS_END);
}

/* Update the DBs. */
void do_update (User *u)
{
    char *whoami = authserv ();

    globops (whoami, SH_FORCE_UPDATE, u->nick);
    runflags |= RUN_SAVEDBS;
}

/* Call rehash () with the nickname of the person doing it */
void do_rehash (User *u)
{
    rehash (u->nick);
}

/* Re-read operstats.conf */
void rehash (const char *source)
{
    char *whoami = authserv ();

    /* Just in case. */
    globops (whoami, SH_FORCE_UPDATE, source);
    runflags |= RUN_SAVEDBS;

    globops (whoami, SH_DOING_REHASH, CONFIGFILE, source);

    /* Reset the conf values */
    reset_conf ();

    /* Flush TLDs, SRAs, and TimeZones (some might be removed) */
    flushlists ();

    /* Now re-read. */
    load_conf ();
    
    /* Now check it */
    check_conf(); 

    /* Remove any disabled pseudoclients */
    if (ss.isonline && statserv_on == FALSE)
    {
	send_cmd (s_StatServ, "%s :Client disabled", me.token ? "," : "QUIT");
	userstat--;
	ss.isonline = 0;
    }

    if (os.isonline && operserv_on == FALSE)
    {
	send_cmd (s_OperServ, "%s :Client disabled", me.token ? "," : "QUIT");
	userstat--;
	os.isonline = 0;
    }

    if (gn.isonline && globalnoticer_on == FALSE)
    {
	send_cmd (s_GlobalNoticer, "%s :Client disabled", me.token ? "," : "QUIT");
	userstat--;
	gn.isonline = 0;
    }

    if (sp.isonline && spamserv_on == FALSE)
    {
	send_cmd (sp.nick, "%s :Client disabled", me.token ? "," : "QUIT");
	userstat--;
	sp.isonline = 0;
    }

    /* Re-read StatServ stuff too */
    if (statserv_on == TRUE)
    {
	load_tlds ();
	load_zones ();
    }
}

/* Search the log file for the specified text. Return Num matching lines. */
void do_search (User *u)
{
    FILE *logfile = fopen (LOGFILE, "r");
    char *whoami = authserv ();
    char *match = strtok (NULL, " ");
    char *param = strtok (NULL, " ");
    char tmp[BUFSIZE];
    char dBuf[2048];
    uint8 max, found = 0;

    if (!match)
    {
	notice (whoami, u->nick, RPL_SYNTAX, "SEARCH MatchText [Num]");
	errmoreinfo (whoami, u->nick, "SEARCH");
	return;
    }

    if (!param || (param && atoi (param) > 250))
	max = 50;
    else
	max = atoi (param);

    if (!logfile)
    {
	notice (whoami, u->nick, RPL_CANT_OPEN, LOGFILE);
	return; 
    }

    notice (whoami, u->nick, SH_LOG_START, max, max == 1 ? "" : "es");

    snprintf (tmp, sizeof (tmp), "*%s*", match);

    while (fgets (dBuf, 2047, logfile))
    {
	if (found >= max)
	    break;

	if (match_wild_nocase (tmp, dBuf))
	{
	    ++found;
	    notice (whoami, u->nick, dBuf);
	}
    }

    notice (whoami, u->nick, SH_LOG_END, found, found == 1 ? "" : "es");

    fclose (logfile);
}

/* Cycle the logfiles */
void do_cyclelogs (User *u)
{
    char *whoami = authserv ();

    /* Close them.. */
    close_log ();

    if (debuglevel > 0)
        close_debug ();

    /* Reopen them.. */
    open_log ();

    if (debuglevel > 0)
	open_debug ();

    log ("-----------------------------------------------------");

    if (debuglevel > 0)
	debug ("-----------------------------------------------------");

    /* That was easy :P */
    notice (whoami, u->nick, SH_LOGS_CYCLED);
}
