/* This file is part of XgIRC 0.1
   irc.c - IRC client <-> server communication

   Copyright (C) 1998 A|vin (Julien Pieraut) <alvin@another-world.com>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <sys/utsname.h>
#include "main.h"
#include "irc.h"
#include "display.h"
#include "text.h"
#include "strings.h"
#include "system.h"

/* ========================================================================== *                  
 * = Answers CTCP 'ctcp' 'data' by 'nick'                                   = *
 * ========================================================================== */
void
answer_ctcp (char *ctcp, char *nick, char *data, int scr)
{
  char text[MAXLEN];
/* ============ VERSION ? =================================================== */
  if (strcomp (ctcp, "VERSION"))
    {
      text_ctcp (current_screen, nick, ctcp);
      sprintf (buf, "NOTICE %s :\01VERSION XgIRC %s by A|vin on %s\01", nick, INTERNAL_VERSION, host ());
      sendln (s, buf);
      return;
    }
/* ============ PING ? ======================================================= */
  if (strcomp (ctcp, "PING"))
    {
      if (!strcomp (nick, me.nick))
	text_ctcp (current_screen, nick, ctcp);
      sprintf (buf, "NOTICE %s :\01PING %s", nick, data);
      sendln (s, buf);
      return;
    }
/* ============ TIME ? ======================================================= */
  if (strcomp (ctcp, "TIME"))
    {
      text_ctcp (current_screen, nick, ctcp);
      sprintf (buf, "NOTICE %s :\01TIME Current time: %s\01", nick, get_the_time ());
      sendln (s, buf);
      return;
    }
/* ============ ACTION ? ===================================================== */
  if (strcomp (ctcp, "ACTION"))
    {
      text_me (scr, nick, data);
      return;
    }
/* ============ CLIENTINFO ? ================================================= */
  if (strcomp (ctcp, "CLIENTINFO"))
    {
      text_ctcp (current_screen, nick, ctcp);
      sprintf (buf, "NOTICE %s :\01CLIENTINFO %s\01", nick, CTCP_CLIENTINFO_REPLY);
      sendln (s, buf);
      return;
    }
/* ============ Unknown CTCP ================================================= */
  sprintf (buf, "unknow : %s %s", ctcp, data);
  text_ctcp (current_screen, nick, buf);
  return;
}

/* ========================================================================== *
 * = Returns the screen corresponding to query to 'nick', 0 if inexistant   = *
 * ========================================================================== */
int
find_query (char *nick)
{
  for (i = 1; i <= total_queries; i++)
    {
      if (strcomp (nick, query[i].nick))
	return (i + total_channels);
    }
  return (0);
}

/* ========================================================================== *
 * = Return the screen corresponding to channel 'chn' or 0 if inexistant    = *
 * ========================================================================== */
int
find_channel (char *chn)
{
  for (i = 1; i <= total_channels; i++)
    {
      if (strcomp (channel[i].name, chn))
	return (i);
    }
  return (0);
}

/* ========================================================================== *
 * = Parses string received from socket s                                   = *
 * ========================================================================== */
void
parse_from_server (int s)
{
  int comm = 0;
  int scr, qry;
  int j, k, type, n;
  char chn[MAXLEN];
  char answer[MAXLEN];
  char text[MAXLEN];
  char names[MAXLEN];
  char who[MAXLEN], nick[MAXLEN], nick2[MAXLEN], user[MAXLEN], hostdomain[MAXLEN],
    message[MAXLEN];
  char status_text[MAXLEN];

  readln (s, &buf);
  
/* === PING from server ? =================================================== */
  if (strcomp (get_arg (buf, 1), "PING"))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... PING from server <irc.c/parse_from_server>\n");
#endif
      /*     text_ping_from_server ();       Boring to get every ping in status window */
      sprintf (answer, "PONG %s", get_arg (buf, 2));
      sendln (s, answer);
      if (me.usermode != NULL && connected != 1)
	{
	  text_connected ();
	  sprintf (status_text, STATUS_CONNECTED, me.nick, me.usermode, server, port);
	  gtk_label_set (GTK_LABEL (status), status_text);
	  gtk_pixmap_set (GTK_PIXMAP(green_pixmapwid), green_on_pixmap, green_on_pixmapm);
	  sprintf (answer, "MODE %s %s", me.nick, me.usermode);
	  sendln (s, answer);
	  check_lag_tag = gtk_timeout_add (CHECK_LAG_DELAY, check_lag, NULL);
	}
      connected = 1;
      comm = 1;
    }
/* ========================================================================== */

/* === PRIVMSG ? ============================================================ */
  if ((count_args (buf) > 2) && (strcomp (get_arg (buf, 2), "PRIVMSG")))
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      strcpy (nick, get_nick (who));
      strcpy (user, get_user (who));
      strcpy (hostdomain, get_hostdomain (who));
      strcpy (chn, get_arg (buf, 3));
      scr = find_channel (chn);

/* ========= CTCP ? ========================================================= */
      if (count_args (buf) > 3 && get_arg (buf, 4)[1] == 1)
	{
#ifdef DEBUG
	  g_print ("[D] Parsing... CTCP [%s] <irc.c/parse_from_server>\n", strip_fchr (strip_strange_chars (get_arg (buf, 4))));
#endif
	  answer_ctcp (strip_fchr (strip_strange_chars (get_arg (buf, 4))), nick, get_from_arg (buf, 5), scr);
	  comm = 1;
	}
