Update to version 2.9.2d
authorFrancois Fleuret <francois@fleuret.org>
Sun, 6 Oct 2013 09:15:55 +0000 (11:15 +0200)
committerFrancois Fleuret <francois@fleuret.org>
Sun, 6 Oct 2013 09:15:55 +0000 (11:15 +0200)
README.txt
objects.cc
objects.h
secure.cc [new file with mode: 0644]
secure.h [new file with mode: 0644]
tblib.cc
tblib.h
tropbot.cc

index 55b7d7f..5bff2f7 100644 (file)
@@ -1,5 +1,5 @@
 -------------------------------------------------------------------------------
-  TropBot v2.5
+  TropBot v2.9
   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
@@ -20,7 +20,8 @@ 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).
+killed it it was just to run a newer version). The last version
+(2.9.0) runs under Purify(tm) with no error.
 
 -------------------------------------------------------------------------------
 II - TROPBOT CAPABILITIES -----------------------------------------------------
@@ -82,6 +83,18 @@ 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.
 
+Since v2.8.0, TropBot has new features to handle big channels. First,
+it has in memory a list of 'restricted' sites. The bot will detect and
+kick/ban any group of users who are on the same machine. The main idea
+is to protect the channel from clone bots. The second important
+feature is the 'cop-mode'. When this mode is switch ON, the bot will
+detect any graphical effect (caps, reverse, mIrc colors, beeps,
+art-chars, repeated chars, etc.), wil also ban any user who is kicked
+3 times or more in less than 10 minutes, and will ban all site where
+more than 3 people are banned.
+
+The v2.9.0 is a more stable version, debugged using Purify(tm)
+
 -------------------------------------------------------------------------------
 II - HOW TO INSTALL TROPBOT ---------------------------------------------------
 -------------------------------------------------------------------------------
@@ -181,6 +194,12 @@ FRIEND 2 *!*@*.fr trululu
 will make all people from France able to execute functions with a
 level 2 if they use the password trululu.
 
+You can also specify a list of restricted sites. For example, if you
+want to avoid to have more than one personne on a same adress
+containing "ppp", just put
+
+RESTRICTED *!*@*ppp*
+
 -------------------------------------------------------------------------------
 V - TROPBOT FUNCTIONS ---------------------------------------------------------
 -------------------------------------------------------------------------------
@@ -212,6 +231,8 @@ usefull against clone bots.
 anti-flood system for the given duration. This feature is interesting
 when the bot lagged because of network troubles.
 
+"cop" switch the cop-mode on/off
+
 "deban { list of patterns }" (alias "db") remove from the ban-list all
 the entries who match one of the pattern
 
@@ -315,7 +336,8 @@ 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.
+buggs are still creeping somewhere. The last version was checked with
+Purify and is supposed to be kinda stable.
 
 -------------------------------------------------------------------------------
 - AUTHOR ----------------------------------------------------------------------
@@ -330,12 +352,6 @@ 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 -------------------------------------------------------------
 -------------------------------------------------------------------------------
index 7b305fc..14765d2 100644 (file)
@@ -7,6 +7,19 @@ extern int current_time;
 
 //-----------------------------------------------------------------------------
 
