#include #include #include #include #include #include #include #include #include #include "bot.h" #define MAXCHANNELS 32 char myname[BUFSIZE] = "MiniBot 4000"; char mynick[BUFSIZE] = "MiniBot"; char server[BUFSIZE] = "efnet.demon.co.uk"; int server_port = 6667; char *config_file = NULL; char *channels[MAXCHANNELS]; int chan_stack_ptr = -1; hash_t mynick_h; struct msg_queue_t *msg_queue = NULL; int msg_queue_length = 0; /* Whether the msg_loop is in poll mode for the signal handler */ int pollmode = 0; /* The main socket */ int main_soc = 0; int get_line(FILE *file, char *buffer, int length) { int c = fgetc(file); int r = 0; while(c != EOF && r < (length - 1) && (char)c != '\n') { (*buffer) = (char)c; ++buffer; ++r; c = fgetc(file); } *buffer = '\n'; ++buffer; *buffer = '\0'; if (DEBUG) {fprintf(stderr,"\tGet_line:end\n");} if (c == EOF) { return c; } else { return r + 2; } } int get_line_soc(int s, char *buffer, int length, int flags) { char c; int l = 0; int ret = 0; if(DEBUG) {fprintf(stderr,"get_line_soc: start %x\n",flags);} while(l < (length - 1) && c != '\n' && ret != -1) { ret = recv(s,&c,1,flags); if (ret == 1) { (*buffer) = c; ++buffer; ++l; } else { *buffer = '\0'; if(DEBUG) {fprintf(stderr,"get_line_soc: EAGAIN\n");} return EAGAIN; } } *buffer = '\n'; ++buffer; *buffer = '\0'; if(DEBUG) {fprintf(stderr,"get_line_soc: end\n");} if (ret == -1) { return EOF; } else { return l + 2; } } void login(int s) { int i; char *cp; char buffer[BUFSIZE]; sprintf(buffer,"user guest 8 *: %s\nnick %s\r\n",myname,mynick); if(DEBUG) {fprintf(stderr,"Login :%s,%s\n",mynick,myname);} i = strlen(buffer); cp = malloc(i+1); strcpy(cp,buffer); send(s,cp,i,0); free(cp); } void join(int s, const char *channel) { char *cp; int len = strlen(channel); len += 5 + 1 + 1; cp = malloc(len); sprintf(cp,"JOIN %s\r\n",channel); send(s,cp,len,0); free(cp); } void part(int s, const char *channel) { char *cp; int len = strlen(channel); len += 5 + 1 + 1; cp = malloc(len); sprintf(cp,"PART %s\r\n",channel); send(s,cp,len,0); free(cp); } void quit(int s, const char *message) { char *cp; int len = strlen(message); len += 5 + 1 + 1; cp = malloc(len); sprintf(cp,"QUIT %s\r\n",message); send(s,cp,len,0); free(cp); } void ping(int s,char *buffer) { int i; char *b2; char *temp; if(strncmp("PING",buffer,4) == 0) { temp = buffer + 4; while ((*temp) != ':') { ++temp; } b2 = malloc(BUFSIZE); sprintf(b2,"PONG %s\r\n",temp); i = strlen(b2); temp = malloc(i + 1); strcpy(temp,b2); send(s,temp,i,0); printf("%s",temp); free(temp); free(b2); } } int text_to_command(char *command) { // fprintf(stderr,"text_to_command: %s\n",command); hash_t h = hash(command); if(h == commands[PRIVMSG]) { return PRIVMSG; } else if(h == commands[JOIN]) { return JOIN; } else if(h == commands[QUIT]) { return QUIT; } else if(h == commands[NICK]) { return NICK; } else if(h == commands[MODE]) { return MODE; } else if(h == commands[PART]) { return PART; } return NOCMD; } void split_command(int *ct, char *nick, char *channel, char *data, char *buffer) { int n,i,r; int length = strlen(buffer); char *end = buffer + length + 1; char *temp = buffer; char *mark = buffer; char *b2; /* Find beginning of the Nick */ while((*temp) == ':' && temp < end) { ++temp; } /* Set Nick */ while((*temp) != '!' && temp < end) { (*(nick++)) = (*(temp++)); } (*nick) = '\0'; /* Find end of the host */ while(!isspace(*temp) && temp < end) { ++temp; } ++temp; /* Skip White Space */ mark = temp; /* Mark Beginning of Command*/ /* Move to end of Command */ while(!isspace(*temp) && temp < end) { ++temp; } /* Set command type */ b2 = malloc(temp - mark + 1); memset(b2,0,temp - mark + 1); strncpy(b2,mark,temp - mark); (*ct) = text_to_command(b2); free(b2); ++temp; /* Skip White Space */ if ((*ct) == PRIVMSG) { /* Set channel */ while(!isspace(*temp) && temp < end) { (*(channel++)) = (*(temp++)); } (*channel) = '\0'; } ++temp; /* Skip White Space */ if(*temp == ':') { ++temp; /* Skip what I hope is a colon */ } /* Copy Message Data */ while((*temp) != '\0' && temp < end) { (*(data++)) = (*(temp++)); } (*data) = '\0'; } /* Speak, yeah say something */ void speak(int s, const char *channel, const char *message) { char buffer[BUFSIZE]; snprintf(buffer,BUFSIZE,"PRIVMSG %s :%s\r\n",channel,message); send(s,buffer,strlen(buffer),0); printf("[%s][%s]:%s\n",mynick,channel,message); } /* Same as speak apart from with an ACTION and silly \001's round the message */ void action(int s, const char *channel, const char *message) { char buffer[BUFSIZE]; snprintf(buffer,BUFSIZE,"PRIVMSG %s :\001%s\001\r\n",channel,message); send(s,buffer,strlen(buffer),0); printf("[%s][%s]:%s\n",mynick,channel,message); } void queue_msg(int type, const char *channel, const char *message, time_t time) { struct msg_queue_t *last = NULL; struct msg_queue_t *next = NULL; if(DEBUG) {fprintf(stderr,"queue_msg\n");} if(msg_queue == NULL) { msg_queue = malloc(sizeof(struct msg_queue_t)); next = msg_queue; } else { next = msg_queue; while(next != NULL) { last = next; next = next->next_msg; } next = malloc(sizeof(struct msg_queue_t)); last->next_msg = next; } strcpy(next->channel,channel); strcpy(next->message,message); next->next_msg = NULL; next->type = type; next->time = time; ++msg_queue_length; } void queue_run(int s) { time_t current_time = time(NULL); struct msg_queue_t *last = NULL; struct msg_queue_t *next = NULL; int len = 0; int sent = 0; if(DEBUG) {fprintf(stderr,"queue_run: start\n");} next = msg_queue; while (next != NULL && len < 32 && sent < 4) { if (next->time < current_time) { if (next->type == ACTION) { action(s,next->channel,next->message); ++sent; } else { speak(s,next->channel,next->message); ++sent; } if (last != NULL) { last->next_msg = next->next_msg; } else { msg_queue = next->next_msg; } free(next); if (last != NULL) { next = last->next_msg; } else { next = msg_queue; } --msg_queue_length; } else { last = next; next = next->next_msg; } ++len; } if(DEBUG) {fprintf(stderr,"queue_run: end\n");} } int sigalarm(int i) { if(DEBUG) {fprintf(stderr,"sigalarm: entered\n");} check_rcon_log(main_soc); if(!pollmode) { if(msg_queue_length > 0) {queue_run(main_soc);} alarm(2); } if(DEBUG) {fprintf(stderr,"sigalarm: left, pollmode:%d\n",pollmode);} return 0; } void command(int s, char *buffer) { int command_type = NOCMD; int talking_to_me = 0; int pm = 0; /* Private Message */ int swapped = 0; char *membuf = malloc(BUFSIZE * 4); /* Allocate a Memory Buffer */ char *nick = membuf; /* Allocate BUFSIZE of it */ char *data = (membuf + 1*BUFSIZE); /* to each subbuffer */ char *channel = (membuf + 2*BUFSIZE); char *temp_buf = (membuf + 3*BUFSIZE); char *temp_ptr; char *word1; char *word2; hash_t word1_h; hash_t word2_h; if(DEBUG) {fprintf(stderr,"Start Command Loop\n");} split_command(&command_type, nick, channel, data, buffer); if (command_type == PRIVMSG) { if(DEBUG) {fprintf(stderr,"\t\tPRIVMSG\n");} if (strcasecmp(channel,mynick) == 0) { talking_to_me = 1; pm = 1; word1 = word(data,1); word2 = word(data,2); } else { word1 = word(data,1); if (strncasecmp(word1,mynick,strlen(mynick)) == 0) { talking_to_me = 1; free(word1); word1 = word(data,2); word2 = word(data,3); } else { word2 = word(data,2); } } word1_h = hash(word1); word2_h = hash(word2); printf("\[%s]\[%s]:%s\n", nick, channel, data); if(talking_to_me && (*data) != '!') { if(pm) { temp_ptr = channel; channel = nick; swapped = 1; } if(word1_h == words[ASCII] && word2_h == words[RAVE]) { ascii_rave(s,channel); } else if(word1_h == words[STATS]) { output_stats(s,channel,word2); } else if(word1_h == words[KICK]) { meta_kick(s,channel,word2); } else if(word1_h == words[HUG]) { hug(s,channel,word2); } else if(pm) { speak(s,nick,"Sorry :|"); } } else if((*word1) == '!') { if(pm) { temp_ptr = channel; channel = nick; swapped = 1; } ++word1; if(strcasecmp(word1,"rconbot") == 0) { rcon_bot_command(s,channel,nick,data); } else { x_command(s,channel,data); } --word1; } free(word1); free(word2); if (pm && swapped) { channel = temp_ptr; } update_stats(nick, channel, data); } else if(command_type == NICK) { word1 = word(data,1); move_nick_stats(nick,word1); free(word1); } else if(command_type == QUIT) { word1_h = hash(nick); rcon_deauth(word1_h); } free(membuf); /* Free the whole memory buffer */ if(DEBUG) {fprintf(stderr,"End Command Loop\n");} } void msg_loop(int s) { int result = 0; char buffer_data[BUFSIZE]; char *buffer = buffer_data; time_t last_save = 0; time_t new_ping = 0; result = get_line_soc(s,buffer,BUFSIZE,0); while (result != EOF) { chomp(buffer,result); /* Remove \r\n from server lines */ //++buffer; /* Remove @ from server lines */ if (DEBUG) {printf("%s\n",buffer);} /* Print Server Lines */ if ((*buffer) != ':') { ping(s,buffer); new_ping = time(NULL); if ((new_ping - last_save) > 300) { store_stats(config_file); last_save = new_ping; } } else { command(s,buffer); } //--buffer; /* Pull the buffer back to start */ memset(buffer,0,result);/* Clean used buffer, safety :) */ if (msg_queue_length == 0) { alarm(2); result = get_line_soc(s,buffer,BUFSIZE,0); } else { pollmode = 1; queue_run(s); result = get_line_soc(s,buffer,BUFSIZE,MSG_DONTWAIT); while(result == EAGAIN && msg_queue_length > 0) { usleep((int)(1000000/(msg_queue_length + 1))); queue_run(s); result = get_line_soc(s,buffer, BUFSIZE,MSG_DONTWAIT); sigalarm(14); } pollmode = 0; } } } int configure(char *conffile) { FILE *conf; char buffer[BUFSIZE]; char *buf_ptr,*word1,*word2; int result = 0; conf = fopen(conffile,"r"); while (result != EOF) { buf_ptr = buffer; result = get_line(conf,buffer,BUFSIZE); if((*buf_ptr) != '#') { word1 = word(buffer,1); word2 = word(buffer,2); if (strcasecmp(word1,"server") == 0) { strcpy(server,word2); } else if(strcasecmp(word1,"port") == 0) { server_port = atoi(word2); } else if(strcasecmp(word1,"mynick") == 0) { strcpy(mynick,word2); mynick_h = hash(mynick); } else if(strcasecmp(word1,"myname") == 0) { buf_ptr += strlen(word1) + 1; chomp(buf_ptr,strlen(buf_ptr)); strcpy(myname,buf_ptr); } else if(strcasecmp(word1,"channel") == 0) { if((chan_stack_ptr - 1) < MAXCHANNELS) { ++chan_stack_ptr; channels[chan_stack_ptr] = strdup(word2); } } free(word1); free(word2); } } fclose(conf); } int main(int argc, char *argv[]) { int result; char buffer_data[BUFSIZE]; char *buffer = buffer_data; struct sockaddr_in addr; struct hostent *host; init_commands(); init_words(); if (argc < 2) { fprintf(stderr,"Invalid Parameters\n"); fprintf(stderr,"Usage: ./bot \n"); fflush(stderr); return 1; } config_file = strdup(argv[1]); configure(config_file); /* Load Configuration */ load_stats(config_file); /* Load Stats */ host = gethostbyname(server); main_soc = socket(PF_INET,SOCK_STREAM,0); memcpy(&addr.sin_addr.s_addr,host->h_addr_list[0],host->h_length); addr.sin_family = AF_INET; addr.sin_port = htons(server_port); result = connect(main_soc,(struct sockaddr *)&addr,sizeof(addr)); if (result == 0) { fprintf(stderr,"Connected\n"); } else { fprintf(stderr,"Failed to Connect\n"); return 1; } login(main_soc); while(chan_stack_ptr >= 0) { fprintf(stderr,"\tChannels:%i\n",chan_stack_ptr); join(main_soc,channels[chan_stack_ptr]); --chan_stack_ptr; } signal(SIGALRM,(void *)(&sigalarm)); rconbot_reset(main_soc,config_file); msg_loop(main_soc); /* Enter the main loop */ close(main_soc); return 0; }