/* ========================================================================== */

/* ====== Channel message ? ================================================= */
      if ((get_arg (buf, 3))[0] == '#' && !comm)
	{
	  strcpy (message, strip_fchr (get_from_arg (buf, 4)));
#ifdef DEBUG
	  g_print ("[D] Parsing... PRIVMSG [Channel : %s / Screen : %i/%i] <irc.c/parse_from_server>\n", chn, scr, total_screens);
#endif
	  text_channel_msg (scr, nick, message);
	  comm = 1;
	}
/* ========================================================================== */

/* ====== Private message ? ================================================= */
      if (strcomp (get_arg (buf, 3), me.nick) && !comm)
	{
	  strcpy (text, "");
	  for (i = 4; i <= count_args (buf); i++)
	    {
	      strcat (text, get_arg (buf, i));
	      strcat (text, " ");
	    }
	  strcpy (message, strip_fchr (text));
	  strcpy (current_channel, nick);
	  qry = find_query (nick);
	  if (qry)
	    {
#ifdef DEBUG
	      g_print ("[D] Parsing... PRIVMSG [Query : %s / Screen : %i/%i] <irc.c/parse_from_server>\n", nick, qry, total_screens);
#endif
	      text_channel_msg (qry, nick, message);
	    }
	  else
	    {
	      total_screens++;
	      total_queries++;
	      scr = gtk_notebook_current_page (GTK_NOTEBOOK (screen_notebook));
	      current_screen = total_screens;
	      box_screen[total_screens] = screen_box (window_main, 2);
	      gtk_notebook_append_page (GTK_NOTEBOOK (screen_notebook), box_screen[total_screens], gtk_label_new (current_channel));
	      gtk_widget_show (box_screen[total_screens]);
	      gtk_notebook_set_page (GTK_NOTEBOOK (screen_notebook), current_screen);	/* We switch to the query screen... */
	      strcpy (query[total_queries].nick, current_channel);
#ifdef DEBUG
	      g_print ("[D] Parsing... PRIVMSG [Query : %s / Screen : %i/%i] <irc.c/parse_from_server>\n", nick, current_screen, total_screens);
#endif
	      text_channel_msg (current_screen, nick, message);
	      current_screen = scr;
	      gtk_notebook_set_page (GTK_NOTEBOOK (screen_notebook), current_screen);	/*  And we switch back to the current screen :p If this isn't made, we can't write to the hidden screen (?!)  */
	    }
	  comm = 1;
	}
/* ========================================================================== */
    }

/* == NOTICE ? ============================================================== */
  if ((count_args (buf) > 2) && (strcomp (get_arg (buf, 2), "NOTICE")) && !comm)
    {
#ifdef DEBUG
      g_print ("[D] Parsing... NOTICE [");
#endif
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      if (get_arg (buf, 3)[0] == '#')
	{
	  strcpy (chn, get_arg (buf, 3));
	  scr = find_channel (chn);
	  if (is_in_string ('!', who))	/* If this is a user notice */
	    {
	      strcpy (nick, get_nick (who));
	      strcpy (user, get_user (who));
	      strcpy (hostdomain, get_hostdomain (who));
#ifdef DEBUG
	      g_print ("From %s to channel %s] <irc.c/parse_from_server>\n", nick, chn);
#endif
	      text_notice (scr, nick, strip_fchr (get_from_arg (buf, 4)), 1);
	    }
	  else
	    {			/* Do server channel notices exist ? */
	      text_server_raw (strip_fchr (get_from_arg (buf, 4)));
#ifdef DEBUG
	      g_print ("From server to channel %s] <irc.c/parse_from_server>\n", chn);
#endif
	    }
	}
      else
	{
	  if (is_in_string ('!', who))
	    {
	      strcpy (nick, get_nick (who));
	      strcpy (user, get_user (who));
	      strcpy (hostdomain, get_hostdomain (who));
#ifdef DEBUG
	      g_print ("From : %s] <irc.c/parse_from_server>\n", nick);
#endif
	      current_screen = gtk_notebook_current_page (GTK_NOTEBOOK (screen_notebook));
	      if (get_arg (buf, 4)[1] == 1)	/* CTCP reply ? */
		{
		  if (strcomp (strip_strange_chars (strip_fchr (get_arg (buf, 4))), "ping"))	/* CTCP PING reply ? */
		    {
		      sprintf (text, "%d seconds", get_seconds_counter () - atoi (strip_strange_chars (get_arg (buf, 5))));
		      if (!strcomp (nick, me.nick))
			text_ctcp_reply (nick, "PING", text);
		      else
			update_lagmeter (get_seconds_counter () - atoi (strip_strange_chars (get_arg (buf, 5))));
		    }
		  else
		    {
		      text_ctcp_reply (nick, strip_strange_chars (strip_fchr (get_arg (buf, 4))), strip_strange_chars (get_from_arg (buf, 5)));
		    }
		}
	      else
		{
		  strcpy (text, strip_fchr (get_from_arg (buf, 4)));
		  text_notice (current_screen, nick, text, 2);
		}
	    }
	  else
	    {
#ifdef DEBUG
	      g_print ("From server] <irc.c/parse_from_server>\n");
#endif
	      text_server_raw (strip_fchr (get_from_arg (buf, 4)));
	    }
	}
      comm = 1;
    }