+WaitPing::WaitPing(char *n, char *v, int t)
+{
+  nick = strdup(n);
+  value = strdup(v);
+  time_max = t;
+};
+
+WaitPing::~WaitPing()
+{
+  delete[] nick;
+  delete[] value;
+};
+
 WaitInfos::WaitInfos(char *n, char *c, DCCChat *ch, char *u, int m, int d)
 {
   nick = strdup(n);
@@ -19,9 +32,9 @@ WaitInfos::WaitInfos(char *n, char *c, DCCChat *ch, char *u, int m, int d)
 
 WaitInfos::~WaitInfos()
 {
-  delete nick;
-  delete comment;
-  delete user;
+  delete[] nick;
+  delete[] comment;
+  delete[] user;
 };
 
 Welcome::Welcome(char *p, char *c, int time)
@@ -33,8 +46,8 @@ Welcome::Welcome(char *p, char *c, int time)
 
 Welcome::~Welcome()
 {
-  delete pattern;
-  delete comment;
+  delete[] pattern;
+  delete[] comment;
 };
 
 //-----------------------------------------------------------------------------
@@ -49,9 +62,9 @@ DelayModeChange::DelayModeChange(char *w, char *m, char *p, int delay)
 
 DelayModeChange::~DelayModeChange()
 {
-  delete where;
-  delete mode;
-  delete parameter;
+  delete[] where;
+  delete[] mode;
+  delete[] parameter;
 };
 
 //-----------------------------------------------------------------------------
@@ -65,7 +78,7 @@ Person::Person(char *p, int l, char *pwd)
 
 Person::~Person()
 {
-  delete pattern;
+  delete[] pattern;
 };
 
 //-----------------------------------------------------------------------------
@@ -79,7 +92,7 @@ DCCChat::DCCChat(char *p, int s, int l)
 
 DCCChat::~DCCChat()
 {
-  delete prefix;
+  delete[] prefix;
 };
 
 //-----------------------------------------------------------------------------
index 48a92a8..fbfa6ff 100644 (file)
--- a/objects.h
+++ b/objects.h
@@ -35,6 +35,16 @@ public:
   ~DCCChat();
 };
 
