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