/* ========================================================================== */

/* == JOIN ? ================================================================ */
  if ((count_args (buf) > 2) && (strcomp (get_arg (buf, 2), "JOIN")) && !comm)
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      strcpy (nick, get_nick (who));
      strcpy (user, get_user (who));
      strcpy (hostdomain, get_hostdomain (who));
      strcpy (chn, strip_fchr (get_arg (buf, 3)));
      if (!strcomp (nick, me.nick))
	{
	  scr = find_channel (chn);
#ifdef DEBUG
	  g_print ("[D] Parsing... JOIN [Channel : %s / Screen : %i] <irc.c/parse_from_server>\n", chn, scr);
#endif
	  text_join (scr, nick, user, hostdomain);
#ifdef DEBUG
	  g_print ("[D] Updating userlist... <irc.c/parse_from_server>\n");
#endif
	  add_to_userlist (scr, nick);
#ifdef DEBUG
	  g_print ("[D] Ops [%i/%i] : ", channel[scr].nb_ops, channel[scr].nb_ops + channel[scr].nb_nops);
	  for (i = 1; i <= channel[scr].nb_ops; i++)
	    {
	      g_print ("%s ", channel[scr].ops[i]);
	    }
	  g_print ("<irc.c/parse_from_server>\n[D] Non Ops [%i/%i] : ", channel[scr].nb_nops, channel[scr].nb_ops + channel[scr].nb_nops);
	  for (i = 1; i <= channel[scr].nb_nops; i++)
	    {
	      g_print ("%s ", channel[scr].nops[i]);
	    }
	  g_print ("<irc.c/parse_from_server>\n");
#endif
	}
      else
	{			/* Hey, it's MY join ;) */
	  strcpy (current_channel, chn);
	  total_screens++;
	  total_channels++;
	  current_screen = total_channels;	/* We switch to the joined channel */
	  if (total_queries != 0)
	    {
	      for (i = 0; i <= total_queries - 1; i++)
		{
		  strcpy (query[total_screens - i].nick, query[total_screens - i - 1].nick);
		  screen[total_screens - i] = screen[total_screens - i - 1];
		}
	    }
	  box_screen[current_screen] = screen_box (window_main, 1);
	  gtk_notebook_insert_page (GTK_NOTEBOOK (screen_notebook), box_screen[current_screen], gtk_label_new (current_channel), current_screen);
	  gtk_widget_show (box_screen[current_screen]);
	  gtk_notebook_set_page (GTK_NOTEBOOK (screen_notebook), current_screen);
	  strcpy (channel[total_channels].name, current_channel);
#ifdef DEBUG
	  g_print ("[D] Sending modes request of channel %s <irc.c/parse_from_server>\n", chn);
#endif
	  sprintf (buf, "MODE %s", chn);	/* We Request channel modes */
	  sendln (s, buf);
	  text_my_join (chn);
	  scr = current_screen;
	  text_join (scr, nick, user, hostdomain);
	  strcpy (channel[current_screen].topic_author, "?");

	}
      /*  current_screen = gtk_notebook_current_page (GTK_NOTEBOOK (screen_notebook)); */
      update_userlist (scr);
      update_status_bar (scr);
      comm = 1;
    }
/* ========================================================================== */

/* == PART ? ================================================================ */
  if ((count_args (buf) > 2) && (strcomp (get_arg (buf, 2), "PART")) && !comm)
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      strcpy (nick, get_nick (who));
      strcpy (user, get_user (who));
      strcpy (hostdomain, get_hostdomain (who));
      strcpy (chn, get_arg (buf, 3));
      if (!strcomp (nick, me.nick))
	{
	  scr = find_channel (chn);
#ifdef DEBUG
	  g_print ("[D] Parsing... PART [Channel : %s / Screen : %i] <irc.c/parse_from_server>\n", chn, scr);
#endif
	  text_part (scr, nick, user, hostdomain);
#ifdef DEBUG
	  g_print ("[D] Updating userlist...");
#endif
	  remove_from_userlist (scr, nick);
#ifdef DEBUG
	  g_print (" [OK] <irc.c/parse_from_server>\n");
	  g_print ("[D] Ops [%i/%i] : ", channel[scr].nb_ops, channel[scr].nb_ops + channel[scr].nb_nops);
	  for (i = 1; i <= channel[scr].nb_ops; i++)
	    {
	      g_print ("%s ", channel[scr].ops[i]);
	    }
	  g_print ("<irc.c/parse_from_server>\n[D] Non Ops [%i/%i] : ", channel[scr].nb_nops, channel[scr].nb_ops + channel[scr].nb_nops);
	  for (i = 1; i <= channel[scr].nb_nops; i++)
	    {
	      g_print ("%s ", channel[scr].nops[i]);
	    }
	  g_print ("<irc.c/parse_from_server>\n");
#endif
	  update_userlist (scr);
	  update_status_bar (scr);
	}
      else
	{
	  text_my_part (chn);
	}
      comm = 1;
    }
/* ========================================================================== */

/* == QUIT ? ================================================================ */
  if ((count_args (buf) > 2) && (strcomp (get_arg (buf, 2), "QUIT")) && !comm)
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      strcpy (nick, get_nick (who));
      strcpy (user, get_user (who));
      strcpy (hostdomain, get_hostdomain (who));
      strcpy (text, strip_fchr (get_from_arg (buf, 3)));