+class WaitPing
+{
+public:
+  char *nick, *value;
+  int time_max;
+public:
+  WaitPing(char *n, char *v, int t);
+  ~WaitPing();
+};
+
 class WaitInfos
 {
 public:
diff --git a/secure.cc b/secure.cc
new file mode 100644 (file)
index 0000000..ee181a5
--- /dev/null
+++ b/secure.cc
@@ -0,0 +1,278 @@
+
+#include "secure.h"
+
+/*****************************************************************/
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+typedef unsigned long word32;
+typedef unsigned char byte;
+
+struct xMD5Context {
+       word32 buf[4];
+       word32 bytes[2];
+       word32 in[16];
+};
+
+void xMD5Init(struct xMD5Context *context);
+void xMD5Update(struct xMD5Context *context, byte const *buf, int len);
+void xMD5Final(byte digest[16], struct xMD5Context *context);
+void xMD5Transform(word32 buf[4], word32 const in[16]);
+
+
+/*
+ * Shuffle the bytes into little-endian order within words, as per the
+ * MD5 spec.  Note: this code works regardless of the byte order.
+ */
+void
+byteSwap(word32 *buf, unsigned words)
+{
+       byte *p = (byte *)buf;
+
+       do {
+               *buf++ = (word32)((unsigned)p[3] << 8 | p[2]) << 16 |
+                       ((unsigned)p[1] << 8 | p[0]);
+               p += 4;
+       } while (--words);
+}
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+xMD5Init(struct xMD5Context *ctx)
+{
+       ctx->buf[0] = 0x67452301;
+       ctx->buf[1] = 0xefcdab89;
+       ctx->buf[2] = 0x98badcfe;
+       ctx->buf[3] = 0x10325476;
+
+       ctx->bytes[0] = 0;
+       ctx->bytes[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+xMD5Update(struct xMD5Context *ctx, byte const *buf, int len)
+{
+       word32 t;
+
+       /* Update byte count */
+
+       t = ctx->bytes[0];
+       if ((ctx->bytes[0] = t + len) < t)
+               ctx->bytes[1]++;        /* Carry from low to high */
+
+       t = 64 - (t & 0x3f);    /* Space available in ctx->in (at least 1) */
+       if ((unsigned)t > len) {
+               bcopy(buf, (byte *)ctx->in + 64 - (unsigned)t, len);
+               return;
+       }
+       /* First chunk is an odd size */
+       bcopy(buf,(byte *)ctx->in + 64 - (unsigned)t, (unsigned)t);
+       byteSwap(ctx->in, 16);
+       xMD5Transform(ctx->buf, ctx->in);
+       buf += (unsigned)t;
+       len -= (unsigned)t;
+
+       /* Process data in 64-byte chunks */
+       while (len >= 64) {
+               bcopy(buf, ctx->in, 64);
+               byteSwap(ctx->in, 16);
+               xMD5Transform(ctx->buf, ctx->in);
+               buf += 64;
+               len -= 64;
+       }
+
+       /* Handle any remaining bytes of data. */
+       bcopy(buf, ctx->in, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+xMD5Final(byte digest[16], struct xMD5Context *ctx)
+{
+       int count = (int)(ctx->bytes[0] & 0x3f); /* Bytes in ctx->in */
+       byte *p = (byte *)ctx->in + count;      /* First unused byte */
+
+       /* Set the first char of padding to 0x80.  There is always room. */
+       *p++ = 0x80;
+
+       /* Bytes of padding needed to make 56 bytes (-8..55) */
+       count = 56 - 1 - count;
+
+       if (count < 0) {        /* Padding forces an extra block */
+               bzero(p, count+8);
+               byteSwap(ctx->in, 16);
+               xMD5Transform(ctx->buf, ctx->in);
+               p = (byte *)ctx->in;
+               count = 56;
+       }
+       bzero(p, count+8);
+       byteSwap(ctx->in, 14);
+
+       /* Append length in bits and transform */
+       ctx->in[14] = ctx->bytes[0] << 3;
+       ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+       xMD5Transform(ctx->buf, ctx->in);
+
+       byteSwap(ctx->buf, 4);
+       bcopy(ctx->buf, digest, 16);
+       bzero(ctx,sizeof(ctx));
+}
+
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+        (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+xMD5Transform(word32 buf[4], word32 const in[16])
+{
+       register word32 a, b, c, d;
+
+       a = buf[0];
+       b = buf[1];
+       c = buf[2];
+       d = buf[3];
+
+       MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+       MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+       MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+       MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+       MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+       MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+       MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+       MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+       MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+       MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+       MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+       MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+       MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+       MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+       MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+       MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+       MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+       MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+       MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+       MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+       MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+       MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+       MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+       MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+       MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+       MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+       MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+       MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+       MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+       MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+       MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+       MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+       MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+       MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+       MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+       MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+       MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+       MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+       MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+       MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+       MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+       MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+       MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+       MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+       MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+       MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+       MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+       MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+       MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+       MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+       MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+       MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+       MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+       MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+       MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+       MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+       MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+       MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+       MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+       MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+       MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+       MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+       MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+       MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+       buf[0] += a;
+       buf[1] += b;
+       buf[2] += c;
+       buf[3] += d;
+}
+
+
+void MD5(void *dest, void *orig, int len)
+{
+       struct xMD5Context context;
+
+       xMD5Init(&context);
+       xMD5Update(&context, orig, len);
+       xMD5Final(dest, &context);
+}
+
+void secure_nick(char *result, char *user, char *host, char *key, int time)
+{
+  int k;
+  char *s, *t;
+  char *code = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  char src[SECURE_BUFFER_SIZE], dst[16];
+
+  sprintf(src, "%s%s%s%d", user, host, key, time);
+  MD5(dst, src, strlen(src));
+  
+  s = dst; t = result;
+  for(k=0; k<NICK_LENGTH; k++) *t++ = code[((unsigned int) *s++)%52];
+  *t = '\0';
+
+  cout<<"RESULT=>"<<result
+      <<"< USER=>"<<user
+      <<"< HOST=>"<<host
+      <<"< KEY=>"<<key
+      <<"< time="<<time<<"\n";
+
+};
diff --git a/secure.h b/secure.h
new file mode 100644 (file)
index 0000000..8ae7817
--- /dev/null
+++ b/secure.h
@@ -0,0 +1,13 @@
+#ifndef SECURE_H
+#define SECURE_H
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <iostream.h>
+
+#define SECURE_BUFFER_SIZE 1024
+#define NICK_LENGTH 9
+
+void secure_nick(char *result, char *user, char *host, char *key, int time);
+
+#endif
index b396fe9..4347aa5 100644 (file)
--- a/tblib.cc
+++ b/tblib.cc
@@ -421,31 +421,6 @@ int call_socket(char *hostname, unsigned short portnum)
 
   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);
 
@@ -477,7 +452,7 @@ int establish(unsigned short portnum)
   if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */
     return(-1);
 
-  if (bind(s,(struct sockaddr *)&sa,sizeof(struct sockaddr_in)) < 0)
+  if (bind(s,(struct sockaddr *) &sa,sizeof(struct sockaddr_in)) < 0)
     {
       close(s);
       return(-1);                               /* bind address to socket */
@@ -511,92 +486,76 @@ int slice_buffer(char *&src, char *endsrc,
 
   char *s;
 
-  s = src;
-  while((*s != '\r') && (*s != '\n') && (s<endsrc)) s++;
+  s = src; while((*s != '\r') && (*s != '\n') && (s<endsrc)) s++;
   
-  if(s<endsrc)
-    {
-      end = 0;
+  if(s == endsrc) return 1;
+
+  end = 0;
 
-      n_cmd = 0;
-      n_ctcp = 0;
-      ctcp = 0;
-      queue = 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;
+  if(*src == ':')
+    {
+      src++;
+      prefix = dest_ctcp;
+      while((src<endsrc) && (*src != ' ')) *dest_ctcp++ = *src++;
+      *dest_ctcp++ = '\0';
+    }
+  else prefix = NULL;
       
-      while((src < endsrc) && !end)
+  while((src < endsrc) && !end)
+    {
+      if((*src == ' ') || (*src == '\r') || (*src == '\n') || (*src == '\001'))
        {
-         if((*src == ' ') || (*src == '\r') || (*src == '\n')
-            || (*src == '\001'))
+         if(*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
+             src++;
+             slice_ctcp[n_ctcp++] = dest_ctcp;
+
+             while((src<endsrc) && (*src != '\r') &&
+                   (*src != '\n') && (*src != '\001')) *dest_ctcp++ = *src++;
+
+             *dest_ctcp++ = '\0';
+
+             if(src<endsrc)
                {
-                 *dest_cmd = '\0';
-                 dest_cmd++;
                  end = (*src == '\r') || (*src == '\n');
                  src++;
-               };
+               }
+             else end = 1;
            }
          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');
+             *dest_cmd++ = '\0';
+             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;
-};
+    };
 
-//-----------------------------------------------------------------------------
+  if(src < endsrc) if(*src == '\n') src++;
 
-void ListChar::Print()
-{
-  NodeList<char *> *node;
-  for(node = first; node != NULL; node = node->next)
-    cout<<node->body<<"\n";
+  return 0;
 };
 
+//-----------------------------------------------------------------------------
+
 void ListChar::Clear()
 {
   NodeList<char *> *node, *next;
@@ -604,7 +563,7 @@ void ListChar::Clear()
   while(node != NULL)
     {
       next = node->next;
-      delete node->body;
+      delete[] node->body;
       delete node;
       node = next;
     };
@@ -628,14 +587,17 @@ void ListChar::Remove(char *s)
   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->body;
          delete node;
        }
       else pred = node;
+
       node = next;
     };
 };
diff --git a/tblib.h b/tblib.h
index c5c1de7..37ba7e3 100644 (file)
--- a/tblib.h
+++ b/tblib.h
 #include <signal.h>
 
 #ifdef _AIX
+#include <unistd.h>
+#include <strings.h>
 #include <sys/select.h>
+#include <sys/socketvar.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 #endif
 
 #include <iostream.h>
@@ -88,7 +93,7 @@ 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);
+char *pattern_from_prefix(char *prefix, int site_ban);
 
 //-----------------------------------------------------------------------------
 
@@ -140,7 +145,6 @@ int slice_buffer(char *&src, char *endsrc,
 class ListChar : public List<char *>
 {
 public:
-  void Print();
   void Clear();
   void Add(char *s);
   void Remove(char *s);
index 13b85b2..f3f2161 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.2d"
+#define OPTIONS ""
 
 #include <time.h>
 #include <fstream.h>
 //-----------------------------------------------------------------------------
 
 #define SCREEN_OUTPUT
+#define ERROR_OUTPUT
+
+//#define ANTI_SPOOF
+#define ANTI_SPOOF_MAX_TIME 300
 
 //-----------------------------------------------------------------------------
 
 
 #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;
+
 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;
                        }
                    }
                }
@@ -1241,8 +1470,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 +1479,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 +1542,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 +1570,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 +1603,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 +1648,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 +1699,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 +1720,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 +1731,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,15 +1769,6 @@ 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);
                }
@@ -1528,23 +1777,27 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
        }
       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)
