/*
 * irchandlers.c
 * (C) Peter Salanki 2002
 * This program is copyright, and covered by the Gnu Public License.
 * The Natasha bot.
 * sorcer@linux.se
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <dlfcn.h>
#include "../../settings.h"
#include "../../globals.h"
#include "../../bottypes.h"
#include "servtab.h"

#define NAME "IRCHandlers"
#define VERSION 1.00

void s_ctcp (struct arm *a);
MODULE_INIT _module_init(MODULE m);
MODULE_DESTROY _module_destroy(MODULE m);

MODULE_INIT _module_init(MODULE m) {
  strncpy(m->name, NAME, 20);
  strncpy(m->compiledate, __DATE__ " " __TIME__, 30);
  m->version = VERSION;  
}

MODULE_DESTROY _module_destroy(MODULE m) {

}

void s_privmsg (struct arm *a)
{
  int i;
  struct channel *c;
  struct activechanuser *acu;
  struct activeuser *u;
  struct module *m;
  char tmp[512] = "";
  char hostmask[HOSTLEN+5+USERLEN] = "";
  void (*parse)();

  if (strstr (a->parsevars->args[0], "#") != NULL)
    {
      /* A public channel command */
      
      /* Strip out the actual command. */
      for (i = 0; ((a->parsevars->args[1][i] != ' ') && (a->parsevars->args[1][i] != '\n') && (a->parsevars->args[1][i] != '\r') && (a->parsevars->args[1][i] != 0) && (i < 512)); i++)
	{
	  a->parsevars->command[i] = a->parsevars->args[1][i];
	}
      a->parsevars->command[i] = 0;

      m = findmodule("PUBHandlers");
      if(m != NULL) {
	parse = dlsym(m->fl, "p_parse");
	parse(a->parsevars->command, &(a->parsevars->args[1][i + 1]), a);
      }

      /* Here comes the advertiseing and flooding parts */
  
      c = findchannel(a->parsevars->args[0]);
      acu = findachanuser(a->parsevars->sender, a->parsevars->args[0]);

      if (acu == NULL) return; // Strange, he is not here.

      if (c != NULL && c->isop == 1) {

	/* Flood check */
	if (c->floodrep != 0 && c->floodtime != 0) {
	  if(acu->lastreset+c->floodtime <= time(NULL)) {
	    acu->lastreset = time(NULL);
	    acu->rows = 0;
	  }

	  ++acu->rows; // Add to row count

	  if (acu->rows > c->floodrep && acu->op == 0 && chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) == 0) {
	    /* Flooder found */
	    
	    if (acu->warned == 0) {
	      /* We will use CNOTICE here */
	      acu->warned = 1;
	      acu->rows = 0;
	      sprintf(tmp, "You are violating this channel's rules and the Quakenet rules. Please read http://www.quakenet.org/rules/ and cease your abuse or you will get banned for five minutes.");
	      // say(a->parsevars->sender, tmp, a);

	      return;
	    } else if (acu->warned == 1) {
	      /* We bankick him, haha */
	      
	      u = findauser(a->parsevars->sender);
	      sprintf(hostmask, "%s@%s", u->username, u->hostname);
	      sprintf(tmp, "Violated channel flooding rules and ignored warning.");
	      addban(a->parsevars->args[0], hostmask, tmp, 0, time(NULL)+300);

	      sprintf(tmp, "Violated channel flooding rules and ignored warning. Banned for five minutes");
	      kick(a->parsevars->args[0], a->parsevars->sender, tmp);
	      
	      return;
	    }
	  }
	}

	/* Advertise check */
	if (c->advertise == 1) {
	  if (strstr(a->parsevars->args[1], "#") != NULL) strncpy(tmp, strstr(a->parsevars->args[1], "#"), 512);

	  if (tmp != NULL && tmp[1] != ' ' && tmp[2] != '\0' && tmp[2] != ' ' && chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) == 0 && acu->op == 0) {
	    /* Advertiser found */
	    
	    if (acu->warned == 0) {
	      /* We will use CNOTICE here */
	      acu->warned = 1;

	      sprintf(tmp, "You are violating this channel's advertisation rules. Please cease your abuse or you will get banned for five minutes.");
	      say(a->parsevars->sender, tmp, a);

	    } else if (acu->warned == 1) {
	      /* We bankick him, haha */

	      u = findauser(a->parsevars->sender);

	      sprintf(hostmask, "%s@%s", u->username, u->hostname);
	      sprintf(tmp, "Violated channel advertisation rules and ignored warning.");
	      addban(a->parsevars->args[0], hostmask, tmp, 0, time(NULL)+300);

	      sprintf(tmp, "Violated channel advertisation rules and ignored warning. Banned for five minutes");
	      kick(a->parsevars->args[0], a->parsevars->sender, tmp);
	    }
	  }
	}
      }

      /* End of public msg */
      return;
    }
  if (a->parsevars->args[1][0] == 1)
    {
      /* We might have a CTCP a->parsevars->command */
      for (i = 0; i < strlen (a->parsevars->args[1]); i++)
	{
	  if ((a->parsevars->args[1][i] == '\n') || (a->parsevars->args[1][i] == '\r') || (a->parsevars->args[1][i] == 0))
	    break;
	}
      if (a->parsevars->args[1][i - 1] == 1)
	{
	  s_ctcp(a);
	  return;
	}
    }
  
  /* Strip out the actual a->parsevars->command. */
  for (i = 0; ((a->parsevars->args[1][i] != ' ') && (a->parsevars->args[1][i] != '\n') && (a->parsevars->args[1][i] != '\r') && (a->parsevars->args[1][i] != 0) && (i < 512)); i++)
    {
      a->parsevars->command[i] = a->parsevars->args[1][i];
    }
  a->parsevars->command[i] = 0;
  