#ifdef DEBUG
      g_print ("[D] Parsing... QUIT <irc.c/parse_from_server>\n");
#endif
      for (k = 1; k <= total_channels; k++)
	{
	  if (is_in_channel (k, nick))
	    {
	      text_quit (k, nick, user, hostdomain, text);
#ifdef DEBUG
	      g_print ("[D] Updating userlist [Screen : %i] ", k);
#endif
	      for (j = 1; j <= channel[k].nb_ops; j++)
		{
		  if (strcomp (nick, channel[k].ops[j]))
		    remove_from_userlist (k, nick);
		}
	      for (j = 1; j <= channel[k].nb_nops; j++)
		{
		  if (strcomp (nick, channel[k].nops[j]))
		    remove_from_userlist (k, nick);
		}
	      update_userlist (k);
	      update_status_bar (k);
#ifdef DEBUG
	      g_print ("[OK] <irc.c/parse_from_server>\n");
#endif
	    }
	}
      comm = 1;
    }
/* ========================================================================== */

/* == TOPIC ? =============================================================== */
  if ((count_args (buf) > 2) && (strcomp (get_arg (buf, 2), "TOPIC")) && !comm)
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      strcpy (nick, get_nick (who));
      strcpy (user, get_user (who));
      strcpy (hostdomain, get_hostdomain (who));
      strcpy (chn, get_arg (buf, 3));
      scr = find_channel (chn);
#ifdef DEBUG
      g_print ("[D] Parsing... TOPIC [Channel : %s / Screen : %i] <irc.c/parse_from_server>\n", chn, scr);
#endif
      strcpy (channel[scr].topic, strip_fchr (get_from_arg (buf, 4)));
      text_topic (scr, nick, user, hostdomain, channel[scr].topic);	/* Could here remove the last arg */
      strcpy (channel[scr].topic_author, nick);
      update_status_bar (scr);
      comm = 1;
    }
  if ((count_args (buf) > 4) && (strcomp (get_arg (buf, 2), "332")) && !comm)
    {
      strcpy (chn, get_arg (buf, 4));	/* Hmm, not elegant to verify the screen but more secure */
      scr = find_channel (chn);
#ifdef DEBUG
      g_print ("[D] Reading topic of channel %s : ", chn);
#endif
      strcpy (channel[scr].topic, strip_fchr (get_from_arg (buf, 5)));
#ifdef DEBUG
      g_print ("%s <irc.c/parse_from_server>\n", channel[scr].topic);
#endif
      update_status_bar (scr);
      comm = 1;
    }
/* ========================================================================== */

/* == NICK ? ================================================================ */
  if ((count_args (buf) == 3) && (strcomp (get_arg (buf, 2), "NICK")) && !comm)
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      strcpy (nick, get_nick (who));
      strcpy (user, get_user (who));
      strcpy (hostdomain, get_hostdomain (who));
#ifdef DEBUG
      g_print ("[D] Parsing... NICK <irc.c/parse_from_server>\n");
#endif
      if (get_arg (buf, 3)[0] == ':')
	{
	  for (k = 1; k <= total_screens; k++)
	    {
	      if (is_in_channel (k, nick))
		{
		  text_nick (k, nick, strip_fchr (get_arg (buf, 3)));
#ifdef DEBUG
		  g_print ("[D] Updating userlist [Screen : %i] ", k);
#endif
		  for (j = 1; j <= channel[k].nb_ops; j++)
		    {
		      if (strcomp (nick, channel[k].ops[j]))
			strcpy (channel[k].ops[j], strip_fchr (get_arg (buf, 3)));
		    }
		  for (j = 1; j <= channel[k].nb_nops; j++)
		    {
		      if (strcomp (nick, channel[k].nops[j]))
			strcpy (channel[k].nops[j], strip_fchr (get_arg (buf, 3)));
		    }
		  update_userlist (k);
#ifdef DEBUG
		  g_print ("[OK] <irc.c/parse_from_server>\n");
#endif
		}
	    }
	  if (strcomp (nick, me.nick))
	    {			/* If it's my own nick change */
	      strcpy (me.nick, strip_fchr (get_arg (buf, 3)));
	      sprintf (status_text, STATUS_CONNECTED, me.nick, me.usermode, server, port);
	      gtk_label_set (GTK_LABEL (status), status_text);
	      text_own_nick (0, me.nick);
	    }
	}
      comm = 1;
    }
/* ========================================================================== */

/* == KICK ? ================================================================ */
  if (strcomp (get_arg (buf, 2), "KICK") && !comm)
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
      strcpy (nick, get_nick (who));
      strcpy (user, get_user (who));
      strcpy (hostdomain, get_hostdomain (who));
      strcpy (chn, get_arg (buf, 3));
      scr = find_channel (chn);
#ifdef DEBUG
      g_print ("[D] Parsing... KICK <irc.c/parse_from_server>\n");
