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