X-Git-Url: https://www.fleuret.org/cgi-bin/gitweb/gitweb.cgi?p=tropbot.git;a=blobdiff_plain;f=tropbot.cc;h=ac6f9802781ba40c6da56732b2f14aecc5ef7938;hp=13b85b2432a7f733b71a88f808a917b42372d87c;hb=0ffeb3584fe2102ed709e9d9bac7db82fe32ab75;hpb=c6dbdbeafebf079c81ee6046761d09c3c58dfcf8 diff --git a/tropbot.cc b/tropbot.cc index 13b85b2..ac6f980 100644 --- a/tropbot.cc +++ b/tropbot.cc @@ -1,12 +1,12 @@ /*----------------------------------------------------------------------------- - TropBot, a small IRC bot, v2.6 Dec 95 - Oct 96 + TropBot, a small IRC bot, v2.9 Dec 95 - Oct 96 Witten by Francois Fleuret. Contact for comments & bug reports Check http://www.eleves.ens.fr:8080/home/fleuret for latest version -----------------------------------------------------------------------------*/ -#define VERSION "v2.6.3a" -#define OPTIONS " + patch for mode -ko stuff" +#define VERSION "v2.9.3a" +#define OPTIONS "" #include #include @@ -21,6 +21,10 @@ //----------------------------------------------------------------------------- #define SCREEN_OUTPUT +#define ERROR_OUTPUT + +//#define ANTI_SPOOF +#define ANTI_SPOOF_MAX_TIME 300 //----------------------------------------------------------------------------- @@ -32,7 +36,7 @@ #define DEFAULT_CONTROL_CHAR '|' #define DELAY_NICK_BACK 300 -#define DELAY_MAX_RECONNECT 300 +#define DELAY_MAX_RECONNECT 120 #define DELAY_DEAD_SERVER 900 #define DEFAULT_SERVER "sil.polytechnique.fr" @@ -70,7 +74,17 @@ #define HISTORY_SIZE 3 -enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN }; +enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN, FL_KICK }; + +//----------------------------------------------------------------------------- + +// More than 3 kicks in 5 minutes -> 30 mins shit + +#define COP_NB_KICKS 3 +#define COP_NB_BANS 3 +#define COP_DELAY 300 +#define COP_DURATION 1800 +#define COP_DELAY_BEETWEEN_KICKS 2 //----------------------------------------------------------------------------- @@ -98,6 +112,8 @@ int op_delay = DEFAULT_OP_DELAY; int deban_delay = DEFAULT_DEBAN_DELAY; char control_char = DEFAULT_CONTROL_CHAR; +int cop_mode, anti_flood, anti_clone, ctcp_reply; + int delay; timeval delay_pause; time_t current_time, time_killed, time_last_datas, last_answer_time, @@ -118,6 +134,7 @@ template class List; template class List; template class List; template class List; +template class List; template class List; template class List; @@ -125,6 +142,7 @@ List dcc_chat_list; List level_list; List shit_list; List wait_list; +List wait_ping; List mode_change_list; ListChar present_people, banid_list, restricted_list, history; @@ -338,8 +356,10 @@ void write_irc(char *stuff) // I'd like to know why do I have to do such a cast ?!?! if((int) write(socket_irc, stuff, strlen(stuff)) < 0) { +#ifdef ERROR_OUTPUT cerr<<"KILLING CONNECTION : write_irc error\n"; cerr.flush(); +#endif kill_connection(); } else @@ -481,7 +501,7 @@ void smart_shit(DCCChat *chat, char *nick, sprintf(IRC_buffer, "Shit %s for %s (%s)\n", pattern, string_duration, comment); tell(chat, nick, IRC_buffer); - delete string_duration; + delete[] string_duration; } } else if((nick != NULL) || (chat != NULL)) @@ -621,17 +641,24 @@ void synch(char *channel) { nick = cut_nick_from_prefix(node->body); add_mode(channel, "+o", nick); - delete nick; + delete[] nick; } } //----------------------------------------------------------------------------- +ListChar already_kicked; + void filter_kick(char *where, char *pattern, char *comment) { NodeList *node; char *nick; - for(node = present_people.first; node != NULL; node = node->next) + + if(already_kicked.Contains(pattern)) return; + + already_kicked.Add(pattern); + for(node = present_people.first; node != NULL; + node = node->next) { if(match_pattern(pattern, node->body)) if(level_person(node->body, NULL) == 0) @@ -639,7 +666,7 @@ void filter_kick(char *where, char *pattern, char *comment) nick = cut_nick_from_prefix(node->body); sprintf(IRC_buffer, "KICK %s %s :%s\n", where, nick, comment); write_irc(IRC_buffer); - delete nick; + delete[] nick; } } } @@ -684,13 +711,13 @@ public: weigth = w; } - ~FloodLine() { delete prefix; } + ~FloodLine() { delete[] prefix; } void Reset() { individual = 0; site = 0; } }; template class List; -List flood_list; +List flood_list, kick_list; //----------------------------------------------------------------------------- @@ -748,7 +775,7 @@ void alert(char *where, DCCChat *chat, char *nick) { duration = DEFAULT_SHIT_TIME; r = pattern; - *r++ = '*'; *r++ = '!'; *r++ = '*'; *r++ = '@'; + concat(r, "*!*@"); concat_pattern_from_host(r, guilty_site); add_mode(where, "+m", NULL); smart_shit(NULL, NULL, pattern, "Alert", duration); @@ -804,15 +831,15 @@ void check_one_flood(NodeList *node) mode_change_list.Insert(new DelayModeChange(current_channel, "-b", banid, BAN_FLOOD_DELAY)); - delete banid; - delete pattern; + delete[] banid; + delete[] pattern; } #endif nick = cut_nick_from_prefix(node->body->prefix); sprintf(IRC_buffer, "KICK %s %s :%s\n", current_channel, nick, "Flood"); write_irc(IRC_buffer); - delete nick; + delete[] nick; for(son = flood_list.first; son != NULL; son = son->next) { @@ -834,7 +861,7 @@ void check_flood() while(node != NULL) { next = node->next; - if(node->body->time >= current_time - FLOOD_DELAY) + if(current_time <= node->body->time + FLOOD_DELAY) { nb_lines += node->body->weigth; if((node->body->kind == FL_CTCP) && !node->body->alreadykicked) @@ -886,6 +913,143 @@ inline void add_flood_line(char *prefix, int kind, int weigth) flood_list.Insert(new FloodLine(prefix, kind, weigth)); } +int bad_line(char *line, char *comment) +{ + int length, nb_art_chars, longest_word, nb_caps, nb_letters, nb_ctrl; + int l, bad; + unsigned char *s; + char *t; + + nb_ctrl = 0; + nb_art_chars = 0; + nb_caps = 0; + nb_letters = 0; + length = 0; + l = 0; + longest_word = 0; + + for(s=(unsigned char *)line; *s != '\0'; s++) + { + if((*s >= 'A') && (*s <= 'Z')) nb_caps++; + if(((*s >= 'A') && (*s <= 'Z')) || + ((*s >= 'a') && (*s <= 'z'))) nb_letters++; + if((*s > 2) && (*s < 31)) nb_ctrl++; + if((*s != ' ') && (*s != '?') && (*s != '!') && + (((*s >= 32) && (*s <= 47)) || + ((*s >= 58) && (*s <= 63)) || + ((*s >= 91) && (*s <= 96)) || + (*s >= 123))) nb_art_chars++; + + if(s > (unsigned char *) line) + { + if(*s == *(s-1)) l++; + else + { + if(l > longest_word) longest_word = l; + l = 0; + } + } + + length++; + } + if(l > longest_word) longest_word = l; + + t = comment; + + bad = 0; + if(longest_word > 60) + { + bad = 1; + concat(t, "repeated chars"); + } + + if(nb_ctrl > 0) + { + if(bad) concat(t, " + "); + concat(t, "control chars"); + bad = 1; + } + + if((nb_art_chars > nb_letters) && (nb_art_chars >= 20)) + { + if(bad) concat(t, " + "); + concat(t, "art chars"); + bad = 1; + } + + if((nb_caps*4 > nb_letters*3) && (nb_caps >= 10)) + { + if(bad) concat(t, " + "); + concat(t, "caps"); + bad = 1; + } + + *t = '\0'; + + return bad; +} + +void test_kick(char *prefix) +{ + int nb_kicks; + int last_kick_time; + NodeList *node, *next, *pred; + char *pattern, *banid, *loginathost; + + loginathost = reach_loginathost(prefix); + + nb_kicks = 0; + last_kick_time = current_time + COP_DELAY_BEETWEEN_KICKS + 1; + pred = NULL; + node = kick_list.first; + while(node != NULL) + { + next = node->next; + if(current_time <= node->body->time + COP_DELAY) + { + if(strcmp(loginathost, reach_loginathost(node->body->prefix)) == 0) + { + if(node->body->time < last_kick_time - COP_DELAY_BEETWEEN_KICKS) + { + nb_kicks += node->body->weigth; + last_kick_time = node->body->time; + } + } + pred = node; + } + else + { + if(pred == NULL) kick_list.first = next; + else pred->next = next; + delete node->body; + delete node; + } + node = next; + } + + if(nb_kicks >= COP_NB_KICKS) + { + pattern = pattern_from_prefix(prefix, 0); + banid = clean_banid(pattern); + + smart_shit(NULL, NULL, + pattern, "cop : too many kicks", COP_DURATION + deban_delay); + smart_ban(current_channel, pattern); + send_mode(current_channel); + filter_kick(current_channel, pattern, "cop : too many kicks"); + + delete[] banid; + delete[] pattern; + } +} + +inline void add_kick(char *prefix) +{ + if(level_person(prefix, NULL) >= LEVEL_FRIEND) return; + kick_list.Insert(new FloodLine(prefix, FL_KICK, 1)); + test_kick(prefix); +} + //----------------------------------------------------------------------------- // This function is called for all mode changes @@ -896,6 +1060,10 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param) { char *c, *banid; char buffer[3]; + int check_ban, nb_bans, ok; + NodeList *node; + char pattern[SMALL_BUFFER_SIZE]; + char *adr_param; if(signe < 0) buffer[0] = '-'; else buffer[0] = '+'; buffer[1] = mode; @@ -937,10 +1105,51 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param) if(signe > 0) { + check_ban = 1; banid_list.Add(param); - banid = clean_banid(param); - if(strcmp(banid, param) != 0) smart_ban(where, banid); - delete banid; + + if(cop_mode && !is_hostname(who)) + { + adr_param = adr_beginning(param); + nb_bans = 0; + + for(node = banid_list.first; node != NULL; node = node->next) + if(are_same_site(adr_param, adr_beginning(node->body))) + nb_bans++; + + if(nb_bans >= COP_NB_BANS) + { + check_ban = 0; + c = pattern; + concat(c, "*!*@"); + concat(c, adr_param); + *c++ = '\0'; + + ok = 1; + + for(node = present_people.first; + (node != NULL) && ok; node = node->next) + if(match_pattern(pattern, node->body)) + if(level_person(node->body, NULL) >= LEVEL_FRIEND) + ok = 0; + + if(ok) + { + smart_shit(NULL, NULL, + pattern, + "cop : too many bans on one site", + COP_DURATION + deban_delay); + smart_ban(where, pattern); + } + } + } + + if(check_ban) + { + banid = clean_banid(param); + if(strcmp(banid, param) != 0) smart_ban(where, banid); + delete[] banid; + } } else banid_list.Remove(param); break; @@ -963,7 +1172,7 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param) c = cut_nick_from_prefix(who); add_mode(where, "-o", c); add_mode(where, "+o", param); - delete c; + delete[] c; } break; @@ -1000,7 +1209,7 @@ void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param) else add_mode(where, "+m", NULL); c = cut_nick_from_prefix(who); add_mode(where, "-o", c); - delete c; + delete[] c; } } break; @@ -1073,7 +1282,9 @@ void get_one_line(ifstream *s, char *buffer, int buffer_size) *c = '\0'; } -int LoadConfigFile(char *name) +#define MAX_INCLUDE_RECURSE 3 + +int LoadConfigFile(char *name, int recurse) { ifstream *file; int duration, level, error; @@ -1093,7 +1304,23 @@ int LoadConfigFile(char *name) { r = IRC_buffer; r = next_word(buffer, r, SMALL_BUFFER_SIZE); - if(strcmp(buffer, "FRIEND") == 0) + + if(strcmp(buffer, "INCLUDE") == 0) + { + if(r != NULL) + { + if(recurse < MAX_INCLUDE_RECURSE) + { + r = next_word(buffer, r, SMALL_BUFFER_SIZE); + LoadConfigFile(buffer, recurse+1); + } +#ifdef ERROR_OUTPUT + else cerr<<"Can't include " + <"<next) { (*file)<<"FRIEND "<body->level<<" "<body->pattern; @@ -1200,6 +1479,7 @@ int SaveConfigFile(char *name) (*file)<<"\n"; + (*file)<<"% Restricted-sites list\n"; for(restricted=restricted_list.first; restricted != NULL; restricted=restricted->next) @@ -1207,11 +1487,14 @@ int SaveConfigFile(char *name) (*file)<<"\n"; + (*file)<<"% Shit list\n"; for(welcome=shit_list.first; welcome != NULL; welcome=welcome->next) (*file)<<"SHIT "<body->pattern<<" "<< welcome->body->time_max - current_time<<" "<< welcome->body->comment<<"\n"; + (*file)<<"\n"; + (*file)<<"% End of config file\n"; error = 0; } else error = 1; @@ -1241,8 +1524,6 @@ void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern) buf = IRC_buffer; - cerr<<"PATTERN=>"<"<body<<"\n"; - if((pattern == NULL) || match_pattern(pattern, node1->body)) { c = adr_beginning(node1->body); @@ -1317,7 +1596,7 @@ void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern) nb_person[LEVEL_MASTER]); tell(chat, nick, IRC_buffer); - delete ok; + delete[] ok; } //----------------------------------------------------------------------------- @@ -1345,7 +1624,7 @@ void notice_shit_list(DCCChat *chat, char *nick, char *pattern, int matched) string_duration, node->body->comment); tell(chat, nick, IRC_buffer); - delete string_duration; + delete[] string_duration; } if(n == 0) tell(chat, nick, "\002No corresponding shits\002\n"); @@ -1378,7 +1657,7 @@ void add_in_history(char *prefix, char *action) { if(pred == NULL) history.first = next; else pred->next = next; - delete node->body; + delete[] node->body; delete node; } else pred = node; @@ -1423,7 +1702,7 @@ void msg_users(DCCChat *chat, char *nick, char *pattern, char *msg) sprintf(IRC_buffer, "PRIVMSG %s :\002[msg to %s]\002 %s\n", nick_user, pattern, msg); write_irc(IRC_buffer); - delete nick_user; + delete[] nick_user; } } @@ -1474,6 +1753,18 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) { if(dont_flood_server()) notice_shit_list(chat, nick, prefix, 0); } + else if(eq("write", buffer) || eq("wr", buffer)) + { + if(level >= LEVEL_MASTER) + { + if(r != NULL) + { + sprintf(IRC_buffer, "PRIVMSG %s :%s\n", current_channel, r); + write_irc(IRC_buffer); + } + } + else no_authorized = 1; + } else if(eq("sl", buffer) || eq("shitlist", buffer)) { if(level >= LEVEL_FRIEND) @@ -1483,7 +1774,8 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) r = next_word(buffer, r, SMALL_BUFFER_SIZE); uncap(buffer); - if(is_pattern(buffer)) notice_shit_list(chat, nick, buffer, 1); + if(is_pattern(buffer)) + notice_shit_list(chat, nick, buffer, 1); else { wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick, @@ -1493,7 +1785,27 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) write_irc(IRC_buffer); } } - else notice_shit_list(chat, nick, "*", 1); + else + { + int s1, s2, s3, s4, d; + NodeList *node; + s1 = 0; s2 = 0; s3 = 0; s4 = 0; + for(node=shit_list.first; node != NULL; node=node->next) + { + d = node->body->time_max - current_time; + if(d < 1800) s1++; + else if(d < 4*3600) s2++; + else if(d < 24*3600) s3++; + else s4++; + } + + sprintf(IRC_buffer, + "%d entries " + "\002%d\002 < 30min < \002%d\002 < " + "4h < \002%d\002 < 24h < \002%d\002\n", + s1+s2+s3+s4, s1, s2, s3, s4); + tell(chat, nick, IRC_buffer); + } } else no_authorized = 1; } @@ -1511,40 +1823,65 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) else while(r != NULL) { r = next_word(buffer, r, SMALL_BUFFER_SIZE); - /* - if(!is_pattern(buffer)) - { - s = buffer; - while(*s != '\0') s++; - concat(s, "!*"); - *s++ == '\0'; - } - */ uncap(buffer); notice_list_by_sites(chat, nick, buffer); } } else no_authorized = 1; } - else if(eq("ao", buffer) || eq("antifloodoff", buffer)) + else if(eq("cr", buffer) || eq("ctcpreply", buffer)) { - if(r != NULL) + if(level >= LEVEL_OP) { - r = next_word(buffer_time, r, SMALL_BUFFER_SIZE); - duration = string_to_seconds(buffer_time); - anti_flood_off_until = current_time + duration; + ctcp_reply = !ctcp_reply; + if(ctcp_reply) tell(chat, nick, "CTCP reply ON\n"); + else tell(chat, nick, "CTCP reply OFF\n"); } - if(anti_flood_off_until > current_time) + else no_authorized = 1; + } + else if(eq("ac", buffer) || eq("anticlones", buffer)) + { + if(level >= LEVEL_OP) { - string_duration = seconds_to_string(anti_flood_off_until - - current_time); - sprintf(IRC_buffer, "Anti-flood off for %s\n", - string_duration); - delete string_duration; - - tell(chat, nick, IRC_buffer); + anti_clone = !anti_clone; + if(anti_clone) tell(chat, nick, "Anti-clones ON\n"); + else tell(chat, nick, "Anti-clones OFF\n"); } - else tell(chat, nick, "Anti-flood on\n"); + else no_authorized = 1; + } + else if(eq("ao", buffer) || eq("antifloodoff", buffer)) + { + if(level >= LEVEL_OP) + { + if(r != NULL) + { + r = next_word(buffer_time, r, SMALL_BUFFER_SIZE); + duration = string_to_seconds(buffer_time); + anti_flood_off_until = current_time + duration; + anti_flood = 1; + } + else + { + anti_flood_off_until = current_time; + anti_flood = !anti_flood; + } + + if(!anti_flood) + tell(chat, nick, "Anti-flood off\n"); + if(anti_flood_off_until > current_time) + { + string_duration = seconds_to_string(anti_flood_off_until - + current_time); + sprintf(IRC_buffer, "Anti-flood off for %s\n", + string_duration); + delete[] string_duration; + + tell(chat, nick, IRC_buffer); + } + else + tell(chat, nick, "Anti-flood on\n"); + } + else no_authorized = 1; } else if(eq("msg", buffer) || eq("message", buffer)) { @@ -1599,29 +1936,41 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) } else no_authorized = 1; } - else if(eq("help", buffer)) + else if(eq("mode", buffer)) { if(dont_flood_server() || (level >= LEVEL_FRIEND)) { + char *cop, *ao, *ac, *cr; + if(cop_mode) cop = "ON"; else cop = "OFF"; + if(anti_flood) ao = "ON"; else ao = "OFF"; + if(anti_clone) ac = "ON"; else ac = "OFF"; + if(ctcp_reply) cr = "ON"; else cr = "OFF"; if(father) { sprintf(IRC_buffer, - "control_char '%c' op_delay %ds deban_delay %ds" + "control_char '%c' op_delay %ds deban_delay %ds " + "cop-mode %s anti-flood %s anti-clone %s ctcp-reply %s" " your level is %d. I am a father with %d sons.\n", control_char, op_delay, deban_delay, + cop, ao, ac, cr, level, nb_sons); tell(chat, nick, IRC_buffer); } else { sprintf(IRC_buffer, - "control_char '%c' op_delay %ds deban_delay %ds" - " your level is %d. I'm a clone.\n", - control_char, op_delay, deban_delay, level); + "control_char '%c' op_delay %ds deban_delay %ds " + "cop-mode %s anti-flood %s anti-clone %s ctcp-reply %s" + " your level is %d. I am a son.\n", + control_char, op_delay, deban_delay, + cop, ao, ac, cr, + level); tell(chat, nick, IRC_buffer); } } - + } + else if(eq("help", buffer)) + { if(level >= LEVEL_FRIEND) { tell(chat, nick, "\002help\002 \002www\002 \002\037s\037\002hit\037l\037\002ist\002 [!] \002level\002 [] \002\037w\037\002ho\002 \002\037m\037\002y\037s\037\002hit\002\n"); @@ -1629,7 +1978,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) if(level >= LEVEL_OP) { - tell(chat, nick, "\002\037a\037\002ntiflood\037o\037\002ff\002 [] \002\037a\037\002lert\002 \002home\002 \002op\002 [{ list}] \002join\002 <#channel> \002nick\002 \002\037p\037\002rune\037b\037\002an\002 \002\037d\037\002e\037b\037\002an\002 { list} \002\037f\037\002ilter\037k\037\002ick\002 ! [] \002\037s\037\002hit/\037s\037\002hit\037s\037\002ite/\037s\037\002hit\037h\037\002ost\002 ! [ []] \002\037u\037\002n\037s\037\002hit\002 {! list} \002\037pu\037\002n\037s\037\002hit\002 { list} \002\037b\037\002an/\037s\037\002ite\037b\037\002an\002 ! \002synch\002 \002\037h\037\002istory\002\n \002\037m\037\002es\037s\037\002a\037g\037\002e\002 ! \n"); + tell(chat, nick, "\002\037a\037\002ntiflood\037o\037\002ff\002 [] \002\037a\037\002lert\002 \002home\002 \002cop\002 \002op\002 [{ list}] \002join\002 <#channel> \002nick\002 \002\037p\037\002rune\037b\037\002an\002 \002\037d\037\002e\037b\037\002an\002 { list} \002\037f\037\002ilter\037k\037\002ick\002 ! [] \002\037s\037\002hit/\037s\037\002hit\037s\037\002ite/\037s\037\002hit\037h\037\002ost\002 ! [ []] \002\037u\037\002n\037s\037\002hit\002 {! list} \002\037pu\037\002n\037s\037\002hit\002 { list} \002\037b\037\002an/\037s\037\002ite\037b\037\002an\002 ! \002synch\002 \002\037h\037\002istory\002\n \002\037m\037\002es\037s\037\002a\037g\037\002e\002 ! \n"); } if(level >= LEVEL_MASTER) @@ -1730,7 +2079,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) { banid = clean_banid(buffer); smart_ban(current_channel, banid); - delete banid; + delete[] banid; } else { @@ -1779,6 +2128,16 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) if(level >= LEVEL_OP) synch(current_channel); else no_authorized = 1; } + else if(eq("cop", buffer)) + { + if(level >= LEVEL_OP) + { + cop_mode = !cop_mode; + if(cop_mode) tell(chat, nick, "cop mode ON\n"); + else tell(chat, nick, "cop mode OFF\n"); + } + else no_authorized = 1; + } else if(eq("s", buffer) || eq("shit", buffer)) { if(level >= LEVEL_OP) @@ -1801,7 +2160,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) uncap(buffer); banid = clean_banid(buffer); smart_shit(chat, nick, banid, r, duration); - delete banid; + delete[] banid; } else { @@ -2033,7 +2392,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) if((od>=0) && (od <= 60)) { op_delay = od; - sprintf(IRC_buffer,"Oping delay set to %ds\n", op_delay); + sprintf(IRC_buffer,"Op delay set to %ds\n", op_delay); tell(chat, nick, IRC_buffer); } } @@ -2108,8 +2467,10 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) sprintf(IRC_buffer, "QUIT :Changing server\n"); write_irc(IRC_buffer); +#ifdef ERROR_OUTPUT cerr<<"KILLING CONNECTION : Changing server\n"; cerr.flush(); +#endif kill_connection(); } } @@ -2162,7 +2523,7 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) if(level >= LEVEL_MASTER) { if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE); - if(LoadConfigFile(config_file)) + if(LoadConfigFile(config_file, 0)) { sprintf(IRC_buffer, "Can't load the %s configuration file\n", @@ -2184,8 +2545,10 @@ void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg) { sprintf(IRC_buffer, "QUIT :reset command sent by %s\n", nick); write_irc(IRC_buffer); +#ifdef ERROR_OUTPUT cerr<<"KILLING CONNECTION : Die\n"; cerr.flush(); +#endif kill_connection(); } else no_authorized = 1; @@ -2284,110 +2647,213 @@ int accepting_dcc_chat(char *prefix, char *nick, int level, char *r) //----------------------------------------------------------------------------- -// This function is called after a NOTICE +void pong_reply(char *nick, char *value) +{ + NodeList *node, *next, *pred; + + cout<<"pong_reply : nick >"<"<next; + if(current_time > node->body->time_max) + { + if(pred == NULL) wait_ping.first = next; + else pred->next = next; + delete node->body; + delete node; + } + if(strcmp(nick, node->body->nick) == 0) + { + if(strcmp(value, node->body->value) == 0) + add_mode(current_channel, "+o", nick); + + if(pred == NULL) wait_ping.first = next; + else pred->next = next; + delete node->body; + delete node; + } + else pred = node; + node = next; + } +} + +// This function is called after a NOTICE void IRC_NOTICE(char *prefix, char *who, char *msg, char **slice_ctcp, int n_ctcp) { + int k; + char word[SMALL_BUFFER_SIZE], *r, *nick; uncap(who); if(strcmp(who, current_channel) == 0) add_flood_line(prefix, FL_NOTICE, 1); +#ifdef ANTI_SPOOF + else if(strcmp(who, real_nick) == 0) + for(k=0; k"< 0) add_flood_line(prefix, FL_CTCP, n_ctcp); - } + if(n_ctcp > 0) + { + add_flood_line(prefix, FL_CTCP, n_ctcp); + + if((cop_mode) && (level < LEVEL_FRIEND)) + { + ctcp = 0; + for(k = 0; (k0) { if(msg[0] == control_char) tropbot_cmd(NULL, prefix, nick, msg+1); - else if(strcmp(who, real_nick) == 0) tropbot_cmd(NULL, prefix, nick, msg); + else if(strcmp(who, real_nick) == 0) + tropbot_cmd(NULL, prefix, nick, msg); } - - - version = 0; - ping = 0; - for(k=0; k" - "\001\n", - nick); - write_irc(IRC_buffer); + if(dont_flood_server()) + { + version = 1; + sprintf(IRC_buffer, "NOTICE %s :" + "\001VERSION \002TropBot\002 " VERSION OPTIONS + ", " SYSTEM " system, " DATE ". " + "Contact THX-1138 on IRCNet, or " + "\001\n", + nick); + write_irc(IRC_buffer); + } } - } - // Reply the CTCP PING - else if(eq("PING", buffer) && !ping) - { - ping = 1; - if(r != NULL) - if(dont_flood_server()) - { - ping = 1; - r = next_word(buffer, r, SMALL_BUFFER_SIZE); - sprintf(IRC_buffer, - "NOTICE %s :\001PING %s\001\n", nick, buffer); - write_irc(IRC_buffer); - } - } - // DCC (chat) - else if(eq("DCC", buffer)) - { - level = level_person(prefix, NULL); - if(level >= LEVEL_OP) + // Reply the CTCP PING + else if(eq("PING", buffer) && !ping) { + ping = 1; if(r != NULL) + if(dont_flood_server()) + { + ping = 1; + r = next_word(buffer, r, SMALL_BUFFER_SIZE); + sprintf(IRC_buffer, + "NOTICE %s :\001PING %s\001\n", nick, buffer); + write_irc(IRC_buffer); + } + } + // DCC (chat) + else if(eq("DCC", buffer)) + { + if(level >= LEVEL_OP) { - r = next_word(buffer, r, SMALL_BUFFER_SIZE); - if(eq("CHAT", buffer)) + if(r != NULL) { - if(accepting_dcc_chat(prefix, nick, level, r) != 0) + r = next_word(buffer, r, SMALL_BUFFER_SIZE); + if(eq("CHAT", buffer)) { - sprintf(IRC_buffer, "NOTICE %s :\002Error\002" - " can't connect\n", nick); + if(accepting_dcc_chat(prefix, nick, level, r) != 0) + { + sprintf(IRC_buffer, "NOTICE %s :\002Error\002" + " can't connect\n", nick); + write_irc(IRC_buffer); + } + } + else + { + sprintf(IRC_buffer, + "NOTICE %s :I can only DCC CHAT\n", nick); write_irc(IRC_buffer); } } - else - { - sprintf(IRC_buffer, - "NOTICE %s :I can only DCC CHAT\n", nick); - write_irc(IRC_buffer); - } } - } - else if(dont_flood_server()) - { - sprintf(IRC_buffer, - "NOTICE %s :Sorry, can't accept DCC from you\n", - nick, buffer); - write_irc(IRC_buffer); + else if(dont_flood_server()) + { + sprintf(IRC_buffer, + "NOTICE %s :Sorry, can't accept DCC from you\n", + nick, buffer); + write_irc(IRC_buffer); + } } } } - delete nick; + delete[] nick; } //----------------------------------------------------------------------------- @@ -2441,7 +2907,7 @@ void IRC_PART(char *prefix, char *where) present_people.Clear(); in_channel = 0; } - delete nick; + delete[] nick; } //----------------------------------------------------------------------------- @@ -2450,7 +2916,7 @@ void IRC_PART(char *prefix, char *where) void IRC_KICK(char *prefix, char *where, char *victim_nick) { - char *c; + char *c, *d; uncap(victim_nick); if(strcmp(victim_nick, real_nick) == 0) @@ -2461,17 +2927,23 @@ void IRC_KICK(char *prefix, char *where, char *victim_nick) write_irc(IRC_buffer); } + c = strdup(prefix_from_nick(victim_nick)); + if((level_person(prefix, NULL) < level_person(prefix_from_nick(victim_nick), NULL)) && (level_person(prefix_from_nick(victim_nick), NULL) > 0)) { - c = cut_nick_from_prefix(prefix); - add_mode(where, "-o", c); - delete c; + d = cut_nick_from_prefix(prefix); + add_mode(where, "-o", d); + delete[] d; } + else if(cop_mode && (c != NULL)) add_kick(c); - c = prefix_from_nick(victim_nick); if(c != NULL) present_people.Remove(c); +#ifdef ERROR_OUTPUT else cerr<<"** ERROR : non present person has been kicked out **\n"; +#endif + + delete[] c; } //----------------------------------------------------------------------------- @@ -2500,7 +2972,7 @@ int check_restricted(char *where, char *prefix) concat(s, "*!*@"); concat(s, p); *s++ = '\0'; - duration = DEFAULT_RESTRICTED_TIME; + duration = DEFAULT_RESTRICTED_TIME + deban_delay; smart_shit(NULL, NULL, pattern, "Restricted site : no clones", duration); smart_ban(where, pattern); send_mode(where); @@ -2515,8 +2987,9 @@ int check_restricted(char *where, char *prefix) void IRC_JOIN(char *prefix, char *where) { char *nick; - int l, restricted; + int k, l, restricted; NodeList *node; + char buffer[SMALL_BUFFER_SIZE]; nick = cut_nick_from_prefix(prefix); @@ -2536,20 +3009,35 @@ void IRC_JOIN(char *prefix, char *where) uncap(where); present_people.Add(prefix); - if(restricted_list.Matches(prefix)) + l = level_person(prefix, NULL); + + if(anti_clone && (l < LEVEL_FRIEND) && (restricted_list.Matches(prefix))) restricted = check_restricted(where, prefix); else restricted = 0; if(!restricted) { - l = level_person(prefix, NULL); - +#ifdef ANTI_SPOOF + if(l >= LEVEL_FRIEND) + { + for(k=0; k<10; k++) buffer[k] = 'a'+int(rand()%26); + buffer[10] = '\0'; + wait_ping.Insert(new WaitPing(nick, buffer, + current_time+ANTI_SPOOF_MAX_TIME)); + sprintf(IRC_buffer, "PRIVMSG %s :\001PING %s\001\n", + nick, buffer); + write_irc(IRC_buffer); + } +#endif + if(l >= LEVEL_OP) { +#ifndef ANTI_SPOOF if(l >= LEVEL_DEFENCE) add_mode(where, "+o", nick); else mode_change_list.Insert(new DelayModeChange(where, "+o", nick, op_delay)); +#endif } else { @@ -2576,7 +3064,7 @@ void IRC_JOIN(char *prefix, char *where) } } - delete nick; + delete[] nick; } //----------------------------------------------------------------------------- @@ -2775,7 +3263,7 @@ void IRC_RPL_WHOISUSER(char *prefix, } - delete banid; + delete[] banid; if(pred == NULL) wait_list.first = next; else pred->next = next; @@ -2811,7 +3299,9 @@ void IRC_RPL_WHOREPLY(char *prefix, *s++ = '\0'; present_people.Add(IRC_buffer); } +#ifdef ERROR_OUTPUT else cerr< 0) for(k=0; k"; cout<<"\n"; + for(k=0; k 0) for(k=0; k"; + cout<<"\n"; #endif if(prefix != NULL) uncap(prefix); @@ -2891,7 +3385,7 @@ void get_command(char *prefix, { if(n_cmd > 0) if(eq("PING", cmd)) { - if(n_cmd > 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]); + if(n_cmd >= 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]); else sprintf(IRC_buffer, "PONG\n"); write_irc(IRC_buffer); } @@ -2958,13 +3452,17 @@ void get_options(int argc, char **argv) { n++; if(n=1) socket_delay = d; +#ifdef ERROR_OUTPUT else cerr<<"*** Delay error ***\n"; +#endif } +#ifdef ERROR_OUTPUT else cerr<<"*** No delay parameter ***\n"; +#endif } else if(eq("-od", argv[n])) { @@ -3018,9 +3534,13 @@ void get_options(int argc, char **argv) { d = atoi(argv[n]); if(d>=1) op_delay = d; +#ifdef ERROR_OUTPUT else cerr<<"*** Op delay error ***\n"; +#endif } +#ifdef ERROR_OUTPUT else cerr<<"*** No delay parameter ***\n"; +#endif } else if(eq("-dd", argv[n])) { @@ -3029,19 +3549,26 @@ void get_options(int argc, char **argv) { d = atoi(argv[n]); if(d>=1) deban_delay = d; +#ifdef ERROR_OUTPUT else cerr<<"*** Deban delay error ***\n"; +#endif } +#ifdef ERROR_OUTPUT else cerr<<"*** No delay parameter ***\n"; +#endif } else if(eq("-?", argv[n])) help = 1; else { +#ifdef ERROR_OUTPUT cerr<<"*** Unknown option "<.\n"; @@ -3059,6 +3586,7 @@ void get_options(int argc, char **argv) cout<<"-p sets the server port\n"; cout<<"-? shows this help\n"; exit(0); +#endif } n++; @@ -3104,8 +3632,10 @@ void try_reconnect() } strncpy(wanted_server, default_server, MAXHOSTNAME+1); wanted_port = default_port; +#ifdef ERROR_OUTPUT cerr<<"*** Can't contact IRC server ***\n"; cerr<<"*** Next try in "<= buffer+BUFFER_SIZE) { +#ifdef ERROR_OUTPUT cerr<<"*** Buffer full, erase it ***\n"; +#endif endsrc = buffer; } @@ -3146,8 +3678,10 @@ void got_datas_from_server() if(s <= 0) { +#ifdef ERROR_OUTPUT cerr<<"KILLING CONNECTION : Read error\n"; cerr.flush(); +#endif kill_connection(); } else @@ -3184,7 +3718,7 @@ void check_stuffs() { NodeList *md; - if(current_time > anti_flood_off_until) check_flood(); + if(anti_flood && (current_time > anti_flood_off_until)) check_flood(); check_delay_mode_change(); send_mode(current_channel); @@ -3256,8 +3790,10 @@ int main(int argc, char **argv) level_list.Insert(new Person("*!*jolibot@*.ens.fr", LEVEL_DEFENCE, NULL)); level_list.Insert(new Person("*!*jolibot@*.curie.fr", LEVEL_DEFENCE, NULL)); +#ifdef SCREEN_OUTPUT cout<<"TropBot, written by Francois Fleuret," " contact \n"; +#endif get_options(argc, argv); @@ -3272,7 +3808,8 @@ int main(int argc, char **argv) global_state = STATE_WAIT; in_channel = 0; mode_protect_on = DEFAULT_MODE_PROTECT; - + cop_mode = 0; + FD_ZERO(&ready); alive = 1; @@ -3282,11 +3819,18 @@ int main(int argc, char **argv) last_answer_time = 0; anti_flood_off_until = 0; + // The bot does NOTHING at first + anti_flood = 0; + anti_clone = 0; + ctcp_reply = 0; + cop_mode = 0; + src = buffer; endsrc = buffer; delay = socket_delay; struct sigaction action; + memset(&action, 0, sizeof(action)); action.sa_handler = SIG_IGN; // We'll ignore the SIGPIPE signal, which will be catch somewhere else @@ -3336,8 +3880,10 @@ int main(int argc, char **argv) { if(current_time > time_last_datas+DELAY_DEAD_SERVER) { +#ifdef ERROR_OUTPUT cerr<<"KILLING CONNECTION : Quiet server\n"; cerr.flush(); +#endif kill_connection(); } else if(!in_channel) if(global_state == STATE_WAIT) @@ -3348,6 +3894,7 @@ int main(int argc, char **argv) } if(IRC_connected) check_stuffs(); + already_kicked.Clear(); } #ifdef SCREEN_OUTPUT