Update to version 2.9.2d
[tropbot.git] / tropbot.cc
1 /*-----------------------------------------------------------------------------
2   TropBot, a small IRC bot, v2.9 Dec 95 - Oct 96
3   Witten by Francois Fleuret.
4   Contact <francois.fleuret@inria.fr> for comments & bug reports
5   Check http://www.eleves.ens.fr:8080/home/fleuret for latest version
6 -----------------------------------------------------------------------------*/
7
8 #define VERSION "v2.9.2d"
9 #define OPTIONS ""
10
11 #include <time.h>
12 #include <fstream.h>
13
14 #include <sys/types.h>
15 #include <sys/wait.h>
16
17 #include "tblib.h"
18 #include "objects.h"
19 #include "list.cc"
20
21 //-----------------------------------------------------------------------------
22
23 #define SCREEN_OUTPUT
24 #define ERROR_OUTPUT
25
26 //#define ANTI_SPOOF
27 #define ANTI_SPOOF_MAX_TIME 300
28
29 //-----------------------------------------------------------------------------
30
31 #define MODE_NUMBER_MAX 3
32 #define SIZE_BANLIST_MAX 20
33 #define NB_CHAR_MAX 400
34
35 //-----------------------------------------------------------------------------
36
37 #define DEFAULT_CONTROL_CHAR '|'
38 #define DELAY_NICK_BACK 300
39 #define DELAY_MAX_RECONNECT 300
40 #define DELAY_DEAD_SERVER 900
41
42 #define DEFAULT_SERVER "sil.polytechnique.fr"
43 #define DEFAULT_PORT 6667
44
45 #define DEFAULT_USER_NAME "\002TropBot\002 " VERSION OPTIONS
46 #define DEFAULT_LOGIN "tropbot"
47 #define DEFAULT_NICK "TropBot"
48 #define DEFAULT_JAM_NICK "TB-????"
49 #define DEFAULT_HOME_CHANNEL "#tropbot"
50 #define DEFAULT_SOCKET_DELAY 30
51 #define DEFAULT_OP_DELAY 2
52 #define DEFAULT_DEBAN_DELAY 0
53
54 #define DEFAULT_ANTI_FLOOD_OFF_DURATION 600
55
56 #define DEFAULT_CONFIG_FILE ".tropbotrc"
57
58 #define DEFAULT_SHIT_TIME 600
59 #define DEFAULT_RESTRICTED_TIME 900
60
61 #define DEFAULT_MODE_PROTECT 0
62
63 // Not needed coz flooding people can't re-JOIN quickly
64 //#define BAN_ON_FLOOD
65 #define BAN_FLOOD_DELAY 30
66
67 #define MAX_LINE_FLOOD 4
68 #define MAX_CTCP_FLOOD 3
69 #define FLOOD_DELAY 2
70 #define DELAY_ANSWERS 3
71 #define ANTI_CLONES_DELAY 30
72
73 #define NB_SONS_MAX 3
74
75 #define HISTORY_SIZE 3
76
77 enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN, FL_KICK };
78
79 //-----------------------------------------------------------------------------
80
81 // More than 3 kicks in 5 minutes -> 30 mins shit
82
83 #define COP_NB_KICKS 3
84 #define COP_NB_BANS 3
85 #define COP_DELAY 300
86 #define COP_DURATION 1800
87 #define COP_DELAY_BEETWEEN_KICKS 2
88
89 //-----------------------------------------------------------------------------
90
91 #define MAX_DCC_CHAT 16
92
93 //-----------------------------------------------------------------------------
94
95 extern "C" void bzero(void *, int);
96 extern "C" int select(int, fd_set *, fd_set *, fd_set *, timeval *);
97 extern "C" pid_t fork(void); 
98
99 //-----------------------------------------------------------------------------
100
101 int default_port = DEFAULT_PORT;
102 int wanted_port;
103 char default_server[MAXHOSTNAME+1] = DEFAULT_SERVER;
104 char wanted_server[MAXHOSTNAME+1];
105
106 fd_set ready, result;
107 int alive; // Should be set to false (0) to kill the bot
108 int father, nb_sons;
109 int socket_irc;
110 int socket_delay = DEFAULT_SOCKET_DELAY;
111 int op_delay = DEFAULT_OP_DELAY;
112 int deban_delay = DEFAULT_DEBAN_DELAY;
113 char control_char = DEFAULT_CONTROL_CHAR;
114
115 int cop_mode;
116
117 int delay;
118 timeval delay_pause;
119 time_t current_time, time_killed, time_last_datas, last_answer_time,
120   anti_flood_off_until;
121 char *src, *endsrc;
122 char buffer[BUFFER_SIZE];
123
124 int IRC_connected, IRC_registred;
125 int global_state, in_channel, was_killed, mode_protect_on;
126
127 #define STATE_WAIT 0
128 #define STATE_GETING_WHO 1
129 #define STATE_GETING_BAN 2
130
131 //-----------------------------------------------------------------------------
132
133 template class List<DCCChat *>;
134 template class List<Person *>;
135 template class List<Welcome *>;
136 template class List<WaitInfos *>;
137 template class List<WaitPing *>;
138 template class List<DelayModeChange *>;
139 template class List<char *>;
140
141 List<DCCChat *> dcc_chat_list;
142 List<Person *> level_list;
143 List<Welcome *> shit_list;
144 List<WaitInfos *> wait_list;
145 List<WaitPing *> wait_ping;
146 List<DelayModeChange *> mode_change_list;
147
148 ListChar present_people, banid_list, restricted_list, history;
149
150 //-----------------------------------------------------------------------------
151
152 // General buffer for all IRC operations
153 char IRC_buffer[BUFFER_SIZE];
154
155 // Nick we got after registration
156 char real_nick[SMALL_BUFFER_SIZE];
157
158 // Nick we want
159 char wanted_nick[SMALL_BUFFER_SIZE];
160
161 char original_nick[SMALL_BUFFER_SIZE] = DEFAULT_NICK;
162
163 // Pattern used for random-nick generation if nick-collision occurs
164 // all the '?' will be replaced with random digits
165 char jam_nick[SMALL_BUFFER_SIZE] = DEFAULT_JAM_NICK;
166
167 // The "user" we want in the nick!user@host stuff
168 char user_login[SMALL_BUFFER_SIZE] = DEFAULT_LOGIN;
169
170 // The USERNAME string
171 char user_name[SMALL_BUFFER_SIZE] = DEFAULT_USER_NAME;
172
173 // The channel we want to join
174 char current_channel[SMALL_BUFFER_SIZE], wanted_channel[SMALL_BUFFER_SIZE];
175 char home_channel[SMALL_BUFFER_SIZE] = DEFAULT_HOME_CHANNEL;
176
177 // The name of the configuration file
178 char config_file[SMALL_BUFFER_SIZE] = DEFAULT_CONFIG_FILE;
179
180 //-----------------------------------------------------------------------------
181
182 char *prefix_from_nick(char *nick)
183 {
184   NodeList<char *> *node;
185   char *s, *t;
186   int yep;
187   yep = 0;
188
189   node = present_people.first;
190   while((node != NULL) && !yep)
191     {
192       yep = 1;
193       s = node->body;
194       t = nick;
195       while((*t != '\0') &&
196             (*s != '!') && (*s != '\0') && yep) yep &= (*s++ == *t++);
197       yep &= ((*t == '\0') && (*s == '!'));
198       if(!yep) node=node->next;
199     }
200
201   if(node != NULL) return node->body; else return NULL;
202
203 }
204
205 //-----------------------------------------------------------------------------
206
207 int level_person(char *prefix, char *passwd)
208 {
209   NodeList<Person *> *node;
210   int l;
211   l = 0;
212
213   for(node = level_list.first; node != NULL; node=node->next)
214     if(match_pattern(node->body->pattern, prefix))
215       if((node->body->level > l) || (l == 0))
216         {
217           if(node->body->passwd == NULL) l = node->body->level;
218           else
219             if(passwd != NULL)
220               if(strcmp(node->body->passwd, passwd) == 0)
221                 l = node->body->level;
222         }
223   return l;
224 }
225
226 void remove_level(char *prefix)
227 {
228   NodeList<Person *> *node, *pred, *next;
229   pred = NULL; next = NULL;
230
231   node = level_list.first;
232   while(node != NULL)
233     {
234       next = node->next;
235       if(strcmp(node->body->pattern, prefix) == 0)
236         {
237           if(pred == NULL) level_list.first = next;
238           else pred->next = next;
239           delete node->body;
240           delete node;
241         }
242       else pred = node;
243       node = next;
244     }
245 }
246
247 void clear_levels()
248 {
249   NodeList<Person *> *node, *next;
250
251   node = level_list.first;
252   while(node != NULL)
253     {
254       next = node->next;
255       delete node->body;
256       delete node;
257       node = next;
258     }
259   level_list.first = NULL;
260 }
261
262 void clear_shit()
263 {
264   NodeList<Welcome *> *node, *next;
265
266   node = shit_list.first;
267   while(node != NULL)
268     {
269       next = node->next;
270       delete node->body;
271       delete node;
272       node = next;
273     }
274   shit_list.first = NULL;
275 }
276
277 void remove_wait_for_chat(DCCChat *chat)
278 {
279   NodeList<WaitInfos *> *node, *pred, *next;
280   pred = NULL; next = NULL;
281
282   node = wait_list.first;
283   while(node != NULL)
284     {
285       next = node->next;
286       if(node->body->chat == chat)
287         {
288           if(pred == NULL) wait_list.first = next;
289           else pred->next = next;
290           delete node->body;
291           delete node;
292         }
293       else pred = node;
294       node = next;
295     }
296 }
297
298 //-----------------------------------------------------------------------------
299
300 // This function generates a random nick from a pattern. The pattern
301 // is supposed to contain some '?', which will be replaced with random
302 // digits.
303
304 void rand_nick(char *nick, char *pattern)
305 {
306   unsigned int n;
307   for(n=0; n<strlen(pattern); n++)
308     {
309       if(pattern[n] == '?') nick[n] = '0'+int(rand()%10);
310       else nick[n] = pattern[n];
311     }
312   nick[n]='\0';
313 }
314
315 //-----------------------------------------------------------------------------
316
317 void kill_connection()
318 {
319   time_last_datas = current_time;
320   IRC_connected = 0;                // We are not connected
321   IRC_registred = 0;                // We are not registred
322   FD_CLR(socket_irc, &ready);       // Forget the socket
323   close(socket_irc);                // Close it
324   present_people.Clear();           // We don't see anyone
325   rand_nick(wanted_nick, jam_nick); // Random the nick (yeah, we are paranoid)
326   was_killed = 1;                   // We have been killed (I said PARANOID !)
327   time_killed = current_time;       // Note when it happens
328   src = buffer;                     // Forget all the remaining datas
329   endsrc = buffer;                  // Idem.
330   delay = 0;                        // We won't wait for reconnection
331   in_channel = 0;                   // We are not in any channel
332   socket_irc = 0;
333 }
334
335 void clone(char *nick)
336 {
337   if(fork() == 0)
338     {
339       strcpy(wanted_nick, nick);
340       strcpy(original_nick, nick);
341       IRC_connected = 0;
342       IRC_registred = 0;
343       FD_CLR(socket_irc, &ready);
344       present_people.Clear();
345       time_killed = current_time;
346       src = buffer;
347       endsrc = buffer;
348       delay = 0;
349       in_channel = 0;
350       father = 0;
351     }
352 }
353
354 void write_irc(char *stuff)
355 {
356   // I'd like to know why do I have to do such a cast ?!?!
357   if((int) write(socket_irc, stuff, strlen(stuff)) < 0)
358     {
359 #ifdef ERROR_OUTPUT
360       cerr<<"KILLING CONNECTION : write_irc error\n";
361       cerr.flush();
362 #endif
363       kill_connection();
364     }
365   else
366     {
367 #ifdef SCREEN_OUTPUT
368       cout<<"\n!!!!>"<<stuff<<"<\n\n";
369 #endif
370       last_answer_time = current_time;
371     }
372 }
373
374 //-----------------------------------------------------------------------------
375
376 int nb_modes;
377
378 char string_modes[MODE_NUMBER_MAX*2+1];
379 char *ptr_modes;
380 char string_param_modes[MODE_NUMBER_MAX*64+1];
381 char *ptr_param_modes;
382 int k_mode, o_mode;
383
384 void reset_mode()
385 {
386   nb_modes = 0;
387   ptr_modes = string_modes;
388   ptr_param_modes = string_param_modes;
389   k_mode = 0;
390   o_mode = 0;
391 }
392
393 void send_mode(char *where)
394 {
395   if(nb_modes>0)
396     {
397       *ptr_modes = '\0';
398       *ptr_param_modes = '\0';
399       sprintf(IRC_buffer, "MODE %s %s %s\n",
400               where, string_modes, string_param_modes);
401       write_irc(IRC_buffer);
402       reset_mode();
403     }
404 }
405
406 void add_mode(char *where, char *mode, char *param)
407 {
408   char *s;
409
410   // Disgusting hack coz of a FUCKING server bug :-(
411   if(mode[1] == 'o')
412     {
413       if(k_mode) send_mode(where);
414       o_mode = 1;
415     }
416
417   if(mode[1] == 'k')
418     {
419       if(o_mode) send_mode(where);
420       k_mode = 1;
421     }
422
423   s = mode;
424   while(*s != '\0') *ptr_modes++ = *s++;
425   if(param != NULL)
426     {
427       s = param;
428       while(*s != '\0') *ptr_param_modes++ = *s++;
429       *ptr_param_modes++ = ' ';
430     }
431
432   if(++nb_modes == MODE_NUMBER_MAX) send_mode(where);
433 }
434
435 //-----------------------------------------------------------------------------
436
437 void tell(DCCChat *chat, char *nick, char *msg)
438 {
439   char tell_buffer[BUFFER_SIZE];
440
441 #ifdef SCREEN_OUTPUT
442   cout<<"tell(chat="<<chat<<", nick="<<nick<<" msg="<<msg<<")\n";
443   if(msg[strlen(msg)-1] != '\n')
444     cout<<"**************************************\n";
445 #endif
446
447   if(chat != NULL) write(chat->socket, msg, strlen(msg));
448
449   if(nick != NULL)
450     {
451       sprintf(tell_buffer, "NOTICE %s :%s", nick, msg);
452       write_irc(tell_buffer);
453     }
454 }
455
456 //-----------------------------------------------------------------------------
457
458 void smart_shit(DCCChat *chat, char *nick,
459                 char *pattern, char *comment, int duration)
460 {
461   NodeList<Welcome *> *node, *next, *pred;
462   int no_shit;
463   int time_max, l;
464
465   if(duration < 5) duration = 5;
466
467   time_max = duration + current_time;
468
469   no_shit = 0;
470   node = shit_list.first;
471   pred = NULL;
472   while((node != NULL) && !no_shit)
473     {
474       next = node->next;
475       if(strcmp(node->body->pattern, pattern) == 0)
476         {
477           if(node->body->time_max <= time_max)
478             {
479               if(pred == NULL) shit_list.first = next;
480               else pred->next = next;
481               delete node->body;
482               delete node;
483             }
484           else
485             {
486               no_shit = 1;
487               pred = node;
488             }
489         }
490       else pred = node;
491       node = next;
492     }
493
494   if(!no_shit)
495     {
496       shit_list.Insert(new Welcome(pattern, comment, time_max));
497       if((nick != NULL) || (chat != NULL))
498         {
499           char *string_duration;
500           string_duration = seconds_to_string(duration);
501           sprintf(IRC_buffer, "Shit %s for %s (%s)\n",
502                   pattern, string_duration, comment);
503           tell(chat, nick, IRC_buffer);
504           delete[] string_duration;
505         }
506     }
507   else if((nick != NULL) || (chat != NULL))
508     {
509       sprintf(IRC_buffer,
510               "Can't shit %s, already shitted for a longer time\n", pattern);
511       tell(chat, nick, IRC_buffer);
512     }
513 }
514
515 //-----------------------------------------------------------------------------
516
517 void smart_ban(char *where, char *pattern)
518 {
519   NodeList<char *> *node;
520   int n;
521   n = 0;
522   for(node = banid_list.first; node != NULL; node = node->next)
523     {
524       if((n>=SIZE_BANLIST_MAX-1) ||
525          (match_pattern(pattern, node->body) &&
526           (strcmp(pattern, node->body) != 0)))
527         add_mode(where, "-b", node->body);
528       else n++;
529     }
530   add_mode(current_channel, "+b", pattern);
531 }
532
533 void smart_unban(char *where, char *pattern)
534 {
535   if(banid_list.Contains(pattern)) add_mode(where, "-b", pattern);
536 }
537
538 //-----------------------------------------------------------------------------
539
540 void check_delay_mode_change()
541 {
542   NodeList<DelayModeChange *> *node, *pred, *next;
543
544   pred = NULL;
545   node = mode_change_list.first;
546   while(node != NULL)
547     {
548       next = node->next;
549       if(current_time >= node->body->time)
550         {
551           add_mode(node->body->where, node->body->mode, node->body->parameter);
552           if(pred == NULL) mode_change_list.first = next;
553           else pred->next = next;
554           delete node->body;
555           delete node;
556         }
557       else pred = node;
558       node = next;
559     }
560 }
561
562 void clean_delay_mode_change(char *where, char *mode, char *param)
563 {
564   NodeList<DelayModeChange *> *node, *pred, *next;
565
566   uncap(param);
567   uncap(where);
568   pred = NULL;
569   node = mode_change_list.first;
570
571   if(param != NULL)
572     {
573       while(node != NULL)
574         {
575           next = node->next;
576           if((node->body->parameter != NULL) &&
577              (strcmp(where, node->body->where) == 0) &&
578              (strcmp(param, node->body->parameter) == 0) &&
579              (strcmp(mode, node->body->mode) == 0))
580             {
581               if(pred == NULL) mode_change_list.first = next;
582               else pred->next = next;
583               delete node->body;
584               delete node;
585             }
586           else pred = node;
587           node = next;
588         }
589     }
590   else
591     {
592       while(node != NULL)
593         {
594           next = node->next;
595           if((strcmp(where, node->body->where) == 0) &&
596              (node->body->parameter == NULL) &&
597              (strcmp(mode, node->body->mode) == 0))
598             {
599               if(pred == NULL) mode_change_list.first = next;
600               else pred->next = next;
601               delete node->body;
602               delete node;
603             }
604           else pred = node;
605           node = next;
606         }
607     }
608 }
609
610 void RemoveDelayModeChange(char *mode, char *parameter)
611 {
612   NodeList<DelayModeChange *> *node, *pred, *next;
613
614   pred = NULL;
615   node = mode_change_list.first;
616   while(node != NULL)
617     {
618       next = node->next;
619       if((strcmp(node->body->mode, mode) == 0) &&
620          (strcmp(node->body->parameter, parameter) == 0))
621         {
622           if(pred == NULL) mode_change_list.first = next;
623           else pred->next = next;
624           delete node->body;
625           delete node;
626         }
627       else pred = node;
628       node = next;
629     }
630 }
631
632 //-----------------------------------------------------------------------------
633
634 void synch(char *channel)
635 {
636   char *nick;
637   NodeList<char *> *node;
638
639   for(node = present_people.first; node != NULL; node = node->next)
640     if(level_person(node->body, NULL) >= LEVEL_OP)
641       {
642         nick = cut_nick_from_prefix(node->body);
643         add_mode(channel, "+o", nick);
644         delete[] nick;
645       }
646 }
647
648 //-----------------------------------------------------------------------------
649
650 ListChar already_kicked;
651
652 void filter_kick(char *where, char *pattern, char *comment)
653 {
654   NodeList<char *> *node;
655   char *nick;
656
657   if(already_kicked.Contains(pattern)) return;
658
659   already_kicked.Add(pattern);
660   for(node = present_people.first; node != NULL;
661       node = node->next)
662     {
663       if(match_pattern(pattern, node->body))
664         if(level_person(node->body, NULL) == 0)
665           {
666             nick = cut_nick_from_prefix(node->body);
667             sprintf(IRC_buffer, "KICK %s %s :%s\n", where, nick, comment);
668             write_irc(IRC_buffer);
669             delete[] nick;
670           }
671     }
672 }
673
674 //-----------------------------------------------------------------------------
675
676 // Return a pointer on the first character after the last '@' in the string
677 // Beware of some weird hack-script that add @ in the login
678 char *adr_beginning(char *s)
679 {
680   char *t;
681   t = s;
682   while(*s != '\0') if(*s++ == '@') t = s;
683   if(*t == '@') t++;
684   return t;
685 }
686
687 char *reach_loginathost(char *s)
688 {
689   while((*s != '!') && (*s != '\0')) s++;
690   if(s != '\0') s++;
691   return s;
692 }
693
694 //-----------------------------------------------------------------------------
695
696 class FloodLine
697 {
698 public:
699   char *prefix;
700   int kind;
701   int weigth;
702   int time;
703   int individual, site, alreadykicked;
704
705   FloodLine(char *p, int k, int w)
706   {
707     prefix = strdup(p);
708     time = current_time;
709     alreadykicked = 0;
710     kind = k;
711     weigth = w;
712   }
713
714   ~FloodLine() { delete[] prefix; }
715   void Reset() { individual = 0; site = 0; }
716 };
717
718 template class List<FloodLine *>;
719
720 List<FloodLine *> flood_list, kick_list;
721
722 //-----------------------------------------------------------------------------
723
724 void alert(char *where, DCCChat *chat, char *nick)
725 {
726   int nb_lines, max_nb_lines, duration;
727   NodeList<FloodLine *> *node, *son;
728   char *site, *site2, *guilty_site, *r;
729   char pattern[SMALL_BUFFER_SIZE];
730
731   for(node = flood_list.first; node != NULL; node = node->next)
732     node->body->individual = 0;
733
734   node = flood_list.first;
735
736   max_nb_lines = 1;
737   guilty_site = NULL;
738
739   while(node != NULL)
740     {
741       while((node != NULL) && node->body->individual) node = node->next;
742       if(node != NULL)
743         {
744           nb_lines = 0;
745           site = adr_beginning(node->body->prefix);
746           
747           son = node;
748           while(son != NULL)
749             {
750               while((son != NULL) && son->body->individual) son = son->next;
751               if(son != NULL)
752                 {
753                   site2 = adr_beginning(son->body->prefix);
754                   
755                   if(are_same_site(site, site2))
756                     {
757                       son->body->individual = 1;
758                       nb_lines++;
759                     }
760                   son = son->next;
761                 }
762             }
763           
764           if(nb_lines > max_nb_lines)
765             if(level_person(node->body->prefix, NULL) == 0)
766               {
767                 max_nb_lines = nb_lines;
768                 guilty_site = site;
769               }
770           node = node->next;
771         }
772     }
773
774   if(guilty_site != NULL)
775     {
776       duration = DEFAULT_SHIT_TIME;
777       r = pattern;
778       concat(r, "*!*@");
779       concat_pattern_from_host(r, guilty_site);
780       add_mode(where, "+m", NULL);
781       smart_shit(NULL, NULL, pattern, "Alert", duration);
782       smart_ban(where, pattern);
783       send_mode(where);
784       filter_kick(where, pattern, "Filter kick on alert");
785       add_mode(where, "-m", NULL);
786       send_mode(where);
787     }
788   else tell(chat, nick, "\002No flooding site detected\002\n");
789 }
790
791 void check_one_flood(NodeList<FloodLine *> *node)
792 {
793   NodeList<FloodLine *> *son;
794   char *userhost, *userhost2, *nick;
795   int nb_lines;
796
797   userhost = reach_loginathost(node->body->prefix);
798   
799   nb_lines = 0;
800   son = node;
801   while(son != NULL)
802     {
803       while((son != NULL) && son->body->individual) son = son->next;
804       if(son != NULL)
805         {
806           if(!son->body->alreadykicked)
807             {
808               userhost2 = reach_loginathost(son->body->prefix);
809               
810               if(strcmp(userhost, userhost2) == 0)
811                 {
812                   son->body->individual = 1;
813                   nb_lines++;
814                 }
815             }
816           son = son->next;
817         }
818     }
819
820   if(nb_lines >= MAX_LINE_FLOOD)
821     {
822
823 #ifdef BAN_ON_FLOOD
824       char *pattern, *banid;
825       if((level_person(node->body->prefix, NULL) < LEVEL_OP))
826         {
827           pattern = pattern(node->body->prefix, 0);
828           banid = clean_banid(pattern);
829           smart_ban(current_channel, banid);
830           send_mode(current_channel);
831           mode_change_list.Insert(new DelayModeChange(current_channel,
832                                                       "-b", banid,
833                                                       BAN_FLOOD_DELAY));
834           delete[] banid;
835           delete[] pattern;
836         }
837 #endif
838       
839       nick = cut_nick_from_prefix(node->body->prefix);
840       sprintf(IRC_buffer, "KICK %s %s :%s\n", current_channel, nick, "Flood");
841       write_irc(IRC_buffer);
842       delete[] nick;
843       
844       for(son = flood_list.first; son != NULL; son = son->next)
845         {
846           userhost2 = reach_loginathost(son->body->prefix);
847           if(strcmp(userhost, userhost2) == 0) son->body->alreadykicked = 1;
848         }
849     }
850
851 }
852
853 void check_flood()
854 {
855   int nb_lines, nb_ctcp;
856   NodeList<FloodLine *> *node, *next, *pred;
857
858   nb_lines = 0; nb_ctcp = 0;
859   pred = NULL;
860   node = flood_list.first;
861   while(node != NULL)
862     {
863       next = node->next;
864       if(current_time <= node->body->time + FLOOD_DELAY)
865         {
866           nb_lines += node->body->weigth;
867           if((node->body->kind == FL_CTCP)  && !node->body->alreadykicked)
868             nb_ctcp += node->body->weigth;
869           pred = node;
870           node->body->Reset();
871         }
872       else
873         {
874           if(pred == NULL) flood_list.first = next;
875           else pred->next = next;
876           delete node->body;
877           delete node;
878         }
879       node = next;
880     }
881
882   /*
883     if(nb_ctcp >= MAX_CTCP_FLOOD)
884     {
885     add_mode(current_channel, "+m", NULL);
886     send_mode(current_channel);
887     mode_change_list.Insert(new DelayModeChange(current_channel,
888     "-m", NULL,
889     ANTI_CLONES_DELAY));
890     }
891     */
892
893   if(nb_lines >= MAX_LINE_FLOOD)
894     {
895       for(node = flood_list.first; node != NULL; node = node->next)
896         node->body->individual = 0;
897
898       node = flood_list.first;
899       while(node != NULL)
900         {
901           while((node != NULL) && node->body->individual) node = node->next;
902           if(node != NULL)
903             {
904               if(!node->body->alreadykicked) check_one_flood(node);
905               node = node->next;
906             }
907         }
908     }
909 }
910
911 inline void add_flood_line(char *prefix, int kind, int weigth)
912 {
913   flood_list.Insert(new FloodLine(prefix, kind, weigth));
914 }
915
916 int bad_line(char *line, char *comment)
917 {
918   int length, nb_art_chars, longest_word, nb_caps, nb_letters, nb_ctrl;
919   int l, bad;
920   unsigned char *s;
921   char *t;
922
923   nb_ctrl = 0;
924   nb_art_chars = 0;
925   nb_caps = 0;
926   nb_letters = 0;
927   length = 0;
928   l = 0;
929   longest_word = 0;
930
931   for(s=(unsigned char *)line; *s != '\0'; s++)
932     {
933       if((*s >= 'A') && (*s <= 'Z')) nb_caps++;
934       if(((*s >= 'A') && (*s <= 'Z')) ||
935          ((*s >= 'a') && (*s <= 'z'))) nb_letters++;
936       if((*s > 2) && (*s < 31)) nb_ctrl++;
937       if((*s != ' ') && (*s != '?') && (*s != '!') &&
938          (((*s >= 32) && (*s <= 47)) ||
939           ((*s >= 58) && (*s <= 63)) ||
940           ((*s >= 91) && (*s <= 96)) ||
941           (*s >= 123))) nb_art_chars++;
942
943       if(s > (unsigned char *) line)
944         {
945           if(*s == *(s-1)) l++;
946           else
947             {
948               if(l > longest_word) longest_word = l;
949               l = 0;
950             }
951         }
952
953       length++;
954     }
955   if(l > longest_word) longest_word = l;
956
957   t = comment;
958
959   bad = 0;
960   if(longest_word > 60)
961     {
962       bad = 1;
963       concat(t, "repeated chars");
964     }
965
966   if(nb_ctrl > 0)
967     {
968       if(bad) concat(t, " + ");
969       concat(t, "control chars");
970       bad = 1;
971     }
972
973   if((nb_art_chars > nb_letters) && (nb_art_chars >= 20))
974     {
975       if(bad) concat(t, " + ");
976       concat(t, "art chars");
977       bad = 1;
978     }
979
980   if((nb_caps*4 > nb_letters*3) && (nb_caps >= 10))
981     {
982       if(bad) concat(t, " + ");
983       concat(t, "caps");
984       bad = 1;
985     }
986
987   *t = '\0';
988
989   return bad;
990 }
991
992 void test_kick(char *prefix)
993 {
994   int nb_kicks;
995   int last_kick_time;
996   NodeList<FloodLine *> *node, *next, *pred;
997   char *pattern, *banid, *loginathost;
998
999   loginathost = reach_loginathost(prefix);
1000
1001   nb_kicks = 0;
1002   last_kick_time = current_time + COP_DELAY_BEETWEEN_KICKS + 1;
1003   pred = NULL;
1004   node = kick_list.first;
1005   while(node != NULL)
1006     {
1007       next = node->next;
1008       if(current_time <= node->body->time + COP_DELAY)
1009         {
1010           if(strcmp(loginathost, reach_loginathost(node->body->prefix)) == 0)
1011             {
1012               if(node->body->time < last_kick_time - COP_DELAY_BEETWEEN_KICKS)
1013                 {
1014                   nb_kicks += node->body->weigth;
1015                   last_kick_time = node->body->time;
1016                 }
1017             }
1018           pred = node;
1019         }
1020       else
1021         {
1022           if(pred == NULL) kick_list.first = next;
1023           else pred->next = next;
1024           delete node->body;
1025           delete node;
1026         }
1027       node = next;
1028     }
1029
1030   if(nb_kicks >= COP_NB_KICKS)
1031     {
1032       pattern = pattern_from_prefix(prefix, 0);
1033       banid = clean_banid(pattern);
1034
1035       smart_shit(NULL, NULL,
1036                  pattern, "cop : too many kicks", COP_DURATION + deban_delay);
1037       smart_ban(current_channel, pattern);
1038       send_mode(current_channel);
1039       filter_kick(current_channel, pattern, "cop : too many kicks");
1040
1041       delete[] banid;
1042       delete[] pattern;
1043     }
1044 }
1045
1046 inline void add_kick(char *prefix)
1047 {
1048   if(level_person(prefix, NULL) >= LEVEL_FRIEND) return;
1049   kick_list.Insert(new FloodLine(prefix, FL_KICK, 1));
1050   test_kick(prefix);
1051 }
1052
1053 //-----------------------------------------------------------------------------
1054
1055 // This function is called for all mode changes
1056 // signe indicates if it's a + or - mode change
1057 // param is NULL for mode change without parameters
1058
1059 void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
1060 {
1061   char *c, *banid;
1062   char buffer[3];
1063   int check_ban, nb_bans, ok;
1064   NodeList<char *> *node;
1065   char pattern[SMALL_BUFFER_SIZE];
1066   char *adr_param;
1067
1068   if(signe < 0) buffer[0] = '-'; else buffer[0] = '+';
1069   buffer[1] = mode;
1070   buffer[2] = '\0';
1071   if(param != NULL) uncap(param);
1072
1073   clean_delay_mode_change(where, buffer, param);
1074
1075 #ifdef SCREEN_OUTPUT
1076   cout<<"ONE MODE CHANGE CHANNEL ("<<where<<")";
1077   cout<<" BY ("<<who<<") MODE "<<signe<<" "<<mode;
1078   cout<<" ON "<<param<<"\n";
1079 #endif
1080
1081   uncap(param);
1082
1083   // Basic anti-hack procedure. All +o and +b mode done by servers are
1084   // canceled (we have to look if the person is a friend or not)
1085   switch(mode)
1086     {
1087     case 'b':
1088       if(is_hostname(who))
1089         {       
1090           if(deban_delay == 0)
1091             {
1092               if(signe>0) add_mode(where, "-b", param);
1093               else add_mode(where, "+b", param);
1094             }
1095           else
1096             {
1097               if(signe>0)
1098                 mode_change_list.Insert(new DelayModeChange(where, "-b", param,
1099                                                             deban_delay));
1100               else
1101                 mode_change_list.Insert(new DelayModeChange(where, "+b", param,
1102                                                             deban_delay));
1103             }
1104         }
1105
1106       if(signe > 0)
1107         {
1108           check_ban = 1;
1109           banid_list.Add(param);
1110
1111           if(cop_mode && !is_hostname(who))
1112             {
1113               adr_param = adr_beginning(param);
1114               nb_bans = 0;
1115
1116               for(node = banid_list.first; node != NULL; node = node->next)
1117                 if(are_same_site(adr_param, adr_beginning(node->body)))
1118                   nb_bans++;
1119
1120               if(nb_bans >= COP_NB_BANS)
1121                 {
1122                   check_ban = 0;
1123                   c = pattern;
1124                   concat(c, "*!*@");
1125                   concat(c, adr_param);
1126                   *c++ = '\0';
1127
1128                   ok = 1;
1129                   
1130                   for(node = present_people.first;
1131                       (node != NULL) && ok; node = node->next)
1132                     if(match_pattern(pattern, node->body))
1133                       if(level_person(node->body, NULL) >= LEVEL_FRIEND)
1134                         ok = 0;
1135
1136                   if(ok)
1137                     {
1138                       smart_shit(NULL, NULL,
1139                                  pattern,
1140                                  "cop : too many bans on one site",
1141                                  COP_DURATION + deban_delay);
1142                       smart_ban(where, pattern);
1143                     }
1144                 }
1145             }
1146
1147           if(check_ban)
1148             {
1149               banid = clean_banid(param);
1150               if(strcmp(banid, param) != 0) smart_ban(where, banid);
1151               delete[] banid;
1152             }
1153         }
1154       else banid_list.Remove(param);
1155       break;
1156
1157     case 'o':
1158       if(is_hostname(who))
1159         {
1160           c = prefix_from_nick(param);
1161           if((signe > 0) && (level_person(c, NULL) < LEVEL_FRIEND))
1162             add_mode(where, "-o", param);
1163           if((signe < 0) && (level_person(c, NULL) >= LEVEL_FRIEND))
1164             add_mode(where, "+o", param);
1165         }
1166       else
1167         if((signe<0) &&
1168            (level_person(who, NULL) <
1169             level_person(prefix_from_nick(param), NULL)) &&
1170            (level_person(prefix_from_nick(param), NULL) > 0))
1171           {
1172             c = cut_nick_from_prefix(who);
1173             add_mode(where, "-o", c);
1174             add_mode(where, "+o", param);
1175             delete[] c;
1176           }
1177       break;
1178
1179     case 'i':
1180       if(signe>0) if(is_hostname(who) || mode_protect_on)
1181         add_mode(where, "-i", NULL);
1182       break; 
1183
1184     case 'l':
1185       if(signe>0) if(is_hostname(who) || mode_protect_on)
1186         add_mode(where, "-l", NULL);
1187       break; 
1188
1189     case 'p':
1190       if(signe>0) if(is_hostname(who) || mode_protect_on)
1191         add_mode(where, "-p", NULL);
1192       break;
1193
1194     case 'k':
1195       if(signe>0) if(is_hostname(who) || mode_protect_on)
1196         add_mode(where, "-k", param);
1197       break;
1198
1199     case 'm':
1200       if(is_hostname(who))
1201         {
1202           if(signe>0) add_mode(where, "-m", NULL);
1203         }
1204       else if(mode_protect_on)
1205         {
1206           if(level_person(who, NULL) < LEVEL_OP)
1207             {
1208               if(signe>0) add_mode(where, "-m", NULL);
1209               else add_mode(where, "+m", NULL);
1210               c = cut_nick_from_prefix(who);
1211               add_mode(where, "-o", c);
1212               delete[] c;
1213             }
1214         }
1215       break;
1216
1217     case 's':
1218       if(signe>0) if(is_hostname(who) || mode_protect_on)
1219         add_mode(where, "-s", NULL);
1220       break;
1221
1222     default:
1223       break;
1224     }
1225 }
1226
1227 //-----------------------------------------------------------------------------
1228
1229 // This function is called after a "MODE" command
1230 // You should not modify it, unless you find a bug.
1231 // Modify only IRC_ONE_MODE()
1232
1233 void IRC_MODE(char *where, char *who, char *mode, char **params)
1234 {
1235   int param_no, signe;
1236
1237   param_no = 0;
1238   signe = 1;
1239   while(*mode != '\0')
1240     {
1241       switch(*mode)
1242         {
1243         case '+':
1244           signe = 1;
1245           break;
1246         case '-':
1247           signe = -1;
1248           break;
1249         default:
1250           if((*mode == 'l') || (*mode == 'v') ||
1251              (*mode == 'k') || (*mode == 'o') ||
1252              (*mode == 'b'))
1253             IRC_ONE_MODE(where, who, signe, *mode, params[param_no++]);
1254           else
1255             IRC_ONE_MODE(where, who, signe, *mode, NULL);
1256
1257           break;
1258         }
1259       mode++;
1260     }
1261 }
1262
1263 //-----------------------------------------------------------------------------
1264
1265 void get_one_line(ifstream *s, char *buffer, int buffer_size)
1266 {
1267   char *c;
1268   int d, ok;
1269   c = buffer;
1270   ok = 1;
1271   while(ok)
1272     {
1273       d = s->get();
1274       if(d>0)
1275         {
1276           if(d != '\n') *c++ = d;
1277           else ok = 0;
1278         }
1279       else ok = 0;
1280       ok &= (c<buffer + buffer_size);
1281     }
1282   *c = '\0';
1283 }
1284
1285 #define MAX_INCLUDE_RECURSE 3
1286
1287 int LoadConfigFile(char *name, int recurse)
1288 {
1289   ifstream *file;
1290   int duration, level, error;
1291   char *r, *banid;
1292   char pattern[SMALL_BUFFER_SIZE], buffer[SMALL_BUFFER_SIZE];
1293
1294   file = new ifstream(name);
1295   if(!file->fail())
1296     {
1297       clear_levels();
1298       clear_shit();
1299       restricted_list.Clear();
1300       while(!file->eof())
1301         {
1302           get_one_line(file, IRC_buffer, BUFFER_SIZE);
1303           if(strlen(IRC_buffer) > 0)
1304             {
1305               r = IRC_buffer;
1306               r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1307
1308               if(strcmp(buffer, "INCLUDE") == 0)
1309                 {
1310                   if(r != NULL)
1311                     {
1312                       if(recurse < MAX_INCLUDE_RECURSE)
1313                         {
1314                           r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1315                           LoadConfigFile(buffer, recurse+1);
1316                         }
1317 #ifdef ERROR_OUTPUT     
1318                       else cerr<<"Can't include "
1319                                <<buffer<<" : too many recursion.\n";
1320 #endif
1321                     }
1322                 }
1323               else if(strcmp(buffer, "FRIEND") == 0)
1324                 {
1325                   if(r != NULL)
1326                     {
1327                       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1328                       level = atoi(buffer);
1329                       if(r!= NULL)
1330                         {
1331                           r = next_word(pattern, r, SMALL_BUFFER_SIZE);
1332                           uncap(pattern);
1333                           level_list.Insert(new Person(pattern, level, r));
1334                         }
1335                     }
1336                 }
1337               else if(strcmp(buffer, "RESTRICTED") == 0)
1338                 {
1339                   if(r != NULL)
1340                     {
1341                       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1342 #ifdef SCREEN_OUTPUT
1343                       cout<<"RESTRICTED->"<<buffer<<"\n";
1344 #endif
1345                       restricted_list.Insert(strdup(buffer));
1346                     }
1347                 }
1348               else if(strcmp(buffer, "SHIT") == 0)
1349                 {
1350                   if(r != NULL)
1351                     {
1352                       r = next_word(pattern, r, SMALL_BUFFER_SIZE);
1353                       uncap(pattern);
1354                       if(r != NULL)
1355                         {
1356                           r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1357                           duration = atoi(buffer);
1358                           if(r == NULL) r = "Shit";
1359                           banid = clean_banid(pattern);
1360                           smart_shit(NULL, NULL, banid, r, duration);
1361                           delete[] banid;
1362                         }
1363                     }
1364                 }
1365               else if(strcmp(buffer, "OPDELAY") == 0)
1366                 {
1367                   if(r != NULL)
1368                     {
1369                       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1370                       op_delay = atoi(buffer);
1371                     }
1372                 }
1373               else if(strcmp(buffer, "DEBANDELAY") == 0)
1374                 {
1375                   if(r != NULL)
1376                     {
1377                       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1378                       deban_delay = atoi(buffer);
1379                     }
1380                 }
1381               else if(strcmp(buffer, "CONTROLCHAR") == 0)
1382                 {
1383                   if(r != NULL)
1384                     {
1385                       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1386                       if(buffer[0] != '\0') control_char = buffer[0];
1387                     }
1388                 }
1389             }
1390         }
1391       shit_list.Reverse();
1392       level_list.Reverse();
1393       restricted_list.Reverse();
1394       error = 0;
1395     }
1396   else error = 1;
1397
1398   delete file;
1399
1400   return error;
1401 }
1402
1403 int SaveConfigFile(char *name)
1404 {
1405   ofstream *file;
1406   NodeList<Welcome *> *welcome;
1407   NodeList<Person *> *person;
1408   NodeList<char *> *restricted;
1409   int error;
1410
1411   file = new ofstream(name);
1412   if(!file->fail())
1413     {
1414       (*file)<<"% Config file for a TropBot " VERSION "\n";
1415       (*file)<<"\n";
1416
1417       (*file)<<"OPDELAY "<<op_delay<<"\n";
1418       (*file)<<"DEBANDELAY "<<deban_delay<<"\n";
1419       (*file)<<"CONTROLCHAR "<<control_char<<"\n";
1420
1421       (*file)<<"\n";
1422
1423       for(person=level_list.first; person != NULL; person=person->next)
1424         {
1425           (*file)<<"FRIEND "<<person->body->level<<" "<<person->body->pattern;
1426           if(person->body->passwd != NULL) (*file)<<" "<<person->body->passwd;
1427           (*file)<<"\n";
1428         }
1429
1430       (*file)<<"\n";
1431
1432       for(restricted=restricted_list.first;
1433           restricted != NULL;
1434           restricted=restricted->next)
1435         (*file)<<"RESTRICTED "<<restricted->body<<"\n";
1436
1437       (*file)<<"\n";
1438
1439       for(welcome=shit_list.first; welcome != NULL; welcome=welcome->next)
1440         (*file)<<"SHIT "<<welcome->body->pattern<<" "<<
1441           welcome->body->time_max - current_time<<" "<<
1442           welcome->body->comment<<"\n";
1443
1444       error = 0;
1445     }
1446   else error = 1;
1447
1448   delete file;
1449
1450   return error;
1451 }
1452
1453 //-----------------------------------------------------------------------------
1454
1455 void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
1456 {
1457   NodeList<char *> *node1, *node2;
1458   int *ok, nb, k, l, level, put_blank;
1459   char *c, *d, *buf;
1460   int nb_total, nb_person[LEVEL_MAX+1];
1461
1462   nb_total = 0;
1463   for(k=0; k<LEVEL_MAX+1; k++) nb_person[k] = 0;
1464
1465   nb = present_people.Lenght();
1466   ok = new int[nb];
1467   for(k = 0; k<nb; k++) ok[k] = 0;
1468   k = 0;
1469   node1 = present_people.first;
1470
1471   buf = IRC_buffer;
1472
1473   if(pattern != NULL)
1474     {
1475       concat(buf, "\002");
1476       concat(buf, pattern);
1477       concat(buf, "\002 and same site : ");
1478     }
1479
1480   while(node1 != NULL)
1481     {
1482       if((pattern == NULL) || match_pattern(pattern, node1->body))
1483         {
1484           c = adr_beginning(node1->body);
1485           put_blank = 0;
1486           l = k;
1487           node2 = node1;
1488           while(node2 != NULL)
1489             {
1490               d = adr_beginning(node2->body);
1491               if(are_same_site(c, d))
1492                 {
1493                   d = node2->body;
1494                   level = level_person(d, NULL);
1495                   nb_total++;
1496                   nb_person[level]++;
1497                   if(put_blank) *buf++ = '/'; else put_blank = 1;
1498                   
1499                   if(level == LEVEL_OP) *buf++ = '\002';
1500                   else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
1501                   
1502                   while((*d != '!') && (*d != '\0')) *buf++ = *d++;
1503                   
1504                   if(level == LEVEL_OP) *buf++ = '\002';
1505                   else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
1506                   
1507                   ok[l] = 1;
1508                   
1509                   if(buf > IRC_buffer + NB_CHAR_MAX)
1510                     {
1511                       *buf++ = '\n'; *buf++ = '\0';
1512                       tell(chat, nick, IRC_buffer);
1513                       buf = IRC_buffer;
1514                     }
1515                 }
1516               
1517               do
1518                 {
1519                   l++;
1520                   node2 = node2->next;
1521                 }
1522               while((node2 != NULL) && (ok[l] == 1));
1523             }
1524           
1525           concat(buf, " ");
1526         }
1527
1528       do
1529         {
1530           k++;
1531           node1 = node1->next;
1532         }
1533       while((node1 != NULL) && (ok[k] == 1));
1534     }
1535
1536   *buf++ = '\n'; *buf++ = '\0';
1537   tell(chat, nick, IRC_buffer);
1538
1539   sprintf(IRC_buffer, "Total %d (\002%d\002)\n",
1540           nb_total,
1541           nb_person[LEVEL_OP] + nb_person[LEVEL_DEFENCE] +
1542           nb_person[LEVEL_MASTER]);
1543   tell(chat, nick, IRC_buffer);
1544
1545   delete[] ok;
1546 }
1547
1548 //-----------------------------------------------------------------------------
1549
1550 void notice_shit_list(DCCChat *chat, char *nick, char *pattern, int matched)
1551 {
1552   int n;
1553   char *string_duration;
1554   NodeList<Welcome *> *node;
1555
1556   if(shit_list.Lenght() == 0) tell(chat, nick, "\002Empty shit-list\002\n");
1557   else
1558     {
1559       n = 0;
1560       for(node = shit_list.first; node != NULL; node=node->next)
1561         if((matched && match_pattern(pattern, node->body->pattern))
1562            || (!matched && match_pattern(node->body->pattern, pattern)))
1563           {
1564             n++;
1565             string_duration = seconds_to_string(node->body->time_max
1566                                                 - current_time);
1567
1568             sprintf(IRC_buffer, "%s for %s (%s)\n",
1569                     node->body->pattern,
1570                     string_duration,
1571                     node->body->comment);
1572             tell(chat, nick, IRC_buffer);
1573             delete[] string_duration;
1574           }
1575
1576       if(n == 0) tell(chat, nick, "\002No corresponding shits\002\n");
1577     }
1578 }
1579
1580 //-----------------------------------------------------------------------------
1581
1582 void add_in_history(char *prefix, char *action)
1583 {
1584   NodeList<char *> *node, *pred, *next;
1585   char *s, *t;
1586   int n;
1587
1588   s = new char[strlen(prefix) + strlen(action) + 4];
1589   t = s;
1590   concat(t, prefix);
1591   concat(t, " : ");
1592   concat(t, action);
1593   *t++ = '\0';
1594   history.Add(s);
1595
1596   n = 0;
1597   pred = NULL; next = NULL; node = history.first;
1598   while(node != NULL)
1599     {
1600       n++;
1601       next = node->next;
1602       if(n>HISTORY_SIZE)
1603         {
1604           if(pred == NULL) history.first = next;
1605           else pred->next = next;
1606           delete[] node->body;
1607           delete node;
1608         }
1609       else pred = node;
1610       node = next;
1611     }
1612 }
1613
1614 void notice_history(DCCChat *chat, char *nick)
1615 {
1616   NodeList<char *> *node;
1617
1618   for(node = history.first; node != NULL; node = node->next)
1619     {
1620       sprintf(IRC_buffer, "%s\n", node->body);
1621       tell(chat, nick, IRC_buffer);
1622     }
1623 }
1624
1625 //-----------------------------------------------------------------------------
1626
1627 int dont_flood_server()
1628 {
1629   return current_time >= last_answer_time + DELAY_ANSWERS;
1630 }
1631
1632 void msg_users(DCCChat *chat, char *nick, char *pattern, char *msg)
1633 {
1634   NodeList<char *> *node;
1635   char *nick_user;
1636   int nb;
1637
1638   sprintf(IRC_buffer, "\002[msg to %s]\002 %s\n", pattern, msg);
1639   tell(chat, nick, IRC_buffer);
1640
1641   nb = 0;
1642   for(node = present_people.first; node != NULL; node = node->next)
1643     {
1644       if(match_pattern(pattern, node->body))
1645         {
1646           nb++;
1647           nick_user = cut_nick_from_prefix(node->body);
1648           sprintf(IRC_buffer, "PRIVMSG %s :\002[msg to %s]\002 %s\n",
1649                   nick_user, pattern, msg);
1650           write_irc(IRC_buffer);
1651           delete[] nick_user;
1652         }
1653     }
1654
1655   sprintf(IRC_buffer, "\002[msg sent to %d user(s)]\002\n", nb);
1656   tell(chat, nick, IRC_buffer);
1657 };
1658
1659 //-----------------------------------------------------------------------------
1660
1661 #define CMD_DEFAULT 0
1662 #define CMD_JOIN 1
1663 #define CMD_HOME 2
1664 #define CMD_BAN 3
1665 #define CMD_SBAN 4
1666
1667 void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
1668 {
1669   char buffer[SMALL_BUFFER_SIZE], buffer_time[SMALL_BUFFER_SIZE];
1670   char *r, *s, *c, *banid;
1671   char *string_duration;
1672   int cmd, level, l, no_authorized, od;
1673   int duration;
1674   NodeList<DCCChat *> *node;
1675
1676   r = msg;
1677
1678   if(r != NULL)
1679     {
1680       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1681
1682       if(*buffer == '&')
1683         {
1684           level = level_person(prefix, buffer+1);
1685           if(r != NULL) r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1686           else return;
1687         }
1688       else level = level_person(prefix, NULL);
1689
1690       cmd = CMD_DEFAULT;
1691       if(eq("join", buffer)) cmd = CMD_JOIN;
1692       else if(eq("home", buffer)) cmd = CMD_HOME;
1693       else if(eq("b", buffer) || eq("ban", buffer)) cmd = CMD_BAN;
1694       else if(eq("sb", buffer) || eq("siteban", buffer)) cmd = CMD_SBAN;
1695
1696       no_authorized = 0;
1697
1698       if(eq("ms", buffer) || eq("myshit", buffer))
1699         {
1700           if(dont_flood_server()) notice_shit_list(chat, nick, prefix, 0);
1701         }
1702       else if(eq("write", buffer) || eq("wr", buffer))
1703         {
1704           if(level >= LEVEL_MASTER)
1705             {
1706               if(r != NULL)
1707                 {
1708                   sprintf(IRC_buffer, "PRIVMSG %s :%s\n", current_channel, r);
1709                   write_irc(IRC_buffer);
1710                 }
1711             }
1712           else no_authorized = 1;
1713         }
1714       else if(eq("sl", buffer) || eq("shitlist", buffer))
1715         {
1716           if(level >= LEVEL_FRIEND)
1717             {
1718               if(r != NULL)
1719                 {
1720                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1721                   uncap(buffer);
1722
1723                   if(is_pattern(buffer))
1724                     notice_shit_list(chat, nick, buffer, 1);
1725                   else
1726                     {
1727                       wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
1728                                                      MODE_SHITLIST, 0));
1729                       
1730                       sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1731                       write_irc(IRC_buffer);
1732                     }
1733                 }
1734               else
1735                 {
1736                   int s1, s2, s3, s4, d;
1737                   NodeList<Welcome *> *node;
1738                   s1 = 0; s2 = 0; s3 = 0; s4 = 0;
1739                   for(node=shit_list.first; node != NULL; node=node->next)
1740                     {
1741                       d = node->body->time_max - current_time;
1742                       if(d < 1800) s1++;
1743                       else if(d < 4*3600) s2++;
1744                       else if(d < 24*3600) s3++;
1745                       else s4++;
1746                     }
1747
1748                   sprintf(IRC_buffer,
1749                           "%d entries "
1750                           "\002%d\002 < 30min < \002%d\002 < "
1751                           "4h < \002%d\002 < 24h < \002%d\002\n",
1752                           s1+s2+s3+s4, s1, s2, s3, s4);
1753                   tell(chat, nick, IRC_buffer);
1754                 }
1755             }
1756           else no_authorized = 1;
1757         }
1758       else if(eq("www", buffer))
1759         {
1760           if(dont_flood_server())
1761             tell(chat, nick, "THX-1138's home page at "
1762                  "http://www.eleves.ens.fr:8080/home/fleuret/\n");
1763         }
1764       else if(eq("w", buffer) || eq("who", buffer))
1765         {
1766           if(level >= LEVEL_FRIEND)
1767             {
1768               if(r == NULL) notice_list_by_sites(chat, nick, NULL);
1769               else while(r != NULL)
1770                 {
1771                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1772                   uncap(buffer);
1773                   notice_list_by_sites(chat, nick, buffer);
1774                 }
1775             }
1776           else no_authorized = 1;
1777         }
1778       else if(eq("ao", buffer) || eq("antifloodoff", buffer))
1779         {
1780           if(level >= LEVEL_OP)
1781             {
1782               if(r != NULL)
1783                 {
1784                   r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
1785                   duration =  string_to_seconds(buffer_time);
1786                   anti_flood_off_until = current_time + duration;
1787                 }
1788               if(anti_flood_off_until > current_time)
1789                 {
1790                   string_duration = seconds_to_string(anti_flood_off_until - 
1791                                                       current_time);
1792                   sprintf(IRC_buffer, "Anti-flood off for %s\n",
1793                           string_duration);
1794                   delete[] string_duration;
1795                   
1796                   tell(chat, nick, IRC_buffer);
1797                 }
1798               else tell(chat, nick, "Anti-flood on\n");
1799             }
1800           else no_authorized = 1;
1801         }
1802       else if(eq("msg", buffer) || eq("message", buffer))
1803         {
1804           if(level >= LEVEL_OP)
1805             {
1806               if(r != NULL)
1807                 {
1808                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1809                   if(r != NULL)
1810                     {
1811                       if(is_pattern(buffer)) msg_users(chat, nick, buffer, r);
1812                       else
1813                         {
1814                           uncap(buffer);
1815                           wait_list.Insert(new WaitInfos(buffer, r, chat,
1816                                                          nick,
1817                                                          MODE_MSG, 0));
1818                           
1819                           sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1820                           write_irc(IRC_buffer);
1821                         }
1822                     }
1823                 }
1824             }
1825           else no_authorized = 1;
1826         }
1827       else if(eq("h", buffer) || eq("history", buffer))
1828         {
1829           if(level >= LEVEL_OP) notice_history(chat, nick);
1830           else no_authorized = 1;
1831         }
1832       else if(eq("level", buffer))
1833         {
1834           if(level >= LEVEL_FRIEND)
1835             {
1836               if(r != NULL)
1837                 {
1838                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1839                   uncap(buffer);
1840
1841                   wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1842                                                  MODE_LEVEL, 0));
1843                   sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1844                   write_irc(IRC_buffer);
1845                 }
1846               else
1847                 {
1848                   sprintf(IRC_buffer, "%s is level %d\n", prefix,
1849                           level_person(prefix, NULL));
1850                   tell(chat, nick, IRC_buffer);
1851                 }
1852             }
1853           else no_authorized = 1;
1854         }
1855       else if(eq("mode", buffer))
1856         {
1857           if(dont_flood_server() || (level >= LEVEL_FRIEND))
1858             {
1859               char *a;
1860               if(cop_mode) a = "ON"; else a = "OFF";
1861               if(father)
1862                 {
1863                   sprintf(IRC_buffer,
1864                           "control_char '%c' op_delay %ds  deban_delay %ds "
1865                           "cop-mode %s"
1866                           " your level is %d. I am a father with %d sons.\n",
1867                           control_char, op_delay, deban_delay, a,
1868                           level, nb_sons);
1869                   tell(chat, nick, IRC_buffer);
1870                 }
1871               else
1872                 {
1873                   sprintf(IRC_buffer,
1874                           "control_char '%c' op_delay %ds  deban_delay %ds "
1875                           "cop-mode %s"
1876                           " your level is %d. I'm a clone.\n",
1877                           control_char, op_delay, deban_delay, a,
1878                           level);
1879                   tell(chat, nick, IRC_buffer);
1880                 }
1881             }
1882         }
1883       else if(eq("help", buffer))
1884         {
1885           if(level >= LEVEL_FRIEND)
1886             {
1887               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");
1888             }
1889
1890           if(level >= LEVEL_OP)
1891             {
1892               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");
1893             }
1894
1895           if(level >= LEVEL_MASTER)
1896             {
1897               tell(chat, nick, "\002reset\002  \002load\002 [<file>]  \002save\002 [<file>]  \002friend\002 <pattern> <level> [<passwd>]  \002clone\002 [<nick>]  \002die\002  \002server\002 <hostname> [<port>]  \002controlchar\002 <char>  \002opdelay\002 <delay in s>  \002debandelay\002 <delay in s>\n");
1898             }
1899
1900           if(chat != NULL)
1901             {
1902               tell(chat, nick, "\002\037u\037\002sers\002  \002\037t\037\002alk\002 <msg>\n");
1903             }
1904
1905         }
1906       else if((cmd == CMD_JOIN) || (cmd == CMD_HOME))
1907         {
1908           if(level >= LEVEL_OP)
1909             {
1910               if(global_state == STATE_WAIT)
1911                 {
1912                   sprintf(IRC_buffer, "PART %s\n", current_channel);
1913                   write_irc(IRC_buffer);
1914                   if(cmd == CMD_HOME)
1915                     strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
1916                   else
1917                     if(r != NULL)
1918                       { 
1919                         r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1920                         strncpy(wanted_channel, buffer, SMALL_BUFFER_SIZE);
1921                       }
1922                   uncap(wanted_channel);
1923                   sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
1924                   write_irc(IRC_buffer);
1925                 }
1926               else
1927                 tell(chat, nick, "Can't join right now, retry in a while\n");
1928             } else no_authorized = 1;
1929         }
1930       else if(eq("op", buffer))
1931         {
1932           if(level >= LEVEL_OP)
1933             {
1934               if(r == NULL) add_mode(current_channel, "+o", nick);
1935               else
1936                 while(r != NULL)
1937                   {
1938                     r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1939                     add_mode(current_channel, "+o", buffer);
1940                   }
1941             }
1942           else no_authorized = 1;
1943         }
1944       else if(eq("nick", buffer))
1945         {
1946           if(level >= LEVEL_OP)
1947             {
1948               if(r != NULL)
1949                 {
1950                   r = next_word(wanted_nick, r, SMALL_BUFFER_SIZE);
1951                   sprintf(buffer, "NICK %s\n", wanted_nick);
1952                   write_irc(buffer);
1953                 }
1954             } else no_authorized = 1;
1955         }
1956       else if(eq("db", buffer) || eq("deban", buffer))
1957         {
1958           if(level >= LEVEL_OP)
1959             {
1960               while(r != NULL)
1961                 {
1962                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1963                   if(is_pattern(buffer))
1964                     {
1965                       NodeList<char *> *node;
1966                       for(node = banid_list.first; node != NULL; node = node->next)
1967                         if(match_pattern(buffer, node->body))
1968                           add_mode(current_channel, "-b", node->body);
1969                     }
1970                   else
1971                     {
1972                       wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
1973                                                      MODE_UNBAN_NICK, 0));
1974                       sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1975                       write_irc(IRC_buffer);
1976                     }
1977                 }
1978             } else no_authorized = 1;
1979         }
1980       else if((cmd == CMD_BAN) || (cmd == CMD_SBAN))
1981         {
1982           if(level >= LEVEL_OP)
1983             {
1984               while(r != NULL)
1985                 {
1986                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1987                   uncap(buffer);
1988                   
1989                   if(is_pattern(buffer))
1990                     {
1991                       banid = clean_banid(buffer);
1992                       smart_ban(current_channel, banid);
1993                       delete[] banid;
1994                     }
1995                   else
1996                     {
1997                       switch(cmd)
1998                         {
1999                         case CMD_BAN:
2000                           wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2001                                                          MODE_BAN_NICK, 0));
2002                           break;
2003                         case CMD_SBAN:
2004                           wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2005                                                          MODE_BAN_SITE, 0));
2006                           break;
2007                         default:
2008                           break;
2009                         }
2010                       sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2011                       write_irc(IRC_buffer);
2012                     }
2013                 }
2014             }
2015           else no_authorized = 1;
2016         }
2017       else if(eq("pb", buffer) || eq("pruneban", buffer))
2018         {
2019           if(level >= LEVEL_OP)
2020             {
2021               if(r != NULL)
2022                 {
2023                   NodeList<char *> *node;
2024                   int n;
2025                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2026                   n = atoi(buffer);
2027                   if(n >= 0)
2028                     {
2029                       for(node = banid_list.first; node != NULL;
2030                           node = node->next)
2031                         if(n == 0) add_mode(current_channel, "-b", node->body);
2032                         else n--;
2033                     }
2034                 }
2035             } else no_authorized = 1;
2036         }
2037       else if(eq("synch", buffer))
2038         {
2039           if(level >= LEVEL_OP) synch(current_channel);
2040           else no_authorized = 1;
2041         }
2042       else if(eq("cop", buffer))
2043         {
2044           if(level >= LEVEL_OP)
2045             {
2046               cop_mode = !cop_mode;
2047               if(cop_mode) tell(chat, nick, "cop mode ON\n");
2048               else tell(chat, nick, "cop mode OFF\n");
2049             }
2050           else no_authorized = 1;
2051         }
2052       else if(eq("s", buffer) || eq("shit", buffer))
2053         {
2054           if(level >= LEVEL_OP)
2055             {
2056               if(r != NULL)
2057                 {
2058                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2059                   
2060                   if(is_pattern(buffer))
2061                     {
2062                       if(r != NULL)
2063                         {
2064                           r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2065                           duration =  string_to_seconds(buffer_time);
2066                         }
2067                       else duration = DEFAULT_SHIT_TIME;
2068
2069                       if(r == NULL) r = "Shit nick";
2070
2071                       uncap(buffer);
2072                       banid = clean_banid(buffer);
2073                       smart_shit(chat, nick, banid, r, duration);
2074                       delete[] banid;
2075                     }
2076                   else
2077                     {
2078                       if(r != NULL)
2079                         {
2080                           r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2081                           duration = string_to_seconds(buffer_time);
2082                         }
2083                       else duration = DEFAULT_SHIT_TIME;
2084
2085                       if(r == NULL) r = "Shit nick";
2086
2087                       uncap(buffer);
2088                       wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2089                                                      MODE_SHIT_NICK,
2090                                                      duration));
2091
2092                       sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2093                       write_irc(IRC_buffer);
2094                     }
2095                 }
2096             }
2097           else no_authorized = 1;
2098         }
2099
2100       else if(eq("fk", buffer) || eq("filterkick", buffer))
2101         {
2102           if(level >= LEVEL_OP)
2103             {
2104               if(r != NULL)
2105                 {
2106                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2107                   uncap(buffer);
2108                   if(is_pattern(buffer))
2109                     {
2110                       if(r == NULL) r = "Filter kick";
2111                       filter_kick(current_channel, buffer, r);
2112                     }
2113                   else
2114                     {
2115                       if(r == NULL) r = "Filter Kick";
2116                       wait_list.Insert(new
2117                                        WaitInfos(buffer, r, chat, nick,
2118                                                  MODE_FILTER_KICK, 0));
2119                       sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2120                       write_irc(IRC_buffer);
2121                     }
2122                 }
2123             }
2124           else no_authorized = 1;
2125         }
2126
2127       else if(eq("a", buffer) || eq("alert", buffer))
2128         {
2129           if(level >= LEVEL_OP) alert(current_channel, chat, nick);
2130           else no_authorized = 1;
2131         }
2132
2133       else if(eq("sh", buffer) || eq("shithost", buffer))
2134         {
2135           if(level >= LEVEL_OP)
2136             {
2137               if(r != NULL)
2138                 {
2139                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2140                   
2141                   if(r != NULL)
2142                     {
2143                       r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2144                       duration = string_to_seconds(buffer_time);
2145                     }
2146                   else duration = DEFAULT_SHIT_TIME;
2147
2148                   if(r == NULL) r = "Shit host";
2149
2150                   uncap(buffer);
2151                   wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2152                                                  MODE_SHIT_HOST, duration));
2153
2154                   sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2155                   write_irc(IRC_buffer);
2156                 }
2157             }
2158           else no_authorized = 1;
2159         }
2160       else if(eq("ss", buffer) || eq("shitsite", buffer))
2161         {
2162           if(level >= LEVEL_OP)
2163             {
2164               if(r != NULL)
2165                 {
2166                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2167                   
2168                   if(r != NULL)
2169                     {
2170                       r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2171                       duration = string_to_seconds(buffer_time);
2172                     }
2173                   else duration = DEFAULT_SHIT_TIME;
2174
2175                   if(r == NULL) r = "Shit site";
2176
2177                   uncap(buffer);
2178                   wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2179                                                  MODE_SHIT_SITE, duration));
2180
2181                   sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2182                   write_irc(IRC_buffer);
2183                 }
2184             }
2185           else no_authorized = 1;
2186         }
2187       else if(eq("pus", buffer) || eq("punshit", buffer))
2188         {
2189           if(level >= LEVEL_OP)
2190             {
2191               while(r != NULL)
2192                 {
2193                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2194                   
2195                   if(strlen(buffer) > 0)
2196                     {
2197                       NodeList<Welcome *> *node, *next, *pred;
2198                       pred = NULL;
2199                       uncap(buffer);
2200                       node = shit_list.first;
2201                       while(node != NULL)
2202                         {
2203                           next = node->next;
2204                           if(match_pattern(buffer, node->body->pattern))
2205                             {
2206                               smart_unban(current_channel, node->body->pattern);
2207                               if(pred == NULL) shit_list.first = next;
2208                               else pred->next = next;
2209                               sprintf(IRC_buffer,
2210                                       "Unshit %s (%s)\n",
2211                                       node->body->pattern,
2212                                       node->body->comment);
2213                               tell(chat, nick, IRC_buffer);
2214                               delete node->body;
2215                               delete node;
2216                             }
2217                           else pred = node;
2218                           node = next;
2219                         }
2220                     }
2221                 }
2222             }
2223           else no_authorized = 1;
2224         }
2225       else if(eq("us", buffer) || eq("unshit", buffer))
2226         {
2227           if(level >= LEVEL_OP)
2228             {
2229               while(r != NULL)
2230                 {
2231                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2232                   
2233                   uncap(buffer);
2234                   if(is_pattern(buffer))
2235                     {
2236                       NodeList<Welcome *> *node, *next, *pred;
2237                       pred = NULL;
2238                       uncap(buffer);
2239                       node = shit_list.first;
2240                       while(node != NULL)
2241                         {
2242                           next = node->next;
2243                           if(strcmp(node->body->pattern, buffer) == 0)
2244                             {
2245                               if(pred == NULL) shit_list.first = next;
2246                               else pred->next = next;
2247                               sprintf(IRC_buffer,
2248                                       "Unshit %s (%s)\n",
2249                                       buffer, node->body->comment);
2250                               tell(chat, nick, IRC_buffer);
2251                               delete node->body;
2252                               delete node;
2253                             }
2254                           else pred = node;
2255                           node = next;
2256                         }
2257                     }
2258                   else
2259                     {
2260                       wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
2261                                                      MODE_UNSHIT_NICK, 0));
2262                       
2263                       sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2264                       write_irc(IRC_buffer);
2265                     }
2266                 }
2267             }
2268           else no_authorized = 1;
2269         }
2270       else if(eq("friend", buffer))
2271         {
2272           if(level >= LEVEL_MASTER)
2273             {
2274               if(r != NULL)
2275                 {
2276                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2277                   if(r != NULL)
2278                     {
2279                       r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2280                       l = atoi(buffer_time);
2281                       if((l > 0) && (l<=LEVEL_MASTER))
2282                         {
2283                           level_list.Insert(new Person(buffer, l, r));
2284                           sprintf(IRC_buffer,
2285                                   "Adding %s with level %d and passwd %s\n",
2286                                   buffer, l, r);
2287                           tell(chat, nick, IRC_buffer);
2288                           SaveConfigFile(config_file);
2289                         }
2290                     }
2291                 }
2292             }
2293           else no_authorized = 1;
2294         }
2295       else if(eq("opdelay", buffer))
2296         {
2297           if(level >= LEVEL_MASTER)
2298             {
2299               if(r != NULL)
2300                 {
2301                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2302                   od = atoi(buffer);
2303                   if((od>=0) && (od <= 60))
2304                     {
2305                       op_delay = od;
2306                       sprintf(IRC_buffer,"Op delay set to %ds\n", op_delay);
2307                       tell(chat, nick, IRC_buffer);
2308                     }
2309                 }
2310             }
2311           else no_authorized = 1;
2312         }
2313       else if(eq("debandelay", buffer))
2314         {
2315           if(level >= LEVEL_MASTER)
2316             {
2317               if(r != NULL)
2318                 {
2319                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2320                   od = atoi(buffer);
2321                   if((od>=0) && (od <= 60))
2322                     {
2323                       deban_delay = od;
2324                       sprintf(IRC_buffer,
2325                               "Deban delay set to %ds\n",
2326                               deban_delay);
2327                       tell(chat, nick, IRC_buffer);
2328                     }
2329                 }
2330             }
2331           else no_authorized = 1;
2332         }
2333       else if(eq("controlchar", buffer))
2334         {
2335           if(level >= LEVEL_MASTER)
2336             {
2337               if(r != NULL)
2338                 {
2339                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2340                   control_char = buffer[0];
2341                   sprintf(IRC_buffer, "Control char set to '%c'\n",
2342                           control_char);
2343                   tell(chat, nick, IRC_buffer);
2344                 }
2345             }
2346           else no_authorized = 1;
2347         }
2348       else if(eq("die", buffer))
2349         {
2350           if(level >= LEVEL_MASTER)
2351             {
2352               sprintf(IRC_buffer, "QUIT :Killed by %s\n", nick);
2353               write_irc(IRC_buffer);
2354               alive = 0;
2355             }
2356           else no_authorized = 1;
2357         }
2358       else if(eq("server", buffer))
2359         {
2360           if(level >= LEVEL_MASTER)
2361             {
2362               if(r != NULL)
2363                 {
2364                   next_word(wanted_server, r, SMALL_BUFFER_SIZE);
2365                   if(r != NULL)
2366                     {
2367                       next_word(buffer, r, SMALL_BUFFER_SIZE);
2368                       wanted_port = atoi(buffer);
2369                       if(wanted_port == 0) wanted_port = 6667;
2370                     }
2371                   else wanted_port = DEFAULT_PORT;
2372
2373                   sprintf(IRC_buffer,
2374                           "Trying to connect %s:%d\n",
2375                           wanted_server, wanted_port);
2376                   tell(chat, nick, IRC_buffer);
2377                   
2378                   sprintf(IRC_buffer, "QUIT :Changing server\n");
2379                   write_irc(IRC_buffer);
2380
2381 #ifdef ERROR_OUTPUT
2382                   cerr<<"KILLING CONNECTION : Changing server\n";
2383                   cerr.flush();
2384 #endif
2385                   kill_connection();
2386                 }
2387             }
2388           else no_authorized = 1;
2389         }
2390       else if(eq("clone", buffer))
2391         {
2392           if(level >= LEVEL_MASTER)
2393             {
2394               if(father)
2395                 {
2396                   if(nb_sons < NB_SONS_MAX)
2397                     {
2398                       if(r != NULL) next_word(buffer, r, SMALL_BUFFER_SIZE);
2399                       clone(buffer);
2400                       nb_sons++;
2401                     }
2402                   else tell(chat, nick, "Too many clones, can't clone\n");
2403                 }
2404               else
2405                 {
2406                   tell(chat, nick, "I'm a clone, can't clone\n");
2407                 }
2408             }
2409           else no_authorized = 1;
2410         }
2411       else if(eq("save", buffer))
2412         {
2413           if(level >= LEVEL_MASTER)
2414             {
2415               if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
2416               if(SaveConfigFile(config_file))
2417                 {
2418                   sprintf(IRC_buffer,
2419                           "Can't save the %s configuration file\n",
2420                           config_file);
2421                 }
2422               else
2423                 {
2424                   sprintf(IRC_buffer,
2425                           "Saving the %s configuration file\n",
2426                           config_file);
2427                 }
2428               tell(chat, nick, IRC_buffer);
2429             }
2430           else no_authorized = 1;
2431         }
2432       else if(eq("load", buffer))
2433         {
2434           if(level >= LEVEL_MASTER)
2435             {
2436               if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
2437               if(LoadConfigFile(config_file, 0))
2438                 {
2439                   sprintf(IRC_buffer,
2440                           "Can't load the %s configuration file\n",
2441                           config_file);
2442                 }
2443               else
2444                 {
2445                   sprintf(IRC_buffer,
2446                           "Loading the %s configuration file\n",
2447                           config_file);
2448                 }
2449               tell(chat, nick, IRC_buffer);
2450             }
2451           else no_authorized = 1;
2452         }
2453       else if(eq("reset", buffer))
2454         {
2455           if(level >= LEVEL_MASTER)
2456             {
2457               sprintf(IRC_buffer, "QUIT :reset command sent by %s\n", nick);
2458               write_irc(IRC_buffer);
2459 #ifdef ERROR_OUTPUT
2460               cerr<<"KILLING CONNECTION : Die\n";
2461               cerr.flush();
2462 #endif
2463               kill_connection();
2464             }
2465           else no_authorized = 1;
2466         }
2467
2468       // DCC CHAT only commands
2469
2470       else if((chat != NULL) && (eq("t", buffer) || eq("talk", buffer)))
2471         {
2472           NodeList<DCCChat *> *node;
2473           sprintf(IRC_buffer, "<%s> %s\n", prefix, r);
2474           for(node = dcc_chat_list.first; node != NULL; node = node->next)
2475             if(node->body != chat) tell(node->body, NULL, IRC_buffer);
2476         }
2477       else if((chat != NULL) && (eq("u", buffer) || eq("users", buffer)))
2478         {
2479           for(node = dcc_chat_list.first; node != NULL; node = node->next)
2480             {
2481               sprintf(IRC_buffer, "%s\n", node->body->prefix);
2482               tell(chat, NULL, IRC_buffer);
2483             }
2484         }
2485
2486       // Unknown command
2487
2488       else if(dont_flood_server())
2489         {
2490           sprintf(IRC_buffer, "Unknown command \002%s\002\n", buffer);
2491           tell(chat, nick, IRC_buffer);
2492         }
2493     }
2494   
2495   if(no_authorized)
2496     {
2497       if(dont_flood_server())
2498         {
2499           sprintf(IRC_buffer,
2500                   "You are not authorized to use \002%s\002\n", buffer);
2501           tell(chat, nick, IRC_buffer);
2502         }
2503     }
2504   else
2505     {
2506       r = msg;
2507       if(*r == '&') r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2508       add_in_history(prefix, r);
2509     }
2510 }
2511
2512 //-----------------------------------------------------------------------------
2513
2514 int accepting_dcc_chat(char *prefix, char *nick, int level, char *r)
2515 {
2516   NodeList<DCCChat *> *node;
2517   int socket, port_number;
2518   char host[SMALL_BUFFER_SIZE], port[SMALL_BUFFER_SIZE];
2519   DCCChat *dcc_chat;
2520   
2521   if(r == NULL) return 1;
2522   else r = next_word(host, r, SMALL_BUFFER_SIZE);
2523
2524   if(strcmp(host, "chat") != 0) return 1;
2525
2526   if(r == NULL) return 1;
2527   else r = next_word(host, r, SMALL_BUFFER_SIZE);
2528
2529   if(r == NULL) return 1;
2530   else r = next_word(port, r, SMALL_BUFFER_SIZE);
2531
2532   port_number = atoi(port);
2533   socket = call_socket(host, port_number);
2534
2535   if(socket <= 0) return 1;
2536   else
2537     {
2538       dcc_chat = new DCCChat(prefix, socket, port_number);
2539       dcc_chat_list.Insert(dcc_chat);
2540
2541       FD_SET(socket, &ready);
2542
2543       sprintf(IRC_buffer,
2544               "Welcome to \002TropBot\002 " VERSION " on a DCC CHAT\n"
2545               "You are known as %s, your level is %d.\n"
2546               "You are client #%d on DCC CHAT\n",
2547               prefix, level, dcc_chat_list.Lenght());
2548
2549       write(socket, IRC_buffer, strlen(IRC_buffer));
2550
2551       sprintf(IRC_buffer, "%s arrives with level %d.\n", prefix, level);
2552       for(node=dcc_chat_list.first; node!= NULL; node = node->next)
2553         if(node->body != dcc_chat) tell(node->body, NULL, IRC_buffer);
2554
2555       return 0;
2556     }
2557 }
2558
2559 //-----------------------------------------------------------------------------
2560
2561 void pong_reply(char *nick, char *value)
2562 {
2563   NodeList<WaitPing *> *node, *next, *pred;
2564
2565   cout<<"pong_reply : nick >"<<nick<<"< value >"<<value<<"<\n";
2566
2567   pred = NULL;
2568   node = wait_ping.first;
2569   while(node != NULL)
2570     {
2571       next = node->next;
2572       if(current_time > node->body->time_max)
2573         {
2574           if(pred == NULL) wait_ping.first = next;
2575           else pred->next = next;
2576           delete node->body;
2577           delete node;
2578         }
2579       if(strcmp(nick, node->body->nick) == 0)
2580         {
2581           if(strcmp(value, node->body->value) == 0)
2582             add_mode(current_channel, "+o", nick);
2583
2584           if(pred == NULL) wait_ping.first = next;
2585           else pred->next = next;
2586           delete node->body;
2587           delete node;
2588         }
2589       else pred = node;
2590       node = next;
2591     }
2592 }
2593
2594 // This function is called after a NOTICE
2595 void IRC_NOTICE(char *prefix,
2596                 char *who, char *msg, char **slice_ctcp, int n_ctcp)
2597 {
2598   int k;
2599   char word[SMALL_BUFFER_SIZE], *r, *nick;
2600   uncap(who);
2601   if(strcmp(who, current_channel) == 0) add_flood_line(prefix, FL_NOTICE, 1);
2602 #ifdef ANTI_SPOOF
2603   else if(strcmp(who, real_nick) == 0)
2604     for(k=0; k<n_ctcp; k++)
2605       {
2606         cout<<"ctcp >"<<slice_ctcp[k]<<"<\n";
2607         r = slice_ctcp[k];
2608         r = next_word(word, r, SMALL_BUFFER_SIZE);
2609         if(strcmp(word, "PING") == 0)
2610           {
2611             nick = cut_nick_from_prefix(prefix);
2612             r = next_word(word, r, SMALL_BUFFER_SIZE);
2613             pong_reply(nick, word);
2614             delete nick;
2615           }
2616       }
2617 #endif
2618 }
2619
2620 void IRC_PRIVMSG(char *prefix,
2621                  char *who, char *msg, char **slice_ctcp, int n_ctcp)
2622 {
2623   int k, version, ping, level, ctcp, kick;
2624   char *nick, *r, *pattern, *banid;
2625   char buffer[SMALL_BUFFER_SIZE];
2626
2627   uncap(who);
2628   nick = cut_nick_from_prefix(prefix);
2629
2630   level = level_person(prefix, NULL);
2631
2632   kick = 0;
2633   if(strcmp(who, current_channel) == 0)
2634     {
2635       add_flood_line(prefix, FL_PUBLIC, 1);
2636
2637       if(n_ctcp > 0)
2638         {
2639           add_flood_line(prefix, FL_CTCP, n_ctcp);
2640
2641           if((cop_mode) && (level < LEVEL_FRIEND))
2642             {
2643               ctcp = 0;
2644               for(k = 0; (k<n_ctcp) && !ctcp; k++)
2645                 {
2646                   r = slice_ctcp[k];
2647                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2648                   if(strcmp(buffer, "ACTION") != 0) ctcp =1;
2649                   else 
2650                     {
2651                       if(!kick && (r != NULL) && (bad_line(r, buffer)))
2652                         {
2653                           sprintf(IRC_buffer,"KICK %s %s :cop : %s\n",
2654                                   current_channel, nick, buffer);
2655                           write_irc(IRC_buffer);
2656                         }
2657                       kick = 1;
2658                     }
2659                 }
2660
2661               if(!kick) if(ctcp) if(level < LEVEL_FRIEND)
2662                 {
2663                   pattern = pattern_from_prefix(prefix, 0);
2664                   banid = clean_banid(pattern);
2665                   smart_shit(NULL, NULL, pattern, "cop : no ctcp",
2666                              COP_DURATION + deban_delay);
2667                   smart_ban(current_channel, pattern);
2668                   send_mode(current_channel);
2669                   sprintf(IRC_buffer, "KICK %s %s :cop : no ctcp\n",
2670                           current_channel, nick);
2671                   write_irc(IRC_buffer);
2672                   kick = 1;
2673                   delete[] banid;
2674                   delete[] pattern;
2675                 }
2676             }
2677         }
2678       else if(cop_mode) if(level < LEVEL_FRIEND)
2679         if(!kick) if((msg != NULL) && bad_line(msg, buffer))
2680           {
2681             sprintf(IRC_buffer, "KICK %s %s :cop : %s\n",
2682                     current_channel, nick, buffer);
2683             write_irc(IRC_buffer);
2684           }
2685     }
2686   
2687   if(msg != NULL) if(strlen(msg)>0)
2688     {
2689       if(msg[0] == control_char) tropbot_cmd(NULL, prefix, nick, msg+1);
2690       else if(strcmp(who, real_nick) == 0)
2691         tropbot_cmd(NULL, prefix, nick, msg);
2692     }
2693   
2694   version = 0;
2695   ping = 0;
2696   for(k=0; k<n_ctcp; k++)
2697     {
2698       r = slice_ctcp[k];
2699       r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2700       
2701       // Reply the CTCP VERSION
2702       if(eq("VERSION", buffer) && !version)
2703         {
2704           if(dont_flood_server())
2705             {
2706               version = 1;
2707               sprintf(IRC_buffer, "NOTICE %s :"
2708                       "\001VERSION \002TropBot\002 " VERSION OPTIONS
2709                       ", " SYSTEM " system, " DATE ". "
2710                       "Contact THX-1138 on IRCNet, or <francois.fleuret@inria.fr>"
2711                       "\001\n",
2712                       nick);
2713               write_irc(IRC_buffer);
2714             }
2715         }
2716       // Reply the CTCP PING
2717       else if(eq("PING", buffer) && !ping)
2718         {
2719           ping = 1;
2720           if(r != NULL)
2721             if(dont_flood_server())
2722               {
2723                 ping = 1;
2724                 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2725                 sprintf(IRC_buffer,
2726                         "NOTICE %s :\001PING %s\001\n", nick, buffer);
2727                 write_irc(IRC_buffer);
2728               }
2729         }
2730       // DCC (chat)
2731       else if(eq("DCC", buffer))
2732         {
2733           if(level >= LEVEL_OP)
2734             {
2735               if(r != NULL)
2736                 {
2737                   r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2738                   if(eq("CHAT", buffer))
2739                     {
2740                       if(accepting_dcc_chat(prefix, nick, level, r) != 0)
2741                         {
2742                           sprintf(IRC_buffer, "NOTICE %s :\002Error\002"
2743                                   " can't connect\n", nick);
2744                           write_irc(IRC_buffer);
2745                         }
2746                     }
2747                   else
2748                     {
2749                       sprintf(IRC_buffer,
2750                               "NOTICE %s :I can only DCC CHAT\n", nick);
2751                       write_irc(IRC_buffer);
2752                     }
2753                 }
2754             }
2755           else if(dont_flood_server())
2756             {
2757               sprintf(IRC_buffer,
2758                       "NOTICE %s :Sorry, can't accept DCC from you\n",
2759                       nick, buffer);
2760               write_irc(IRC_buffer);
2761             }
2762         }
2763     }
2764   delete[] nick;
2765 }
2766
2767 //-----------------------------------------------------------------------------
2768
2769 // This function is called after a QUIT
2770
2771 void IRC_QUIT(char *prefix)
2772 {
2773   present_people.Remove(prefix);
2774 }
2775
2776 //-----------------------------------------------------------------------------
2777
2778 // This function is called after a NICK
2779
2780 void IRC_NICK(char *prefix, char *nick)
2781 {
2782   char *s, *t;
2783   int ok;
2784   add_flood_line(prefix, FL_NICK, 1);
2785   present_people.Remove(prefix);
2786   s = IRC_buffer;
2787   t = nick; while(*t != '\0') *s++=*t++; // copy the nick
2788   *s++='!';                           // put the '!'
2789   t = reach_loginathost(prefix);
2790   while(*t != '\0') *s++=*t++;           // copy the user@host
2791   *s = '\0';                          // end of string
2792   present_people.Add(IRC_buffer);     // hop !
2793
2794   ok = 1; s = prefix; t = real_nick;
2795   while(ok && (*t != '\0') && (*s != '\0')) ok = (*s++ == *t++);
2796   if(ok && (*t == '\0') && (*s == '!'))
2797     {
2798       strncpy(real_nick, nick, SMALL_BUFFER_SIZE);
2799       uncap(real_nick);
2800     }
2801 }
2802
2803 //-----------------------------------------------------------------------------
2804
2805 // This function is called after a PART
2806
2807 void IRC_PART(char *prefix, char *where)
2808 {
2809   char *nick;
2810   add_flood_line(prefix, FL_PART, 1);
2811   present_people.Remove(prefix);
2812   nick = cut_nick_from_prefix(prefix);
2813   if(strcmp(real_nick, nick) == 0)
2814     {
2815       present_people.Clear();
2816       in_channel = 0;
2817     }
2818   delete[] nick;
2819 }
2820
2821 //-----------------------------------------------------------------------------
2822
2823 // This function is called after a KICK
2824
2825 void IRC_KICK(char *prefix, char *where, char *victim_nick)
2826 {
2827   char *c, *d;
2828   uncap(victim_nick);
2829
2830   if(strcmp(victim_nick, real_nick) == 0)
2831     {
2832       present_people.Clear();
2833       in_channel = 0;
2834       sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
2835       write_irc(IRC_buffer);
2836     }
2837
2838   c = strdup(prefix_from_nick(victim_nick));
2839
2840   if((level_person(prefix, NULL) < level_person(prefix_from_nick(victim_nick), NULL)) &&
2841      (level_person(prefix_from_nick(victim_nick), NULL) > 0))
2842     {
2843       d = cut_nick_from_prefix(prefix);
2844       add_mode(where, "-o", d);
2845       delete[] d;
2846     }
2847   else if(cop_mode && (c != NULL)) add_kick(c);
2848
2849   if(c != NULL) present_people.Remove(c);
2850 #ifdef ERROR_OUTPUT
2851   else cerr<<"** ERROR : non present person has been kicked out **\n";
2852 #endif
2853
2854   delete[] c;
2855 }
2856
2857 //-----------------------------------------------------------------------------
2858
2859 int check_restricted(char *where, char *prefix)
2860 {
2861   char pattern[SMALL_BUFFER_SIZE];
2862   NodeList<char *> *node;
2863   char *p, *s;
2864   int n, duration;
2865
2866   p = adr_beginning(prefix);
2867
2868   node = present_people.first;
2869   n = 0;
2870   while((node != NULL) && (n < 2))
2871     {
2872       s = adr_beginning(node->body);
2873       if(strcmp(s, p) == 0) n++;
2874       node = node->next;
2875     }
2876
2877   if(n >= 2)
2878     {
2879       s = pattern;
2880       concat(s, "*!*@");
2881       concat(s, p);
2882       *s++ = '\0';
2883       duration = DEFAULT_RESTRICTED_TIME + deban_delay;
2884       smart_shit(NULL, NULL, pattern, "Restricted site : no clones", duration);
2885       smart_ban(where, pattern);
2886       send_mode(where);
2887       filter_kick(where, pattern, "Restricted site : no clones");
2888       return 1;
2889     }
2890   else return 0;
2891 }
2892
2893 // This function is called after a JOIN
2894
2895 void IRC_JOIN(char *prefix, char *where)
2896 {
2897   char *nick;
2898   int k, l, restricted;
2899   NodeList<Welcome *> *node;
2900   char buffer[SMALL_BUFFER_SIZE];
2901
2902   nick = cut_nick_from_prefix(prefix);
2903
2904   if(strcmp(real_nick, nick) == 0)
2905     {
2906       strncpy(current_channel, where, SMALL_BUFFER_SIZE);
2907       sprintf(IRC_buffer, "WHO %s\n", where);
2908       write_irc(IRC_buffer);
2909       present_people.Clear();
2910       global_state = STATE_GETING_WHO;
2911       in_channel = 1;
2912     }
2913   else
2914     {
2915       add_flood_line(prefix, FL_JOIN, 1);
2916       
2917       uncap(where);
2918       present_people.Add(prefix);
2919       
2920       l =  level_person(prefix, NULL);
2921
2922       if((l < LEVEL_FRIEND) && (restricted_list.Matches(prefix)))
2923         restricted = check_restricted(where, prefix);
2924       else restricted = 0;
2925       
2926       if(!restricted)
2927         {
2928 #ifdef ANTI_SPOOF
2929           if(l >= LEVEL_FRIEND)
2930             {
2931               for(k=0; k<10; k++) buffer[k] = 'a'+int(rand()%26);
2932               buffer[10] = '\0';
2933               wait_ping.Insert(new WaitPing(nick, buffer,
2934                                             current_time+ANTI_SPOOF_MAX_TIME));
2935               sprintf(IRC_buffer, "PRIVMSG %s :\001PING %s\001\n",
2936                       nick, buffer);
2937               write_irc(IRC_buffer);
2938             }
2939 #endif
2940
2941           if(l >= LEVEL_OP)
2942             {
2943 #ifndef ANTI_SPOOF
2944               if(l >= LEVEL_DEFENCE) add_mode(where, "+o", nick);
2945               else
2946                 mode_change_list.Insert(new DelayModeChange(where, "+o",
2947                                                             nick, op_delay));
2948 #endif
2949             }
2950           else
2951             {
2952               if(banid_list.Matches(prefix))
2953                 {
2954                   sprintf(IRC_buffer, "KICK %s %s :You are banned\n", where, nick);
2955                   write_irc(IRC_buffer);
2956                 }
2957               else
2958                 {
2959                   for(node = shit_list.first; node != NULL; node = node->next)
2960                     if(match_pattern(node->body->pattern, prefix))
2961                       {
2962                         smart_ban(where, node->body->pattern);
2963                         send_mode(current_channel);
2964                         
2965                         sprintf(IRC_buffer, "KICK %s %s :%s\n",
2966                                 where, nick, node->body->comment);
2967                         
2968                         write_irc(IRC_buffer);
2969                       }
2970                 }
2971             }
2972         }
2973     }
2974
2975   delete[] nick;
2976 }
2977
2978 //-----------------------------------------------------------------------------
2979
2980 void IRC_RPL_BANLIST(char *prefix, char *channel, char *banid)
2981 {
2982   banid_list.Add(banid);
2983 }
2984
2985 void IRC_ENDOFBANLIST(char *prefix)
2986 {
2987   banid_list.Reverse();
2988   global_state = STATE_WAIT;
2989 }
2990
2991 void IRC_RPL_ENDOFWHOIS(char *prefix, char *nick)
2992 {
2993   NodeList<WaitInfos *> *node, *pred, *next;
2994
2995   uncap(nick);
2996   node = wait_list.first;
2997   pred = NULL;
2998   while(node != NULL)
2999     {
3000       next = node->next;
3001       if(strcmp(nick, node->body->nick) == 0)
3002         {
3003           sprintf(IRC_buffer, "Can't find %s\n", nick);
3004           tell(node->body->chat, node->body->user, IRC_buffer);
3005
3006           if(pred == NULL) wait_list.first = next;
3007           else pred->next = next;
3008           delete node->body;
3009           delete node;
3010         }
3011       else pred = node;
3012       node = next;
3013     }
3014 }
3015
3016 void IRC_RPL_WHOISUSER(char *prefix,
3017                        char *nick, char *login, char *host, char *real_name)
3018 {
3019   char *c, *d, *banid;
3020   int l;
3021   char buffer[SMALL_BUFFER_SIZE];
3022   NodeList<WaitInfos *> *node, *next, *pred;
3023
3024   int no_pattern, one_login, all_machines;
3025
3026   uncap(nick);
3027   uncap(login);
3028   uncap(host);
3029
3030   pred = NULL;
3031   node = wait_list.first;
3032   while(node != NULL)
3033     {
3034       next = node->next;
3035
3036       if(strcmp(nick, node->body->nick) == 0)
3037         {
3038           c = buffer;
3039
3040           no_pattern =  (node->body->mode == MODE_UNSHIT_NICK) ||
3041             (node->body->mode == MODE_LEVEL) ||
3042             (node->body->mode == MODE_UNBAN_NICK) ||
3043             (node->body->mode == MODE_SHITLIST);;
3044
3045           one_login = (node->body->mode == MODE_SHIT_NICK) ||
3046             (node->body->mode == MODE_BAN_NICK);
3047
3048           all_machines = (node->body->mode == MODE_SHIT_NICK) ||
3049             (node->body->mode == MODE_BAN_NICK) ||
3050             (node->body->mode == MODE_BAN_SITE) ||
3051             (node->body->mode == MODE_FILTER_KICK) ||
3052             (node->body->mode == MODE_SHIT_SITE) ||
3053             (node->body->mode == MODE_MSG);
3054
3055           if(no_pattern)
3056             {
3057               concat(c, nick);
3058               *c++ = '!';
3059               concat(c, login);
3060               *c++ = '@';
3061               concat(c, host);
3062               *c++ = '\0';
3063             }
3064           else
3065             {
3066               if((*login == '~') || (*login == '+') ||
3067                  (*login == '-') || (*login=='^'))
3068                 login++;
3069
3070               concat(c, "*!*");
3071
3072               if(one_login)
3073                 {
3074                   
3075                   l = 0;
3076                   while((*login != '\0') && ((l<7) || *(login+1) == '\0'))
3077                     { *c++ = *login++; l++; }
3078                   if(*login != '\0') *c++ = '*';
3079                   
3080                 }
3081               *c++ = '@';
3082
3083               d = adr_beginning(host);
3084               if(host != d) if(*(c-1) != '*') *c++ = '*';
3085
3086               if(all_machines) concat_pattern_from_host(c, d);
3087               else
3088                 {
3089                   concat(c, d);
3090                   *c++ = '\0';
3091                 }
3092
3093             }
3094
3095           uncap(buffer);
3096           banid = clean_banid(buffer);
3097
3098           if(node->body->mode == MODE_MSG)
3099             msg_users(node->body->chat, node->body->user,
3100                       banid, node->body->comment);
3101
3102           else if(node->body->mode == MODE_FILTER_KICK)
3103             filter_kick(current_channel, banid, node->body->comment);
3104
3105           else if((node->body->mode == MODE_BAN_NICK) ||
3106                   (node->body->mode == MODE_BAN_SITE))
3107             smart_ban(current_channel, banid);
3108
3109           else if((node->body->mode == MODE_SHIT_NICK)
3110                   || (node->body->mode == MODE_SHIT_SITE)
3111                   || (node->body->mode == MODE_SHIT_HOST))
3112             {
3113               smart_shit(node->body->chat,
3114                          node->body->user, banid, node->body->comment,
3115                          node->body->duration);
3116
3117               if(prefix_from_nick(nick) != NULL)
3118                 {
3119                   smart_ban(current_channel, banid);
3120                   send_mode(current_channel);
3121                   sprintf(IRC_buffer, "KICK %s %s :%s\n",
3122                           current_channel, nick, node->body->comment);
3123                   write_irc(IRC_buffer);
3124                 }
3125
3126             }
3127
3128           else if(node->body->mode == MODE_SHITLIST)
3129             notice_shit_list(NULL, node->body->user, banid, 0);
3130
3131           else if(node->body->mode == MODE_LEVEL)
3132             {
3133               sprintf(IRC_buffer, "%s is level %d\n",
3134                       banid, level_person(banid, NULL));
3135               tell(node->body->chat, node->body->user, IRC_buffer);
3136             }
3137           else if(node->body->mode == MODE_UNSHIT_NICK)
3138             {
3139               NodeList<Welcome *> *node2, *pred, *next;
3140               
3141               node2 = shit_list.first;
3142               pred = NULL;
3143               while(node2 != NULL)
3144                 {
3145                   next = node2->next;
3146                   if(match_pattern(node2->body->pattern, banid))
3147                     {
3148                       if(pred == NULL) shit_list.first = next;
3149                       else pred->next = next;
3150                       
3151                       sprintf(IRC_buffer, "Unshit %s (%s)\n",
3152                               node2->body->pattern, node2->body->comment);
3153                       
3154                       tell(node->body->chat, node->body->user, IRC_buffer);
3155                       
3156                       smart_unban(current_channel, node2->body->pattern);
3157                       
3158                       delete node2->body;
3159                       delete node2;
3160                     }
3161                   else pred = node2;
3162                   node2 = next;
3163                 }
3164             }
3165           else if(node->body->mode == MODE_UNBAN_NICK)
3166             {
3167               NodeList<char *> *node2;
3168               for(node2 = banid_list.first; node2 != NULL; node2 = node2->next)
3169                 if(match_pattern(node2->body, banid))
3170                   add_mode(current_channel, "-b", node2->body);
3171             }
3172           
3173
3174           delete[] banid;
3175
3176           if(pred == NULL) wait_list.first = next;
3177           else pred->next = next;
3178           delete node->body;
3179           delete node;
3180         }
3181       else pred = node;
3182       node = next;
3183     }
3184 }
3185
3186 // This function is called after a RPL_WHOREPLY
3187
3188 void IRC_RPL_WHOREPLY(char *prefix,
3189                       char *where,
3190                       char *login, char *host, char *server,
3191                       char *nick, char *state)
3192 {
3193   char *s, *t;
3194
3195   uncap(where);
3196   uncap(nick);
3197
3198   if((global_state == STATE_GETING_WHO) && 
3199      (strcmp(where, current_channel) == 0))
3200     {
3201       s = IRC_buffer;
3202       t = nick; while(*t != '\0') *s++ = *t++;
3203       *s++ = '!';
3204       t = login; while(*t != '\0') *s++ = *t++;
3205       *s++ = '@';
3206       t = host; while(*t != '\0') *s++ = *t++;
3207       *s++ = '\0';
3208       present_people.Add(IRC_buffer);
3209     }
3210 #ifdef ERROR_OUTPUT
3211   else cerr<<where<<"!="<<current_channel<<"\n";
3212 #endif
3213 }
3214
3215 void IRC_RPL_ENDOFWHO(char *prefix, char *name)
3216 {
3217   sprintf(IRC_buffer, "MODE %s +b\n", current_channel);
3218   write_irc(IRC_buffer);
3219   banid_list.Clear();
3220   if(in_channel) global_state = STATE_GETING_BAN;
3221   else global_state = STATE_WAIT;
3222 }
3223
3224 //-----------------------------------------------------------------------------
3225
3226 void IRC_ERR_NICKNAMEINUSE(char *prefix, char *channel)
3227 {
3228   rand_nick(wanted_nick, jam_nick);
3229 #ifdef SCREEN_OUTPUT
3230   cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
3231 #endif
3232   sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
3233   write_irc(IRC_buffer);
3234   was_killed = 1;                   // We have been killed (I said PARANOID !)
3235   time_killed = current_time;       // Note when it happens
3236 }
3237
3238 //-----------------------------------------------------------------------------
3239
3240 // This function is called after a ERR_NOSUCHCHANNEL
3241
3242 void IRC_ERR_NOSUCHCHANNEL(char *prefix, char *nick)
3243 {
3244   strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
3245   uncap(wanted_channel);
3246 }
3247
3248 //-----------------------------------------------------------------------------
3249
3250 // This function is called after a ERR_NICKCOLLISION (436)
3251
3252 void IRC_ERR_NICKCOLLISION(char *prefix, char *nick)
3253 {
3254   rand_nick(wanted_nick, jam_nick);
3255 #ifdef SCREEN_OUTPUT
3256   cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
3257 #endif
3258   sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
3259   write_irc(IRC_buffer);
3260   was_killed = 1;                   // We have been killed (I said PARANOID !)
3261   time_killed = current_time;       // Note when it happens
3262 }
3263
3264 //-----------------------------------------------------------------------------
3265
3266 // This is the main command. It is called for each line from the server.
3267
3268 void get_command(char *prefix,
3269                  char **slice_cmd, int n_cmd,
3270                  char **slice_ctcp, int n_ctcp)
3271 {
3272   char small_buffer[SMALL_BUFFER_SIZE];
3273   char *cmd;
3274
3275   cmd = slice_cmd[0];
3276
3277 #ifdef SCREEN_OUTPUT
3278
3279   cout<<"from "<<prefix<<" ";
3280   int k;
3281   for(k=0; k<n_cmd; k++) cout<<"["<<slice_cmd[k]<<"]";
3282   if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<slice_ctcp[k]<<">";
3283   cout<<"\n";
3284   for(k=0; k<n_cmd; k++) cout<<"["<<(void *) slice_cmd[k]<<"]";
3285   if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<(void *) slice_ctcp[k]<<">";
3286   cout<<"\n";
3287 #endif
3288
3289   if(prefix != NULL) uncap(prefix);
3290
3291   // No prefix : server command
3292   if(prefix == NULL)
3293     {
3294       if(n_cmd > 0) if(eq("PING", cmd))
3295         {
3296           if(n_cmd >= 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]);
3297           else sprintf(IRC_buffer, "PONG\n");
3298           write_irc(IRC_buffer);
3299         }
3300     }
3301   else
3302     {
3303       // If we are not registred yet, then get the registration
3304       if(eq("002", cmd))
3305         {
3306           if(!IRC_registred)
3307             {
3308               strncpy(real_nick, slice_cmd[1], SMALL_BUFFER_SIZE);
3309               uncap(real_nick);
3310               IRC_registred = 1;
3311               sprintf(small_buffer, "MODE %s +i\n", real_nick);
3312               write_irc(small_buffer);
3313               sprintf(small_buffer, "JOIN %s\n", wanted_channel);
3314               write_irc(small_buffer);
3315             }
3316         }
3317       else if(eq("PRIVMSG", cmd))
3318         IRC_PRIVMSG(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
3319       else if(eq("NOTICE", cmd))
3320         IRC_NOTICE(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
3321       else if(eq("MODE", cmd))
3322         IRC_MODE(slice_cmd[1], prefix, slice_cmd[2], slice_cmd+3);
3323       else if(eq("JOIN", cmd)) IRC_JOIN(prefix, slice_cmd[1]);
3324       else if(eq("KICK", cmd)) IRC_KICK(prefix, slice_cmd[1], slice_cmd[2]);
3325       else if(eq("QUIT", cmd)) IRC_QUIT(prefix);
3326       else if(eq("NICK", cmd)) IRC_NICK(prefix, slice_cmd[1]);
3327       else if(eq("PART", cmd)) IRC_PART(prefix, slice_cmd[1]);
3328       else if(eq("311", cmd))
3329         IRC_RPL_WHOISUSER(prefix,
3330                           slice_cmd[2], slice_cmd[3], slice_cmd[4],
3331                           slice_cmd[6]);
3332       else if(eq("318", cmd)) IRC_RPL_ENDOFWHOIS(prefix, slice_cmd[2]);
3333       else if(eq("352", cmd))
3334         IRC_RPL_WHOREPLY(prefix,
3335                          slice_cmd[2], slice_cmd[3], slice_cmd[4],
3336                          slice_cmd[5], slice_cmd[6], slice_cmd[7]);
3337       else if(eq("315", cmd)) IRC_RPL_ENDOFWHO(prefix, slice_cmd[1]);
3338       else if(eq("367", cmd))
3339         IRC_RPL_BANLIST(prefix, slice_cmd[2], slice_cmd[3]);
3340       else if(eq("368", cmd)) IRC_ENDOFBANLIST(prefix);
3341       else if(eq("403", cmd)) IRC_ERR_NOSUCHCHANNEL(prefix, slice_cmd[1]);
3342       else if(eq("433", cmd)) IRC_ERR_NICKNAMEINUSE(prefix, slice_cmd[1]);
3343       else if(eq("436", cmd)) IRC_ERR_NICKCOLLISION(prefix, slice_cmd[1]);
3344     }
3345 }
3346
3347 //-----------------------------------------------------------------------------
3348
3349 // Rough routine to read the options
3350
3351 void get_options(int argc, char **argv)
3352 {
3353   int n, help, d;
3354   n = 1;
3355   help = 0;
3356
3357   while(n<argc)
3358     {
3359       if(eq("-p", argv[n]))
3360         {
3361           n++;
3362           if(n<argc) default_port = atoi(argv[n]);
3363 #ifdef ERROR_OUTPUT
3364           else cerr<<"*** No port parameter ***\n";
3365 #endif
3366         }
3367       else if(eq("-h", argv[n]))
3368         {
3369           n++;
3370           if(n<argc) strncpy(default_server, argv[n], MAXHOSTNAME);
3371 #ifdef ERROR_OUTPUT
3372           else cerr<<"*** No hostname parameter ***\n";
3373 #endif
3374         }
3375       else if(eq("-o", argv[n]))
3376         {
3377           n++;
3378           if(n<argc)
3379             {
3380               strncpy(config_file, argv[n], SMALL_BUFFER_SIZE);
3381               LoadConfigFile(argv[n], 0);
3382             }
3383 #ifdef ERROR_OUTPUT
3384           else cerr<<"*** No friends list parameter ***\n";
3385 #endif
3386         }
3387       else if(eq("-c", argv[n]))
3388         {
3389           n++;
3390           if(n<argc) strncpy(home_channel, argv[n], SMALL_BUFFER_SIZE);
3391 #ifdef ERROR_OUTPUT
3392           else cerr<<"*** No channel parameter ***\n";
3393 #endif
3394         }
3395       else if(eq("-l", argv[n]))
3396         {
3397           n++;
3398           if(n<argc) strncpy(user_login, argv[n], SMALL_BUFFER_SIZE);
3399 #ifdef ERROR_OUTPUT
3400           else cerr<<"*** No username parameter ***\n";
3401 #endif
3402         }
3403       else if(eq("-n", argv[n]))
3404         {
3405           n++;
3406           if(n<argc) strncpy(original_nick, argv[n], SMALL_BUFFER_SIZE);
3407 #ifdef ERROR_OUTPUT
3408           else cerr<<"*** No nickname parameter ***\n";
3409 #endif
3410         }
3411       else if(eq("-j", argv[n]))
3412         {
3413           n++;
3414           if(n<argc) strncpy(jam_nick, argv[n], SMALL_BUFFER_SIZE);
3415 #ifdef ERROR_OUTPUT
3416           else cerr<<"*** No jam nickname parameter ***\n";
3417 #endif
3418         }
3419       else if(eq("-cop", argv[n]))
3420         {
3421           cop_mode = 1;
3422         }
3423       else if(eq("-d", argv[n]))
3424         {
3425           n++;
3426           if(n<argc)
3427             {
3428               d = atoi(argv[n]);
3429               if(d>=1) socket_delay = d;
3430 #ifdef ERROR_OUTPUT
3431               else cerr<<"*** Delay error ***\n";
3432 #endif
3433             }
3434 #ifdef&nb