#endif
      if (strcomp (get_arg (buf, 4), me.nick))
	{
	  gtk_notebook_remove_page (GTK_NOTEBOOK (screen_notebook), scr);
	  for (i = scr; i <= total_channels - 1; i++)
	    {
	      strcpy (channel[i].name, channel[i + 1].name);
	      strcpy (channel[i].topic, channel[i + 1].topic);
	      strcpy (channel[i].modes, channel[i + 1].modes);
	      channel[i].nb_ops = channel[i + 1].nb_ops;
	      channel[i].nb_nops = channel[i + 1].nb_nops;
	      for (j = 1; j <= channel[i].nb_ops; j++)
		{
		  strcpy (channel[i].ops[j], channel[i + 1].ops[j]);
		}
	      for (j = 1; j <= channel[i].nb_nops; j++)
		{
		  strcpy (channel[i].nops[j], channel[i + 1].nops[j]);
		}
	      screen[i] = screen[i + 1];
	    }
	  for (i = total_channels; i <= total_screens - 1; i++)
	    {
	      screen[i] = screen[i + 1];
	    }
	  total_screens--;
	  total_channels--;
	  current_screen = 0;
	  gtk_notebook_set_page (GTK_NOTEBOOK (screen_notebook), current_screen);
	  strcpy (current_channel, channel[current_screen].name);
	  text_my_kick (nick, chn, strip_fchr (get_from_arg (buf, 5)));
	}
      else
	{
	  text_kick (scr, nick, get_arg (buf, 4), strip_fchr (get_from_arg (buf, 5)));
	  remove_from_userlist (scr, get_arg (buf, 4));
	  update_userlist (scr);
	  update_status_bar (scr);
	}
      comm = 1;
    }
/* ========================================================================== */

/* == MODE ? ================================================================ */
  if ((count_args (buf) > 2) && (strcomp (get_arg (buf, 2), "MODE")))
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
#ifdef DEBUG
      g_print ("[D] Parsing... MODE <irc.c/parse_from_server>\n");
#endif
      if (get_arg (buf, 3)[0] == '#')
	{			/* Channel mode */
	  strcpy (nick, get_nick (who));
	  strcpy (chn, get_arg (buf, 3));
	  scr = find_channel (chn);
	  text_mode (scr, nick, get_arg (buf, 4), get_from_arg (buf, 5));
	  n = 0;
	  for (k = 0; k <= strlen (get_arg (buf, 4)) - 1; k++)
	    {
	      if (get_arg (buf, 4)[k] == '+')
		{
		  type = 1;
		  n++;
		}
	      if (get_arg (buf, 4)[k] == '-')
		{
		  type = 0;
		  n++;
		}
	      if (get_arg (buf, 4)[k] == 'o')
		{
		  if (type)
		    {
		      strcpy (nick, get_arg (buf, 5 + k - n));
		      remove_from_userlist (scr, nick);
		      sprintf (nick2, "@%s", nick);
		      add_to_userlist (scr, nick2);
		      update_userlist (scr);
		    }
		  else
		    {
		      strcpy (nick, get_arg (buf, 5 + k - n));
		      remove_from_userlist (scr, nick);
		      add_to_userlist (scr, nick);
		      update_userlist (scr);
		    }
		}
	      if (get_arg (buf, 4)[k] == 'i')
		{
		  n++;
		}
	      if (get_arg (buf, 4)[k] == 'm')
		{
		  n++;
		}
	      if (get_arg (buf, 4)[k] == 's')
		{
		  n++;
		}
	      if (get_arg (buf, 4)[k] == 'p')
		{
		  n++;
		}
	      if (get_arg (buf, 4)[k] == 'k')
		{
		  n++;
		}
	      if (get_arg (buf, 4)[k] == 'v')
		{
		  n++;
		}
	      if (get_arg (buf, 4)[k] == 'b')
		{
		  n++;
		}
	    }
	  sprintf (buf, "MODE %s", chn);	/* Need to remove that and correctly update the statusbar ;) */
	  sendln (s, buf);
	  update_status_bar (scr);
	}
      comm = 1;
    }
  if (strcomp (get_arg (buf, 2), "324") && !comm)
    {
#ifdef DEBUG
      g_print ("[D] Parsing... Channel mode <irc.c/parse_from_server>\n");
#endif
      strcpy (chn, get_arg (buf, 4));
      scr = find_channel (chn);
      strcpy (channel[scr].modes, strip_fchr (get_from_arg (buf, 5)));
      channel[scr].modes[strlen (channel[scr].modes) - 1] = '\0';	/* Needed to delete a blank char */
      update_status_bar (scr);
      comm = 1;
    }
/* ========================================================================== */

/* == NAMES ? =============================================================== */
  if ((count_args (buf) > 5) && (strcomp (get_arg (buf, 2), "353")) && !comm)
    {
      strcpy (names, strip_fchr (get_from_arg (buf, 6)));
#ifdef DEBUG
      g_print ("[D] Parsing... NAMES <irc.c/parse_from_server>\n");
      g_print ("[D] Updating userlist... <irc.c/parse_from_server>\n");
#endif
      strcpy (chn, get_arg (buf, 5));
      scr = find_channel (chn);
      if (!channel[scr].names)
	{
	  channel[scr].nb_ops = 0;
	  channel[scr].nb_nops = 0;
	  channel[scr].names = 1;
	}
      for (i = 1; i <= count_args (names) - 1; i++)
	{
	  add_to_userlist (scr, get_arg (names, i));
	}
#ifdef DEBUG
      g_print ("[D] Ops [%i/%i] : ", channel[scr].nb_ops, channel[scr].nb_ops + channel[scr].nb_nops);
      for (i = 1; i <= channel[scr].nb_ops; i++)
	{
	  g_print ("%s ", channel[scr].ops[i]);
	}
      g_print ("<irc.c/parse_from_server>\n[D] Non Ops [%i/%i] : ", channel[scr].nb_nops, channel[scr].nb_ops + channel[scr].nb_nops);
      for (i = 1; i <= channel[scr].nb_nops; i++)
	{
	  g_print ("%s ", channel[scr].nops[i]);
	}
      g_print ("<irc.c/parse_from_server>\n");
#endif
      comm = 1;
    }
  if (strcomp (get_arg (buf, 2), "366") && !comm)
    {
#ifdef DEBUG
      g_print ("[D] Parsing... End of NAMES <irc.c/parse_from_server>\n");
#endif
      strcpy (chn, get_arg (buf, 4));
      scr = find_channel (chn);
      channel[scr].names = 0;
      update_userlist (scr);
      comm = 1;
    }