#ifdef Q
  if(strcmp(a->parsevars->sender, "O") == 0)
  {
      sprintf(tmp, "%s: %s", a->parsevars->sender, a->parsevars->args[1]);
      privmsg(HOMECHAN, tmp);
  }
#endif

  m = findmodule("MSGHandlers");
  if(m != NULL) {
    parse = dlsym(m->fl, "m_parse");
    parse(a->parsevars->command, &(a->parsevars->args[1][i + 1]), a);
  }
  return;
}

/*
 * Parse a CTCP-style a->parsevars->command.
 */

void s_ctcp (struct arm *a)
{
  if (strcasecmp (a->parsevars->args[0], a->nick) != 0)
    {
      return;
    }
  if (strncasecmp (a->parsevars->args[1], "\1VERSION", 8) == 0)
    {
      ctcpreply (a->parsevars->sender, "VERSION " CTCP_VERSION_REPLY, a);
#ifdef DEBUG
      printf("ctcpreply\n");
#endif
    }
  if (strncasecmp (a->parsevars->args[1], "\1PING", 5) == 0)
    {
      putserver("NOTICE ", a);
      putserver(a->parsevars->sender, a);
      putserver(" :\1PING", a);
      puttime(a);
      putserver("\1\n", a);
      
    }
}

void s_notice (struct arm *a)
{
#ifdef Q
  char msg[512];

#ifndef L
  if(strcmp(a->parsevars->sender, Q_NICK) == 0 || strcmp(a->parsevars->sender, "O") == 0)
#else
  if(strcmp(a->parsevars->sender, Q_NICK) == 0 || strcmp(a->parsevars->sender, L_NICK) == 0 || strcmp(a->parsevars->sender, "O") == 0)
#endif
    {
      sprintf(msg, "%s: %s", a->parsevars->sender, a->parsevars->args[1]);
      if(a->parsevars->args[1][0] != '[' && a->parsevars->args[1][1] != '#') privmsg(HOMECHAN, msg);
    }
#endif

  return;
}

void s_nick (struct arm *a)
{
  struct activeuser *u;

  // char channel[255]; #saltlake2002 haxx
  
  u = findauser(a->parsevars->sender);
  
  strncpy (u->nick, a->parsevars->args[0], NICKLEN);
  
  /* Some haxx for #saltlake2002. Impelement in bot?
  strcpy(a->parsevars->sender, a->parsevars->args[0]);
  strcpy(channel, "#SaltLake2002");

  if (u != NULL && (strstr(a->parsevars->sender, "GER|") != NULL || strstr(a->parsevars->sender, "SWE|") != NULL || strstr(a->parsevars->sender, "FIN|") != NULL || strstr(a->parsevars->sender, "USA|") != NULL || strstr(a->parsevars->sender, "RUS|") != NULL || strstr(a->parsevars->sender, "DEN|") != NULL || strstr(a->parsevars->sender, "NOR|") != NULL )) voice(channel, a->parsevars->sender); else devoice(channel, a->parsevars->sender);
  */

  return;
}

