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 -----------------------------------------------------------------------------*/
8 #define VERSION "v2.9.2d"
14 #include <sys/types.h>
21 //-----------------------------------------------------------------------------
27 #define ANTI_SPOOF_MAX_TIME 300
29 //-----------------------------------------------------------------------------
31 #define MODE_NUMBER_MAX 3
32 #define SIZE_BANLIST_MAX 20
33 #define NB_CHAR_MAX 400
35 //-----------------------------------------------------------------------------
37 #define DEFAULT_CONTROL_CHAR '|'
38 #define DELAY_NICK_BACK 300
39 #define DELAY_MAX_RECONNECT 300
40 #define DELAY_DEAD_SERVER 900
42 #define DEFAULT_SERVER "sil.polytechnique.fr"
43 #define DEFAULT_PORT 6667
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
54 #define DEFAULT_ANTI_FLOOD_OFF_DURATION 600
56 #define DEFAULT_CONFIG_FILE ".tropbotrc"
58 #define DEFAULT_SHIT_TIME 600
59 #define DEFAULT_RESTRICTED_TIME 900
61 #define DEFAULT_MODE_PROTECT 0
63 // Not needed coz flooding people can't re-JOIN quickly
64 //#define BAN_ON_FLOOD
65 #define BAN_FLOOD_DELAY 30
67 #define MAX_LINE_FLOOD 4
68 #define MAX_CTCP_FLOOD 3
70 #define DELAY_ANSWERS 3
71 #define ANTI_CLONES_DELAY 30
75 #define HISTORY_SIZE 3
77 enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN, FL_KICK };
79 //-----------------------------------------------------------------------------
81 // More than 3 kicks in 5 minutes -> 30 mins shit
83 #define COP_NB_KICKS 3
86 #define COP_DURATION 1800
87 #define COP_DELAY_BEETWEEN_KICKS 2
89 //-----------------------------------------------------------------------------
91 #define MAX_DCC_CHAT 16
93 //-----------------------------------------------------------------------------
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);
99 //-----------------------------------------------------------------------------
101 int default_port = DEFAULT_PORT;
103 char default_server[MAXHOSTNAME+1] = DEFAULT_SERVER;
104 char wanted_server[MAXHOSTNAME+1];
106 fd_set ready, result;
107 int alive; // Should be set to false (0) to kill the bot
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;
119 time_t current_time, time_killed, time_last_datas, last_answer_time,
120 anti_flood_off_until;
122 char buffer[BUFFER_SIZE];
124 int IRC_connected, IRC_registred;
125 int global_state, in_channel, was_killed, mode_protect_on;
128 #define STATE_GETING_WHO 1
129 #define STATE_GETING_BAN 2
131 //-----------------------------------------------------------------------------
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 *>;
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;
148 ListChar present_people, banid_list, restricted_list, history;
150 //-----------------------------------------------------------------------------
152 // General buffer for all IRC operations
153 char IRC_buffer[BUFFER_SIZE];
155 // Nick we got after registration
156 char real_nick[SMALL_BUFFER_SIZE];
159 char wanted_nick[SMALL_BUFFER_SIZE];
161 char original_nick[SMALL_BUFFER_SIZE] = DEFAULT_NICK;
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;
167 // The "user" we want in the nick!user@host stuff
168 char user_login[SMALL_BUFFER_SIZE] = DEFAULT_LOGIN;
170 // The USERNAME string
171 char user_name[SMALL_BUFFER_SIZE] = DEFAULT_USER_NAME;
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;
177 // The name of the configuration file
178 char config_file[SMALL_BUFFER_SIZE] = DEFAULT_CONFIG_FILE;
180 //-----------------------------------------------------------------------------
182 char *prefix_from_nick(char *nick)
184 NodeList<char *> *node;
189 node = present_people.first;
190 while((node != NULL) && !yep)
195 while((*t != '\0') &&
196 (*s != '!') && (*s != '\0') && yep) yep &= (*s++ == *t++);
197 yep &= ((*t == '\0') && (*s == '!'));
198 if(!yep) node=node->next;
201 if(node != NULL) return node->body; else return NULL;
205 //-----------------------------------------------------------------------------
207 int level_person(char *prefix, char *passwd)
209 NodeList<Person *> *node;
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))
217 if(node->body->passwd == NULL) l = node->body->level;
220 if(strcmp(node->body->passwd, passwd) == 0)
221 l = node->body->level;
226 void remove_level(char *prefix)
228 NodeList<Person *> *node, *pred, *next;
229 pred = NULL; next = NULL;
231 node = level_list.first;
235 if(strcmp(node->body->pattern, prefix) == 0)
237 if(pred == NULL) level_list.first = next;
238 else pred->next = next;
249 NodeList<Person *> *node, *next;
251 node = level_list.first;
259 level_list.first = NULL;
264 NodeList<Welcome *> *node, *next;
266 node = shit_list.first;
274 shit_list.first = NULL;
277 void remove_wait_for_chat(DCCChat *chat)
279 NodeList<WaitInfos *> *node, *pred, *next;
280 pred = NULL; next = NULL;
282 node = wait_list.first;
286 if(node->body->chat == chat)
288 if(pred == NULL) wait_list.first = next;
289 else pred->next = next;
298 //-----------------------------------------------------------------------------
300 // This function generates a random nick from a pattern. The pattern
301 // is supposed to contain some '?', which will be replaced with random
304 void rand_nick(char *nick, char *pattern)
307 for(n=0; n<strlen(pattern); n++)
309 if(pattern[n] == '?') nick[n] = '0'+int(rand()%10);
310 else nick[n] = pattern[n];
315 //-----------------------------------------------------------------------------
317 void kill_connection()
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
335 void clone(char *nick)
339 strcpy(wanted_nick, nick);
340 strcpy(original_nick, nick);
343 FD_CLR(socket_irc, &ready);
344 present_people.Clear();
345 time_killed = current_time;
354 void write_irc(char *stuff)
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)
360 cerr<<"KILLING CONNECTION : write_irc error\n";
368 cout<<"\n!!!!>"<<stuff<<"<\n\n";
370 last_answer_time = current_time;
374 //-----------------------------------------------------------------------------
378 char string_modes[MODE_NUMBER_MAX*2+1];
380 char string_param_modes[MODE_NUMBER_MAX*64+1];
381 char *ptr_param_modes;
387 ptr_modes = string_modes;
388 ptr_param_modes = string_param_modes;
393 void send_mode(char *where)
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);
406 void add_mode(char *where, char *mode, char *param)
410 // Disgusting hack coz of a FUCKING server bug :-(
413 if(k_mode) send_mode(where);
419 if(o_mode) send_mode(where);
424 while(*s != '\0') *ptr_modes++ = *s++;
428 while(*s != '\0') *ptr_param_modes++ = *s++;
429 *ptr_param_modes++ = ' ';
432 if(++nb_modes == MODE_NUMBER_MAX) send_mode(where);
435 //-----------------------------------------------------------------------------
437 void tell(DCCChat *chat, char *nick, char *msg)
439 char tell_buffer[BUFFER_SIZE];
442 cout<<"tell(chat="<<chat<<", nick="<<nick<<" msg="<<msg<<")\n";
443 if(msg[strlen(msg)-1] != '\n')
444 cout<<"**************************************\n";
447 if(chat != NULL) write(chat->socket, msg, strlen(msg));
451 sprintf(tell_buffer, "NOTICE %s :%s", nick, msg);
452 write_irc(tell_buffer);
456 //-----------------------------------------------------------------------------
458 void smart_shit(DCCChat *chat, char *nick,
459 char *pattern, char *comment, int duration)
461 NodeList<Welcome *> *node, *next, *pred;
465 if(duration < 5) duration = 5;
467 time_max = duration + current_time;
470 node = shit_list.first;
472 while((node != NULL) && !no_shit)
475 if(strcmp(node->body->pattern, pattern) == 0)
477 if(node->body->time_max <= time_max)
479 if(pred == NULL) shit_list.first = next;
480 else pred->next = next;
496 shit_list.Insert(new Welcome(pattern, comment, time_max));
497 if((nick != NULL) || (chat != NULL))
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;
507 else if((nick != NULL) || (chat != NULL))
510 "Can't shit %s, already shitted for a longer time\n", pattern);
511 tell(chat, nick, IRC_buffer);
515 //-----------------------------------------------------------------------------
517 void smart_ban(char *where, char *pattern)
519 NodeList<char *> *node;
522 for(node = banid_list.first; node != NULL; node = node->next)
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);
530 add_mode(current_channel, "+b", pattern);
533 void smart_unban(char *where, char *pattern)
535 if(banid_list.Contains(pattern)) add_mode(where, "-b", pattern);
538 //-----------------------------------------------------------------------------
540 void check_delay_mode_change()
542 NodeList<DelayModeChange *> *node, *pred, *next;
545 node = mode_change_list.first;
549 if(current_time >= node->body->time)
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;
562 void clean_delay_mode_change(char *where, char *mode, char *param)
564 NodeList<DelayModeChange *> *node, *pred, *next;
569 node = mode_change_list.first;
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))
581 if(pred == NULL) mode_change_list.first = next;
582 else pred->next = next;
595 if((strcmp(where, node->body->where) == 0) &&
596 (node->body->parameter == NULL) &&
597 (strcmp(mode, node->body->mode) == 0))
599 if(pred == NULL) mode_change_list.first = next;
600 else pred->next = next;
610 void RemoveDelayModeChange(char *mode, char *parameter)
612 NodeList<DelayModeChange *> *node, *pred, *next;
615 node = mode_change_list.first;
619 if((strcmp(node->body->mode, mode) == 0) &&
620 (strcmp(node->body->parameter, parameter) == 0))
622 if(pred == NULL) mode_change_list.first = next;
623 else pred->next = next;
632 //-----------------------------------------------------------------------------
634 void synch(char *channel)
637 NodeList<char *> *node;
639 for(node = present_people.first; node != NULL; node = node->next)
640 if(level_person(node->body, NULL) >= LEVEL_OP)
642 nick = cut_nick_from_prefix(node->body);
643 add_mode(channel, "+o", nick);
648 //-----------------------------------------------------------------------------
650 ListChar already_kicked;
652 void filter_kick(char *where, char *pattern, char *comment)
654 NodeList<char *> *node;
657 if(already_kicked.Contains(pattern)) return;
659 already_kicked.Add(pattern);
660 for(node = present_people.first; node != NULL;
663 if(match_pattern(pattern, node->body))
664 if(level_person(node->body, NULL) == 0)
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);
674 //-----------------------------------------------------------------------------
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)
682 while(*s != '\0') if(*s++ == '@') t = s;
687 char *reach_loginathost(char *s)
689 while((*s != '!') && (*s != '\0')) s++;
694 //-----------------------------------------------------------------------------
703 int individual, site, alreadykicked;
705 FloodLine(char *p, int k, int w)
714 ~FloodLine() { delete[] prefix; }
715 void Reset() { individual = 0; site = 0; }
718 template class List<FloodLine *>;
720 List<FloodLine *> flood_list, kick_list;
722 //-----------------------------------------------------------------------------
724 void alert(char *where, DCCChat *chat, char *nick)
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];
731 for(node = flood_list.first; node != NULL; node = node->next)
732 node->body->individual = 0;
734 node = flood_list.first;
741 while((node != NULL) && node->body->individual) node = node->next;
745 site = adr_beginning(node->body->prefix);
750 while((son != NULL) && son->body->individual) son = son->next;
753 site2 = adr_beginning(son->body->prefix);
755 if(are_same_site(site, site2))
757 son->body->individual = 1;
764 if(nb_lines > max_nb_lines)
765 if(level_person(node->body->prefix, NULL) == 0)
767 max_nb_lines = nb_lines;
774 if(guilty_site != NULL)
776 duration = DEFAULT_SHIT_TIME;
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);
784 filter_kick(where, pattern, "Filter kick on alert");
785 add_mode(where, "-m", NULL);
788 else tell(chat, nick, "\002No flooding site detected\002\n");
791 void check_one_flood(NodeList<FloodLine *> *node)
793 NodeList<FloodLine *> *son;
794 char *userhost, *userhost2, *nick;
797 userhost = reach_loginathost(node->body->prefix);
803 while((son != NULL) && son->body->individual) son = son->next;
806 if(!son->body->alreadykicked)
808 userhost2 = reach_loginathost(son->body->prefix);
810 if(strcmp(userhost, userhost2) == 0)
812 son->body->individual = 1;
820 if(nb_lines >= MAX_LINE_FLOOD)
824 char *pattern, *banid;
825 if((level_person(node->body->prefix, NULL) < LEVEL_OP))
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,
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);
844 for(son = flood_list.first; son != NULL; son = son->next)
846 userhost2 = reach_loginathost(son->body->prefix);
847 if(strcmp(userhost, userhost2) == 0) son->body->alreadykicked = 1;
855 int nb_lines, nb_ctcp;
856 NodeList<FloodLine *> *node, *next, *pred;
858 nb_lines = 0; nb_ctcp = 0;
860 node = flood_list.first;
864 if(current_time <= node->body->time + FLOOD_DELAY)
866 nb_lines += node->body->weigth;
867 if((node->body->kind == FL_CTCP) && !node->body->alreadykicked)
868 nb_ctcp += node->body->weigth;
874 if(pred == NULL) flood_list.first = next;
875 else pred->next = next;
883 if(nb_ctcp >= MAX_CTCP_FLOOD)
885 add_mode(current_channel, "+m", NULL);
886 send_mode(current_channel);
887 mode_change_list.Insert(new DelayModeChange(current_channel,
893 if(nb_lines >= MAX_LINE_FLOOD)
895 for(node = flood_list.first; node != NULL; node = node->next)
896 node->body->individual = 0;
898 node = flood_list.first;
901 while((node != NULL) && node->body->individual) node = node->next;
904 if(!node->body->alreadykicked) check_one_flood(node);
911 inline void add_flood_line(char *prefix, int kind, int weigth)
913 flood_list.Insert(new FloodLine(prefix, kind, weigth));
916 int bad_line(char *line, char *comment)
918 int length, nb_art_chars, longest_word, nb_caps, nb_letters, nb_ctrl;
931 for(s=(unsigned char *)line; *s != '\0'; s++)
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++;
943 if(s > (unsigned char *) line)
945 if(*s == *(s-1)) l++;
948 if(l > longest_word) longest_word = l;
955 if(l > longest_word) longest_word = l;
960 if(longest_word > 60)
963 concat(t, "repeated chars");
968 if(bad) concat(t, " + ");
969 concat(t, "control chars");
973 if((nb_art_chars > nb_letters) && (nb_art_chars >= 20))
975 if(bad) concat(t, " + ");
976 concat(t, "art chars");
980 if((nb_caps*4 > nb_letters*3) && (nb_caps >= 10))
982 if(bad) concat(t, " + ");
992 void test_kick(char *prefix)
996 NodeList<FloodLine *> *node, *next, *pred;
997 char *pattern, *banid, *loginathost;
999 loginathost = reach_loginathost(prefix);
1002 last_kick_time = current_time + COP_DELAY_BEETWEEN_KICKS + 1;
1004 node = kick_list.first;
1008 if(current_time <= node->body->time + COP_DELAY)
1010 if(strcmp(loginathost, reach_loginathost(node->body->prefix)) == 0)
1012 if(node->body->time < last_kick_time - COP_DELAY_BEETWEEN_KICKS)
1014 nb_kicks += node->body->weigth;
1015 last_kick_time = node->body->time;
1022 if(pred == NULL) kick_list.first = next;
1023 else pred->next = next;
1030 if(nb_kicks >= COP_NB_KICKS)
1032 pattern = pattern_from_prefix(prefix, 0);
1033 banid = clean_banid(pattern);
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");
1046 inline void add_kick(char *prefix)
1048 if(level_person(prefix, NULL) >= LEVEL_FRIEND) return;
1049 kick_list.Insert(new FloodLine(prefix, FL_KICK, 1));
1053 //-----------------------------------------------------------------------------
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
1059 void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
1063 int check_ban, nb_bans, ok;
1064 NodeList<char *> *node;
1065 char pattern[SMALL_BUFFER_SIZE];
1068 if(signe < 0) buffer[0] = '-'; else buffer[0] = '+';
1071 if(param != NULL) uncap(param);
1073 clean_delay_mode_change(where, buffer, param);
1075 #ifdef SCREEN_OUTPUT
1076 cout<<"ONE MODE CHANGE CHANNEL ("<<where<<")";
1077 cout<<" BY ("<<who<<") MODE "<<signe<<" "<<mode;
1078 cout<<" ON "<<param<<"\n";
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)
1088 if(is_hostname(who))
1090 if(deban_delay == 0)
1092 if(signe>0) add_mode(where, "-b", param);
1093 else add_mode(where, "+b", param);
1098 mode_change_list.Insert(new DelayModeChange(where, "-b", param,
1101 mode_change_list.Insert(new DelayModeChange(where, "+b", param,
1109 banid_list.Add(param);
1111 if(cop_mode && !is_hostname(who))
1113 adr_param = adr_beginning(param);
1116 for(node = banid_list.first; node != NULL; node = node->next)
1117 if(are_same_site(adr_param, adr_beginning(node->body)))
1120 if(nb_bans >= COP_NB_BANS)
1125 concat(c, adr_param);
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)
1138 smart_shit(NULL, NULL,
1140 "cop : too many bans on one site",
1141 COP_DURATION + deban_delay);
1142 smart_ban(where, pattern);
1149 banid = clean_banid(param);
1150 if(strcmp(banid, param) != 0) smart_ban(where, banid);
1154 else banid_list.Remove(param);
1158 if(is_hostname(who))
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);
1168 (level_person(who, NULL) <
1169 level_person(prefix_from_nick(param), NULL)) &&
1170 (level_person(prefix_from_nick(param), NULL) > 0))
1172 c = cut_nick_from_prefix(who);
1173 add_mode(where, "-o", c);
1174 add_mode(where, "+o", param);
1180 if(signe>0) if(is_hostname(who) || mode_protect_on)
1181 add_mode(where, "-i", NULL);
1185 if(signe>0) if(is_hostname(who) || mode_protect_on)
1186 add_mode(where, "-l", NULL);
1190 if(signe>0) if(is_hostname(who) || mode_protect_on)
1191 add_mode(where, "-p", NULL);
1195 if(signe>0) if(is_hostname(who) || mode_protect_on)
1196 add_mode(where, "-k", param);
1200 if(is_hostname(who))
1202 if(signe>0) add_mode(where, "-m", NULL);
1204 else if(mode_protect_on)
1206 if(level_person(who, NULL) < LEVEL_OP)
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);
1218 if(signe>0) if(is_hostname(who) || mode_protect_on)
1219 add_mode(where, "-s", NULL);
1227 //-----------------------------------------------------------------------------
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()
1233 void IRC_MODE(char *where, char *who, char *mode, char **params)
1235 int param_no, signe;
1239 while(*mode != '\0')
1250 if((*mode == 'l') || (*mode == 'v') ||
1251 (*mode == 'k') || (*mode == 'o') ||
1253 IRC_ONE_MODE(where, who, signe, *mode, params[param_no++]);
1255 IRC_ONE_MODE(where, who, signe, *mode, NULL);
1263 //-----------------------------------------------------------------------------
1265 void get_one_line(ifstream *s, char *buffer, int buffer_size)
1276 if(d != '\n') *c++ = d;
1280 ok &= (c<buffer + buffer_size);
1285 #define MAX_INCLUDE_RECURSE 3
1287 int LoadConfigFile(char *name, int recurse)
1290 int duration, level, error;
1292 char pattern[SMALL_BUFFER_SIZE], buffer[SMALL_BUFFER_SIZE];
1294 file = new ifstream(name);
1299 restricted_list.Clear();
1302 get_one_line(file, IRC_buffer, BUFFER_SIZE);
1303 if(strlen(IRC_buffer) > 0)
1306 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1308 if(strcmp(buffer, "INCLUDE") == 0)
1312 if(recurse < MAX_INCLUDE_RECURSE)
1314 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1315 LoadConfigFile(buffer, recurse+1);
1318 else cerr<<"Can't include "
1319 <<buffer<<" : too many recursion.\n";
1323 else if(strcmp(buffer, "FRIEND") == 0)
1327 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1328 level = atoi(buffer);
1331 r = next_word(pattern, r, SMALL_BUFFER_SIZE);
1333 level_list.Insert(new Person(pattern, level, r));
1337 else if(strcmp(buffer, "RESTRICTED") == 0)
1341 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1342 #ifdef SCREEN_OUTPUT
1343 cout<<"RESTRICTED->"<<buffer<<"\n";
1345 restricted_list.Insert(strdup(buffer));
1348 else if(strcmp(buffer, "SHIT") == 0)
1352 r = next_word(pattern, r, SMALL_BUFFER_SIZE);
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);
1365 else if(strcmp(buffer, "OPDELAY") == 0)
1369 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1370 op_delay = atoi(buffer);
1373 else if(strcmp(buffer, "DEBANDELAY") == 0)
1377 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1378 deban_delay = atoi(buffer);
1381 else if(strcmp(buffer, "CONTROLCHAR") == 0)
1385 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1386 if(buffer[0] != '\0') control_char = buffer[0];
1391 shit_list.Reverse();
1392 level_list.Reverse();
1393 restricted_list.Reverse();
1403 int SaveConfigFile(char *name)
1406 NodeList<Welcome *> *welcome;
1407 NodeList<Person *> *person;
1408 NodeList<char *> *restricted;
1411 file = new ofstream(name);
1414 (*file)<<"% Config file for a TropBot " VERSION "\n";
1417 (*file)<<"OPDELAY "<<op_delay<<"\n";
1418 (*file)<<"DEBANDELAY "<<deban_delay<<"\n";
1419 (*file)<<"CONTROLCHAR "<<control_char<<"\n";
1423 for(person=level_list.first; person != NULL; person=person->next)
1425 (*file)<<"FRIEND "<<person->body->level<<" "<<person->body->pattern;
1426 if(person->body->passwd != NULL) (*file)<<" "<<person->body->passwd;
1432 for(restricted=restricted_list.first;
1434 restricted=restricted->next)
1435 (*file)<<"RESTRICTED "<<restricted->body<<"\n";
1439 for(welcome=shit_list.first; welcome != NULL; welcome=welcome->next)
1440 (*file)<<"SHIT "<<welcome->body->pattern<<" "<<
1441 welcome->body->time_max - current_time<<" "<<
1442 welcome->body->comment<<"\n";
1453 //-----------------------------------------------------------------------------
1455 void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
1457 NodeList<char *> *node1, *node2;
1458 int *ok, nb, k, l, level, put_blank;
1460 int nb_total, nb_person[LEVEL_MAX+1];
1463 for(k=0; k<LEVEL_MAX+1; k++) nb_person[k] = 0;
1465 nb = present_people.Lenght();
1467 for(k = 0; k<nb; k++) ok[k] = 0;
1469 node1 = present_people.first;
1475 concat(buf, "\002");
1476 concat(buf, pattern);
1477 concat(buf, "\002 and same site : ");
1480 while(node1 != NULL)
1482 if((pattern == NULL) || match_pattern(pattern, node1->body))
1484 c = adr_beginning(node1->body);
1488 while(node2 != NULL)
1490 d = adr_beginning(node2->body);
1491 if(are_same_site(c, d))
1494 level = level_person(d, NULL);
1497 if(put_blank) *buf++ = '/'; else put_blank = 1;
1499 if(level == LEVEL_OP) *buf++ = '\002';
1500 else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
1502 while((*d != '!') && (*d != '\0')) *buf++ = *d++;
1504 if(level == LEVEL_OP) *buf++ = '\002';
1505 else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
1509 if(buf > IRC_buffer + NB_CHAR_MAX)
1511 *buf++ = '\n'; *buf++ = '\0';
1512 tell(chat, nick, IRC_buffer);
1520 node2 = node2->next;
1522 while((node2 != NULL) && (ok[l] == 1));
1531 node1 = node1->next;
1533 while((node1 != NULL) && (ok[k] == 1));
1536 *buf++ = '\n'; *buf++ = '\0';
1537 tell(chat, nick, IRC_buffer);
1539 sprintf(IRC_buffer, "Total %d (\002%d\002)\n",
1541 nb_person[LEVEL_OP] + nb_person[LEVEL_DEFENCE] +
1542 nb_person[LEVEL_MASTER]);
1543 tell(chat, nick, IRC_buffer);
1548 //-----------------------------------------------------------------------------
1550 void notice_shit_list(DCCChat *chat, char *nick, char *pattern, int matched)
1553 char *string_duration;
1554 NodeList<Welcome *> *node;
1556 if(shit_list.Lenght() == 0) tell(chat, nick, "\002Empty shit-list\002\n");
1560 for(node = shit_list.first; node != NULL; node=node->next)
1561 if((matched && match_pattern(pattern, node->body->pattern))
1562 || (!matched && match_pattern(node->body->pattern, pattern)))
1565 string_duration = seconds_to_string(node->body->time_max
1568 sprintf(IRC_buffer, "%s for %s (%s)\n",
1569 node->body->pattern,
1571 node->body->comment);
1572 tell(chat, nick, IRC_buffer);
1573 delete[] string_duration;
1576 if(n == 0) tell(chat, nick, "\002No corresponding shits\002\n");
1580 //-----------------------------------------------------------------------------
1582 void add_in_history(char *prefix, char *action)
1584 NodeList<char *> *node, *pred, *next;
1588 s = new char[strlen(prefix) + strlen(action) + 4];
1597 pred = NULL; next = NULL; node = history.first;
1604 if(pred == NULL) history.first = next;
1605 else pred->next = next;
1606 delete[] node->body;
1614 void notice_history(DCCChat *chat, char *nick)
1616 NodeList<char *> *node;
1618 for(node = history.first; node != NULL; node = node->next)
1620 sprintf(IRC_buffer, "%s\n", node->body);
1621 tell(chat, nick, IRC_buffer);
1625 //-----------------------------------------------------------------------------
1627 int dont_flood_server()
1629 return current_time >= last_answer_time + DELAY_ANSWERS;
1632 void msg_users(DCCChat *chat, char *nick, char *pattern, char *msg)
1634 NodeList<char *> *node;
1638 sprintf(IRC_buffer, "\002[msg to %s]\002 %s\n", pattern, msg);
1639 tell(chat, nick, IRC_buffer);
1642 for(node = present_people.first; node != NULL; node = node->next)
1644 if(match_pattern(pattern, node->body))
1647 nick_user = cut_nick_from_prefix(node->body);
1648 sprintf(IRC_buffer, "PRIVMSG %s :\002[msg to %s]\002 %s\n",
1649 nick_user, pattern, msg);
1650 write_irc(IRC_buffer);
1655 sprintf(IRC_buffer, "\002[msg sent to %d user(s)]\002\n", nb);
1656 tell(chat, nick, IRC_buffer);
1659 //-----------------------------------------------------------------------------
1661 #define CMD_DEFAULT 0
1667 void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
1669 char buffer[SMALL_BUFFER_SIZE], buffer_time[SMALL_BUFFER_SIZE];
1670 char *r, *s, *c, *banid;
1671 char *string_duration;
1672 int cmd, level, l, no_authorized, od;
1674 NodeList<DCCChat *> *node;
1680 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1684 level = level_person(prefix, buffer+1);
1685 if(r != NULL) r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1688 else level = level_person(prefix, NULL);
1691 if(eq("join", buffer)) cmd = CMD_JOIN;
1692 else if(eq("home", buffer)) cmd = CMD_HOME;
1693 else if(eq("b", buffer) || eq("ban", buffer)) cmd = CMD_BAN;
1694 else if(eq("sb", buffer) || eq("siteban", buffer)) cmd = CMD_SBAN;
1698 if(eq("ms", buffer) || eq("myshit", buffer))
1700 if(dont_flood_server()) notice_shit_list(chat, nick, prefix, 0);
1702 else if(eq("write", buffer) || eq("wr", buffer))
1704 if(level >= LEVEL_MASTER)
1708 sprintf(IRC_buffer, "PRIVMSG %s :%s\n", current_channel, r);
1709 write_irc(IRC_buffer);
1712 else no_authorized = 1;
1714 else if(eq("sl", buffer) || eq("shitlist", buffer))
1716 if(level >= LEVEL_FRIEND)
1720 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1723 if(is_pattern(buffer))
1724 notice_shit_list(chat, nick, buffer, 1);
1727 wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
1730 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1731 write_irc(IRC_buffer);
1736 int s1, s2, s3, s4, d;
1737 NodeList<Welcome *> *node;
1738 s1 = 0; s2 = 0; s3 = 0; s4 = 0;
1739 for(node=shit_list.first; node != NULL; node=node->next)
1741 d = node->body->time_max - current_time;
1743 else if(d < 4*3600) s2++;
1744 else if(d < 24*3600) s3++;
1750 "\002%d\002 < 30min < \002%d\002 < "
1751 "4h < \002%d\002 < 24h < \002%d\002\n",
1752 s1+s2+s3+s4, s1, s2, s3, s4);
1753 tell(chat, nick, IRC_buffer);
1756 else no_authorized = 1;
1758 else if(eq("www", buffer))
1760 if(dont_flood_server())
1761 tell(chat, nick, "THX-1138's home page at "
1762 "http://www.eleves.ens.fr:8080/home/fleuret/\n");
1764 else if(eq("w", buffer) || eq("who", buffer))
1766 if(level >= LEVEL_FRIEND)
1768 if(r == NULL) notice_list_by_sites(chat, nick, NULL);
1769 else while(r != NULL)
1771 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1773 notice_list_by_sites(chat, nick, buffer);
1776 else no_authorized = 1;
1778 else if(eq("ao", buffer) || eq("antifloodoff", buffer))
1780 if(level >= LEVEL_OP)
1784 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
1785 duration = string_to_seconds(buffer_time);
1786 anti_flood_off_until = current_time + duration;
1788 if(anti_flood_off_until > current_time)
1790 string_duration = seconds_to_string(anti_flood_off_until -
1792 sprintf(IRC_buffer, "Anti-flood off for %s\n",
1794 delete[] string_duration;
1796 tell(chat, nick, IRC_buffer);
1798 else tell(chat, nick, "Anti-flood on\n");
1800 else no_authorized = 1;
1802 else if(eq("msg", buffer) || eq("message", buffer))
1804 if(level >= LEVEL_OP)
1808 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1811 if(is_pattern(buffer)) msg_users(chat, nick, buffer, r);
1815 wait_list.Insert(new WaitInfos(buffer, r, chat,
1819 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1820 write_irc(IRC_buffer);
1825 else no_authorized = 1;
1827 else if(eq("h", buffer) || eq("history", buffer))
1829 if(level >= LEVEL_OP) notice_history(chat, nick);
1830 else no_authorized = 1;
1832 else if(eq("level", buffer))
1834 if(level >= LEVEL_FRIEND)
1838 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1841 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
1843 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1844 write_irc(IRC_buffer);
1848 sprintf(IRC_buffer, "%s is level %d\n", prefix,
1849 level_person(prefix, NULL));
1850 tell(chat, nick, IRC_buffer);
1853 else no_authorized = 1;
1855 else if(eq("mode", buffer))
1857 if(dont_flood_server() || (level >= LEVEL_FRIEND))
1860 if(cop_mode) a = "ON"; else a = "OFF";
1864 "control_char '%c' op_delay %ds deban_delay %ds "
1866 " your level is %d. I am a father with %d sons.\n",
1867 control_char, op_delay, deban_delay, a,
1869 tell(chat, nick, IRC_buffer);
1874 "control_char '%c' op_delay %ds deban_delay %ds "
1876 " your level is %d. I'm a clone.\n",
1877 control_char, op_delay, deban_delay, a,
1879 tell(chat, nick, IRC_buffer);
1883 else if(eq("help", buffer))
1885 if(level >= LEVEL_FRIEND)
1887 tell(chat, nick, "\002help\002 \002www\002 \002\037s\037\002hit\037l\037\002ist\002 [<nick>!<pattern>] \002level\002 [<nick>] \002\037w\037\002ho\002 \002\037m\037\002y\037s\037\002hit\002\n");
1890 if(level >= LEVEL_OP)
1892 tell(chat, nick, "\002\037a\037\002ntiflood\037o\037\002ff\002 [<duration>] \002\037a\037\002lert\002 \002home\002 \002cop\002 \002op\002 [{<nick> list}] \002join\002 <#channel> \002nick\002 <nick> \002\037p\037\002rune\037b\037\002an\002 <number> \002\037d\037\002e\037b\037\002an\002 {<pattern> list} \002\037f\037\002ilter\037k\037\002ick\002 <pattern>!<nick> [<comment>] \002\037s\037\002hit/\037s\037\002hit\037s\037\002ite/\037s\037\002hit\037h\037\002ost\002 <pattern>!<nick> [<duration> [<comment>]] \002\037u\037\002n\037s\037\002hit\002 {<pattern>!<nick> list} \002\037pu\037\002n\037s\037\002hit\002 {<pattern> list} \002\037b\037\002an/\037s\037\002ite\037b\037\002an\002 <pattern>!<nick> \002synch\002 \002\037h\037\002istory\002\n \002\037m\037\002es\037s\037\002a\037g\037\002e\002 <nick>!<pattern> <msg>\n");
1895 if(level >= LEVEL_MASTER)
1897 tell(chat, nick, "\002reset\002 \002load\002 [<file>] \002save\002 [<file>] \002friend\002 <pattern> <level> [<passwd>] \002clone\002 [<nick>] \002die\002 \002server\002 <hostname> [<port>] \002controlchar\002 <char> \002opdelay\002 <delay in s> \002debandelay\002 <delay in s>\n");
1902 tell(chat, nick, "\002\037u\037\002sers\002 \002\037t\037\002alk\002 <msg>\n");
1906 else if((cmd == CMD_JOIN) || (cmd == CMD_HOME))
1908 if(level >= LEVEL_OP)
1910 if(global_state == STATE_WAIT)
1912 sprintf(IRC_buffer, "PART %s\n", current_channel);
1913 write_irc(IRC_buffer);
1915 strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
1919 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1920 strncpy(wanted_channel, buffer, SMALL_BUFFER_SIZE);
1922 uncap(wanted_channel);
1923 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
1924 write_irc(IRC_buffer);
1927 tell(chat, nick, "Can't join right now, retry in a while\n");
1928 } else no_authorized = 1;
1930 else if(eq("op", buffer))
1932 if(level >= LEVEL_OP)
1934 if(r == NULL) add_mode(current_channel, "+o", nick);
1938 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1939 add_mode(current_channel, "+o", buffer);
1942 else no_authorized = 1;
1944 else if(eq("nick", buffer))
1946 if(level >= LEVEL_OP)
1950 r = next_word(wanted_nick, r, SMALL_BUFFER_SIZE);
1951 sprintf(buffer, "NICK %s\n", wanted_nick);
1954 } else no_authorized = 1;
1956 else if(eq("db", buffer) || eq("deban", buffer))
1958 if(level >= LEVEL_OP)
1962 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1963 if(is_pattern(buffer))
1965 NodeList<char *> *node;
1966 for(node = banid_list.first; node != NULL; node = node->next)
1967 if(match_pattern(buffer, node->body))
1968 add_mode(current_channel, "-b", node->body);
1972 wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
1973 MODE_UNBAN_NICK, 0));
1974 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
1975 write_irc(IRC_buffer);
1978 } else no_authorized = 1;
1980 else if((cmd == CMD_BAN) || (cmd == CMD_SBAN))
1982 if(level >= LEVEL_OP)
1986 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
1989 if(is_pattern(buffer))
1991 banid = clean_banid(buffer);
1992 smart_ban(current_channel, banid);
2000 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2004 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2010 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2011 write_irc(IRC_buffer);
2015 else no_authorized = 1;
2017 else if(eq("pb", buffer) || eq("pruneban", buffer))
2019 if(level >= LEVEL_OP)
2023 NodeList<char *> *node;
2025 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2029 for(node = banid_list.first; node != NULL;
2031 if(n == 0) add_mode(current_channel, "-b", node->body);
2035 } else no_authorized = 1;
2037 else if(eq("synch", buffer))
2039 if(level >= LEVEL_OP) synch(current_channel);
2040 else no_authorized = 1;
2042 else if(eq("cop", buffer))
2044 if(level >= LEVEL_OP)
2046 cop_mode = !cop_mode;
2047 if(cop_mode) tell(chat, nick, "cop mode ON\n");
2048 else tell(chat, nick, "cop mode OFF\n");
2050 else no_authorized = 1;
2052 else if(eq("s", buffer) || eq("shit", buffer))
2054 if(level >= LEVEL_OP)
2058 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2060 if(is_pattern(buffer))
2064 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2065 duration = string_to_seconds(buffer_time);
2067 else duration = DEFAULT_SHIT_TIME;
2069 if(r == NULL) r = "Shit nick";
2072 banid = clean_banid(buffer);
2073 smart_shit(chat, nick, banid, r, duration);
2080 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2081 duration = string_to_seconds(buffer_time);
2083 else duration = DEFAULT_SHIT_TIME;
2085 if(r == NULL) r = "Shit nick";
2088 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2092 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2093 write_irc(IRC_buffer);
2097 else no_authorized = 1;
2100 else if(eq("fk", buffer) || eq("filterkick", buffer))
2102 if(level >= LEVEL_OP)
2106 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2108 if(is_pattern(buffer))
2110 if(r == NULL) r = "Filter kick";
2111 filter_kick(current_channel, buffer, r);
2115 if(r == NULL) r = "Filter Kick";
2116 wait_list.Insert(new
2117 WaitInfos(buffer, r, chat, nick,
2118 MODE_FILTER_KICK, 0));
2119 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2120 write_irc(IRC_buffer);
2124 else no_authorized = 1;
2127 else if(eq("a", buffer) || eq("alert", buffer))
2129 if(level >= LEVEL_OP) alert(current_channel, chat, nick);
2130 else no_authorized = 1;
2133 else if(eq("sh", buffer) || eq("shithost", buffer))
2135 if(level >= LEVEL_OP)
2139 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2143 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2144 duration = string_to_seconds(buffer_time);
2146 else duration = DEFAULT_SHIT_TIME;
2148 if(r == NULL) r = "Shit host";
2151 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2152 MODE_SHIT_HOST, duration));
2154 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2155 write_irc(IRC_buffer);
2158 else no_authorized = 1;
2160 else if(eq("ss", buffer) || eq("shitsite", buffer))
2162 if(level >= LEVEL_OP)
2166 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2170 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2171 duration = string_to_seconds(buffer_time);
2173 else duration = DEFAULT_SHIT_TIME;
2175 if(r == NULL) r = "Shit site";
2178 wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
2179 MODE_SHIT_SITE, duration));
2181 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2182 write_irc(IRC_buffer);
2185 else no_authorized = 1;
2187 else if(eq("pus", buffer) || eq("punshit", buffer))
2189 if(level >= LEVEL_OP)
2193 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2195 if(strlen(buffer) > 0)
2197 NodeList<Welcome *> *node, *next, *pred;
2200 node = shit_list.first;
2204 if(match_pattern(buffer, node->body->pattern))
2206 smart_unban(current_channel, node->body->pattern);
2207 if(pred == NULL) shit_list.first = next;
2208 else pred->next = next;
2211 node->body->pattern,
2212 node->body->comment);
2213 tell(chat, nick, IRC_buffer);
2223 else no_authorized = 1;
2225 else if(eq("us", buffer) || eq("unshit", buffer))
2227 if(level >= LEVEL_OP)
2231 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2234 if(is_pattern(buffer))
2236 NodeList<Welcome *> *node, *next, *pred;
2239 node = shit_list.first;
2243 if(strcmp(node->body->pattern, buffer) == 0)
2245 if(pred == NULL) shit_list.first = next;
2246 else pred->next = next;
2249 buffer, node->body->comment);
2250 tell(chat, nick, IRC_buffer);
2260 wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
2261 MODE_UNSHIT_NICK, 0));
2263 sprintf(IRC_buffer, "WHOIS %s\n", buffer);
2264 write_irc(IRC_buffer);
2268 else no_authorized = 1;
2270 else if(eq("friend", buffer))
2272 if(level >= LEVEL_MASTER)
2276 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2279 r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
2280 l = atoi(buffer_time);
2281 if((l > 0) && (l<=LEVEL_MASTER))
2283 level_list.Insert(new Person(buffer, l, r));
2285 "Adding %s with level %d and passwd %s\n",
2287 tell(chat, nick, IRC_buffer);
2288 SaveConfigFile(config_file);
2293 else no_authorized = 1;
2295 else if(eq("opdelay", buffer))
2297 if(level >= LEVEL_MASTER)
2301 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2303 if((od>=0) && (od <= 60))
2306 sprintf(IRC_buffer,"Op delay set to %ds\n", op_delay);
2307 tell(chat, nick, IRC_buffer);
2311 else no_authorized = 1;
2313 else if(eq("debandelay", buffer))
2315 if(level >= LEVEL_MASTER)
2319 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2321 if((od>=0) && (od <= 60))
2325 "Deban delay set to %ds\n",
2327 tell(chat, nick, IRC_buffer);
2331 else no_authorized = 1;
2333 else if(eq("controlchar", buffer))
2335 if(level >= LEVEL_MASTER)
2339 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2340 control_char = buffer[0];
2341 sprintf(IRC_buffer, "Control char set to '%c'\n",
2343 tell(chat, nick, IRC_buffer);
2346 else no_authorized = 1;
2348 else if(eq("die", buffer))
2350 if(level >= LEVEL_MASTER)
2352 sprintf(IRC_buffer, "QUIT :Killed by %s\n", nick);
2353 write_irc(IRC_buffer);
2356 else no_authorized = 1;
2358 else if(eq("server", buffer))
2360 if(level >= LEVEL_MASTER)
2364 next_word(wanted_server, r, SMALL_BUFFER_SIZE);
2367 next_word(buffer, r, SMALL_BUFFER_SIZE);
2368 wanted_port = atoi(buffer);
2369 if(wanted_port == 0) wanted_port = 6667;
2371 else wanted_port = DEFAULT_PORT;
2374 "Trying to connect %s:%d\n",
2375 wanted_server, wanted_port);
2376 tell(chat, nick, IRC_buffer);
2378 sprintf(IRC_buffer, "QUIT :Changing server\n");
2379 write_irc(IRC_buffer);
2382 cerr<<"KILLING CONNECTION : Changing server\n";
2388 else no_authorized = 1;
2390 else if(eq("clone", buffer))
2392 if(level >= LEVEL_MASTER)
2396 if(nb_sons < NB_SONS_MAX)
2398 if(r != NULL) next_word(buffer, r, SMALL_BUFFER_SIZE);
2402 else tell(chat, nick, "Too many clones, can't clone\n");
2406 tell(chat, nick, "I'm a clone, can't clone\n");
2409 else no_authorized = 1;
2411 else if(eq("save", buffer))
2413 if(level >= LEVEL_MASTER)
2415 if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
2416 if(SaveConfigFile(config_file))
2419 "Can't save the %s configuration file\n",
2425 "Saving the %s configuration file\n",
2428 tell(chat, nick, IRC_buffer);
2430 else no_authorized = 1;
2432 else if(eq("load", buffer))
2434 if(level >= LEVEL_MASTER)
2436 if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
2437 if(LoadConfigFile(config_file, 0))
2440 "Can't load the %s configuration file\n",
2446 "Loading the %s configuration file\n",
2449 tell(chat, nick, IRC_buffer);
2451 else no_authorized = 1;
2453 else if(eq("reset", buffer))
2455 if(level >= LEVEL_MASTER)
2457 sprintf(IRC_buffer, "QUIT :reset command sent by %s\n", nick);
2458 write_irc(IRC_buffer);
2460 cerr<<"KILLING CONNECTION : Die\n";
2465 else no_authorized = 1;
2468 // DCC CHAT only commands
2470 else if((chat != NULL) && (eq("t", buffer) || eq("talk", buffer)))
2472 NodeList<DCCChat *> *node;
2473 sprintf(IRC_buffer, "<%s> %s\n", prefix, r);
2474 for(node = dcc_chat_list.first; node != NULL; node = node->next)
2475 if(node->body != chat) tell(node->body, NULL, IRC_buffer);
2477 else if((chat != NULL) && (eq("u", buffer) || eq("users", buffer)))
2479 for(node = dcc_chat_list.first; node != NULL; node = node->next)
2481 sprintf(IRC_buffer, "%s\n", node->body->prefix);
2482 tell(chat, NULL, IRC_buffer);
2488 else if(dont_flood_server())
2490 sprintf(IRC_buffer, "Unknown command \002%s\002\n", buffer);
2491 tell(chat, nick, IRC_buffer);
2497 if(dont_flood_server())
2500 "You are not authorized to use \002%s\002\n", buffer);
2501 tell(chat, nick, IRC_buffer);
2507 if(*r == '&') r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2508 add_in_history(prefix, r);
2512 //-----------------------------------------------------------------------------
2514 int accepting_dcc_chat(char *prefix, char *nick, int level, char *r)
2516 NodeList<DCCChat *> *node;
2517 int socket, port_number;
2518 char host[SMALL_BUFFER_SIZE], port[SMALL_BUFFER_SIZE];
2521 if(r == NULL) return 1;
2522 else r = next_word(host, r, SMALL_BUFFER_SIZE);
2524 if(strcmp(host, "chat") != 0) return 1;
2526 if(r == NULL) return 1;
2527 else r = next_word(host, r, SMALL_BUFFER_SIZE);
2529 if(r == NULL) return 1;
2530 else r = next_word(port, r, SMALL_BUFFER_SIZE);
2532 port_number = atoi(port);
2533 socket = call_socket(host, port_number);
2535 if(socket <= 0) return 1;
2538 dcc_chat = new DCCChat(prefix, socket, port_number);
2539 dcc_chat_list.Insert(dcc_chat);
2541 FD_SET(socket, &ready);
2544 "Welcome to \002TropBot\002 " VERSION " on a DCC CHAT\n"
2545 "You are known as %s, your level is %d.\n"
2546 "You are client #%d on DCC CHAT\n",
2547 prefix, level, dcc_chat_list.Lenght());
2549 write(socket, IRC_buffer, strlen(IRC_buffer));
2551 sprintf(IRC_buffer, "%s arrives with level %d.\n", prefix, level);
2552 for(node=dcc_chat_list.first; node!= NULL; node = node->next)
2553 if(node->body != dcc_chat) tell(node->body, NULL, IRC_buffer);
2559 //-----------------------------------------------------------------------------
2561 void pong_reply(char *nick, char *value)
2563 NodeList<WaitPing *> *node, *next, *pred;
2565 cout<<"pong_reply : nick >"<<nick<<"< value >"<<value<<"<\n";
2568 node = wait_ping.first;
2572 if(current_time > node->body->time_max)
2574 if(pred == NULL) wait_ping.first = next;
2575 else pred->next = next;
2579 if(strcmp(nick, node->body->nick) == 0)
2581 if(strcmp(value, node->body->value) == 0)
2582 add_mode(current_channel, "+o", nick);
2584 if(pred == NULL) wait_ping.first = next;
2585 else pred->next = next;
2594 // This function is called after a NOTICE
2595 void IRC_NOTICE(char *prefix,
2596 char *who, char *msg, char **slice_ctcp, int n_ctcp)
2599 char word[SMALL_BUFFER_SIZE], *r, *nick;
2601 if(strcmp(who, current_channel) == 0) add_flood_line(prefix, FL_NOTICE, 1);
2603 else if(strcmp(who, real_nick) == 0)
2604 for(k=0; k<n_ctcp; k++)
2606 cout<<"ctcp >"<<slice_ctcp[k]<<"<\n";
2608 r = next_word(word, r, SMALL_BUFFER_SIZE);
2609 if(strcmp(word, "PING") == 0)
2611 nick = cut_nick_from_prefix(prefix);
2612 r = next_word(word, r, SMALL_BUFFER_SIZE);
2613 pong_reply(nick, word);
2620 void IRC_PRIVMSG(char *prefix,
2621 char *who, char *msg, char **slice_ctcp, int n_ctcp)
2623 int k, version, ping, level, ctcp, kick;
2624 char *nick, *r, *pattern, *banid;
2625 char buffer[SMALL_BUFFER_SIZE];
2628 nick = cut_nick_from_prefix(prefix);
2630 level = level_person(prefix, NULL);
2633 if(strcmp(who, current_channel) == 0)
2635 add_flood_line(prefix, FL_PUBLIC, 1);
2639 add_flood_line(prefix, FL_CTCP, n_ctcp);
2641 if((cop_mode) && (level < LEVEL_FRIEND))
2644 for(k = 0; (k<n_ctcp) && !ctcp; k++)
2647 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2648 if(strcmp(buffer, "ACTION") != 0) ctcp =1;
2651 if(!kick && (r != NULL) && (bad_line(r, buffer)))
2653 sprintf(IRC_buffer,"KICK %s %s :cop : %s\n",
2654 current_channel, nick, buffer);
2655 write_irc(IRC_buffer);
2661 if(!kick) if(ctcp) if(level < LEVEL_FRIEND)
2663 pattern = pattern_from_prefix(prefix, 0);
2664 banid = clean_banid(pattern);
2665 smart_shit(NULL, NULL, pattern, "cop : no ctcp",
2666 COP_DURATION + deban_delay);
2667 smart_ban(current_channel, pattern);
2668 send_mode(current_channel);
2669 sprintf(IRC_buffer, "KICK %s %s :cop : no ctcp\n",
2670 current_channel, nick);
2671 write_irc(IRC_buffer);
2678 else if(cop_mode) if(level < LEVEL_FRIEND)
2679 if(!kick) if((msg != NULL) && bad_line(msg, buffer))
2681 sprintf(IRC_buffer, "KICK %s %s :cop : %s\n",
2682 current_channel, nick, buffer);
2683 write_irc(IRC_buffer);
2687 if(msg != NULL) if(strlen(msg)>0)
2689 if(msg[0] == control_char) tropbot_cmd(NULL, prefix, nick, msg+1);
2690 else if(strcmp(who, real_nick) == 0)
2691 tropbot_cmd(NULL, prefix, nick, msg);
2696 for(k=0; k<n_ctcp; k++)
2699 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2701 // Reply the CTCP VERSION
2702 if(eq("VERSION", buffer) && !version)
2704 if(dont_flood_server())
2707 sprintf(IRC_buffer, "NOTICE %s :"
2708 "\001VERSION \002TropBot\002 " VERSION OPTIONS
2709 ", " SYSTEM " system, " DATE ". "
2710 "Contact THX-1138 on IRCNet, or <francois.fleuret@inria.fr>"
2713 write_irc(IRC_buffer);
2716 // Reply the CTCP PING
2717 else if(eq("PING", buffer) && !ping)
2721 if(dont_flood_server())
2724 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2726 "NOTICE %s :\001PING %s\001\n", nick, buffer);
2727 write_irc(IRC_buffer);
2731 else if(eq("DCC", buffer))
2733 if(level >= LEVEL_OP)
2737 r = next_word(buffer, r, SMALL_BUFFER_SIZE);
2738 if(eq("CHAT", buffer))
2740 if(accepting_dcc_chat(prefix, nick, level, r) != 0)
2742 sprintf(IRC_buffer, "NOTICE %s :\002Error\002"
2743 " can't connect\n", nick);
2744 write_irc(IRC_buffer);
2750 "NOTICE %s :I can only DCC CHAT\n", nick);
2751 write_irc(IRC_buffer);
2755 else if(dont_flood_server())
2758 "NOTICE %s :Sorry, can't accept DCC from you\n",
2760 write_irc(IRC_buffer);
2767 //-----------------------------------------------------------------------------
2769 // This function is called after a QUIT
2771 void IRC_QUIT(char *prefix)
2773 present_people.Remove(prefix);
2776 //-----------------------------------------------------------------------------
2778 // This function is called after a NICK
2780 void IRC_NICK(char *prefix, char *nick)
2784 add_flood_line(prefix, FL_NICK, 1);
2785 present_people.Remove(prefix);
2787 t = nick; while(*t != '\0') *s++=*t++; // copy the nick
2788 *s++='!'; // put the '!'
2789 t = reach_loginathost(prefix);
2790 while(*t != '\0') *s++=*t++; // copy the user@host
2791 *s = '\0'; // end of string
2792 present_people.Add(IRC_buffer); // hop !
2794 ok = 1; s = prefix; t = real_nick;
2795 while(ok && (*t != '\0') && (*s != '\0')) ok = (*s++ == *t++);
2796 if(ok && (*t == '\0') && (*s == '!'))
2798 strncpy(real_nick, nick, SMALL_BUFFER_SIZE);
2803 //-----------------------------------------------------------------------------
2805 // This function is called after a PART
2807 void IRC_PART(char *prefix, char *where)
2810 add_flood_line(prefix, FL_PART, 1);
2811 present_people.Remove(prefix);
2812 nick = cut_nick_from_prefix(prefix);
2813 if(strcmp(real_nick, nick) == 0)
2815 present_people.Clear();
2821 //-----------------------------------------------------------------------------
2823 // This function is called after a KICK
2825 void IRC_KICK(char *prefix, char *where, char *victim_nick)
2830 if(strcmp(victim_nick, real_nick) == 0)
2832 present_people.Clear();
2834 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
2835 write_irc(IRC_buffer);
2838 c = strdup(prefix_from_nick(victim_nick));
2840 if((level_person(prefix, NULL) < level_person(prefix_from_nick(victim_nick), NULL)) &&
2841 (level_person(prefix_from_nick(victim_nick), NULL) > 0))
2843 d = cut_nick_from_prefix(prefix);
2844 add_mode(where, "-o", d);
2847 else if(cop_mode && (c != NULL)) add_kick(c);
2849 if(c != NULL) present_people.Remove(c);
2851 else cerr<<"** ERROR : non present person has been kicked out **\n";
2857 //-----------------------------------------------------------------------------
2859 int check_restricted(char *where, char *prefix)
2861 char pattern[SMALL_BUFFER_SIZE];
2862 NodeList<char *> *node;
2866 p = adr_beginning(prefix);
2868 node = present_people.first;
2870 while((node != NULL) && (n < 2))
2872 s = adr_beginning(node->body);
2873 if(strcmp(s, p) == 0) n++;
2883 duration = DEFAULT_RESTRICTED_TIME + deban_delay;
2884 smart_shit(NULL, NULL, pattern, "Restricted site : no clones", duration);
2885 smart_ban(where, pattern);
2887 filter_kick(where, pattern, "Restricted site : no clones");
2893 // This function is called after a JOIN
2895 void IRC_JOIN(char *prefix, char *where)
2898 int k, l, restricted;
2899 NodeList<Welcome *> *node;
2900 char buffer[SMALL_BUFFER_SIZE];
2902 nick = cut_nick_from_prefix(prefix);
2904 if(strcmp(real_nick, nick) == 0)
2906 strncpy(current_channel, where, SMALL_BUFFER_SIZE);
2907 sprintf(IRC_buffer, "WHO %s\n", where);
2908 write_irc(IRC_buffer);
2909 present_people.Clear();
2910 global_state = STATE_GETING_WHO;
2915 add_flood_line(prefix, FL_JOIN, 1);
2918 present_people.Add(prefix);
2920 l = level_person(prefix, NULL);
2922 if((l < LEVEL_FRIEND) && (restricted_list.Matches(prefix)))
2923 restricted = check_restricted(where, prefix);
2924 else restricted = 0;
2929 if(l >= LEVEL_FRIEND)
2931 for(k=0; k<10; k++) buffer[k] = 'a'+int(rand()%26);
2933 wait_ping.Insert(new WaitPing(nick, buffer,
2934 current_time+ANTI_SPOOF_MAX_TIME));
2935 sprintf(IRC_buffer, "PRIVMSG %s :\001PING %s\001\n",
2937 write_irc(IRC_buffer);
2944 if(l >= LEVEL_DEFENCE) add_mode(where, "+o", nick);
2946 mode_change_list.Insert(new DelayModeChange(where, "+o",
2952 if(banid_list.Matches(prefix))
2954 sprintf(IRC_buffer, "KICK %s %s :You are banned\n", where, nick);
2955 write_irc(IRC_buffer);
2959 for(node = shit_list.first; node != NULL; node = node->next)
2960 if(match_pattern(node->body->pattern, prefix))
2962 smart_ban(where, node->body->pattern);
2963 send_mode(current_channel);
2965 sprintf(IRC_buffer, "KICK %s %s :%s\n",
2966 where, nick, node->body->comment);
2968 write_irc(IRC_buffer);
2978 //-----------------------------------------------------------------------------
2980 void IRC_RPL_BANLIST(char *prefix, char *channel, char *banid)
2982 banid_list.Add(banid);
2985 void IRC_ENDOFBANLIST(char *prefix)
2987 banid_list.Reverse();
2988 global_state = STATE_WAIT;
2991 void IRC_RPL_ENDOFWHOIS(char *prefix, char *nick)
2993 NodeList<WaitInfos *> *node, *pred, *next;
2996 node = wait_list.first;
3001 if(strcmp(nick, node->body->nick) == 0)
3003 sprintf(IRC_buffer, "Can't find %s\n", nick);
3004 tell(node->body->chat, node->body->user, IRC_buffer);
3006 if(pred == NULL) wait_list.first = next;
3007 else pred->next = next;
3016 void IRC_RPL_WHOISUSER(char *prefix,
3017 char *nick, char *login, char *host, char *real_name)
3019 char *c, *d, *banid;
3021 char buffer[SMALL_BUFFER_SIZE];
3022 NodeList<WaitInfos *> *node, *next, *pred;
3024 int no_pattern, one_login, all_machines;
3031 node = wait_list.first;
3036 if(strcmp(nick, node->body->nick) == 0)
3040 no_pattern = (node->body->mode == MODE_UNSHIT_NICK) ||
3041 (node->body->mode == MODE_LEVEL) ||
3042 (node->body->mode == MODE_UNBAN_NICK) ||
3043 (node->body->mode == MODE_SHITLIST);;
3045 one_login = (node->body->mode == MODE_SHIT_NICK) ||
3046 (node->body->mode == MODE_BAN_NICK);
3048 all_machines = (node->body->mode == MODE_SHIT_NICK) ||
3049 (node->body->mode == MODE_BAN_NICK) ||
3050 (node->body->mode == MODE_BAN_SITE) ||
3051 (node->body->mode == MODE_FILTER_KICK) ||
3052 (node->body->mode == MODE_SHIT_SITE) ||
3053 (node->body->mode == MODE_MSG);
3066 if((*login == '~') || (*login == '+') ||
3067 (*login == '-') || (*login=='^'))
3076 while((*login != '\0') && ((l<7) || *(login+1) == '\0'))
3077 { *c++ = *login++; l++; }
3078 if(*login != '\0') *c++ = '*';
3083 d = adr_beginning(host);
3084 if(host != d) if(*(c-1) != '*') *c++ = '*';
3086 if(all_machines) concat_pattern_from_host(c, d);
3096 banid = clean_banid(buffer);
3098 if(node->body->mode == MODE_MSG)
3099 msg_users(node->body->chat, node->body->user,
3100 banid, node->body->comment);
3102 else if(node->body->mode == MODE_FILTER_KICK)
3103 filter_kick(current_channel, banid, node->body->comment);
3105 else if((node->body->mode == MODE_BAN_NICK) ||
3106 (node->body->mode == MODE_BAN_SITE))
3107 smart_ban(current_channel, banid);
3109 else if((node->body->mode == MODE_SHIT_NICK)
3110 || (node->body->mode == MODE_SHIT_SITE)
3111 || (node->body->mode == MODE_SHIT_HOST))
3113 smart_shit(node->body->chat,
3114 node->body->user, banid, node->body->comment,
3115 node->body->duration);
3117 if(prefix_from_nick(nick) != NULL)
3119 smart_ban(current_channel, banid);
3120 send_mode(current_channel);
3121 sprintf(IRC_buffer, "KICK %s %s :%s\n",
3122 current_channel, nick, node->body->comment);
3123 write_irc(IRC_buffer);
3128 else if(node->body->mode == MODE_SHITLIST)
3129 notice_shit_list(NULL, node->body->user, banid, 0);
3131 else if(node->body->mode == MODE_LEVEL)
3133 sprintf(IRC_buffer, "%s is level %d\n",
3134 banid, level_person(banid, NULL));
3135 tell(node->body->chat, node->body->user, IRC_buffer);
3137 else if(node->body->mode == MODE_UNSHIT_NICK)
3139 NodeList<Welcome *> *node2, *pred, *next;
3141 node2 = shit_list.first;
3143 while(node2 != NULL)
3146 if(match_pattern(node2->body->pattern, banid))
3148 if(pred == NULL) shit_list.first = next;
3149 else pred->next = next;
3151 sprintf(IRC_buffer, "Unshit %s (%s)\n",
3152 node2->body->pattern, node2->body->comment);
3154 tell(node->body->chat, node->body->user, IRC_buffer);
3156 smart_unban(current_channel, node2->body->pattern);
3165 else if(node->body->mode == MODE_UNBAN_NICK)
3167 NodeList<char *> *node2;
3168 for(node2 = banid_list.first; node2 != NULL; node2 = node2->next)
3169 if(match_pattern(node2->body, banid))
3170 add_mode(current_channel, "-b", node2->body);
3176 if(pred == NULL) wait_list.first = next;
3177 else pred->next = next;
3186 // This function is called after a RPL_WHOREPLY
3188 void IRC_RPL_WHOREPLY(char *prefix,
3190 char *login, char *host, char *server,
3191 char *nick, char *state)
3198 if((global_state == STATE_GETING_WHO) &&
3199 (strcmp(where, current_channel) == 0))
3202 t = nick; while(*t != '\0') *s++ = *t++;
3204 t = login; while(*t != '\0') *s++ = *t++;
3206 t = host; while(*t != '\0') *s++ = *t++;
3208 present_people.Add(IRC_buffer);
3211 else cerr<<where<<"!="<<current_channel<<"\n";
3215 void IRC_RPL_ENDOFWHO(char *prefix, char *name)
3217 sprintf(IRC_buffer, "MODE %s +b\n", current_channel);
3218 write_irc(IRC_buffer);
3220 if(in_channel) global_state = STATE_GETING_BAN;
3221 else global_state = STATE_WAIT;
3224 //-----------------------------------------------------------------------------
3226 void IRC_ERR_NICKNAMEINUSE(char *prefix, char *channel)
3228 rand_nick(wanted_nick, jam_nick);
3229 #ifdef SCREEN_OUTPUT
3230 cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
3232 sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
3233 write_irc(IRC_buffer);
3234 was_killed = 1; // We have been killed (I said PARANOID !)
3235 time_killed = current_time; // Note when it happens
3238 //-----------------------------------------------------------------------------
3240 // This function is called after a ERR_NOSUCHCHANNEL
3242 void IRC_ERR_NOSUCHCHANNEL(char *prefix, char *nick)
3244 strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
3245 uncap(wanted_channel);
3248 //-----------------------------------------------------------------------------
3250 // This function is called after a ERR_NICKCOLLISION (436)
3252 void IRC_ERR_NICKCOLLISION(char *prefix, char *nick)
3254 rand_nick(wanted_nick, jam_nick);
3255 #ifdef SCREEN_OUTPUT
3256 cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
3258 sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
3259 write_irc(IRC_buffer);
3260 was_killed = 1; // We have been killed (I said PARANOID !)
3261 time_killed = current_time; // Note when it happens
3264 //-----------------------------------------------------------------------------
3266 // This is the main command. It is called for each line from the server.
3268 void get_command(char *prefix,
3269 char **slice_cmd, int n_cmd,
3270 char **slice_ctcp, int n_ctcp)
3272 char small_buffer[SMALL_BUFFER_SIZE];
3277 #ifdef SCREEN_OUTPUT
3279 cout<<"from "<<prefix<<" ";
3281 for(k=0; k<n_cmd; k++) cout<<"["<<slice_cmd[k]<<"]";
3282 if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<slice_ctcp[k]<<">";
3284 for(k=0; k<n_cmd; k++) cout<<"["<<(void *) slice_cmd[k]<<"]";
3285 if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<(void *) slice_ctcp[k]<<">";
3289 if(prefix != NULL) uncap(prefix);
3291 // No prefix : server command
3294 if(n_cmd > 0) if(eq("PING", cmd))
3296 if(n_cmd >= 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]);
3297 else sprintf(IRC_buffer, "PONG\n");
3298 write_irc(IRC_buffer);
3303 // If we are not registred yet, then get the registration
3308 strncpy(real_nick, slice_cmd[1], SMALL_BUFFER_SIZE);
3311 sprintf(small_buffer, "MODE %s +i\n", real_nick);
3312 write_irc(small_buffer);
3313 sprintf(small_buffer, "JOIN %s\n", wanted_channel);
3314 write_irc(small_buffer);
3317 else if(eq("PRIVMSG", cmd))
3318 IRC_PRIVMSG(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
3319 else if(eq("NOTICE", cmd))
3320 IRC_NOTICE(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
3321 else if(eq("MODE", cmd))
3322 IRC_MODE(slice_cmd[1], prefix, slice_cmd[2], slice_cmd+3);
3323 else if(eq("JOIN", cmd)) IRC_JOIN(prefix, slice_cmd[1]);
3324 else if(eq("KICK", cmd)) IRC_KICK(prefix, slice_cmd[1], slice_cmd[2]);
3325 else if(eq("QUIT", cmd)) IRC_QUIT(prefix);
3326 else if(eq("NICK", cmd)) IRC_NICK(prefix, slice_cmd[1]);
3327 else if(eq("PART", cmd)) IRC_PART(prefix, slice_cmd[1]);
3328 else if(eq("311", cmd))
3329 IRC_RPL_WHOISUSER(prefix,
3330 slice_cmd[2], slice_cmd[3], slice_cmd[4],
3332 else if(eq("318", cmd)) IRC_RPL_ENDOFWHOIS(prefix, slice_cmd[2]);
3333 else if(eq("352", cmd))
3334 IRC_RPL_WHOREPLY(prefix,
3335 slice_cmd[2], slice_cmd[3], slice_cmd[4],
3336 slice_cmd[5], slice_cmd[6], slice_cmd[7]);
3337 else if(eq("315", cmd)) IRC_RPL_ENDOFWHO(prefix, slice_cmd[1]);
3338 else if(eq("367", cmd))
3339 IRC_RPL_BANLIST(prefix, slice_cmd[2], slice_cmd[3]);
3340 else if(eq("368", cmd)) IRC_ENDOFBANLIST(prefix);
3341 else if(eq("403", cmd)) IRC_ERR_NOSUCHCHANNEL(prefix, slice_cmd[1]);
3342 else if(eq("433", cmd)) IRC_ERR_NICKNAMEINUSE(prefix, slice_cmd[1]);
3343 else if(eq("436", cmd)) IRC_ERR_NICKCOLLISION(prefix, slice_cmd[1]);
3347 //-----------------------------------------------------------------------------
3349 // Rough routine to read the options
3351 void get_options(int argc, char **argv)
3359 if(eq("-p", argv[n]))
3362 if(n<argc) default_port = atoi(argv[n]);
3364 else cerr<<"*** No port parameter ***\n";
3367 else if(eq("-h", argv[n]))
3370 if(n<argc) strncpy(default_server, argv[n], MAXHOSTNAME);
3372 else cerr<<"*** No hostname parameter ***\n";
3375 else if(eq("-o", argv[n]))
3380 strncpy(config_file, argv[n], SMALL_BUFFER_SIZE);
3381 LoadConfigFile(argv[n], 0);
3384 else cerr<<"*** No friends list parameter ***\n";
3387 else if(eq("-c", argv[n]))
3390 if(n<argc) strncpy(home_channel, argv[n], SMALL_BUFFER_SIZE);
3392 else cerr<<"*** No channel parameter ***\n";
3395 else if(eq("-l", argv[n]))
3398 if(n<argc) strncpy(user_login, argv[n], SMALL_BUFFER_SIZE);
3400 else cerr<<"*** No username parameter ***\n";
3403 else if(eq("-n", argv[n]))
3406 if(n<argc) strncpy(original_nick, argv[n], SMALL_BUFFER_SIZE);
3408 else cerr<<"*** No nickname parameter ***\n";
3411 else if(eq("-j", argv[n]))
3414 if(n<argc) strncpy(jam_nick, argv[n], SMALL_BUFFER_SIZE);
3416 else cerr<<"*** No jam nickname parameter ***\n";
3419 else if(eq("-cop", argv[n]))
3423 else if(eq("-d", argv[n]))
3429 if(d>=1) socket_delay = d;
3431 else cerr<<"*** Delay error ***\n";
3435 else cerr<<"*** No delay parameter ***\n";
3438 else if(eq("-od", argv[n]))
3444 if(d>=1) op_delay = d;
3446 else cerr<<"*** Op delay error ***\n";
3450 else cerr<<"*** No delay parameter ***\n";
3453 else if(eq("-dd", argv[n]))
3459 if(d>=1) deban_delay = d;
3461 else cerr<<"*** Deban delay error ***\n";
3465 else cerr<<"*** No delay parameter ***\n";
3468 else if(eq("-?", argv[n])) help = 1;
3472 cerr<<"*** Unknown option "<<argv[n]<<" ***\n";
3479 #ifdef SCREEN_OUTPUT
3480 cout<<"Tropbot " VERSION " Written by Francois Fleuret.\n";
3481 cout<<"Compiled the " DATE " on a " SYSTEM " system.\n";
3482 cout<<"Contact <francois.fleuret@inria.fr>.\n";
3484 cout<<"Options are :\n";
3485 cout<<"-c <#channel> sets the channel\n";
3486 cout<<"-d <delay in s> sets the reconnection delay\n";
3487 cout<<"-h <hostname> sets the server name\n";
3488 cout<<"-j <jam nickname> sets the pattern nick for collision\n";
3489 cout<<"-l <user> sets the user in the user@host stuff\n";
3490 cout<<"-n <nickname> sets the nickname\n";
3491 cout<<"-o <friends file> loads configuration file\n";
3492 cout<<"-od <delay in s> set the delay before +o\n";
3493 cout<<"-dd <delay in s> set the delay before -b\n";
3494 cout<<"-p <port number> sets the server port\n";
3495 cout<<"-? shows this help\n";
3504 //-----------------------------------------------------------------------------
3506 void clean_shit_list()
3508 NodeList<Welcome *> *node, *pred, *next;
3510 node = shit_list.first;
3515 if(current_time >= node->body->time_max)
3517 if(pred == NULL) shit_list.first = next;
3518 else pred->next = next;
3520 smart_unban(current_channel, node->body->pattern);
3528 send_mode(current_channel);
3531 //-----------------------------------------------------------------------------
3533 void try_reconnect()
3535 if(delay < DELAY_MAX_RECONNECT)
3537 if(delay == 0) delay = 1;
3539 if(delay > DELAY_MAX_RECONNECT) delay = DELAY_MAX_RECONNECT;
3541 strncpy(wanted_server, default_server, MAXHOSTNAME+1);
3542 wanted_port = default_port;
3544 cerr<<"*** Can't contact IRC server ***\n";
3545 cerr<<"*** Next try in "<<delay<<" s\n";
3549 void got_connection()
3551 time_last_datas = current_time;
3553 FD_SET(socket_irc, &ready);
3554 sprintf(buffer, "USER %s x x :%s\n", user_login, user_name);
3556 sprintf(buffer, "NICK %s\n", wanted_nick);
3558 delay = socket_delay;
3561 void got_datas_from_server()
3564 char *prefix, *r, *t;
3566 char *slice_cmd[NB_SLICES_MAX], *slice_ctcp[NB_SLICES_MAX];
3567 char *dest_cmd, *dest_ctcp;
3570 char buffer_cmd[BUFFER_SIZE], buffer_ctcp[BUFFER_SIZE];
3572 time_last_datas = current_time;
3574 // If the buffer is already full, purge it
3575 if(endsrc >= buffer+BUFFER_SIZE)
3578 cerr<<"*** Buffer full, erase it ***\n";
3583 s = read(socket_irc, endsrc, buffer+BUFFER_SIZE-1-endsrc);
3590 cerr<<"KILLING CONNECTION : Read error\n";
3601 dest_cmd = buffer_cmd;
3602 dest_ctcp = buffer_ctcp;
3604 if(slice_buffer(src, endsrc,
3606 dest_cmd, slice_cmd, n_cmd,
3607 dest_ctcp, slice_ctcp, n_ctcp))
3608 // No more \r in the buffer
3612 while(r<endsrc) *t++ = *r++;
3618 // Oki, we got a full line
3619 get_command(prefix, slice_cmd, n_cmd, slice_ctcp, n_ctcp);
3627 NodeList<DelayModeChange *> *md;
3629 if(current_time > anti_flood_off_until) check_flood();
3630 check_delay_mode_change();
3631 send_mode(current_channel);
3633 delay = socket_delay;
3634 NodeList<Welcome *> *nd;
3635 for(nd = shit_list.first; nd != NULL; nd = nd->next)
3636 if(delay > nd->body->time_max-current_time)
3637 delay = nd->body->time_max-current_time;
3639 for(md = mode_change_list.first; md != NULL; md = md->next)
3640 if(delay > md->body->time-current_time)
3641 delay = md->body->time-current_time;
3643 if(delay < 0) delay = 0;
3648 NodeList<DCCChat *> *node, *pred, *next, *node2;
3649 char CHAT_buffer[BUFFER_SIZE];
3652 pred = NULL; next = NULL;
3653 node = dcc_chat_list.first;
3657 if(FD_ISSET(node->body->socket, &result))
3659 s = read(node->body->socket, CHAT_buffer, BUFFER_SIZE-1);
3662 FD_CLR(node->body->socket, &ready); // Forget the socket
3663 close(node->body->socket);
3665 sprintf(IRC_buffer, "%s leaves.\n", node->body->prefix);
3666 for(node2=dcc_chat_list.first; node2!= NULL; node2 = node2->next)
3667 if(node2->body != node->body)
3668 tell(node2->body, NULL, IRC_buffer);
3670 remove_wait_for_chat(node->body);
3672 if(pred == NULL) dcc_chat_list.first = next;
3673 else pred->next = next;
3679 *(CHAT_buffer+s-1) = '\0';
3680 tropbot_cmd(node->body, node->body->prefix, NULL, CHAT_buffer);
3690 int main(int argc, char **argv)
3693 // I think it's a good idea to have few friends forever (me ? yeahhh !)
3694 level_list.Insert(new Person("*!*fleuret@*.inria.fr", LEVEL_MASTER, NULL));
3695 level_list.Insert(new Person("*!*fleuret@*.ens.fr", LEVEL_MASTER, NULL));
3696 level_list.Insert(new Person("*!*fleuret@*.curie.fr", LEVEL_MASTER, NULL));
3697 level_list.Insert(new Person("*!*jolibot@*.inria.fr", LEVEL_DEFENCE, NULL));
3698 level_list.Insert(new Person("*!*jolibot@*.ens.fr", LEVEL_DEFENCE, NULL));
3699 level_list.Insert(new Person("*!*jolibot@*.curie.fr", LEVEL_DEFENCE, NULL));
3701 #ifdef SCREEN_OUTPUT
3702 cout<<"TropBot, written by Francois Fleuret,"
3703 " contact <francois.fleuret@inria.fr>\n";
3706 get_options(argc, argv);
3708 uncap(home_channel);
3709 strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
3710 strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
3711 strncpy(wanted_server, default_server, MAXHOSTNAME+1);
3712 wanted_port = default_port;
3714 IRC_registred = 0; // true if we are registred
3715 IRC_connected = 0; // true if we have a connection with an IRC server
3716 global_state = STATE_WAIT;
3718 mode_protect_on = DEFAULT_MODE_PROTECT;
3727 last_answer_time = 0;
3728 anti_flood_off_until = 0;
3732 delay = socket_delay;
3734 struct sigaction action;
3735 memset(&action, 0, sizeof(action));
3736 action.sa_handler = SIG_IGN;
3738 // We'll ignore the SIGPIPE signal, which will be catch somewhere else
3739 sigaction(SIGPIPE, &action, NULL);
3745 delay_pause.tv_sec = delay;
3746 delay_pause.tv_usec = 0;
3749 while(waitpid(-1, NULL, WNOHANG) > 0) nb_sons--;
3751 select(64, &result, NULL, NULL, &delay_pause);
3753 time(¤t_time);
3759 #ifdef SCREEN_OUTPUT
3760 cout<<"No connection yet\n";
3761 cout<<"Try to contact "<<wanted_server<<":"<<wanted_port<<"\n";
3763 socket_irc = call_socket(wanted_server, wanted_port);
3765 if(socket_irc <= 0) try_reconnect();
3766 else got_connection();
3770 if((current_time > time_killed+DELAY_NICK_BACK) && was_killed)
3773 strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
3774 sprintf(buffer, "NICK %s\n", wanted_nick);
3778 if(IRC_registred) clean_shit_list();
3780 if(FD_ISSET(socket_irc, &result)) got_datas_from_server();
3783 if(current_time > time_last_datas+DELAY_DEAD_SERVER)
3786 cerr<<"KILLING CONNECTION : Quiet server\n";
3791 else if(!in_channel) if(global_state == STATE_WAIT)
3793 sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
3794 write_irc(IRC_buffer);
3798 if(IRC_connected) check_stuffs();
3799 already_kicked.Clear();
3802 #ifdef SCREEN_OUTPUT
3803 cout<<present_people.Lenght()<<" person(s) inside\n";
3804 // banid_list.Print();
3808 while(alive || (socket_irc > 0));
3812 //-----------------------------------------------------------------------------