#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include "global.h"
#include "constants.h"
#include "numeric.h"
#include "window.h"
#include "command.h"
#include "chan.h"

extern char g_from[MAXNICKLEN], g_join[MAXNICKLEN], g_public[MAXNICKLEN];
extern char date[], userhost[], flush_nick[], g_invite[MAXLEN];
extern int AUTO_WHOWAS, show_end_of_msgs, send_ignore_message;
extern int beep_when_away, flushing, old_display, display;
extern int names_min, names_max, names_public, names_private;
extern int list_min, list_max, list_public, list_private;
extern int channel_name_width, getpid();
extern win_ptr awins, outwin;

server_ptr SRV = NULL;

/* ------------------------------------------------------------------------ */
extern void remove_from_chan();
extern void clear_redirect(server_ptr srv);
/* ------------------------------------------------------------------------ */
int strncasecmp(char *t1, char *t2, int num)
{
  int loop = 0;

  if (t1==NULL) return (t2!=NULL);  
  if (t2==NULL) return -1;

  while ((*t1) && (*t2) && (num>0))
  {
    if (tolower(*t1) != tolower(*t2))
    {
      if (tolower(*t1) < tolower(*t2)) return -1;
      return 1;
    } else {
       t1++; t2++;
    }
    num--;
  }
  if (!num) return 0;
  if (*t1==0)
    if (*t2==0) return 0;
    else return -1;
  return 1;
}

/* ------------------------------------------------------------------------ */
int strcasecmp(char *t1, char *t2)
{
  int good = 1;
  int comp;
  
  if (!t1) return (t2?1:0);
  if (!t2) return -1;
  while ((*t1) && (*t2))
  {
    if (tolower(*t1) != tolower(*t2))
      if (tolower(*t1) > tolower(*t2)) return 1;
      else return -1;
    t1++; t2++;
  }
  if (*t1 == 0)
    if (*t2 == 0) return 0;
    else return -1;
  return 1;
}

/* ------------------------------------------------------------------------ */
/* This is only valid because we can only message from a server at any      */
/* given point in time. If this changes, we will have problems. -- dough    */
/* ------------------------------------------------------------------------ */
char on_line[MAXLEN];
/* ------------------------------------------------------------------------ */
/* Received an error from the server - what do we do about it?!             */
/* ------------------------------------------------------------------------ */
void han_error(split *temp)
{
  say("*** ERROR - %s %s %s %s %s %s %s %s",
                temp->p[0], temp->p[1], temp->p[2], temp->p[3], temp->p[4],
                temp->p[5], temp->p[6], temp->text);
}

/* ------------------------------------------------------------------------ */
void han_wallops(split *temp)
{
  if (strcasecmp(temp->from, SRV->server_name)!= 0)
    say("!%s! %s", temp->from, temp->text);
  else say("%s", temp->text);
}