void s_mode (struct arm *a)
{

  struct channel *c;
  struct activechanuser *acu;
  int param, direction, i, num;

  c = findchannel (a->parsevars->args[0]);
  param = 2;
  direction = 1;	       
  i = 0;
  num = 2;

  while (a->parsevars->args[1][i] != 0)
    {
      switch (a->parsevars->args[1][i])
	{
	case '+':
	  direction = 1;
	  break;
	case '-':
	  direction = 0;
	  break;
	case 'b':

	  param++;
	  break;
	case 'k':
	  if(c != NULL && c->bitch == 1 && c->isop == 1) {
	    if(direction == 1) {
		  
	      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) >= CHAN_MASTER || strcasecmp(a->nick, a->parsevars->sender) == 0) { 
		strcpy(c->key, a->parsevars->args[num]);
		dbchanmode(c->id, "key", a->parsevars->args[num]);
	      } else {
		
		putserver("MODE ", c->arm);
		putserver(a->parsevars->args[0], c->arm);
		putserver(" ", c->arm);
		putserver("-k ", c->arm);
		putserver(a->parsevars->args[num], c->arm);
		putserver("\r\n", c->arm);
		
		say(a->parsevars->sender, "Only masters or higher can set key in this channel.", a);
	      } 
	    } else {
	      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) >= 4 || strcasecmp(a->nick, a->parsevars->sender) == 0) { 
		strcpy(c->key, "");
		dbchanmode(c->id, "key", "");
	      } else {
		
		putserver("MODE ", c->arm);
		putserver(a->parsevars->args[0], c->arm);
		putserver(" ", c->arm);
		putserver("+k ", c->arm);
		putserver(c->key, c->arm);
		putserver("\r\n", c->arm);
		
		say(a->parsevars->sender, "Only masters or higher can remove key in this channel.", a);
	      }
	    }
	  }
	  if(c != NULL) {
	    if(direction == 1) {
	      
	      strcpy(c->key, a->parsevars->args[num]);
	      dbchanmode(c->id, "key", a->parsevars->args[num]);
	    } else {
	      strcpy(c->key, "");
	      dbchanmode(c->id, "key", "");
	    }
	  } else
#ifdef SAFEHOME
	    {
	      if(direction == 1) {
		strncpy(homekey, a->parsevars->args[num], KEYLEN);
		writedatatofile("homekey", homekey);
	      }
	    }
#endif

	  param++;
	  break;
	case 'o':
	  if(strcasecmp(a->nick, a->parsevars->args[param]) == 0) {
	    if(direction == 1) {
#ifdef DEBUG
	      if(strcmp(a->parsevars->sender, L_NICK) != 0 && strcmp(a->parsevars->sender, Q_NICK) != 0) say(a->parsevars->sender, "Thanx 4 op dude.", a);
#endif
	      /* Set right channel modes */
	      if(c != NULL) c->isop = 1;
	      else return;

	    
	      putserver("MODE ", c->arm);
	      putserver(a->parsevars->args[0], c->arm);
	      putserver(" ", c->arm);
	      putserver(c->modes, c->arm);
	      if(strcmp(c->key, "") != 0) {
		putserver("+k ", c->arm);
		putserver(c->key, c->arm);
	      }
	      putserver ("\n\r", c->arm);
		
	      // Give out right modes
	      acu = firstacu;
	      while (acu != NULL)
		{
		  if(acu->channel == c) {
#ifdef Q
		    if(strcmp(acu->user->nick, Q_NICK) != 0)
#ifdef L
		      if(strcmp(acu->user->nick, L_NICK) != 0)
#endif
#endif
			{
			  if(strcasecmp(acu->user->nick, a->nick) == 0) acu->op = 1;
			  else setrightmode(a->parsevars->args[0], acu->user->nick); 
			}
		  }
		  acu = acu->next;
		}
		
	    } else {
	      if(c != NULL) c->isop = 0;
 
	      if((acu = findachanuser(a->nick, a->parsevars->args[0])) != NULL) acu->op = 0;
	      
	      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) < 5) {
		
		/*
		privmsg(a->parsevars->sender, "Only channel owners are allowed to deop bots. All channel owners will be informed of your actions.");
		*/
		/* Future msg code to chanowners goes here */

	      }
#ifdef L
	      if(c != NULL) l_getop(c);