+         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);
+             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 tell(chat, nick, "Anti-flood on\n");
+         else no_authorized = 1;
        }
       else if(eq("msg", buffer) || eq("message", buffer))
        {
@@ -1599,29 +1852,36 @@ 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 *a;
+             if(cop_mode) a = "ON"; else a = "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"
                          " your level is %d. I am a father with %d sons.\n",
-                         control_char, op_delay, deban_delay,
+                         control_char, op_delay, deban_delay, a,
                          level, nb_sons);
                  tell(chat, nick, IRC_buffer);
                }
              else
                {
                  sprintf(IRC_buffer,
-                         "control_char '%c' op_delay %ds  deban_delay %ds"
+                         "control_char '%c' op_delay %ds  deban_delay %ds "
+                         "cop-mode %s"
                          " your level is %d. I'm a clone.\n",
-                         control_char, op_delay, deban_delay, level);
+                         control_char, op_delay, deban_delay, a,
+                         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 +1889,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)
@@ -1695,7 +1955,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
        }
       else if(eq("db", buffer) || eq("deban", buffer))
        {
-         if(level >= LEVEL_FRIEND)
+         if(level >= LEVEL_OP)
            {
              while(r != NULL)
                {
@@ -1730,7 +1990,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 +2039,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 +2071,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 +2303,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 +2378,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 +2434,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 +2456,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,45 +2558,146 @@ 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++)
     {
       r = slice_ctcp[k];
       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
-
+      
       // Reply the CTCP VERSION
       if(eq("VERSION", buffer) && !version)
        {
@@ -2332,7 +2707,7 @@ void IRC_PRIVMSG(char *prefix,
              sprintf(IRC_buffer, "NOTICE %s :"
                      "\001VERSION \002TropBot\002 " VERSION OPTIONS
                      ", " SYSTEM " system, " DATE ". "
-                     "Contact THX-1138 on IRC, or <francois.fleuret@inria.fr>"
+                     "Contact THX-1138 on IRCNet, or <francois.fleuret@inria.fr>"
                      "\001\n",
                      nick);
              write_irc(IRC_buffer);
@@ -2355,7 +2730,6 @@ void IRC_PRIVMSG(char *prefix,
       // DCC (chat)
       else if(eq("DCC", buffer))
        {
-         level = level_person(prefix, NULL);
          if(level >= LEVEL_OP)
            {
              if(r != NULL)
@@ -2387,7 +2761,7 @@ void IRC_PRIVMSG(char *prefix,
            }
        }
     }
-  delete nick;
+  delete[] nick;
 }
 
 //-----------------------------------------------------------------------------
@@ -2441,7 +2815,7 @@ void IRC_PART(char *prefix, char *where)
       present_people.Clear();
       in_channel = 0;
     }
-  delete nick;
+  delete[] nick;
 }
 
 //-----------------------------------------------------------------------------
@@ -2450,7 +2824,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 +2835,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 +2880,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 +2895,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 +2917,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((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 +2972,7 @@ void IRC_JOIN(char *prefix, char *where)
        }
     }
 
-  delete nick;
+  delete[] nick;
 }
 
 //-----------------------------------------------------------------------------
@@ -2775,7 +3171,7 @@ void IRC_RPL_WHOISUSER(char *prefix,
            }
          
 
-         delete banid;
+         delete[] banid;
 
          if(pred == NULL) wait_list.first = next;
          else pred->next = next;
@@ -2811,7 +3207,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 +3275,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 +3293,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 +3360,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 +3378,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 +3427,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 +3442,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 +3457,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 +3494,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 +3540,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 +3574,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 +3586,10 @@ void got_datas_from_server()
 
   if(s <= 0)
     {
+#ifdef ERROR_OUTPUT
       cerr<<"KILLING CONNECTION : Read error\n";
       cerr.flush();
+#endif
       kill_connection();
     }
   else
@@ -3256,8 +3698,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 +3716,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;
@@ -3287,6 +3732,7 @@ int main(int argc, char **argv)
   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 +3782,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 +3796,7 @@ int main(int argc, char **argv)
            }
 
          if(IRC_connected) check_stuffs();
+         already_kicked.Clear();
        }
 
 #ifdef SCREEN_OUTPUT