/* ------------------------------------------------------------------------ */
void han_join(split *temp)
{
  char *rest, *chan;
  win_ptr win = NULL, oldwin;

  chan = temp->text;
  if (strcasecmp(temp->from, SRV->nick) == 0) {
    join_channel(SRV, chan);
    (void)new_send(SRV, "MODE %s\n", chan);
  } else add_users_to_chan(SRV->chan_list, chan, temp->from);

  (void)get_chan_num(SRV->chan_list, chan, &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);

  (void)strcpy(g_join, temp->from);
  (void)sprintf(on_line, "%s %s", temp->from, chan);
  if (!ignore(temp->from, temp->userhost, CRAP) && 
      !handle_on(o_join, on_line, 0))
    say("--- %s (%s) has joined channel %s.", temp->from, temp->userhost, chan);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */
void han_part(split *temp)
{
  win_ptr window_num = NULL, oldwin;

  remove_from_chan(SRV->chan_list, temp->p[0], temp->from);
  if (strcasecmp(temp->from, SRV->nick) == 0)
    window_num = (win_ptr)leave_channel(SRV, temp->p[0]);
  else
    get_chan_num(SRV->chan_list, temp->p[0], &window_num);
  if (!window_num) window_num = type_winget(SRV, CRAP);
  oldwin = set_outwin(window_num);

  (void)sprintf(on_line, "%s %s", temp->from, temp->p[0]);
  if (!ignore(temp->from, temp->userhost, CRAP) && 
      !handle_on(o_leave, on_line, 0))
    say("*** %s has left channel %s.", temp->from, temp->p[0]);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_kick(split *temp)
{
  win_ptr win, oldwin;

  remove_from_chan(SRV->chan_list, temp->p[0], temp->p[1]);
  (void)get_chan_num(SRV->chan_list, temp->p[0], &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);
  if (strcasecmp(temp->p[1], SRV->nick) == 0)
    (void)leave_channel(SRV, temp->p[0]);

  if (!ignore(temp->from, temp->userhost, CRAP))
    say("*** %s has been kicked off channel %s by %s (%s)",
        temp->p[1], temp->p[0], temp->from, temp->text);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void ctcp_action(temp, str)
  split *temp;
  char *str;
{
  int oldlevel;
  char msg[MAXLEN], *walk;
  win_ptr index, win = NW, oldwin;

  walk = temp->text;
  (void)grab_word(&walk, ' ', msg);  /* Grab the word ACTION */
  if (ignore(temp->from, temp->userhost, ACTIONS)) return;
  (void)sprintf(on_line, "%s %s %s %s", temp->from, temp->p[0], msg, walk);
  if (is_chan(temp->p[0]))
    (void)get_chan_num(SRV->chan_list, temp->p[0], &win);
  else
    for (index = awins; index; index = index->next)
      if ((index->server == SRV) &&
          (strcasecmp(index->query, temp->from) == 0)) win = index;
  if (!win) win = type_winget(SRV, ACTIONS);
  oldwin = set_outwin(win);
  if (!handle_on(o_action, on_line, 0)) {
    oldlevel = set_loglevel(ACTIONS);
    say("* %s %s", temp->from, str);
    set_loglevel(oldlevel);
  }
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */
extern logdcc_request();
void ctcp_dcc(temp, rest)
  split *temp;
  char *rest;
{
  char type[MAXLEN], file[MAXLEN], host[MAXLEN];
  unsigned long hostid;
  unsigned short port;

  (void)grab_word(&rest, ' ', type);   /* The request type */
  (void)grab_word(&rest, ' ', file);   /* Paramater 1 - type dependant */
  (void)grab_word(&rest, ' ', host);   /* host id in network byte order */

  if (*host) hostid = atol(host);
  port = atoi(rest);                    /* Port - host byte order */
  if (strcmp(type, "SEND") == 0)
    (void)logdcc_request(hostid, port, temp->from, file, DCC_INFILE, NULL);
  else if (strcmp(type, "CHAT") == 0)
    (void)logdcc_request(hostid, port, temp->from, file, DCC_CHAT, NULL);
  else
    say("*** DCC %s request from %s: %s", type, temp->from, file);
}

/* ------------------------------------------------------------------------ */

void msg(temp, to, msg)
  split *temp;
  char *to, *msg;
{
  char *rest, format[20];
  win_ptr index, win = NW, oldwin;
  int oldlevel;

  if (ignore(temp->from, temp->userhost, MSGS))
  {
    if (send_ignore_message)
      if (strcasecmp(to, SRV->nick) == 0)
        (void)new_send(SRV, "NOTICE %s :%s is ignoring you\n", temp->from, SRV->nick);
    return;
  }

  (void)strcpy(g_from, temp->from);
  (void)sprintf(on_line, "%s %s", temp->from, msg);

  for (index=awins;index;index=index->next)
    if ((index->server == SRV) &&
        (strcasecmp(index->query, temp->from) == 0)) win = index;
  if (!win) win = type_winget(SRV, MSGS);
  oldwin = set_outwin(win);
  if (!handle_on(o_msg, on_line, 0)) {
    if (SRV->away) {
      (void)strcpy(format, "*%s* %s <%s>");
      if (beep_when_away) (void)strcat(format, "\007");
    } else
      (void)strcpy(format, "*%s* %s");
    oldlevel = set_loglevel(MSGS);
    say(format, temp->from, msg, date);
    set_loglevel(oldlevel);
  }
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */
extern int user_on_chan(unsigned int *, char *, char *);
/* ------------------------------------------------------------------------ */
void public(temp, msg)
  split *temp;
  char *msg;
{
  win_ptr win = NW, oldwin = NW;
  int oldlevel;

  if (ignore(temp->from, temp->userhost, PUBLIC)) return;

  (void)strcpy(g_public, temp->from);
  (void)get_chan_num(SRV->chan_list, temp->p[0], &win);
  oldlevel = set_loglevel(PUBLIC);
  (void)sprintf(on_line, "%s %s %s", temp->from, temp->p[0], msg);
  if (win != NW) {
    oldwin = set_outwin(win);
    if (!handle_on(o_public, on_line, 0))
      if (user_on_chan(SRV->chan_list, temp->p[0], temp->from))
        say("<%s> %s", temp->from, msg);
      else
        say("(%s/%s) %s", temp->from, temp->p[0], msg);
  } else {
    win = type_winget(SRV, PUBLIC);
    oldwin = set_outwin(win);
    if (!handle_on(o_public_other, on_line, 0))
      say("<%s\\%s> %s", temp->from, temp->p[0], msg);
  }
  set_loglevel(oldlevel);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_ctcp(temp, to, rest)
  split *temp;
  char *to, *rest;
{
  char type[MAXLEN];

  (void)sprintf(on_line, "%s %s %s", temp->from, temp->p[0], rest);
  (void)grab_word(&rest, ' ', type);

  if (strcmp(type, "DCC")!=0)
    if (handle_on(o_ctcp, on_line, 0)) return;

  if (strcmp("ACTION", type) == 0)
    ctcp_action(temp, rest);  /* Get rid of the space */
  else if (strcmp("CLIENTINFO", type) == 0)
    (void)new_send(SRV,
               "NOTICE %s :\001CLIENTINFO ACTION CLIENTINFO DCC VERSION\001\n",
             temp->from);
  else if (strcmp("DCC", type) == 0) {
    ctcp_dcc(temp, rest);
    if (handle_on(o_ctcp, on_line, 0)) return;
  } else if (strcmp("ERRMSG", type) == 0) { }
  else if (strcmp("FINGER", type) == 0)
    (void)new_send(SRV, "NOTICE %s :\001FINGER not supported\001\n", temp->from);
  else if (strcmp("PID", type) == 0)
    (void)new_send(SRV, "NOTICE %s :\001PID %X\001\n", temp->from, getpid(0));
  else if (strcmp("PING", type) == 0)
    (void)new_send(SRV, "NOTICE %s :\001PING %s\001\n", temp->from, rest);
  else if (strcmp("VERSION", type) == 0)
    (void)new_send(SRV, "NOTICE %s :\001VERSION Dough's vms client:%s:VMS\001\n",
             temp->from, VERSION);
/*
  else
    (void)new_send(SRV, "NOTICE %s :\001ERRMSG %s :unknown query\001\n",
                   temp->from, type);
*/
}

/* ------------------------------------------------------------------------ */

#define X_DELIM   1
#define X_QUOTE  '\\'

void han_privmsg(temp)
  split *temp;
{
  char *text, privmsg[MAXLEN], *walk, ctcp[MAXLEN];
  int len, c_ind = 0, c_on = FALSE, c_priv = 0, num, done = FALSE;

  (void)get_variable("NO_CTCP_FLOOD", &num, NULL);
  for (walk = temp->text; *walk; walk++) {
    if (*walk == X_DELIM) {
      if (c_on) {
        ctcp[c_ind] = 0;
        if ((num==1) && (!done)) han_ctcp(temp, temp->p[0], ctcp);
        done = TRUE;
        c_ind = 0;
      }
      c_on = !c_on;
    } else {
/*      if (*walk == X_QUOTE) walk++; /**/
      if (c_on) ctcp[c_ind++] = *walk;
      else privmsg[c_priv++] = *walk;
    }
  }
  if (c_priv == 0) {
    return;
  }
  privmsg[c_priv] = 0;
  if is_chan(temp->p[0])
    public(temp, privmsg);
  else
    msg(temp, temp->p[0], privmsg);
}

/* ------------------------------------------------------------------------ */

void han_notice(temp)
  split *temp;
{
  char templine[MAXLEN], ctcp[MAXLEN], notice[MAXLEN];
  char *text, *walk;
  int c_ind = 0, c_notice = 0, c_on = FALSE, oldlevel;
  win_ptr index, win = NW, oldwin;

  for (walk = temp->text; *walk; walk++) {
    if (*walk == X_DELIM) {
      if (c_on) {
        ctcp[c_ind] = 0;
        text = ctcp;
        (void)sprintf(on_line, "%s %s", temp->from, text);
        (void)grab_word(&text, ' ', templine);
        if (!handle_on(o_ctcp_reply, on_line, 0)) {
          if (strcmp(templine, "PING") == 0) 
            say("CTCP PING reply from %s: %d seconds",
                temp->from, time(NULL) - atoi(text));
          else
            say("*** CTCP %s reply from %s:%s", templine, temp->from, text);
        }
        c_ind = 0;
      }
      c_on = !c_on;
    } else {
/*      if (*walk == X_QUOTE) walk++;/**/
      if (c_on) ctcp[c_ind++] = *walk;
      else notice[c_notice++] = *walk;
    }
  }
  if (c_notice == 0) return;
  notice[c_notice] = 0;

  if (ignore(temp->from, temp->userhost, NOTICES)) return;
  if (temp->userhost[0] == 0) {
     win = type_winget(SRV, NOTICES);
     oldwin = set_outwin(win);
    (void)sprintf(on_line, "%s %s", temp->from, notice);
    if (!handle_on(o_server_notice, on_line, 0)) {
      oldlevel = set_loglevel(NOTICES);
      if (strcasecmp(SRV->server_name, temp->from) == 0)
        say("%s", notice);
      else
        say("\026%s\026 %s", temp->from, notice);
      set_loglevel(oldlevel);
    }
  } else {
    (void)sprintf(on_line, "%s %s", temp->from, notice);
    if (is_chan(temp->p[0]))
      (void)get_chan_num(SRV->chan_list, temp->p[0], &win);
    else
      for (index=awins; index; index = index->next)
        if ((index->server == SRV) &&
            (strcasecmp(index->query, temp->from) == 0)) win = index;
    if (!win) 
      win = type_winget(SRV, NOTICES);
    oldwin = set_outwin(win);
    if (!handle_on(o_notice, on_line, 0)) {
      oldlevel = set_loglevel(NOTICES);
      say("\026%s\026 %s", temp->from, notice);
      set_loglevel(oldlevel);
    }
  }
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_ping(split *temp)
{
  (void)new_send(SRV, "PONG %s\n", temp->text);
}

/* ------------------------------------------------------------------------ */

void han_whois(split *temp, int IS)
{
  say("*** %s\017 %s %s\017@%s (%s\017)", temp->p[1],
      IS?"is":"was", temp->p[2], temp->p[3], temp->text);
}

/* ------------------------------------------------------------------------ */

void han_whochan(temp)
  split *temp;
{
  say("*** on channels: %s", temp->text);
}

/* ------------------------------------------------------------------------ */

void han_whoserv(temp)
  split *temp;
{
  say("*** on irc via server %s (%s)", temp->p[2], temp->text);
}

/* ------------------------------------------------------------------------ */
extern void built_tdiff(char *, char *);
/* ------------------------------------------------------------------------ */
void han_whoidle(temp)
  split *temp;
{
  char str[MAXLEN];
  built_tdiff(temp->p[2], str);
  say("*** %s has been idling for %s.", temp->p[1], str);
}

/* ------------------------------------------------------------------------ */

void han_whoircop(temp)
  split *temp;
{
  say("*** %s %s", temp->p[1], temp->text);
}

/* ------------------------------------------------------------------------ */

void han_server_message(temp)
  split *temp;
{
  say("*** %s: %s", temp->p[1], temp->text);
}

/* ------------------------------------------------------------------------ */

void han_noparams(temp)
  split *temp;
{
  say("*** %s", temp->text);
}

/* ------------------------------------------------------------------------ */

void han_oneparam(temp)
  split *temp;
{
  win_ptr win = NULL, oldwin;
  (void)get_chan_num(SRV->chan_list, temp->p[1], &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);
  say("*** %s: %s", temp->p[1], temp->text);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_twoparams(temp)
  split *temp;
{
  say("*** %s %s: %s", temp->p[1], temp->p[2], temp->text);
}

/* ------------------------------------------------------------------------ */

void han_nonick(temp)
  split *temp;
{
  say("*** %s: %s", temp->p[1], temp->text);
  if (AUTO_WHOWAS) (void)new_send(SRV, "WHOWAS %s 1\n", temp->p[1]);
}

/* ------------------------------------------------------------------------ */
void user_chan_nick();
/* ------------------------------------------------------------------------ */
void han_nick(temp)
  split *temp;
{
  char chan[MAXLEN];
  win_ptr win = NW, oldwin = NW;

  user_chan_nick(SRV->chan_list, temp->from, chan, 3);
  if (*chan) (void)get_chan_num(SRV->chan_list, chan, &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);

  if (strcmp(temp->from, SRV->nick) == 0)
  {
    say("--> You are now known as %s.", temp->text);
    (void)strcpy(SRV->nick, temp->text);
    updatestatwin();
  }
  else
    say("--> %s is now known as %s.", temp->from, temp->text);

  (void)sprintf(on_line, "%s %s", temp->from, temp->text);
  user_chan_nick(SRV->chan_list, temp->from, temp->text, 1);
  handle_on(o_nickname, on_line, 0); 
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_def(split *temp)
{
  if (ignore(temp->from, temp->userhost, CRAP)) return;
  say("%s %s %s %s %s %s %s %s %s",
      temp->from, temp->userhost, temp->command, temp->p[0],
      temp->p[1], temp->p[2], temp->p[3], temp->p[4], temp->text);
}

/* ------------------------------------------------------------------------ */

void han_away(temp)
  split *temp;
{
  say("*** %s is away: %s", temp->p[1], temp->text);
}

/* ------------------------------------------------------------------------ */

void han_invite(temp)
  split *temp;
{
  strcpy(g_invite, temp->text);
  if (ignore(temp->from, temp->userhost, CRAP)) return;
  (void)sprintf(on_line, "%s %s", temp->from, temp->text);
  if (handle_on(o_invite, on_line, 0)) return; 
  say("*** You have been invited to channel \"%s\" by %s.", temp->text,
      temp->from);
}

/* ------------------------------------------------------------------------ */

void han_modeis(temp)
  split *temp;
{
  win_ptr win, oldwin;
  (void)get_chan_num(SRV->chan_list, temp->p[1], &win);
  if (!win) win = type_winget(SRV, CRAP);
  else set_chan_mode(SRV->chan_list, temp->p[1], temp->p[2]);
  oldwin = set_outwin(win);
  if (temp->p[2][0] && temp->p[2][1])
    say("*** Mode for channel %s is \"%s\"", temp->p[1], temp->p[2]);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_invited(temp)
  split *temp;
{
  win_ptr win, oldwin;
  (void)get_chan_num(SRV->chan_list, temp->p[2], &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);
  say("*** %s has been invited to %s", temp->p[1], temp->p[2]);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_stats_basic(temp)
  split *temp;
{
  say("*** %s: H: %s N: %s Port: %s Class: %s",
      temp->p[1], temp->p[2], temp->p[3], temp->p[4], temp->p[5]);
}

/* ------------------------------------------------------------------------ */

void han_mode(split *temp)
{
  int args;
  char templine[MAXLEN], mode[MAXLEN];
  win_ptr win, oldwin;

  (void)strcpy(mode, temp->text);
  for (args=1;*(temp->p[args]); args++) {
    (void)strcat(mode, temp->p[args]);
    (void)strcat(mode, " ");
  }
  if (ignore(temp->from, temp->userhost, CRAP)) return;
  (void)sprintf(on_line, "%s %s %s", temp->from, temp->p[0], mode);
  if (!is_chan(temp->p[0]))
    (void)sprintf(templine, "*** Mode change \"%s\" for user %s by %s",
                  mode, temp->p[0], temp->from);
  else if (strlen(temp->from) == 0)
    (void)sprintf(templine, "*** Mode change \"%s\" on channel %s by %s",
                  mode, temp->p[0], temp->userhost);
  else
    (void)sprintf(templine, "*** Mode change \"%s\" on channel %s by %s",
                  mode, temp->p[0], temp->from);
  (void)get_chan_num(SRV->chan_list, temp->p[0], &win);
  if (!win) win = type_winget(SRV, CRAP);
  else set_chan_mode(SRV->chan_list, temp->p[0], mode);
  oldwin = set_outwin(win);
  if (!handle_on(o_mode, on_line, 0))
    say("%s", templine);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */
extern struct userhost_struct userhost_list[MAX_USERHOST];

void han_userhost(temp)
  split *temp;
{
  char *str, nick[MAXLEN], param[MAXLEN], *ret, p1 = '+', p2, user[MAXLEN];
  int loop, len, print = 1;

  str = temp->text;
  len = grab_word(&str, '=', nick);
  if (!len) return;
  if (nick[len-1]=='*') nick[len-1] = 0;
  else p1 = '-';
  p2 = *str++;
  grab_word(&str, '@', user);
  if (flushing) {
    display = old_display;
    flushing = FALSE;
    say("*** Flushing completed.");
    print = 0;
  } else
  sprintf(param, "%s %c %c %s %s", nick, p1, p2, user, str);
  for(loop=0;loop<MAX_USERHOST;loop++)
    if (strcasecmp(userhost_list[loop].nick, nick) == 0) {
      print = 0;
      *userhost_list[loop].nick = 0;
      parse_line(userhost_list[loop].command, param, FALSE, FALSE);
    }
  if (print)
    say("*** %s is %s@%s%s%s", nick, user, str,
        (p1=='+')?" (Is an IRC operator)":"", (p2=='-')?" (Away)":"");
}

/* ------------------------------------------------------------------------ */

void han_join_list(temp)
  split *temp;
{
  char *str;
  int count = 0;
  win_ptr win = NULL, oldwin;

  add_users_to_chan(SRV->chan_list, temp->p[2], temp->text);
  if (*temp->p[2] == '*')  {
    if (!names_private) return;
  } else
   if (!names_public) return;

  str = temp->text;
  while (*str) if (*str++ == ' ') count++;
  if (count < names_min) return;
  if ((count > names_max) && (names_max != -1)) return;
  (void)get_chan_num(SRV->chan_list, temp->p[2], &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);
  say("*** Users on %s: %s", temp->p[2], temp->text);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_quit(temp)
  split *temp;
{
  int gone = FALSE;
  char chan[MAXLEN];
  win_ptr win = NW, oldwin = NW;

  user_chan_nick(SRV->chan_list, temp->from, chan, 2);
  (void)get_chan_num(SRV->chan_list, chan, &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);
  (void)sprintf(on_line, "%s %s", temp->from, temp->text);
  if (handle_on(o_signoff, on_line, 0)) gone = TRUE;
  if (!gone) {
    (void)sprintf(on_line, "%s %s %s", chan, temp->from, temp->text);
    if (handle_on(o_channel_signoff, on_line, 0)) gone = TRUE;
    if (!gone) say("*** Signoff by %s (%s)", temp->from, temp->text);
  }
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */
extern int waiting;

void han_unknown(temp)
  split *temp;
{
  if (strcasecmp(temp->p[1], "WAIT") == 0) waiting = FALSE;
  else if (strcasecmp(temp->p[1], "REDIRECT") == 0)
    clear_redirect(SRV);
}

/* ------------------------------------------------------------------------ */

void han_topic(split *temp)
{
  win_ptr win, oldwin;
  (void)sprintf(on_line, "%s %s %s", temp->from, temp->p[0], temp->text);
  (void)get_chan_num(SRV->chan_list, temp->p[0], &win);
  if (!win) win = type_winget(SRV, CRAP);
  oldwin = set_outwin(win);
  if (!handle_on(o_topic, on_line, 0))
    say("*** %s has changed the topic on channel %s to %s",
        temp->from, temp->p[0], temp->text);
  set_outwin(oldwin);
}

/* ------------------------------------------------------------------------ */

void han_list(split *temp)
{
  int num = 0, loop;
  (void)sprintf(on_line, "%s %s %s %s", temp->from, temp->p[1], temp->p[2],
                temp->text);
  if (handle_on(o_numeric, on_line, RPL_LIST)) return;
  num = atoi(temp->p[2]);
  if (num<list_min) return;
  if ((num>list_max) && (list_max != -1)) return;
  if (*(temp->p[1]) == '*') {
    if (!list_private) return;
  } else if (!list_public) return;
  num = sprintf(on_line, "%*.*s", channel_name_width,channel_name_width,
                temp->p[1]);
  for (loop=num;loop<channel_name_width;loop++) on_line[loop] = ' ';
  on_line[loop] = 0;
  say("%s %-5s %s", on_line, temp->p[2], temp->text);
}

/* ------------------------------------------------------------------------ */
CmdList handle_list[] =
{
 {{"ERROR"},	han_error,	0},
 {{"INVITE"},	han_invite,	0},
 {{"JOIN"},	han_join,	0},
 {{"KICK"},	han_kick,	0},
 {{"MODE"},	han_mode,	0},
 {{"NICK"},	han_nick,	0},
 {{"NOTICE"},	han_notice,	0},
 {{"PART"},	han_part,	0},
 {{"PING"},	han_ping,	0},
 {{"PRIVMSG"},	han_privmsg,	0},
 {{"QUIT"},	han_quit,	0},
 {{"TOPIC"},	han_topic,	0},
 {{"WALLOPS"},	han_wallops,	0}
};
#define NUMBER_HANDLE (sizeof(handle_list) / sizeof(CmdList)) -1

/* ------------------------------------------------------------------------ */
void handle_line(line, srv)
  char line[MAXLEN];
  server_ptr srv;
{
  CmdList *command;
  split temp;
  char *eek, str[10];
  int loop, cnt;
  win_ptr old_outwin;

  SRV = srv;
  old_outwin = outwin;
  outwin = type_winget(SRV, CRAP);
  if (!line_split(line, &temp)) return;
  if (*line==':') eek = &line[1];
  else eek = line;
  if (handle_on(o_raw_irc, eek, 0)) return;
  if (temp.commandnum) {
    (void)strcpy(on_line, temp.from);
    for (loop=1; (loop<MAX_ARGS) && *temp.p[loop]; loop++) {
      strcat(on_line, " ");
      strcat(on_line, temp.p[loop]);
    }
    strcat(on_line, " ");
    strcat(on_line, temp.text);
    if (handle_on(o_numeric, on_line, temp.commandnum)) {
      outwin = old_outwin;
      return;
     }
  }
  switch (temp.commandnum) {
    case RPL_AWAY:
      han_away(&temp);
      break;
    case RPL_ISON:
      han_notify(SRV, temp.text);
      break;
    case RPL_WHOISUSER:
      han_whois(&temp, TRUE);
      break;
    case RPL_WHOISSERVER:
      han_whoserv(&temp);
      break;
    case RPL_WHOISOPERATOR:
      han_whoircop(&temp);
      break;
    case RPL_WHOWASUSER:
      han_whois(&temp, FALSE);
      break;
    case RPL_WHOISIDLE:
      han_whoidle(&temp);
      break;
    case RPL_WHOISCHANNELS:
      han_whochan(&temp);
      break;
    case RPL_WHOREPLY:
      say("%-11.11s %-10.10s %-4.4s %s@%s (%s)",
          temp.p[1], temp.p[5], temp.p[6], temp.p[2], temp.p[3], temp.text);
      break;
    case RPL_NAMREPLY:
      han_join_list(&temp);
      break;
    case RPL_LISTSTART:
      han_server_message(&temp);
      break;
    case RPL_LIST:
      han_list(&temp);
      break;
    case ERR_USERNOTINCHANNEL:
    case ERR_USERONCHANNEL:
    case RPL_LINKS:
    case RPL_VERSION:
      han_twoparams(&temp);
      break;
    case RPL_MYINFO:
     /* we really don't want to see this information */
      break;
    case RPL_UMODEIS:
      say("*** Your user mode is \"%s\"", temp.p[1]);
      break;
    case RPL_INVITING:
      han_invited(&temp);
      break;
    case RPL_CHANNELMODEIS:
      han_modeis(&temp);
      break;
    case RPL_USERHOST:
      han_userhost(&temp);
      break;
    case RPL_WELCOME:
      (void)strcpy(SRV->nick, temp.p[0]);
      updatestatwin();
      han_noparams(&temp);
      break;
    case ERR_NOSUCHNICK:
      han_nonick(&temp);
      break;
    case RPL_ENDOFWHO:
    case RPL_ENDOFNAMES:
    case RPL_ENDOFWHOIS:
    case RPL_ENDOFWHOWAS:
    case RPL_ENDOFSTATS:
    case RPL_ENDOFLINKS:
    case RPL_ENDOFBANLIST:
      if (show_end_of_msgs)
        han_oneparam(&temp);
      break;
    case ERR_NOORIGIN:
    case ERR_NORECIPIENT:
    case ERR_NOTEXTTOSEND:
    case ERR_NOMOTD:
    case ERR_FILEERROR:
    case ERR_NONICKNAMEGIVEN:
    case ERR_SUMMONDISABLED:
    case ERR_USERSDISABLED:
    case ERR_NOTREGISTERED:
    case ERR_ALREADYREGISTRED:
    case ERR_NOPERMFORHOST:
    case ERR_PASSWDMISMATCH:
    case ERR_YOUREBANNEDCREEP:
    case ERR_NOPRIVILEGES:
    case ERR_CANTKILLSERVER:
    case ERR_NOOPERHOST:
    case ERR_UMODEUNKNOWNFLAG:
    case ERR_USERSDONTMATCH:
    case RPL_YOURHOST:
    case RPL_CREATED:
    case RPL_MOTD:
    case RPL_ENDOFMOTD:
    case RPL_MOTDSTART:
    case RPL_UNAWAY:
    case RPL_NOWAWAY:
    case RPL_LISTEND:
    case RPL_LUSERCLIENT:
    case RPL_LUSERME:
    case RPL_USERSSTART:
    case RPL_USERS:
    case RPL_ENDOFUSERS:
    case RPL_NOUSERS:
    case RPL_STATSUPTIME:
    case RPL_YOUREOPER:
    case RPL_INFO:
    case RPL_ENDOFINFO:
    case RPL_ADMINLOC1:
    case RPL_ADMINLOC2:
    case RPL_ADMINEMAIL:
      han_noparams(&temp);
      break;
    case ERR_UNKNOWNCOMMAND:
      han_unknown(&temp);
      break;
    case ERR_NICKNAMEINUSE:
      say("*** Nickname already in use, please pick another");
      read_input(str, 9, "Nickname: ");
      new_send(SRV, "NICK %s\n", str);
      break;
    case RPL_TOPIC:
    case ERR_NOSUCHSERVER:
    case ERR_NOSUCHCHANNEL:
    case ERR_CANNOTSENDTOCHAN:
    case ERR_TOOMANYCHANNELS:
    case ERR_WASNOSUCHNICK:
    case ERR_TOOMANYTARGETS:
    case ERR_NOTOPLEVEL:
    case ERR_WILDTOPLEVEL:
    case ERR_NOADMININFO:
    case ERR_ERRONEUSNICKNAME:
    case ERR_NICKCOLLISION:
    case ERR_NOTONCHANNEL:
    case ERR_NOLOGIN:
    case ERR_NEEDMOREPARAMS:
    case ERR_KEYSET:
    case ERR_CHANNELISFULL:
    case ERR_UNKNOWNMODE:
    case ERR_INVITEONLYCHAN:
    case ERR_BANNEDFROMCHAN:
    case ERR_BADCHANNELKEY:
    case ERR_CHANOPRIVSNEEDED:
    case RPL_NOTOPIC:
    case RPL_SUMMONING:
    case RPL_LUSEROP:
    case RPL_LUSERCHANNELS:
    case RPL_LUSERUNKNOWN:
    case RPL_TIME:
    case RPL_REHASHING:
    case RPL_ADMINME:
      han_oneparam(&temp);
      break;
    case ERR_NOSUCHSERVICE:
    case ERR_SERVICENAMEINUSE:
    case ERR_SERVICECONFUSED:
    case RPL_TEXT:
    case RPL_YOURESERVICE:
    case RPL_NOTOPERANYMORE:
    case RPL_TRACESERVICE:
      say("+++ Numeric (%d) not in rfc.", temp.commandnum);
      han_def(&temp);
      break;
    case ERR_BADCHANMASK:
    case ERR_NOSERVICEHOST: 
    case RPL_KILLDONE:
    case RPL_CLOSING:
    case RPL_CLOSEEND:
    case RPL_INFOSTART:
    case RPL_MYPORTIS:
    case RPL_SERVICEINFO:
    case RPL_ENDOFSERVICES:
    case RPL_SERVICE:
    case RPL_SERVLIST:
    case RPL_SERVLISTEND:
    case RPL_WHOISCHANOP:
      say("+++ Reserved/not in use from rfc.");
      han_def(&temp);
      break;
    case RPL_STATSCLINE:
    case RPL_STATSNLINE:
    case RPL_STATSILINE:
    case RPL_STATSKLINE:
    case RPL_STATSQLINE:
      han_stats_basic(&temp);
      break;
    case RPL_STATSLINKINFO:
    case RPL_STATSCOMMANDS:
    case RPL_STATSYLINE:
    case RPL_STATSOLINE:
    case RPL_STATSHLINE:
    case RPL_STATSSLINE:
    case RPL_TRACELINK:
    case RPL_TRACECONNECTING:
    case RPL_TRACEHANDSHAKE:
    case RPL_TRACEUNKNOWN:
    case RPL_TRACEOPERATOR:
    case RPL_TRACEUSER:
    case RPL_TRACESERVER:
    case RPL_TRACENEWTYPE:
    case RPL_TRACECLASS:
    case RPL_BANLIST:
    case RPL_STATSLLINE:
    case RPL_TRACELOG:
      say("*** %s %s %s %s %s %s", temp.p[1],
          temp.p[2], temp.p[3], temp.p[4], temp.p[5], temp.p[6]);
      break;
    case 0: 
      (void)strcpy(userhost, temp.userhost);
      command = find_command(handle_list, NUMBER_HANDLE, temp.command, &cnt);
      if (((cnt<0) || (cnt == 1)) && command)
        command->cmdfcn(&temp);
      else
        han_def(&temp);
      break;
    default:
      han_def(&temp);
  } /* switch statement */
  outwin = old_outwin;
  (void)find_input_prompt(FALSE);
  updatestatwin();
}