#endif
	      snprintf(a->parsevars->command, 511, "deoped %c%s%c in", BOLD, a->nick, BOLD); /* Horrible */
	      violation(a->parsevars->sender, a->parsevars->command, a->parsevars->args[0]);
	    }
	  }

	  if(c != NULL && c->bitch == 1 && c->isop == 1 && strcmp(a->nick, a->parsevars->sender) != 0) {
	    if(direction == 1) {
	      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) < 4 && strcmp(a->nick, a->parsevars->args[num]) != 0 && (strcmp(a->parsevars->sender, a->nick) != 0 && a->parsevars->isserver == 0)) {
		deop(a->parsevars->args[0], a->parsevars->args[num]);
	      }
	    } else {
	      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) < 4  && c->isop == 1 && strcmp(a->parsevars->sender, a->parsevars->args[num]) != 0 && (strcmp(a->parsevars->sender, a->nick) != 0 && a->parsevars->isserver == 0)) { 
		op(a->parsevars->args[0], a->parsevars->args[num]);
	      }
	    }
	  }
	  acu = findachanuser(a->parsevars->args[num], a->parsevars->args[0]);
	  if(acu != NULL) {
	    if(direction == 1) acu->op = 1;
	    else acu->op = 0;
	  }

	  ++num;	      
	  param++;
	  break;
	case 'v':
	  acu = findachanuser(a->parsevars->args[num], a->parsevars->args[0]);
	  if(acu != NULL) {
	    if(direction == 1) acu->voice = 1;
	    else acu->voice = 0;
	  }

	  ++num;
	  param++;
	  break;
	case 'l':

	  param++;
	  break;
	case 't':

	  break;
	case 'i':
	  if(c != NULL && c->bitch == 1 && c->isop == 1) {
	    if(direction == 1) {
		  
	      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) < 4 && strcasecmp(a->nick, a->parsevars->sender) != 0) { 
		
		putserver("MODE ", c->arm);
		putserver(a->parsevars->args[0], c->arm);
		putserver(" ", c->arm);
		putserver("-i", c->arm);
		putserver("\r\n", c->arm);
		say(a->parsevars->sender, "Only masters or higher can set invite on this channel.", a);
		
		} 
	    } else {
	      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) < 4  && strcasecmp(a->nick, a->parsevars->sender) != 0) { 
		
		putserver("MODE ", c->arm);
		putserver(a->parsevars->args[0], c->arm);
		putserver(" ", c->arm);
		putserver("+i", c->arm);
		putserver("\r\n", c->arm);
		
		say(a->parsevars->sender, "Only masters or higher can remove invite on this channel.", a);
	      }
	    }
	  }
	  break;
	case 'n':

	  break;
	case 's':

	  break;
	}
      i++;
    }
    

    }

/*
 * Remove a user from the list of people currently on the network.
 * Needs to remove their entry from the linked lists, and more importantly,
 * free the memory they were using.
 */

void s_quit (struct arm *a) {
  /* User has quit/split - remove them from the lists. */
  struct activeuser *u;

  u = findauser(a->parsevars->sender);

  if(!delallauserchans(u)) deluser(u);
}

/*
 * User has joined a particular channel. (Possibly having just un-net-split.)
 */

