1 /*-----------------------------------------------------------------------------
2 TropBot, a small IRC bot, v2.6 Dec 95 - Oct 96
3 Witten by Francois Fleuret.
4 Contact <francois.fleuret@inria.fr> for comments & bug reports
5 Check http://www.eleves.ens.fr:8080/home/fleuret for latest version
6 -----------------------------------------------------------------------------*/
8 #define VERSION "v2.6.3a"
9 #define OPTIONS " + patch for mode -ko stuff"
14 #include <sys/types.h>
21 //-----------------------------------------------------------------------------
25 //-----------------------------------------------------------------------------
27 #define MODE_NUMBER_MAX 3
28 #define SIZE_BANLIST_MAX 20
29 #define NB_CHAR_MAX 400
31 //-----------------------------------------------------------------------------
33 #define DEFAULT_CONTROL_CHAR '|'
34 #define DELAY_NICK_BACK 300
35 #define DELAY_MAX_RECONNECT 300
36 #define DELAY_DEAD_SERVER 900
38 #define DEFAULT_SERVER "sil.polytechnique.fr"
39 #define DEFAULT_PORT 6667
41 #define DEFAULT_USER_NAME "\002TropBot\002 " VERSION OPTIONS
42 #define DEFAULT_LOGIN "tropbot"
43 #define DEFAULT_NICK "TropBot"
44 #define DEFAULT_JAM_NICK "TB-????"
45 #define DEFAULT_HOME_CHANNEL "#tropbot"
46 #define DEFAULT_SOCKET_DELAY 30
47 #define DEFAULT_OP_DELAY 2
48 #define DEFAULT_DEBAN_DELAY 0
50 #define DEFAULT_ANTI_FLOOD_OFF_DURATION 600
52 #define DEFAULT_CONFIG_FILE ".tropbotrc"
54 #define DEFAULT_SHIT_TIME 600
55 #define DEFAULT_RESTRICTED_TIME 900
57 #define DEFAULT_MODE_PROTECT 0
59 // Not needed coz flooding people can't re-JOIN quickly
60 //#define BAN_ON_FLOOD
61 #define BAN_FLOOD_DELAY 30
63 #define MAX_LINE_FLOOD 4
64 #define MAX_CTCP_FLOOD 3
66 #define DELAY_ANSWERS 3
67 #define ANTI_CLONES_DELAY 30
71 #define HISTORY_SIZE 3
73 enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN };
75 //-----------------------------------------------------------------------------
77 #define MAX_DCC_CHAT 16
79 //-----------------------------------------------------------------------------
81 extern "C" void bzero(void *, int);
82 extern "C" int select(int, fd_set *, fd_set *, fd_set *, timeval *);
83 extern "C" pid_t fork(void);
85 //-----------------------------------------------------------------------------
87 int default_port = DEFAULT_PORT;
89 char default_server[MAXHOSTNAME+1] = DEFAULT_SERVER;
90 char wanted_server[MAXHOSTNAME+1];
93 int alive; // Should be set to false (0) to kill the bot
96 int socket_delay = DEFAULT_SOCKET_DELAY;
97 int op_delay = DEFAULT_OP_DELAY;
98 int deban_delay = DEFAULT_DEBAN_DELAY;
99 char control_char = DEFAULT_CONTROL_CHAR;
103 time_t current_time, time_killed, time_last_datas, last_answer_time,
104 anti_flood_off_until;
106 char buffer[BUFFER_SIZE];
108 int IRC_connected, IRC_registred;
109 int global_state, in_channel, was_killed, mode_protect_on;
112 #define STATE_GETING_WHO 1
113 #define STATE_GETING_BAN 2
115 //-----------------------------------------------------------------------------
117 template class List<DCCChat *>;
118 template class List<Person *>;
119 template class List<Welcome *>;
120 template class List<WaitInfos *>;
121 template class List<DelayModeChange *>;
122 template class List<char *>;
124 List<DCCChat *> dcc_chat_list;
125 List<Person *> level_list;
126 List<Welcome *> shit_list;
127 List<WaitInfos *> wait_list;
128 List<DelayModeChange *> mode_change_list;
130 ListChar present_people, banid_list, restricted_list, history;
132 //-----------------------------------------------------------------------------
134 // General buffer for all IRC operations
135 char IRC_buffer[BUFFER_SIZE];
137 // Nick we got after registration
138 char real_nick[SMALL_BUFFER_SIZE];
141 char wanted_nick[SMALL_BUFFER_SIZE];
143 char original_nick[SMALL_BUFFER_SIZE] = DEFAULT_NICK;
145 // Pattern used for random-nick generation if nick-collision occurs
146 // all the '?' will be replaced with random digits
147 char jam_nick[SMALL_BUFFER_SIZE] = DEFAULT_JAM_NICK;
149 // The "user" we want in the nick!user@host stuff
150 char user_login[SMALL_BUFFER_SIZE] = DEFAULT_LOGIN;
152 // The USERNAME string
153 char user_name[SMALL_BUFFER_SIZE] = DEFAULT_USER_NAME;
155 // The channel we want to join
156 char current_channel[SMALL_BUFFER_SIZE], wanted_channel[SMALL_BUFFER_SIZE];
157 char home_channel[SMALL_BUFFER_SIZE] = DEFAULT_HOME_CHANNEL;
159 // The name of the configuration file
160 char config_file[SMALL_BUFFER_SIZE] = DEFAULT_CONFIG_FILE;
162 //-----------------------------------------------------------------------------
164 char *prefix_from_nick(char *nick)
166 NodeList<char *> *node;
171 node = present_people.first;
172 while((node != NULL) && !yep)
177 while((*t != '\0') &&
178 (*s != '!') && (*s != '\0') && yep) yep &= (*s++ == *t++);
179 yep &= ((*t == '\0') && (*s == '!'));
180 if(!yep) node=node->next;
183 if(node != NULL) return node->body; else return NULL;
187 //-----------------------------------------------------------------------------
189 int level_person(char *prefix, char *passwd)
191 NodeList<Person *> *node;
195 for(node = level_list.first; node != NULL; node=node->next)
196 if(match_pattern(node->body->pattern, prefix))
197 if((node->body->level > l) || (l == 0))
199 if(node->body->passwd == NULL) l = node->body->level;
202 if(strcmp(node->body->passwd, passwd) == 0)
203 l = node->body->level;
208 void remove_level(char *prefix)
210 NodeList<Person *> *node, *pred, *next;
211 pred = NULL; next = NULL;
213 node = level_list.first;
217 if(strcmp(node->body->pattern, prefix) == 0)
219 if(pred == NULL) level_list.first = next;
220 else pred->next = next;
231 NodeList<Person *> *node, *next;
233 node = level_list.first;
241 level_list.first = NULL;
246 NodeList<Welcome *> *node, *next;
248 node = shit_list.first;
256 shit_list.first = NULL;
259 void remove_wait_for_chat(DCCChat *chat)
261 NodeList<WaitInfos *> *node, *pred, *next;
262 pred = NULL; next = NULL;
264 node = wait_list.first;
268 if(node->body->chat == chat)
270 if(pred == NULL) wait_list.first = next;
271 else pred->next = next;
280 //-----------------------------------------------------------------------------
282 // This function generates a random nick from a pattern. The pattern
283 // is supposed to contain some '?', which will be replaced with random
286 void rand_nick(char *nick, char *pattern)
289 for(n=0; n<strlen(pattern); n++)
291 if(pattern[n] == '?') nick[n] = '0'+int(rand()%10);
292 else nick[n] = pattern[n];
297 //-----------------------------------------------------------------------------
299 void kill_connection()
301 time_last_datas = current_time;
302 IRC_connected = 0; // We are not connected
303 IRC_registred = 0; // We are not registred
304 FD_CLR(socket_irc, &ready); // Forget the socket
305 close(socket_irc); // Close it
306 present_people.Clear(); // We don't see anyone
307 rand_nick(wanted_nick, jam_nick); // Random the nick (yeah, we are paranoid)
308 was_killed = 1; // We have been killed (I said PARANOID !)
309 time_killed = current_time; // Note when it happens
310 src = buffer; // Forget all the remaining datas
311 endsrc = buffer; // Idem.
312 delay = 0; // We won't wait for reconnection
313 in_channel = 0; // We are not in any channel
317 void clone(char *nick)
321 strcpy(wanted_nick, nick);
322 strcpy(original_nick, nick);
325 FD_CLR(socket_irc, &ready);
326 present_people.Clear();
327 time_killed = current_time;
336 void write_irc(char *stuff)
338 // I'd like to know why do I have to do such a cast ?!?!
339 if((int) write(socket_irc, stuff, strlen(stuff)) < 0)
341 cerr<<"KILLING CONNECTION : write_irc error\n";
348 cout<<"\n!!!!>"<<stuff<<"<\n\n";
350 last_answer_time = current_time;
354 //-----------------------------------------------------------------------------
358 char string_modes[MODE_NUMBER_MAX*2+1];
360 char string_param_modes[MODE_NUMBER_MAX*64+1];
361 char *ptr_param_modes;
367 ptr_modes = string_modes;
368 ptr_param_modes = string_param_modes;
373 void send_mode(char *where)
378 *ptr_param_modes = '\0';
379 sprintf(IRC_buffer, "MODE %s %s %s\n",
380 where, string_modes, string_param_modes);
381 write_irc(IRC_buffer);
386 void add_mode(char *where, char *mode, char *param)
390 // Disgusting hack coz of a FUCKING server bug :-(
393 if(k_mode) send_mode(where);
399 if(o_mode) send_mode(where);
404 while(*s != '\0') *ptr_modes++ = *s++;
408 while(*s != '\0') *ptr_param_modes++ = *s++;
409 *ptr_param_modes++ = ' ';
412 if(++nb_modes == MODE_NUMBER_MAX) send_mode(where);
415 //-----------------------------------------------------------------------------
417 void tell(DCCChat *chat, char *nick, char *msg)
419 char tell_buffer[BUFFER_SIZE];
422 cout<<"tell(chat="<<chat<<", nick="<<nick<<" msg="<<msg<<")\n";
423 if(msg[strlen(msg)-1] != '\n')
424 cout<<"**************************************\n";
427 if(chat != NULL) write(chat->socket, msg, strlen(msg));
431 sprintf(tell_buffer, "NOTICE %s :%s", nick, msg);
432 write_irc(tell_buffer);
436 //-----------------------------------------------------------------------------
438 void smart_shit(DCCChat *chat, char *nick,
439 char *pattern, char *comment, int duration)
441 NodeList<Welcome *> *node, *next, *pred;
445 if(duration < 5) duration = 5;
447 time_max = duration + current_time;
450 node = shit_list.first;
452 while((node != NULL) && !no_shit)
455 if(strcmp(node->body->pattern, pattern) == 0)
457 if(node->body->time_max <= time_max)
459 if(pred == NULL) shit_list.first = next;
460 else pred->next = next;
476 shit_list.Insert(new Welcome(pattern, comment, time_max));
477 if((nick != NULL) || (chat != NULL))
479 char *string_duration;
480 string_duration = seconds_to_string(duration);
481 sprintf(IRC_buffer, "Shit %s for %s (%s)\n",
482 pattern, string_duration, comment);
483 tell(chat, nick, IRC_buffer);
484 delete string_duration;
487 else if((nick != NULL) || (chat != NULL))
490 "Can't shit %s, already shitted for a longer time\n", pattern);
491 tell(chat, nick, IRC_buffer);
495 //-----------------------------------------------------------------------------
497 void smart_ban(char *where, char *pattern)
499 NodeList<char *> *node;
502 for(node = banid_list.first; node != NULL; node = node->next)
504 if((n>=SIZE_BANLIST_MAX-1) ||
505 (match_pattern(pattern, node->body) &&
506 (strcmp(pattern, node->body) != 0)))
507 add_mode(where, "-b", node->body);
510 add_mode(current_channel, "+b", pattern);
513 void smart_unban(char *where, char *pattern)
515 if(banid_list.Contains(pattern)) add_mode(where, "-b", pattern);
518 //-----------------------------------------------------------------------------
520 void check_delay_mode_change()
522 NodeList<DelayModeChange *> *node, *pred, *next;
525 node = mode_change_list.first;
529 if(current_time >= node->body->time)
531 add_mode(node->body->where, node->body->mode, node->body->parameter);
532 if(pred == NULL) mode_change_list.first = next;
533 else pred->next = next;
542 void clean_delay_mode_change(char *where, char *mode, char *param)
544 NodeList<DelayModeChange *> *node, *pred, *next;
549 node = mode_change_list.first;
556 if((node->body->parameter != NULL) &&
557 (strcmp(where, node->body->where) == 0) &&
558 (strcmp(param, node->body->parameter) == 0) &&
559 (strcmp(mode, node->body->mode) == 0))
561 if(pred == NULL) mode_change_list.first = next;
562 else pred->next = next;
575 if((strcmp(where, node->body->where) == 0) &&
576 (node->body->parameter == NULL) &&
577 (strcmp(mode, node->body->mode) == 0))
579 if(pred == NULL) mode_change_list.first = next;
580 else pred->next = next;
590 void RemoveDelayModeChange(char *mode, char *parameter)
592 NodeList<DelayModeChange *> *node, *pred, *next;
595 node = mode_change_list.first;
599 if((strcmp(node->body->mode, mode) == 0) &&
600 (strcmp(node->body->parameter, parameter) == 0))
602 if(pred == NULL) mode_change_list.first = next;
603 else pred->next = next;
612 //-----------------------------------------------------------------------------
614 void synch(char *channel)
617 NodeList<char *> *node;
619 for(node = present_people.first; node != NULL; node = node->next)
620 if(level_person(node->body, NULL) >= LEVEL_OP)
622 nick = cut_nick_from_prefix(node->body);
623 add_mode(channel, "+o", nick);
628 //-----------------------------------------------------------------------------
630 void filter_kick(char *where, char *pattern, char *comment)
632 NodeList<char *> *node;
634 for(node = present_people.first; node != NULL; node = node->next)
636 if(match_pattern(pattern, node->body))
637 if(level_person(node->body, NULL) == 0)
639 nick = cut_nick_from_prefix(node->body);
640 sprintf(IRC_buffer, "KICK %s %s :%s\n", where, nick, comment);
641 write_irc(IRC_buffer);
647 //-----------------------------------------------------------------------------
649 // Return a pointer on the first character after the last '@' in the string
650 // Beware of some weird hack-script that add @ in the login
651 char *adr_beginning(char *s)
655 while(*s != '\0') if(*s++ == '@') t = s;
660 char *reach_loginathost(char *s)
662 while((*s != '!') && (*s != '\0')) s++;
667 //-----------------------------------------------------------------------------
676 int individual, site, alreadykicked;
678 FloodLine(char *p, int k, int w)
687 ~FloodLine() { delete prefix; }
688 void Reset() { individual = 0; site = 0; }
691 template class List<FloodLine *>;
693 List<FloodLine *> flood_list;
695 //-----------------------------------------------------------------------------
697 void alert(char *where, DCCChat *chat, char *nick)
699 int nb_lines, max_nb_lines, duration;
700 NodeList<FloodLine *> *node, *son;
701 char *site, *site2, *guilty_site, *r;
702 char pattern[SMALL_BUFFER_SIZE];
704 for(node = flood_list.first; node != NULL; node = node->next)
705 node->body->individual = 0;
707 node = flood_list.first;
714 while((node != NULL) && node->body->individual) node = node->next;
718 site = adr_beginning(node->body->prefix);
723 while((son != NULL) && son->body->individual) son = son->next;
726 site2 = adr_beginning(son->body->prefix);
728 if(are_same_site(site, site2))
730 son->body->individual = 1;
737 if(nb_lines > max_nb_lines)
738 if(level_person(node->body->prefix, NULL) == 0)
740 max_nb_lines = nb_lines;
747 if(guilty_site != NULL)
749 duration = DEFAULT_SHIT_TIME;
751 *r++ = '*'; *r++ = '!'; *r++ = '*'; *r++ = '@';
752 concat_pattern_from_host(r, guilty_site);
753 add_mode(where, "+m", NULL);
754 smart_shit(NULL, NULL, pattern, "Alert", duration);
755 smart_ban(where, pattern);
757 filter_kick(where, pattern, "Filter kick on alert");
758 add_mode(where, "-m", NULL);
761 else tell(chat, nick, "\002No flooding site detected\002\n");
764 void check_one_flood(NodeList<FloodLine *> *node)
766 NodeList<FloodLine *> *son;
767 char *userhost, *userhost2, *nick;
770 userhost = reach_loginathost(node->body->prefix);
776 while((son != NULL) && son->body->individual) son = son->next;
779 if(!son->body->alreadykicked)
781 userhost2 = reach_loginathost(son->body->prefix);
783 if(strcmp(userhost, userhost2) == 0)
785 son->body->individual = 1;
793 if(nb_lines >= MAX_LINE_FLOOD)
797 char *pattern, *banid;
798 if((level_person(node->body->prefix, NULL) < LEVEL_OP))
800 pattern = pattern(node->body->prefix, 0);
801 banid = clean_banid(pattern);
802 smart_ban(current_channel, banid);
803 send_mode(current_channel);
804 mode_change_list.Insert(new DelayModeChange(current_channel,
812 nick = cut_nick_from_prefix(node->body->prefix);
813 sprintf(IRC_buffer, "KICK %s %s :%s\n", current_channel, nick, "Flood");
814 write_irc(IRC_buffer);
817 for(son = flood_list.first; son != NULL; son = son->next)
819 userhost2 = reach_loginathost(son->body->prefix);
820 if(strcmp(userhost, userhost2) == 0) son->body->alreadykicked = 1;
828 int nb_lines, nb_ctcp;
829 NodeList<FloodLine *> *node, *next, *pred;
831 nb_lines = 0; nb_ctcp = 0;
833 node = flood_list.first;
837 if(node->body->time >= current_time - FLOOD_DELAY)
839 nb_lines += node->body->weigth;
840 if((node->body->kind == FL_CTCP) && !node->body->alreadykicked)
841 nb_ctcp += node->body->weigth;
847 if(pred == NULL) flood_list.first = next;
848 else pred->next = next;
856 if(nb_ctcp >= MAX_CTCP_FLOOD)
858 add_mode(current_channel, "+m", NULL);
859 send_mode(current_channel);
860 mode_change_list.Insert(new DelayModeChange(current_channel,
866 if(nb_lines >= MAX_LINE_FLOOD)
868 for(node = flood_list.first; node != NULL; node = node->next)
869 node->body->individual = 0;
871 node = flood_list.first;
874 while((node != NULL) && node->body->individual) node = node->next;
877 if(!node->body->alreadykicked) check_one_flood(node);
884 inline void add_flood_line(char *prefix, int kind, int weigth)
886 flood_list.Insert(new FloodLine(prefix, kind, weigth));
889 //-----------------------------------------------------------------------------
891 // This function is called for all mode changes
892 // signe indicates if it's a + or - mode change
893 // param is NULL for mode change without parameters
895 void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
900 if(signe < 0) buffer[0] = '-'; else buffer[0] = '+';
903 if(param != NULL) uncap(param);
905 clean_delay_mode_change(where, buffer, param);
908 cout<<"ONE MODE CHANGE CHANNEL ("<<where<<")";
909 cout<<" BY ("<<who<<") MODE "<<signe<<" "<<mode;
910 cout<<" ON "<<param<<"\n";
915 // Basic anti-hack procedure. All +o and +b mode done by servers are
916 // canceled (we have to look if the person is a friend or not)
924 if(signe>0) add_mode(where, "-b", param);
925 else add_mode(where, "+b", param);
930 mode_change_list.Insert(new DelayModeChange(where, "-b", param,
933 mode_change_list.Insert(new DelayModeChange(where, "+b", param,
940 banid_list.Add(param);
941 banid = clean_banid(param);
942 if(strcmp(banid, param) != 0) smart_ban(where, banid);
945 else banid_list.Remove(param);
951 c = prefix_from_nick(param);
952 if((signe > 0) && (level_person(c, NULL) < LEVEL_FRIEND))
953 add_mode(where, "-o", param);
954 if((signe < 0) && (level_person(c, NULL) >= LEVEL_FRIEND))
955 add_mode(where, "+o", param);
959 (level_person(who, NULL) <
960 level_person(prefix_from_nick(param), NULL)) &&
961 (level_person(prefix_from_nick(param), NULL) > 0))
963 c = cut_nick_from_prefix(who);
964 add_mode(where, "-o", c);
965 add_mode(where, "+o", param);
971 if(signe>0) if(is_hostname(who) || mode_protect_on)
972 add_mode(where, "-i", NULL);
976 if(signe>0) if(is_hostname(who) || mode_protect_on)
977 add_mode(where, "-l", NULL);
981 if(signe>0) if(is_hostname(who) || mode_protect_on)
982 add_mode(where, "-p", NULL);
986 if(signe>0) if(is_hostname(who) || mode_protect_on)
987 add_mode(where, "-k", param);
993 if(signe>0) add_mode(where, "-m", NULL);
995 else if(mode_protect_on)
997 if(level_person(who, NULL) < LEVEL_OP)
999 if(signe>0) add_mode(where, "-m", NULL);
1000 else add_mode(where, "+m", NULL);
1001 c = cut_nick_from_prefix(who);
1002 add_mode(where, "-o", c);
1009 if(signe>0) if(is_hostname(who) || mode_protect_on)
1010 add_mode(where, "-s", NULL);
1018 //-----------------------------------------------------------------------------
1020 // This function is called after a "MODE" command
1021 // You should not modify it, unless you find a bug.
1022 // Modify only IRC_ONE_MODE()
1024 void IRC_MODE(char *where, char *who, char *mode, char **params)
1026 int param_no, signe;
1030 while(*mode != '\0')
1041 if((*mode == 'l') || (*mode == 'v') ||
1042 (*mode == 'k') || (*mode == 'o') ||
1044 IRC_ONE_MODE(where, who, signe, *mode, params[param_no++]);
1046 IRC_ONE_MODE(where, who, signe, *mode, NULL);
1054 //-----------------------------------------------------------------------------
1056 void get_one_line(ifstream *s, char *buffer, int buffer_size)
1067 if(d != '\n') *c++ = d;
1071 ok &= (c<buffer + buffer_size);
1076 int LoadConfigFile(char *name)
1079 int duration, level, error;
1081 char pattern[SMALL_BUFFER_SIZE], buffer[SMALL_BUFFER_SIZE];
1083 file = new ifstream(name);
1088 restricted_list.Clear();
1091 get_one_line(file, IRC_buffer, BUFFER_SIZE);
1092 if(strlen(IRC_buffer) > 0)
1095 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1096 if(strcmp(buffer, "FRIEND") == 0)
1100 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1101 level = atoi(buffer);
1104 r = next_word(pattern, r, SMALL_BUFFER_SIZE);
1106 level_list.Insert(new Person(pattern, level, r));
1110 else if(strcmp(buffer, "RESTRICTED") == 0)
1114 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1115 cout<<"RESTRICTED->"<<buffer<<"\n";
1116 restricted_list.Insert(strdup(buffer));
1119 else if(strcmp(buffer, "SHIT") == 0)
1123 r = next_word(pattern, r, SMALL_BUFFER_SIZE);
1127 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1128 duration = atoi(buffer);
1129 if(r == NULL) r = "Shit";
1130 banid = clean_banid(pattern);
1131 smart_shit(NULL, NULL, banid, r, duration);
1136 else if(strcmp(buffer, "OPDELAY") == 0)
1140 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1141 op_delay = atoi(buffer);
1144 else if(strcmp(buffer, "DEBANDELAY") == 0)
1148 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1149 deban_delay = atoi(buffer);
1152 else if(strcmp(buffer, "CONTROLCHAR") == 0)
1156 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1157 if(buffer[0] != '\0') control_char = buffer[0];
1162 shit_list.Reverse();
1163 level_list.Reverse();
1164 restricted_list.Reverse();
1174 int SaveConfigFile(char *name)
1177 NodeList<Welcome *> *welcome;
1178 NodeList<Person *> *person;
1179 NodeList<char *> *restricted;
1182 file = new ofstream(name);
1185 (*file)<<"% Config file for a TropBot " VERSION "\n";
1188 (*file)<<"OPDELAY "<<op_delay<<"\n";
1189 (*file)<<"DEBANDELAY "<<deban_delay<<"\n";
1190 (*file)<<"CONTROLCHAR "<<control_char<<"\n";
1194 for(person=level_list.first; person != NULL; person=person->next)
1196 (*file)<<"FRIEND "<<person->body->level<<" "<<person->body->pattern;
1197 if(person->body->passwd != NULL) (*file)<<" "<<person->body->passwd;
1203 for(restricted=restricted_list.first;
1205 restricted=restricted->next)
1206 (*file)<<"RESTRICTED "<<restricted->body<<"\n";
1210 for(welcome=shit_list.first; welcome != NULL; welcome=welcome->next)
1211 (*file)<<"SHIT "<<welcome->body->pattern<<" "<<
1212 welcome->body->time_max - current_time<<" "<<
1213 welcome->body->comment<<"\n";
1224 //-----------------------------------------------------------------------------
1226 void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
1228 NodeList<char *> *node1, *node2;
1229 int *ok, nb, k, l, level, put_blank;
1231 int nb_total, nb_person[LEVEL_MAX+1];
1234 for(k=0; k<LEVEL_MAX+1; k++) nb_person[k] = 0;
1236 nb = present_people.Lenght();
1238 for(k = 0; k<nb; k++) ok[k] = 0;
1240 node1 = present_people.first;
1244 cerr<<"PATTERN=>"<<pattern<<"<\n";
1248 concat(buf, "\002");
1249 concat(buf, pattern);
1250 concat(buf, "\002 and same site : ");
1253 while(node1 != NULL)
1255 cout<<" =>"<<node1->body<<"\n";
1257 if((pattern == NULL) || match_pattern(pattern, node1->body))
1259 c = adr_beginning(node1->body);
1263 while(node2 != NULL)
1265 d = adr_beginning(node2->body);
1266 if(are_same_site(c, d))
1269 level = level_person(d, NULL);
1272 if(put_blank) *buf++ = '/'; else put_blank = 1;
1274 if(level == LEVEL_OP) *buf++ = '\002';
1275 else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
1277 while((*d != '!') && (*d != '\0')) *buf++ = *d++;
1279 if(level == LEVEL_OP) *buf++ = '\002';
1280 else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
1284 if(buf > IRC_buffer + NB_CHAR_MAX)
1286 *buf++ = '\n'; *buf++ = '\0';
1287 tell(chat, nick, IRC_buffer);
1295 node2 = node2->next;
1297 while((node2 != NULL) && (ok[l] == 1));
1306 node1 = node1->next;
1308 while((node1 != NULL) && (ok[k] == 1));
1311 *buf++ = '\n'; *buf++ = '\0';
1312 tell(chat, nick, IRC_buffer);
1314 sprintf(IRC_buffer, "Total %d (\002%d\002)\n",
1316 nb_person[LEVEL_OP] + nb_person[LEVEL_DEFENCE] +
1317 nb_person[LEVEL_MASTER]);
1318 tell(chat, nick, IRC_buffer);
1323 //-----------------------------------------------------------------------------
1325 void notice_shit_list(DCCChat *chat, char *nick, char *pattern, int matched)
1328 char *string_duration;
1329 NodeList<Welcome *> *node;
1331 if(shit_list.Lenght() == 0) tell(chat, nick, "\002Empty shit-list\002\n");
1335 for(node = shit_list.first; node != NULL; node=node->next)
1336 if((matched && match_pattern(pattern, node->body->pattern))
1337 || (!matched && match_pattern(node->body->pattern, pattern)))
1340 string_duration = seconds_to_string(node->body->time_max
1343 sprintf(IRC_buffer, "%s for %s (%s)\n",
1344 node->body->pattern,
1346 node->body->comment);
1347 tell(chat, nick, IRC_buffer);
1348 delete string_duration;
1351 if(n == 0) tell(chat, nick, "\002No corresponding shits\002\n");
1355 //-----------------------------------------------------------------------------
1357 void add_in_history(char *prefix, char *action)
1359 NodeList<char *> *node, *pred, *next;
1363 s = new char[strlen(prefix) + strlen(action) + 4];
1372 pred = NULL; next = NULL; node = history.first;
1379 if(pred == NULL) history.first = next;
1380 else pred->next = next;
1389 void notice_history(DCCChat *chat, char *nick)
1391 NodeList<char *> *node;
1393 for(node = history.first; node != NULL; node = node->next)
1395 sprintf(IRC_buffer, "%s\n", node->body);
1396 tell(chat, nick, IRC_buffer);
1400 //-----------------------------------------------------------------------------
1402 int dont_flood_server()
1404 return current_time >= last_answer_time + DELAY_ANSWERS;
1407 void msg_users(DCCChat *chat, char *nick, char *pattern, char *msg)
1409 NodeList<char *> *node;
1413 sprintf(IRC_buffer, "\002[msg to %s]\002 %s\n", pattern, msg);
1414 tell(chat, nick, IRC_buffer);
1417 for(node = present_people.first; node != NULL; node = node->next)
1419 if(match_pattern(pattern, node->body))
1422 nick_user = cut_nick_from_prefix(node->body);
1423 sprintf(IRC_buffer, "PRIVMSG %s :\002[msg to %s]\002 %s\n",
1424 nick_user, pattern, msg);
1425 write_irc(IRC_buffer);
1430 sprintf(IRC_buffer, "\002[msg sent to %d user(s)]\002\n", nb);
1431 tell(chat, nick, IRC_buffer);
1434 //-----------------------------------------------------------------------------
1436 #define CMD_DEFAULT 0
1442 void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
1444 char buffer[SMALL_BUFFER_SIZE], buffer_time[SMALL_BUFFER_SIZE];
1445 char *r, *s, *c, *banid;
1446 char *string_duration;
1447 int cmd, level, l, no_authorized, od;
1449 NodeList<DCCChat *> *node;
1455 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1459 level = level_person(prefix, buffer+1);
1460 if(r != NULL) r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1463 else level = level_person(prefix, NULL);
1466 if(eq("join", buffer)) cmd = CMD_JOIN;
1467 else if(eq("home", buffer)) cmd = CMD_HOME;
1468 else if(eq("b", buffer) || eq("ban", buffer)) cmd = CMD_BAN;
1469 else if(eq("sb", buffer) || eq("siteban", buffer)) cmd = CMD_SBAN;
1473 if(eq("ms", buffer) || eq("myshit", buffer))
1475 if(dont_flood_server()) notice_shit_list(chat, nick, prefix, 0);
1477 else if(eq("sl", buffer) || eq("shitlist", buffer))
1479 if(level >= LEVEL_FRIEND)
1483 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1486 if(is_pattern(buffer)) notice_shit_list(chat, nick, buffer, 1);
1489 wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
1492 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1493 write_irc(IRC_buffer);
1496 else notice_shit_list(chat, nick, "*", 1);
1498 else no_authorized = 1;
1500 else if(eq("www", buffer))
1502 if(dont_flood_server())
1503 tell(chat, nick, "THX-1138's home page at "
1504 "http://www.eleves.ens.fr:8080/home/fleuret/\n");
1506 else if(eq("w", buffer) || eq("who", buffer))
1508 if(level >= LEVEL_FRIEND)
1510 if(r == NULL) notice_list_by_sites(chat, nick, NULL);
1511 else while(r != NULL)
1513 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1515 if(!is_pattern(buffer))
1518 while(*s != '\0') s++;
1524 notice_list_by_sites(chat, nick, buffer);
1527 else no_authorized = 1;
1529 else if(eq("ao", buffer) || eq("antifloodoff", buffer))
1533 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
1534 duration = string_to_seconds(buffer_time);
1535 anti_flood_off_until = current_time + duration;
1537 if(anti_flood_off_until > current_time)
1539 string_duration = seconds_to_string(anti_flood_off_until -
1541 sprintf(IRC_buffer, "Anti-flood off for %s\n",
1543 delete string_duration;
1545 tell(chat, nick, IRC_buffer);
1547 else tell(chat, nick, "Anti-flood on\n");
1549 else if(eq("msg", buffer) || eq("message", buffer))
1551 if(level >= LEVEL_OP)
1555 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1558 if(is_pattern(buffer)) msg_users(chat, nick, buffer, r);
1562 wait_list.Insert(new WaitInfos(buffer, r, chat,
1566 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1567 write_irc(IRC_buffer);
1572 else no_authorized = 1;
1574 else if(eq("h", buffer) || eq("history", buffer))
1576 if(level >= LEVEL_OP) notice_history(chat, nick);
1577 else no_authorized = 1;
1579 else if(eq("level", buffer))
1581 if(level >= LEVEL_FRIEND)
1585 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1588 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1590 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1591 write_irc(IRC_buffer);
1595 sprintf(IRC_buffer, "%s is level %d\n", prefix,
1596 level_person(prefix, NULL));
1597 tell(chat, nick, IRC_buffer);
1600 else no_authorized = 1;
1602 else if(eq("help", buffer))
1604 if(dont_flood_server() || (level >= LEVEL_FRIEND))
1609 "control_char '%c' op_delay %ds deban_delay %ds"
1610 " your level is %d. I am a father with %d sons.\n",
1611 control_char, op_delay, deban_delay,
1613 tell(chat, nick, IRC_buffer);
1618 "control_char '%c' op_delay %ds deban_delay %ds"
1619 " your level is %d. I'm a clone.\n",
1620 control_char, op_delay, deban_delay, level);
1621 tell(chat, nick, IRC_buffer);
1625 if(level >= LEVEL_FRIEND)
1627 tell(chat, nick, "\002help\002 \002www\002 \002\037s\037\002hit\037l\037\002ist\002 [<nick>!<pattern>] \002level\002 [<nick>] \002\037w\037\002ho\002 \002\037m\037\002y\037s\037\002hit\002\n");
1630 if(level >= LEVEL_OP)
1632 tell(chat, nick, "\002\037a\037\002ntiflood\037o\037\002ff\002 [<duration>] \002\037a\037\002lert\002 \002home\002 \002op\002 [{<nick> list}] \002join\002 <#channel> \002nick\002 <nick> \002\037p\037\002rune\037b\037\002an\002 <number> \002\037d\037\002e\037b\037\002an\002 {<pattern> list} \002\037f\037\002ilter\037k\037\002ick\002 <pattern>!<nick> [<comment>] \002\037s\037\002hit/\037s\037\002hit\037s\037\002ite/\037s\037\002hit\037h\037\002ost\002 <pattern>!<nick> [<duration> [<comment>]] \002\037u\037\002n\037s\037\002hit\002 {<pattern>!<nick> list} \002\037pu\037\002n\037s\037\002hit\002 {<pattern> list} \002\037b\037\002an/\037s\037\002ite\037b\037\002an\002 <pattern>!<nick> \002synch\002 \002\037h\037\002istory\002\n \002\037m\037\002es\037s\037\002a\037g\037\002e\002 <nick>!<pattern> <msg>\n");
1635 if(level >= LEVEL_MASTER)
1637 tell(chat, nick, "\002reset\002 \002load\002 [<file>] \002save\002 [<file>] \002friend\002 <pattern> <level> [<passwd>] \002clone\002 [<nick>] \002die\002 \002server\002 <hostname> [<port>] \002controlchar\002 <char> \002opdelay\002 <delay in s> \002debandelay\002 <delay in s>\n");
1642 tell(chat, nick, "\002\037u\037\002sers\002 \002\037t\037\002alk\002 <msg>\n");
1646 else if((cmd == CMD_JOIN) || (cmd == CMD_HOME))
1648 if(level >= LEVEL_OP)
1650 if(global_state == STATE_WAIT)
1652 sprintf(IRC_buffer, "PART %s\n", current_channel);
1653 write_irc(IRC_buffer);
1655 strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
1659 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1660 strncpy(wanted_channel, buffer, SMALL_BUFFER_SIZE);
1662 uncap(wanted_channel);
1663 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
1664 write_irc(IRC_buffer);
1667 tell(chat, nick, "Can't join right now, retry in a while\n");
1668 } else no_authorized = 1;
1670 else if(eq("op", buffer))
1672 if(level >= LEVEL_OP)
1674 if(r == NULL) add_mode(current_channel, "+o", nick);
1678 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1679 add_mode(current_channel, "+o", buffer);
1682 else no_authorized = 1;
1684 else if(eq("nick", buffer))
1686 if(level >= LEVEL_OP)
1690 r = next_word(wanted_nick, r, SMALL_BUFFER_SIZE);
1691 sprintf(buffer, "NICK %s\n", wanted_nick);
1694 } else no_authorized = 1;
1696 else if(eq("db", buffer) || eq("deban", buffer))
1698 if(level >= LEVEL_FRIEND)
1702 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1703 if(is_pattern(buffer))
1705 NodeList<char *> *node;
1706 for(node = banid_list.first; node != NULL; node = node->next)
1707 if(match_pattern(buffer, node->body))
1708 add_mode(current_channel, "-b", node->body);
1712 wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
1713 MODE_UNBAN_NICK, 0));
1714 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1715 write_irc(IRC_buffer);
1718 } else no_authorized = 1;
1720 else if((cmd == CMD_BAN) || (cmd == CMD_SBAN))
1722 if(level >= LEVEL_OP)
1726 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1729 if(is_pattern(buffer))
1731 banid = clean_banid(buffer);
1732 smart_ban(current_channel, banid);
1740 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1744 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1750 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1751 write_irc(IRC_buffer);
1755 else no_authorized = 1;
1757 else if(eq("pb", buffer) || eq("pruneban", buffer))
1759 if(level >= LEVEL_OP)
1763 NodeList<char *> *node;
1765 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1769 for(node = banid_list.first; node != NULL;
1771 if(n == 0) add_mode(current_channel, "-b", node->body);
1775 } else no_authorized = 1;
1777 else if(eq("synch", buffer))
1779 if(level >= LEVEL_OP) synch(current_channel);
1780 else no_authorized = 1;
1782 else if(eq("s", buffer) || eq("shit", buffer))
1784 if(level >= LEVEL_OP)
1788 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1790 if(is_pattern(buffer))
1794 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
1795 duration = string_to_seconds(buffer_time);
1797 else duration = DEFAULT_SHIT_TIME;
1799 if(r == NULL) r = "Shit nick";
1802 banid = clean_banid(buffer);
1803 smart_shit(chat, nick, banid, r, duration);
1810 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
1811 duration = string_to_seconds(buffer_time);
1813 else duration = DEFAULT_SHIT_TIME;
1815 if(r == NULL) r = "Shit nick";
1818 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1822 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1823 write_irc(IRC_buffer);
1827 else no_authorized = 1;
1830 else if(eq("fk", buffer) || eq("filterkick", buffer))
1832 if(level >= LEVEL_OP)
1836 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1838 if(is_pattern(buffer))
1840 if(r == NULL) r = "Filter kick";
1841 filter_kick(current_channel, buffer, r);
1845 if(r == NULL) r = "Filter Kick";
1846 wait_list.Insert(new
1847 WaitInfos(buffer, r, chat, nick,
1848 MODE_FILTER_KICK, 0));
1849 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1850 write_irc(IRC_buffer);
1854 else no_authorized = 1;
1857 else if(eq("a", buffer) || eq("alert", buffer))
1859 if(level >= LEVEL_OP) alert(current_channel, chat, nick);
1860 else no_authorized = 1;
1863 else if(eq("sh", buffer) || eq("shithost", buffer))
1865 if(level >= LEVEL_OP)
1869 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1873 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
1874 duration = string_to_seconds(buffer_time);
1876 else duration = DEFAULT_SHIT_TIME;
1878 if(r == NULL) r = "Shit host";
1881 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1882 MODE_SHIT_HOST, duration));
1884 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1885 write_irc(IRC_buffer);
1888 else no_authorized = 1;
1890 else if(eq("ss", buffer) || eq("shitsite", buffer))
1892 if(level >= LEVEL_OP)
1896 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1900 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
1901 duration = string_to_seconds(buffer_time);
1903 else duration = DEFAULT_SHIT_TIME;
1905 if(r == NULL) r = "Shit site";
1908 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1909 MODE_SHIT_SITE, duration));
1911 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1912 write_irc(IRC_buffer);
1915 else no_authorized = 1;
1917 else if(eq("pus", buffer) || eq("punshit", buffer))
1919 if(level >= LEVEL_OP)
1923 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1925 if(strlen(buffer) > 0)
1927 NodeList<Welcome *> *node, *next, *pred;
1930 node = shit_list.first;
1934 if(match_pattern(buffer, node->body->pattern))
1936 smart_unban(current_channel, node->body->pattern);
1937 if(pred == NULL) shit_list.first = next;
1938 else pred->next = next;
1941 node->body->pattern,
1942 node->body->comment);
1943 tell(chat, nick, IRC_buffer);
1953 else no_authorized = 1;
1955 else if(eq("us", buffer) || eq("unshit", buffer))
1957 if(level >= LEVEL_OP)
1961 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1964 if(is_pattern(buffer))
1966 NodeList<Welcome *> *node, *next, *pred;
1969 node = shit_list.first;
1973 if(strcmp(node->body->pattern, buffer) == 0)
1975 if(pred == NULL) shit_list.first = next;
1976 else pred->next = next;
1979 buffer, node->body->comment);
1980 tell(chat, nick, IRC_buffer);
1990 wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
1991 MODE_UNSHIT_NICK, 0));
1993 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1994 write_irc(IRC_buffer);
1998 else no_authorized = 1;
2000 else if(eq("friend", buffer))
2002 if(level >= LEVEL_MASTER)
2006 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2009 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2010 l = atoi(buffer_time);
2011 if((l > 0) && (l<=LEVEL_MASTER))
2013 level_list.Insert(new Person(buffer, l, r));
2015 "Adding %s with level %d and passwd %s\n",
2017 tell(chat, nick, IRC_buffer);
2018 SaveConfigFile(config_file);
2023 else no_authorized = 1;
2025 else if(eq("opdelay", buffer))
2027 if(level >= LEVEL_MASTER)
2031 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2033 if((od>=0) && (od <= 60))
2036 sprintf(IRC_buffer,"Oping delay set to %ds\n", op_delay);
2037 tell(chat, nick, IRC_buffer);
2041 else no_authorized = 1;
2043 else if(eq("debandelay", buffer))
2045 if(level >= LEVEL_MASTER)
2049 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2051 if((od>=0) && (od <= 60))
2055 "Deban delay set to %ds\n",
2057 tell(chat, nick, IRC_buffer);
2061 else no_authorized = 1;
2063 else if(eq("controlchar", buffer))
2065 if(level >= LEVEL_MASTER)
2069 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2070 control_char = buffer[0];
2071 sprintf(IRC_buffer, "Control char set to '%c'\n",
2073 tell(chat, nick, IRC_buffer);
2076 else no_authorized = 1;
2078 else if(eq("die", buffer))
2080 if(level >= LEVEL_MASTER)
2082 sprintf(IRC_buffer, "QUIT :Killed by %s\n", nick);
2083 write_irc(IRC_buffer);
2086 else no_authorized = 1;
2088 else if(eq("server", buffer))
2090 if(level >= LEVEL_MASTER)
2094 next_word(wanted_server, r, SMALL_BUFFER_SIZE);
2097 next_word(buffer, r, SMALL_BUFFER_SIZE);
2098 wanted_port = atoi(buffer);
2099 if(wanted_port == 0) wanted_port = 6667;
2101 else wanted_port = DEFAULT_PORT;
2104 "Trying to connect %s:%d\n",
2105 wanted_server, wanted_port);
2106 tell(chat, nick, IRC_buffer);
2108 sprintf(IRC_buffer, "QUIT :Changing server\n");
2109 write_irc(IRC_buffer);
2111 cerr<<"KILLING CONNECTION : Changing server\n";
2116 else no_authorized = 1;
2118 else if(eq("clone", buffer))
2120 if(level >= LEVEL_MASTER)
2124 if(nb_sons < NB_SONS_MAX)
2126 if(r != NULL) next_word(buffer, r, SMALL_BUFFER_SIZE);
2130 else tell(chat, nick, "Too many clones, can't clone\n");
2134 tell(chat, nick, "I'm a clone, can't clone\n");
2137 else no_authorized = 1;
2139 else if(eq("save", buffer))
2141 if(level >= LEVEL_MASTER)
2143 if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
2144 if(SaveConfigFile(config_file))
2147 "Can't save the %s configuration file\n",
2153 "Saving the %s configuration file\n",
2156 tell(chat, nick, IRC_buffer);
2158 else no_authorized = 1;
2160 else if(eq("load", buffer))
2162 if(level >= LEVEL_MASTER)
2164 if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
2165 if(LoadConfigFile(config_file))
2168 "Can't load the %s configuration file\n",
2174 "Loading the %s configuration file\n",
2177 tell(chat, nick, IRC_buffer);
2179 else no_authorized = 1;
2181 else if(eq("reset", buffer))
2183 if(level >= LEVEL_MASTER)
2185 sprintf(IRC_buffer, "QUIT :reset command sent by %s\n", nick);
2186 write_irc(IRC_buffer);
2187 cerr<<"KILLING CONNECTION : Die\n";
2191 else no_authorized = 1;
2194 // DCC CHAT only commands
2196 else if((chat != NULL) && (eq("t", buffer) || eq("talk", buffer)))
2198 NodeList<DCCChat *> *node;
2199 sprintf(IRC_buffer, "<%s> %s\n", prefix, r);
2200 for(node = dcc_chat_list.first; node != NULL; node = node->next)
2201 if(node->body != chat) tell(node->body, NULL, IRC_buffer);
2203 else if((chat != NULL) && (eq("u", buffer) || eq("users", buffer)))
2205 for(node = dcc_chat_list.first; node != NULL; node = node->next)
2207 sprintf(IRC_buffer, "%s\n", node->body->prefix);
2208 tell(chat, NULL, IRC_buffer);
2214 else if(dont_flood_server())
2216 sprintf(IRC_buffer, "Unknown command \002%s\002\n", buffer);
2217 tell(chat, nick, IRC_buffer);
2223 if(dont_flood_server())
2226 "You are not authorized to use \002%s\002\n", buffer);
2227 tell(chat, nick, IRC_buffer);
2233 if(*r == '&') r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2234 add_in_history(prefix, r);
2238 //-----------------------------------------------------------------------------
2240 int accepting_dcc_chat(char *prefix, char *nick, int level, char *r)
2242 NodeList<DCCChat *> *node;
2243 int socket, port_number;
2244 char host[SMALL_BUFFER_SIZE], port[SMALL_BUFFER_SIZE];
2247 if(r == NULL) return 1;
2248 else r = next_word(host, r, SMALL_BUFFER_SIZE);
2250 if(strcmp(host, "chat") != 0) return 1;
2252 if(r == NULL) return 1;
2253 else r = next_word(host, r, SMALL_BUFFER_SIZE);
2255 if(r == NULL) return 1;
2256 else r = next_word(port, r, SMALL_BUFFER_SIZE);
2258 port_number = atoi(port);
2259 socket = call_socket(host, port_number);
2261 if(socket <= 0) return 1;
2264 dcc_chat = new DCCChat(prefix, socket, port_number);
2265 dcc_chat_list.Insert(dcc_chat);
2267 FD_SET(socket, &ready);
2270 "Welcome to \002TropBot\002 " VERSION " on a DCC CHAT\n"
2271 "You are known as %s, your level is %d.\n"
2272 "You are client #%d on DCC CHAT\n",
2273 prefix, level, dcc_chat_list.Lenght());
2275 write(socket, IRC_buffer, strlen(IRC_buffer));
2277 sprintf(IRC_buffer, "%s arrives with level %d.\n", prefix, level);
2278 for(node=dcc_chat_list.first; node!= NULL; node = node->next)
2279 if(node->body != dcc_chat) tell(node->body, NULL, IRC_buffer);
2285 //-----------------------------------------------------------------------------
2287 // This function is called after a NOTICE
2289 void IRC_NOTICE(char *prefix,
2290 char *who, char *msg, char **slice_ctcp, int n_ctcp)
2293 if(strcmp(who, current_channel) == 0) add_flood_line(prefix, FL_NOTICE, 1);
2296 void IRC_PRIVMSG(char *prefix,
2297 char *who, char *msg, char **slice_ctcp, int n_ctcp)
2299 int k, version, ping, level;
2301 char buffer[SMALL_BUFFER_SIZE];
2304 nick = cut_nick_from_prefix(prefix);
2305 if(strcmp(who, current_channel) == 0)
2307 add_flood_line(prefix, FL_PUBLIC, 1);
2308 if(n_ctcp > 0) add_flood_line(prefix, FL_CTCP, n_ctcp);
2311 if(msg != NULL) if(strlen(msg)>0)
2313 if(msg[0] == control_char) tropbot_cmd(NULL, prefix, nick, msg+1);
2314 else if(strcmp(who, real_nick) == 0) tropbot_cmd(NULL, prefix, nick, msg);
2321 for(k=0; k<n_ctcp; k++)
2324 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2326 // Reply the CTCP VERSION
2327 if(eq("VERSION", buffer) && !version)
2329 if(dont_flood_server())
2332 sprintf(IRC_buffer, "NOTICE %s :"
2333 "\001VERSION \002TropBot\002 " VERSION OPTIONS
2334 ", " SYSTEM " system, " DATE ". "
2335 "Contact THX-1138 on IRC, or <francois.fleuret@inria.fr>"
2338 write_irc(IRC_buffer);
2341 // Reply the CTCP PING
2342 else if(eq("PING", buffer) && !ping)
2346 if(dont_flood_server())
2349 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2351 "NOTICE %s :\001PING %s\001\n", nick, buffer);
2352 write_irc(IRC_buffer);
2356 else if(eq("DCC", buffer))
2358 level = level_person(prefix, NULL);
2359 if(level >= LEVEL_OP)
2363 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2364 if(eq("CHAT", buffer))
2366 if(accepting_dcc_chat(prefix, nick, level, r) != 0)
2368 sprintf(IRC_buffer, "NOTICE %s :\002Error\002"
2369 " can't connect\n", nick);
2370 write_irc(IRC_buffer);
2376 "NOTICE %s :I can only DCC CHAT\n", nick);
2377 write_irc(IRC_buffer);
2381 else if(dont_flood_server())
2384 "NOTICE %s :Sorry, can't accept DCC from you\n",
2386 write_irc(IRC_buffer);
2393 //-----------------------------------------------------------------------------
2395 // This function is called after a QUIT
2397 void IRC_QUIT(char *prefix)
2399 present_people.Remove(prefix);
2402 //-----------------------------------------------------------------------------
2404 // This function is called after a NICK
2406 void IRC_NICK(char *prefix, char *nick)
2410 add_flood_line(prefix, FL_NICK, 1);
2411 present_people.Remove(prefix);
2413 t = nick; while(*t != '\0') *s++=*t++; // copy the nick
2414 *s++='!'; // put the '!'
2415 t = reach_loginathost(prefix);
2416 while(*t != '\0') *s++=*t++; // copy the user@host
2417 *s = '\0'; // end of string
2418 present_people.Add(IRC_buffer); // hop !
2420 ok = 1; s = prefix; t = real_nick;
2421 while(ok && (*t != '\0') && (*s != '\0')) ok = (*s++ == *t++);
2422 if(ok && (*t == '\0') && (*s == '!'))
2424 strncpy(real_nick, nick, SMALL_BUFFER_SIZE);
2429 //-----------------------------------------------------------------------------
2431 // This function is called after a PART
2433 void IRC_PART(char *prefix, char *where)
2436 add_flood_line(prefix, FL_PART, 1);
2437 present_people.Remove(prefix);
2438 nick = cut_nick_from_prefix(prefix);
2439 if(strcmp(real_nick, nick) == 0)
2441 present_people.Clear();
2447 //-----------------------------------------------------------------------------
2449 // This function is called after a KICK
2451 void IRC_KICK(char *prefix, char *where, char *victim_nick)
2456 if(strcmp(victim_nick, real_nick) == 0)
2458 present_people.Clear();
2460 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
2461 write_irc(IRC_buffer);
2464 if((level_person(prefix, NULL) < level_person(prefix_from_nick(victim_nick), NULL)) &&
2465 (level_person(prefix_from_nick(victim_nick), NULL) > 0))
2467 c = cut_nick_from_prefix(prefix);
2468 add_mode(where, "-o", c);
2472 c = prefix_from_nick(victim_nick);
2473 if(c != NULL) present_people.Remove(c);
2474 else cerr<<"** ERROR : non present person has been kicked out **\n";
2477 //-----------------------------------------------------------------------------
2479 int check_restricted(char *where, char *prefix)
2481 char pattern[SMALL_BUFFER_SIZE];
2482 NodeList<char *> *node;
2486 p = adr_beginning(prefix);
2488 node = present_people.first;
2490 while((node != NULL) && (n < 2))
2492 s = adr_beginning(node->body);
2493 if(strcmp(s, p) == 0) n++;
2503 duration = DEFAULT_RESTRICTED_TIME;
2504 smart_shit(NULL, NULL, pattern, "Restricted site : no clones", duration);
2505 smart_ban(where, pattern);
2507 filter_kick(where, pattern, "Restricted site : no clones");
2513 // This function is called after a JOIN
2515 void IRC_JOIN(char *prefix, char *where)
2519 NodeList<Welcome *> *node;
2521 nick = cut_nick_from_prefix(prefix);
2523 if(strcmp(real_nick, nick) == 0)
2525 strncpy(current_channel, where, SMALL_BUFFER_SIZE);
2526 sprintf(IRC_buffer, "WHO %s\n", where);
2527 write_irc(IRC_buffer);
2528 present_people.Clear();
2529 global_state = STATE_GETING_WHO;
2534 add_flood_line(prefix, FL_JOIN, 1);
2537 present_people.Add(prefix);
2539 if(restricted_list.Matches(prefix))
2540 restricted = check_restricted(where, prefix);
2541 else restricted = 0;
2545 l = level_person(prefix, NULL);
2549 if(l >= LEVEL_DEFENCE) add_mode(where, "+o", nick);
2551 mode_change_list.Insert(new DelayModeChange(where, "+o",
2556 if(banid_list.Matches(prefix))
2558 sprintf(IRC_buffer, "KICK %s %s :You are banned\n", where, nick);
2559 write_irc(IRC_buffer);
2563 for(node = shit_list.first; node != NULL; node = node->next)
2564 if(match_pattern(node->body->pattern, prefix))
2566 smart_ban(where, node->body->pattern);
2567 send_mode(current_channel);
2569 sprintf(IRC_buffer, "KICK %s %s :%s\n",
2570 where, nick, node->body->comment);
2572 write_irc(IRC_buffer);
2582 //-----------------------------------------------------------------------------
2584 void IRC_RPL_BANLIST(char *prefix, char *channel, char *banid)
2586 banid_list.Add(banid);
2589 void IRC_ENDOFBANLIST(char *prefix)
2591 banid_list.Reverse();
2592 global_state = STATE_WAIT;
2595 void IRC_RPL_ENDOFWHOIS(char *prefix, char *nick)
2597 NodeList<WaitInfos *> *node, *pred, *next;
2600 node = wait_list.first;
2605 if(strcmp(nick, node->body->nick) == 0)
2607 sprintf(IRC_buffer, "Can't find %s\n", nick);
2608 tell(node->body->chat, node->body->user, IRC_buffer);
2610 if(pred == NULL) wait_list.first = next;
2611 else pred->next = next;
2620 void IRC_RPL_WHOISUSER(char *prefix,
2621 char *nick, char *login, char *host, char *real_name)
2623 char *c, *d, *banid;
2625 char buffer[SMALL_BUFFER_SIZE];
2626 NodeList<WaitInfos *> *node, *next, *pred;
2628 int no_pattern, one_login, all_machines;
2635 node = wait_list.first;
2640 if(strcmp(nick, node->body->nick) == 0)
2644 no_pattern = (node->body->mode == MODE_UNSHIT_NICK) ||
2645 (node->body->mode == MODE_LEVEL) ||
2646 (node->body->mode == MODE_UNBAN_NICK) ||
2647 (node->body->mode == MODE_SHITLIST);;
2649 one_login = (node->body->mode == MODE_SHIT_NICK) ||
2650 (node->body->mode == MODE_BAN_NICK);
2652 all_machines = (node->body->mode == MODE_SHIT_NICK) ||
2653 (node->body->mode == MODE_BAN_NICK) ||
2654 (node->body->mode == MODE_BAN_SITE) ||
2655 (node->body->mode == MODE_FILTER_KICK) ||
2656 (node->body->mode == MODE_SHIT_SITE) ||
2657 (node->body->mode == MODE_MSG);
2670 if((*login == '~') || (*login == '+') ||
2671 (*login == '-') || (*login=='^'))
2680 while((*login != '\0') && ((l<7) || *(login+1) == '\0'))
2681 { *c++ = *login++; l++; }
2682 if(*login != '\0') *c++ = '*';
2687 d = adr_beginning(host);
2688 if(host != d) if(*(c-1) != '*') *c++ = '*';
2690 if(all_machines) concat_pattern_from_host(c, d);
2700 banid = clean_banid(buffer);
2702 if(node->body->mode == MODE_MSG)
2703 msg_users(node->body->chat, node->body->user,
2704 banid, node->body->comment);
2706 else if(node->body->mode == MODE_FILTER_KICK)
2707 filter_kick(current_channel, banid, node->body->comment);
2709 else if((node->body->mode == MODE_BAN_NICK) ||
2710 (node->body->mode == MODE_BAN_SITE))
2711 smart_ban(current_channel, banid);
2713 else if((node->body->mode == MODE_SHIT_NICK)
2714 || (node->body->mode == MODE_SHIT_SITE)
2715 || (node->body->mode == MODE_SHIT_HOST))
2717 smart_shit(node->body->chat,
2718 node->body->user, banid, node->body->comment,
2719 node->body->duration);
2721 if(prefix_from_nick(nick) != NULL)
2723 smart_ban(current_channel, banid);
2724 send_mode(current_channel);
2725 sprintf(IRC_buffer, "KICK %s %s :%s\n",
2726 current_channel, nick, node->body->comment);
2727 write_irc(IRC_buffer);
2732 else if(node->body->mode == MODE_SHITLIST)
2733 notice_shit_list(NULL, node->body->user, banid, 0);
2735 else if(node->body->mode == MODE_LEVEL)
2737 sprintf(IRC_buffer, "%s is level %d\n",
2738 banid, level_person(banid, NULL));
2739 tell(node->body->chat, node->body->user, IRC_buffer);
2741 else if(node->body->mode == MODE_UNSHIT_NICK)
2743 NodeList<Welcome *> *node2, *pred, *next;
2745 node2 = shit_list.first;
2747 while(node2 != NULL)
2750 if(match_pattern(node2->body->pattern, banid))
2752 if(pred == NULL) shit_list.first = next;
2753 else pred->next = next;
2755 sprintf(IRC_buffer, "Unshit %s (%s)\n",
2756 node2->body->pattern, node2->body->comment);
2758 tell(node->body->chat, node->body->user, IRC_buffer);
2760 smart_unban(current_channel, node2->body->pattern);
2769 else if(node->body->mode == MODE_UNBAN_NICK)
2771 NodeList<char *> *node2;
2772 for(node2 = banid_list.first; node2 != NULL; node2 = node2->next)
2773 if(match_pattern(node2->body, banid))
2774 add_mode(current_channel, "-b", node2->body);
2780 if(pred == NULL) wait_list.first = next;
2781 else pred->next = next;
2790 // This function is called after a RPL_WHOREPLY
2792 void IRC_RPL_WHOREPLY(char *prefix,
2794 char *login, char *host, char *server,
2795 char *nick, char *state)
2802 if((global_state == STATE_GETING_WHO) &&
2803 (strcmp(where, current_channel) == 0))
2806 t = nick; while(*t != '\0') *s++ = *t++;
2808 t = login; while(*t != '\0') *s++ = *t++;
2810 t = host; while(*t != '\0') *s++ = *t++;
2812 present_people.Add(IRC_buffer);
2814 else cerr<<where<<"!="<<current_channel<<"\n";
2817 void IRC_RPL_ENDOFWHO(char *prefix, char *name)
2819 sprintf(IRC_buffer, "MODE %s +b\n", current_channel);
2820 write_irc(IRC_buffer);
2822 if(in_channel) global_state = STATE_GETING_BAN;
2823 else global_state = STATE_WAIT;
2826 //-----------------------------------------------------------------------------
2828 void IRC_ERR_NICKNAMEINUSE(char *prefix, char *channel)
2830 rand_nick(wanted_nick, jam_nick);
2831 #ifdef SCREEN_OUTPUT
2832 cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
2834 sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
2835 write_irc(IRC_buffer);
2836 was_killed = 1; // We have been killed (I said PARANOID !)
2837 time_killed = current_time; // Note when it happens
2840 //-----------------------------------------------------------------------------
2842 // This function is called after a ERR_NOSUCHCHANNEL
2844 void IRC_ERR_NOSUCHCHANNEL(char *prefix, char *nick)
2846 strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
2847 uncap(wanted_channel);
2850 //-----------------------------------------------------------------------------
2852 // This function is called after a ERR_NICKCOLLISION (436)
2854 void IRC_ERR_NICKCOLLISION(char *prefix, char *nick)
2856 rand_nick(wanted_nick, jam_nick);
2857 #ifdef SCREEN_OUTPUT
2858 cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
2860 sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
2861 write_irc(IRC_buffer);
2862 was_killed = 1; // We have been killed (I said PARANOID !)
2863 time_killed = current_time; // Note when it happens
2866 //-----------------------------------------------------------------------------
2868 // This is the main command. It is called for each line from the server.
2870 void get_command(char *prefix,
2871 char **slice_cmd, int n_cmd,
2872 char **slice_ctcp, int n_ctcp)
2874 char small_buffer[SMALL_BUFFER_SIZE];
2879 #ifdef SCREEN_OUTPUT
2880 cout<<"from "<<prefix<<" ";
2882 for(k=0; k<n_cmd; k++) cout<<"["<<slice_cmd[k]<<"]";
2883 if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<slice_ctcp[k]<<">";
2887 if(prefix != NULL) uncap(prefix);
2889 // No prefix : server command
2892 if(n_cmd > 0) if(eq("PING", cmd))
2894 if(n_cmd > 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]);
2895 else sprintf(IRC_buffer, "PONG\n");
2896 write_irc(IRC_buffer);
2901 // If we are not registred yet, then get the registration
2906 strncpy(real_nick, slice_cmd[1], SMALL_BUFFER_SIZE);
2909 sprintf(small_buffer, "MODE %s +i\n", real_nick);
2910 write_irc(small_buffer);
2911 sprintf(small_buffer, "JOIN %s\n", wanted_channel);
2912 write_irc(small_buffer);
2915 else if(eq("PRIVMSG", cmd))
2916 IRC_PRIVMSG(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
2917 else if(eq("NOTICE", cmd))
2918 IRC_NOTICE(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
2919 else if(eq("MODE", cmd))
2920 IRC_MODE(slice_cmd[1], prefix, slice_cmd[2], slice_cmd+3);
2921 else if(eq("JOIN", cmd)) IRC_JOIN(prefix, slice_cmd[1]);
2922 else if(eq("KICK", cmd)) IRC_KICK(prefix, slice_cmd[1], slice_cmd[2]);
2923 else if(eq("QUIT", cmd)) IRC_QUIT(prefix);
2924 else if(eq("NICK", cmd)) IRC_NICK(prefix, slice_cmd[1]);
2925 else if(eq("PART", cmd)) IRC_PART(prefix, slice_cmd[1]);
2926 else if(eq("311", cmd))
2927 IRC_RPL_WHOISUSER(prefix,
2928 slice_cmd[2], slice_cmd[3], slice_cmd[4],
2930 else if(eq("318", cmd)) IRC_RPL_ENDOFWHOIS(prefix, slice_cmd[2]);
2931 else if(eq("352", cmd))
2932 IRC_RPL_WHOREPLY(prefix,
2933 slice_cmd[2], slice_cmd[3], slice_cmd[4],
2934 slice_cmd[5], slice_cmd[6], slice_cmd[7]);
2935 else if(eq("315", cmd)) IRC_RPL_ENDOFWHO(prefix, slice_cmd[1]);
2936 else if(eq("367", cmd))
2937 IRC_RPL_BANLIST(prefix, slice_cmd[2], slice_cmd[3]);
2938 else if(eq("368", cmd)) IRC_ENDOFBANLIST(prefix);
2939 else if(eq("403", cmd)) IRC_ERR_NOSUCHCHANNEL(prefix, slice_cmd[1]);
2940 else if(eq("433", cmd)) IRC_ERR_NICKNAMEINUSE(prefix, slice_cmd[1]);
2941 else if(eq("436", cmd)) IRC_ERR_NICKCOLLISION(prefix, slice_cmd[1]);
2945 //-----------------------------------------------------------------------------
2947 // Rough routine to read the options
2949 void get_options(int argc, char **argv)
2957 if(eq("-p", argv[n]))
2960 if(n<argc) default_port = atoi(argv[n]);
2961 else cerr<<"*** No port parameter ***\n";
2963 else if(eq("-h", argv[n]))
2966 if(n<argc) strncpy(default_server, argv[n], MAXHOSTNAME);
2967 else cerr<<"*** No hostname parameter ***\n";
2969 else if(eq("-o", argv[n]))
2974 strncpy(config_file, argv[n], SMALL_BUFFER_SIZE);
2975 LoadConfigFile(argv[n]);
2977 else cerr<<"*** No friends list parameter ***\n";
2979 else if(eq("-c", argv[n]))
2982 if(n<argc) strncpy(home_channel, argv[n], SMALL_BUFFER_SIZE);
2983 else cerr<<"*** No channel parameter ***\n";
2985 else if(eq("-l", argv[n]))
2988 if(n<argc) strncpy(user_login, argv[n], SMALL_BUFFER_SIZE);
2989 else cerr<<"*** No username parameter ***\n";
2991 else if(eq("-n", argv[n]))
2994 if(n<argc) strncpy(original_nick, argv[n], SMALL_BUFFER_SIZE);
2995 else cerr<<"*** No nickname parameter ***\n";
2997 else if(eq("-j", argv[n]))
3000 if(n<argc) strncpy(jam_nick, argv[n], SMALL_BUFFER_SIZE);
3001 else cerr<<"*** No jam nickname parameter ***\n";
3003 else if(eq("-d", argv[n]))
3009 if(d>=1) socket_delay = d;
3010 else cerr<<"*** Delay error ***\n";
3012 else cerr<<"*** No delay parameter ***\n";
3014 else if(eq("-od", argv[n]))
3020 if(d>=1) op_delay = d;
3021 else cerr<<"*** Op delay error ***\n";
3023 else cerr<<"*** No delay parameter ***\n";
3025 else if(eq("-dd", argv[n]))
3031 if(d>=1) deban_delay = d;
3032 else cerr<<"*** Deban delay error ***\n";
3034 else cerr<<"*** No delay parameter ***\n";
3036 else if(eq("-?", argv[n])) help = 1;
3039 cerr<<"*** Unknown option "<<argv[n]<<" ***\n";
3045 cout<<"Tropbot " VERSION " Written by Francois Fleuret.\n";
3046 cout<<"Compiled the " DATE " on a " SYSTEM " system.\n";
3047 cout<<"Contact <francois.fleuret@inria.fr>.\n";
3049 cout<<"Options are :\n";
3050 cout<<"-c <#channel> sets the channel\n";
3051 cout<<"-d <delay in s> sets the reconnection delay\n";
3052 cout<<"-h <hostname> sets the server name\n";
3053 cout<<"-j <jam nickname> sets the pattern nick for collision\n";
3054 cout<<"-l <user> sets the user in the user@host stuff\n";
3055 cout<<"-n <nickname> sets the nickname\n";
3056 cout<<"-o <friends file> loads configuration file\n";
3057 cout<<"-od <delay in s> set the delay before +o\n";
3058 cout<<"-dd <delay in s> set the delay before -b\n";
3059 cout<<"-p <port number> sets the server port\n";
3060 cout<<"-? shows this help\n";
3068 //-----------------------------------------------------------------------------
3070 void clean_shit_list()
3072 NodeList<Welcome *> *node, *pred, *next;
3074 node = shit_list.first;
3079 if(current_time >= node->body->time_max)
3081 if(pred == NULL) shit_list.first = next;
3082 else pred->next = next;
3084 smart_unban(current_channel, node->body->pattern);
3092 send_mode(current_channel);
3095 //-----------------------------------------------------------------------------
3097 void try_reconnect()
3099 if(delay < DELAY_MAX_RECONNECT)
3101 if(delay == 0) delay = 1;
3103 if(delay > DELAY_MAX_RECONNECT) delay = DELAY_MAX_RECONNECT;
3105 strncpy(wanted_server, default_server, MAXHOSTNAME+1);
3106 wanted_port = default_port;
3107 cerr<<"*** Can't contact IRC server ***\n";
3108 cerr<<"*** Next try in "<<delay<<" s\n";
3111 void got_connection()
3113 time_last_datas = current_time;
3115 FD_SET(socket_irc, &ready);
3116 sprintf(buffer, "USER %s x x :%s\n", user_login, user_name);
3118 sprintf(buffer, "NICK %s\n", wanted_nick);
3120 delay = socket_delay;
3123 void got_datas_from_server()
3126 char *prefix, *r, *t;
3128 char *slice_cmd[NB_SLICES_MAX], *slice_ctcp[NB_SLICES_MAX];
3129 char *dest_cmd, *dest_ctcp;
3132 char buffer_cmd[BUFFER_SIZE], buffer_ctcp[BUFFER_SIZE];
3134 time_last_datas = current_time;
3136 // If the buffer is already full, purge it
3137 if(endsrc >= buffer+BUFFER_SIZE)
3139 cerr<<"*** Buffer full, erase it ***\n";
3143 s = read(socket_irc, endsrc, buffer+BUFFER_SIZE-1-endsrc);
3149 cerr<<"KILLING CONNECTION : Read error\n";
3159 dest_cmd = buffer_cmd;
3160 dest_ctcp = buffer_ctcp;
3162 if(slice_buffer(src, endsrc,
3164 dest_cmd, slice_cmd, n_cmd,
3165 dest_ctcp, slice_ctcp, n_ctcp))
3166 // No more \r in the buffer
3170 while(r<endsrc) *t++ = *r++;
3176 // Oki, we got a full line
3177 get_command(prefix, slice_cmd, n_cmd, slice_ctcp, n_ctcp);
3185 NodeList<DelayModeChange *> *md;
3187 if(current_time > anti_flood_off_until) check_flood();
3188 check_delay_mode_change();
3189 send_mode(current_channel);
3191 delay = socket_delay;
3192 NodeList<Welcome *> *nd;
3193 for(nd = shit_list.first; nd != NULL; nd = nd->next)
3194 if(delay > nd->body->time_max-current_time)
3195 delay = nd->body->time_max-current_time;
3197 for(md = mode_change_list.first; md != NULL; md = md->next)
3198 if(delay > md->body->time-current_time)
3199 delay = md->body->time-current_time;
3201 if(delay < 0) delay = 0;
3206 NodeList<DCCChat *> *node, *pred, *next, *node2;
3207 char CHAT_buffer[BUFFER_SIZE];
3210 pred = NULL; next = NULL;
3211 node = dcc_chat_list.first;
3215 if(FD_ISSET(node->body->socket, &result))
3217 s = read(node->body->socket, CHAT_buffer, BUFFER_SIZE-1);
3220 FD_CLR(node->body->socket, &ready); // Forget the socket
3221 close(node->body->socket);
3223 sprintf(IRC_buffer, "%s leaves.\n", node->body->prefix);
3224 for(node2=dcc_chat_list.first; node2!= NULL; node2 = node2->next)
3225 if(node2->body != node->body)
3226 tell(node2->body, NULL, IRC_buffer);
3228 remove_wait_for_chat(node->body);
3230 if(pred == NULL) dcc_chat_list.first = next;
3231 else pred->next = next;
3237 *(CHAT_buffer+s-1) = '\0';
3238 tropbot_cmd(node->body, node->body->prefix, NULL, CHAT_buffer);
3248 int main(int argc, char **argv)
3251 // I think it's a good idea to have few friends forever (me ? yeahhh !)
3252 level_list.Insert(new Person("*!*fleuret@*.inria.fr", LEVEL_MASTER, NULL));
3253 level_list.Insert(new Person("*!*fleuret@*.ens.fr", LEVEL_MASTER, NULL));
3254 level_list.Insert(new Person("*!*fleuret@*.curie.fr", LEVEL_MASTER, NULL));
3255 level_list.Insert(new Person("*!*jolibot@*.inria.fr", LEVEL_DEFENCE, NULL));
3256 level_list.Insert(new Person("*!*jolibot@*.ens.fr", LEVEL_DEFENCE, NULL));
3257 level_list.Insert(new Person("*!*jolibot@*.curie.fr", LEVEL_DEFENCE, NULL));
3259 cout<<"TropBot, written by Francois Fleuret,"
3260 " contact <francois.fleuret@inria.fr>\n";
3262 get_options(argc, argv);
3264 uncap(home_channel);
3265 strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
3266 strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
3267 strncpy(wanted_server, default_server, MAXHOSTNAME+1);
3268 wanted_port = default_port;
3270 IRC_registred = 0; // true if we are registred
3271 IRC_connected = 0; // true if we have a connection with an IRC server
3272 global_state = STATE_WAIT;
3274 mode_protect_on = DEFAULT_MODE_PROTECT;
3282 last_answer_time = 0;
3283 anti_flood_off_until = 0;
3287 delay = socket_delay;
3289 struct sigaction action;
3290 action.sa_handler = SIG_IGN;
3292 // We'll ignore the SIGPIPE signal, which will be catch somewhere else
3293 sigaction(SIGPIPE, &action, NULL);
3299 delay_pause.tv_sec = delay;
3300 delay_pause.tv_usec = 0;
3303 while(waitpid(-1, NULL, WNOHANG) > 0) nb_sons--;
3305 select(64, &result, NULL, NULL, &delay_pause);
3307 time(¤t_time);
3313 #ifdef SCREEN_OUTPUT
3314 cout<<"No connection yet\n";
3315 cout<<"Try to contact "<<wanted_server<<":"<<wanted_port<<"\n";
3317 socket_irc = call_socket(wanted_server, wanted_port);
3319 if(socket_irc <= 0) try_reconnect();
3320 else got_connection();
3324 if((current_time > time_killed+DELAY_NICK_BACK) && was_killed)
3327 strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
3328 sprintf(buffer, "NICK %s\n", wanted_nick);
3332 if(IRC_registred) clean_shit_list();
3334 if(FD_ISSET(socket_irc, &result)) got_datas_from_server();
3337 if(current_time > time_last_datas+DELAY_DEAD_SERVER)
3339 cerr<<"KILLING CONNECTION : Quiet server\n";
3343 else if(!in_channel) if(global_state == STATE_WAIT)
3345 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
3346 write_irc(IRC_buffer);
3350 if(IRC_connected) check_stuffs();
3353 #ifdef SCREEN_OUTPUT
3354 cout<<present_people.Lenght()<<" person(s) inside\n";
3355 // banid_list.Print();
3359 while(alive || (socket_irc > 0));
3363 //-----------------------------------------------------------------------------