/*-----------------------------------------------------------------------------
- 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 <francois.fleuret@inria.fr> 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.2d"
+#define OPTIONS ""
#include <time.h>
#include <fstream.h>
//-----------------------------------------------------------------------------
#define SCREEN_OUTPUT
+#define ERROR_OUTPUT
+
+//#define ANTI_SPOOF
+#define ANTI_SPOOF_MAX_TIME 300
//-----------------------------------------------------------------------------
#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
//-----------------------------------------------------------------------------
int deban_delay = DEFAULT_DEBAN_DELAY;
char control_char = DEFAULT_CONTROL_CHAR;
+int cop_mode;
+
int delay;
timeval delay_pause;
time_t current_time, time_killed, time_last_datas, last_answer_time,
template class List<Person *>;
template class List<Welcome *>;
template class List<WaitInfos *>;
+template class List<WaitPing *>;
template class List<DelayModeChange *>;
template class List<char *>;
List<Person *> level_list;
List<Welcome *> shit_list;
List<WaitInfos *> wait_list;
+List<WaitPing *> wait_ping;
List<DelayModeChange *> mode_change_list;
ListChar present_people, banid_list, restricted_list, history;
// 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
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))
{
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<char *> *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)
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;
}
}
}
weigth = w;
}
- ~FloodLine() { delete prefix; }
+ ~FloodLine() { delete[] prefix; }
void Reset() { individual = 0; site = 0; }
};
template class List<FloodLine *>;
-List<FloodLine *> flood_list;
+List<FloodLine *> flood_list, kick_list;
//-----------------------------------------------------------------------------
{
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);
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)
{
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)
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<FloodLine *> *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
{
char *c, *banid;
char buffer[3];
+ int check_ban, nb_bans, ok;
+ NodeList<char *> *node;
+ char pattern[SMALL_BUFFER_SIZE];
+ char *adr_param;
if(signe < 0) buffer[0] = '-'; else buffer[0] = '+';
buffer[1] = mode;
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;
c = cut_nick_from_prefix(who);
add_mode(where, "-o", c);
add_mode(where, "+o", param);
- delete c;
+ delete[] c;
}
break;
else add_mode(where, "+m", NULL);
c = cut_nick_from_prefix(who);
add_mode(where, "-o", c);
- delete c;
+ delete[] c;
}
}
break;
*c = '\0';
}
-int LoadConfigFile(char *name)
+#define MAX_INCLUDE_RECURSE 3
+
+int LoadConfigFile(char *name, int recurse)
{
ifstream *file;
int duration, level, error;
{
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 "
+ <<buffer<<" : too many recursion.\n";
+#endif
+ }
+ }
+ else if(strcmp(buffer, "FRIEND") == 0)
{
if(r != NULL)
{
if(r != NULL)
{
r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+#ifdef SCREEN_OUTPUT
cout<<"RESTRICTED->"<<buffer<<"\n";
+#endif
restricted_list.Insert(strdup(buffer));
}
}
if(r == NULL) r = "Shit";
banid = clean_banid(pattern);
smart_shit(NULL, NULL, banid, r, duration);
- delete banid;
+ delete[] banid;
}
}
}
buf = IRC_buffer;
- cerr<<"PATTERN=>"<<pattern<<"<\n";
-
if(pattern != NULL)
{
concat(buf, "\002");
while(node1 != NULL)
{
- cout<<" =>"<<node1->body<<"\n";
-
if((pattern == NULL) || match_pattern(pattern, node1->body))
{
c = adr_beginning(node1->body);
nb_person[LEVEL_MASTER]);
tell(chat, nick, IRC_buffer);
- delete ok;
+ delete[] ok;
}
//-----------------------------------------------------------------------------
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");
{
if(pred == NULL) history.first = next;
else pred->next = next;
- delete node->body;
+ delete[] node->body;
delete node;
}
else pred = node;
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;
}
}
{
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)
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,
write_irc(IRC_buffer);
}
}
- else notice_shit_list(chat, nick, "*", 1);
+ else
+ {
+ int s1, s2, s3, s4, d;
+ NodeList<Welcome *> *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;
}
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 if(eq("ao", buffer) || eq("antifloodoff", buffer))
{
- 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;
- }
- if(anti_flood_off_until > current_time)
+ 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);
+ 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;
+ }
+ 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 tell(chat, nick, "Anti-flood on\n");
+ else no_authorized = 1;
}
else if(eq("msg", buffer) || eq("message", buffer))
{
}
else no_authorized = 1;
}
- else if(eq("help", buffer))
+ else if(eq("mode", buffer))
{
if(dont_flood_server() || (level >= LEVEL_FRIEND))
{
+ char *a;
+ if(cop_mode) a = "ON"; else a = "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"
" your level is %d. I am a father with %d sons.\n",
- control_char, op_delay, deban_delay,
+ control_char, op_delay, deban_delay, a,
level, nb_sons);
tell(chat, nick, IRC_buffer);
}
else
{
sprintf(IRC_buffer,
- "control_char '%c' op_delay %ds deban_delay %ds"
+ "control_char '%c' op_delay %ds deban_delay %ds "
+ "cop-mode %s"
" your level is %d. I'm a clone.\n",
- control_char, op_delay, deban_delay, level);
+ control_char, op_delay, deban_delay, a,
+ 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 [<nick>!<pattern>] \002level\002 [<nick>] \002\037w\037\002ho\002 \002\037m\037\002y\037s\037\002hit\002\n");
if(level >= LEVEL_OP)
{
- tell(chat, nick, "\002\037a\037\002ntiflood\037o\037\002ff\002 [<duration>] \002\037a\037\002lert\002 \002home\002 \002op\002 [{<nick> list}] \002join\002 <#channel> \002nick\002 <nick> \002\037p\037\002rune\037b\037\002an\002 <number> \002\037d\037\002e\037b\037\002an\002 {<pattern> list} \002\037f\037\002ilter\037k\037\002ick\002 <pattern>!<nick> [<comment>] \002\037s\037\002hit/\037s\037\002hit\037s\037\002ite/\037s\037\002hit\037h\037\002ost\002 <pattern>!<nick> [<duration> [<comment>]] \002\037u\037\002n\037s\037\002hit\002 {<pattern>!<nick> list} \002\037pu\037\002n\037s\037\002hit\002 {<pattern> list} \002\037b\037\002an/\037s\037\002ite\037b\037\002an\002 <pattern>!<nick> \002synch\002 \002\037h\037\002istory\002\n \002\037m\037\002es\037s\037\002a\037g\037\002e\002 <nick>!<pattern> <msg>\n");
+ 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");
}
if(level >= LEVEL_MASTER)
}
else if(eq("db", buffer) || eq("deban", buffer))
{
- if(level >= LEVEL_FRIEND)
+ if(level >= LEVEL_OP)
{
while(r != NULL)
{
{
banid = clean_banid(buffer);
smart_ban(current_channel, banid);
- delete banid;
+ delete[] banid;
}
else
{
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)
uncap(buffer);
banid = clean_banid(buffer);
smart_shit(chat, nick, banid, r, duration);
- delete banid;
+ delete[] banid;
}
else
{
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);
}
}
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();
}
}
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",
{
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;
//-----------------------------------------------------------------------------
-// This function is called after a NOTICE
+void pong_reply(char *nick, char *value)
+{
+ NodeList<WaitPing *> *node, *next, *pred;
+
+ cout<<"pong_reply : nick >"<<nick<<"< value >"<<value<<"<\n";
+
+ pred = NULL;
+ node = wait_ping.first;
+ while(node != NULL)
+ {
+ next = node->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<n_ctcp; k++)
+ {
+ cout<<"ctcp >"<<slice_ctcp[k]<<"<\n";
+ r = slice_ctcp[k];
+ r = next_word(word, r, SMALL_BUFFER_SIZE);
+ if(strcmp(word, "PING") == 0)
+ {
+ nick = cut_nick_from_prefix(prefix);
+ r = next_word(word, r, SMALL_BUFFER_SIZE);
+ pong_reply(nick, word);
+ delete nick;
+ }
+ }
+#endif
}
void IRC_PRIVMSG(char *prefix,
char *who, char *msg, char **slice_ctcp, int n_ctcp)
{
- int k, version, ping, level;
- char *nick, *r;
+ int k, version, ping, level, ctcp, kick;
+ char *nick, *r, *pattern, *banid;
char buffer[SMALL_BUFFER_SIZE];
uncap(who);
nick = cut_nick_from_prefix(prefix);
+
+ level = level_person(prefix, NULL);
+
+ kick = 0;
if(strcmp(who, current_channel) == 0)
{
add_flood_line(prefix, FL_PUBLIC, 1);
- if(n_ctcp > 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; (k<n_ctcp) && !ctcp; k++)
+ {
+ r = slice_ctcp[k];
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ if(strcmp(buffer, "ACTION") != 0) ctcp =1;
+ else
+ {
+ if(!kick && (r != NULL) && (bad_line(r, buffer)))
+ {
+ sprintf(IRC_buffer,"KICK %s %s :cop : %s\n",
+ current_channel, nick, buffer);
+ write_irc(IRC_buffer);
+ }
+ kick = 1;
+ }
+ }
+
+ if(!kick) if(ctcp) if(level < LEVEL_FRIEND)
+ {
+ pattern = pattern_from_prefix(prefix, 0);
+ banid = clean_banid(pattern);
+ smart_shit(NULL, NULL, pattern, "cop : no ctcp",
+ COP_DURATION + deban_delay);
+ smart_ban(current_channel, pattern);
+ send_mode(current_channel);
+ sprintf(IRC_buffer, "KICK %s %s :cop : no ctcp\n",
+ current_channel, nick);
+ write_irc(IRC_buffer);
+ kick = 1;
+ delete[] banid;
+ delete[] pattern;
+ }
+ }
+ }
+ else if(cop_mode) if(level < LEVEL_FRIEND)
+ if(!kick) if((msg != NULL) && bad_line(msg, buffer))
+ {
+ sprintf(IRC_buffer, "KICK %s %s :cop : %s\n",
+ current_channel, nick, buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+
if(msg != NULL) if(strlen(msg)>0)
{
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<n_ctcp; k++)
{
r = slice_ctcp[k];
r = next_word(buffer, r, SMALL_BUFFER_SIZE);
-
+
// Reply the CTCP VERSION
if(eq("VERSION", buffer) && !version)
{
sprintf(IRC_buffer, "NOTICE %s :"
"\001VERSION \002TropBot\002 " VERSION OPTIONS
", " SYSTEM " system, " DATE ". "
- "Contact THX-1138 on IRC, or <francois.fleuret@inria.fr>"
+ "Contact THX-1138 on IRCNet, or <francois.fleuret@inria.fr>"
"\001\n",
nick);
write_irc(IRC_buffer);
// DCC (chat)
else if(eq("DCC", buffer))
{
- level = level_person(prefix, NULL);
if(level >= LEVEL_OP)
{
if(r != NULL)
}
}
}
- delete nick;
+ delete[] nick;
}
//-----------------------------------------------------------------------------
present_people.Clear();
in_channel = 0;
}
- delete nick;
+ delete[] nick;
}
//-----------------------------------------------------------------------------
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)
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;
}
//-----------------------------------------------------------------------------
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);
void IRC_JOIN(char *prefix, char *where)
{
char *nick;
- int l, restricted;
+ int k, l, restricted;
NodeList<Welcome *> *node;
+ char buffer[SMALL_BUFFER_SIZE];
nick = cut_nick_from_prefix(prefix);
uncap(where);
present_people.Add(prefix);
- if(restricted_list.Matches(prefix))
+ l = level_person(prefix, NULL);
+
+ if((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
{
}
}
- delete nick;
+ delete[] nick;
}
//-----------------------------------------------------------------------------
}
- delete banid;
+ delete[] banid;
if(pred == NULL) wait_list.first = next;
else pred->next = next;
*s++ = '\0';
present_people.Add(IRC_buffer);
}
+#ifdef ERROR_OUTPUT
else cerr<<where<<"!="<<current_channel<<"\n";
+#endif
}
void IRC_RPL_ENDOFWHO(char *prefix, char *name)
cmd = slice_cmd[0];
#ifdef SCREEN_OUTPUT
+
cout<<"from "<<prefix<<" ";
int k;
for(k=0; k<n_cmd; k++) cout<<"["<<slice_cmd[k]<<"]";
if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<slice_ctcp[k]<<">";
cout<<"\n";
+ for(k=0; k<n_cmd; k++) cout<<"["<<(void *) slice_cmd[k]<<"]";
+ if(n_ctcp > 0) for(k=0; k<n_ctcp; k++) cout<<"<"<<(void *) slice_ctcp[k]<<">";
+ cout<<"\n";
#endif
if(prefix != NULL) uncap(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);
}
{
n++;
if(n<argc) default_port = atoi(argv[n]);
+#ifdef ERROR_OUTPUT
else cerr<<"*** No port parameter ***\n";
+#endif
}
else if(eq("-h", argv[n]))
{
n++;
if(n<argc) strncpy(default_server, argv[n], MAXHOSTNAME);
+#ifdef ERROR_OUTPUT
else cerr<<"*** No hostname parameter ***\n";
+#endif
}
else if(eq("-o", argv[n]))
{
if(n<argc)
{
strncpy(config_file, argv[n], SMALL_BUFFER_SIZE);
- LoadConfigFile(argv[n]);
+ LoadConfigFile(argv[n], 0);
}
+#ifdef ERROR_OUTPUT
else cerr<<"*** No friends list parameter ***\n";
+#endif
}
else if(eq("-c", argv[n]))
{
n++;
if(n<argc) strncpy(home_channel, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
else cerr<<"*** No channel parameter ***\n";
+#endif
}
else if(eq("-l", argv[n]))
{
n++;
if(n<argc) strncpy(user_login, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
else cerr<<"*** No username parameter ***\n";
+#endif
}
else if(eq("-n", argv[n]))
{
n++;
if(n<argc) strncpy(original_nick, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
else cerr<<"*** No nickname parameter ***\n";
+#endif
}
else if(eq("-j", argv[n]))
{
n++;
if(n<argc) strncpy(jam_nick, argv[n], SMALL_BUFFER_SIZE);
+#ifdef ERROR_OUTPUT
else cerr<<"*** No jam nickname parameter ***\n";
+#endif
+ }
+ else if(eq("-cop", argv[n]))
+ {
+ cop_mode = 1;
}
else if(eq("-d", argv[n]))
{
{
d = atoi(argv[n]);
if(d>=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]))
{
{
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]))
{
{
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 "<<argv[n]<<" ***\n";
+#endif
help = 1;
}
if(help)
{
+#ifdef SCREEN_OUTPUT
cout<<"Tropbot " VERSION " Written by Francois Fleuret.\n";
cout<<"Compiled the " DATE " on a " SYSTEM " system.\n";
cout<<"Contact <francois.fleuret@inria.fr>.\n";
cout<<"-p <port number> sets the server port\n";
cout<<"-? shows this help\n";
exit(0);
+#endif
}
n++;
}
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 "<<delay<<" s\n";
+#endif
}
void got_connection()
// If the buffer is already full, purge it
if(endsrc >= buffer+BUFFER_SIZE)
{
+#ifdef ERROR_OUTPUT
cerr<<"*** Buffer full, erase it ***\n";
+#endif
endsrc = buffer;
}
if(s <= 0)
{
+#ifdef ERROR_OUTPUT
cerr<<"KILLING CONNECTION : Read error\n";
cerr.flush();
+#endif
kill_connection();
}
else
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 <francois.fleuret@inria.fr>\n";
+#endif
get_options(argc, argv);
global_state = STATE_WAIT;
in_channel = 0;
mode_protect_on = DEFAULT_MODE_PROTECT;
-
+ cop_mode = 0;
+
FD_ZERO(&ready);
alive = 1;
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
{
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)
}
if(IRC_connected) check_stuffs();
+ already_kicked.Clear();
}
#ifdef SCREEN_OUTPUT