void s_join (struct arm *a)
{
  char *channel;
  char ret[512];

  int i;
  struct activeuser *au;
  struct activeuser *u;
  int linked, bots, techs, mtechs, queue, ichannels;
  float capacity, channels;
  char techsn[50], mtechsn[50], queuen, queuea[4];
  struct channel *c;
  struct activechanuser *acu;
  char msg[512];

  channel = a->parsevars->args[0];

  if(strcasecmp(channel, HOMECHAN) == 0 && a->id != 1 && strcasecmp(a->parsevars->sender, a->nick) != 0) return;

  u = findauser(a->parsevars->sender);

#ifdef DEBUG
  printf("join: addachanuser\n");
#endif
  addachanuser(a->parsevars->sender, channel);

  if(findachanuser(a->parsevars->sender, channel) == NULL && strcasecmp(channel, HOMECHAN) != 0 && strcasecmp(a->parsevars->sender, a->nick) != 0) return;


  if(strcasecmp(a->parsevars->sender, a->nick) != 0) {
    if(a->id == 1 && strcasecmp(channel, HOMECHAN) == 0) {
      if(findarm(a->parsevars->sender) != NULL) { /* || ((i = findarmndb(a->parsevars->sender)) != 0) */
	if(u->auth <= 1) u->auth = findarm(a->parsevars->sender)->type;
	setrightmode(channel, a->parsevars->sender);
	return;
      }
#ifdef SAFEHOME
      if(u->auth < LEASTINHOME) {
	kick(channel, a->parsevars->sender, "You are not allowed in this channel");
	printf("Warning: Home channel security compromised.\n");
	securehome();
      }
#endif
    }

    c = findchannel(channel);

#ifdef DEBUG
    printf("join: setrightmode\n");
#endif
    /* Make sure to give the user the right modes */
    if (c != NULL && c->isop == 1) setrightmode(channel, a->parsevars->sender);
    else if (c == NULL) setrightmode(channel, a->parsevars->sender);

#ifdef Q_AUTOAUTH   
    /* Recheck Q auth in 10 mins */
    if(u != NULL && u->auth == 0) u->check = time(NULL) + RECHECKTIME;
#endif
    
#ifdef DEBUG  
    printf("join: onjoin\n");
#endif
    /* Massvoice */
    if (c != NULL && c->mvoice[0] != '\0' && c->isop == 1 && (strcmp(c->mvoice, "*") == 0 || (regex_match(c->mvoice, a->parsevars->sender)))) voice(channel, a->parsevars->sender);

    /* Check onjoin */
    if (c != NULL && strcmp(c->onjoin, "") != 0 && userlevel(a->parsevars->sender) < 30) {
      STR_replace_c (c->onjoin, "%n", a->parsevars->sender, ret);
      sprintf(msg, "%i", c->peak);
      STR_replace_c (ret, "%p", msg, ret);
      /* #ifdef CNOTICE
      cnotice(a->parsevars->sender, ret);
      #else */
      say(a->parsevars->sender, ret, a);
      //#endif
    }
#ifdef DEBUG
    printf("join: onjoin1\n");
#endif
    if(a->id == 1) {
      channels = linked = bots = capacity = techs = mtechs = queue = 0;

      /* Arms */
      dbquery("SELECT `status` FROM `arms`");
      while((row = mysql_fetch_row(res))) {
	++bots;
	if(atoi(row[0]) == 1) ++linked;
      }
      EndDbQuery();
    
      /* Queue status */
      dbquery("SELECT count(*) FROM `request` WHERE status = '0'");
      row = mysql_fetch_row(res);
      queue = atoi(row[0]);
      EndDbQuery();

      /* Number of channels */
      dbquery("SELECT count(*) FROM `channels`");
      row = mysql_fetch_row(res);
      channels = atoi(row[0]);
      EndDbQuery();

      au = firstauser;
      while (au != NULL)
	{
	  if(au->auth == 20) ++techs;
	  if(au->auth == 21) ++mtechs;
	  au = au->next;
	}

      ichannels = channels;
      capacity = (channels/(MAXCHANS * bots)) * 100;

      strcpy(techsn, authtotext(20));
      if(techs > 1|| techs == 0 ) strcat(techsn, "s");

      strcpy(mtechsn, authtotext(21));
      if(mtechs > 1 || mtechs == 0) strcat(mtechsn, "s");

      if(queue > 1 || queue == 0) {
	strcpy(queuea, "are");
	queuen = 's';
      } else {
	strcpy(queuea, "is");
	queuen = ' ';
      }

      sprintf(ret, "We have %c%d%c bots online of a total of %c%d%c bots. We are active on %c%i%c channels and we are using %c%.0f%%%c of our total capacity. There are %c%d%c %s and %c%d%c %s online. There %s %c%i%c item%c in queue.", BOLD, linked, BOLD, BOLD, bots, BOLD, BOLD, ichannels, BOLD, BOLD, capacity, BOLD, BOLD, techs, BOLD, techsn, BOLD, mtechs, BOLD, mtechsn, queuea, BOLD, queue, BOLD, queuen);
#ifdef CNOTICE
      cnotice(a->parsevars->sender, ret);
#else
      say(a->parsevars->sender, ret, a);
#endif

    }
#ifdef DEBUG
    printf("join: onjoin2\n");
#endif
    if (c != NULL && c->greet == 1 && chanusergreet(a->parsevars->sender, channel, ret)) privmsg(channel, ret);
    else if(c != NULL && u->auth >= 20 && u->auth < 30 && u->auth != 22 && c->greet == 1 && strcasecmp(a->parsevars->sender, "T") != 0) {
      sprintf(ret, "%s %s entered the channel.", BOTHOUSE, authtotext(u->auth)); 
      privmsg(channel, ret);
    }

    OnJoinVoteMsg(c, u); /* Msg vote msg if needed */

#ifdef DEBUG
    printf("join: onjoin3\n");
#endif
    if (c != NULL && c->peak != 0) {

      i = 0;   
     
      acu = firstacu;
      while (acu != NULL)
	{
	  if(acu->channel == c) ++i;
	  acu = acu->next;
	}
      
      if(i > c->peak) {
	
	c->peak = i;
	sprintf(msg, "%i", i);
	dbchanmode(c->id, "peak", msg);
	
	sprintf(msg, "New channel peak! (%c%i%c) by: %s", BOLD, i, BOLD, a->parsevars->sender); 
	privmsg(c->name, msg);
      }
    }

  /* Some haxx for #saltlake2002. Impelement in bot?
    if (u != NULL && strcasecmp(channel, "#os-2002") == 0) 
    {
    u->auth = 66;
    op("#SaltLake2002", a->parsevars->sender);
    }

    if (u != NULL && strcasecmp(u->hostname, AOPHOST) == 0) op(channel, a->parsevars->sender);
    if (u != NULL && u->auth == 66 && (strcasecmp(channel, "#os-2002") == 0 || strcmp(channel, "#SaltLake2002") == 0)) op(channel, a->parsevars->sender);
    if (u != NULL && strcmp(channel, "#SaltLake2002") == 0 && (strstr(a->parsevars->sender, "GER|") != NULL || strstr(a->parsevars->sender, "SWE|") != NULL || strstr(a->parsevars->sender, "FIN|") != NULL || strstr(a->parsevars->sender, "USA|") != NULL || strstr(a->parsevars->sender, "RUS|") != NULL || strstr(a->parsevars->sender, "DEN|") != NULL || strstr(a->parsevars->sender, "NOR|") != NULL )) voice(channel, a->parsevars->sender);
 */
#ifdef DEBUG
    printf("join: end\n");
#endif
    } else {
 
      if(strcasecmp(channel, HOMECHAN) == 0 && userlevel(a->parsevars->sender) <= 1 && findarm(a->parsevars->sender) != NULL) u->auth = findarm(a->parsevars->sender)->type;

      c = findchannel(channel);

#ifdef DEBUG
      printf("We are on: %s\n", channel);
#endif

      if(c != NULL) {
	c->ison = 1;
	who(c);
      }
      else putserver("WHO " HOMECHAN "\n\r", a);
    }
  }