/* ========================================================================== */

/* === WHOIS ? ============================================================== */
  if ((strcomp (get_arg (buf, 2), "311")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... line of WHOIS response <irc.c/parse_from_server>\n");
#endif
      text_whois1 (current_screen, get_arg (buf, 4), get_arg (buf, 5), get_arg (buf, 6), strip_fchr (get_from_arg (buf, 8)));
      comm = 1;
    }
  if ((strcomp (get_arg (buf, 2), "319")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... line of WHOIS response <irc.c/parse_from_server>\n");
#endif
      text_whois2 (current_screen, get_arg (buf, 4), strip_fchr (get_from_arg (buf, 5)));
      comm = 1;
    }
  if ((strcomp (get_arg (buf, 2), "312")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... line of WHOIS response <irc.c/parse_from_server>\n");
#endif
      text_whois3 (current_screen, get_arg (buf, 4), get_arg (buf, 5), strip_fchr (get_from_arg (buf, 6)));
      comm = 1;
    }
  if ((strcomp (get_arg (buf, 2), "317")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... line of WHOIS response <irc.c/parse_from_server>\n");
#endif
      text_whois4 (current_screen, get_arg (buf, 4), get_arg (buf, 5), get_arg (buf, 6));
      comm = 1;
    }
  if ((strcomp (get_arg (buf, 2), "318")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... end of WHOIS response <irc.c/parse_from_server>\n");
#endif
      comm = 1;
    }
/* ========================================================================== */

/* === MOTD ? =============================================================== */
  if ((strcomp (get_arg (buf, 2), "375")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... MOTD header <irc.c/parse_from_server>\n");
#endif
      text_motd_header ();
      comm = 1;
    }
  if ((strcomp (get_arg (buf, 2), "376")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... MOTD footer <irc.c/parse_from_server>\n");
#endif
	  text_motd_footer ();
      if (me.usermode != NULL && connected != 1)
	{
	  text_connected ();
	  sprintf (status_text, STATUS_CONNECTED, me.nick, me.usermode, server, port);
	  gtk_label_set (GTK_LABEL (status), status_text);
	  gtk_pixmap_set (GTK_PIXMAP(green_pixmapwid), green_on_pixmap, green_on_pixmapm);
	  sprintf (answer, "MODE %s %s", me.nick, me.usermode);
	  sendln (s, answer);
	  check_lag_tag = gtk_timeout_add (CHECK_LAG_DELAY, check_lag, NULL);
	}
      connected = 1;
      comm = 1;
    }
  if ((strcomp (get_arg (buf, 2), "372")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... MOTD text <irc.c/parse_from_server>\n");
#endif
      text_motd (strip_fchr (get_from_arg (buf, 4)));
      comm = 1;
    }
/* ========================================================================== */

/* === Error msg ? ========================================================== */
  if (strcomp (get_arg (buf, 2), "401") || strcomp (get_arg (buf, 2), "433") || strcomp (get_arg (buf, 2), "473"))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... Error msg [%s : %s] <irc.c/parse_from_server>\n", get_arg (buf, 4), strip_fchr (get_from_arg (buf, 5)));
#endif
      text_error (current_screen, get_arg (buf, 4), strip_fchr (get_from_arg (buf, 5)));
      comm = 1;
    }
  if (strcomp (get_arg (buf, 2), "438") || strcomp (get_arg (buf, 2), "405") || strcomp (get_arg (buf, 2), "482") || strcomp (get_arg (buf, 2), "404"))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... Error msg [%s] <irc.c/parse_from_server>\n", strip_fchr (get_from_arg (buf, 5)));
#endif
      text_error2 (current_screen, strip_fchr (get_from_arg (buf, 5)));
      comm = 1;
    }
/* ========================================================================== */

/* === WALLOPS ? ============================================================ */
  if (strcomp (get_arg (buf, 2), "WALLOPS") && !comm)
    {
      strcpy (who, strip_fchr (get_arg (buf, 1)));
#ifdef DEBUG
      g_print ("[D] Parsing... WALLOPS <irc.c/parse_from_server>\n");
#endif
      if (is_in_string ('!', who))
	{
	  strcpy (nick, get_nick (who));
	  strcpy (user, get_user (who));
	  strcpy (hostdomain, get_hostdomain (who));
	  text_wallops (nick, strip_fchr (get_from_arg (buf, 3)));
	}
      else
	{
	  text_server_wallops (strip_fchr (get_from_arg (buf, 3)));
	}
      comm = 1;
    }
/* ========================================================================== */

/* === Topic info ? ========================================================= */
  if ((strcomp (get_arg (buf, 2), "333")))
    {
      strcpy (nick, get_arg (buf, 5));
      strcpy (chn, get_arg (buf, 4));
      scr = find_channel (chn);
#ifdef DEBUG
      g_print("[D] Parsing... Topic information [Author of %s topic : %s] <irc.c/parse_from_server>\n", chn, nick);
#endif
      strcpy (channel[scr].topic_author, nick);
      update_status_bar (scr);
      comm = 1;
    }
/* ========================================================================== */

/* === Other server msg ? =================================================== */
  if ((strcomp (get_arg (buf, 2), "001") || strcomp (get_arg (buf, 2), "002") || strcomp (get_arg (buf, 2), "003") || strcomp (get_arg (buf, 2), "251") || strcomp (get_arg (buf, 2), "255")) && !comm)
    {
#ifdef DEBUG
      g_print ("[D] Parsing... Server message <irc.c/parse_from_server>\n");
#endif
      strcpy (message, strip_fchr (get_from_arg (buf, 4)));
      text_server_raw (message);
      comm = 1;
    }
  if ((strcomp (get_arg (buf, 2), "004")))
    {
#ifdef DEBUG
      g_print ("[D] Parsing... Server message <irc.c/parse_from_server>\n");
#endif
      strcpy (message, get_from_arg (buf, 4));
      text_server_raw (message);
      comm = 1;
    }
#ifdef RAW_SERVER_MSGS
  if (!comm)
  {				/* Displays everything that hasn't been parsed */
//	  memset(&buf, 0, MAXLEN);
      sprintf (buf, "[RAW] %s", get_from_arg (buf, 1));
      text_server_raw (buf);
    }
#endif
/* ========================================================================== */
}

/* ========================================================================== *
 * = Sends data to socket s by parsing 'string'                             = *
 * ========================================================================== */
void
send_to_server (int s, char *string)
{
  char test_command[MAXLEN];
  char command[MAXLEN];
  int comm = 0;

  if (connected != 1)
    {
      text_error_not_connected ();
      return;
    }

/* === Message ? ============================================================ */
  if (string[0] != COMMAND_CHAR)
    {
      if (current_screen)
	{			/* We verify that text was not typed in status screen */
	  sprintf (command, "PRIVMSG %s :%s", current_channel, string);
	  sendln (s, command);
	  text_own_channel_msg (me.nick, string);
	  comm = 1;
	}
      else
	{			/* Else print an error msg */
	  text_error_not_on_a_channel ();
	  return;
	}
    }
/* ========================================================================== */

  else
    {

/* ===== JOIN command ? ===================================================== */
      sprintf (test_command, "%cJOIN", COMMAND_CHAR);
      if ((strcomp (get_arg (string, 1), test_command)) && (count_args (string) == 2))
	comm = command_join (get_arg (string, 2));
/* ========================================================================== */

/* ===== PART command ? ===================================================== */
      sprintf (test_command, "%cPART", COMMAND_CHAR);
      if ((strcomp (get_arg (string, 1), test_command)) && (count_args (string) == 1))
	comm = command_part (current_channel);
/* ========================================================================== */

/* ===== ME command ? ======================================================= */
      sprintf (test_command, "%cme", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	comm = command_me (get_from_arg (string, 2));
/* ========================================================================== */

/* ===== NICK command ? ===================================================== */
      sprintf (test_command, "%cNICK", COMMAND_CHAR);
      if ((strcomp (get_arg (string, 1), test_command)) && (count_args (string) == 2))
	comm = command_nick (get_arg (string, 2));
/* ========================================================================== */

/* ===== WHOIS command ? ==================================================== */
      sprintf (test_command, "%cWHOIS", COMMAND_CHAR);
      if ((strcomp (get_arg (string, 1), test_command)) && (count_args (string) == 2))
	comm = command_whois (get_arg (string, 2));
/* ========================================================================== */

/* ===== QUOTE command ? ==================================================== */
      sprintf (test_command, "%cQUOTE", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	comm = command_quote (get_from_arg (string, 2));
/* ========================================================================== */

/* ===== TOPIC command ? ==================================================== */
      sprintf (test_command, "%cTOPIC", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	comm = command_topic (get_from_arg (string, 2));
/* ========================================================================== */

/* ===== QUERY command ? ==================================================== */
      sprintf (test_command, "%cQUERY", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	comm = command_query (get_arg (string, 2));
/* ========================================================================== */

/* ===== MODE command ? ===================================================== */
      sprintf (test_command, "%cMODE", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	comm = command_mode (get_from_arg (string, 2));
/* ========================================================================== */

/* ===== CTCP command ? ===================================================== */
      sprintf (test_command, "%cCTCP", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	comm = command_ctcp (get_arg (string, 2), upper_case (get_arg (string, 3)), get_from_arg (string, 4));
/* ========================================================================== */

/* ===== QUIT command ? ===================================================== */
      sprintf (test_command, "%cQUIT", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	  comm = command_quit (get_from_arg (string, 2));
/* ========================================================================== */

/* ===== MSG command ? ====================================================== */
      sprintf (test_command, "%cMSG", COMMAND_CHAR);
      if (strcomp (get_arg (string, 1), test_command))
	  comm = command_msg (get_arg(string, 2), get_from_arg (string, 3));
/* ========================================================================== */

	  
    }

/* === Unrecognised command ================================================= */
  if (!comm)
    text_error_not_a_cmd (strip_fchr (get_arg (string, 1)));
/* ========================================================================== */

}

/* ========================================================================== *
 * = Opens connection to 'server', port 'port' - Returns socket fd          = *
 * ========================================================================== */
int
connect_to_server (char *server, int port)
{
  int s;
  char line[MAXLEN], status_text[MAXLEN];
  sprintf (status_text, STATUS_CONNECTING, server, port);
  text_connect (server, port);
  gtk_label_set (GTK_LABEL (status), status_text);
  gtk_widget_show (icon_deconnect_pixmapwid);
  gtk_widget_hide (icon_connect_pixmapwid);
  s = open_socket (server, port);
  if (s == -1)
    {
      text_error_connect (server, port);
      return (-1);
    }
  gdk_input_add (s, GDK_INPUT_READ, (GdkInputFunction) parse_from_server, (int *) s);
  sprintf (buf, "NICK %s", me.nick);
  sendln (s, buf);
  sprintf (buf, "USER %s 0 0 :%s", me.user, me.gecos);	
  sendln (s, buf);
  connected = 0;
  return (s);
}

/* ========================================================================== *
 * = Close server connection & close socket 's' - Returns 1 if success,     = *
 * = 0 otherwise                                                            = *
 * ========================================================================== */
int
close_server_connection (int s, char *reason)
{
  if (connected == -1)
    return (0);
  connected = -1;
  gtk_label_set (GTK_LABEL (status), STATUS_NOT_CONNECTED);
  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (button_connect), FALSE);
  gtk_pixmap_set (GTK_PIXMAP(green_pixmapwid), green_off_pixmap, green_off_pixmapm);

  text_disconnected ();
  gtk_timeout_remove (check_lag_tag);
  gdk_input_remove (s);
  if (strlen (reason))
    sprintf (buf, "QUIT :%s", reason);
  else
    sprintf (buf, "QUIT :%s has no reason", me.nick);
  sendln (s, buf);
  close (s);
#ifdef DEBUG
  g_print ("[D] Closing server connection <irc.c/close_server_connection>\n");
#endif
  return (1);
}

/* ========================================================================== *
 * = Removes 'user' from userlist of channel 'chn'                          = *
 * ========================================================================== */
void
remove_from_userlist (int chn, char *user)
{
  int j;

#ifdef DEBUG
  g_print ("[D] Removing %s from userlist of channel %s <irc.c/remove_from_userlist>\n", user, channel[chn].name);
#endif
  for (i = 1; i <= channel[chn].nb_nops; i++)
    {
      if (strcomp (user, channel[chn].nops[i]))
	{
	  for (j = i; j < channel[chn].nb_nops; j++)
	    {
	      strcpy (channel[chn].nops[j], channel[chn].nops[j + 1]);
	    }
	  channel[chn].nb_nops--;
	  return;
	}
    }
  for (i = 1; i <= channel[chn].nb_ops; i++)
    {
      if (strcomp (user, channel[chn].ops[i]))
	{
	  for (j = i; j < channel[chn].nb_ops; j++)
	    {
	      strcpy (channel[chn].ops[j], channel[chn].ops[j + 1]);
	    }
	  channel[chn].nb_ops--;
	  return;
	}
    }
}

/* ========================================================================== *
 * = Adds 'user' to userlist of channel 'chn'                               = *
 * ========================================================================== */
void
add_to_userlist (int chn, char *user)
{
#ifdef DEBUG
  g_print ("[D] Adding %s to userlist of channel %s", user, channel[chn].name);
#endif
  if (user[0] == '@')
    {
      if (channel[chn].nb_ops < MAXLEN)
	{
	  channel[chn].nb_ops++;
	  strcpy (channel[chn].ops[channel[chn].nb_ops], strip_fchr (user));
	}
      else
	{
#ifdef DEBUG
	  g_print ("\n[D] ERROR : More than %i chanops, userlist is no more updated <irc.c/add_to_userlist>\n", MAXLEN);
#endif
return;
	}
    }
  else
    {
      if (channel[chn].nb_nops < MAXLEN)
	{
	  channel[chn].nb_nops++;
	  strcpy (channel[chn].nops[channel[chn].nb_nops], user);
	}
      else
	{
#ifdef DEBUG
	  g_print ("\n[D] ERROR : More than %i non-ops, userlist is no more updated <irc.c/add_to_userlist>\n",
		  MAXLEN);
#endif
return;
	}
    }
#ifdef DEBUG                                                                                              
  g_print (" [OK] <irc.c/add_to_userlist>\n");
#endif 
}

/* ========================================================================== *
 * = Returns 1 if 'nick' is in userlist 'chn'                               = *
 * ========================================================================== */
int
is_in_channel (int chn, char *nick)
{
  for (i = 1; i <= channel[chn].nb_ops; i++)
    {
      if (strcomp (nick, channel[chn].ops[i]))
	return 1;
    }
  for (i = 1; i <= channel[chn].nb_nops; i++)
    {
      if (strcomp (nick, channel[chn].nops[i]))
	return 1;
    }
  return 0;
}

int
check_lag (gpointer data)
{
#ifdef DEBUG
  g_print ("[D] Lag checking <irc.c/check_lag>\n");
#endif
  sprintf (buf, "PRIVMSG %s :\01PING %d\01", me.nick, get_seconds_counter ());
  sendln (s, buf);
  return (1);
}
