--- /dev/null
+/*-----------------------------------------------------------------------------
+ TropBot, a small IRC bot, v2.6 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"
+
+#include <time.h>
+#include <fstream.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "tblib.h"
+#include "objects.h"
+#include "list.cc"
+
+//-----------------------------------------------------------------------------
+
+#define SCREEN_OUTPUT
+
+//-----------------------------------------------------------------------------
+
+#define MODE_NUMBER_MAX 3
+#define SIZE_BANLIST_MAX 20
+#define NB_CHAR_MAX 400
+
+//-----------------------------------------------------------------------------
+
+#define DEFAULT_CONTROL_CHAR '|'
+#define DELAY_NICK_BACK 300
+#define DELAY_MAX_RECONNECT 300
+#define DELAY_DEAD_SERVER 900
+
+#define DEFAULT_SERVER "sil.polytechnique.fr"
+#define DEFAULT_PORT 6667
+
+#define DEFAULT_USER_NAME "\002TropBot\002 " VERSION OPTIONS
+#define DEFAULT_LOGIN "tropbot"
+#define DEFAULT_NICK "TropBot"
+#define DEFAULT_JAM_NICK "TB-????"
+#define DEFAULT_HOME_CHANNEL "#tropbot"
+#define DEFAULT_SOCKET_DELAY 30
+#define DEFAULT_OP_DELAY 2
+#define DEFAULT_DEBAN_DELAY 0
+
+#define DEFAULT_ANTI_FLOOD_OFF_DURATION 600
+
+#define DEFAULT_CONFIG_FILE ".tropbotrc"
+
+#define DEFAULT_SHIT_TIME 600
+#define DEFAULT_RESTRICTED_TIME 900
+
+#define DEFAULT_MODE_PROTECT 0
+
+// Not needed coz flooding people can't re-JOIN quickly
+//#define BAN_ON_FLOOD
+#define BAN_FLOOD_DELAY 30
+
+#define MAX_LINE_FLOOD 4
+#define MAX_CTCP_FLOOD 3
+#define FLOOD_DELAY 2
+#define DELAY_ANSWERS 3
+#define ANTI_CLONES_DELAY 30
+
+#define NB_SONS_MAX 3
+
+#define HISTORY_SIZE 3
+
+enum { FL_NOTICE, FL_PUBLIC, FL_CTCP, FL_NICK, FL_PART, FL_JOIN };
+
+//-----------------------------------------------------------------------------
+
+#define MAX_DCC_CHAT 16
+
+//-----------------------------------------------------------------------------
+
+extern "C" void bzero(void *, int);
+extern "C" int select(int, fd_set *, fd_set *, fd_set *, timeval *);
+extern "C" pid_t fork(void);
+
+//-----------------------------------------------------------------------------
+
+int default_port = DEFAULT_PORT;
+int wanted_port;
+char default_server[MAXHOSTNAME+1] = DEFAULT_SERVER;
+char wanted_server[MAXHOSTNAME+1];
+
+fd_set ready, result;
+int alive; // Should be set to false (0) to kill the bot
+int father, nb_sons;
+int socket_irc;
+int socket_delay = DEFAULT_SOCKET_DELAY;
+int op_delay = DEFAULT_OP_DELAY;
+int deban_delay = DEFAULT_DEBAN_DELAY;
+char control_char = DEFAULT_CONTROL_CHAR;
+
+int delay;
+timeval delay_pause;
+time_t current_time, time_killed, time_last_datas, last_answer_time,
+ anti_flood_off_until;
+char *src, *endsrc;
+char buffer[BUFFER_SIZE];
+
+int IRC_connected, IRC_registred;
+int global_state, in_channel, was_killed, mode_protect_on;
+
+#define STATE_WAIT 0
+#define STATE_GETING_WHO 1
+#define STATE_GETING_BAN 2
+
+//-----------------------------------------------------------------------------
+
+template class List<DCCChat *>;
+template class List<Person *>;
+template class List<Welcome *>;
+template class List<WaitInfos *>;
+template class List<DelayModeChange *>;
+template class List<char *>;
+
+List<DCCChat *> dcc_chat_list;
+List<Person *> level_list;
+List<Welcome *> shit_list;
+List<WaitInfos *> wait_list;
+List<DelayModeChange *> mode_change_list;
+
+ListChar present_people, banid_list, restricted_list, history;
+
+//-----------------------------------------------------------------------------
+
+// General buffer for all IRC operations
+char IRC_buffer[BUFFER_SIZE];
+
+// Nick we got after registration
+char real_nick[SMALL_BUFFER_SIZE];
+
+// Nick we want
+char wanted_nick[SMALL_BUFFER_SIZE];
+
+char original_nick[SMALL_BUFFER_SIZE] = DEFAULT_NICK;
+
+// Pattern used for random-nick generation if nick-collision occurs
+// all the '?' will be replaced with random digits
+char jam_nick[SMALL_BUFFER_SIZE] = DEFAULT_JAM_NICK;
+
+// The "user" we want in the nick!user@host stuff
+char user_login[SMALL_BUFFER_SIZE] = DEFAULT_LOGIN;
+
+// The USERNAME string
+char user_name[SMALL_BUFFER_SIZE] = DEFAULT_USER_NAME;
+
+// The channel we want to join
+char current_channel[SMALL_BUFFER_SIZE], wanted_channel[SMALL_BUFFER_SIZE];
+char home_channel[SMALL_BUFFER_SIZE] = DEFAULT_HOME_CHANNEL;
+
+// The name of the configuration file
+char config_file[SMALL_BUFFER_SIZE] = DEFAULT_CONFIG_FILE;
+
+//-----------------------------------------------------------------------------
+
+char *prefix_from_nick(char *nick)
+{
+ NodeList<char *> *node;
+ char *s, *t;
+ int yep;
+ yep = 0;
+
+ node = present_people.first;
+ while((node != NULL) && !yep)
+ {
+ yep = 1;
+ s = node->body;
+ t = nick;
+ while((*t != '\0') &&
+ (*s != '!') && (*s != '\0') && yep) yep &= (*s++ == *t++);
+ yep &= ((*t == '\0') && (*s == '!'));
+ if(!yep) node=node->next;
+ }
+
+ if(node != NULL) return node->body; else return NULL;
+
+}
+
+//-----------------------------------------------------------------------------
+
+int level_person(char *prefix, char *passwd)
+{
+ NodeList<Person *> *node;
+ int l;
+ l = 0;
+
+ for(node = level_list.first; node != NULL; node=node->next)
+ if(match_pattern(node->body->pattern, prefix))
+ if((node->body->level > l) || (l == 0))
+ {
+ if(node->body->passwd == NULL) l = node->body->level;
+ else
+ if(passwd != NULL)
+ if(strcmp(node->body->passwd, passwd) == 0)
+ l = node->body->level;
+ }
+ return l;
+}
+
+void remove_level(char *prefix)
+{
+ NodeList<Person *> *node, *pred, *next;
+ pred = NULL; next = NULL;
+
+ node = level_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(strcmp(node->body->pattern, prefix) == 0)
+ {
+ if(pred == NULL) level_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+}
+
+void clear_levels()
+{
+ NodeList<Person *> *node, *next;
+
+ node = level_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ delete node->body;
+ delete node;
+ node = next;
+ }
+ level_list.first = NULL;
+}
+
+void clear_shit()
+{
+ NodeList<Welcome *> *node, *next;
+
+ node = shit_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ delete node->body;
+ delete node;
+ node = next;
+ }
+ shit_list.first = NULL;
+}
+
+void remove_wait_for_chat(DCCChat *chat)
+{
+ NodeList<WaitInfos *> *node, *pred, *next;
+ pred = NULL; next = NULL;
+
+ node = wait_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(node->body->chat == chat)
+ {
+ if(pred == NULL) wait_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function generates a random nick from a pattern. The pattern
+// is supposed to contain some '?', which will be replaced with random
+// digits.
+
+void rand_nick(char *nick, char *pattern)
+{
+ unsigned int n;
+ for(n=0; n<strlen(pattern); n++)
+ {
+ if(pattern[n] == '?') nick[n] = '0'+int(rand()%10);
+ else nick[n] = pattern[n];
+ }
+ nick[n]='\0';
+}
+
+//-----------------------------------------------------------------------------
+
+void kill_connection()
+{
+ time_last_datas = current_time;
+ IRC_connected = 0; // We are not connected
+ IRC_registred = 0; // We are not registred
+ FD_CLR(socket_irc, &ready); // Forget the socket
+ close(socket_irc); // Close it
+ present_people.Clear(); // We don't see anyone
+ rand_nick(wanted_nick, jam_nick); // Random the nick (yeah, we are paranoid)
+ was_killed = 1; // We have been killed (I said PARANOID !)
+ time_killed = current_time; // Note when it happens
+ src = buffer; // Forget all the remaining datas
+ endsrc = buffer; // Idem.
+ delay = 0; // We won't wait for reconnection
+ in_channel = 0; // We are not in any channel
+ socket_irc = 0;
+}
+
+void clone(char *nick)
+{
+ if(fork() == 0)
+ {
+ strcpy(wanted_nick, nick);
+ strcpy(original_nick, nick);
+ IRC_connected = 0;
+ IRC_registred = 0;
+ FD_CLR(socket_irc, &ready);
+ present_people.Clear();
+ time_killed = current_time;
+ src = buffer;
+ endsrc = buffer;
+ delay = 0;
+ in_channel = 0;
+ father = 0;
+ }
+}
+
+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)
+ {
+ cerr<<"KILLING CONNECTION : write_irc error\n";
+ cerr.flush();
+ kill_connection();
+ }
+ else
+ {
+#ifdef SCREEN_OUTPUT
+ cout<<"\n!!!!>"<<stuff<<"<\n\n";
+#endif
+ last_answer_time = current_time;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+int nb_modes;
+
+char string_modes[MODE_NUMBER_MAX*2+1];
+char *ptr_modes;
+char string_param_modes[MODE_NUMBER_MAX*64+1];
+char *ptr_param_modes;
+int k_mode, o_mode;
+
+void reset_mode()
+{
+ nb_modes = 0;
+ ptr_modes = string_modes;
+ ptr_param_modes = string_param_modes;
+ k_mode = 0;
+ o_mode = 0;
+}
+
+void send_mode(char *where)
+{
+ if(nb_modes>0)
+ {
+ *ptr_modes = '\0';
+ *ptr_param_modes = '\0';
+ sprintf(IRC_buffer, "MODE %s %s %s\n",
+ where, string_modes, string_param_modes);
+ write_irc(IRC_buffer);
+ reset_mode();
+ }
+}
+
+void add_mode(char *where, char *mode, char *param)
+{
+ char *s;
+
+ // Disgusting hack coz of a FUCKING server bug :-(
+ if(mode[1] == 'o')
+ {
+ if(k_mode) send_mode(where);
+ o_mode = 1;
+ }
+
+ if(mode[1] == 'k')
+ {
+ if(o_mode) send_mode(where);
+ k_mode = 1;
+ }
+
+ s = mode;
+ while(*s != '\0') *ptr_modes++ = *s++;
+ if(param != NULL)
+ {
+ s = param;
+ while(*s != '\0') *ptr_param_modes++ = *s++;
+ *ptr_param_modes++ = ' ';
+ }
+
+ if(++nb_modes == MODE_NUMBER_MAX) send_mode(where);
+}
+
+//-----------------------------------------------------------------------------
+
+void tell(DCCChat *chat, char *nick, char *msg)
+{
+ char tell_buffer[BUFFER_SIZE];
+
+#ifdef SCREEN_OUTPUT
+ cout<<"tell(chat="<<chat<<", nick="<<nick<<" msg="<<msg<<")\n";
+ if(msg[strlen(msg)-1] != '\n')
+ cout<<"**************************************\n";
+#endif
+
+ if(chat != NULL) write(chat->socket, msg, strlen(msg));
+
+ if(nick != NULL)
+ {
+ sprintf(tell_buffer, "NOTICE %s :%s", nick, msg);
+ write_irc(tell_buffer);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void smart_shit(DCCChat *chat, char *nick,
+ char *pattern, char *comment, int duration)
+{
+ NodeList<Welcome *> *node, *next, *pred;
+ int no_shit;
+ int time_max, l;
+
+ if(duration < 5) duration = 5;
+
+ time_max = duration + current_time;
+
+ no_shit = 0;
+ node = shit_list.first;
+ pred = NULL;
+ while((node != NULL) && !no_shit)
+ {
+ next = node->next;
+ if(strcmp(node->body->pattern, pattern) == 0)
+ {
+ if(node->body->time_max <= time_max)
+ {
+ if(pred == NULL) shit_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else
+ {
+ no_shit = 1;
+ pred = node;
+ }
+ }
+ else pred = node;
+ node = next;
+ }
+
+ if(!no_shit)
+ {
+ shit_list.Insert(new Welcome(pattern, comment, time_max));
+ if((nick != NULL) || (chat != NULL))
+ {
+ char *string_duration;
+ string_duration = seconds_to_string(duration);
+ sprintf(IRC_buffer, "Shit %s for %s (%s)\n",
+ pattern, string_duration, comment);
+ tell(chat, nick, IRC_buffer);
+ delete string_duration;
+ }
+ }
+ else if((nick != NULL) || (chat != NULL))
+ {
+ sprintf(IRC_buffer,
+ "Can't shit %s, already shitted for a longer time\n", pattern);
+ tell(chat, nick, IRC_buffer);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void smart_ban(char *where, char *pattern)
+{
+ NodeList<char *> *node;
+ int n;
+ n = 0;
+ for(node = banid_list.first; node != NULL; node = node->next)
+ {
+ if((n>=SIZE_BANLIST_MAX-1) ||
+ (match_pattern(pattern, node->body) &&
+ (strcmp(pattern, node->body) != 0)))
+ add_mode(where, "-b", node->body);
+ else n++;
+ }
+ add_mode(current_channel, "+b", pattern);
+}
+
+void smart_unban(char *where, char *pattern)
+{
+ if(banid_list.Contains(pattern)) add_mode(where, "-b", pattern);
+}
+
+//-----------------------------------------------------------------------------
+
+void check_delay_mode_change()
+{
+ NodeList<DelayModeChange *> *node, *pred, *next;
+
+ pred = NULL;
+ node = mode_change_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(current_time >= node->body->time)
+ {
+ add_mode(node->body->where, node->body->mode, node->body->parameter);
+ if(pred == NULL) mode_change_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+}
+
+void clean_delay_mode_change(char *where, char *mode, char *param)
+{
+ NodeList<DelayModeChange *> *node, *pred, *next;
+
+ uncap(param);
+ uncap(where);
+ pred = NULL;
+ node = mode_change_list.first;
+
+ if(param != NULL)
+ {
+ while(node != NULL)
+ {
+ next = node->next;
+ if((node->body->parameter != NULL) &&
+ (strcmp(where, node->body->where) == 0) &&
+ (strcmp(param, node->body->parameter) == 0) &&
+ (strcmp(mode, node->body->mode) == 0))
+ {
+ if(pred == NULL) mode_change_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+ }
+ else
+ {
+ while(node != NULL)
+ {
+ next = node->next;
+ if((strcmp(where, node->body->where) == 0) &&
+ (node->body->parameter == NULL) &&
+ (strcmp(mode, node->body->mode) == 0))
+ {
+ if(pred == NULL) mode_change_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+ }
+}
+
+void RemoveDelayModeChange(char *mode, char *parameter)
+{
+ NodeList<DelayModeChange *> *node, *pred, *next;
+
+ pred = NULL;
+ node = mode_change_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if((strcmp(node->body->mode, mode) == 0) &&
+ (strcmp(node->body->parameter, parameter) == 0))
+ {
+ if(pred == NULL) mode_change_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void synch(char *channel)
+{
+ char *nick;
+ NodeList<char *> *node;
+
+ for(node = present_people.first; node != NULL; node = node->next)
+ if(level_person(node->body, NULL) >= LEVEL_OP)
+ {
+ nick = cut_nick_from_prefix(node->body);
+ add_mode(channel, "+o", nick);
+ delete nick;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+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(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;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// Return a pointer on the first character after the last '@' in the string
+// Beware of some weird hack-script that add @ in the login
+char *adr_beginning(char *s)
+{
+ char *t;
+ t = s;
+ while(*s != '\0') if(*s++ == '@') t = s;
+ if(*t == '@') t++;
+ return t;
+}
+
+char *reach_loginathost(char *s)
+{
+ while((*s != '!') && (*s != '\0')) s++;
+ if(s != '\0') s++;
+ return s;
+}
+
+//-----------------------------------------------------------------------------
+
+class FloodLine
+{
+public:
+ char *prefix;
+ int kind;
+ int weigth;
+ int time;
+ int individual, site, alreadykicked;
+
+ FloodLine(char *p, int k, int w)
+ {
+ prefix = strdup(p);
+ time = current_time;
+ alreadykicked = 0;
+ kind = k;
+ weigth = w;
+ }
+
+ ~FloodLine() { delete prefix; }
+ void Reset() { individual = 0; site = 0; }
+};
+
+template class List<FloodLine *>;
+
+List<FloodLine *> flood_list;
+
+//-----------------------------------------------------------------------------
+
+void alert(char *where, DCCChat *chat, char *nick)
+{
+ int nb_lines, max_nb_lines, duration;
+ NodeList<FloodLine *> *node, *son;
+ char *site, *site2, *guilty_site, *r;
+ char pattern[SMALL_BUFFER_SIZE];
+
+ for(node = flood_list.first; node != NULL; node = node->next)
+ node->body->individual = 0;
+
+ node = flood_list.first;
+
+ max_nb_lines = 1;
+ guilty_site = NULL;
+
+ while(node != NULL)
+ {
+ while((node != NULL) && node->body->individual) node = node->next;
+ if(node != NULL)
+ {
+ nb_lines = 0;
+ site = adr_beginning(node->body->prefix);
+
+ son = node;
+ while(son != NULL)
+ {
+ while((son != NULL) && son->body->individual) son = son->next;
+ if(son != NULL)
+ {
+ site2 = adr_beginning(son->body->prefix);
+
+ if(are_same_site(site, site2))
+ {
+ son->body->individual = 1;
+ nb_lines++;
+ }
+ son = son->next;
+ }
+ }
+
+ if(nb_lines > max_nb_lines)
+ if(level_person(node->body->prefix, NULL) == 0)
+ {
+ max_nb_lines = nb_lines;
+ guilty_site = site;
+ }
+ node = node->next;
+ }
+ }
+
+ if(guilty_site != NULL)
+ {
+ duration = DEFAULT_SHIT_TIME;
+ r = pattern;
+ *r++ = '*'; *r++ = '!'; *r++ = '*'; *r++ = '@';
+ concat_pattern_from_host(r, guilty_site);
+ add_mode(where, "+m", NULL);
+ smart_shit(NULL, NULL, pattern, "Alert", duration);
+ smart_ban(where, pattern);
+ send_mode(where);
+ filter_kick(where, pattern, "Filter kick on alert");
+ add_mode(where, "-m", NULL);
+ send_mode(where);
+ }
+ else tell(chat, nick, "\002No flooding site detected\002\n");
+}
+
+void check_one_flood(NodeList<FloodLine *> *node)
+{
+ NodeList<FloodLine *> *son;
+ char *userhost, *userhost2, *nick;
+ int nb_lines;
+
+ userhost = reach_loginathost(node->body->prefix);
+
+ nb_lines = 0;
+ son = node;
+ while(son != NULL)
+ {
+ while((son != NULL) && son->body->individual) son = son->next;
+ if(son != NULL)
+ {
+ if(!son->body->alreadykicked)
+ {
+ userhost2 = reach_loginathost(son->body->prefix);
+
+ if(strcmp(userhost, userhost2) == 0)
+ {
+ son->body->individual = 1;
+ nb_lines++;
+ }
+ }
+ son = son->next;
+ }
+ }
+
+ if(nb_lines >= MAX_LINE_FLOOD)
+ {
+
+#ifdef BAN_ON_FLOOD
+ char *pattern, *banid;
+ if((level_person(node->body->prefix, NULL) < LEVEL_OP))
+ {
+ pattern = pattern(node->body->prefix, 0);
+ banid = clean_banid(pattern);
+ smart_ban(current_channel, banid);
+ send_mode(current_channel);
+ mode_change_list.Insert(new DelayModeChange(current_channel,
+ "-b", banid,
+ BAN_FLOOD_DELAY));
+ 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;
+
+ for(son = flood_list.first; son != NULL; son = son->next)
+ {
+ userhost2 = reach_loginathost(son->body->prefix);
+ if(strcmp(userhost, userhost2) == 0) son->body->alreadykicked = 1;
+ }
+ }
+
+}
+
+void check_flood()
+{
+ int nb_lines, nb_ctcp;
+ NodeList<FloodLine *> *node, *next, *pred;
+
+ nb_lines = 0; nb_ctcp = 0;
+ pred = NULL;
+ node = flood_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(node->body->time >= current_time - FLOOD_DELAY)
+ {
+ nb_lines += node->body->weigth;
+ if((node->body->kind == FL_CTCP) && !node->body->alreadykicked)
+ nb_ctcp += node->body->weigth;
+ pred = node;
+ node->body->Reset();
+ }
+ else
+ {
+ if(pred == NULL) flood_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ node = next;
+ }
+
+ /*
+ if(nb_ctcp >= MAX_CTCP_FLOOD)
+ {
+ add_mode(current_channel, "+m", NULL);
+ send_mode(current_channel);
+ mode_change_list.Insert(new DelayModeChange(current_channel,
+ "-m", NULL,
+ ANTI_CLONES_DELAY));
+ }
+ */
+
+ if(nb_lines >= MAX_LINE_FLOOD)
+ {
+ for(node = flood_list.first; node != NULL; node = node->next)
+ node->body->individual = 0;
+
+ node = flood_list.first;
+ while(node != NULL)
+ {
+ while((node != NULL) && node->body->individual) node = node->next;
+ if(node != NULL)
+ {
+ if(!node->body->alreadykicked) check_one_flood(node);
+ node = node->next;
+ }
+ }
+ }
+}
+
+inline void add_flood_line(char *prefix, int kind, int weigth)
+{
+ flood_list.Insert(new FloodLine(prefix, kind, weigth));
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called for all mode changes
+// signe indicates if it's a + or - mode change
+// param is NULL for mode change without parameters
+
+void IRC_ONE_MODE(char *where, char *who, int signe, char mode, char *param)
+{
+ char *c, *banid;
+ char buffer[3];
+
+ if(signe < 0) buffer[0] = '-'; else buffer[0] = '+';
+ buffer[1] = mode;
+ buffer[2] = '\0';
+ if(param != NULL) uncap(param);
+
+ clean_delay_mode_change(where, buffer, param);
+
+#ifdef SCREEN_OUTPUT
+ cout<<"ONE MODE CHANGE CHANNEL ("<<where<<")";
+ cout<<" BY ("<<who<<") MODE "<<signe<<" "<<mode;
+ cout<<" ON "<<param<<"\n";
+#endif
+
+ uncap(param);
+
+ // Basic anti-hack procedure. All +o and +b mode done by servers are
+ // canceled (we have to look if the person is a friend or not)
+ switch(mode)
+ {
+ case 'b':
+ if(is_hostname(who))
+ {
+ if(deban_delay == 0)
+ {
+ if(signe>0) add_mode(where, "-b", param);
+ else add_mode(where, "+b", param);
+ }
+ else
+ {
+ if(signe>0)
+ mode_change_list.Insert(new DelayModeChange(where, "-b", param,
+ deban_delay));
+ else
+ mode_change_list.Insert(new DelayModeChange(where, "+b", param,
+ deban_delay));
+ }
+ }
+
+ if(signe > 0)
+ {
+ banid_list.Add(param);
+ banid = clean_banid(param);
+ if(strcmp(banid, param) != 0) smart_ban(where, banid);
+ delete banid;
+ }
+ else banid_list.Remove(param);
+ break;
+
+ case 'o':
+ if(is_hostname(who))
+ {
+ c = prefix_from_nick(param);
+ if((signe > 0) && (level_person(c, NULL) < LEVEL_FRIEND))
+ add_mode(where, "-o", param);
+ if((signe < 0) && (level_person(c, NULL) >= LEVEL_FRIEND))
+ add_mode(where, "+o", param);
+ }
+ else
+ if((signe<0) &&
+ (level_person(who, NULL) <
+ level_person(prefix_from_nick(param), NULL)) &&
+ (level_person(prefix_from_nick(param), NULL) > 0))
+ {
+ c = cut_nick_from_prefix(who);
+ add_mode(where, "-o", c);
+ add_mode(where, "+o", param);
+ delete c;
+ }
+ break;
+
+ case 'i':
+ if(signe>0) if(is_hostname(who) || mode_protect_on)
+ add_mode(where, "-i", NULL);
+ break;
+
+ case 'l':
+ if(signe>0) if(is_hostname(who) || mode_protect_on)
+ add_mode(where, "-l", NULL);
+ break;
+
+ case 'p':
+ if(signe>0) if(is_hostname(who) || mode_protect_on)
+ add_mode(where, "-p", NULL);
+ break;
+
+ case 'k':
+ if(signe>0) if(is_hostname(who) || mode_protect_on)
+ add_mode(where, "-k", param);
+ break;
+
+ case 'm':
+ if(is_hostname(who))
+ {
+ if(signe>0) add_mode(where, "-m", NULL);
+ }
+ else if(mode_protect_on)
+ {
+ if(level_person(who, NULL) < LEVEL_OP)
+ {
+ if(signe>0) add_mode(where, "-m", NULL);
+ else add_mode(where, "+m", NULL);
+ c = cut_nick_from_prefix(who);
+ add_mode(where, "-o", c);
+ delete c;
+ }
+ }
+ break;
+
+ case 's':
+ if(signe>0) if(is_hostname(who) || mode_protect_on)
+ add_mode(where, "-s", NULL);
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a "MODE" command
+// You should not modify it, unless you find a bug.
+// Modify only IRC_ONE_MODE()
+
+void IRC_MODE(char *where, char *who, char *mode, char **params)
+{
+ int param_no, signe;
+
+ param_no = 0;
+ signe = 1;
+ while(*mode != '\0')
+ {
+ switch(*mode)
+ {
+ case '+':
+ signe = 1;
+ break;
+ case '-':
+ signe = -1;
+ break;
+ default:
+ if((*mode == 'l') || (*mode == 'v') ||
+ (*mode == 'k') || (*mode == 'o') ||
+ (*mode == 'b'))
+ IRC_ONE_MODE(where, who, signe, *mode, params[param_no++]);
+ else
+ IRC_ONE_MODE(where, who, signe, *mode, NULL);
+
+ break;
+ }
+ mode++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void get_one_line(ifstream *s, char *buffer, int buffer_size)
+{
+ char *c;
+ int d, ok;
+ c = buffer;
+ ok = 1;
+ while(ok)
+ {
+ d = s->get();
+ if(d>0)
+ {
+ if(d != '\n') *c++ = d;
+ else ok = 0;
+ }
+ else ok = 0;
+ ok &= (c<buffer + buffer_size);
+ }
+ *c = '\0';
+}
+
+int LoadConfigFile(char *name)
+{
+ ifstream *file;
+ int duration, level, error;
+ char *r, *banid;
+ char pattern[SMALL_BUFFER_SIZE], buffer[SMALL_BUFFER_SIZE];
+
+ file = new ifstream(name);
+ if(!file->fail())
+ {
+ clear_levels();
+ clear_shit();
+ restricted_list.Clear();
+ while(!file->eof())
+ {
+ get_one_line(file, IRC_buffer, BUFFER_SIZE);
+ if(strlen(IRC_buffer) > 0)
+ {
+ r = IRC_buffer;
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ if(strcmp(buffer, "FRIEND") == 0)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ level = atoi(buffer);
+ if(r!= NULL)
+ {
+ r = next_word(pattern, r, SMALL_BUFFER_SIZE);
+ uncap(pattern);
+ level_list.Insert(new Person(pattern, level, r));
+ }
+ }
+ }
+ else if(strcmp(buffer, "RESTRICTED") == 0)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ cout<<"RESTRICTED->"<<buffer<<"\n";
+ restricted_list.Insert(strdup(buffer));
+ }
+ }
+ else if(strcmp(buffer, "SHIT") == 0)
+ {
+ if(r != NULL)
+ {
+ r = next_word(pattern, r, SMALL_BUFFER_SIZE);
+ uncap(pattern);
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ duration = atoi(buffer);
+ if(r == NULL) r = "Shit";
+ banid = clean_banid(pattern);
+ smart_shit(NULL, NULL, banid, r, duration);
+ delete banid;
+ }
+ }
+ }
+ else if(strcmp(buffer, "OPDELAY") == 0)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ op_delay = atoi(buffer);
+ }
+ }
+ else if(strcmp(buffer, "DEBANDELAY") == 0)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ deban_delay = atoi(buffer);
+ }
+ }
+ else if(strcmp(buffer, "CONTROLCHAR") == 0)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ if(buffer[0] != '\0') control_char = buffer[0];
+ }
+ }
+ }
+ }
+ shit_list.Reverse();
+ level_list.Reverse();
+ restricted_list.Reverse();
+ error = 0;
+ }
+ else error = 1;
+
+ delete file;
+
+ return error;
+}
+
+int SaveConfigFile(char *name)
+{
+ ofstream *file;
+ NodeList<Welcome *> *welcome;
+ NodeList<Person *> *person;
+ NodeList<char *> *restricted;
+ int error;
+
+ file = new ofstream(name);
+ if(!file->fail())
+ {
+ (*file)<<"% Config file for a TropBot " VERSION "\n";
+ (*file)<<"\n";
+
+ (*file)<<"OPDELAY "<<op_delay<<"\n";
+ (*file)<<"DEBANDELAY "<<deban_delay<<"\n";
+ (*file)<<"CONTROLCHAR "<<control_char<<"\n";
+
+ (*file)<<"\n";
+
+ for(person=level_list.first; person != NULL; person=person->next)
+ {
+ (*file)<<"FRIEND "<<person->body->level<<" "<<person->body->pattern;
+ if(person->body->passwd != NULL) (*file)<<" "<<person->body->passwd;
+ (*file)<<"\n";
+ }
+
+ (*file)<<"\n";
+
+ for(restricted=restricted_list.first;
+ restricted != NULL;
+ restricted=restricted->next)
+ (*file)<<"RESTRICTED "<<restricted->body<<"\n";
+
+ (*file)<<"\n";
+
+ for(welcome=shit_list.first; welcome != NULL; welcome=welcome->next)
+ (*file)<<"SHIT "<<welcome->body->pattern<<" "<<
+ welcome->body->time_max - current_time<<" "<<
+ welcome->body->comment<<"\n";
+
+ error = 0;
+ }
+ else error = 1;
+
+ delete file;
+
+ return error;
+}
+
+//-----------------------------------------------------------------------------
+
+void notice_list_by_sites(DCCChat *chat, char *nick, char *pattern)
+{
+ NodeList<char *> *node1, *node2;
+ int *ok, nb, k, l, level, put_blank;
+ char *c, *d, *buf;
+ int nb_total, nb_person[LEVEL_MAX+1];
+
+ nb_total = 0;
+ for(k=0; k<LEVEL_MAX+1; k++) nb_person[k] = 0;
+
+ nb = present_people.Lenght();
+ ok = new int[nb];
+ for(k = 0; k<nb; k++) ok[k] = 0;
+ k = 0;
+ node1 = present_people.first;
+
+ buf = IRC_buffer;
+
+ cerr<<"PATTERN=>"<<pattern<<"<\n";
+
+ if(pattern != NULL)
+ {
+ concat(buf, "\002");
+ concat(buf, pattern);
+ concat(buf, "\002 and same site : ");
+ }
+
+ while(node1 != NULL)
+ {
+ cout<<" =>"<<node1->body<<"\n";
+
+ if((pattern == NULL) || match_pattern(pattern, node1->body))
+ {
+ c = adr_beginning(node1->body);
+ put_blank = 0;
+ l = k;
+ node2 = node1;
+ while(node2 != NULL)
+ {
+ d = adr_beginning(node2->body);
+ if(are_same_site(c, d))
+ {
+ d = node2->body;
+ level = level_person(d, NULL);
+ nb_total++;
+ nb_person[level]++;
+ if(put_blank) *buf++ = '/'; else put_blank = 1;
+
+ if(level == LEVEL_OP) *buf++ = '\002';
+ else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
+
+ while((*d != '!') && (*d != '\0')) *buf++ = *d++;
+
+ if(level == LEVEL_OP) *buf++ = '\002';
+ else if(level >= LEVEL_DEFENCE) *buf++ = '\026';
+
+ ok[l] = 1;
+
+ if(buf > IRC_buffer + NB_CHAR_MAX)
+ {
+ *buf++ = '\n'; *buf++ = '\0';
+ tell(chat, nick, IRC_buffer);
+ buf = IRC_buffer;
+ }
+ }
+
+ do
+ {
+ l++;
+ node2 = node2->next;
+ }
+ while((node2 != NULL) && (ok[l] == 1));
+ }
+
+ concat(buf, " ");
+ }
+
+ do
+ {
+ k++;
+ node1 = node1->next;
+ }
+ while((node1 != NULL) && (ok[k] == 1));
+ }
+
+ *buf++ = '\n'; *buf++ = '\0';
+ tell(chat, nick, IRC_buffer);
+
+ sprintf(IRC_buffer, "Total %d (\002%d\002)\n",
+ nb_total,
+ nb_person[LEVEL_OP] + nb_person[LEVEL_DEFENCE] +
+ nb_person[LEVEL_MASTER]);
+ tell(chat, nick, IRC_buffer);
+
+ delete ok;
+}
+
+//-----------------------------------------------------------------------------
+
+void notice_shit_list(DCCChat *chat, char *nick, char *pattern, int matched)
+{
+ int n;
+ char *string_duration;
+ NodeList<Welcome *> *node;
+
+ if(shit_list.Lenght() == 0) tell(chat, nick, "\002Empty shit-list\002\n");
+ else
+ {
+ n = 0;
+ for(node = shit_list.first; node != NULL; node=node->next)
+ if((matched && match_pattern(pattern, node->body->pattern))
+ || (!matched && match_pattern(node->body->pattern, pattern)))
+ {
+ n++;
+ string_duration = seconds_to_string(node->body->time_max
+ - current_time);
+
+ sprintf(IRC_buffer, "%s for %s (%s)\n",
+ node->body->pattern,
+ string_duration,
+ node->body->comment);
+ tell(chat, nick, IRC_buffer);
+ delete string_duration;
+ }
+
+ if(n == 0) tell(chat, nick, "\002No corresponding shits\002\n");
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void add_in_history(char *prefix, char *action)
+{
+ NodeList<char *> *node, *pred, *next;
+ char *s, *t;
+ int n;
+
+ s = new char[strlen(prefix) + strlen(action) + 4];
+ t = s;
+ concat(t, prefix);
+ concat(t, " : ");
+ concat(t, action);
+ *t++ = '\0';
+ history.Add(s);
+
+ n = 0;
+ pred = NULL; next = NULL; node = history.first;
+ while(node != NULL)
+ {
+ n++;
+ next = node->next;
+ if(n>HISTORY_SIZE)
+ {
+ if(pred == NULL) history.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+}
+
+void notice_history(DCCChat *chat, char *nick)
+{
+ NodeList<char *> *node;
+
+ for(node = history.first; node != NULL; node = node->next)
+ {
+ sprintf(IRC_buffer, "%s\n", node->body);
+ tell(chat, nick, IRC_buffer);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+int dont_flood_server()
+{
+ return current_time >= last_answer_time + DELAY_ANSWERS;
+}
+
+void msg_users(DCCChat *chat, char *nick, char *pattern, char *msg)
+{
+ NodeList<char *> *node;
+ char *nick_user;
+ int nb;
+
+ sprintf(IRC_buffer, "\002[msg to %s]\002 %s\n", pattern, msg);
+ tell(chat, nick, IRC_buffer);
+
+ nb = 0;
+ for(node = present_people.first; node != NULL; node = node->next)
+ {
+ if(match_pattern(pattern, node->body))
+ {
+ nb++;
+ nick_user = cut_nick_from_prefix(node->body);
+ sprintf(IRC_buffer, "PRIVMSG %s :\002[msg to %s]\002 %s\n",
+ nick_user, pattern, msg);
+ write_irc(IRC_buffer);
+ delete nick_user;
+ }
+ }
+
+ sprintf(IRC_buffer, "\002[msg sent to %d user(s)]\002\n", nb);
+ tell(chat, nick, IRC_buffer);
+};
+
+//-----------------------------------------------------------------------------
+
+#define CMD_DEFAULT 0
+#define CMD_JOIN 1
+#define CMD_HOME 2
+#define CMD_BAN 3
+#define CMD_SBAN 4
+
+void tropbot_cmd(DCCChat *chat, char *prefix, char *nick, char *msg)
+{
+ char buffer[SMALL_BUFFER_SIZE], buffer_time[SMALL_BUFFER_SIZE];
+ char *r, *s, *c, *banid;
+ char *string_duration;
+ int cmd, level, l, no_authorized, od;
+ int duration;
+ NodeList<DCCChat *> *node;
+
+ r = msg;
+
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+ if(*buffer == '&')
+ {
+ level = level_person(prefix, buffer+1);
+ if(r != NULL) r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ else return;
+ }
+ else level = level_person(prefix, NULL);
+
+ cmd = CMD_DEFAULT;
+ if(eq("join", buffer)) cmd = CMD_JOIN;
+ else if(eq("home", buffer)) cmd = CMD_HOME;
+ else if(eq("b", buffer) || eq("ban", buffer)) cmd = CMD_BAN;
+ else if(eq("sb", buffer) || eq("siteban", buffer)) cmd = CMD_SBAN;
+
+ no_authorized = 0;
+
+ if(eq("ms", buffer) || eq("myshit", buffer))
+ {
+ if(dont_flood_server()) notice_shit_list(chat, nick, prefix, 0);
+ }
+ else if(eq("sl", buffer) || eq("shitlist", buffer))
+ {
+ if(level >= LEVEL_FRIEND)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ uncap(buffer);
+
+ if(is_pattern(buffer)) notice_shit_list(chat, nick, buffer, 1);
+ else
+ {
+ wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
+ MODE_SHITLIST, 0));
+
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ else notice_shit_list(chat, nick, "*", 1);
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("www", buffer))
+ {
+ if(dont_flood_server())
+ tell(chat, nick, "THX-1138's home page at "
+ "http://www.eleves.ens.fr:8080/home/fleuret/\n");
+ }
+ else if(eq("w", buffer) || eq("who", buffer))
+ {
+ if(level >= LEVEL_FRIEND)
+ {
+ if(r == NULL) notice_list_by_sites(chat, nick, NULL);
+ 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))
+ {
+ 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 if(eq("msg", buffer) || eq("message", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ if(r != NULL)
+ {
+ if(is_pattern(buffer)) msg_users(chat, nick, buffer, r);
+ else
+ {
+ uncap(buffer);
+ wait_list.Insert(new WaitInfos(buffer, r, chat,
+ nick,
+ MODE_MSG, 0));
+
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("h", buffer) || eq("history", buffer))
+ {
+ if(level >= LEVEL_OP) notice_history(chat, nick);
+ else no_authorized = 1;
+ }
+ else if(eq("level", buffer))
+ {
+ if(level >= LEVEL_FRIEND)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ uncap(buffer);
+
+ wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+ MODE_LEVEL, 0));
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ else
+ {
+ sprintf(IRC_buffer, "%s is level %d\n", prefix,
+ level_person(prefix, NULL));
+ tell(chat, nick, IRC_buffer);
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("help", buffer))
+ {
+ if(dont_flood_server() || (level >= LEVEL_FRIEND))
+ {
+ if(father)
+ {
+ sprintf(IRC_buffer,
+ "control_char '%c' op_delay %ds deban_delay %ds"
+ " your level is %d. I am a father with %d sons.\n",
+ control_char, op_delay, deban_delay,
+ 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);
+ tell(chat, nick, IRC_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");
+ }
+
+ if(level >= LEVEL_MASTER)
+ {
+ 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");
+ }
+
+ if(chat != NULL)
+ {
+ tell(chat, nick, "\002\037u\037\002sers\002 \002\037t\037\002alk\002 <msg>\n");
+ }
+
+ }
+ else if((cmd == CMD_JOIN) || (cmd == CMD_HOME))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(global_state == STATE_WAIT)
+ {
+ sprintf(IRC_buffer, "PART %s\n", current_channel);
+ write_irc(IRC_buffer);
+ if(cmd == CMD_HOME)
+ strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
+ else
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ strncpy(wanted_channel, buffer, SMALL_BUFFER_SIZE);
+ }
+ uncap(wanted_channel);
+ sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
+ write_irc(IRC_buffer);
+ }
+ else
+ tell(chat, nick, "Can't join right now, retry in a while\n");
+ } else no_authorized = 1;
+ }
+ else if(eq("op", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r == NULL) add_mode(current_channel, "+o", nick);
+ else
+ while(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ add_mode(current_channel, "+o", buffer);
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("nick", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r != NULL)
+ {
+ r = next_word(wanted_nick, r, SMALL_BUFFER_SIZE);
+ sprintf(buffer, "NICK %s\n", wanted_nick);
+ write_irc(buffer);
+ }
+ } else no_authorized = 1;
+ }
+ else if(eq("db", buffer) || eq("deban", buffer))
+ {
+ if(level >= LEVEL_FRIEND)
+ {
+ while(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ if(is_pattern(buffer))
+ {
+ NodeList<char *> *node;
+ for(node = banid_list.first; node != NULL; node = node->next)
+ if(match_pattern(buffer, node->body))
+ add_mode(current_channel, "-b", node->body);
+ }
+ else
+ {
+ wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
+ MODE_UNBAN_NICK, 0));
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ } else no_authorized = 1;
+ }
+ else if((cmd == CMD_BAN) || (cmd == CMD_SBAN))
+ {
+ if(level >= LEVEL_OP)
+ {
+ while(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ uncap(buffer);
+
+ if(is_pattern(buffer))
+ {
+ banid = clean_banid(buffer);
+ smart_ban(current_channel, banid);
+ delete banid;
+ }
+ else
+ {
+ switch(cmd)
+ {
+ case CMD_BAN:
+ wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+ MODE_BAN_NICK, 0));
+ break;
+ case CMD_SBAN:
+ wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+ MODE_BAN_SITE, 0));
+ break;
+ default:
+ break;
+ }
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("pb", buffer) || eq("pruneban", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r != NULL)
+ {
+ NodeList<char *> *node;
+ int n;
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ n = atoi(buffer);
+ if(n >= 0)
+ {
+ for(node = banid_list.first; node != NULL;
+ node = node->next)
+ if(n == 0) add_mode(current_channel, "-b", node->body);
+ else n--;
+ }
+ }
+ } else no_authorized = 1;
+ }
+ else if(eq("synch", buffer))
+ {
+ if(level >= LEVEL_OP) synch(current_channel);
+ else no_authorized = 1;
+ }
+ else if(eq("s", buffer) || eq("shit", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+ if(is_pattern(buffer))
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+ duration = string_to_seconds(buffer_time);
+ }
+ else duration = DEFAULT_SHIT_TIME;
+
+ if(r == NULL) r = "Shit nick";
+
+ uncap(buffer);
+ banid = clean_banid(buffer);
+ smart_shit(chat, nick, banid, r, duration);
+ delete banid;
+ }
+ else
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+ duration = string_to_seconds(buffer_time);
+ }
+ else duration = DEFAULT_SHIT_TIME;
+
+ if(r == NULL) r = "Shit nick";
+
+ uncap(buffer);
+ wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+ MODE_SHIT_NICK,
+ duration));
+
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+
+ else if(eq("fk", buffer) || eq("filterkick", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ uncap(buffer);
+ if(is_pattern(buffer))
+ {
+ if(r == NULL) r = "Filter kick";
+ filter_kick(current_channel, buffer, r);
+ }
+ else
+ {
+ if(r == NULL) r = "Filter Kick";
+ wait_list.Insert(new
+ WaitInfos(buffer, r, chat, nick,
+ MODE_FILTER_KICK, 0));
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+
+ else if(eq("a", buffer) || eq("alert", buffer))
+ {
+ if(level >= LEVEL_OP) alert(current_channel, chat, nick);
+ else no_authorized = 1;
+ }
+
+ else if(eq("sh", buffer) || eq("shithost", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+ if(r != NULL)
+ {
+ r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+ duration = string_to_seconds(buffer_time);
+ }
+ else duration = DEFAULT_SHIT_TIME;
+
+ if(r == NULL) r = "Shit host";
+
+ uncap(buffer);
+ wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+ MODE_SHIT_HOST, duration));
+
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("ss", buffer) || eq("shitsite", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+ if(r != NULL)
+ {
+ r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+ duration = string_to_seconds(buffer_time);
+ }
+ else duration = DEFAULT_SHIT_TIME;
+
+ if(r == NULL) r = "Shit site";
+
+ uncap(buffer);
+ wait_list.Insert(new WaitInfos(buffer, r, chat, nick,
+ MODE_SHIT_SITE, duration));
+
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("pus", buffer) || eq("punshit", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ while(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+ if(strlen(buffer) > 0)
+ {
+ NodeList<Welcome *> *node, *next, *pred;
+ pred = NULL;
+ uncap(buffer);
+ node = shit_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(match_pattern(buffer, node->body->pattern))
+ {
+ smart_unban(current_channel, node->body->pattern);
+ if(pred == NULL) shit_list.first = next;
+ else pred->next = next;
+ sprintf(IRC_buffer,
+ "Unshit %s (%s)\n",
+ node->body->pattern,
+ node->body->comment);
+ tell(chat, nick, IRC_buffer);
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("us", buffer) || eq("unshit", buffer))
+ {
+ if(level >= LEVEL_OP)
+ {
+ while(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+
+ uncap(buffer);
+ if(is_pattern(buffer))
+ {
+ NodeList<Welcome *> *node, *next, *pred;
+ pred = NULL;
+ uncap(buffer);
+ node = shit_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(strcmp(node->body->pattern, buffer) == 0)
+ {
+ if(pred == NULL) shit_list.first = next;
+ else pred->next = next;
+ sprintf(IRC_buffer,
+ "Unshit %s (%s)\n",
+ buffer, node->body->comment);
+ tell(chat, nick, IRC_buffer);
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+ }
+ else
+ {
+ wait_list.Insert(new WaitInfos(buffer, NULL, chat, nick,
+ MODE_UNSHIT_NICK, 0));
+
+ sprintf(IRC_buffer, "WHOIS %s\n", buffer);
+ write_irc(IRC_buffer);
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("friend", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ if(r != NULL)
+ {
+ r = next_word(buffer_time, r, SMALL_BUFFER_SIZE);
+ l = atoi(buffer_time);
+ if((l > 0) && (l<=LEVEL_MASTER))
+ {
+ level_list.Insert(new Person(buffer, l, r));
+ sprintf(IRC_buffer,
+ "Adding %s with level %d and passwd %s\n",
+ buffer, l, r);
+ tell(chat, nick, IRC_buffer);
+ SaveConfigFile(config_file);
+ }
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("opdelay", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ od = atoi(buffer);
+ if((od>=0) && (od <= 60))
+ {
+ op_delay = od;
+ sprintf(IRC_buffer,"Oping delay set to %ds\n", op_delay);
+ tell(chat, nick, IRC_buffer);
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("debandelay", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ od = atoi(buffer);
+ if((od>=0) && (od <= 60))
+ {
+ deban_delay = od;
+ sprintf(IRC_buffer,
+ "Deban delay set to %ds\n",
+ deban_delay);
+ tell(chat, nick, IRC_buffer);
+ }
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("controlchar", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ control_char = buffer[0];
+ sprintf(IRC_buffer, "Control char set to '%c'\n",
+ control_char);
+ tell(chat, nick, IRC_buffer);
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("die", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ sprintf(IRC_buffer, "QUIT :Killed by %s\n", nick);
+ write_irc(IRC_buffer);
+ alive = 0;
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("server", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(r != NULL)
+ {
+ next_word(wanted_server, r, SMALL_BUFFER_SIZE);
+ if(r != NULL)
+ {
+ next_word(buffer, r, SMALL_BUFFER_SIZE);
+ wanted_port = atoi(buffer);
+ if(wanted_port == 0) wanted_port = 6667;
+ }
+ else wanted_port = DEFAULT_PORT;
+
+ sprintf(IRC_buffer,
+ "Trying to connect %s:%d\n",
+ wanted_server, wanted_port);
+ tell(chat, nick, IRC_buffer);
+
+ sprintf(IRC_buffer, "QUIT :Changing server\n");
+ write_irc(IRC_buffer);
+
+ cerr<<"KILLING CONNECTION : Changing server\n";
+ cerr.flush();
+ kill_connection();
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("clone", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(father)
+ {
+ if(nb_sons < NB_SONS_MAX)
+ {
+ if(r != NULL) next_word(buffer, r, SMALL_BUFFER_SIZE);
+ clone(buffer);
+ nb_sons++;
+ }
+ else tell(chat, nick, "Too many clones, can't clone\n");
+ }
+ else
+ {
+ tell(chat, nick, "I'm a clone, can't clone\n");
+ }
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("save", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
+ if(SaveConfigFile(config_file))
+ {
+ sprintf(IRC_buffer,
+ "Can't save the %s configuration file\n",
+ config_file);
+ }
+ else
+ {
+ sprintf(IRC_buffer,
+ "Saving the %s configuration file\n",
+ config_file);
+ }
+ tell(chat, nick, IRC_buffer);
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("load", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ if(r != NULL) r = next_word(config_file, r, SMALL_BUFFER_SIZE);
+ if(LoadConfigFile(config_file))
+ {
+ sprintf(IRC_buffer,
+ "Can't load the %s configuration file\n",
+ config_file);
+ }
+ else
+ {
+ sprintf(IRC_buffer,
+ "Loading the %s configuration file\n",
+ config_file);
+ }
+ tell(chat, nick, IRC_buffer);
+ }
+ else no_authorized = 1;
+ }
+ else if(eq("reset", buffer))
+ {
+ if(level >= LEVEL_MASTER)
+ {
+ sprintf(IRC_buffer, "QUIT :reset command sent by %s\n", nick);
+ write_irc(IRC_buffer);
+ cerr<<"KILLING CONNECTION : Die\n";
+ cerr.flush();
+ kill_connection();
+ }
+ else no_authorized = 1;
+ }
+
+ // DCC CHAT only commands
+
+ else if((chat != NULL) && (eq("t", buffer) || eq("talk", buffer)))
+ {
+ NodeList<DCCChat *> *node;
+ sprintf(IRC_buffer, "<%s> %s\n", prefix, r);
+ for(node = dcc_chat_list.first; node != NULL; node = node->next)
+ if(node->body != chat) tell(node->body, NULL, IRC_buffer);
+ }
+ else if((chat != NULL) && (eq("u", buffer) || eq("users", buffer)))
+ {
+ for(node = dcc_chat_list.first; node != NULL; node = node->next)
+ {
+ sprintf(IRC_buffer, "%s\n", node->body->prefix);
+ tell(chat, NULL, IRC_buffer);
+ }
+ }
+
+ // Unknown command
+
+ else if(dont_flood_server())
+ {
+ sprintf(IRC_buffer, "Unknown command \002%s\002\n", buffer);
+ tell(chat, nick, IRC_buffer);
+ }
+ }
+
+ if(no_authorized)
+ {
+ if(dont_flood_server())
+ {
+ sprintf(IRC_buffer,
+ "You are not authorized to use \002%s\002\n", buffer);
+ tell(chat, nick, IRC_buffer);
+ }
+ }
+ else
+ {
+ r = msg;
+ if(*r == '&') r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ add_in_history(prefix, r);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+int accepting_dcc_chat(char *prefix, char *nick, int level, char *r)
+{
+ NodeList<DCCChat *> *node;
+ int socket, port_number;
+ char host[SMALL_BUFFER_SIZE], port[SMALL_BUFFER_SIZE];
+ DCCChat *dcc_chat;
+
+ if(r == NULL) return 1;
+ else r = next_word(host, r, SMALL_BUFFER_SIZE);
+
+ if(strcmp(host, "chat") != 0) return 1;
+
+ if(r == NULL) return 1;
+ else r = next_word(host, r, SMALL_BUFFER_SIZE);
+
+ if(r == NULL) return 1;
+ else r = next_word(port, r, SMALL_BUFFER_SIZE);
+
+ port_number = atoi(port);
+ socket = call_socket(host, port_number);
+
+ if(socket <= 0) return 1;
+ else
+ {
+ dcc_chat = new DCCChat(prefix, socket, port_number);
+ dcc_chat_list.Insert(dcc_chat);
+
+ FD_SET(socket, &ready);
+
+ sprintf(IRC_buffer,
+ "Welcome to \002TropBot\002 " VERSION " on a DCC CHAT\n"
+ "You are known as %s, your level is %d.\n"
+ "You are client #%d on DCC CHAT\n",
+ prefix, level, dcc_chat_list.Lenght());
+
+ write(socket, IRC_buffer, strlen(IRC_buffer));
+
+ sprintf(IRC_buffer, "%s arrives with level %d.\n", prefix, level);
+ for(node=dcc_chat_list.first; node!= NULL; node = node->next)
+ if(node->body != dcc_chat) tell(node->body, NULL, IRC_buffer);
+
+ return 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a NOTICE
+
+void IRC_NOTICE(char *prefix,
+ char *who, char *msg, char **slice_ctcp, int n_ctcp)
+{
+ uncap(who);
+ if(strcmp(who, current_channel) == 0) add_flood_line(prefix, FL_NOTICE, 1);
+}
+
+void IRC_PRIVMSG(char *prefix,
+ char *who, char *msg, char **slice_ctcp, int n_ctcp)
+{
+ int k, version, ping, level;
+ char *nick, *r;
+ char buffer[SMALL_BUFFER_SIZE];
+
+ uncap(who);
+ nick = cut_nick_from_prefix(prefix);
+ 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(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);
+ }
+
+
+
+ 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)
+ {
+ if(dont_flood_server())
+ {
+ version = 1;
+ sprintf(IRC_buffer, "NOTICE %s :"
+ "\001VERSION \002TropBot\002 " VERSION OPTIONS
+ ", " SYSTEM " system, " DATE ". "
+ "Contact THX-1138 on IRC, or <francois.fleuret@inria.fr>"
+ "\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)
+ {
+ if(r != NULL)
+ {
+ r = next_word(buffer, r, SMALL_BUFFER_SIZE);
+ if(eq("CHAT", buffer))
+ {
+ 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 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;
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a QUIT
+
+void IRC_QUIT(char *prefix)
+{
+ present_people.Remove(prefix);
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a NICK
+
+void IRC_NICK(char *prefix, char *nick)
+{
+ char *s, *t;
+ int ok;
+ add_flood_line(prefix, FL_NICK, 1);
+ present_people.Remove(prefix);
+ s = IRC_buffer;
+ t = nick; while(*t != '\0') *s++=*t++; // copy the nick
+ *s++='!'; // put the '!'
+ t = reach_loginathost(prefix);
+ while(*t != '\0') *s++=*t++; // copy the user@host
+ *s = '\0'; // end of string
+ present_people.Add(IRC_buffer); // hop !
+
+ ok = 1; s = prefix; t = real_nick;
+ while(ok && (*t != '\0') && (*s != '\0')) ok = (*s++ == *t++);
+ if(ok && (*t == '\0') && (*s == '!'))
+ {
+ strncpy(real_nick, nick, SMALL_BUFFER_SIZE);
+ uncap(real_nick);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a PART
+
+void IRC_PART(char *prefix, char *where)
+{
+ char *nick;
+ add_flood_line(prefix, FL_PART, 1);
+ present_people.Remove(prefix);
+ nick = cut_nick_from_prefix(prefix);
+ if(strcmp(real_nick, nick) == 0)
+ {
+ present_people.Clear();
+ in_channel = 0;
+ }
+ delete nick;
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a KICK
+
+void IRC_KICK(char *prefix, char *where, char *victim_nick)
+{
+ char *c;
+ uncap(victim_nick);
+
+ if(strcmp(victim_nick, real_nick) == 0)
+ {
+ present_people.Clear();
+ in_channel = 0;
+ sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
+ write_irc(IRC_buffer);
+ }
+
+ 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;
+ }
+
+ c = prefix_from_nick(victim_nick);
+ if(c != NULL) present_people.Remove(c);
+ else cerr<<"** ERROR : non present person has been kicked out **\n";
+}
+
+//-----------------------------------------------------------------------------
+
+int check_restricted(char *where, char *prefix)
+{
+ char pattern[SMALL_BUFFER_SIZE];
+ NodeList<char *> *node;
+ char *p, *s;
+ int n, duration;
+
+ p = adr_beginning(prefix);
+
+ node = present_people.first;
+ n = 0;
+ while((node != NULL) && (n < 2))
+ {
+ s = adr_beginning(node->body);
+ if(strcmp(s, p) == 0) n++;
+ node = node->next;
+ }
+
+ if(n >= 2)
+ {
+ s = pattern;
+ concat(s, "*!*@");
+ concat(s, p);
+ *s++ = '\0';
+ duration = DEFAULT_RESTRICTED_TIME;
+ smart_shit(NULL, NULL, pattern, "Restricted site : no clones", duration);
+ smart_ban(where, pattern);
+ send_mode(where);
+ filter_kick(where, pattern, "Restricted site : no clones");
+ return 1;
+ }
+ else return 0;
+}
+
+// This function is called after a JOIN
+
+void IRC_JOIN(char *prefix, char *where)
+{
+ char *nick;
+ int l, restricted;
+ NodeList<Welcome *> *node;
+
+ nick = cut_nick_from_prefix(prefix);
+
+ if(strcmp(real_nick, nick) == 0)
+ {
+ strncpy(current_channel, where, SMALL_BUFFER_SIZE);
+ sprintf(IRC_buffer, "WHO %s\n", where);
+ write_irc(IRC_buffer);
+ present_people.Clear();
+ global_state = STATE_GETING_WHO;
+ in_channel = 1;
+ }
+ else
+ {
+ add_flood_line(prefix, FL_JOIN, 1);
+
+ uncap(where);
+ present_people.Add(prefix);
+
+ if(restricted_list.Matches(prefix))
+ restricted = check_restricted(where, prefix);
+ else restricted = 0;
+
+ if(!restricted)
+ {
+ l = level_person(prefix, NULL);
+
+ if(l >= LEVEL_OP)
+ {
+ if(l >= LEVEL_DEFENCE) add_mode(where, "+o", nick);
+ else
+ mode_change_list.Insert(new DelayModeChange(where, "+o",
+ nick, op_delay));
+ }
+ else
+ {
+ if(banid_list.Matches(prefix))
+ {
+ sprintf(IRC_buffer, "KICK %s %s :You are banned\n", where, nick);
+ write_irc(IRC_buffer);
+ }
+ else
+ {
+ for(node = shit_list.first; node != NULL; node = node->next)
+ if(match_pattern(node->body->pattern, prefix))
+ {
+ smart_ban(where, node->body->pattern);
+ send_mode(current_channel);
+
+ sprintf(IRC_buffer, "KICK %s %s :%s\n",
+ where, nick, node->body->comment);
+
+ write_irc(IRC_buffer);
+ }
+ }
+ }
+ }
+ }
+
+ delete nick;
+}
+
+//-----------------------------------------------------------------------------
+
+void IRC_RPL_BANLIST(char *prefix, char *channel, char *banid)
+{
+ banid_list.Add(banid);
+}
+
+void IRC_ENDOFBANLIST(char *prefix)
+{
+ banid_list.Reverse();
+ global_state = STATE_WAIT;
+}
+
+void IRC_RPL_ENDOFWHOIS(char *prefix, char *nick)
+{
+ NodeList<WaitInfos *> *node, *pred, *next;
+
+ uncap(nick);
+ node = wait_list.first;
+ pred = NULL;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(strcmp(nick, node->body->nick) == 0)
+ {
+ sprintf(IRC_buffer, "Can't find %s\n", nick);
+ tell(node->body->chat, node->body->user, IRC_buffer);
+
+ if(pred == NULL) wait_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+}
+
+void IRC_RPL_WHOISUSER(char *prefix,
+ char *nick, char *login, char *host, char *real_name)
+{
+ char *c, *d, *banid;
+ int l;
+ char buffer[SMALL_BUFFER_SIZE];
+ NodeList<WaitInfos *> *node, *next, *pred;
+
+ int no_pattern, one_login, all_machines;
+
+ uncap(nick);
+ uncap(login);
+ uncap(host);
+
+ pred = NULL;
+ node = wait_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+
+ if(strcmp(nick, node->body->nick) == 0)
+ {
+ c = buffer;
+
+ no_pattern = (node->body->mode == MODE_UNSHIT_NICK) ||
+ (node->body->mode == MODE_LEVEL) ||
+ (node->body->mode == MODE_UNBAN_NICK) ||
+ (node->body->mode == MODE_SHITLIST);;
+
+ one_login = (node->body->mode == MODE_SHIT_NICK) ||
+ (node->body->mode == MODE_BAN_NICK);
+
+ all_machines = (node->body->mode == MODE_SHIT_NICK) ||
+ (node->body->mode == MODE_BAN_NICK) ||
+ (node->body->mode == MODE_BAN_SITE) ||
+ (node->body->mode == MODE_FILTER_KICK) ||
+ (node->body->mode == MODE_SHIT_SITE) ||
+ (node->body->mode == MODE_MSG);
+
+ if(no_pattern)
+ {
+ concat(c, nick);
+ *c++ = '!';
+ concat(c, login);
+ *c++ = '@';
+ concat(c, host);
+ *c++ = '\0';
+ }
+ else
+ {
+ if((*login == '~') || (*login == '+') ||
+ (*login == '-') || (*login=='^'))
+ login++;
+
+ concat(c, "*!*");
+
+ if(one_login)
+ {
+
+ l = 0;
+ while((*login != '\0') && ((l<7) || *(login+1) == '\0'))
+ { *c++ = *login++; l++; }
+ if(*login != '\0') *c++ = '*';
+
+ }
+ *c++ = '@';
+
+ d = adr_beginning(host);
+ if(host != d) if(*(c-1) != '*') *c++ = '*';
+
+ if(all_machines) concat_pattern_from_host(c, d);
+ else
+ {
+ concat(c, d);
+ *c++ = '\0';
+ }
+
+ }
+
+ uncap(buffer);
+ banid = clean_banid(buffer);
+
+ if(node->body->mode == MODE_MSG)
+ msg_users(node->body->chat, node->body->user,
+ banid, node->body->comment);
+
+ else if(node->body->mode == MODE_FILTER_KICK)
+ filter_kick(current_channel, banid, node->body->comment);
+
+ else if((node->body->mode == MODE_BAN_NICK) ||
+ (node->body->mode == MODE_BAN_SITE))
+ smart_ban(current_channel, banid);
+
+ else if((node->body->mode == MODE_SHIT_NICK)
+ || (node->body->mode == MODE_SHIT_SITE)
+ || (node->body->mode == MODE_SHIT_HOST))
+ {
+ smart_shit(node->body->chat,
+ node->body->user, banid, node->body->comment,
+ node->body->duration);
+
+ if(prefix_from_nick(nick) != NULL)
+ {
+ smart_ban(current_channel, banid);
+ send_mode(current_channel);
+ sprintf(IRC_buffer, "KICK %s %s :%s\n",
+ current_channel, nick, node->body->comment);
+ write_irc(IRC_buffer);
+ }
+
+ }
+
+ else if(node->body->mode == MODE_SHITLIST)
+ notice_shit_list(NULL, node->body->user, banid, 0);
+
+ else if(node->body->mode == MODE_LEVEL)
+ {
+ sprintf(IRC_buffer, "%s is level %d\n",
+ banid, level_person(banid, NULL));
+ tell(node->body->chat, node->body->user, IRC_buffer);
+ }
+ else if(node->body->mode == MODE_UNSHIT_NICK)
+ {
+ NodeList<Welcome *> *node2, *pred, *next;
+
+ node2 = shit_list.first;
+ pred = NULL;
+ while(node2 != NULL)
+ {
+ next = node2->next;
+ if(match_pattern(node2->body->pattern, banid))
+ {
+ if(pred == NULL) shit_list.first = next;
+ else pred->next = next;
+
+ sprintf(IRC_buffer, "Unshit %s (%s)\n",
+ node2->body->pattern, node2->body->comment);
+
+ tell(node->body->chat, node->body->user, IRC_buffer);
+
+ smart_unban(current_channel, node2->body->pattern);
+
+ delete node2->body;
+ delete node2;
+ }
+ else pred = node2;
+ node2 = next;
+ }
+ }
+ else if(node->body->mode == MODE_UNBAN_NICK)
+ {
+ NodeList<char *> *node2;
+ for(node2 = banid_list.first; node2 != NULL; node2 = node2->next)
+ if(match_pattern(node2->body, banid))
+ add_mode(current_channel, "-b", node2->body);
+ }
+
+
+ delete banid;
+
+ if(pred == NULL) wait_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+}
+
+// This function is called after a RPL_WHOREPLY
+
+void IRC_RPL_WHOREPLY(char *prefix,
+ char *where,
+ char *login, char *host, char *server,
+ char *nick, char *state)
+{
+ char *s, *t;
+
+ uncap(where);
+ uncap(nick);
+
+ if((global_state == STATE_GETING_WHO) &&
+ (strcmp(where, current_channel) == 0))
+ {
+ s = IRC_buffer;
+ t = nick; while(*t != '\0') *s++ = *t++;
+ *s++ = '!';
+ t = login; while(*t != '\0') *s++ = *t++;
+ *s++ = '@';
+ t = host; while(*t != '\0') *s++ = *t++;
+ *s++ = '\0';
+ present_people.Add(IRC_buffer);
+ }
+ else cerr<<where<<"!="<<current_channel<<"\n";
+}
+
+void IRC_RPL_ENDOFWHO(char *prefix, char *name)
+{
+ sprintf(IRC_buffer, "MODE %s +b\n", current_channel);
+ write_irc(IRC_buffer);
+ banid_list.Clear();
+ if(in_channel) global_state = STATE_GETING_BAN;
+ else global_state = STATE_WAIT;
+}
+
+//-----------------------------------------------------------------------------
+
+void IRC_ERR_NICKNAMEINUSE(char *prefix, char *channel)
+{
+ rand_nick(wanted_nick, jam_nick);
+#ifdef SCREEN_OUTPUT
+ cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
+#endif
+ sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
+ write_irc(IRC_buffer);
+ was_killed = 1; // We have been killed (I said PARANOID !)
+ time_killed = current_time; // Note when it happens
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a ERR_NOSUCHCHANNEL
+
+void IRC_ERR_NOSUCHCHANNEL(char *prefix, char *nick)
+{
+ strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
+ uncap(wanted_channel);
+}
+
+//-----------------------------------------------------------------------------
+
+// This function is called after a ERR_NICKCOLLISION (436)
+
+void IRC_ERR_NICKCOLLISION(char *prefix, char *nick)
+{
+ rand_nick(wanted_nick, jam_nick);
+#ifdef SCREEN_OUTPUT
+ cout<<"Nickname collision, trying "<<wanted_nick<<"\n";
+#endif
+ sprintf(IRC_buffer, "NICK %s\n", wanted_nick);
+ write_irc(IRC_buffer);
+ was_killed = 1; // We have been killed (I said PARANOID !)
+ time_killed = current_time; // Note when it happens
+}
+
+//-----------------------------------------------------------------------------
+
+// This is the main command. It is called for each line from the server.
+
+void get_command(char *prefix,
+ char **slice_cmd, int n_cmd,
+ char **slice_ctcp, int n_ctcp)
+{
+ char small_buffer[SMALL_BUFFER_SIZE];
+ char *cmd;
+
+ 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";
+#endif
+
+ if(prefix != NULL) uncap(prefix);
+
+ // No prefix : server command
+ if(prefix == NULL)
+ {
+ if(n_cmd > 0) if(eq("PING", cmd))
+ {
+ if(n_cmd > 2) sprintf(IRC_buffer, "PONG :%s\n", slice_cmd[1]);
+ else sprintf(IRC_buffer, "PONG\n");
+ write_irc(IRC_buffer);
+ }
+ }
+ else
+ {
+ // If we are not registred yet, then get the registration
+ if(eq("002", cmd))
+ {
+ if(!IRC_registred)
+ {
+ strncpy(real_nick, slice_cmd[1], SMALL_BUFFER_SIZE);
+ uncap(real_nick);
+ IRC_registred = 1;
+ sprintf(small_buffer, "MODE %s +i\n", real_nick);
+ write_irc(small_buffer);
+ sprintf(small_buffer, "JOIN %s\n", wanted_channel);
+ write_irc(small_buffer);
+ }
+ }
+ else if(eq("PRIVMSG", cmd))
+ IRC_PRIVMSG(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
+ else if(eq("NOTICE", cmd))
+ IRC_NOTICE(prefix, slice_cmd[1], slice_cmd[2], slice_ctcp, n_ctcp);
+ else if(eq("MODE", cmd))
+ IRC_MODE(slice_cmd[1], prefix, slice_cmd[2], slice_cmd+3);
+ else if(eq("JOIN", cmd)) IRC_JOIN(prefix, slice_cmd[1]);
+ else if(eq("KICK", cmd)) IRC_KICK(prefix, slice_cmd[1], slice_cmd[2]);
+ else if(eq("QUIT", cmd)) IRC_QUIT(prefix);
+ else if(eq("NICK", cmd)) IRC_NICK(prefix, slice_cmd[1]);
+ else if(eq("PART", cmd)) IRC_PART(prefix, slice_cmd[1]);
+ else if(eq("311", cmd))
+ IRC_RPL_WHOISUSER(prefix,
+ slice_cmd[2], slice_cmd[3], slice_cmd[4],
+ slice_cmd[6]);
+ else if(eq("318", cmd)) IRC_RPL_ENDOFWHOIS(prefix, slice_cmd[2]);
+ else if(eq("352", cmd))
+ IRC_RPL_WHOREPLY(prefix,
+ slice_cmd[2], slice_cmd[3], slice_cmd[4],
+ slice_cmd[5], slice_cmd[6], slice_cmd[7]);
+ else if(eq("315", cmd)) IRC_RPL_ENDOFWHO(prefix, slice_cmd[1]);
+ else if(eq("367", cmd))
+ IRC_RPL_BANLIST(prefix, slice_cmd[2], slice_cmd[3]);
+ else if(eq("368", cmd)) IRC_ENDOFBANLIST(prefix);
+ else if(eq("403", cmd)) IRC_ERR_NOSUCHCHANNEL(prefix, slice_cmd[1]);
+ else if(eq("433", cmd)) IRC_ERR_NICKNAMEINUSE(prefix, slice_cmd[1]);
+ else if(eq("436", cmd)) IRC_ERR_NICKCOLLISION(prefix, slice_cmd[1]);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// Rough routine to read the options
+
+void get_options(int argc, char **argv)
+{
+ int n, help, d;
+ n = 1;
+ help = 0;
+
+ while(n<argc)
+ {
+ if(eq("-p", argv[n]))
+ {
+ n++;
+ if(n<argc) default_port = atoi(argv[n]);
+ else cerr<<"*** No port parameter ***\n";
+ }
+ else if(eq("-h", argv[n]))
+ {
+ n++;
+ if(n<argc) strncpy(default_server, argv[n], MAXHOSTNAME);
+ else cerr<<"*** No hostname parameter ***\n";
+ }
+ else if(eq("-o", argv[n]))
+ {
+ n++;
+ if(n<argc)
+ {
+ strncpy(config_file, argv[n], SMALL_BUFFER_SIZE);
+ LoadConfigFile(argv[n]);
+ }
+ else cerr<<"*** No friends list parameter ***\n";
+ }
+ else if(eq("-c", argv[n]))
+ {
+ n++;
+ if(n<argc) strncpy(home_channel, argv[n], SMALL_BUFFER_SIZE);
+ else cerr<<"*** No channel parameter ***\n";
+ }
+ else if(eq("-l", argv[n]))
+ {
+ n++;
+ if(n<argc) strncpy(user_login, argv[n], SMALL_BUFFER_SIZE);
+ else cerr<<"*** No username parameter ***\n";
+ }
+ else if(eq("-n", argv[n]))
+ {
+ n++;
+ if(n<argc) strncpy(original_nick, argv[n], SMALL_BUFFER_SIZE);
+ else cerr<<"*** No nickname parameter ***\n";
+ }
+ else if(eq("-j", argv[n]))
+ {
+ n++;
+ if(n<argc) strncpy(jam_nick, argv[n], SMALL_BUFFER_SIZE);
+ else cerr<<"*** No jam nickname parameter ***\n";
+ }
+ else if(eq("-d", argv[n]))
+ {
+ n++;
+ if(n<argc)
+ {
+ d = atoi(argv[n]);
+ if(d>=1) socket_delay = d;
+ else cerr<<"*** Delay error ***\n";
+ }
+ else cerr<<"*** No delay parameter ***\n";
+ }
+ else if(eq("-od", argv[n]))
+ {
+ n++;
+ if(n<argc)
+ {
+ d = atoi(argv[n]);
+ if(d>=1) op_delay = d;
+ else cerr<<"*** Op delay error ***\n";
+ }
+ else cerr<<"*** No delay parameter ***\n";
+ }
+ else if(eq("-dd", argv[n]))
+ {
+ n++;
+ if(n<argc)
+ {
+ d = atoi(argv[n]);
+ if(d>=1) deban_delay = d;
+ else cerr<<"*** Deban delay error ***\n";
+ }
+ else cerr<<"*** No delay parameter ***\n";
+ }
+ else if(eq("-?", argv[n])) help = 1;
+ else
+ {
+ cerr<<"*** Unknown option "<<argv[n]<<" ***\n";
+ help = 1;
+ }
+
+ if(help)
+ {
+ 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<<"\n";
+ cout<<"Options are :\n";
+ cout<<"-c <#channel> sets the channel\n";
+ cout<<"-d <delay in s> sets the reconnection delay\n";
+ cout<<"-h <hostname> sets the server name\n";
+ cout<<"-j <jam nickname> sets the pattern nick for collision\n";
+ cout<<"-l <user> sets the user in the user@host stuff\n";
+ cout<<"-n <nickname> sets the nickname\n";
+ cout<<"-o <friends file> loads configuration file\n";
+ cout<<"-od <delay in s> set the delay before +o\n";
+ cout<<"-dd <delay in s> set the delay before -b\n";
+ cout<<"-p <port number> sets the server port\n";
+ cout<<"-? shows this help\n";
+ exit(0);
+ }
+
+ n++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void clean_shit_list()
+{
+ NodeList<Welcome *> *node, *pred, *next;
+
+ node = shit_list.first;
+ pred = NULL;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(current_time >= node->body->time_max)
+ {
+ if(pred == NULL) shit_list.first = next;
+ else pred->next = next;
+
+ smart_unban(current_channel, node->body->pattern);
+
+ delete node->body;
+ delete node;
+ }
+ else pred = node;
+ node = next;
+ }
+ send_mode(current_channel);
+}
+
+//-----------------------------------------------------------------------------
+
+void try_reconnect()
+{
+ if(delay < DELAY_MAX_RECONNECT)
+ {
+ if(delay == 0) delay = 1;
+ else delay *= 2;
+ if(delay > DELAY_MAX_RECONNECT) delay = DELAY_MAX_RECONNECT;
+ }
+ strncpy(wanted_server, default_server, MAXHOSTNAME+1);
+ wanted_port = default_port;
+ cerr<<"*** Can't contact IRC server ***\n";
+ cerr<<"*** Next try in "<<delay<<" s\n";
+}
+
+void got_connection()
+{
+ time_last_datas = current_time;
+ IRC_connected = 1;
+ FD_SET(socket_irc, &ready);
+ sprintf(buffer, "USER %s x x :%s\n", user_login, user_name);
+ write_irc(buffer);
+ sprintf(buffer, "NICK %s\n", wanted_nick);
+ write_irc(buffer);
+ delay = socket_delay;
+}
+
+void got_datas_from_server()
+{
+ int s, end;
+ char *prefix, *r, *t;
+
+ char *slice_cmd[NB_SLICES_MAX], *slice_ctcp[NB_SLICES_MAX];
+ char *dest_cmd, *dest_ctcp;
+ int n_cmd, n_ctcp;
+
+ char buffer_cmd[BUFFER_SIZE], buffer_ctcp[BUFFER_SIZE];
+
+ time_last_datas = current_time;
+
+ // If the buffer is already full, purge it
+ if(endsrc >= buffer+BUFFER_SIZE)
+ {
+ cerr<<"*** Buffer full, erase it ***\n";
+ endsrc = buffer;
+ }
+
+ s = read(socket_irc, endsrc, buffer+BUFFER_SIZE-1-endsrc);
+ src = buffer;
+ endsrc += s;
+
+ if(s <= 0)
+ {
+ cerr<<"KILLING CONNECTION : Read error\n";
+ cerr.flush();
+ kill_connection();
+ }
+ else
+ {
+ end = 0;
+ reset_mode();
+ while(!end)
+ {
+ dest_cmd = buffer_cmd;
+ dest_ctcp = buffer_ctcp;
+
+ if(slice_buffer(src, endsrc,
+ prefix,
+ dest_cmd, slice_cmd, n_cmd,
+ dest_ctcp, slice_ctcp, n_ctcp))
+ // No more \r in the buffer
+ {
+ r = src;
+ t = buffer;
+ while(r<endsrc) *t++ = *r++;
+ endsrc = t;
+ src = buffer;
+ end = 1;
+ }
+ else
+ // Oki, we got a full line
+ get_command(prefix, slice_cmd, n_cmd, slice_ctcp, n_ctcp);
+ }
+
+ }
+}
+
+void check_stuffs()
+{
+ NodeList<DelayModeChange *> *md;
+
+ if(current_time > anti_flood_off_until) check_flood();
+ check_delay_mode_change();
+ send_mode(current_channel);
+
+ delay = socket_delay;
+ NodeList<Welcome *> *nd;
+ for(nd = shit_list.first; nd != NULL; nd = nd->next)
+ if(delay > nd->body->time_max-current_time)
+ delay = nd->body->time_max-current_time;
+
+ for(md = mode_change_list.first; md != NULL; md = md->next)
+ if(delay > md->body->time-current_time)
+ delay = md->body->time-current_time;
+
+ if(delay < 0) delay = 0;
+}
+
+void dcc_chat()
+{
+ NodeList<DCCChat *> *node, *pred, *next, *node2;
+ char CHAT_buffer[BUFFER_SIZE];
+ int s;
+
+ pred = NULL; next = NULL;
+ node = dcc_chat_list.first;
+ while(node != NULL)
+ {
+ next = node->next;
+ if(FD_ISSET(node->body->socket, &result))
+ {
+ s = read(node->body->socket, CHAT_buffer, BUFFER_SIZE-1);
+ if(s <= 0)
+ {
+ FD_CLR(node->body->socket, &ready); // Forget the socket
+ close(node->body->socket);
+
+ sprintf(IRC_buffer, "%s leaves.\n", node->body->prefix);
+ for(node2=dcc_chat_list.first; node2!= NULL; node2 = node2->next)
+ if(node2->body != node->body)
+ tell(node2->body, NULL, IRC_buffer);
+
+ remove_wait_for_chat(node->body);
+
+ if(pred == NULL) dcc_chat_list.first = next;
+ else pred->next = next;
+ delete node->body;
+ delete node;
+ }
+ else
+ {
+ *(CHAT_buffer+s-1) = '\0';
+ tropbot_cmd(node->body, node->body->prefix, NULL, CHAT_buffer);
+ pred = node;
+ }
+ }
+ else pred = node;
+
+ node = next;
+ }
+}
+
+int main(int argc, char **argv)
+{
+
+ // I think it's a good idea to have few friends forever (me ? yeahhh !)
+ level_list.Insert(new Person("*!*fleuret@*.inria.fr", LEVEL_MASTER, NULL));
+ level_list.Insert(new Person("*!*fleuret@*.ens.fr", LEVEL_MASTER, NULL));
+ level_list.Insert(new Person("*!*fleuret@*.curie.fr", LEVEL_MASTER, NULL));
+ level_list.Insert(new Person("*!*jolibot@*.inria.fr", LEVEL_DEFENCE, NULL));
+ level_list.Insert(new Person("*!*jolibot@*.ens.fr", LEVEL_DEFENCE, NULL));
+ level_list.Insert(new Person("*!*jolibot@*.curie.fr", LEVEL_DEFENCE, NULL));
+
+ cout<<"TropBot, written by Francois Fleuret,"
+ " contact <francois.fleuret@inria.fr>\n";
+
+ get_options(argc, argv);
+
+ uncap(home_channel);
+ strncpy(wanted_channel, home_channel, SMALL_BUFFER_SIZE);
+ strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
+ strncpy(wanted_server, default_server, MAXHOSTNAME+1);
+ wanted_port = default_port;
+
+ IRC_registred = 0; // true if we are registred
+ IRC_connected = 0; // true if we have a connection with an IRC server
+ global_state = STATE_WAIT;
+ in_channel = 0;
+ mode_protect_on = DEFAULT_MODE_PROTECT;
+
+ FD_ZERO(&ready);
+
+ alive = 1;
+ father = 1;
+ nb_sons = 0;
+ was_killed = 0;
+ last_answer_time = 0;
+ anti_flood_off_until = 0;
+
+ src = buffer;
+ endsrc = buffer;
+ delay = socket_delay;
+
+ struct sigaction action;
+ action.sa_handler = SIG_IGN;
+
+ // We'll ignore the SIGPIPE signal, which will be catch somewhere else
+ sigaction(SIGPIPE, &action, NULL);
+
+ delay = 0;
+
+ do
+ {
+ delay_pause.tv_sec = delay;
+ delay_pause.tv_usec = 0;
+ result = ready;
+
+ while(waitpid(-1, NULL, WNOHANG) > 0) nb_sons--;
+
+ select(64, &result, NULL, NULL, &delay_pause);
+
+ time(¤t_time);
+
+ dcc_chat();
+
+ if(!IRC_connected)
+ {
+#ifdef SCREEN_OUTPUT
+ cout<<"No connection yet\n";
+ cout<<"Try to contact "<<wanted_server<<":"<<wanted_port<<"\n";
+#endif
+ socket_irc = call_socket(wanted_server, wanted_port);
+
+ if(socket_irc <= 0) try_reconnect();
+ else got_connection();
+ }
+ else
+ {
+ if((current_time > time_killed+DELAY_NICK_BACK) && was_killed)
+ {
+ was_killed = 0;
+ strncpy(wanted_nick, original_nick, SMALL_BUFFER_SIZE);
+ sprintf(buffer, "NICK %s\n", wanted_nick);
+ write_irc(buffer);
+ }
+
+ if(IRC_registred) clean_shit_list();
+
+ if(FD_ISSET(socket_irc, &result)) got_datas_from_server();
+ else
+ {
+ if(current_time > time_last_datas+DELAY_DEAD_SERVER)
+ {
+ cerr<<"KILLING CONNECTION : Quiet server\n";
+ cerr.flush();
+ kill_connection();
+ }
+ else if(!in_channel) if(global_state == STATE_WAIT)
+ {
+ sprintf(IRC_buffer, "JOIN %s\n", wanted_channel);
+ write_irc(IRC_buffer);
+ }
+ }
+
+ if(IRC_connected) check_stuffs();
+ }
+
+#ifdef SCREEN_OUTPUT
+ cout<<present_people.Lenght()<<" person(s) inside\n";
+ // banid_list.Print();
+ cout.flush();
+#endif
+ }
+ while(alive || (socket_irc > 0));
+
+}
+
+//-----------------------------------------------------------------------------