/*
 * User has left a channel. Much the same deal as above.
*/

void s_part (struct arm *a)
{
  /*  struct activechanuser *acu;
  if(findachanuser(a->parsevars->sender, a->parsevars->args[0]) == NULL) {x
    addachanuser(a->parsevars->sender, a->parsevars->args[0]);
    // Typ nåt här
    acu = findachanuser(a->parsevars->sender, a->parsevars->args[0]);
    if(acu != NULL) acu->op = 5;
    } else */

  delachanuser(a->parsevars->sender, a->parsevars->args[0]);
}

/*
 * Erk! Someone just tried a /KILL on us
 */

void s_kill (struct arm *a)
{
  a->status = 0;
}

/*
 * Respond to a PING from a server.
 */

void s_ping (struct arm *a)
{
  pong(a);
  return;
}

void s_topic (struct arm *a)
{
  struct channel *c;
  int i = 1;
  char newtopic[TOPICLEN] = "";

  c = findchannel(a->parsevars->args[0]);
  
  if(c != NULL && c->ftopic == 1 && c->isop == 1) {
    if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) < 4 && (strcasecmp(a->parsevars->sender, a->nick) != 0 && a->parsevars->isserver == 0)) {
      if(strcmp(c->topic, "") != 0) settopic(a->parsevars->args[0], c->topic);
      say(a->parsevars->sender, "Sorry, only masters or higher are allowed to set topic on this channel.", a);
    } else {
      
      while (i < MAX_ARGS) {
	strcat(newtopic, a->parsevars->args[i]);
	++i;
      }
      strncpy(c->topic, newtopic, TOPICLEN);

#ifdef DEBUG
      printf("New topic set to: %s\n", newtopic);
#endif
    }
  }
}

void s_kick (struct arm *a)
{
  struct channel *c;
  char msg[512];

  if (strcasecmp (a->nick, a->parsevars->args[1]) == 0)
    {
      rejoinchannel(a->parsevars->args[0], a);

      c = findchannel(a->parsevars->args[0]);
      if(c == NULL) return;

      OutOfChannel(c);

      /* Some cheeky sod just kicked us! */   
      if(chanuserlevel(a->parsevars->sender, a->parsevars->args[0]) < 5) {
	/*
	privmsg(a->parsevars->sender, "Only channel owners are allowed to kick bots. All channel owners will be informed of your actions.");
	*/
	/* Future msg code to chanowners goes here */
      }
      
      sprintf(msg, "kicked %c%s%c from", BOLD, a->nick, BOLD); /* Horrible */
      violation(a->parsevars->sender, msg, a->parsevars->args[0]);

    }
  else
    {
      delachanuser(a->parsevars->args[1], a->parsevars->args[0]);
    }
}

void s_whoreply (struct arm *a) {
  /* <channel> <user> <host> <server> <nick> <H|G>[*][@|+] :<hopcount> <real name> */
  struct channel *c;
  struct activechanuser *acu;

  char nick[NICKLEN] = "";
  char username[USERLEN] = "";
  char hostname[HOSTLEN] = "";
  char temp[512];

  c = findchannel(a->parsevars->args[1]);
 
#ifdef DEBUG
  printf("This is a WHOReply on channel: %s nick: %s\n", a->parsevars->args[1], a->parsevars->args[5]);
#endif

  strncpy(username, a->parsevars->args[2], USERLEN);
  strncpy(hostname, a->parsevars->args[3], HOSTLEN);
  strncpy(nick, a->parsevars->args[5], NICKLEN);
  STR_replace_c (a->parsevars->args[6], "H", "", temp);
  STR_replace_c (temp, "G", "", temp);
  STR_replace_c (temp, "*", "", temp);
  STR_replace_c (temp, "d", "", temp);

  if(c != NULL && c->isop == 2 && strcasecmp(a->nick, nick) != 0) c->isop = 0;

  if(findauser(nick) == NULL) addauser(nick, username, hostname); 

  acu = addachanuser(nick, a->parsevars->args[1]);

  if(acu != NULL) {
    if(strcmp(temp, "@") == 0) acu->op = 1;
    else if(strcmp(temp, "+") == 0) acu->voice = 1;
  }
}

