/*
 * 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 <assert.h>
#include "../../settings.h"
#include "../../globals.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 activechanuser *acu;
  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 */
  
      acu = findachanuser(a->parsevars->u, a->parsevars->c);

      if (acu == NULL) return; // Strange, he is not here.
      assert(acu != NULL);
      
      if(htm == 0 && a->parsevars->c != NULL && a->parsevars->c->isop == 1) {

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

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

	  if (acu->rows > a->parsevars->c->floodrep && acu->op == 0 && chanuserlevel(a->parsevars->u, a->parsevars->c) == 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, a->parsevars->u);

	      return;
	    } else if (acu->warned == 1) {
	      /* We bankick him, haha */
	      
	      sprintf(hostmask, "%s@%s", a->parsevars->u->username, a->parsevars->u->hostname);
	      sprintf(tmp, "Violated channel flooding rules and ignored warning. Banned for five minutes");

	      addban(a->parsevars->c, hostmask, tmp, 0, time(NULL)+300, a->parsevars->u, tmp, a->parsevars->u->userid, 1);

	      return;
	    }
	  }
	}

	/* Advertise check */
	if (a->parsevars->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->u, a->parsevars->c) == 0 && acu->op == 0 && irc_strcmp(tmp, a->parsevars->c->name) != 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, a->parsevars->u);

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

	      sprintf(hostmask, "%s@%s", a->parsevars->u->username, a->parsevars->u->hostname);
	      sprintf(tmp, "Violated channel advertisation rules and ignored warning. Banned for five minutes");
	      
	      addban(a->parsevars->c, hostmask, tmp, 0, time(NULL)+300, a->parsevars->u, tmp, a->parsevars->u->userid, 1);
	    }
	  }
	}
      }

      /* 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): %s", a->parsevars->sender, a->nick, 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 command.
 */

void s_ctcp (struct arm *a)
{
  char msg[512];
  if (strncasecmp (a->parsevars->args[1], "\1VERSION", 8) == 0)
    {
      ctcpreply (a->parsevars->sender, "VERSION " CTCP_VERSION_REPLY, a);
#ifdef DEBUG
      printf("ctcpreply\n");
#endif
    }
  else if (strncasecmp (a->parsevars->args[1], "\1PING", 5) == 0)
    {
      snprintf(msg, 512, "NOTICE %s:\1PING %s\n\r", a->parsevars->sender, a->parsevars->args[1]+6);
      putserver(msg, 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): %s", a->parsevars->sender, a->nick, a->parsevars->args[1]);
      if(a->parsevars->args[1][0] != '[' && a->parsevars->args[1][1] != '#') privmsg(HOMECHAN, msg);
#ifdef L
      if(strcmp(a->parsevars->sender, L_NICK) == 0 && a->parsevars->args[1][0] == '#') CheckLWhoaamiRow(a, a->parsevars->args[1]);
#endif
    }
#endif

  return;
}

