Update to version 2.9.3a
[tropbot.git] / tropbot.cc
index 13b85b2..ac6f980 100644 (file)
@@ -1,12 +1,12 @@
 /*-----------------------------------------------------------------------------
-  TropBot, a small IRC bot, v2.6 Dec 95 - Oct 96
+  TropBot, a small IRC bot, v2.9 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"
+#define VERSION "v2.9.3a"
+#define OPTIONS ""
 
 #include <time.h>
 #include <fstream.h>
 //-----------------------------------------------------------------------------
 
 #define SCREEN_OUTPUT
+#define ERROR_OUTPUT
+
+//#define ANTI_SPOOF
+#define ANTI_SPOOF_MAX_TIME 300
 
 //-----------------------------------------------------------------------------
 
@@ -32,7 +36,7 @@
 
 #define DEFAULT_CONTROL_CHAR '|'
 #define DELAY_NICK_BACK 300
-#define DELAY_MAX_RECONNECT 300
+#define DELAY_MAX_RECONNECT 120
 #define DELAY_DEAD_SERVER 900
 
 #define DEFAULT_SERVER "sil.polytechnique.fr"
 
 #define HISTORY_SIZE 3
 
-enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN };
+enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN, FL_KICK };
+
+//-----------------------------------------------------------------------------
+
+// More than 3 kicks in 5 minutes -> 30 mins shit
+
+#define COP_NB_KICKS 3
+#define COP_NB_BANS 3
+#define COP_DELAY 300
+#define COP_DURATION 1800
+#define COP_DELAY_BEETWEEN_KICKS 2
 
 //-----------------------------------------------------------------------------
 
@@ -98,6 +112,8 @@ int op_delay = DEFAULT_OP_DELAY;
 int deban_delay = DEFAULT_DEBAN_DELAY;
 char control_char = DEFAULT_CONTROL_CHAR;
 
+int cop_mode, anti_flood, anti_clone, ctcp_reply;
+
 int delay;
 timeval delay_pause;
 time_t current_time, time_killed, time_last_datas, last_answer_time,
@@ -118,6 +134,7 @@ template class List<DCCChat *>;
 template class List<Person *>;
 template class List<Welcome *>;
 template class List<WaitInfos *>;
+template class List<WaitPing *>;
 template class List<DelayModeChange *>;
 template class List<char *>;
 
@@ -125,6 +142,7 @@ List<DCCChat *> dcc_chat_list;
 List<Person *> level_list;
 List<Welcome *> shit_list;
 List<WaitInfos *> wait_list;
+List<WaitPing *> wait_ping;
 List<DelayModeChange *> mode_change_list;
 
 ListChar present_people, banid_list, restricted_list, history;
@@ -338,8 +356,10 @@ 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)
     {
+#ifdef ERROR_OUTPUT
       cerr<<"KILLING CONNECTION : write_irc error\n";
       cerr.flush();
+#endif
       kill_connection();
     }
   else
@@ -481,7 +501,7 @@ void smart_shit(DCCChat *chat, char *nick,
          sprintf(IRC_buffer, "Shit %s for %s (%s)\n",
                  pattern, string_duration, comment);
          tell(chat, nick, IRC_buffer);
-         delete string_duration;
+         delete[] string_duration;
        }
     }
   else if((nick != NULL) || (chat != NULL))
@@ -621,17 +641,24 @@ void synch(char *channel)
       {
        nick = cut_nick_from_prefix(node->body);
        add_mode(channel, "+o", nick);
-       delete nick;
+       delete[] nick;
       }
 }
 
 //-----------------------------------------------------------------------------
 
+ListChar already_kicked;
+
 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(already_kicked.Contains(pattern)) return;
+
+  already_kicked.Add(pattern);
+  for(node = present_people.first; node != NULL;
+      node = node->next)
     {
       if(match_pattern(pattern, node->body))
        if(level_person(node->body, NULL) == 0)
@@ -639,7 +666,7 @@ void filter_kick(char *where, char *pattern, char *comment)
            nick = cut_nick_from_prefix(node->body);
            sprintf(IRC_buffer, "KICK %s %s :%s\n", where, nick, comment);
            write_irc(IRC_buffer);
-           delete nick;
+           delete[] nick;
          }
     }
 }
@@ -684,13 +711,13 @@ public:
     weigth = w;
   }
 
-  ~FloodLine() { delete prefix; }
+  ~FloodLine() { delete[] prefix; }
   void Reset() { individual = 0; site = 0; }
 };
 
 template class List<FloodLine *>;
 
-List<FloodLine *> flood_list;
+List<FloodLine *> flood_list, kick_list;
 
 //-----------------------------------------------------------------------------
 
@@ -748,7 +775,7 @@ void alert(char *where, DCCChat *chat, char *nick)
     {
       duration = DEFAULT_SHIT_TIME;
       r = pattern;
-      *r++ = '*'; *r++ = '!'; *r++ = '*'; *r++ = '@';
+      concat(r, "*!*@");
       concat_pattern_from_host(r, guilty_site);
       add_mode(where, "+m", NULL);
       smart_shit(NULL, NULL, pattern, "Alert", duration);
@@ -804,15 +831,15 @@ void check_one_flood(NodeList<FloodLine *> *node)
          mode_change_list.Insert(new DelayModeChange(current_channel,
                                                      "-b", banid,
                                                      BAN_FLOOD_DELAY));
-         delete banid;
-         delete pattern;
+         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;
+      delete[] nick;
       
       for(son = flood_list.first; son != NULL; son = son->next)
        {
@@ -834,7 +861,7 @@ void check_flood()
   while(node != NULL)
     {
       next = node->next;
-      if(node->body->time >= current_time - FLOOD_DELAY)
+      if(current_time <= node->body->time + FLOOD_DELAY)
        {
          nb_lines += node->body->weigth;
          if((node->body->kind == FL_CTCP)  && !node->body->alreadykicked)
@@ -886,6 +913,143 @@ inline void add_flood_line(char *prefix, int kind, int weigth)
   flood_list.Insert(new FloodLine(prefix, kind, weigth));
 }
 
+int bad_line(char *line, char *comment)
+{
+  int length, nb_art_chars, longest_word, nb_caps, nb_letters, nb_ctrl;
+  int l, bad;
+  unsigned char *s;
+  char *t;
+
+  nb_ctrl = 0;
+  nb_art_chars = 0;
+  nb_caps = 0;
+  nb_letters = 0;
+  length = 0;
+  l = 0;
+  longest_word = 0;
+
+  for(s=(unsigned char *)line; *s != '\0'; s++)
+    {
+      if((*s >= 'A') && (*s <= 'Z')) nb_caps++;
+      if(((*s >= 'A') && (*s <= 'Z')) ||
+        ((*s >= 'a') && (*s <= 'z'))) nb_letters++;
+      if((*s > 2) && (*s < 31)) nb_ctrl++;
+      if((*s != ' ') && (*s != '?') && (*s != '!') &&
+        (((*s >= 32) && (*s <= 47)) ||
+         ((*s >= 58) && (*s <= 63)) ||
+         ((*s >= 91) && (*s <= 96)) ||
+         (*s >= 123))) nb_art_chars++;
+
+      if(s > (unsigned char *) line)
+       {
+         if(*s == *(s-1)) l++;
+         else
+           {
+             if(l > longest_word) longest_word = l;
+             l = 0;
+           }
+       }
+
+      length++;
+    }
+  if(l > longest_word) longest_word = l;
+
+  t = comment;
+
+  bad = 0;
+  if(longest_word > 60)
+    {
+      bad = 1;
+      concat(t, "repeated chars");
+    }
+
+  if(nb_ctrl > 0)
+    {
+      if(bad) concat(t, " + ");
+      concat(t, "control chars");
+      bad = 1;
+    }
+
+  if((nb_art_chars > nb_letters) && (nb_art_chars >= 20))
+    {
+      if(bad) concat(t, " + ");
+      concat(t, "art chars");
+      bad = 1;
+    }
+
+  if((nb_caps*4 > nb_letters*3) && (nb_caps >= 10))
+    {
+      if(bad) concat(t, " + ");
+      concat(t, "caps");
+      bad = 1;
+    }
+
+  *t = '\0';
+
+  return bad;
+}
+
+void test_kick(char *prefix)
+{
+  int nb_kicks;
+  int last_kick_time;
+  NodeList<FloodLine *> *node, *next, *pred;
+  char *pattern, *banid, *loginathost;
+
+  loginathost = reach_loginathost(prefix);
+
+  nb_kicks = 0;
+  last_kick_time = current_time + COP_DELAY_BEETWEEN_KICKS + 1;
+  pred = NULL;
+  node = kick_list.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(current_time <= node->body->time + COP_DELAY)
+       {
+         if(strcmp(loginathost, reach_loginathost(node->body->prefix)) == 0)
+           {
+             if(node->body->time < last_kick_time - COP_DELAY_BEETWEEN_KICKS)
+               {
+                 nb_kicks += node->body->weigth;
+                 last_kick_time = node->body->time;
+               }
+           }
+         pred = node;
+       }
+      else
+       {
+         if(pred == NULL) kick_list.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      node = next;
+    }
+
+  if(nb_kicks >= COP_NB_KICKS)
+    {
+      pattern = pattern_from_prefix(prefix, 0);
+      banid = clean_banid(pattern);
+
+      smart_shit(NULL, NULL,
+                pattern, "cop : too many kicks", COP_DURATION + deban_delay);
+      smart_ban(current_channel, pattern);
+      send_mode(current_channel);
+      filter_kick(current_channel, pattern, "cop : too many kicks");
+
+      delete[] banid;
+      delete[] pattern;
+    }
+}
+
+inline void add_kick(char *prefix)
+{
+  if(level_person(prefix, NULL) >= LEVEL_FRIEND) return;
+  kick_list.Insert(new FloodLine(prefix, FL_KICK, 1));
+  test_kick(prefix);
+}
+
 //-----------------------------------------------------------------------------
 
 // This function is called for all mode changes
@@ -896,6 +1060,10 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
 {
   char *c, *banid;
   char buffer[3];
+  int check_ban, nb_bans, ok;
+  NodeList<char *> *node;
+  char pattern[SMALL_BUFFER_SIZE];
+  char *adr_param;
 
   if(signe < 0) buffer[0] = '-'; else buffer[0] = '+';
   buffer[1] = mode;
@@ -937,10 +1105,51 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
 
       if(signe > 0)
        {
+         check_ban = 1;
          banid_list.Add(param);
-         banid = clean_banid(param);
-         if(strcmp(banid, param) != 0) smart_ban(where, banid);
-         delete banid;
+
+         if(cop_mode && !is_hostname(who))
+           {
+             adr_param = adr_beginning(param);
+             nb_bans = 0;
+
+             for(node = banid_list.first; node != NULL; node = node->next)
+               if(are_same_site(adr_param, adr_beginning(node->body)))
+                 nb_bans++;
+
+             if(nb_bans >= COP_NB_BANS)
+               {
+                 check_ban = 0;
+                 c = pattern;
+                 concat(c, "*!*@");
+                 concat(c, adr_param);
+                 *c++ = '\0';
+
+                 ok = 1;
+                 
+                 for(node = present_people.first;
+                     (node != NULL) && ok; node = node->next)
+                   if(match_pattern(pattern, node->body))
+                     if(level_person(node->body, NULL) >= LEVEL_FRIEND)
+                       ok = 0;
+
+                 if(ok)
+                   {
+                     smart_shit(NULL, NULL,
+                                pattern,
+                                "cop : too many bans on one site",
+                                COP_DURATION + deban_delay);
+                     smart_ban(where, pattern);
+                   }
+               }
+           }
+
+         if(check_ban)
+           {
+             banid = clean_banid(param);
+             if(strcmp(banid, param) != 0) smart_ban(where, banid);
+             delete[] banid;
+           }
        }
       else banid_list.Remove(param);
       break;
@@ -963,7 +1172,7 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
            c = cut_nick_from_prefix(who);
            add_mode(where, "-o", c);
            add_mode(where, "+o", param);
-           delete c;
+           delete[] c;
          }
       break;
 
@@ -1000,7 +1209,7 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
              else add_mode(where, "+m", NULL);
              c = cut_nick_from_prefix(who);
              add_mode(where, "-o", c);
-             delete c;
+             delete[] c;
            }
        }
       break;
@@ -1073,7 +1282,9 @@ void get_one_line(ifstream *s, char *buffer, int buffer_size)
   *c = '\0';
 }
 
-int LoadConfigFile(char *name)
+#define MAX_INCLUDE_RECURSE 3
+
+int LoadConfigFile(char *name, int recurse)
 {
   ifstream *file;
   int duration, level, error;
@@ -1093,7 +1304,23 @@ int LoadConfigFile(char *name)
            {
              r = IRC_buffer;
              r = next_word(buffer, r, SMALL_BUFFER_SIZE);
-             if(strcmp(buffer, "FRIEND") == 0)
+
+             if(strcmp(buffer, "INCLUDE") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     if(recurse < MAX_INCLUDE_RECURSE)
+                       {
+                         r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                         LoadConfigFile(buffer, recurse+1);
+                       }
+#ifdef ERROR_OUTPUT    
+                     else cerr<<"Can't include "
+                              <<buffer<<" : too many recursion.\n";
+#endif
+                   }
+               }
+             else if(strcmp(buffer, "FRIEND") == 0)
                {
                  if(r != NULL)
                    {
@@ -1112,7 +1339,9 @@ int LoadConfigFile(char *name)
                  if(r != NULL)
                    {
                      r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+#ifdef SCREEN_OUTPUT
                      cout<<"RESTRICTED->"<<buffer<<"\n";
+#endif
                      restricted_list.Insert(strdup(buffer));
                    }
                }
@@ -1129,7 +1358,7 @@ int LoadConfigFile(char *name)
                          if(r == NULL) r = "Shit";
                          banid = clean_banid(pattern);
                          smart_shit(NULL, NULL, banid, r, duration);
-                         delete banid;
+                         delete[] banid;
                        }
                    }
                }
@@ -1157,6 +1386,31 @@ int LoadConfigFile(char *name)
                      if(buffer[0] != '\0') control_char = buffer[0];
                    }
                }
+             else if(strcmp(buffer, "COPMODE") == 0)
+               {
+                 cop_mode = 1;
+               }
+             else if(strcmp(buffer, "ANTIFLOOD") == 0)
+               {
+                 anti_flood = 1;
+                 anti_flood_off_until = current_time;
+               }
+             else if(strcmp(buffer, "ANTICLONES") == 0)
+               {
+                 anti_clone = 1;
+               }
+             else if(strcmp(buffer, "CTCPREPLY") == 0)
+               {
+                 ctcp_reply = 1;
+               }
+             else if(strcmp(buffer, "CHANNEL") == 0)
+               {
+                 if(r != NULL)
+                   {
+                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     strncpy(home_channel, buffer, SMALL_BUFFER_SIZE);
+                   }
+               }
            }
        }
       shit_list.Reverse();
@@ -1185,12 +1439,37 @@ int SaveConfigFile(char *name)
       (*file)<<"% Config file for a TropBot " VERSION "\n";
       (*file)<<"\n";
 
+      (*file)<<"% Delay in s before +o on level 2 users\n";
       (*file)<<"OPDELAY "<<op_delay<<"\n";
+      (*file)<<"% Delay before auto -b on servers +b\n";
       (*file)<<"DEBANDELAY "<<deban_delay<<"\n";
+      (*file)<<"% Charactere used for public commands\n";
       (*file)<<"CONTROLCHAR "<<control_char<<"\n";
 
+      (*file)<<"\n";
+      (*file)<<"% Home channel\n";
+      (*file)<<"CHANNEL "<<home_channel<<"\n";
+
+      (*file)<<"\n";
+      (*file)<<"% Cop-mode activation/desactivation\n";
+      if(cop_mode) (*file)<<"COPMODE\n";
+      else (*file)<<"% COPMODE\n";
+
+      (*file)<<"% Anti-flood activation/desactivation\n";
+      if(anti_flood) (*file)<<"ANTIFLOOD\n";
+      else (*file)<<"% ANTIFLOOD\n";
+
+      (*file)<<"% Anti-clones activation/desactivation\n";
+      if(anti_clone) (*file)<<"ANTICLONES\n";
+      else (*file)<<"% ANTICLONES\n";
+
+      (*file)<<"% Ctcp replies activation/desactivation\n";
+      if(ctcp_reply) (*file)<<"CTCPREPLY\n";
+      else (*file)<<"% CTCPREPLY\n";
+
       (*file)<<"\n";
 
+      (*file)<<"% Friends list\n";
       for(person=level_list.first; person != NULL; person=person->next)
        {
          (*file)<<"FRIEND "<<person->body->level<<" "<<person->body->pattern;
@@ -1200,6 +1479,7 @@ int SaveConfigFile(char *name)
 
       (*file)<<"\n";
 
+      (*file)<<"% Restricted-sites list\n";
       for(restricted=restricted_list.first;
          restricted != NULL;
          restricted=restricted->next)
@@ -1207,11 +1487,14 @@ int SaveConfigFile(char *name)
 
       (*file)<<"\n";
 
+      (*file)<<"% Shit list\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";
 
+      (*file)<<"\n";
+      (*file)<<"% End of config file\n";
       error = 0;
     }
   else error = 1;
@@ -1241,8 +1524,6 @@ void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
 
   buf = IRC_buffer;
 
-  cerr<<"PATTERN=>"<<pattern<<"<\n";
-
   if(pattern != NULL)
     {
       concat(buf, "\002");
@@ -1252,8 +1533,6 @@ void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
 
   while(node1 != NULL)
     {
-      cout<<"    =>"<<node1->body<<"\n";
-
       if((pattern == NULL) || match_pattern(pattern, node1->body))
        {
          c = adr_beginning(node1->body);
@@ -1317,7 +1596,7 @@ void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
          nb_person[LEVEL_MASTER]);
   tell(chat, nick, IRC_buffer);
 
-  delete ok;
+  delete[] ok;
 }
 
 //-----------------------------------------------------------------------------
@@ -1345,7 +1624,7 @@ void notice_shit_list(DCCChat *chat, char *nick, char *pattern, int matched)
                    string_duration,
                    node->body->comment);
            tell(chat, nick, IRC_buffer);
-           delete string_duration;
+           delete[] string_duration;
          }
 
       if(n == 0) tell(chat, nick, "\002No corresponding shits\002\n");
@@ -1378,7 +1657,7 @@ void add_in_history(char *prefix, char *action)
        {
          if(pred == NULL) history.first = next;
          else pred->next = next;
-         delete node->body;
+         delete[] node->body;
          delete node;
        }
       else pred = node;
@@ -1423,7 +1702,7 @@ void msg_users(DCCChat *chat, char *nick, char *pattern, char *msg)
          sprintf(IRC_buffer, "PRIVMSG %s :\002[msg to %s]\002 %s\n",
                  nick_user, pattern, msg);
          write_irc(IRC_buffer);
-         delete nick_user;
+         delete[] nick_user;
        }
     }
 
@@ -1474,6 +1753,18 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
        {
          if(dont_flood_server()) notice_shit_list(chat, nick, prefix, 0);
        }
+      else if(eq("write", buffer) || eq("wr", buffer))
+       {
+         if(level >= LEVEL_MASTER)
+           {
+             if(r != NULL)
+               {
+                 sprintf(IRC_buffer, "PRIVMSG %s :%s\n", current_channel, r);
+                 write_irc(IRC_buffer);
+               }
+           }
+         else no_authorized = 1;
+       }
       else if(eq("sl", buffer) || eq("shitlist", buffer))
        {
          if(level >= LEVEL_FRIEND)
@@ -1483,7 +1774,8 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
                  r = next_word(buffer, r, SMALL_BUFFER_SIZE);
                  uncap(buffer);
 
-                 if(is_pattern(buffer)) notice_shit_list(chat, nick, buffer, 1);
+                 if(is_pattern(buffer))
+                   notice_shit_list(chat, nick, buffer, 1);
                  else
                    {
                      wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
@@ -1493,7 +1785,27 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
                      write_irc(IRC_buffer);
                    }
                }
-             else notice_shit_list(chat, nick, "*", 1);
+             else
+               {
+                 int s1, s2, s3, s4, d;
+                 NodeList<Welcome *> *node;
+                 s1 = 0; s2 = 0; s3 = 0; s4 = 0;
+                 for(node=shit_list.first; node != NULL; node=node->next)
+                   {
+                     d = node->body->time_max - current_time;
+                     if(d < 1800) s1++;
+                     else if(d < 4*3600) s2++;
+                     else if(d < 24*3600) s3++;
+                     else s4++;
+                   }
+
+                 sprintf(IRC_buffer,
+                         "%d entries "
+                         "\002%d\002 < 30min < \002%d\002 < "
+                         "4h < \002%d\002 < 24h < \002%d\002\n",
+                         s1+s2+s3+s4, s1, s2, s3, s4);
+                 tell(chat, nick, IRC_buffer);
+               }
            }
          else no_authorized = 1;
        }
@@ -1511,40 +1823,65 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
              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))
+      else if(eq("cr", buffer) || eq("ctcpreply", buffer))
        {
-         if(r != NULL)
+         if(level >= LEVEL_OP)
            {
-             r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
-             duration =  string_to_seconds(buffer_time);
-             anti_flood_off_until = current_time + duration;
+             ctcp_reply = !ctcp_reply;
+             if(ctcp_reply) tell(chat, nick, "CTCP reply ON\n");
+             else tell(chat, nick, "CTCP reply OFF\n");
            }
-         if(anti_flood_off_until > current_time)
+         else no_authorized = 1;
+       }
+      else if(eq("ac", buffer) || eq("anticlones", buffer))
+       {
+         if(level >= LEVEL_OP)
            {
-             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);
+             anti_clone = !anti_clone;
+             if(anti_clone) tell(chat, nick, "Anti-clones ON\n");
+             else tell(chat, nick, "Anti-clones OFF\n");
            }
-         else tell(chat, nick, "Anti-flood on\n");
+         else no_authorized = 1;
+       }
+      else if(eq("ao", buffer) || eq("antifloodoff", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             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;
+                 anti_flood = 1;
+               }
+             else
+               {
+                 anti_flood_off_until = current_time;
+                 anti_flood = !anti_flood;
+               }
+
+             if(!anti_flood)
+               tell(chat, nick, "Anti-flood off\n");
+             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 no_authorized = 1;
        }
       else if(eq("msg", buffer) || eq("message", buffer))
        {
@@ -1599,29 +1936,41 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
            }
          else no_authorized = 1;
        }
-      else if(eq("help", buffer))
+      else if(eq("mode", buffer))
        {
          if(dont_flood_server() || (level >= LEVEL_FRIEND))
            {
+             char *cop, *ao, *ac, *cr;
+             if(cop_mode) cop = "ON"; else cop = "OFF";
+             if(anti_flood) ao = "ON"; else ao = "OFF";
+             if(anti_clone) ac = "ON"; else ac = "OFF";
+             if(ctcp_reply) cr = "ON"; else cr = "OFF";
              if(father)
                {
                  sprintf(IRC_buffer,
-                         "control_char '%c' op_delay %ds  deban_delay %ds"
+                         "control_char '%c' op_delay %ds  deban_delay %ds "
+                         "cop-mode %s anti-flood %s anti-clone %s ctcp-reply %s"
                          " your level is %d. I am a father with %d sons.\n",
                          control_char, op_delay, deban_delay,
+                         cop, ao, ac, cr,
                          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);
+                         "control_char '%c' op_delay %ds  deban_delay %ds "
+                         "cop-mode %s anti-flood %s anti-clone %s ctcp-reply %s"
+                         " your level is %d. I am a son.\n",
+                         control_char, op_delay, deban_delay,
+                         cop, ao, ac, cr,
+                         level);
                  tell(chat, nick, IRC_buffer);
                }
            }
-
+       }
+      else if(eq("help", 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");
@@ -1629,7 +1978,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
 
          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");
+             tell(chat, nick, "\002\037a\037\002ntiflood\037o\037\002ff\002 [<duration>]  \002\037a\037\002lert\002  \002home\002  \002cop\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)
@@ -1730,7 +2079,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
                    {
                      banid = clean_banid(buffer);
                      smart_ban(current_channel, banid);
-                     delete banid;
+                     delete[] banid;
                    }
                  else
                    {
@@ -1779,6 +2128,16 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
          if(level >= LEVEL_OP) synch(current_channel);
          else no_authorized = 1;
        }
+      else if(eq("cop", buffer))
+       {
+         if(level >= LEVEL_OP)
+           {
+             cop_mode = !cop_mode;
+             if(cop_mode) tell(chat, nick, "cop mode ON\n");
+             else tell(chat, nick, "cop mode OFF\n");
+           }
+         else no_authorized = 1;
+       }
       else if(eq("s", buffer) || eq("shit", buffer))
        {
          if(level >= LEVEL_OP)
@@ -1801,7 +2160,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
                      uncap(buffer);
                      banid = clean_banid(buffer);
                      smart_shit(chat, nick, banid, r, duration);
-                     delete banid;
+                     delete[] banid;
                    }
                  else
                    {
@@ -2033,7 +2392,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
                  if((od>=0) && (od <= 60))
                    {
                      op_delay = od;
-                     sprintf(IRC_buffer,"Oping delay set to %ds\n", op_delay);
+                     sprintf(IRC_buffer,"Op delay set to %ds\n", op_delay);
                      tell(chat, nick, IRC_buffer);
                    }
                }
@@ -2108,8 +2467,10 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
                  sprintf(IRC_buffer, "QUIT :Changing server\n");
                  write_irc(IRC_buffer);
 
+#ifdef ERROR_OUTPUT
                  cerr<<"KILLING CONNECTION : Changing server\n";
                  cerr.flush();
+#endif
                  kill_connection();
                }
            }
@@ -2162,7 +2523,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
          if(level >= LEVEL_MASTER)
            {
              if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
-             if(LoadConfigFile(config_file))
+             if(LoadConfigFile(config_file, 0))
                {
                  sprintf(IRC_buffer,
                          "Can't load the %s configuration file\n",
@@ -2184,8 +2545,10 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
            {
              sprintf(IRC_buffer, "QUIT :reset command sent by %s\n", nick);
              write_irc(IRC_buffer);
+#ifdef ERROR_OUTPUT
              cerr<<"KILLING CONNECTION : Die\n";
              cerr.flush();
+#endif
              kill_connection();
            }
          else no_authorized = 1;
@@ -2284,110 +2647,213 @@ int accepting_dcc_chat(char *prefix, char *nick, int level, char *r)
 
 //-----------------------------------------------------------------------------
 
-// This function is called after a NOTICE
+void pong_reply(char *nick, char *value)
+{
+  NodeList<WaitPing *> *node, *next, *pred;
+
+  cout<<"pong_reply : nick >"<<nick<<"< value >"<<value<<"<\n";
 
+  pred = NULL;
+  node = wait_ping.first;
+  while(node != NULL)
+    {
+      next = node->next;
+      if(current_time > node->body->time_max)
+       {
+         if(pred == NULL) wait_ping.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      if(strcmp(nick, node->body->nick) == 0)
+       {
+         if(strcmp(value, node->body->value) == 0)
+           add_mode(current_channel, "+o", nick);
+
+         if(pred == NULL) wait_ping.first = next;
+         else pred->next = next;
+         delete node->body;
+         delete node;
+       }
+      else pred = node;
+      node = next;
+    }
+}
+
+// This function is called after a NOTICE
 void IRC_NOTICE(char *prefix,
                char *who, char *msg, char **slice_ctcp, int n_ctcp)
 {
+  int k;
+  char word[SMALL_BUFFER_SIZE], *r, *nick;
   uncap(who);
   if(strcmp(who, current_channel) == 0) add_flood_line(prefix, FL_NOTICE, 1);
+#ifdef ANTI_SPOOF
+  else if(strcmp(who, real_nick) == 0)
+    for(k=0; k<n_ctcp; k++)
+      {
+       cout<<"ctcp >"<<slice_ctcp[k]<<"<\n";
+       r = slice_ctcp[k];
+       r = next_word(word, r, SMALL_BUFFER_SIZE);
+       if(strcmp(word, "PING") == 0)
+         {
+           nick = cut_nick_from_prefix(prefix);
+           r = next_word(word, r, SMALL_BUFFER_SIZE);
+           pong_reply(nick, word);
+           delete nick;
+         }
+      }
+#endif
 }
 
 void IRC_PRIVMSG(char *prefix,
                 char *who, char *msg, char **slice_ctcp, int n_ctcp)
 {
-  int k, version, ping, level;
-  char *nick, *r;
+  int k, version, ping, level, ctcp, kick;
+  char *nick, *r, *pattern, *banid;
   char buffer[SMALL_BUFFER_SIZE];
 
   uncap(who);
   nick = cut_nick_from_prefix(prefix);
+
+  level = level_person(prefix, NULL);
+
+  kick = 0;
   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(n_ctcp > 0)
+       {
+         add_flood_line(prefix, FL_CTCP, n_ctcp);
+
+         if((cop_mode) && (level < LEVEL_FRIEND))
+           {
+             ctcp = 0;
+             for(k = 0; (k<n_ctcp) && !ctcp; k++)
+               {
+                 r = slice_ctcp[k];
+                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                 if(strcmp(buffer, "ACTION") != 0) ctcp =1;
+                 else 
+                   {
+                     if(!kick && (r != NULL) && (bad_line(r, buffer)))
+                       {
+                         sprintf(IRC_buffer,"KICK %s %s :cop : %s\n",
+                                 current_channel, nick, buffer);
+                         write_irc(IRC_buffer);
+                       }
+                     kick = 1;
+                   }
+               }
+
+             if(!kick) if(ctcp) if(level < LEVEL_FRIEND)
+               {
+                 pattern = pattern_from_prefix(prefix, 0);
+                 banid = clean_banid(pattern);
+                 smart_shit(NULL, NULL, pattern, "cop : no ctcp",
+                            COP_DURATION + deban_delay);
+                 smart_ban(current_channel, pattern);
+                 send_mode(current_channel);
+                 sprintf(IRC_buffer, "KICK %s %s :cop : no ctcp\n",
+                         current_channel, nick);
+                 write_irc(IRC_buffer);
+                 kick = 1;
+                 delete[] banid;
+                 delete[] pattern;
+               }
+           }
+       }
+      else if(cop_mode) if(level < LEVEL_FRIEND)
+       if(!kick) if((msg != NULL) && bad_line(msg, buffer))
+         {
+           sprintf(IRC_buffer, "KICK %s %s :cop : %s\n",
+                   current_channel, nick, buffer);
+           write_irc(IRC_buffer);
+         }
+    }
+  
   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);
+      else if(strcmp(who, real_nick) == 0)
+       tropbot_cmd(NULL, prefix, nick, msg);
     }
-
   
-
-  version = 0;
-  ping = 0;
-  for(k=0; k<n_ctcp; k++)
+  if(ctcp_reply)
     {
-      r = slice_ctcp[k];
-      r = next_word(buffer, r, SMALL_BUFFER_SIZE);
-
-      // Reply the CTCP VERSION
-      if(eq("VERSION", buffer) && !version)
+      version = 0;
+      ping = 0;
+      for(k=0; k<n_ctcp; k++)
        {
-         if(dont_flood_server())
+         r = slice_ctcp[k];
+         r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+      
+         // Reply the CTCP VERSION
+         if(eq("VERSION", buffer) && !version)
            {
-             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);
+             if(dont_flood_server())
+               {
+                 version = 1;
+                 sprintf(IRC_buffer, "NOTICE %s :"
+                         "\001VERSION \002TropBot\002 " VERSION OPTIONS
+                         ", " SYSTEM " system, " DATE ". "
+                         "Contact THX-1138 on IRCNet, 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)
+         // 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))
+           {
+             if(level >= LEVEL_OP)
                {
-                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
-                 if(eq("CHAT", buffer))
+                 if(r != NULL)
                    {
-                     if(accepting_dcc_chat(prefix, nick, level, r) != 0)
+                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+                     if(eq("CHAT", buffer))
                        {
-                         sprintf(IRC_buffer, "NOTICE %s :\002Error\002"
-                                 " can't connect\n", nick);
+                         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
-                   {
-                     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);
+             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;
+  delete[] nick;
 }
 
 //-----------------------------------------------------------------------------
@@ -2441,7 +2907,7 @@ void IRC_PART(char *prefix, char *where)
       present_people.Clear();
       in_channel = 0;
     }
-  delete nick;
+  delete[] nick;
 }
 
 //-----------------------------------------------------------------------------
@@ -2450,7 +2916,7 @@ void IRC_PART(char *prefix, char *where)
 
 void IRC_KICK(char *prefix, char *where, char *victim_nick)
 {
-  char *c;
+  char *c, *d;
   uncap(victim_nick);
 
   if(strcmp(victim_nick, real_nick) == 0)
@@ -2461,17 +2927,23 @@ void IRC_KICK(char *prefix, char *where, char *victim_nick)
       write_irc(IRC_buffer);
     }
 
+  c = strdup(prefix_from_nick(victim_nick));
+
   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;
+      d = cut_nick_from_prefix(prefix);
+      add_mode(where, "-o", d);
+      delete[] d;
     }
+  else if(cop_mode && (c != NULL)) add_kick(c);
 
-  c = prefix_from_nick(victim_nick);
   if(c != NULL) present_people.Remove(c);
+#ifdef ERROR_OUTPUT
   else cerr<<"** ERROR : non present person has been kicked out **\n";
+#endif
+
+  delete[] c;
 }
 
 //-----------------------------------------------------------------------------
@@ -2500,7 +2972,7 @@ int check_restricted(char *where, char *prefix)
       concat(s, "*!*@");
       concat(s, p);
       *s++ = '\0';
-      duration = DEFAULT_RESTRICTED_TIME;
+      duration = DEFAULT_RESTRICTED_TIME + deban_delay;
       smart_shit(NULL, NULL, pattern, "Restricted site : no clones", duration);
       smart_ban(where, pattern);
       send_mode(where);
@@ -2515,8 +2987,9 @@ int check_restricted(char *where, char *prefix)
 void IRC_JOIN(char *prefix, char *where)
 {
   char *nick;
-  int l, restricted;
+  int k, l, restricted;
   NodeList<Welcome *> *node;
+  char buffer[SMALL_BUFFER_SIZE];
 
   nick = cut_nick_from_prefix(prefix);
 
@@ -2536,20 +3009,35 @@ void IRC_JOIN(char *prefix, char *where)
       uncap(where);
       present_people.Add(prefix);
       
-      if(restricted_list.Matches(prefix)) 
+      l =  level_person(prefix, NULL);
+
+      if(anti_clone && (l < LEVEL_FRIEND) && (restricted_list.Matches(prefix)))
        restricted = check_restricted(where, prefix);
       else restricted = 0;
       
       if(!restricted)
        {
-         l =  level_person(prefix, NULL);
-         
+#ifdef ANTI_SPOOF
+         if(l >= LEVEL_FRIEND)
+           {
+             for(k=0; k<10; k++) buffer[k] = 'a'+int(rand()%26);
+             buffer[10] = '\0';
+             wait_ping.Insert(new WaitPing(nick, buffer,
+                                           current_time+ANTI_SPOOF_MAX_TIME));
+             sprintf(IRC_buffer, "PRIVMSG %s :\001PING %s\001\n",
+                     nick, buffer);
+             write_irc(IRC_buffer);
+           }
+#endif
+
          if(l >= LEVEL_OP)
            {
+#ifndef ANTI_SPOOF
              if(l >= LEVEL_DEFENCE) add_mode(where, "+o", nick);
              else
                mode_change_list.Insert(new DelayModeChange(where, "+o",
                                                            nick, op_delay));
+#endif
            }
          else
            {
@@ -2576,7 +3064,7 @@ void IRC_JOIN(char *prefix, char *where)
        }
     }
 
-  delete nick;
+  delete[] nick;
 }
 
 //-----------------------------------------------------------------------------
@@ -2775,7 +3263,7 @@ void IRC_RPL_WHOISUSER(char *prefix,
            }
          
 
-         delete banid;
+         delete[] banid;
 
          if(pred == NULL) wait_list.first = next;
          else pred->next = next;
@@ -2811,7 +3299,9 @@ void IRC_RPL_WHOREPLY(char *prefix,
       *s++ = '\0';
       present_people.Add(IRC_buffer);
     }
+#ifdef ERROR_OUTPUT
   else cerr<<where<<"!="<<current_channel<<"\n";
+#endif
 }
 
 void IRC_RPL_ENDOFWHO(char *prefix, char *name)
@@ -2877,11 +3367,15 @@ void get_command(char *prefix,
   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";
+  for(k=0; k<n_cmd; k++) cout<<"["<<(void *) slice_cmd[k]<<"]";
+  if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<(void *) slice_ctcp[k]<<">";
+  cout<<"\n";
 #endif
 
   if(prefix != NULL) uncap(prefix);
@@ -2891,7 +3385,7 @@ void get_command(char *prefix,
     {
       if(n_cmd > 0) if(eq("PING", cmd))
        {
-         if(n_cmd > 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]);
+         if(n_cmd >= 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]);
          else sprintf(IRC_buffer, "PONG\n");
          write_irc(IRC_buffer);
        }
@@ -2958,13 +3452,17 @@ void get_options(int argc, char **argv)
        {
          n++;
          if(n<argc) default_port = atoi(argv[n]);
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No port parameter ***\n";
+#endif
        }
       else if(eq("-h", argv[n]))
        {
          n++;
          if(n<argc) strncpy(default_server, argv[n], MAXHOSTNAME);
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No hostname parameter ***\n";
+#endif
        }
       else if(eq("-o", argv[n]))
        {
@@ -2972,33 +3470,47 @@ void get_options(int argc, char **argv)
          if(n<argc)
            {
              strncpy(config_file, argv[n], SMALL_BUFFER_SIZE);
-             LoadConfigFile(argv[n]);
+             LoadConfigFile(argv[n], 0);
            }
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No friends list parameter ***\n";
+#endif
        }
       else if(eq("-c", argv[n]))
        {
          n++;
          if(n<argc) strncpy(home_channel, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No channel parameter ***\n";
+#endif
        }
       else if(eq("-l", argv[n]))
        {
          n++;
          if(n<argc) strncpy(user_login, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No username parameter ***\n";
+#endif
        }
       else if(eq("-n", argv[n]))
        {
          n++;
          if(n<argc) strncpy(original_nick, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No nickname parameter ***\n";
+#endif
        }
       else if(eq("-j", argv[n]))
        {
          n++;
          if(n<argc) strncpy(jam_nick, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No jam nickname parameter ***\n";
+#endif
+       }
+      else if(eq("-cop", argv[n]))
+       {
+         cop_mode = 1;
        }
       else if(eq("-d", argv[n]))
        {
@@ -3007,9 +3519,13 @@ void get_options(int argc, char **argv)
            {
              d = atoi(argv[n]);
              if(d>=1) socket_delay = d;
+#ifdef ERROR_OUTPUT
              else cerr<<"*** Delay error ***\n";
+#endif
            }
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No delay parameter ***\n";
+#endif
        }
       else if(eq("-od", argv[n]))
        {
@@ -3018,9 +3534,13 @@ void get_options(int argc, char **argv)
            {
              d = atoi(argv[n]);
              if(d>=1) op_delay = d;
+#ifdef ERROR_OUTPUT
              else cerr<<"*** Op delay error ***\n";
+#endif
            }
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No delay parameter ***\n";
+#endif
        }
       else if(eq("-dd", argv[n]))
        {
@@ -3029,19 +3549,26 @@ void get_options(int argc, char **argv)
            {
              d = atoi(argv[n]);
              if(d>=1) deban_delay = d;
+#ifdef ERROR_OUTPUT
              else cerr<<"*** Deban delay error ***\n";
+#endif
            }
+#ifdef ERROR_OUTPUT
          else cerr<<"*** No delay parameter ***\n";
+#endif
        }
       else if(eq("-?", argv[n])) help = 1;
       else
        {
+#ifdef ERROR_OUTPUT
          cerr<<"*** Unknown option "<<argv[n]<<" ***\n";
+#endif
          help = 1;
        }
 
       if(help)
        {
+#ifdef SCREEN_OUTPUT
          cout<<"Tropbot " VERSION " Written by Francois Fleuret.\n";
          cout<<"Compiled the " DATE " on a " SYSTEM " system.\n";
          cout<<"Contact <francois.fleuret@inria.fr>.\n";
@@ -3059,6 +3586,7 @@ void get_options(int argc, char **argv)
          cout<<"-p <port number>    sets the server port\n";
          cout<<"-?                  shows this help\n";
          exit(0);
+#endif
        }
 
       n++;
@@ -3104,8 +3632,10 @@ void try_reconnect()
     }
   strncpy(wanted_server, default_server, MAXHOSTNAME+1);
   wanted_port = default_port;
+#ifdef ERROR_OUTPUT
   cerr<<"*** Can't contact IRC server ***\n";
   cerr<<"*** Next try in "<<delay<<" s\n";
+#endif
 }
 
 void got_connection()
@@ -3136,7 +3666,9 @@ void got_datas_from_server()
   // If the buffer is already full, purge it
   if(endsrc >= buffer+BUFFER_SIZE)
     {
+#ifdef ERROR_OUTPUT
       cerr<<"*** Buffer full, erase it ***\n";
+#endif
       endsrc = buffer;
     }
 
@@ -3146,8 +3678,10 @@ void got_datas_from_server()
 
   if(s <= 0)
     {
+#ifdef ERROR_OUTPUT
       cerr<<"KILLING CONNECTION : Read error\n";
       cerr.flush();
+#endif
       kill_connection();
     }
   else
@@ -3184,7 +3718,7 @@ void check_stuffs()
 {
   NodeList<DelayModeChange *> *md;
 
-  if(current_time > anti_flood_off_until) check_flood();
+  if(anti_flood && (current_time > anti_flood_off_until)) check_flood();
   check_delay_mode_change();
   send_mode(current_channel);
   
@@ -3256,8 +3790,10 @@ int main(int argc, char **argv)
   level_list.Insert(new Person("*!*jolibot@*.ens.fr", LEVEL_DEFENCE, NULL));
   level_list.Insert(new Person("*!*jolibot@*.curie.fr", LEVEL_DEFENCE, NULL));
 
+#ifdef SCREEN_OUTPUT
   cout<<"TropBot, written by Francois Fleuret,"
     " contact <francois.fleuret@inria.fr>\n";
+#endif
 
   get_options(argc, argv);
 
@@ -3272,7 +3808,8 @@ int main(int argc, char **argv)
   global_state = STATE_WAIT;
   in_channel = 0;
   mode_protect_on = DEFAULT_MODE_PROTECT;
-  
+  cop_mode = 0;
+
   FD_ZERO(&ready);
 
   alive = 1;
@@ -3282,11 +3819,18 @@ int main(int argc, char **argv)
   last_answer_time = 0;
   anti_flood_off_until = 0;
 
+  // The bot does NOTHING at first
+  anti_flood = 0;
+  anti_clone = 0;
+  ctcp_reply = 0;
+  cop_mode = 0;
+
   src = buffer;
   endsrc = buffer;
   delay = socket_delay;
 
   struct sigaction action;
+  memset(&action, 0, sizeof(action));
   action.sa_handler = SIG_IGN;
 
   // We'll ignore the SIGPIPE signal, which will be catch somewhere else
@@ -3336,8 +3880,10 @@ int main(int argc, char **argv)
            {
              if(current_time > time_last_datas+DELAY_DEAD_SERVER)
                {
+#ifdef ERROR_OUTPUT
                  cerr<<"KILLING CONNECTION : Quiet server\n";
                  cerr.flush();
+#endif
                  kill_connection();
                }
              else if(!in_channel) if(global_state == STATE_WAIT)
@@ -3348,6 +3894,7 @@ int main(int argc, char **argv)
            }
 
          if(IRC_connected) check_stuffs();
+         already_kicked.Clear();
        }
 
 #ifdef SCREEN_OUTPUT