void s_endofwho (struct arm *a) {
  struct channel *c;
  
  c = findchannel(a->parsevars->args[1]);

  if(c != NULL && c->isop == 2) c->isop = 1;

  if(c != NULL && c->isop == 1) {
    
    putserver("MODE ", a);
    putserver(a->parsevars->args[1], a);
    putserver(" ", a);
    putserver(c->modes, a);
    if(strcmp(c->key, "") != 0) {
      putserver("+k ", a);
      putserver(c->key, a);
    }

    putserver ("\n\r", a);
    
  }

  if(c != NULL && a->type == 40) amodfunc("Request", "onchan", a);

#ifdef DEBUG
  printf("End of WHO list for channel: %s\n", a->parsevars->args[1]);
#endif
}

void s_whoisuser (struct arm *a) {
  /* <nick> <user> <host> * :<real name> */
#ifdef DEBUG
  printf("Got WHOIS_USER for: %s\n", a->parsevars->args[1]);
#endif
}

void s_endofwhois (struct arm *a) {
  if(findauser(a->parsevars->args[1]) == NULL) {  
#ifdef DEBUG
    printf("Got WHOIS_END for: %s (not existing)\n", a->parsevars->args[1]);
#endif
    return;
  }

#ifdef DEBUG
  printf("Got WHOIS_END for: %s\n", a->parsevars->args[1]);
#endif
}

void s_whoischannels (struct arm *a) {
  /* Obsolote
  char chan[CHANNELLEN] = "";
  int op = 0; 
  int i = 0;
  int end = 0;
  struct channel *c;

  // <nick> :{[@|+]<channel><space>} 
  
  if(strcmp(a->parsevars->args[1], a->nick) == 0) {
#ifdef DEBUG
    printf("Got RPL_WHOISCHANNELS on me\n");
#endif
    printf("a->parsevars->args[2] %s a->parsevars->args[3] %s a->parsevars->args[4] %s\n", a->parsevars->args[2], a->parsevars->args[3], a->parsevars->args[4]);
    while(end == 0) {

      op = 0;
      
      if(a->parsevars->args[i][0] == '@') {
	sscanf(a->parsevars->args[i], "@%s", chan);
	op = 1;
      } else if(a->parsevars->args[i][0] == '+') sscanf(a->parsevars->args[i], "+%s", chan);
      else if(a->parsevars->args[i][0] == '\0') end = 1;
      else strncpy(chan, a->parsevars->args[i], CHANNELLEN);

      c = findchannel(chan);

      if(c != NULL) c->isop = op;
#ifdef DEBUG
      printf("OP: %d Chan: %s\n", op, chan);
#endif
      ++i;
    }
    printf("ended\n");
  }
  */
}

void s_rpltopic (struct arm *a) {
  struct channel *c;

  /* <channel> :<topic> */
  
  c = findchannel(a->parsevars->args[1]);

  if(c != NULL) {
    strncpy(c->topic, a->parsevars->args[2], TOPICLEN);
#ifdef DEBUG
    printf("Topic for %s set to: %s\n", a->parsevars->args[1], c->topic);
#endif
  }
  
}

void s_isoper (struct arm *a) {
  struct activeuser *u;
  char msg[512];
  /* <nick> :is an IRC operator */

#ifdef Q
  if(strcmp(a->parsevars->args[1], Q_NICK) == 0) return; // We don't want Q
#ifdef L
  if(strcmp(a->parsevars->args[1], L_NICK) == 0) return; // We don't want L
#endif
  if(strcmp(a->parsevars->args[1], "T") == 0) return; // We don't want T
  else if(strcmp(a->parsevars->args[1], "S") == 0) return; // We don't want S
#endif
  
  if((u = findauser(a->parsevars->args[1])) == NULL) return;

  u->auth = 22;
  
  if(strcmp(a->parsevars->args[1], Q_NICK) != 0) {
    sprintf(msg, "%s is now known as an IRC Operator.", a->parsevars->args[1]);
    privmsg(HOMECHAN, msg);
  }
  
}

void s_inviteonlychan (struct arm *a) {
  struct module *m; 
  void (*cmd)();
  
  if(a->type == 40 && ((m = findmodule("Request")) != NULL)) { 
    cmd = dlsym(m->fl, "response");
    cmd(0);
    c_part(a->parsevars->args[1], "Cannot join");
  }
#ifdef L
  else 
    { 
      l_invite(findchannel(a->parsevars->args[1]));
    }
#endif
}