void s_nick (struct arm *a)
{
  // char channel[255]; #saltlake2002 haxx
   
  strncpy (a->parsevars->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)
{
  char msg[512];
  struct activechanuser *acu;
  struct activeuser *tmpu;
  int param, direction, i, num;

  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(a->parsevars->c != NULL && a->parsevars->c->bitch == 1 && a->parsevars->c->isop == 1) {
	    if(direction == 1) {
		  
	      if(chanuserlevel(a->parsevars->u, a->parsevars->c) >= CHAN_MASTER || strcasecmp(a->nick, a->parsevars->sender) == 0) { 
		strcpy(a->parsevars->c->key, a->parsevars->args[num]);
		dbchanmode(a->parsevars->c->id, "key", a->parsevars->args[num]);
	      } else {
		
		snprintf(msg, 512, "MODE %s -k %s\r\n", a->parsevars->args[0], a->parsevars->args[num]);
		putserver(msg, a->parsevars->c->arm);
		
		say(a->parsevars->sender, "Only masters or higher can set key in this channel.", a, a->parsevars->u);
	      } 
	    } else {
	      if(chanuserlevel(a->parsevars->u, a->parsevars->c) >= CHAN_MASTER || strcasecmp(a->nick, a->parsevars->sender) == 0) { 
		strcpy(a->parsevars->c->key, "");
		dbchanmode(a->parsevars->c->id, "key", "");
	      } else {
		snprintf(msg, 512, "MODE %s +k %s\r\n", a->parsevars->args[0], a->parsevars->c->key);
		putserver(msg, a->parsevars->c->arm);
			
		say(a->parsevars->sender, "Only masters or higher can remove key in this channel.", a, a->parsevars->u);
	      }
	    }
	  }
	  if(a->parsevars->c != NULL) {
	    if(direction == 1) {
	      
	      strcpy(a->parsevars->c->key, a->parsevars->args[num]);
	      dbchanmode(a->parsevars->c->id, "key", a->parsevars->args[num]);
	    } else {
	      strcpy(a->parsevars->c->key, "");
	      dbchanmode(a->parsevars->c->id, "key", "");
	    }
	  } else
#ifdef SAFEHOME
	    {
	      if(direction == 1 && a == firstarm) {
		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); /* No need anymore */
#endif
	      /* Set right channel modes */
	      if(a->parsevars->c != NULL) a->parsevars->c->isop = 1;
	      else return;

	    
	      snprintf(msg, 512, "MODE %s %s", a->parsevars->args[0], a->parsevars->c->modes);
	      if(strcmp(a->parsevars->c->key, "") != 0) {
		strcat(msg, "+k ");
		strcat(msg, a->parsevars->c->key);
	      }
	      strcat(msg, "\n\r");
	      putserver(msg, a->parsevars->c->arm);
		
	      // Give out right modes
	      acu = firstacu;
	      while (acu != NULL)
		{
		  if(acu->channel == a->parsevars->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(acu, acu->user); 
			}
		  }
		  acu = acu->next;
		}
		
	    } else {
	      if(a->parsevars->c != NULL) a->parsevars->c->isop = 0;
 
	      if((acu = findachanuser(a->parsevars->u, a->parsevars->c)) != NULL) acu->op = 0;
	      
	      if(chanuserlevel(a->parsevars->u, a->parsevars->c) < CHAN_OWNER) {
		
		/*
		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 Q
	      if(a->parsevars->c != NULL && a->parsevars->c->service == 'Q') q_getop(a->parsevars->c);
#ifdef L
	      else if(a->parsevars->c != NULL && a->parsevars->c->service == 'L') l_getop(a->parsevars->c);
#endif
#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]);
	    }
	  }
	  /* Reauth-check unauthed users on L/Q op */
#if defined(Q) && !defined(L)
	  if(direction == 1 && a->parsevars->u == Qu) if((tmpu = findauser(a->parsevars->args[num])) != NULL && tmpu->auth == UNAUTHED) add(tmpu);
#endif
#if defined(L)
	  if(direction == 1 && (a->parsevars->u == Qu || a->parsevars->u == Lu)) if((tmpu = findauser(a->parsevars->args[num])) != NULL && tmpu->auth == UNAUTHED) add(tmpu);	       
#endif
	  if(a->parsevars->c != NULL && a->parsevars->c->bitch == 1 && a->parsevars->c->isop == 1 && strcmp(a->nick, a->parsevars->sender) != 0) {
	    if(direction == 1) {

	      if(chanuserlevel(a->parsevars->u, a->parsevars->c) < CHAN_MASTER && strcasecmp(a->nick, a->parsevars->args[num]) != 0 && (strcasecmp(a->parsevars->sender, a->nick) != 0 && a->parsevars->isserver == 0)) {
		deop(a->parsevars->args[0], a->parsevars->args[num]);
	      }
	    } else {
	      if(chanuserlevel(a->parsevars->u, a->parsevars->c) < CHAN_MASTER && a->parsevars->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(findauser(a->parsevars->args[num]), a->parsevars->c);
	  if(acu != NULL) {
	    if(direction == 1) acu->op = 1;
	    else acu->op = 0;
	  }

	  ++num;	      
	  param++;
	  break;
	case 'v':
	  acu = findachanuser(findauser(a->parsevars->args[num]), a->parsevars->c);
	  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(a->parsevars->c != NULL && a->parsevars->c->bitch == 1 && a->parsevars->c->isop == 1) {
	    if(direction == 1) {
		  
	      if(chanuserlevel(a->parsevars->u, a->parsevars->c) < CHAN_MASTER && strcasecmp(a->nick, a->parsevars->sender) != 0) { 
		
		snprintf(msg, 512, "MODE %s -i\r\n", a->parsevars->args[0]);
		putserver(msg, a->parsevars->c->arm);

		say(a->parsevars->sender, "Only masters or higher can set invite on this channel.", a, a->parsevars->u);
		
		} 
	    } else {
	      if(chanuserlevel(a->parsevars->u, a->parsevars->c) < CHAN_MASTER  && strcasecmp(a->nick, a->parsevars->sender) != 0) { 
		
		snprintf(msg, 512, "MODE %s +i\r\n", a->parsevars->args[0]);
		putserver(msg, a->parsevars->c->arm);
		
		say(a->parsevars->sender, "Only masters or higher can remove invite on this channel.", a, a->parsevars->u);
	      }
	    }
	  }
	  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;
#ifdef MAIN
  int helpersonline;
  char helpersn[50], techsn[50], mtechsn[50], queuen, queuea[4];
  struct generalinfo ginfo;
#endif
  struct activechanuser *cacu;
  char msg[512], *authtotexttmp;
  /* Module dependent vars */
#ifdef MODULE_op
#ifndef MODULE_GEN_s_join_M
#define MODULE_GEN_s_join_M
  struct module *m;
#endif
  int (*opjoin)(struct channel *c, struct activeuser *u);
#endif

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

  cacu = addachanuser(a->parsevars->u, a->parsevars->c);
  if(cacu == 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 = findarmindb(a->parsevars->sender)) != 0) */
	if(a->parsevars->u->auth <= NORMAL) a->parsevars->u->auth = findarm(a->parsevars->sender)->type;
	setrightmode(cacu, a->parsevars->u);
	return;
      }
#ifdef SAFEHOME
      if(a->parsevars->u->auth < LEASTINHOME) {
	kick(channel, a->parsevars->sender, "You are not allowed in this channel");
	printf("Warning: Home channel security compromised.\n");
	securehome();
      }
#endif
    }
    
    /* Check if user is banned */
    if(htm == 0) BannedUser(a->parsevars->c, a->parsevars->u);
    
    /* Make sure to give the user the right modes */
    if (a->parsevars->c != NULL && a->parsevars->c->isop == 1) setrightmode(cacu, a->parsevars->u);
    else if (a->parsevars->c == NULL) setrightmode(cacu, a->parsevars->u);

#ifdef MODULE_op
    m = findmodule("Op");
    if(m != NULL) {
      opjoin = dlsym(m->fl, "opjoin");
      if(opjoin(a->parsevars->c, a->parsevars->u)) return;
    }   
#endif

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

    /* Check onjoin */
    if (a->parsevars->c != NULL && strcmp(a->parsevars->c->onjoin, "") != 0 && userlevel(a->parsevars->u) < 30) {
      STR_replace_c (a->parsevars->c->onjoin, "%n", a->parsevars->sender, ret);
      sprintf(msg, "%i", a->parsevars->c->peak);
      STR_replace_c (ret, "%p", msg, ret);
      /* #ifdef CNOTICE
      cnotice(a->parsevars->sender, ret);
      #else */
      say(a->parsevars->sender, ret, a, a->parsevars->u);
      //#endif
    }

#ifdef MAIN
    if(a->id == 1) {
      
      ginfo = GetGeneralInfo(1, 1, 0, 1, 1, 1, 1);

      helpersonline = ginfo.helpersonline + ginfo.queueworkersonline;

      authtotexttmp = authtotext(HELPER);
      strcpy(helpersn, authtotexttmp);
      if(helpersonline > 1 || helpersonline == 0) strcat(helpersn, "s");
      Free(authtotexttmp);

      authtotexttmp = authtotext(TECHNICIAN);
      strcpy(techsn, authtotexttmp);
      if(ginfo.techsonline > 1 || ginfo.techsonline == 0) strcat(techsn, "s");
      Free(authtotexttmp);

      authtotexttmp = authtotext(MASTER_TECHNICIAN);
      strcpy(mtechsn, authtotexttmp);
      if(ginfo.mtechsonline > 1 || ginfo.mtechsonline == 0) strcat(mtechsn, "s");
      Free(authtotexttmp);

      if(ginfo.queuestatus > 1 || ginfo.queuestatus == 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%i%%%c of our total capacity. There are %c%d%c %s, %c%d%c %s and %c%d%c %s online. There %s %c%i%c item%c in queue.", BOLD, ginfo.connectedarms, BOLD, BOLD, ginfo.arms, BOLD, BOLD, ginfo.channels, BOLD, BOLD, ginfo.percentused, BOLD, BOLD, helpersonline, BOLD, helpersn, BOLD, ginfo.techsonline, BOLD, techsn, BOLD, ginfo.mtechsonline, BOLD, mtechsn, queuea, BOLD, ginfo.queuestatus, BOLD, queuen);
#ifdef CNOTICE
      cnotice(a->parsevars->sender, ret);
#else
      say(a->parsevars->sender, ret, a, arm->parsevars->u);
#endif

    }
#endif
    if(a->parsevars->c != NULL && a->parsevars->c->greet == 1 && (authtotexttmp = chanusergreet(a->parsevars->u, a->parsevars->c)) != NULL) privmsg(channel, authtotexttmp);
    
    else if(a->parsevars->c != NULL && a->parsevars->u->auth >= HELPER && a->parsevars->u->auth < BOT_NORMAL && a->parsevars->u->auth != IRC_OPERATOR && a->parsevars->c->greet == 1 && strcasecmp(a->parsevars->sender, "T") != 0) {
      /* Oki, staff greet time */
      authtotexttmp = authtotext(a->parsevars->u->auth);
      
      sprintf(ret, "%s %s entered the channel.", BOTHOUSE, authtotexttmp); 
      privmsg(channel, ret);

      Free(authtotexttmp);
    }

    OnJoinVoteMsg(a->parsevars->c, a->parsevars->u); /* Msg vote msg if needed */

    if(htm == 0 && a->parsevars->c != NULL && a->parsevars->c->peak != 0) {

      i = UsersOnChannelCount(a->parsevars->c);
         
      if(i > a->parsevars->c->peak) {
	
	a->parsevars->c->peak = i;
	sprintf(msg, "%i", i);
	dbchanmode(a->parsevars->c->id, "peak", msg);
	
	sprintf(msg, "New channel peak! (%c%i%c) by: %s", BOLD, i, BOLD, a->parsevars->sender); 
	privmsg(a->parsevars->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);
 */
    } else {
 
      if(strcasecmp(channel, HOMECHAN) == 0 && userlevel(a->parsevars->u) <= NORMAL && findarm(a->parsevars->sender) != NULL) a->parsevars->u->auth = findarm(a->parsevars->sender)->type;

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

      if(a->parsevars->c != NULL) {
	a->parsevars->c->ison = 1;
	who(a->parsevars->c);
      }
      else putserver("WHO " HOMECHAN " %uhfcnua\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(findachanuser(a->parsevars->u, a->parsevars->c), a->parsevars->u);
}

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

void s_kill (struct arm *a)
{
  linkbreak(a);
}

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

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

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

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

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

void s_kick (struct arm *a)
{
  char msg[512];
  struct activeuser *u = NULL;

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

      if(a->parsevars->c == NULL) return;

      OutOfChannel(a->parsevars->c);

      /* Some cheeky sod just kicked us! */   
      if(chanuserlevel(a->parsevars->u, a->parsevars->c) < CHAN_OWNER) {
	/*
	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
    {
      u = findauser(a->parsevars->args[1]);
      delachanuser(findachanuser(u, a->parsevars->c), u);
    }
}

void s_whoreply (struct arm *a) {
  /* <channel> <user> <host> <server> <nick> <H|G>[*][@|+] :<hopcount> <real name> */
  struct channel *c;
  struct activechanuser *acu;
  struct activeuser *u;
  
  char nick[NICKLEN] = "";
  char username[USERLEN] = "";
  char hostname[HOSTLEN] = "";
#ifdef Q_AUTOAUTH
  char auth[NICKLEN] = "";
#endif

  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[4]);
#endif

  strncpy(username, a->parsevars->args[2], USERLEN);
  strncpy(hostname, a->parsevars->args[3], HOSTLEN);
  strncpy(nick, a->parsevars->args[4], NICKLEN);
#ifdef Q_AUTOAUTH
  strncpy(auth, a->parsevars->args[6], NICKLEN);
#endif

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

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

  acu = addachanuser(u, c);

  if(acu != NULL) {
    if(a->parsevars->args[5][1] == '@' || (a->parsevars->args[5][1] == '*' && a->parsevars->args[5][2] == '@')) acu->op = 1;
    else if(a->parsevars->args[5][1] == '+' || (a->parsevars->args[5][1] == '*' && a->parsevars->args[5][2] == '+')) acu->voice = 1;
#ifdef Q
    if(u == Qu) {
      if(c->service != 'Q') {
	c->service = 'Q';
	dbchanmode(c->id, "service", "Q");
#ifdef DEBUG
	printf("New service set for channel: %s. Service: Q\n", c->name);
#endif
      }
    }
#ifdef L
    else if(u == Lu) {
      if(c->service != 'L') {
	c->service = 'L';
	dbchanmode(c->id, "service", "L");
#ifdef DEBUG
	printf("New service set for channel: %s. Service: L\n", c->name);
#endif
      }
    }
#endif
#endif

  } // else privmsg(HOMECHAN, "WRN, acu == NULL");
#ifdef Q_AUTOAUTH
  if(u->auth == UNAUTHED && auth[0] != '0') AuthUser(u, auth);
#endif
}

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

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

  if(c != NULL && c->isop == 1) {
    
    snprintf(msg, 512, "MODE %s %s", a->parsevars->args[1], c->modes);
    if(strcmp(c->key, "") != 0) {
      strcat(msg, "+k ");
      strcat(msg, c->key);
    }
    strcat(msg, "\n\r");
    putserver(msg, 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; 
  struct channel *c;
  void (*cmd)();
  
  c = findchannel(a->parsevars->args[1]);

  if(a->type == 40 && ((m = findmodule("Request")) != NULL)) { 
    cmd = dlsym(m->fl, "response");
    cmd(0);
    c_part(a->parsevars->args[1], "Cannot join");
  }
#ifdef Q
  else if(c != NULL) 
    {       
      if(c->service == 'Q') q_invite(c);
#ifdef L
      else if(c->service == 'L') l_invite(c);
#endif
    }
#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)();
  struct channel *c = findchannel(a->parsevars->args[1]);
  
  if(a->type == 40 && ((m = findmodule("Request")) != NULL)) { 
    cmd = dlsym(m->fl, "response");
    cmd(0);
    c_part(a->parsevars->args[1], "Cannot join");
  }

#ifdef Q
  else if(c != NULL) 
    {       
      if(c->service == 'Q') q_invite(c);
#ifdef L
      else if(c->service == 'L') l_invite(c);
#endif
    }
#endif
}

void s_bannedfromchan (struct arm *a) {
  struct module *m; 
  struct channel *c;
  void (*cmd)();
  
  if((c = findchannel(a->parsevars->args[1])) == NULL) return;


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

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

  /* 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;

  AuthUser(u, auth);
}

#endif
