Initial commit, version 2.6.3a
authorFrancois Fleuret <francois@fleuret.org>
Sun, 6 Oct 2013 09:15:06 +0000 (11:15 +0200)
committerFrancois Fleuret <francois@fleuret.org>
Sun, 6 Oct 2013 09:15:06 +0000 (11:15 +0200)
Makefile [new file with mode: 0644]
README.txt [new file with mode: 0644]
list.cc [new file with mode: 0644]
objects.cc [new file with mode: 0644]
objects.h [new file with mode: 0644]
tblib.cc [new file with mode: 0644]
tblib.h [new file with mode: 0644]
tropbot.cc [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..1c72caf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,33 @@
+
+# Makefile for TropBot
+# Bug report & comments to <francois.fleuret@inria.fr>
+
+CC     =       g++
+
+OPTIONS =      -g
+
+# add -lsocket -lnsl for SOLARIS
+LIBS   =
+
+
+all:   tropbot
+
+tropbot: tropbot.cc tblib.o objects.o
+       $(CC) $(OPTIONS) -D SYSTEM=\"`uname`\" -D DATE="\"`date`\"" -o tropbot tblib.o objects.o tropbot.cc $(LIBS)
+
+tblib.o: tblib.cc tblib.h list.cc
+       $(CC) $(OPTIONS) -c tblib.cc
+
+objects.o: objects.cc objects.h list.cc
+       $(CC) $(OPTIONS) -c objects.cc
+
+clean:
+       rm *.o tropbot
+
+archive:
+       rm -f ../tropbot.tar.gz
+       tar -cvf ../tropbot.tar *.cc *.h *.txt Makefile
+       gzip ../tropbot.tar
+
+count:
+       wc *.cc *.h Makefile
diff --git a/README.txt b/README.txt
new file mode 100644 (file)
index 0000000..55b7d7f
--- /dev/null
@@ -0,0 +1,347 @@
+-------------------------------------------------------------------------------
+  TropBot v2.5
+  Documentation written by Francois Fleuret
+  Contact <francois.fleuret@inria.fr> for comments & bug reports
+  Check http://www.eleves.ens.fr:8080/home/fleuret for latest version
+-------------------------------------------------------------------------------
+
+-------------------------------------------------------------------------------
+I - INTRODUCTION --------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+TropBot is an IRC bot for UNIX system. If you don't know what is IRC,
+you should get some infos about it before trying to use TropBot.
+
+Many IRC Bots exist, and most of them are just extensions of
+"classical" bots like VladBot. TropBot was written from scratch, in
+C++. My goal was at first to make a short and easy to extend bot, just
+a small thing used in emergency cases on the #france channel on
+EFNet. After few months, TropBot became a real bot, with many
+features. He's still a fast and small bot, but he can defend a channel
+by himself. The version 2.2.0 was so stable that I have run one on
+#france for longer than one month with no reboot (when I finally
+killed it it was just to run a newer version).
+
+-------------------------------------------------------------------------------
+II - TROPBOT CAPABILITIES -----------------------------------------------------
+-------------------------------------------------------------------------------
+
+TropBot has all the main functions of an IRC bot. First, he has a list
+of friends. A friend is a pattern which matches nick!user@host
+stuff. Each of those pattern is associated with a level beetween 1 and
+4. Anybody matching one of those pattern will be considered to have
+the associated level.
+
+* Level 1 (FRIEND) allows someone to use the simplest functions of the
+bot (asking for the level of people, the shit-list, etc.)
+
+* Level 2 (OP) is the op level. With this level, one will get the +o
+automatically after a short delay, and will be allowed to use the
+shit-list (see below).
+
+* Level 3 (DEFENCE) is almost the same thing as level 2, except that
+the person will gain the +o without delay. This level is reserved to
+other bots of the channel. That way, during collide-attacks, the
+TropBot will re-op them faster.
+
+* Level 4 (MASTER) is the highest level and allows the person to use
+all the functions (like adding friends, etc.)
+
+The shit-list is a list of people who shouldn't be in the
+channel. Each entry of this list is a pattern, associated with a delay
+and a comment. Each time someone matching the pattern enters the
+channel, he will be banned & kicked with the comment. This feature is
+usefull against unpleasant people.
+
+Since v2.0.0, the TropBot has a smart handling of ban-list. He has in
+memory a copy of the ban list, so he is able to detect people entering
+the channel using hack and kick them; and he is also able to ban or
+unban only the required banid and avoid redudant +b/-b change mode.
+
+TropBot has also a anti-flood procedure. Each person sending more than
+4 lines in 2 s will be kicked. TropBot detects all kind of lines
+(PRIVMSG, NOTICE, NICK and even JOIN). It's pretty hard to make a good
+flood-detection algorithm. TropBot's one is far from perfection, but
+works quite nicely. If you have smart ideas to improve it, please mail
+me (I wrote a site-flood detection, but didn't include it ... I also
+made a routine that counts the number of caractere lines on the
+screen, but this kind of algorithm kick both bad and good guys :-))
+
+Since v2.3.4 TropBot accepts passwords for users on unsafe sites
+(i.e. sites where other people can fake their login). It's done in a
+very primitive way, so I guess one should use them only in critical
+situations. To use a command when you are a user with passwd, you just
+have to add &passwd before all command. In any case, the bot won't be
+able to recognize you after a split.
+
+Since v2.5.5, TropBot accepts DCC CHAT connections; those are direct
+socket connections, with no use of servers. This has few interests :
+the connection is most of the time faster, you can keep the connection
+even if splits occurs and if the bot and you are not on the same part
+of the net, there are no flood detection and you won't loose the
+connection even if the bots send you a lot of datas, etc. This kind of
+connection is great for commands like "who" "help" "shitlist" etc.
+
+-------------------------------------------------------------------------------
+II - HOW TO INSTALL TROPBOT ---------------------------------------------------
+-------------------------------------------------------------------------------
+
+I assume you've already downloaded & detared all the stuff, so you are
+supposed to have some files like tblic.cc, tblic.h, tropbot.cc,
+Makefile, etc. You just have to do a "make -k", and after a short
+compilation, you should obtain a tropbot executable file. I developped
+this program on both a Linux system, SunOS and SOLARIS (with gcc
+2.7.*), I really don't know what can happen on other systems ... hope
+it will work :-) If it doesn't, I fear I can't help you, I'm
+definitively NOT a UNIX wizard :-P
+
+-------------------------------------------------------------------------------
+III - HOW TO RUN TROPBOT ------------------------------------------------------
+-------------------------------------------------------------------------------
+
+The main goal of a bot is to stay in a channel 24h/day to keep the +o
+privileges so that he can give them to his friends when they enter the
+channel. To do that, a bot must run on a station which is connected to
+the net all the time.
+
+To run the TropBot, you need a tropbot binary (obtained after
+compilation). Then, just type "./tropbot" to run it. If you don't
+indicate any parameter, you will run a tropbot with the nickname
+"TropBot", connected to the server "sil.polytechnique.fr" on the port
+6667, and this bot will go to the channel "#tropbot". So, the best way
+to run a TropBot is the following :
+
+       nohup ./tropbot -n nickname -c "#channel" -h server
+
+The 'nohup' UNIX command will make the bot go on running even after
+you log out, and the parameters will set the nickname, the channel and
+the server (you MUST use your local servers, AFTER you have got an
+autorization from an IRCop ! Using a bot on a server without
+autorization can make you be killed or even K-lined. Being K-lined
+means that you'll never be able to use this server again).
+
+      NEVER PUT A BOT ON A SERVER WITH NO AUTHORIZATION FROM AN IRCOP
+
+The options you can use in the command lines are the following :
+
+ -c <#channel>       sets the channel
+ -d <delay in s>     sets the reconnection delay
+ -h <hostname>       sets the server name
+ -j <jam nickname>   sets the pattern nick for collision
+ -l <user>           sets the user in the user@host stuff
+ -n <nickname>       sets the nickname
+ -o <friends file>   loads config file
+ -od <op delay>      set the delay before +o of level 2 people
+ -p <port number>    sets the server port
+ -?                  shows help
+
+Most of those options are quite clear. The -d option allowed you to
+modify the delay the bot will wait before he tries to reconnect after
+he lost his connection. The -j option is used to give the bot a
+"generic nickname". The form of such a nickname is a caractere string
+with some '?' which will be replaced with random digits before
+use. That way the bot is able to generate random nicks if the nick you
+gave him is already used, or after a nick collision (by default the
+jam nick is "TB-????"). The -o option is used to load a configuration
+file (see below).
+
+-------------------------------------------------------------------------------
+IV - TROPBOT CONFIGURATION FILE -----------------------------------------------
+-------------------------------------------------------------------------------
+
+If you use the '-o' option, or the 'load' command on IRC, the TropBot
+will load a configuration file (.tropbotrc by default, but can be
+changed by both the '-o' option and the 'load'/'save' commands).
+
+The configuration file contains two kinds of lines. The "FRIEND"
+lines, who indicate a new friend, and the "SHIT" lines, who indicate
+who is supposed to be shit-listed.
+
+If you want this bot to op all people from united kingdom, just put in
+the configuration file the following line :
+
+FRIEND 2 *!*@*.uk
+
+This way, the bot will give a level 2 to all people whose
+nick!user@host matches *!*@*.uk, and a level 2 is an op level.
+
+          YOU MUST BE IN THIS LIST TO MAKE THE BOT RECOGNIZE YOU
+
+If you want the bot to shit-list all people from Ecole Polytechnique
+in France for 2 days (172800 s), with the comment "I don't like people
+with strange hats", just add :
+
+SHIT *!*@*.polytechnique.fr 172800 I don't like people with strange hats
+
+You can add a password in the configuration file just as a third
+parameter. For example
+
+FRIEND 2 *!*@*.fr trululu
+
+will make all people from France able to execute functions with a
+level 2 if they use the password trululu.
+
+-------------------------------------------------------------------------------
+V - TROPBOT FUNCTIONS ---------------------------------------------------------
+-------------------------------------------------------------------------------
+
+The functions you can use on a TropBot depend with your level in his
+list. For functions that accept both <nick> or <pattern> parameter, a
+pattern must contain at least one '@' and one '!' or the bot will
+consider it as a nickname.
+
+LEVEL 1 FUNCTIONS :
+
+"www" prints the URL of my home page, where you can find the latest
+version of TropBot
+
+"level [<nick>]" prints the level of the given person (or your own
+level if you don't give any parameter).
+
+"shitlist [<nick>!<pattern>]" (alias "sl") prints the shit-list, or
+the shits matched by a given pattern, or the shits that match a nick.
+
+LEVEL 2 & 3 FUNCTIONS :
+
+"alert" (alias "a") will put the channel in +m, shit the site who
+flooded the more during the last seconds, will kick all the nick on
+this site, and then will put the channel -m. This command is VERY
+usefull against clone bots.
+
+"antifloodoff <duration>" (alias "ao") will make suppress the
+anti-flood system for the given duration. This feature is interesting
+when the bot lagged because of network troubles.
+
+"deban { list of patterns }" (alias "db") remove from the ban-list all
+the entries who match one of the pattern
+
+"filterkick <nick>!<pattern> [<comment>]" (alias "fk") will kick all
+the people matching the pattern, or on the same site as the given nick
+
+"home" sends back to the home channel
+
+"join <#channel>" makes the bot leave the current channel and join
+#channel
+
+"op [{ nicks list }]" makes the bot give you the +o if no list is
+given, and give the +o to the given nicks if there is a list
+
+"pruneban <number>" (alias "pb") check the ban-list and keeps only the
+<number> first bans
+
+"punshit { <pattern> list }" (alias "pus") removes all the pattern
+that matches <pattern> from the shit-list (so "punshit *" will clear
+the shit-list).
+
+"shit <nick>!<pattern> [<duration> [<comment>]]" (alias "s") adds a
+pattern in the shit-list for a given duration. Each time a person
+matching this pattern enters the channel, he will be banned & kicked
+(with the given comment). If the parameter is a nickname, the bot will
+compute a nick!user@host pattern by itself (matching all the person
+with the same login, on the same site). The duration is the string
+like #d#h#m#s where the # are integer numbers. For example, 2d4h means
+2 days and 4 hours.
+
+"shithost <nick> <duration> <comment>" (alias "sh") adds a pattern
+that matches all the person from the <nick>'s host. Usefull for
+providers'people who can easily change their login in the login@host
+but have to hangup to change the modem/machine name.
+
+"shitsite <nick> <duration> <comment>" (alias "ss") adds a pattern
+that matches all the person from the <nick>'s site.
+
+"synch" makes the bot give the +o to all the people in the channel
+with a level greater than 2 (usefull when you want to re-synchronize a
+channel after hacks/splits, etc.)
+
+"unshit { <nick>!<pattern> list }" (alias "us") removes patterns from
+the shit-list, or all the pattern who match a given user.
+
+LEVEL 4 FUNCTIONS :
+
+"save [<file>]" saves the configuration file
+
+"load [<file>]" loads the configuration file
+
+"reset" kills the connection, randoms the nickname, reconnects, and
+rejoins.
+
+"friend <pattern> <level> [<passwd>]" adds someone in the friend list
+with the given level and passwd if specified
+
+"clone [<nick>]" starts a new session with the given nick or a random
+one
+
+"die" kills the bot
+
+"server <hostname> [<port>]" set the server name and the port number
+(6667 by default)
+
+"controlchar <char>" set the control character
+
+"opdelay <delay in s>" set the delay before +o when level 2 enter the
+channel
+
+"debandelay <delay in s>" set the delay before -b in case of +b by
+split
+
+USING PASSWORDS :
+
+If you have the password abcdef, to use a command with your level, you
+just have to add &abcdef before any command. For example,
+
+/msg TropBot &abcdef op
+
+will make the bot op you.
+
+USING DCCHAT :
+
+With a DCC CHAT connection to tropbot, you can send all the commands
+you use to send with /msg or with the control character in public. The
+bot will send you back the answers throught the DCC CHAT too.
+
+You gain two new commands, which can be used only in DCC CHAT :
+
+"users" (alias "u") that gives you the nick!user@host of all the
+people connected to the bot with DCC CHAT at the same time.
+
+"talk <msg>" (alias "t") that send a message to all the people
+connected with DCC CHAT.
+
+-------------------------------------------------------------------------------
+VI - CONCLUSION/BUGS ----------------------------------------------------------
+-------------------------------------------------------------------------------
+
+A bot is a complex program. This one, even if it's not very long has
+to deal with many buffers and strings operations. Such kind of program
+can't be 100% safe. I hope current version is stable, but I fear some
+buggs are still creeping somewhere.
+
+-------------------------------------------------------------------------------
+- AUTHOR ----------------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+Francois Fleuret
+
+E-mail :  <francois.fleuret@inria.fr>.
+IRCNICK : THX-1138 (EFNet, eureopean part, #france channel)
+
+I really DON'T appreciate questions about compilation, and I HATE
+questions whose answers are in this file. I appreciate suggestions and
+bug reports :P
+
+Snail mail :
+
+ Francois Fleuret
+ 16 Rue Pasteur
+ 78330 Fontenay le Fleury, FRANCE
+
+-------------------------------------------------------------------------------
+- ACKNOWLEDGEMENT -------------------------------------------------------------
+-------------------------------------------------------------------------------
+
+Linux, GCC, Emacs and XFree86 people ... I love you men ! :-)
+
+Jim Frost <jimf@world.std.com> for http://world.std.com/~jimf/sockets.html
+
+-------------------------------------------------------------------------------
diff --git a/list.cc b/list.cc
new file mode 100644 (file)
index 0000000..48c8ab2
--- /dev/null
+++ b/list.cc
@@ -0,0 +1,134 @@
+/*-----------------------------------------------------------------------------
+  List class
+  Written by Francois Fleuret <francois.fleuret@inria.fr>
+-----------------------------------------------------------------------------*/
+
+#ifndef LIST_H
+#define LIST_H
+
+#include <stdio.h>
+
+//-----------------------------------------------------------------------------
+
+template <class T>
+class NodeList
+{
+public:
+  T body;
+  NodeList<T> *next;
+};
+
+template <class T>
+class List
+{
+public:
+  NodeList<T> *first;
+
+  List();
+  ~List();
+  void Insert(T t);
+  NodeList<T> *DeleteNext(NodeList<T> *node);
+  void Remove(T t);
+  void Reverse();
+  int Lenght();
+};
+
+//-----------------------------------------------------------------------------
+
+template<class T>
+List<T>::List() { first = NULL; }
+
+template<class T>
+List<T>::~List()
+{
+  NodeList<T> *node, *suivant;
+  for(node=first; node != NULL;)
+    {
+      suivant = node->next;
+      delete node;
+      node = suivant;
+    };
+}
+
+template<class T>
+void List<T>::Insert(T t)
+{
+  NodeList<T> *node;
+  node = new NodeList<T>;
+  node->body = t;
+  node->next = first;
+  first = node;
+}
+
+template<class T>
+NodeList<T> *List<T>::DeleteNext(NodeList<T> *node)
+{
+  NodeList<T> *next;
+  if(node == 0)
+    {
+      next = first;
+      delete first;
+    }
+  else
+    {
+      next = node->next;
+      delete node;
+    }
+  return next;
+}
+
+template<class T>
+void List<T>::Remove(T t)
+{
+  NodeList<T> *node, *pred, *next;
+  node = first;
+  pred = NULL;
+  while(node != NULL)
+    {
+      if(node->body == t)
+       {
+         next = node->next;
+         if(pred == NULL) first = next;
+         else pred->next = next;
+         delete node;
+         node = next;
+       }
+      else
+       {
+         pred = node;
+         node = node->next;
+       };
+    };
+}
+
+template<class T>
+void List<T>::Reverse()
+{
+  NodeList<T> *node, *next, *pred;
+  node = first;
+  pred = NULL;
+  while(node != NULL)
+    {
+      next = node->next;
+      node->next = pred;
+      pred = node;
+      node = next;
+    };
+  first = pred;
+};
+
+template<class T>
+int List<T>::Lenght()
+{
+  NodeList<T> *node;
+  int l;
+  l = 0;
+  for(node=first; node != NULL; node = node->next) l++;
+  return l;
+}
+
+//-----------------------------------------------------------------------------
+
+#endif
+
+//-----------------------------------------------------------------------------
diff --git a/objects.cc b/objects.cc
new file mode 100644 (file)
index 0000000..7b305fc
--- /dev/null
@@ -0,0 +1,85 @@
+//-----------------------------------------------------------------------------
+
+#include "objects.h"
+#include "tblib.h"
+
+extern int current_time;
+
+//-----------------------------------------------------------------------------
+
+WaitInfos::WaitInfos(char *n, char *c, DCCChat *ch, char *u, int m, int d)
+{
+  nick = strdup(n);
+  comment = strdup(c);
+  chat = ch;
+  user = strdup(u);
+  mode = m;
+  duration = d;
+};
+
+WaitInfos::~WaitInfos()
+{
+  delete nick;
+  delete comment;
+  delete user;
+};
+
+Welcome::Welcome(char *p, char *c, int time)
+{
+  pattern = strdup(p);
+  comment = strdup(c);
+  time_max = time;
+};
+
+Welcome::~Welcome()
+{
+  delete pattern;
+  delete comment;
+};
+
+//-----------------------------------------------------------------------------
+
+DelayModeChange::DelayModeChange(char *w, char *m, char *p, int delay)
+{
+  where = strdup(w);
+  mode = strdup(m);
+  parameter = strdup(p);
+  time = delay+current_time;
+};
+
+DelayModeChange::~DelayModeChange()
+{
+  delete where;
+  delete mode;
+  delete parameter;
+};
+
+//-----------------------------------------------------------------------------
+
+Person::Person(char *p, int l, char *pwd)
+{
+  pattern = strdup(p);
+  level = l;
+  passwd = strdup(pwd);
+};
+
+Person::~Person()
+{
+  delete pattern;
+};
+
+//-----------------------------------------------------------------------------
+
+DCCChat::DCCChat(char *p, int s, int l)
+{
+  prefix = strdup(p);
+  socket = s;
+  level = l;
+};
+
+DCCChat::~DCCChat()
+{
+  delete prefix;
+};
+
+//-----------------------------------------------------------------------------
diff --git a/objects.h b/objects.h
new file mode 100644 (file)
index 0000000..48a92a8
--- /dev/null
+++ b/objects.h
@@ -0,0 +1,83 @@
+//-----------------------------------------------------------------------------
+
+#ifndef OBJECTS_H
+#define OBJECTS_H
+
+#include "list.cc"
+
+#define LEVEL_MAX 4
+#define LEVEL_MASTER 4
+#define LEVEL_DEFENCE 3
+#define LEVEL_OP 2
+#define LEVEL_FRIEND 1
+
+enum
+{
+  MODE_SHIT_NICK, MODE_SHIT_SITE, MODE_SHIT_HOST,
+  MODE_UNSHIT_NICK, MODE_UNBAN_NICK,
+  MODE_FILTER_KICK,
+  MODE_BAN_NICK, MODE_BAN_SITE,
+  MODE_LEVEL,
+  MODE_SHITLIST,
+  MODE_MSG
+};
+
+//-----------------------------------------------------------------------------
+
+class DCCChat
+{
+public:
+  char *prefix;
+  int socket;
+  int level;
+public:
+  DCCChat(char *p, int s, int l);
+  ~DCCChat();
+};
+
+class WaitInfos
+{
+public:
+  DCCChat *chat;
+  char *nick, *comment, *user;
+  int mode;
+  int duration;
+public:
+  WaitInfos(char *n, char *c, DCCChat *ch, char *u, int m, int d);
+  ~WaitInfos();
+};
+
+class Welcome
+{
+public:
+  char *pattern, *comment;
+  int time_max;
+public:
+  Welcome(char *p, char *c, int time);
+  ~Welcome();
+};
+
+class DelayModeChange
+{
+public:
+  char *where, *mode, *parameter;
+  int time;
+public:
+  DelayModeChange(char *w, char *m, char *p, int delay);
+  ~DelayModeChange();
+};
+
+class Person
+{
+public:
+  char *pattern;
+  char *passwd;
+  int level;
+public:
+  Person(char *p, int l, char *pwd);
+  ~Person();
+};
+
+//-----------------------------------------------------------------------------
+
+#endif
diff --git a/tblib.cc b/tblib.cc
new file mode 100644 (file)
index 0000000..b396fe9
--- /dev/null
+++ b/tblib.cc
@@ -0,0 +1,672 @@
+//-----------------------------------------------------------------------------
+
+#include "tblib.h"
+
+//-----------------------------------------------------------------------------
+
+char *cut_nick_from_prefix(char *name)
+{
+  char *s, *nick;
+  s = name;
+  while((*s != '!') && (*s != '\0')) s++;
+  nick = new char[s-name+1];
+  strncpy(nick, name, s-name);
+  *(nick+(s-name)) = '\0';
+  return nick;
+};
+
+//-----------------------------------------------------------------------------
+
+int is_weird_login(char *login)
+{
+  char *s;
+  s = login;
+  while((*s != '\0') && (*s != '!') &&
+       ((*s & 128) == 0) && (*s >= 32) && (*s != 127)) s++;
+  return (*s != '\0') || (*s == '!');
+}
+
+//-----------------------------------------------------------------------------
+
+int is_pattern(char *s)
+{
+  while((*s != '\0') && (*s != '!') && (*s != '*')) s++;
+  return (*s == '*') || (*s == '!');
+}
+
+//-----------------------------------------------------------------------------
+
+char *clean_banid(char *banid)
+{
+  char *result, *s, *t;
+  int joker_mode, min_car, k;
+
+  result = new char[strlen(banid)+1];
+
+  s = banid;
+  t = result;
+
+  joker_mode = 0;
+  while(*s != '\0')
+    {
+      if(*s == '*')
+       {
+         if(!joker_mode) min_car = 0;
+         joker_mode = 1;
+       }
+      else
+       {
+         if(*s == '?')
+           {
+             if(joker_mode) min_car++;
+             else *t++ = *s;
+           }
+         else
+           {
+             if(joker_mode)
+               {
+                 *t++ = '*';
+                 for(k=0; k<min_car; k++) *t++ = '?';
+                 joker_mode = 0;
+               }
+
+             if(((*s & 128) != 0) || (*s < 32) || (*s == 127)) *t++ = '?';
+             else *t++ = *s;
+           }
+       }
+      s++;
+    }
+
+  if(joker_mode)
+    {
+      *t++ = '*';
+      for(k=0; k<min_car; k++) *t++ = '?';
+    }
+  
+  *t++ = '\0';
+
+  return result;
+}
+
+//-----------------------------------------------------------------------------
+
+char *next_word(char *buffer, char *r, int buffer_size)
+{
+  char *s;
+  s = buffer;
+  if(r != NULL)
+    {
+      while((*r != '\0') && (*r != ' ') && (s<buffer+buffer_size-1))
+       *s++ = *r++;
+      while(*r == ' ') r++;
+      if(*r == '\0') r = NULL;
+    };
+  *s = '\0';
+  return r;
+};
+
+//-----------------------------------------------------------------------------
+
+int is_hostname(char *host)
+{
+  char *s;
+  s = host;
+  while((*s != '!') && (*s != '\0')) s++;
+  return *s == '\0';
+};
+
+int is_numeric(char *host)
+{
+  int r;
+  char *c;
+
+  r = 1;
+  for(c = host; *c != '\0'; c++)
+    {
+      r &= (((*c >='0') && (*c <= '9')) || (*c == '.'));
+      r |= (*c == '@');
+    };
+
+  return r;
+};
+
+int are_same_site(char *u1, char *u2)
+{
+  int n1, n2;
+  char *c1, *c2;
+
+  n1 = is_numeric(u1);
+  n2 = is_numeric(u2);
+
+  if(n1 && n2)
+    {
+      c1 = u1; c2 = u2;
+      while(*c1 != '\0') c1++; while((c1 > u1) && (*c1 != '.')) c1--;
+      while(*c2 != '\0') c2++; while((c2 > u2) && (*c2 != '.')) c2--;
+      if((c1-u1) == (c2-u2)) return strncmp(u1, u2, c1-u1) == 0;
+      else return 0;
+    };
+
+  if(!n1 && !n2)
+    {
+      while(*u1 != '.') u1++;
+      while(*u2 != '.') u2++;
+      return strcmp(u1, u2) == 0;
+    };
+
+  return 0;
+};
+
+// :CISMhp.Univ-Lyon1.FR 311 chose Johnkee gponcet@bi bi@192.93.80.208 * :Gael
+// :sil.polytechnique.fr 311 chose Johnkee gponcet bi@192.93.80.208 * :Gael 
+
+void concat_pattern_from_host(char *result, char *host)
+{
+  int r;
+  if(is_numeric(host))
+    {
+      r = 0;
+      while((*host != '\0') && (r<3))
+       {
+         *result++ = *host++;
+         if(*host == '.') r++;
+       };
+      concat(result, ".*");
+    }
+  else
+    {
+      *result++ = '*';
+      while((*host != '.') && (*host != '\0')) host++;
+      concat(result, host);
+    };
+  *result++ = '\0';
+};
+
+char *pattern_from_prefix(char *prefix, int site_pattern)
+{
+  char small_buffer[SMALL_BUFFER_SIZE];
+  int l;
+  char *c, *d, *pattern;
+
+  c = small_buffer;
+  d = prefix;
+  concat(c, "*!*");
+
+  // Skip the nickname
+  while((*d != '!') && (*d != '\0')) d++;
+
+  if(*d == '!')
+    if(site_pattern)
+      {
+       while((*d != '@') && (*d != '\0')) d++;
+      }
+    else
+      {
+       // Copy the login
+       d++;
+       if((*d == '~') || (*d == '+') ||
+          (*d == '-') || (*d=='^')) d++;
+       l = 0;
+       while((*d != '@') && (*d != '\0') &&
+             ((l<7) || *(d+1) == '\0')) { *c++ = *d++; l++; }
+       if((*d != '\0') && (*d != '@')) *c++ = '*';
+       while(*d != '@') d++;
+      };
+  *c++ = *d++;
+
+  concat_pattern_from_host(c, d);
+
+  pattern = new char[strlen(small_buffer)+1];
+  strcpy(pattern, small_buffer);
+
+  return pattern;
+};
+
+//-----------------------------------------------------------------------------
+
+int Contains(char *string, char c)
+{
+  while((*string != '\0') && (*string != c)) string++;
+  return *string == c;
+};
+
+int find_substring(char *&sub, char *&str)
+{
+  char *s, *u;
+  u = sub;
+  s = str;
+
+  if(*u == '\0') while(*s != '\0') s++;
+  else
+    while((*u != '\0') && (*u != '*') && (*s != '\0') &&
+         ((*u == *s) || (*u == '?'))) { u++; s++; };
+
+  if((*u == '\0') || (*u == '*'))
+    {
+      sub = u;
+      str = s;
+      return 1;
+    }
+  else
+    {
+      str++;
+      return 0;
+    };
+};
+
+int match_pattern(char *pattern, char *string)
+{
+  char *p, *s;
+  int ok;
+
+  if(pattern == NULL) return -1;
+  if(string == NULL) return 0;
+
+  p = pattern; s = string;
+
+  if(*p != '*') ok = find_substring(p, s);
+  else ok = 1;
+
+  while((*s != '\0') && (*p != '\0') && ok)
+    {
+      while(*p == '*') p++;
+      ok = 0;
+      while((*s != '\0') && !ok) ok = find_substring(p, s);
+    };
+
+  if((*p == '\0') && (*s != '\0') && ok)
+    {
+      while(*s != '\0') s++;
+      while((p>=pattern) && (s>=string) && ok && (*p != '*'))
+        {
+          ok = (*p == '?') || (*p == *s);
+          p--; s--;
+        }
+      return (*p == '*') || (p == pattern-1);
+    }
+  else return (*p == '\0') && (*s == '\0') && ok;
+};
+
+void uncap(char *string)
+{
+  char *s;
+  if(string != NULL)
+    {
+      s = string;
+      for(s = string; *s != '\0'; s++)
+       if((*s >= 'A') && (*s <= 'Z')) *s -= 'A'-'a';
+    };
+};
+
+char *strdup(char *s)
+{
+  char *t;
+  if(s == NULL) return NULL;
+  else
+    {
+      t = new char[strlen(s)+1];
+      strcpy(t, s);
+      return t;
+    };
+};
+
+int eq(char *s, char *t)
+{
+  return strcmp(s, t) == 0;
+};
+
+//-----------------------------------------------------------------------------
+
+char *seconds_to_string(int time)
+{
+  char buffer[128];
+  char *t, *u, *result;
+  int d, h, m, s;
+  int before;
+
+  s = time%60;
+  m = (time/60)%60;
+  h = (time/3600)%24;
+  d = time/86400;
+
+  t = buffer;
+
+  before = 0;
+  if(s>0)
+    {
+      before = 1;
+      *t++ = 's';
+      *t++ = (s%10)+'0';
+      if(s/10>0) *t++ = (s/10)+'0';
+    };
+  
+  if(m>0)
+    {
+      if(before) *t++ = ' ';
+      else before = 1;
+      concat(t, "nim");
+      *t++ = (m%10)+'0';
+      if(m/10>0) *t++ = (m/10)+'0';
+    };
+
+  if(h>0)
+    {
+      if(before) *t++ = ' ';
+      else before = 1;
+      *t++ = 'h';
+      *t++ = (h%10)+'0';
+      if(h/10>0) *t++ = (h/10)+'0';
+    };
+  
+  if(d>0)
+    {
+      if(before) *t++ = ' ';
+      else before = 1;
+      *t++ = 'd';
+      while(d>0)
+       {
+         *t++ = (d%10)+'0';
+         d /= 10;
+       };
+    };
+  
+  result = new char[(t-buffer)+1];
+  u = result;
+
+  t--;
+  while(t>=buffer) *u++ = *t--;
+  *u = '\0';
+
+  return result;
+};
+
+int string_to_seconds(char *string)
+{
+  int total;
+  int acc;
+  total = 0; acc = 0;
+  while(*string != '\0')
+    {
+      if((*string >= '0') && (*string <= '9')) acc = 10*acc + (*string - '0');
+      if(*string == 'd') { total = total+86400*acc; acc = 0; };
+      if(*string == 'h') { total = total+3600*acc; acc = 0; };
+      if(*string == 'm') { total = total+60*acc; acc = 0; }
+      if((*string == 's') || (*string == '\0')) { total = total+acc; acc = 0; }
+      string++;
+    };
+  return total;
+};
+
+//-----------------------------------------------------------------------------
+
+int call_socket(char *hostname, unsigned short portnum)
+{
+  struct sockaddr_in sa;
+  struct hostent     *hp;
+  int s;
+
+  if ((sa.sin_addr.s_addr = inet_addr(hostname)) == -1)
+    {
+      if ((hp = gethostbyname(hostname)) != NULL)
+       {
+         bzero((char *) &sa, sizeof(sa));
+         bcopy(hp->h_addr, (char *) &sa.sin_addr,
+               hp->h_length);
+         sa.sin_family = hp->h_addrtype;
+       }
+      else
+       return (-2);
+    }
+  else sa.sin_family = AF_INET;
+
+  sa.sin_port = (unsigned short) htons(portnum);
+
+
+
+/*
+  if(is_numeric(hostname))
+    {
+//      if ((hp = gethostbyaddr(hostname)) == NULL)
+      cerr<<"*** Can't use numeric IP ***\n";
+      return -1;
+    }
+  else
+    {
+      if ((hp = gethostbyname(hostname)) == NULL)
+       return -1;
+    };
+
+  cout<<"HP->H_ADDR >";
+  for(int k=0; k<hp->h_length; k++) cout<<"["<<hp->h_addr[k]<<"]";
+  cout<<"<\n";
+
+  memset(&sa,0,sizeof(sa));
+  memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length);
+  sa.sin_family= hp->h_addrtype;
+  sa.sin_port= htons((u_short)portnum);
+*/
+
+  if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0)   /* get socket */
+    return(-1);
+
+  if (connect(s, (struct sockaddr *) &sa, sizeof sa) < 0)      /* connect */
+    {
+      close(s);
+      return(-1);
+    }
+  return(s);
+}
+
+//-----------------------------------------------------------------------------
+
+int establish(unsigned short portnum)
+{
+  char   myname[MAXHOSTNAME+1];
+  int    s;
+  struct sockaddr_in sa;
+  struct hostent *hp;
+
+  memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */
+  gethostname(myname, MAXHOSTNAME);           /* who are we? */
+  hp= gethostbyname(myname);                  /* get our address info */
+  if (hp == NULL)                             /* we don't exist !? */
+    return(-1);
+  sa.sin_family= hp->h_addrtype;              /* this is our host address */
+  sa.sin_port= htons(portnum);                /* this is our port number */
+
+  if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */
+    return(-1);
+
+  if (bind(s,(struct sockaddr *)&sa,sizeof(struct sockaddr_in)) < 0)
+    {
+      close(s);
+      return(-1);                               /* bind address to socket */
+    }
+
+  listen(s, NB_QUEUE_CONNECTS);               /* max # of queued connects */
+  return(s);
+}
+
+//-----------------------------------------------------------------------------
+
+int get_connection(int s)
+{
+  int t;                  /* socket of connection */
+  if ((t = accept(s,NULL,NULL)) < 0)   /* accept connection if there is one */
+    return(-1);
+  return(t);
+}
+
+//-----------------------------------------------------------------------------
+
+int slice_buffer(char *&src, char *endsrc,
+                char *&prefix,
+                char *&dest_cmd,
+                char **slice_cmd, int &n_cmd,
+                char *&dest_ctcp,
+                char **slice_ctcp, int &n_ctcp)
+{
+  int end;
+  int ctcp, queue;
+
+  char *s;
+
+  s = src;
+  while((*s != '\r') && (*s != '\n') && (s<endsrc)) s++;
+  
+  if(s<endsrc)
+    {
+      end = 0;
+
+      n_cmd = 0;
+      n_ctcp = 0;
+      ctcp = 0;
+      queue = 0;
+      
+      if(*src == ':')
+       {
+         src++;
+         prefix = dest_ctcp;
+         while((src<endsrc) && (*src != ' '))
+           {
+             *dest_ctcp = *src;
+             dest_ctcp++;
+             src++;
+           };
+         *dest_ctcp = '\0';
+         dest_ctcp++;
+       }
+      else prefix = NULL;
+      
+      while((src < endsrc) && !end)
+       {
+         if((*src == ' ') || (*src == '\r') || (*src == '\n')
+            || (*src == '\001'))
+           {
+             if(*src == '\001')
+               {
+                 src++;
+                 slice_ctcp[n_ctcp++] = dest_ctcp;
+                 while((src<endsrc) && (*src != '\r') && (*src != '\001'))
+                   *dest_ctcp++ = *src++;
+                 *dest_ctcp = '\0';
+                 dest_ctcp++;
+                 if(src<endsrc)
+                   {
+                     end = (*src == '\r') || (*src == '\n');
+                     src++;
+                   }
+                 else end = 1;
+               }
+             else
+               {
+                 *dest_cmd = '\0';
+                 dest_cmd++;
+                 end = (*src == '\r') || (*src == '\n');
+                 src++;
+               };
+           }
+         else
+           {
+             if(!ctcp) slice_cmd[n_cmd++] = dest_cmd;
+             if(*src == ':')
+               {
+                 queue = 1;
+                 src++;
+               };
+             ctcp = 0;
+             while((src<endsrc) &&
+               ((*src != ' ') || queue) && (*src != '\r') && (*src != '\n') 
+                   && (*src != '\001'))
+               *dest_cmd++ = *src++;
+             ctcp = (*src == '\001');
+           };
+       };
+      if(src < endsrc) if(*src == '\n') src++; // Loose the '\n'
+      return 0;
+    }
+  else return 1;
+};
+
+//-----------------------------------------------------------------------------
+
+void ListChar::Print()
+{
+  NodeList<char *> *node;
+  for(node = first; node != NULL; node = node->next)
+    cout<<node->body<<"\n";
+};
+
+void ListChar::Clear()
+{
+  NodeList<char *> *node, *next;
+  node = first;
+  while(node != NULL)
+    {
+      next = node->next;
+      delete node->body;
+      delete node;
+      node = next;
+    };
+  first = NULL;
+};
+
+void ListChar::Add(char *s)
+{
+  char *p;
+  p = strdup(s);
+  uncap(p);
+  Insert(p);
+};
+
+void ListChar::Remove(char *s)
+{
+  NodeList<char *> *node, *pred, *next;
+
+  pred = NULL;
+  node = first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(strcmp(node->body, s) == 0)
+       {
+         if(pred == NULL) first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    };
+};
+
+int ListChar::Matches(char *s)
+{
+  NodeList<char *> *node;
+  int yep;
+  yep = 0;
+  for(node = first; (node != NULL) && !yep; node = node->next)
+    yep = match_pattern(node->body, s);
+  return yep;
+};
+
+int ListChar::IsMatchedBy(char *s)
+{
+  NodeList<char *> *node;
+  int yep;
+  yep = 0;
+  for(node = first; (node != NULL) && !yep; node = node->next)
+    yep = match_pattern(s, node->body);
+  return yep;
+};
+
+int ListChar::Contains(char *s)
+{
+  NodeList<char *> *node;
+  int yep;
+  yep = 0;
+  for(node = first; (node != NULL) && !yep; node = node->next)
+    yep = (strcmp(node->body, s) == 0);
+  return yep;
+};
+
diff --git a/tblib.h b/tblib.h
new file mode 100644 (file)
index 0000000..c5c1de7
--- /dev/null
+++ b/tblib.h
@@ -0,0 +1,154 @@
+/*-----------------------------------------------------------------------------
+  Thanks to http://world.std.com/~jimf/sockets.html
+-----------------------------------------------------------------------------*/
+
+#ifndef TBLIB_H
+#define TBLIB_H
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+
+#ifdef _AIX
+#include <sys/select.h>
+#endif
+
+#include <iostream.h>
+#include <string.h>
+
+#include "list.cc"
+
+//-----------------------------------------------------------------------------
+
+/*
+extern "C" int close(int);
+extern "C" int read(int, char *, int);
+extern "C" int gethostname();
+extern "C" size_t write(int, char *, int);
+extern "C" int socket(int, int, int);
+extern "C" int connect(int, struct sockaddr *, int);
+extern "C" int bind(int, struct sockaddr *, int);
+extern "C" int listen(int, int);
+extern "C" int accept(int, struct sockaddr *, int *);
+*/
+
+//-----------------------------------------------------------------------------
+
+#define BUFFER_SIZE 4096
+#define SMALL_BUFFER_SIZE 128
+
+#define NB_QUEUE_CONNECTS 3
+#define MAXHOSTNAME 64
+#define NB_SLICES_MAX 32
+
+//-----------------------------------------------------------------------------
+
+// This routine gets the nickame from the nick!user@host stuff
+
+char *cut_nick_from_prefix(char *name);
+
+int is_weird_login(char *login);
+
+int is_pattern(char *s);
+
+char *clean_banid(char *banid);
+
+//-----------------------------------------------------------------------------
+
+// This routine copy r in s, and move r to the next ' ', or sets it to
+// NULL if no more ' ' is find
+
+char *next_word(char *buffer, char *r, int buffer_size);
+
+//-----------------------------------------------------------------------------
+
+// This routine add the d string at the c car, and modify c
+//                       ** USE WITH CARE **
+
+inline void concat(char *&c, char *d)
+{
+  while(*d != '\0') *c++ = *d++;
+};
+
+//-----------------------------------------------------------------------------
+
+int is_hostname(char *host);
+
+// Evaluate if an IP is numerical or not
+
+int is_numeric(char *host);
+
+int are_same_site(char *u1, char *u2);
+
+//-----------------------------------------------------------------------------
+
+void concat_pattern_from_host(char *result, char *host);
+char *patter_from_prefix(char *prefix, int site_ban, char *&pattern);
+
+//-----------------------------------------------------------------------------
+
+int Contains(char *string, char c);
+int find_substring(char *string, char *substring,
+                  int *debut, int *debut_sub);
+
+// Send back if the string match pattern or not (pattern with '?' and
+// '*')
+
+int match_pattern(char *pattern, char *string);
+
+//-----------------------------------------------------------------------------
+
+// Uncap string
+void uncap(char *string);
+
+// Duplicate a string
+char *strdup(char *s);
+
+// Evaluate if strings are equal
+int eq(char *s, char *t);
+
+//-----------------------------------------------------------------------------
+
+char *seconds_to_string(int time);
+int string_to_seconds(char *string);
+
+//-----------------------------------------------------------------------------
+
+// Socket stuff
+
+int call_socket_ip(unsigned short host, unsigned short portnum);
+int call_socket(char *hostname, unsigned short portnum);
+int establish(unsigned short portnum);
+int get_connection(int s);
+
+//-----------------------------------------------------------------------------
+
+int slice_buffer(char *&src, char *endsrc,
+                char *&dest_cmd,
+                char *&prefix,
+                char **slice_cmd, int &n_cmd,
+                char *&dest_ctcp,
+                char **slice_ctcp, int &n_ctcp);
+
+//-----------------------------------------------------------------------------
+
+class ListChar : public List<char *>
+{
+public:
+  void Print();
+  void Clear();
+  void Add(char *s);
+  void Remove(char *s);
+  int Matches(char *s);
+  int IsMatchedBy(char *s);
+  int Contains(char *s);
+};
+
+//-----------------------------------------------------------------------------
+
+#endif
diff --git a/tropbot.cc b/tropbot.cc
new file mode 100644 (file)
index 0000000..13b85b2
--- /dev/null
@@ -0,0 +1,3363 @@
+/*-----------------------------------------------------------------------------
+  TropBot, a small IRC bot, v2.6 Dec 95 - Oct 96
+  Witten by Francois Fleuret.
+  Contact <francois.fleuret@inria.fr> for comments & bug reports
+  Check http://www.eleves.ens.fr:8080/home/fleuret for latest version
+-----------------------------------------------------------------------------*/
+
+#define VERSION "v2.6.3a"
+#define OPTIONS " + patch for mode -ko stuff"
+
+#include <time.h>
+#include <fstream.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "tblib.h"
+#include "objects.h"
+#include "list.cc"
+
+//-----------------------------------------------------------------------------
+
+#define SCREEN_OUTPUT
+
+//-----------------------------------------------------------------------------
+
+#define MODE_NUMBER_MAX 3
+#define SIZE_BANLIST_MAX 20
+#define NB_CHAR_MAX 400
+
+//-----------------------------------------------------------------------------
+
+#define DEFAULT_CONTROL_CHAR '|'
+#define DELAY_NICK_BACK 300
+#define DELAY_MAX_RECONNECT 300
+#define DELAY_DEAD_SERVER 900
+
+#define DEFAULT_SERVER "sil.polytechnique.fr"
+#define DEFAULT_PORT 6667
+
+#define DEFAULT_USER_NAME "\002TropBot\002 " VERSION OPTIONS
+#define DEFAULT_LOGIN "tropbot"
+#define DEFAULT_NICK "TropBot"
+#define DEFAULT_JAM_NICK "TB-????"
+#define DEFAULT_HOME_CHANNEL "#tropbot"
+#define DEFAULT_SOCKET_DELAY 30
+#define DEFAULT_OP_DELAY 2
+#define DEFAULT_DEBAN_DELAY 0
+
+#define DEFAULT_ANTI_FLOOD_OFF_DURATION 600
+
+#define DEFAULT_CONFIG_FILE ".tropbotrc"
+
+#define DEFAULT_SHIT_TIME 600
+#define DEFAULT_RESTRICTED_TIME 900
+
+#define DEFAULT_MODE_PROTECT 0
+
+// Not needed coz flooding people can't re-JOIN quickly
+//#define BAN_ON_FLOOD
+#define BAN_FLOOD_DELAY 30
+
+#define MAX_LINE_FLOOD 4
+#define MAX_CTCP_FLOOD 3
+#define FLOOD_DELAY 2
+#define DELAY_ANSWERS 3
+#define ANTI_CLONES_DELAY 30
+
+#define NB_SONS_MAX 3
+
+#define HISTORY_SIZE 3
+
+enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN };
+
+//-----------------------------------------------------------------------------
+
+#define MAX_DCC_CHAT 16
+
+//-----------------------------------------------------------------------------
+
+extern "C" void bzero(void *, int);
+extern "C" int select(int, fd_set *, fd_set *, fd_set *, timeval *);
+extern "C" pid_t fork(void); 
+
+//-----------------------------------------------------------------------------
+
+int default_port = DEFAULT_PORT;
+int wanted_port;
+char default_server[MAXHOSTNAME+1] = DEFAULT_SERVER;
+char wanted_server[MAXHOSTNAME+1];
+
+fd_set ready, result;
+int alive; // Should be set to false (0) to kill the bot
+int father, nb_sons;
+int socket_irc;
+int socket_delay = DEFAULT_SOCKET_DELAY;
+int op_delay = DEFAULT_OP_DELAY;
+int deban_delay = DEFAULT_DEBAN_DELAY;
+char control_char = DEFAULT_CONTROL_CHAR;
+
+int delay;
+timeval delay_pause;
+time_t current_time, time_killed, time_last_datas, last_answer_time,
+  anti_flood_off_until;
+char *src, *endsrc;
+char buffer[BUFFER_SIZE];
+
+int IRC_connected, IRC_registred;
+int global_state, in_channel, was_killed, mode_protect_on;
+
+#define STATE_WAIT 0
+#define STATE_GETING_WHO 1
+#define STATE_GETING_BAN 2
+
+//-----------------------------------------------------------------------------
+
+template class List<DCCChat *>;
+template class List<Person *>;
+template class List<Welcome *>;
+template class List<WaitInfos *>;
+template class List<DelayModeChange *>;
+template class List<char *>;
+
+List<DCCChat *> dcc_chat_list;
+List<Person *> level_list;
+List<Welcome *> shit_list;
+List<WaitInfos *> wait_list;
+List<DelayModeChange *> mode_change_list;
+
+ListChar present_people, banid_list, restricted_list, history;
+
+//-----------------------------------------------------------------------------
+
+// General buffer for all IRC operations
+char IRC_buffer[BUFFER_SIZE];
+
+// Nick we got after registration
+char real_nick[SMALL_BUFFER_SIZE];
+
+// Nick we want
+char wanted_nick[SMALL_BUFFER_SIZE];
+
+char original_nick[SMALL_BUFFER_SIZE] = DEFAULT_NICK;
+
+// Pattern used for random-nick generation if nick-collision occurs
+// all the '?' will be replaced with random digits
+char jam_nick[SMALL_BUFFER_SIZE] = DEFAULT_JAM_NICK;
+
+// The "user" we want in the nick!user@host stuff
+char user_login[SMALL_BUFFER_SIZE] = DEFAULT_LOGIN;
+
+// The USERNAME string
+char user_name[SMALL_BUFFER_SIZE] = DEFAULT_USER_NAME;
+
+// The channel we want to join
+char current_channel[SMALL_BUFFER_SIZE], wanted_channel[SMALL_BUFFER_SIZE];
+char home_channel[SMALL_BUFFER_SIZE] = DEFAULT_HOME_CHANNEL;
+
+// The name of the configuration file
+char config_file[SMALL_BUFFER_SIZE] = DEFAULT_CONFIG_FILE;
+
+//-----------------------------------------------------------------------------
+
+char *prefix_from_nick(char *nick)
+{
+  NodeList<char *> *node;
+  char *s, *t;
+  int yep;
+  yep = 0;
+
+  node = present_people.first;
+  while((node != NULL) && !yep)
+    {
+      yep = 1;
+      s = node->body;
+      t = nick;
+      while((*t != '\0') &&
+           (*s != '!') && (*s != '\0') && yep) yep &= (*s++ == *t++);
+      yep &= ((*t == '\0') && (*s == '!'));
+      if(!yep) node=node->next;
+    }
+
+  if(node != NULL) return node->body; else return NULL;
+
+}
+
+//-----------------------------------------------------------------------------
+
+int level_person(char *prefix, char *passwd)
+{
+  NodeList<Person *> *node;
+  int l;
+  l = 0;
+
+  for(node = level_list.first; node != NULL; node=node->next)
+    if(match_pattern(node->body->pattern, prefix))
+      if((node->body->level > l) || (l == 0))
+       {
+         if(node->body->passwd == NULL) l = node->body->level;
+         else
+           if(passwd != NULL)
+             if(strcmp(node->body->passwd, passwd) == 0)
+               l = node->body->level;
+       }
+  return l;
+}
+
+void remove_level(char *prefix)
+{
+  NodeList<Person *> *node, *pred, *next;
+  pred = NULL; next = NULL;
+
+  node = level_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(strcmp(node->body->pattern, prefix) == 0)
+       {
+         if(pred == NULL) level_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+void clear_levels()
+{
+  NodeList<Person *> *node, *next;
+
+  node = level_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      delete node->body;
+      delete node;
+      node = next;
+    }
+  level_list.first = NULL;
+}
+
+void clear_shit()
+{
+  NodeList<Welcome *> *node, *next;
+
+  node = shit_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      delete node->body;
+      delete node;
+      node = next;
+    }
+  shit_list.first = NULL;
+}
+
+void remove_wait_for_chat(DCCChat *chat)
+{
+  NodeList<WaitInfos *> *node, *pred, *next;
+  pred = NULL; next = NULL;
+
+  node = wait_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(node->body->chat == chat)
+       {
+         if(pred == NULL) wait_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function generates a random nick from a pattern. The pattern
+// is supposed to contain some '?', which will be replaced with random
+// digits.
+
+void rand_nick(char *nick, char *pattern)
+{
+  unsigned int n;
+  for(n=0; n<strlen(pattern); n++)
+    {
+      if(pattern[n] == '?') nick[n] = '0'+int(rand()%10);
+      else nick[n] = pattern[n];
+    }
+  nick[n]='\0';
+}
+
+//-----------------------------------------------------------------------------
+
+void kill_connection()
+{
+  time_last_datas = current_time;
+  IRC_connected = 0;                // We are not connected
+  IRC_registred = 0;                // We are not registred
+  FD_CLR(socket_irc, &ready);       // Forget the socket
+  close(socket_irc);                // Close it
+  present_people.Clear();           // We don't see anyone
+  rand_nick(wanted_nick, jam_nick); // Random the nick (yeah, we are paranoid)
+  was_killed = 1;                   // We have been killed (I said PARANOID !)
+  time_killed = current_time;       // Note when it happens
+  src = buffer;                     // Forget all the remaining datas
+  endsrc = buffer;                  // Idem.
+  delay = 0;                        // We won't wait for reconnection
+  in_channel = 0;                   // We are not in any channel
+  socket_irc = 0;
+}
+
+void clone(char *nick)
+{
+  if(fork() == 0)
+    {
+      strcpy(wanted_nick, nick);
+      strcpy(original_nick, nick);
+      IRC_connected = 0;
+      IRC_registred = 0;
+      FD_CLR(socket_irc, &ready);
+      present_people.Clear();
+      time_killed = current_time;
+      src = buffer;
+      endsrc = buffer;
+      delay = 0;
+      in_channel = 0;
+      father = 0;
+    }
+}
+
+void write_irc(char *stuff)
+{
+  // I'd like to know why do I have to do such a cast ?!?!
+  if((int) write(socket_irc, stuff, strlen(stuff)) < 0)
+    {
+      cerr<<"KILLING CONNECTION : write_irc error\n";
+      cerr.flush();
+      kill_connection();
+    }
+  else
+    {
+#ifdef SCREEN_OUTPUT
+      cout<<"\n!!!!>"<<stuff<<"<\n\n";
+#endif
+      last_answer_time = current_time;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+int nb_modes;
+
+char string_modes[MODE_NUMBER_MAX*2+1];
+char *ptr_modes;
+char string_param_modes[MODE_NUMBER_MAX*64+1];
+char *ptr_param_modes;
+int k_mode, o_mode;
+
+void reset_mode()
+{
+  nb_modes = 0;
+  ptr_modes = string_modes;
+  ptr_param_modes = string_param_modes;
+  k_mode = 0;
+  o_mode = 0;
+}
+
+void send_mode(char *where)
+{
+  if(nb_modes>0)
+    {
+      *ptr_modes = '\0';
+      *ptr_param_modes = '\0';
+      sprintf(IRC_buffer, "MODE %s %s %s\n",
+             where, string_modes, string_param_modes);
+      write_irc(IRC_buffer);
+      reset_mode();
+    }
+}
+
+void add_mode(char *where, char *mode, char *param)
+{
+  char *s;
+
+  // Disgusting hack coz of a FUCKING server bug :-(
+  if(mode[1] == 'o')
+    {
+      if(k_mode) send_mode(where);
+      o_mode = 1;
+    }
+
+  if(mode[1] == 'k')
+    {
+      if(o_mode) send_mode(where);
+      k_mode = 1;
+    }
+
+  s = mode;
+  while(*s != '\0') *ptr_modes++ = *s++;
+  if(param != NULL)
+    {
+      s = param;
+      while(*s != '\0') *ptr_param_modes++ = *s++;
+      *ptr_param_modes++ = ' ';
+    }
+
+  if(++nb_modes == MODE_NUMBER_MAX) send_mode(where);
+}
+
+//-----------------------------------------------------------------------------
+
+void tell(DCCChat *chat, char *nick, char *msg)
+{
+  char tell_buffer[BUFFER_SIZE];
+
+#ifdef SCREEN_OUTPUT
+  cout<<"tell(chat="<<chat<<", nick="<<nick<<" msg="<<msg<<")\n";
+  if(msg[strlen(msg)-1] != '\n')
+    cout<<"**************************************\n";
+#endif
+
+  if(chat != NULL) write(chat->socket, msg, strlen(msg));
+
+  if(nick != NULL)
+    {
+      sprintf(tell_buffer, "NOTICE %s :%s", nick, msg);
+      write_irc(tell_buffer);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void smart_shit(DCCChat *chat, char *nick,
+               char *pattern, char *comment, int duration)
+{
+  NodeList<Welcome *> *node, *next, *pred;
+  int no_shit;
+  int time_max, l;
+
+  if(duration < 5) duration = 5;
+
+  time_max = duration + current_time;
+
+  no_shit = 0;
+  node = shit_list.first;
+  pred = NULL;
+  while((node != NULL) && !no_shit)
+    {
+      next = node->next;
+      if(strcmp(node->body->pattern, pattern) == 0)
+       {
+         if(node->body->time_max <= time_max)
+           {
+             if(pred == NULL) shit_list.first = next;
+             else pred->next = next;
+             delete node->body;
+             delete node;
+           }
+         else
+           {
+             no_shit = 1;
+             pred = node;
+           }
+       }
+      else pred = node;
+      node = next;
+    }
+
+  if(!no_shit)
+    {
+      shit_list.Insert(new Welcome(pattern, comment, time_max));
+      if((nick != NULL) || (chat != NULL))
+       {
+         char *string_duration;
+         string_duration = seconds_to_string(duration);
+         sprintf(IRC_buffer, "Shit %s for %s (%s)\n",
+                 pattern, string_duration, comment);
+         tell(chat, nick, IRC_buffer);
+         delete string_duration;
+       }
+    }
+  else if((nick != NULL) || (chat != NULL))
+    {
+      sprintf(IRC_buffer,
+             "Can't shit %s, already shitted for a longer time\n", pattern);
+      tell(chat, nick, IRC_buffer);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void smart_ban(char *where, char *pattern)
+{
+  NodeList<char *> *node;
+  int n;
+  n = 0;
+  for(node = banid_list.first; node != NULL; node = node->next)
+    {
+      if((n>=SIZE_BANLIST_MAX-1) ||
+        (match_pattern(pattern, node->body) &&
+         (strcmp(pattern, node->body) != 0)))
+       add_mode(where, "-b", node->body);
+      else n++;
+    }
+  add_mode(current_channel, "+b", pattern);
+}
+
+void smart_unban(char *where, char *pattern)
+{
+  if(banid_list.Contains(pattern)) add_mode(where, "-b", pattern);
+}
+
+//-----------------------------------------------------------------------------
+
+void check_delay_mode_change()
+{
+  NodeList<DelayModeChange *> *node, *pred, *next;
+
+  pred = NULL;
+  node = mode_change_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(current_time >= node->body->time)
+       {
+         add_mode(node->body->where, node->body->mode, node->body->parameter);
+         if(pred == NULL) mode_change_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+void clean_delay_mode_change(char *where, char *mode, char *param)
+{
+  NodeList<DelayModeChange *> *node, *pred, *next;
+
+  uncap(param);
+  uncap(where);
+  pred = NULL;
+  node = mode_change_list.first;
+
+  if(param != NULL)
+    {
+      while(node != NULL)
+       {
+         next = node->next;
+         if((node->body->parameter != NULL) &&
+            (strcmp(where, node->body->where) == 0) &&
+            (strcmp(param, node->body->parameter) == 0) &&
+            (strcmp(mode, node->body->mode) == 0))
+           {
+             if(pred == NULL) mode_change_list.first = next;
+             else pred->next = next;
+             delete node->body;
+             delete node;
+           }
+         else pred = node;
+         node = next;
+       }
+    }
+  else
+    {
+      while(node != NULL)
+       {
+         next = node->next;
+         if((strcmp(where, node->body->where) == 0) &&
+            (node->body->parameter == NULL) &&
+            (strcmp(mode, node->body->mode) == 0))
+           {
+             if(pred == NULL) mode_change_list.first = next;
+             else pred->next = next;
+             delete node->body;
+             delete node;
+           }
+         else pred = node;
+         node = next;
+       }
+    }
+}
+
+void RemoveDelayModeChange(char *mode, char *parameter)
+{
+  NodeList<DelayModeChange *> *node, *pred, *next;
+
+  pred = NULL;
+  node = mode_change_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if((strcmp(node->body->mode, mode) == 0) &&
+        (strcmp(node->body->parameter, parameter) == 0))
+       {
+         if(pred == NULL) mode_change_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void synch(char *channel)
+{
+  char *nick;
+  NodeList<char *> *node;
+
+  for(node = present_people.first; node != NULL; node = node->next)
+    if(level_person(node->body, NULL) >= LEVEL_OP)
+      {
+       nick = cut_nick_from_prefix(node->body);
+       add_mode(channel, "+o", nick);
+       delete nick;
+      }
+}
+
+//-----------------------------------------------------------------------------
+
+void filter_kick(char *where, char *pattern, char *comment)
+{
+  NodeList<char *> *node;
+  char *nick;
+  for(node = present_people.first; node != NULL; node = node->next)
+    {
+      if(match_pattern(pattern, node->body))
+       if(level_person(node->body, NULL) == 0)
+         {
+           nick = cut_nick_from_prefix(node->body);
+           sprintf(IRC_buffer, "KICK %s %s :%s\n", where, nick, comment);
+           write_irc(IRC_buffer);
+           delete nick;
+         }
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+// Return a pointer on the first character after the last '@' in the string
+// Beware of some weird hack-script that add @ in the login
+char *adr_beginning(char *s)
+{
+  char *t;
+  t = s;
+  while(*s != '\0') if(*s++ == '@') t = s;
+  if(*t == '@') t++;
+  return t;
+}
+
+char *reach_loginathost(char *s)
+{
+  while((*s != '!') && (*s != '\0')) s++;
+  if(s != '\0') s++;
+  return s;
+}
+
+//-----------------------------------------------------------------------------
+
+class FloodLine
+{
+public:
+  char *prefix;
+  int kind;
+  int weigth;
+  int time;
+  int individual, site, alreadykicked;
+
+  FloodLine(char *p, int k, int w)
+  {
+    prefix = strdup(p);
+    time = current_time;
+    alreadykicked = 0;
+    kind = k;
+    weigth = w;
+  }
+
+  ~FloodLine() { delete prefix; }
+  void Reset() { individual = 0; site = 0; }
+};
+
+template class List<FloodLine *>;
+
+List<FloodLine *> flood_list;
+
+//-----------------------------------------------------------------------------
+
+void alert(char *where, DCCChat *chat, char *nick)
+{
+  int nb_lines, max_nb_lines, duration;
+  NodeList<FloodLine *> *node, *son;
+  char *site, *site2, *guilty_site, *r;
+  char pattern[SMALL_BUFFER_SIZE];
+
+  for(node = flood_list.first; node != NULL; node = node->next)
+    node->body->individual = 0;
+
+  node = flood_list.first;
+
+  max_nb_lines = 1;
+  guilty_site = NULL;
+
+  while(node != NULL)
+    {
+      while((node != NULL) && node->body->individual) node = node->next;
+      if(node != NULL)
+       {
+         nb_lines = 0;
+         site = adr_beginning(node->body->prefix);
+         
+         son = node;
+         while(son != NULL)
+           {
+             while((son != NULL) && son->body->individual) son = son->next;
+             if(son != NULL)
+               {
+                 site2 = adr_beginning(son->body->prefix);
+                 
+                 if(are_same_site(site, site2))
+                   {
+                     son->body->individual = 1;
+                     nb_lines++;
+                   }
+                 son = son->next;
+               }
+           }
+         
+         if(nb_lines > max_nb_lines)
+           if(level_person(node->body->prefix, NULL) == 0)
+             {
+               max_nb_lines = nb_lines;
+               guilty_site = site;
+             }
+         node = node->next;
+       }
+    }
+
+  if(guilty_site != NULL)
+    {
+      duration = DEFAULT_SHIT_TIME;
+      r = pattern;
+      *r++ = '*'; *r++ = '!'; *r++ = '*'; *r++ = '@';
+      concat_pattern_from_host(r, guilty_site);
+      add_mode(where, "+m", NULL);
+      smart_shit(NULL, NULL, pattern, "Alert", duration);
+      smart_ban(where, pattern);
+      send_mode(where);
+      filter_kick(where, pattern, "Filter kick on alert");
+      add_mode(where, "-m", NULL);
+      send_mode(where);
+    }
+  else tell(chat, nick, "\002No flooding site detected\002\n");
+}
+
+void check_one_flood(NodeList<FloodLine *> *node)
+{
+  NodeList<FloodLine *> *son;
+  char *userhost, *userhost2, *nick;
+  int nb_lines;
+
+  userhost = reach_loginathost(node->body->prefix);
+  
+  nb_lines = 0;
+  son = node;
+  while(son != NULL)
+    {
+      while((son != NULL) && son->body->individual) son = son->next;
+      if(son != NULL)
+       {
+         if(!son->body->alreadykicked)
+           {
+             userhost2 = reach_loginathost(son->body->prefix);
+             
+             if(strcmp(userhost, userhost2) == 0)
+               {
+                 son->body->individual = 1;
+                 nb_lines++;
+               }
+           }
+         son = son->next;
+       }
+    }
+
+  if(nb_lines >= MAX_LINE_FLOOD)
+    {
+
+#ifdef BAN_ON_FLOOD
+      char *pattern, *banid;
+      if((level_person(node->body->prefix, NULL) < LEVEL_OP))
+       {
+         pattern = pattern(node->body->prefix, 0);
+         banid = clean_banid(pattern);
+         smart_ban(current_channel, banid);
+         send_mode(current_channel);
+         mode_change_list.Insert(new DelayModeChange(current_channel,
+                                                     "-b", banid,
+                                                     BAN_FLOOD_DELAY));
+         delete banid;
+         delete pattern;
+       }
+#endif
+      
+      nick = cut_nick_from_prefix(node->body->prefix);
+      sprintf(IRC_buffer, "KICK %s %s :%s\n", current_channel, nick, "Flood");
+      write_irc(IRC_buffer);
+      delete nick;
+      
+      for(son = flood_list.first; son != NULL; son = son->next)
+       {
+         userhost2 = reach_loginathost(son->body->prefix);
+         if(strcmp(userhost, userhost2) == 0) son->body->alreadykicked = 1;
+       }
+    }
+
+}
+
+void check_flood()
+{
+  int nb_lines, nb_ctcp;
+  NodeList<FloodLine *> *node, *next, *pred;
+
+  nb_lines = 0; nb_ctcp = 0;
+  pred = NULL;
+  node = flood_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(node->body->time >= current_time - FLOOD_DELAY)
+       {
+         nb_lines += node->body->weigth;
+         if((node->body->kind == FL_CTCP)  && !node->body->alreadykicked)
+           nb_ctcp += node->body->weigth;
+         pred = node;
+         node->body->Reset();
+       }
+      else
+       {
+         if(pred == NULL) flood_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      node = next;
+    }
+
+  /*
+    if(nb_ctcp >= MAX_CTCP_FLOOD)
+    {
+    add_mode(current_channel, "+m", NULL);
+    send_mode(current_channel);
+    mode_change_list.Insert(new DelayModeChange(current_channel,
+    "-m", NULL,
+    ANTI_CLONES_DELAY));
+    }
+    */
+
+  if(nb_lines >= MAX_LINE_FLOOD)
+    {
+      for(node = flood_list.first; node != NULL; node = node->next)
+       node->body->individual = 0;
+
+      node = flood_list.first;
+      while(node != NULL)
+       {
+         while((node != NULL) && node->body->individual) node = node->next;
+         if(node != NULL)
+           {
+             if(!node->body->alreadykicked) check_one_flood(node);
+             node = node->next;
+           }
+       }
+    }
+}
+
+inline void add_flood_line(char *prefix, int kind, int weigth)
+{
+  flood_list.Insert(new FloodLine(prefix, kind, weigth));
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called for all mode changes
+// signe indicates if it's a + or - mode change
+// param is NULL for mode change without parameters
+
+void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
+{
+  char *c, *banid;
+  char buffer[3];
+
+  if(signe < 0) buffer[0] = '-'; else buffer[0] = '+';
+  buffer[1] = mode;
+  buffer[2] = '\0';
+  if(param != NULL) uncap(param);
+
+  clean_delay_mode_change(where, buffer, param);
+
+#ifdef SCREEN_OUTPUT
+  cout<<"ONE MODE CHANGE CHANNEL ("<<where<<")";
+  cout<<" BY ("<<who<<") MODE "<<signe<<" "<<mode;
+  cout<<" ON "<<param<<"\n";
+#endif
+
+  uncap(param);
+
+  // Basic anti-hack procedure. All +o and +b mode done by servers are
+  // canceled (we have to look if the person is a friend or not)
+  switch(mode)
+    {
+    case 'b':
+      if(is_hostname(who))
+       {       
+         if(deban_delay == 0)
+           {
+             if(signe>0) add_mode(where, "-b", param);
+             else add_mode(where, "+b", param);
+           }
+         else
+           {
+             if(signe>0)
+               mode_change_list.Insert(new DelayModeChange(where, "-b", param,
+                                                           deban_delay));
+             else
+               mode_change_list.Insert(new DelayModeChange(where, "+b", param,
+                                                           deban_delay));
+           }
+       }
+
+      if(signe > 0)
+       {
+         banid_list.Add(param);
+         banid = clean_banid(param);
+         if(strcmp(banid, param) != 0) smart_ban(where, banid);
+         delete banid;
+       }
+      else banid_list.Remove(param);
+      break;
+
+    case 'o':
+      if(is_hostname(who))
+       {
+         c = prefix_from_nick(param);
+         if((signe > 0) && (level_person(c, NULL) < LEVEL_FRIEND))
+           add_mode(where, "-o", param);
+         if((signe < 0) && (level_person(c, NULL) >= LEVEL_FRIEND))
+           add_mode(where, "+o", param);
+       }
+      else
+       if((signe<0) &&
+          (level_person(who, NULL) <
+           level_person(prefix_from_nick(param), NULL)) &&
+          (level_person(prefix_from_nick(param), NULL) > 0))
+         {
+           c = cut_nick_from_prefix(who);
+           add_mode(where, "-o", c);
+           add_mode(where, "+o", param);
+           delete c;
+         }
+      break;
+
+    case 'i':
+      if(signe>0) if(is_hostname(who) || mode_protect_on)
+       add_mode(where, "-i", NULL);
+      break; 
+
+    case 'l':
+      if(signe>0) if(is_hostname(who) || mode_protect_on)
+       add_mode(where, "-l", NULL);
+      break; 
+
+    case 'p':
+      if(signe>0) if(is_hostname(who) || mode_protect_on)
+       add_mode(where, "-p", NULL);
+      break;
+
+    case 'k':
+      if(signe>0) if(is_hostname(who) || mode_protect_on)
+       add_mode(where, "-k", param);
+      break;
+
+    case 'm':
+      if(is_hostname(who))
+       {
+         if(signe>0) add_mode(where, "-m", NULL);
+       }
+      else if(mode_protect_on)
+       {
+         if(level_person(who, NULL) < LEVEL_OP)
+           {
+             if(signe>0) add_mode(where, "-m", NULL);
+             else add_mode(where, "+m", NULL);
+             c = cut_nick_from_prefix(who);
+             add_mode(where, "-o", c);
+             delete c;
+           }
+       }
+      break;
+
+    case 's':
+      if(signe>0) if(is_hostname(who) || mode_protect_on)
+       add_mode(where, "-s", NULL);
+      break;
+
+    default:
+      break;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a "MODE" command
+// You should not modify it, unless you find a bug.
+// Modify only IRC_ONE_MODE()
+
+void IRC_MODE(char *where, char *who, char *mode, char **params)
+{
+  int param_no, signe;
+
+  param_no = 0;
+  signe = 1;
+  while(*mode != '\0')
+    {
+      switch(*mode)
+       {
+       case '+':
+         signe = 1;
+         break;
+       case '-':
+         signe = -1;
+         break;
+       default:
+         if((*mode == 'l') || (*mode == 'v') ||
+            (*mode == 'k') || (*mode == 'o') ||
+            (*mode == 'b'))
+           IRC_ONE_MODE(where, who, signe, *mode, params[param_no++]);
+         else
+           IRC_ONE_MODE(where, who, signe, *mode, NULL);
+
+         break;
+       }
+      mode++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void get_one_line(ifstream *s, char *buffer, int buffer_size)
+{
+  char *c;
+  int d, ok;
+  c = buffer;
+  ok = 1;
+  while(ok)
+    {
+      d = s->get();
+      if(d>0)
+       {
+         if(d != '\n') *c++ = d;
+         else ok = 0;
+       }
+      else ok = 0;
+      ok &= (c<buffer + buffer_size);
+    }
+  *c = '\0';
+}
+
+int LoadConfigFile(char *name)
+{
+  ifstream *file;
+  int duration, level, error;
+  char *r, *banid;
+  char pattern[SMALL_BUFFER_SIZE], buffer[SMALL_BUFFER_SIZE];
+
+  file = new ifstream(name);
+  if(!file->fail())
+    {
+      clear_levels();
+      clear_shit();
+      restricted_list.Clear();
+      while(!file->eof())
+       {
+         get_one_line(file, IRC_buffer, BUFFER_SIZE);
+         if(strlen(IRC_buffer) > 0)
+           {
+             r = IRC_buffer;
+             r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+             if(strcmp(buffer, "FRIEND") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     level = atoi(buffer);
+                     if(r!= NULL)
+                       {
+                         r = next_word(pattern, r, SMALL_BUFFER_SIZE);
+                         uncap(pattern);
+                         level_list.Insert(new Person(pattern, level, r));
+                       }
+                   }
+               }
+             else if(strcmp(buffer, "RESTRICTED") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     cout<<"RESTRICTED->"<<buffer<<"\n";
+                     restricted_list.Insert(strdup(buffer));
+                   }
+               }
+             else if(strcmp(buffer, "SHIT") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     r = next_word(pattern, r, SMALL_BUFFER_SIZE);
+                     uncap(pattern);
+                     if(r != NULL)
+                       {
+                         r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                         duration = atoi(buffer);
+                         if(r == NULL) r = "Shit";
+                         banid = clean_banid(pattern);
+                         smart_shit(NULL, NULL, banid, r, duration);
+                         delete banid;
+                       }
+                   }
+               }
+             else if(strcmp(buffer, "OPDELAY") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     op_delay = atoi(buffer);
+                   }
+               }
+             else if(strcmp(buffer, "DEBANDELAY") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     deban_delay = atoi(buffer);
+                   }
+               }
+             else if(strcmp(buffer, "CONTROLCHAR") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     if(buffer[0] != '\0') control_char = buffer[0];
+                   }
+               }
+           }
+       }
+      shit_list.Reverse();
+      level_list.Reverse();
+      restricted_list.Reverse();
+      error = 0;
+    }
+  else error = 1;
+
+  delete file;
+
+  return error;
+}
+
+int SaveConfigFile(char *name)
+{
+  ofstream *file;
+  NodeList<Welcome *> *welcome;
+  NodeList<Person *> *person;
+  NodeList<char *> *restricted;
+  int error;
+
+  file = new ofstream(name);
+  if(!file->fail())
+    {
+      (*file)<<"% Config file for a TropBot " VERSION "\n";
+      (*file)<<"\n";
+
+      (*file)<<"OPDELAY "<<op_delay<<"\n";
+      (*file)<<"DEBANDELAY "<<deban_delay<<"\n";
+      (*file)<<"CONTROLCHAR "<<control_char<<"\n";
+
+      (*file)<<"\n";
+
+      for(person=level_list.first; person != NULL; person=person->next)
+       {
+         (*file)<<"FRIEND "<<person->body->level<<" "<<person->body->pattern;
+         if(person->body->passwd != NULL) (*file)<<" "<<person->body->passwd;
+         (*file)<<"\n";
+       }
+
+      (*file)<<"\n";
+
+      for(restricted=restricted_list.first;
+         restricted != NULL;
+         restricted=restricted->next)
+       (*file)<<"RESTRICTED "<<restricted->body<<"\n";
+
+      (*file)<<"\n";
+
+      for(welcome=shit_list.first; welcome != NULL; welcome=welcome->next)
+       (*file)<<"SHIT "<<welcome->body->pattern<<" "<<
+         welcome->body->time_max - current_time<<" "<<
+         welcome->body->comment<<"\n";
+
+      error = 0;
+    }
+  else error = 1;
+
+  delete file;
+
+  return error;
+}
+
+//-----------------------------------------------------------------------------
+
+void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
+{
+  NodeList<char *> *node1, *node2;
+  int *ok, nb, k, l, level, put_blank;
+  char *c, *d, *buf;
+  int nb_total, nb_person[LEVEL_MAX+1];
+
+  nb_total = 0;
+  for(k=0; k<LEVEL_MAX+1; k++) nb_person[k] = 0;
+
+  nb = present_people.Lenght();
+  ok = new int[nb];
+  for(k = 0; k<nb; k++) ok[k] = 0;
+  k = 0;
+  node1 = present_people.first;
+
+  buf = IRC_buffer;
+
+  cerr<<"PATTERN=>"<<pattern<<"<\n";
+
+  if(pattern != NULL)
+    {
+      concat(buf, "\002");
+      concat(buf, pattern);
+      concat(buf, "\002 and same site : ");
+    }
+
+  while(node1 != NULL)
+    {
+      cout<<"    =>"<<node1->body<<"\n";
+
+      if((pattern == NULL) || match_pattern(pattern, node1->body))
+       {
+         c = adr_beginning(node1->body);
+         put_blank = 0;
+         l = k;
+         node2 = node1;
+         while(node2 != NULL)
+           {
+             d = adr_beginning(node2->body);
+             if(are_same_site(c, d))
+               {
+                 d = node2->body;
+                 level = level_person(d, NULL);
+                 nb_total++;
+                 nb_person[level]++;
+                 if(put_blank) *buf++ = '/'; else put_blank = 1;
+                 
+                 if(level == LEVEL_OP) *buf++ = '\002';
+                 else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
+                 
+                 while((*d != '!') && (*d != '\0')) *buf++ = *d++;
+                 
+                 if(level == LEVEL_OP) *buf++ = '\002';
+                 else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
+                 
+                 ok[l] = 1;
+                 
+                 if(buf > IRC_buffer + NB_CHAR_MAX)
+                   {
+                     *buf++ = '\n'; *buf++ = '\0';
+                     tell(chat, nick, IRC_buffer);
+                     buf = IRC_buffer;
+                   }
+               }
+             
+             do
+               {
+                 l++;
+                 node2 = node2->next;
+               }
+             while((node2 != NULL) && (ok[l] == 1));
+           }
+         
+         concat(buf, " ");
+       }
+
+      do
+       {
+         k++;
+         node1 = node1->next;
+       }
+      while((node1 != NULL) && (ok[k] == 1));
+    }
+
+  *buf++ = '\n'; *buf++ = '\0';
+  tell(chat, nick, IRC_buffer);
+
+  sprintf(IRC_buffer, "Total %d (\002%d\002)\n",
+         nb_total,
+         nb_person[LEVEL_OP] + nb_person[LEVEL_DEFENCE] +
+         nb_person[LEVEL_MASTER]);
+  tell(chat, nick, IRC_buffer);
+
+  delete ok;
+}
+
+//-----------------------------------------------------------------------------
+
+void notice_shit_list(DCCChat *chat, char *nick, char *pattern, int matched)
+{
+  int n;
+  char *string_duration;
+  NodeList<Welcome *> *node;
+
+  if(shit_list.Lenght() == 0) tell(chat, nick, "\002Empty shit-list\002\n");
+  else
+    {
+      n = 0;
+      for(node = shit_list.first; node != NULL; node=node->next)
+       if((matched && match_pattern(pattern, node->body->pattern))
+          || (!matched && match_pattern(node->body->pattern, pattern)))
+         {
+           n++;
+           string_duration = seconds_to_string(node->body->time_max
+                                               - current_time);
+
+           sprintf(IRC_buffer, "%s for %s (%s)\n",
+                   node->body->pattern,
+                   string_duration,
+                   node->body->comment);
+           tell(chat, nick, IRC_buffer);
+           delete string_duration;
+         }
+
+      if(n == 0) tell(chat, nick, "\002No corresponding shits\002\n");
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void add_in_history(char *prefix, char *action)
+{
+  NodeList<char *> *node, *pred, *next;
+  char *s, *t;
+  int n;
+
+  s = new char[strlen(prefix) + strlen(action) + 4];
+  t = s;
+  concat(t, prefix);
+  concat(t, " : ");
+  concat(t, action);
+  *t++ = '\0';
+  history.Add(s);
+
+  n = 0;
+  pred = NULL; next = NULL; node = history.first;
+  while(node != NULL)
+    {
+      n++;
+      next = node->next;
+      if(n>HISTORY_SIZE)
+       {
+         if(pred == NULL) history.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+void notice_history(DCCChat *chat, char *nick)
+{
+  NodeList<char *> *node;
+
+  for(node = history.first; node != NULL; node = node->next)
+    {
+      sprintf(IRC_buffer, "%s\n", node->body);
+      tell(chat, nick, IRC_buffer);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+int dont_flood_server()
+{
+  return current_time >= last_answer_time + DELAY_ANSWERS;
+}
+
+void msg_users(DCCChat *chat, char *nick, char *pattern, char *msg)
+{
+  NodeList<char *> *node;
+  char *nick_user;
+  int nb;
+
+  sprintf(IRC_buffer, "\002[msg to %s]\002 %s\n", pattern, msg);
+  tell(chat, nick, IRC_buffer);
+
+  nb = 0;
+  for(node = present_people.first; node != NULL; node = node->next)
+    {
+      if(match_pattern(pattern, node->body))
+       {
+         nb++;
+         nick_user = cut_nick_from_prefix(node->body);
+         sprintf(IRC_buffer, "PRIVMSG %s :\002[msg to %s]\002 %s\n",
+                 nick_user, pattern, msg);
+         write_irc(IRC_buffer);
+         delete nick_user;
+       }
+    }
+
+  sprintf(IRC_buffer, "\002[msg sent to %d user(s)]\002\n", nb);
+  tell(chat, nick, IRC_buffer);
+};
+
+//-----------------------------------------------------------------------------
+
+#define CMD_DEFAULT 0
+#define CMD_JOIN 1
+#define CMD_HOME 2
+#define CMD_BAN 3
+#define CMD_SBAN 4
+
+void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
+{
+  char buffer[SMALL_BUFFER_SIZE], buffer_time[SMALL_BUFFER_SIZE];
+  char *r, *s, *c, *banid;
+  char *string_duration;
+  int cmd, level, l, no_authorized, od;
+  int duration;
+  NodeList<DCCChat *> *node;
+
+  r = msg;
+
+  if(r != NULL)
+    {
+      r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+      if(*buffer == '&')
+       {
+         level = level_person(prefix, buffer+1);
+         if(r != NULL) r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+         else return;
+       }
+      else level = level_person(prefix, NULL);
+
+      cmd = CMD_DEFAULT;
+      if(eq("join", buffer)) cmd = CMD_JOIN;
+      else if(eq("home", buffer)) cmd = CMD_HOME;
+      else if(eq("b", buffer) || eq("ban", buffer)) cmd = CMD_BAN;
+      else if(eq("sb", buffer) || eq("siteban", buffer)) cmd = CMD_SBAN;
+
+      no_authorized = 0;
+
+      if(eq("ms", buffer) || eq("myshit", buffer))
+       {
+         if(dont_flood_server()) notice_shit_list(chat, nick, prefix, 0);
+       }
+      else if(eq("sl", buffer) || eq("shitlist", buffer))
+       {
+         if(level >= LEVEL_FRIEND)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 uncap(buffer);
+
+                 if(is_pattern(buffer)) notice_shit_list(chat, nick, buffer, 1);
+                 else
+                   {
+                     wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
+                                                    MODE_SHITLIST, 0));
+                     
+                     sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                     write_irc(IRC_buffer);
+                   }
+               }
+             else notice_shit_list(chat, nick, "*", 1);
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("www", buffer))
+       {
+         if(dont_flood_server())
+           tell(chat, nick, "THX-1138's home page at "
+                "http://www.eleves.ens.fr:8080/home/fleuret/\n");
+       }
+      else if(eq("w", buffer) || eq("who", buffer))
+       {
+         if(level >= LEVEL_FRIEND)
+           {
+             if(r == NULL) notice_list_by_sites(chat, nick, NULL);
+             else while(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 /*
+                 if(!is_pattern(buffer))
+                   {
+                     s = buffer;
+                     while(*s != '\0') s++;
+                     concat(s, "!*");
+                     *s++ == '\0';
+                   }
+                   */
+                 uncap(buffer);
+                 notice_list_by_sites(chat, nick, buffer);
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("ao", buffer) || eq("antifloodoff", buffer))
+       {
+         if(r != NULL)
+           {
+             r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+             duration =  string_to_seconds(buffer_time);
+             anti_flood_off_until = current_time + duration;
+           }
+         if(anti_flood_off_until > current_time)
+           {
+             string_duration = seconds_to_string(anti_flood_off_until - 
+                                                 current_time);
+             sprintf(IRC_buffer, "Anti-flood off for %s\n",
+                     string_duration);
+             delete string_duration;
+             
+             tell(chat, nick, IRC_buffer);
+           }
+         else tell(chat, nick, "Anti-flood on\n");
+       }
+      else if(eq("msg", buffer) || eq("message", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 if(r != NULL)
+                   {
+                     if(is_pattern(buffer)) msg_users(chat, nick, buffer, r);
+                     else
+                       {
+                         uncap(buffer);
+                         wait_list.Insert(new WaitInfos(buffer, r, chat,
+                                                        nick,
+                                                        MODE_MSG, 0));
+                         
+                         sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                         write_irc(IRC_buffer);
+                       }
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("h", buffer) || eq("history", buffer))
+       {
+         if(level >= LEVEL_OP) notice_history(chat, nick);
+         else no_authorized = 1;
+       }
+      else if(eq("level", buffer))
+       {
+         if(level >= LEVEL_FRIEND)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 uncap(buffer);
+
+                 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+                                                MODE_LEVEL, 0));
+                 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                 write_irc(IRC_buffer);
+               }
+             else
+               {
+                 sprintf(IRC_buffer, "%s is level %d\n", prefix,
+                         level_person(prefix, NULL));
+                 tell(chat, nick, IRC_buffer);
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("help", buffer))
+       {
+         if(dont_flood_server() || (level >= LEVEL_FRIEND))
+           {
+             if(father)
+               {
+                 sprintf(IRC_buffer,
+                         "control_char '%c' op_delay %ds  deban_delay %ds"
+                         " your level is %d. I am a father with %d sons.\n",
+                         control_char, op_delay, deban_delay,
+                         level, nb_sons);
+                 tell(chat, nick, IRC_buffer);
+               }
+             else
+               {
+                 sprintf(IRC_buffer,
+                         "control_char '%c' op_delay %ds  deban_delay %ds"
+                         " your level is %d. I'm a clone.\n",
+                         control_char, op_delay, deban_delay, level);
+                 tell(chat, nick, IRC_buffer);
+               }
+           }
+
+         if(level >= LEVEL_FRIEND)
+           {
+             tell(chat, nick, "\002help\002  \002www\002  \002\037s\037\002hit\037l\037\002ist\002 [<nick>!<pattern>]  \002level\002 [<nick>]  \002\037w\037\002ho\002 \002\037m\037\002y\037s\037\002hit\002\n");
+           }
+
+         if(level >= LEVEL_OP)
+           {
+             tell(chat, nick, "\002\037a\037\002ntiflood\037o\037\002ff\002 [<duration>]  \002\037a\037\002lert\002  \002home\002  \002op\002 [{<nick> list}]  \002join\002 <#channel>  \002nick\002 <nick>  \002\037p\037\002rune\037b\037\002an\002 <number>  \002\037d\037\002e\037b\037\002an\002 {<pattern> list}  \002\037f\037\002ilter\037k\037\002ick\002 <pattern>!<nick> [<comment>]  \002\037s\037\002hit/\037s\037\002hit\037s\037\002ite/\037s\037\002hit\037h\037\002ost\002 <pattern>!<nick> [<duration> [<comment>]]  \002\037u\037\002n\037s\037\002hit\002 {<pattern>!<nick> list}  \002\037pu\037\002n\037s\037\002hit\002 {<pattern> list} \002\037b\037\002an/\037s\037\002ite\037b\037\002an\002 <pattern>!<nick>  \002synch\002  \002\037h\037\002istory\002\n  \002\037m\037\002es\037s\037\002a\037g\037\002e\002 <nick>!<pattern> <msg>\n");
+           }
+
+         if(level >= LEVEL_MASTER)
+           {
+             tell(chat, nick, "\002reset\002  \002load\002 [<file>]  \002save\002 [<file>]  \002friend\002 <pattern> <level> [<passwd>]  \002clone\002 [<nick>]  \002die\002  \002server\002 <hostname> [<port>]  \002controlchar\002 <char>  \002opdelay\002 <delay in s>  \002debandelay\002 <delay in s>\n");
+           }
+
+         if(chat != NULL)
+           {
+             tell(chat, nick, "\002\037u\037\002sers\002  \002\037t\037\002alk\002 <msg>\n");
+           }
+
+       }
+      else if((cmd == CMD_JOIN) || (cmd == CMD_HOME))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(global_state == STATE_WAIT)
+               {
+                 sprintf(IRC_buffer, "PART %s\n", current_channel);
+                 write_irc(IRC_buffer);
+                 if(cmd == CMD_HOME)
+                   strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
+                 else
+                   if(r != NULL)
+                     { 
+                       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                       strncpy(wanted_channel, buffer, SMALL_BUFFER_SIZE);
+                     }
+                 uncap(wanted_channel);
+                 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
+                 write_irc(IRC_buffer);
+               }
+             else
+               tell(chat, nick, "Can't join right now, retry in a while\n");
+           } else no_authorized = 1;
+       }
+      else if(eq("op", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r == NULL) add_mode(current_channel, "+o", nick);
+             else
+               while(r != NULL)
+                 {
+                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                   add_mode(current_channel, "+o", buffer);
+                 }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("nick", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(wanted_nick, r, SMALL_BUFFER_SIZE);
+                 sprintf(buffer, "NICK %s\n", wanted_nick);
+                 write_irc(buffer);
+               }
+           } else no_authorized = 1;
+       }
+      else if(eq("db", buffer) || eq("deban", buffer))
+       {
+         if(level >= LEVEL_FRIEND)
+           {
+             while(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 if(is_pattern(buffer))
+                   {
+                     NodeList<char *> *node;
+                     for(node = banid_list.first; node != NULL; node = node->next)
+                       if(match_pattern(buffer, node->body))
+                         add_mode(current_channel, "-b", node->body);
+                   }
+                 else
+                   {
+                     wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
+                                                    MODE_UNBAN_NICK, 0));
+                     sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                     write_irc(IRC_buffer);
+                   }
+               }
+           } else no_authorized = 1;
+       }
+      else if((cmd == CMD_BAN) || (cmd == CMD_SBAN))
+       {
+         if(level >= LEVEL_OP)
+           {
+             while(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 uncap(buffer);
+                 
+                 if(is_pattern(buffer))
+                   {
+                     banid = clean_banid(buffer);
+                     smart_ban(current_channel, banid);
+                     delete banid;
+                   }
+                 else
+                   {
+                     switch(cmd)
+                       {
+                       case CMD_BAN:
+                         wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+                                                        MODE_BAN_NICK, 0));
+                         break;
+                       case CMD_SBAN:
+                         wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+                                                        MODE_BAN_SITE, 0));
+                         break;
+                       default:
+                         break;
+                       }
+                     sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                     write_irc(IRC_buffer);
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("pb", buffer) || eq("pruneban", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 NodeList<char *> *node;
+                 int n;
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 n = atoi(buffer);
+                 if(n >= 0)
+                   {
+                     for(node = banid_list.first; node != NULL;
+                         node = node->next)
+                       if(n == 0) add_mode(current_channel, "-b", node->body);
+                       else n--;
+                   }
+               }
+           } else no_authorized = 1;
+       }
+      else if(eq("synch", buffer))
+       {
+         if(level >= LEVEL_OP) synch(current_channel);
+         else no_authorized = 1;
+       }
+      else if(eq("s", buffer) || eq("shit", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 
+                 if(is_pattern(buffer))
+                   {
+                     if(r != NULL)
+                       {
+                         r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+                         duration =  string_to_seconds(buffer_time);
+                       }
+                     else duration = DEFAULT_SHIT_TIME;
+
+                     if(r == NULL) r = "Shit nick";
+
+                     uncap(buffer);
+                     banid = clean_banid(buffer);
+                     smart_shit(chat, nick, banid, r, duration);
+                     delete banid;
+                   }
+                 else
+                   {
+                     if(r != NULL)
+                       {
+                         r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+                         duration = string_to_seconds(buffer_time);
+                       }
+                     else duration = DEFAULT_SHIT_TIME;
+
+                     if(r == NULL) r = "Shit nick";
+
+                     uncap(buffer);
+                     wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+                                                    MODE_SHIT_NICK,
+                                                    duration));
+
+                     sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                     write_irc(IRC_buffer);
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+
+      else if(eq("fk", buffer) || eq("filterkick", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 uncap(buffer);
+                 if(is_pattern(buffer))
+                   {
+                     if(r == NULL) r = "Filter kick";
+                     filter_kick(current_channel, buffer, r);
+                   }
+                 else
+                   {
+                     if(r == NULL) r = "Filter Kick";
+                     wait_list.Insert(new
+                                      WaitInfos(buffer, r, chat, nick,
+                                                MODE_FILTER_KICK, 0));
+                     sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                     write_irc(IRC_buffer);
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+
+      else if(eq("a", buffer) || eq("alert", buffer))
+       {
+         if(level >= LEVEL_OP) alert(current_channel, chat, nick);
+         else no_authorized = 1;
+       }
+
+      else if(eq("sh", buffer) || eq("shithost", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+                     duration = string_to_seconds(buffer_time);
+                   }
+                 else duration = DEFAULT_SHIT_TIME;
+
+                 if(r == NULL) r = "Shit host";
+
+                 uncap(buffer);
+                 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+                                                MODE_SHIT_HOST, duration));
+
+                 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                 write_irc(IRC_buffer);
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("ss", buffer) || eq("shitsite", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+                     duration = string_to_seconds(buffer_time);
+                   }
+                 else duration = DEFAULT_SHIT_TIME;
+
+                 if(r == NULL) r = "Shit site";
+
+                 uncap(buffer);
+                 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+                                                MODE_SHIT_SITE, duration));
+
+                 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                 write_irc(IRC_buffer);
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("pus", buffer) || eq("punshit", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             while(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 
+                 if(strlen(buffer) > 0)
+                   {
+                     NodeList<Welcome *> *node, *next, *pred;
+                     pred = NULL;
+                     uncap(buffer);
+                     node = shit_list.first;
+                     while(node != NULL)
+                       {
+                         next = node->next;
+                         if(match_pattern(buffer, node->body->pattern))
+                           {
+                             smart_unban(current_channel, node->body->pattern);
+                             if(pred == NULL) shit_list.first = next;
+                             else pred->next = next;
+                             sprintf(IRC_buffer,
+                                     "Unshit %s (%s)\n",
+                                     node->body->pattern,
+                                     node->body->comment);
+                             tell(chat, nick, IRC_buffer);
+                             delete node->body;
+                             delete node;
+                           }
+                         else pred = node;
+                         node = next;
+                       }
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("us", buffer) || eq("unshit", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             while(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 
+                 uncap(buffer);
+                 if(is_pattern(buffer))
+                   {
+                     NodeList<Welcome *> *node, *next, *pred;
+                     pred = NULL;
+                     uncap(buffer);
+                     node = shit_list.first;
+                     while(node != NULL)
+                       {
+                         next = node->next;
+                         if(strcmp(node->body->pattern, buffer) == 0)
+                           {
+                             if(pred == NULL) shit_list.first = next;
+                             else pred->next = next;
+                             sprintf(IRC_buffer,
+                                     "Unshit %s (%s)\n",
+                                     buffer, node->body->comment);
+                             tell(chat, nick, IRC_buffer);
+                             delete node->body;
+                             delete node;
+                           }
+                         else pred = node;
+                         node = next;
+                       }
+                   }
+                 else
+                   {
+                     wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
+                                                    MODE_UNSHIT_NICK, 0));
+                     
+                     sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+                     write_irc(IRC_buffer);
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("friend", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+                     l = atoi(buffer_time);
+                     if((l > 0) && (l<=LEVEL_MASTER))
+                       {
+                         level_list.Insert(new Person(buffer, l, r));
+                         sprintf(IRC_buffer,
+                                 "Adding %s with level %d and passwd %s\n",
+                                 buffer, l, r);
+                         tell(chat, nick, IRC_buffer);
+                         SaveConfigFile(config_file);
+                       }
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("opdelay", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 od = atoi(buffer);
+                 if((od>=0) && (od <= 60))
+                   {
+                     op_delay = od;
+                     sprintf(IRC_buffer,"Oping delay set to %ds\n", op_delay);
+                     tell(chat, nick, IRC_buffer);
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("debandelay", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 od = atoi(buffer);
+                 if((od>=0) && (od <= 60))
+                   {
+                     deban_delay = od;
+                     sprintf(IRC_buffer,
+                             "Deban delay set to %ds\n",
+                             deban_delay);
+                     tell(chat, nick, IRC_buffer);
+                   }
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("controlchar", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 control_char = buffer[0];
+                 sprintf(IRC_buffer, "Control char set to '%c'\n",
+                         control_char);
+                 tell(chat, nick, IRC_buffer);
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("die", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             sprintf(IRC_buffer, "QUIT :Killed by %s\n", nick);
+             write_irc(IRC_buffer);
+             alive = 0;
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("server", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL)
+               {
+                 next_word(wanted_server, r, SMALL_BUFFER_SIZE);
+                 if(r != NULL)
+                   {
+                     next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     wanted_port = atoi(buffer);
+                     if(wanted_port == 0) wanted_port = 6667;
+                   }
+                 else wanted_port = DEFAULT_PORT;
+
+                 sprintf(IRC_buffer,
+                         "Trying to connect %s:%d\n",
+                         wanted_server, wanted_port);
+                 tell(chat, nick, IRC_buffer);
+                 
+                 sprintf(IRC_buffer, "QUIT :Changing server\n");
+                 write_irc(IRC_buffer);
+
+                 cerr<<"KILLING CONNECTION : Changing server\n";
+                 cerr.flush();
+                 kill_connection();
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("clone", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(father)
+               {
+                 if(nb_sons < NB_SONS_MAX)
+                   {
+                     if(r != NULL) next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     clone(buffer);
+                     nb_sons++;
+                   }
+                 else tell(chat, nick, "Too many clones, can't clone\n");
+               }
+             else
+               {
+                 tell(chat, nick, "I'm a clone, can't clone\n");
+               }
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("save", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
+             if(SaveConfigFile(config_file))
+               {
+                 sprintf(IRC_buffer,
+                         "Can't save the %s configuration file\n",
+                         config_file);
+               }
+             else
+               {
+                 sprintf(IRC_buffer,
+                         "Saving the %s configuration file\n",
+                         config_file);
+               }
+             tell(chat, nick, IRC_buffer);
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("load", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
+             if(LoadConfigFile(config_file))
+               {
+                 sprintf(IRC_buffer,
+                         "Can't load the %s configuration file\n",
+                         config_file);
+               }
+             else
+               {
+                 sprintf(IRC_buffer,
+                         "Loading the %s configuration file\n",
+                         config_file);
+               }
+             tell(chat, nick, IRC_buffer);
+           }
+         else no_authorized = 1;
+       }
+      else if(eq("reset", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             sprintf(IRC_buffer, "QUIT :reset command sent by %s\n", nick);
+             write_irc(IRC_buffer);
+             cerr<<"KILLING CONNECTION : Die\n";
+             cerr.flush();
+             kill_connection();
+           }
+         else no_authorized = 1;
+       }
+
+      // DCC CHAT only commands
+
+      else if((chat != NULL) && (eq("t", buffer) || eq("talk", buffer)))
+       {
+         NodeList<DCCChat *> *node;
+         sprintf(IRC_buffer, "<%s> %s\n", prefix, r);
+         for(node = dcc_chat_list.first; node != NULL; node = node->next)
+           if(node->body != chat) tell(node->body, NULL, IRC_buffer);
+       }
+      else if((chat != NULL) && (eq("u", buffer) || eq("users", buffer)))
+       {
+         for(node = dcc_chat_list.first; node != NULL; node = node->next)
+           {
+             sprintf(IRC_buffer, "%s\n", node->body->prefix);
+             tell(chat, NULL, IRC_buffer);
+           }
+       }
+
+      // Unknown command
+
+      else if(dont_flood_server())
+       {
+         sprintf(IRC_buffer, "Unknown command \002%s\002\n", buffer);
+         tell(chat, nick, IRC_buffer);
+       }
+    }
+  
+  if(no_authorized)
+    {
+      if(dont_flood_server())
+       {
+         sprintf(IRC_buffer,
+                 "You are not authorized to use \002%s\002\n", buffer);
+         tell(chat, nick, IRC_buffer);
+       }
+    }
+  else
+    {
+      r = msg;
+      if(*r == '&') r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+      add_in_history(prefix, r);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+int accepting_dcc_chat(char *prefix, char *nick, int level, char *r)
+{
+  NodeList<DCCChat *> *node;
+  int socket, port_number;
+  char host[SMALL_BUFFER_SIZE], port[SMALL_BUFFER_SIZE];
+  DCCChat *dcc_chat;
+  
+  if(r == NULL) return 1;
+  else r = next_word(host, r, SMALL_BUFFER_SIZE);
+
+  if(strcmp(host, "chat") != 0) return 1;
+
+  if(r == NULL) return 1;
+  else r = next_word(host, r, SMALL_BUFFER_SIZE);
+
+  if(r == NULL) return 1;
+  else r = next_word(port, r, SMALL_BUFFER_SIZE);
+
+  port_number = atoi(port);
+  socket = call_socket(host, port_number);
+
+  if(socket <= 0) return 1;
+  else
+    {
+      dcc_chat = new DCCChat(prefix, socket, port_number);
+      dcc_chat_list.Insert(dcc_chat);
+
+      FD_SET(socket, &ready);
+
+      sprintf(IRC_buffer,
+             "Welcome to \002TropBot\002 " VERSION " on a DCC CHAT\n"
+             "You are known as %s, your level is %d.\n"
+             "You are client #%d on DCC CHAT\n",
+             prefix, level, dcc_chat_list.Lenght());
+
+      write(socket, IRC_buffer, strlen(IRC_buffer));
+
+      sprintf(IRC_buffer, "%s arrives with level %d.\n", prefix, level);
+      for(node=dcc_chat_list.first; node!= NULL; node = node->next)
+       if(node->body != dcc_chat) tell(node->body, NULL, IRC_buffer);
+
+      return 0;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a NOTICE
+
+void IRC_NOTICE(char *prefix,
+               char *who, char *msg, char **slice_ctcp, int n_ctcp)
+{
+  uncap(who);
+  if(strcmp(who, current_channel) == 0) add_flood_line(prefix, FL_NOTICE, 1);
+}
+
+void IRC_PRIVMSG(char *prefix,
+                char *who, char *msg, char **slice_ctcp, int n_ctcp)
+{
+  int k, version, ping, level;
+  char *nick, *r;
+  char buffer[SMALL_BUFFER_SIZE];
+
+  uncap(who);
+  nick = cut_nick_from_prefix(prefix);
+  if(strcmp(who, current_channel) == 0)
+    {
+      add_flood_line(prefix, FL_PUBLIC, 1);
+      if(n_ctcp > 0) add_flood_line(prefix, FL_CTCP, n_ctcp);
+    }
+
+  if(msg != NULL) if(strlen(msg)>0)
+    {
+      if(msg[0] == control_char) tropbot_cmd(NULL, prefix, nick, msg+1);
+      else if(strcmp(who, real_nick) == 0) tropbot_cmd(NULL, prefix, nick, msg);
+    }
+
+  
+
+  version = 0;
+  ping = 0;
+  for(k=0; k<n_ctcp; k++)
+    {
+      r = slice_ctcp[k];
+      r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+      // Reply the CTCP VERSION
+      if(eq("VERSION", buffer) && !version)
+       {
+         if(dont_flood_server())
+           {
+             version = 1;
+             sprintf(IRC_buffer, "NOTICE %s :"
+                     "\001VERSION \002TropBot\002 " VERSION OPTIONS
+                     ", " SYSTEM " system, " DATE ". "
+                     "Contact THX-1138 on IRC, or <francois.fleuret@inria.fr>"
+                     "\001\n",
+                     nick);
+             write_irc(IRC_buffer);
+           }
+       }
+      // Reply the CTCP PING
+      else if(eq("PING", buffer) && !ping)
+       {
+         ping = 1;
+         if(r != NULL)
+           if(dont_flood_server())
+             {
+               ping = 1;
+               r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+               sprintf(IRC_buffer,
+                       "NOTICE %s :\001PING %s\001\n", nick, buffer);
+               write_irc(IRC_buffer);
+             }
+       }
+      // DCC (chat)
+      else if(eq("DCC", buffer))
+       {
+         level = level_person(prefix, NULL);
+         if(level >= LEVEL_OP)
+           {
+             if(r != NULL)
+               {
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 if(eq("CHAT", buffer))
+                   {
+                     if(accepting_dcc_chat(prefix, nick, level, r) != 0)
+                       {
+                         sprintf(IRC_buffer, "NOTICE %s :\002Error\002"
+                                 " can't connect\n", nick);
+                         write_irc(IRC_buffer);
+                       }
+                   }
+                 else
+                   {
+                     sprintf(IRC_buffer,
+                             "NOTICE %s :I can only DCC CHAT\n", nick);
+                     write_irc(IRC_buffer);
+                   }
+               }
+           }
+         else if(dont_flood_server())
+           {
+             sprintf(IRC_buffer,
+                     "NOTICE %s :Sorry, can't accept DCC from you\n",
+                     nick, buffer);
+             write_irc(IRC_buffer);
+           }
+       }
+    }
+  delete nick;
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a QUIT
+
+void IRC_QUIT(char *prefix)
+{
+  present_people.Remove(prefix);
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a NICK
+
+void IRC_NICK(char *prefix, char *nick)
+{
+  char *s, *t;
+  int ok;
+  add_flood_line(prefix, FL_NICK, 1);
+  present_people.Remove(prefix);
+  s = IRC_buffer;
+  t = nick; while(*t != '\0') *s++=*t++; // copy the nick
+  *s++='!';                           // put the '!'
+  t = reach_loginathost(prefix);
+  while(*t != '\0') *s++=*t++;           // copy the user@host
+  *s = '\0';                          // end of string
+  present_people.Add(IRC_buffer);     // hop !
+
+  ok = 1; s = prefix; t = real_nick;
+  while(ok && (*t != '\0') && (*s != '\0')) ok = (*s++ == *t++);
+  if(ok && (*t == '\0') && (*s == '!'))
+    {
+      strncpy(real_nick, nick, SMALL_BUFFER_SIZE);
+      uncap(real_nick);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a PART
+
+void IRC_PART(char *prefix, char *where)
+{
+  char *nick;
+  add_flood_line(prefix, FL_PART, 1);
+  present_people.Remove(prefix);
+  nick = cut_nick_from_prefix(prefix);
+  if(strcmp(real_nick, nick) == 0)
+    {
+      present_people.Clear();
+      in_channel = 0;
+    }
+  delete nick;
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a KICK
+
+void IRC_KICK(char *prefix, char *where, char *victim_nick)
+{
+  char *c;
+  uncap(victim_nick);
+
+  if(strcmp(victim_nick, real_nick) == 0)
+    {
+      present_people.Clear();
+      in_channel = 0;
+      sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
+      write_irc(IRC_buffer);
+    }
+
+  if((level_person(prefix, NULL) < level_person(prefix_from_nick(victim_nick), NULL)) &&
+     (level_person(prefix_from_nick(victim_nick), NULL) > 0))
+    {
+      c = cut_nick_from_prefix(prefix);
+      add_mode(where, "-o", c);
+      delete c;
+    }
+
+  c = prefix_from_nick(victim_nick);
+  if(c != NULL) present_people.Remove(c);
+  else cerr<<"** ERROR : non present person has been kicked out **\n";
+}
+
+//-----------------------------------------------------------------------------
+
+int check_restricted(char *where, char *prefix)
+{
+  char pattern[SMALL_BUFFER_SIZE];
+  NodeList<char *> *node;
+  char *p, *s;
+  int n, duration;
+
+  p = adr_beginning(prefix);
+
+  node = present_people.first;
+  n = 0;
+  while((node != NULL) && (n < 2))
+    {
+      s = adr_beginning(node->body);
+      if(strcmp(s, p) == 0) n++;
+      node = node->next;
+    }
+
+  if(n >= 2)
+    {
+      s = pattern;
+      concat(s, "*!*@");
+      concat(s, p);
+      *s++ = '\0';
+      duration = DEFAULT_RESTRICTED_TIME;
+      smart_shit(NULL, NULL, pattern, "Restricted site : no clones", duration);
+      smart_ban(where, pattern);
+      send_mode(where);
+      filter_kick(where, pattern, "Restricted site : no clones");
+      return 1;
+    }
+  else return 0;
+}
+
+// This function is called after a JOIN
+
+void IRC_JOIN(char *prefix, char *where)
+{
+  char *nick;
+  int l, restricted;
+  NodeList<Welcome *> *node;
+
+  nick = cut_nick_from_prefix(prefix);
+
+  if(strcmp(real_nick, nick) == 0)
+    {
+      strncpy(current_channel, where, SMALL_BUFFER_SIZE);
+      sprintf(IRC_buffer, "WHO %s\n", where);
+      write_irc(IRC_buffer);
+      present_people.Clear();
+      global_state = STATE_GETING_WHO;
+      in_channel = 1;
+    }
+  else
+    {
+      add_flood_line(prefix, FL_JOIN, 1);
+      
+      uncap(where);
+      present_people.Add(prefix);
+      
+      if(restricted_list.Matches(prefix)) 
+       restricted = check_restricted(where, prefix);
+      else restricted = 0;
+      
+      if(!restricted)
+       {
+         l =  level_person(prefix, NULL);
+         
+         if(l >= LEVEL_OP)
+           {
+             if(l >= LEVEL_DEFENCE) add_mode(where, "+o", nick);
+             else
+               mode_change_list.Insert(new DelayModeChange(where, "+o",
+                                                           nick, op_delay));
+           }
+         else
+           {
+             if(banid_list.Matches(prefix))
+               {
+                 sprintf(IRC_buffer, "KICK %s %s :You are banned\n", where, nick);
+                 write_irc(IRC_buffer);
+               }
+             else
+               {
+                 for(node = shit_list.first; node != NULL; node = node->next)
+                   if(match_pattern(node->body->pattern, prefix))
+                     {
+                       smart_ban(where, node->body->pattern);
+                       send_mode(current_channel);
+                       
+                       sprintf(IRC_buffer, "KICK %s %s :%s\n",
+                               where, nick, node->body->comment);
+                       
+                       write_irc(IRC_buffer);
+                     }
+               }
+           }
+       }
+    }
+
+  delete nick;
+}
+
+//-----------------------------------------------------------------------------
+
+void IRC_RPL_BANLIST(char *prefix, char *channel, char *banid)
+{
+  banid_list.Add(banid);
+}
+
+void IRC_ENDOFBANLIST(char *prefix)
+{
+  banid_list.Reverse();
+  global_state = STATE_WAIT;
+}
+
+void IRC_RPL_ENDOFWHOIS(char *prefix, char *nick)
+{
+  NodeList<WaitInfos *> *node, *pred, *next;
+
+  uncap(nick);
+  node = wait_list.first;
+  pred = NULL;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(strcmp(nick, node->body->nick) == 0)
+       {
+         sprintf(IRC_buffer, "Can't find %s\n", nick);
+         tell(node->body->chat, node->body->user, IRC_buffer);
+
+         if(pred == NULL) wait_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+void IRC_RPL_WHOISUSER(char *prefix,
+                      char *nick, char *login, char *host, char *real_name)
+{
+  char *c, *d, *banid;
+  int l;
+  char buffer[SMALL_BUFFER_SIZE];
+  NodeList<WaitInfos *> *node, *next, *pred;
+
+  int no_pattern, one_login, all_machines;
+
+  uncap(nick);
+  uncap(login);
+  uncap(host);
+
+  pred = NULL;
+  node = wait_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+
+      if(strcmp(nick, node->body->nick) == 0)
+       {
+         c = buffer;
+
+         no_pattern =  (node->body->mode == MODE_UNSHIT_NICK) ||
+           (node->body->mode == MODE_LEVEL) ||
+           (node->body->mode == MODE_UNBAN_NICK) ||
+           (node->body->mode == MODE_SHITLIST);;
+
+         one_login = (node->body->mode == MODE_SHIT_NICK) ||
+           (node->body->mode == MODE_BAN_NICK);
+
+         all_machines = (node->body->mode == MODE_SHIT_NICK) ||
+           (node->body->mode == MODE_BAN_NICK) ||
+           (node->body->mode == MODE_BAN_SITE) ||
+           (node->body->mode == MODE_FILTER_KICK) ||
+           (node->body->mode == MODE_SHIT_SITE) ||
+           (node->body->mode == MODE_MSG);
+
+         if(no_pattern)
+           {
+             concat(c, nick);
+             *c++ = '!';
+             concat(c, login);
+             *c++ = '@';
+             concat(c, host);
+             *c++ = '\0';
+           }
+         else
+           {
+             if((*login == '~') || (*login == '+') ||
+                (*login == '-') || (*login=='^'))
+               login++;
+
+             concat(c, "*!*");
+
+             if(one_login)
+               {
+                 
+                 l = 0;
+                 while((*login != '\0') && ((l<7) || *(login+1) == '\0'))
+                   { *c++ = *login++; l++; }
+                 if(*login != '\0') *c++ = '*';
+                 
+               }
+             *c++ = '@';
+
+             d = adr_beginning(host);
+             if(host != d) if(*(c-1) != '*') *c++ = '*';
+
+             if(all_machines) concat_pattern_from_host(c, d);
+             else
+               {
+                 concat(c, d);
+                 *c++ = '\0';
+               }
+
+           }
+
+         uncap(buffer);
+         banid = clean_banid(buffer);
+
+         if(node->body->mode == MODE_MSG)
+           msg_users(node->body->chat, node->body->user,
+                     banid, node->body->comment);
+
+         else if(node->body->mode == MODE_FILTER_KICK)
+           filter_kick(current_channel, banid, node->body->comment);
+
+         else if((node->body->mode == MODE_BAN_NICK) ||
+                 (node->body->mode == MODE_BAN_SITE))
+           smart_ban(current_channel, banid);
+
+         else if((node->body->mode == MODE_SHIT_NICK)
+                 || (node->body->mode == MODE_SHIT_SITE)
+                 || (node->body->mode == MODE_SHIT_HOST))
+           {
+             smart_shit(node->body->chat,
+                        node->body->user, banid, node->body->comment,
+                        node->body->duration);
+
+             if(prefix_from_nick(nick) != NULL)
+               {
+                 smart_ban(current_channel, banid);
+                 send_mode(current_channel);
+                 sprintf(IRC_buffer, "KICK %s %s :%s\n",
+                         current_channel, nick, node->body->comment);
+                 write_irc(IRC_buffer);
+               }
+
+           }
+
+         else if(node->body->mode == MODE_SHITLIST)
+           notice_shit_list(NULL, node->body->user, banid, 0);
+
+         else if(node->body->mode == MODE_LEVEL)
+           {
+             sprintf(IRC_buffer, "%s is level %d\n",
+                     banid, level_person(banid, NULL));
+             tell(node->body->chat, node->body->user, IRC_buffer);
+           }
+         else if(node->body->mode == MODE_UNSHIT_NICK)
+           {
+             NodeList<Welcome *> *node2, *pred, *next;
+             
+             node2 = shit_list.first;
+             pred = NULL;
+             while(node2 != NULL)
+               {
+                 next = node2->next;
+                 if(match_pattern(node2->body->pattern, banid))
+                   {
+                     if(pred == NULL) shit_list.first = next;
+                     else pred->next = next;
+                     
+                     sprintf(IRC_buffer, "Unshit %s (%s)\n",
+                             node2->body->pattern, node2->body->comment);
+                     
+                     tell(node->body->chat, node->body->user, IRC_buffer);
+                     
+                     smart_unban(current_channel, node2->body->pattern);
+                     
+                     delete node2->body;
+                     delete node2;
+                   }
+                 else pred = node2;
+                 node2 = next;
+               }
+           }
+         else if(node->body->mode == MODE_UNBAN_NICK)
+           {
+             NodeList<char *> *node2;
+             for(node2 = banid_list.first; node2 != NULL; node2 = node2->next)
+               if(match_pattern(node2->body, banid))
+                 add_mode(current_channel, "-b", node2->body);
+           }
+         
+
+         delete banid;
+
+         if(pred == NULL) wait_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+// This function is called after a RPL_WHOREPLY
+
+void IRC_RPL_WHOREPLY(char *prefix,
+                     char *where,
+                     char *login, char *host, char *server,
+                     char *nick, char *state)
+{
+  char *s, *t;
+
+  uncap(where);
+  uncap(nick);
+
+  if((global_state == STATE_GETING_WHO) && 
+     (strcmp(where, current_channel) == 0))
+    {
+      s = IRC_buffer;
+      t = nick; while(*t != '\0') *s++ = *t++;
+      *s++ = '!';
+      t = login; while(*t != '\0') *s++ = *t++;
+      *s++ = '@';
+      t = host; while(*t != '\0') *s++ = *t++;
+      *s++ = '\0';
+      present_people.Add(IRC_buffer);
+    }
+  else cerr<<where<<"!="<<current_channel<<"\n";
+}
+
+void IRC_RPL_ENDOFWHO(char *prefix, char *name)
+{
+  sprintf(IRC_buffer, "MODE %s +b\n", current_channel);
+  write_irc(IRC_buffer);
+  banid_list.Clear();
+  if(in_channel) global_state = STATE_GETING_BAN;
+  else global_state = STATE_WAIT;
+}
+
+//-----------------------------------------------------------------------------
+
+void IRC_ERR_NICKNAMEINUSE(char *prefix, char *channel)
+{
+  rand_nick(wanted_nick, jam_nick);
+#ifdef SCREEN_OUTPUT
+  cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
+#endif
+  sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
+  write_irc(IRC_buffer);
+  was_killed = 1;                   // We have been killed (I said PARANOID !)
+  time_killed = current_time;       // Note when it happens
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a ERR_NOSUCHCHANNEL
+
+void IRC_ERR_NOSUCHCHANNEL(char *prefix, char *nick)
+{
+  strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
+  uncap(wanted_channel);
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a ERR_NICKCOLLISION (436)
+
+void IRC_ERR_NICKCOLLISION(char *prefix, char *nick)
+{
+  rand_nick(wanted_nick, jam_nick);
+#ifdef SCREEN_OUTPUT
+  cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
+#endif
+  sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
+  write_irc(IRC_buffer);
+  was_killed = 1;                   // We have been killed (I said PARANOID !)
+  time_killed = current_time;       // Note when it happens
+}
+
+//-----------------------------------------------------------------------------
+
+// This is the main command. It is called for each line from the server.
+
+void get_command(char *prefix,
+                char **slice_cmd, int n_cmd,
+                char **slice_ctcp, int n_ctcp)
+{
+  char small_buffer[SMALL_BUFFER_SIZE];
+  char *cmd;
+
+  cmd = slice_cmd[0];
+
+#ifdef SCREEN_OUTPUT
+  cout<<"from "<<prefix<<" ";
+  int k;
+  for(k=0; k<n_cmd; k++) cout<<"["<<slice_cmd[k]<<"]";
+  if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<slice_ctcp[k]<<">";
+  cout<<"\n";
+#endif
+
+  if(prefix != NULL) uncap(prefix);
+
+  // No prefix : server command
+  if(prefix == NULL)
+    {
+      if(n_cmd > 0) if(eq("PING", cmd))
+       {
+         if(n_cmd > 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]);
+         else sprintf(IRC_buffer, "PONG\n");
+         write_irc(IRC_buffer);
+       }
+    }
+  else
+    {
+      // If we are not registred yet, then get the registration
+      if(eq("002", cmd))
+       {
+         if(!IRC_registred)
+           {
+             strncpy(real_nick, slice_cmd[1], SMALL_BUFFER_SIZE);
+             uncap(real_nick);
+             IRC_registred = 1;
+             sprintf(small_buffer, "MODE %s +i\n", real_nick);
+             write_irc(small_buffer);
+             sprintf(small_buffer, "JOIN %s\n", wanted_channel);
+             write_irc(small_buffer);
+           }
+       }
+      else if(eq("PRIVMSG", cmd))
+       IRC_PRIVMSG(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
+      else if(eq("NOTICE", cmd))
+       IRC_NOTICE(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
+      else if(eq("MODE", cmd))
+       IRC_MODE(slice_cmd[1], prefix, slice_cmd[2], slice_cmd+3);
+      else if(eq("JOIN", cmd)) IRC_JOIN(prefix, slice_cmd[1]);
+      else if(eq("KICK", cmd)) IRC_KICK(prefix, slice_cmd[1], slice_cmd[2]);
+      else if(eq("QUIT", cmd)) IRC_QUIT(prefix);
+      else if(eq("NICK", cmd)) IRC_NICK(prefix, slice_cmd[1]);
+      else if(eq("PART", cmd)) IRC_PART(prefix, slice_cmd[1]);
+      else if(eq("311", cmd))
+       IRC_RPL_WHOISUSER(prefix,
+                         slice_cmd[2], slice_cmd[3], slice_cmd[4],
+                         slice_cmd[6]);
+      else if(eq("318", cmd)) IRC_RPL_ENDOFWHOIS(prefix, slice_cmd[2]);
+      else if(eq("352", cmd))
+       IRC_RPL_WHOREPLY(prefix,
+                        slice_cmd[2], slice_cmd[3], slice_cmd[4],
+                        slice_cmd[5], slice_cmd[6], slice_cmd[7]);
+      else if(eq("315", cmd)) IRC_RPL_ENDOFWHO(prefix, slice_cmd[1]);
+      else if(eq("367", cmd))
+       IRC_RPL_BANLIST(prefix, slice_cmd[2], slice_cmd[3]);
+      else if(eq("368", cmd)) IRC_ENDOFBANLIST(prefix);
+      else if(eq("403", cmd)) IRC_ERR_NOSUCHCHANNEL(prefix, slice_cmd[1]);
+      else if(eq("433", cmd)) IRC_ERR_NICKNAMEINUSE(prefix, slice_cmd[1]);
+      else if(eq("436", cmd)) IRC_ERR_NICKCOLLISION(prefix, slice_cmd[1]);
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+// Rough routine to read the options
+
+void get_options(int argc, char **argv)
+{
+  int n, help, d;
+  n = 1;
+  help = 0;
+
+  while(n<argc)
+    {
+      if(eq("-p", argv[n]))
+       {
+         n++;
+         if(n<argc) default_port = atoi(argv[n]);
+         else cerr<<"*** No port parameter ***\n";
+       }
+      else if(eq("-h", argv[n]))
+       {
+         n++;
+         if(n<argc) strncpy(default_server, argv[n], MAXHOSTNAME);
+         else cerr<<"*** No hostname parameter ***\n";
+       }
+      else if(eq("-o", argv[n]))
+       {
+         n++;
+         if(n<argc)
+           {
+             strncpy(config_file, argv[n], SMALL_BUFFER_SIZE);
+             LoadConfigFile(argv[n]);
+           }
+         else cerr<<"*** No friends list parameter ***\n";
+       }
+      else if(eq("-c", argv[n]))
+       {
+         n++;
+         if(n<argc) strncpy(home_channel, argv[n], SMALL_BUFFER_SIZE);
+         else cerr<<"*** No channel parameter ***\n";
+       }
+      else if(eq("-l", argv[n]))
+       {
+         n++;
+         if(n<argc) strncpy(user_login, argv[n], SMALL_BUFFER_SIZE);
+         else cerr<<"*** No username parameter ***\n";
+       }
+      else if(eq("-n", argv[n]))
+       {
+         n++;
+         if(n<argc) strncpy(original_nick, argv[n], SMALL_BUFFER_SIZE);
+         else cerr<<"*** No nickname parameter ***\n";
+       }
+      else if(eq("-j", argv[n]))
+       {
+         n++;
+         if(n<argc) strncpy(jam_nick, argv[n], SMALL_BUFFER_SIZE);
+         else cerr<<"*** No jam nickname parameter ***\n";
+       }
+      else if(eq("-d", argv[n]))
+       {
+         n++;
+         if(n<argc)
+           {
+             d = atoi(argv[n]);
+             if(d>=1) socket_delay = d;
+             else cerr<<"*** Delay error ***\n";
+           }
+         else cerr<<"*** No delay parameter ***\n";
+       }
+      else if(eq("-od", argv[n]))
+       {
+         n++;
+         if(n<argc)
+           {
+             d = atoi(argv[n]);
+             if(d>=1) op_delay = d;
+             else cerr<<"*** Op delay error ***\n";
+           }
+         else cerr<<"*** No delay parameter ***\n";
+       }
+      else if(eq("-dd", argv[n]))
+       {
+         n++;
+         if(n<argc)
+           {
+             d = atoi(argv[n]);
+             if(d>=1) deban_delay = d;
+             else cerr<<"*** Deban delay error ***\n";
+           }
+         else cerr<<"*** No delay parameter ***\n";
+       }
+      else if(eq("-?", argv[n])) help = 1;
+      else
+       {
+         cerr<<"*** Unknown option "<<argv[n]<<" ***\n";
+         help = 1;
+       }
+
+      if(help)
+       {
+         cout<<"Tropbot " VERSION " Written by Francois Fleuret.\n";
+         cout<<"Compiled the " DATE " on a " SYSTEM " system.\n";
+         cout<<"Contact <francois.fleuret@inria.fr>.\n";
+         cout<<"\n";
+         cout<<"Options are :\n";
+         cout<<"-c <#channel>       sets the channel\n";
+         cout<<"-d <delay in s>     sets the reconnection delay\n";
+         cout<<"-h <hostname>       sets the server name\n";
+         cout<<"-j <jam nickname>   sets the pattern nick for collision\n";
+         cout<<"-l <user>           sets the user in the user@host stuff\n";
+         cout<<"-n <nickname>       sets the nickname\n";
+         cout<<"-o <friends file>   loads configuration file\n";
+         cout<<"-od <delay in s>    set the delay before +o\n";
+         cout<<"-dd <delay in s>    set the delay before -b\n";
+         cout<<"-p <port number>    sets the server port\n";
+         cout<<"-?                  shows this help\n";
+         exit(0);
+       }
+
+      n++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+
+void clean_shit_list()
+{
+  NodeList<Welcome *> *node, *pred, *next;
+
+  node = shit_list.first;
+  pred = NULL;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(current_time >= node->body->time_max)
+       {
+         if(pred == NULL) shit_list.first = next;
+         else pred->next = next;
+
+         smart_unban(current_channel, node->body->pattern);
+
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+  send_mode(current_channel);
+}
+
+//-----------------------------------------------------------------------------
+
+void try_reconnect()
+{
+  if(delay < DELAY_MAX_RECONNECT)
+    {
+      if(delay == 0) delay = 1;
+      else delay *= 2;
+      if(delay > DELAY_MAX_RECONNECT) delay = DELAY_MAX_RECONNECT;
+    }
+  strncpy(wanted_server, default_server, MAXHOSTNAME+1);
+  wanted_port = default_port;
+  cerr<<"*** Can't contact IRC server ***\n";
+  cerr<<"*** Next try in "<<delay<<" s\n";
+}
+
+void got_connection()
+{
+  time_last_datas = current_time;
+  IRC_connected = 1;
+  FD_SET(socket_irc, &ready);
+  sprintf(buffer, "USER %s x x :%s\n", user_login, user_name);
+  write_irc(buffer);
+  sprintf(buffer, "NICK %s\n", wanted_nick);
+  write_irc(buffer);
+  delay = socket_delay;
+}
+
+void got_datas_from_server()
+{
+  int s, end;
+  char *prefix, *r, *t;
+
+  char *slice_cmd[NB_SLICES_MAX], *slice_ctcp[NB_SLICES_MAX];
+  char *dest_cmd, *dest_ctcp;
+  int n_cmd, n_ctcp;
+
+  char buffer_cmd[BUFFER_SIZE], buffer_ctcp[BUFFER_SIZE];
+
+  time_last_datas = current_time;
+
+  // If the buffer is already full, purge it
+  if(endsrc >= buffer+BUFFER_SIZE)
+    {
+      cerr<<"*** Buffer full, erase it ***\n";
+      endsrc = buffer;
+    }
+
+  s = read(socket_irc, endsrc, buffer+BUFFER_SIZE-1-endsrc);
+  src = buffer;
+  endsrc += s;
+
+  if(s <= 0)
+    {
+      cerr<<"KILLING CONNECTION : Read error\n";
+      cerr.flush();
+      kill_connection();
+    }
+  else
+    {
+      end = 0;
+      reset_mode();
+      while(!end)
+       {
+         dest_cmd  = buffer_cmd;
+         dest_ctcp = buffer_ctcp;
+
+         if(slice_buffer(src, endsrc,
+                         prefix,
+                         dest_cmd, slice_cmd, n_cmd,
+                         dest_ctcp, slice_ctcp, n_ctcp))
+           // No more \r in the buffer
+           {
+             r = src;
+             t = buffer;
+             while(r<endsrc) *t++ = *r++;
+             endsrc = t;
+             src = buffer;
+             end = 1;
+           }
+         else
+           // Oki, we got a full line
+           get_command(prefix, slice_cmd, n_cmd, slice_ctcp, n_ctcp);
+       }
+
+    }
+}
+
+void check_stuffs()
+{
+  NodeList<DelayModeChange *> *md;
+
+  if(current_time > anti_flood_off_until) check_flood();
+  check_delay_mode_change();
+  send_mode(current_channel);
+  
+  delay = socket_delay;
+  NodeList<Welcome *> *nd;
+  for(nd = shit_list.first; nd != NULL; nd = nd->next)
+    if(delay > nd->body->time_max-current_time)
+      delay =  nd->body->time_max-current_time;
+  
+  for(md = mode_change_list.first; md != NULL; md = md->next)
+    if(delay > md->body->time-current_time)
+      delay =  md->body->time-current_time;
+
+  if(delay < 0) delay = 0;
+}
+
+void dcc_chat()
+{
+  NodeList<DCCChat *> *node, *pred, *next, *node2;
+  char CHAT_buffer[BUFFER_SIZE];
+  int s;
+
+  pred = NULL; next = NULL;
+  node = dcc_chat_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(FD_ISSET(node->body->socket, &result))
+       {
+         s = read(node->body->socket, CHAT_buffer, BUFFER_SIZE-1);
+         if(s <= 0)
+           {
+             FD_CLR(node->body->socket, &ready);       // Forget the socket
+             close(node->body->socket);
+
+             sprintf(IRC_buffer, "%s leaves.\n", node->body->prefix);
+             for(node2=dcc_chat_list.first; node2!= NULL; node2 = node2->next)
+               if(node2->body != node->body)
+                 tell(node2->body, NULL, IRC_buffer);
+
+             remove_wait_for_chat(node->body);
+
+             if(pred == NULL) dcc_chat_list.first = next;
+             else pred->next = next;
+             delete node->body;
+             delete node;
+           }
+         else
+           {
+             *(CHAT_buffer+s-1) = '\0';
+             tropbot_cmd(node->body, node->body->prefix, NULL, CHAT_buffer);
+             pred = node;
+           }
+       }
+      else pred = node;
+
+      node = next;
+    }
+}
+
+int main(int argc, char **argv)
+{
+
+  // I think it's a good idea to have few friends forever (me ? yeahhh !)
+  level_list.Insert(new Person("*!*fleuret@*.inria.fr", LEVEL_MASTER, NULL));
+  level_list.Insert(new Person("*!*fleuret@*.ens.fr", LEVEL_MASTER, NULL));
+  level_list.Insert(new Person("*!*fleuret@*.curie.fr", LEVEL_MASTER, NULL));
+  level_list.Insert(new Person("*!*jolibot@*.inria.fr", LEVEL_DEFENCE, NULL));
+  level_list.Insert(new Person("*!*jolibot@*.ens.fr", LEVEL_DEFENCE, NULL));
+  level_list.Insert(new Person("*!*jolibot@*.curie.fr", LEVEL_DEFENCE, NULL));
+
+  cout<<"TropBot, written by Francois Fleuret,"
+    " contact <francois.fleuret@inria.fr>\n";
+
+  get_options(argc, argv);
+
+  uncap(home_channel);
+  strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
+  strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
+  strncpy(wanted_server, default_server, MAXHOSTNAME+1);
+  wanted_port = default_port;
+
+  IRC_registred = 0; // true if we are registred
+  IRC_connected = 0; // true if we have a connection with an IRC server
+  global_state = STATE_WAIT;
+  in_channel = 0;
+  mode_protect_on = DEFAULT_MODE_PROTECT;
+  
+  FD_ZERO(&ready);
+
+  alive = 1;
+  father = 1;
+  nb_sons = 0;
+  was_killed = 0;
+  last_answer_time = 0;
+  anti_flood_off_until = 0;
+
+  src = buffer;
+  endsrc = buffer;
+  delay = socket_delay;
+
+  struct sigaction action;
+  action.sa_handler = SIG_IGN;
+
+  // We'll ignore the SIGPIPE signal, which will be catch somewhere else
+  sigaction(SIGPIPE, &action, NULL);
+
+  delay = 0;
+
+  do
+    {
+      delay_pause.tv_sec = delay;
+      delay_pause.tv_usec = 0;
+      result = ready;
+
+      while(waitpid(-1, NULL, WNOHANG) > 0) nb_sons--;
+
+      select(64, &result, NULL, NULL, &delay_pause);
+
+      time(&current_time);
+
+      dcc_chat();
+
+      if(!IRC_connected)
+       {
+#ifdef SCREEN_OUTPUT
+         cout<<"No connection yet\n";
+         cout<<"Try to contact "<<wanted_server<<":"<<wanted_port<<"\n";
+#endif
+         socket_irc = call_socket(wanted_server, wanted_port);
+
+         if(socket_irc <= 0) try_reconnect();
+         else got_connection();
+       }
+      else
+       {
+         if((current_time > time_killed+DELAY_NICK_BACK) && was_killed)
+           {
+             was_killed = 0;
+             strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
+             sprintf(buffer, "NICK %s\n", wanted_nick);
+             write_irc(buffer);
+           }
+
+         if(IRC_registred) clean_shit_list();
+
+         if(FD_ISSET(socket_irc, &result)) got_datas_from_server();
+         else
+           {
+             if(current_time > time_last_datas+DELAY_DEAD_SERVER)
+               {
+                 cerr<<"KILLING CONNECTION : Quiet server\n";
+                 cerr.flush();
+                 kill_connection();
+               }
+             else if(!in_channel) if(global_state == STATE_WAIT)
+               {
+                 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
+                 write_irc(IRC_buffer);
+               }
+           }
+
+         if(IRC_connected) check_stuffs();
+       }
+
+#ifdef SCREEN_OUTPUT
+      cout<<present_people.Lenght()<<" person(s) inside\n";
+      //      banid_list.Print();
+      cout.flush();
+#endif
+    }
+  while(alive || (socket_irc > 0));
+
+}
+
+//-----------------------------------------------------------------------------