void s_isfullchan (struct arm *a) {
  struct module *m; 
  void (*cmd)();
  
  if(a->type == 40 && ((m = findmodule("Request")) != NULL)) { 
    cmd = dlsym(m->fl, "response");
    cmd(0);
    c_part(a->parsevars->args[1], "Cannot join");
 }
}

void s_badkeychan (struct arm *a) {
  struct module *m; 
  void (*cmd)();
  
  if(a->type == 40 && ((m = findmodule("Request")) != NULL)) { 
    cmd = dlsym(m->fl, "response");
    cmd(0);
    c_part(a->parsevars->args[1], "Cannot join");
  }
}

void s_bannedfromchan (struct arm *a) {
  struct module *m; 
  void (*cmd)();
  
  if(strcasecmp(a->parsevars->args[1], HOMECHAN) == 0) return; // Ignore homechan

  if(a->type == 40 && ((m = findmodule("Request")) != NULL)) { 
    cmd = dlsym(m->fl, "response");
    cmd(0);
    c_part(a->parsevars->args[1], "Cannot join");
  } 
#ifdef L
  else 
    { 
      l_clearbans(findchannel(a->parsevars->args[1]));
    }
#endif
}

#ifdef Q_AUTOAUTH
void s_qauth (struct arm *a) {
  char auth[NICKLEN];
  char query[MAX_QUERY];
  struct activeuser *u;
  struct aculink *aculink;
  char *esauth;
  char *textauth;

  /* Numeric 330
   * lain-Syntax: <nick> :is authed as <username>
   * asuka-Syntax: <nick> <username> :is authed as
   */

  /* This code should be cleaned up after the asuka->lain merge is complete */
  if(regex_match("is authed as .+", a->parsevars->args[2])) sscanf(a->parsevars->args[2], "is authed as %s", auth);
  else strncpy(auth, a->parsevars->args[2], NICKLEN);

#ifdef DEBUG
  printf("Got WHOIS_QAUTH for: %s Handle: %s\n", a->parsevars->args[1], auth);
#endif
  u = findauser(a->parsevars->args[1]);

  if (u == NULL || u->auth >= 30) return;

#ifdef DEBUG
  printf("QQ\n");
#endif
  esauth = escapequery(auth);
  snprintf(query, MAX_QUERY, "SELECT `id`,`auth` FROM `users` WHERE `handle` = '%s'", esauth);
#ifdef DEBUG
  printf("db\n");
#endif
  dbquery(query);
#ifdef DEBUG
  printf("here\n");
#endif
  if(!(row = mysql_fetch_row(res))) {
    EndDbQuery();

    sprintf(query, "INSERT INTO `users` (`handle`) VALUES ('%s')", esauth);
    dbquery(query);

    EndDbQuery();

#ifdef DEBUG
  printf("here\n");
#endif
    sprintf(query, "SELECT `id`,`auth` FROM `users` WHERE handle = '%s'", esauth);
    dbquery(query);
#ifdef DEBUG
  printf("here\n");
#endif
    if(!(row = mysql_fetch_row(res))) {
      privmsg(HOMECHAN, "ERROR: Fatal error, check user database.");

      EndDbQuery();
      free(esauth);

      return;
    }
  }
#ifdef DEBUG  
  printf("afterdb\n");
#endif

  u->userid = atoi(row[0]);
  if(u->auth != 22) u->auth = atoi(row[1]);

  EndDbQuery();

  if(u->auth > 1 && u->auth != 22) {

    textauth = authtotext(u->auth);

#ifdef SAFEHOME
#ifdef MAIN
    /*
    snprintf(query, 512, "INVITE %s " HOMECHAN "\n\r", u->nick);
    putserver (query, firstarm);
    */
    if(u->auth >= LEASTINHOME) {
      snprintf(query, MAX_QUERY, "Welcome %c%s%c, the current access key to %c%s%c is %c%s%c", BOLD, textauth, BOLD, BOLD, HOMECHAN, BOLD, BOLD, homekey, BOLD);
      privmsg(u->nick, query);
    }
#endif
#endif

    setrightmode(HOMECHAN, u->nick);

    sprintf(query, "%s logged in: %s (%s)", textauth, u->nick, auth);
    free(textauth);

    privmsg(HOMECHAN, query);
  }

  strncpy(u->hand, auth, NICKLEN);
#ifdef DEBUG  
  printf("setrightmode\n");
#endif

  aculink = u->firstlink;
  while (aculink != NULL)
    {
      setrightmode(aculink->link->channel->name, aculink->link->user->nick);
      aculink = aculink->next;
    }

  snprintf(query, MAX_QUERY, "UPDATE `users` SET `lastseen` = UNIX_TIMESTAMP() WHERE id = '%d'", u->userid);
  dbquery(query);

  EndDbQuery();
  
  free(esauth);
#ifdef DEBUG
  printf("End of QAUTH\n");
#endif
}

#endif
