Description
Bot for IRC channels with different interactive commands and automatic functions to manage the IRC channel.
Bot for IRC channels with different interactive commands and automatic functions to manage the IRC channel.
/* * Davide Francesco Merico <hds619@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * */ #include <glib.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <stdarg.h> #include <ctype.h> #include <unistd.h> #include <errno.h> #include <math.h> #include <regex.h> #include <time.h> #include <getopt.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #define IRC_BUFFER 0x200 struct quandan { char *name; int code; }; struct irc_users { char *name; int op; int warning; int protect; time_t *last_message; }; struct { char *cmd_init; char *channel; char *server; char *name; char *file_vulgarity; char *file_spam; int spam_match; int port; int flood_range; int flood_time; int max_warning; } adusirc = { "bot", "#adusirc", "irc.freenode.net", "AdUsIRC", "adusirc_vulgarity.txt", "adusirc_spam.txt", 3, 6667, 3, 9, 2 }; typedef enum { UNKNOWN_CODE = -1, CODE_PING, CODE_PONG, CODE_RAND, CODE_ENABLE, CODE_DISABLE, CODE_USER, CODE_TIME, CODE_HELP, CODE_QUIT, CODE_PROT, CODE_UNPROT, CODE_FILTER, CODE_ENCODE } cmd_code; struct { char *name[4]; int vulgarity; int flood; int spam; } filters = { { "VULGARITY", "FLOOD", "SPAM", NULL }, 0, 0, 0 }; GList *users_list = NULL; void adusirc_error (const char *fmsg, ...); void adusirc_cmd_send (int sock_fd, const char *fmsg, ...); int adusirc_substr (char *string, int bytes, char *substring); void adusirc_main (int sock_fd, char *buffer, int bytes); void adusirc_cmd (int sock_fd, char **word); int adusirc_valid_set (char *setting); void adusirc_vulgarity_filter (int sock_fd, char **word); void adusirc_flood_filter (int sock_fd, char *name); void adusirc_spam_filter (int sock_fd, char *name, char **word); void adusirc_do_users_list (char **word, int start); char *adusirc_get_name (char *string); void adusirc_add_user (char *name); void adusirc_rm_user (char *name); void adusirc_set_op (char *name, char set_type); void adusirc_add_warning (int sock_fd, char *string, char *reason); int adusirc_is_op (char *raw_name); void adusirc_change_name (char *old_name, char *new_name); void adusirc_add_message_time (time_t message_time, char *user); char **adusirc_get_array_from_file (char *filename); gint adusirc_find_username (gconstpointer a, gconstpointer b); int main (int argc, char *argv[]) { int sd, bytesRcv, opt, opt_index, j; char buffer[IRC_BUFFER]; struct sockaddr_in serv_addr; struct hostent *server; struct option long_options[] = { {"command", required_argument, 0, 'c' }, {"help", no_argument, 0, 'h' }, {"channel", required_argument, 0, 'j' }, {"spam-match", required_argument, 0, 'm' }, {"name", required_argument, 0, 'n' }, {"port", required_argument, 0, 'p' }, {"flood-range", required_argument, 0, 'r' }, {"server", required_argument, 0, 's' }, {"flood-time", required_argument, 0, 't' }, {"vulgarity", required_argument, 0, 'v' }, {"max-warning", required_argument, 0, 'w' }, {"spam", required_argument, 0, 'x' }, { 0, 0, 0, 0 } }; srand (time (NULL)); while ( (opt = getopt_long (argc, argv, "c:hj:n:m:p:r:s:t:v:w:x:", long_options, &opt_index)) != -1 ) { switch (opt) { case 'c': for ( j = strlen (optarg) - 1; j > -1; j-- ) { if ( !isalnum (optarg[j]) && optarg[j] != '_' ) { adusirc_error ("option '-c': Command can have only alphanumerical characters or '_'"); exit (EXIT_FAILURE); } } adusirc.cmd_init = strdup (optarg); break; case 'j': for ( j = strlen (optarg) - 1; j > -1; j-- ) { if ( !isalnum (optarg[j]) && optarg[j] != '_' && optarg[j] != '#' ) { adusirc_error ("option '-j': Channel can have only alphanumerical characters or '_'"); exit (EXIT_FAILURE); } } adusirc.channel = strdup (optarg); break; case 'm': adusirc.spam_match = atoi (optarg); if ( adusirc.spam_match < 1 ) { adusirc_error ("option '-m': Invalid value ( < 1 )"); exit (EXIT_FAILURE); } break; case 'n': for ( j = strlen (optarg) - 1; j > -1; j-- ) { if ( !isalnum (optarg[j]) && optarg[j] != '_' ) { adusirc_error ("option '-n': Name can have only alphanumerical characters or '_'"); exit (EXIT_FAILURE); } } adusirc.name = strdup (optarg); break; case 'p': adusirc.port = atoi (optarg); if ( adusirc.port < 1 ) { adusirc_error ("option '-p': Invalid port ( < 1 )"); exit (EXIT_FAILURE); } break; case 'r': adusirc.flood_range = atoi (optarg); if ( adusirc.flood_range < 1 ) { adusirc_error ("option '-r': Invalid range ( < 1 )"); exit (EXIT_FAILURE); } break; case 's': adusirc.server = strdup (optarg); break; case 't': adusirc.flood_time = atoi (optarg); if ( adusirc.flood_time < 1 ) { adusirc_error ("option '-t': Invalid value ( < 1 )"); exit (EXIT_FAILURE); } break; case 'v': adusirc.file_vulgarity = strdup (optarg); break; case 'x': adusirc.file_spam = strdup (optarg); break; case 'w': adusirc.max_warning = atoi (optarg); if ( adusirc.max_warning < 1 ) { adusirc_error ("option '-w': Invalid value ( < 1 )"); exit (EXIT_FAILURE); } break; case 'h': fprintf (stdout, "Usage: AdUsIRC [-chjmnprstvwx]\n" " -c, --command [command]\nSet the command to activate bot\n" "Default: 'bot'\n" " -h, --help\nDisplay this help\n" " -j, --channel [channel]\nBot join in [channel] IRC channel\n" "Default: '#adusirc'\n" " -n, --name [name]\nSet the name of the bot\n" "Default: 'AdUsIRC'\n" " -m, --spam-match [value]\nSet the number of link in one message to " "mark it as spam\n" "Default: 3\n" " -p, --port [port]\nSet the port of the irc server\n" "Default: 6667\n" " -r, --flood-range [value]\nSet the number of message to observe to " "identify flood actions\n" "Default: 3\n" " -s, --server [url]\nSet the url of IRC Server to connect the bot\n" "Default: 'irc.freenode.net'\n" " -t, --flood-time\nSet the minimum time for user to send a number of " "messages specified with --flood-range option\n" "Default: 9\n" " -v, --vulgarity\nSet the file contains vulgarity words to identify it " "in the channel.\n" "Default: 'adusirc_vulgarity.txt'\n" " -w, --max-warning\nSet the maximum warning for user before it get kicked\n" "Default: 2\n" " -x, --spam\nSet the file contains regex to identify spam in the channel\n" "Default: 'adusirc_spam.txt'\n"); exit (EXIT_SUCCESS); } } fprintf (stdout, "Connect to %s:%d.. ", adusirc.server, adusirc.port); fflush (stdout); if ( (sd = socket (AF_INET, SOCK_STREAM, 0)) == -1 ) { adusirc_error ("%s", strerror (errno)); exit (EXIT_FAILURE); } if ( !(server = gethostbyname(adusirc.server)) ) { switch (h_errno) { case HOST_NOT_FOUND: adusirc_error ("The specified host is unknown"); break; case NO_ADDRESS: adusirc_error ("The requested name is valid but does not " "have an IP address"); break; case NO_RECOVERY: adusirc_error ("A nonrecoverable name server error occurred"); break; case TRY_AGAIN: adusirc_error ("A temporary error occurred on an authoritative " "name server. Try again later."); break; } exit (EXIT_FAILURE); } bzero ((char *) &serv_addr, sizeof (struct sockaddr)); serv_addr.sin_family = AF_INET; bcopy ((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons (adusirc.port); if ( connect (sd, (struct sockaddr *) &serv_addr, sizeof (struct sockaddr)) == -1 ) { adusirc_error ("%s", strerror (errno)); exit (EXIT_FAILURE); } else printf ("[Ok]\n"); while ( 1 ) { memset (buffer, 0x00, IRC_BUFFER); bytesRcv = recv (sd, buffer, IRC_BUFFER, 0); if ( bytesRcv != 0 && bytesRcv != -1 ) { if ( adusirc_substr (buffer, bytesRcv, "No Ident response") != -1 ) { adusirc_cmd_send (sd, "USER %s[%s] localhost localhost :Style\r\n", adusirc.name, adusirc.cmd_init); adusirc_cmd_send (sd, "NICK %s[%s]\r\n", adusirc.name, adusirc.cmd_init); break; } } else break; } adusirc_cmd_send (sd, "JOIN %s\r\n", adusirc.channel); while ( 1 ) { memset (buffer, 0x00, IRC_BUFFER); bytesRcv = recv (sd, buffer, IRC_BUFFER, 0); if ( bytesRcv != 0 && bytesRcv != -1 ) adusirc_main (sd, buffer, bytesRcv); else break; } fprintf (stdout, "Exit"); fflush (stdout); return EXIT_SUCCESS; } void adusirc_error (const char *fmsg, ...) { va_list ap; char *l_str; if ( fmsg == NULL ) return; l_str = (char *) malloc ((128 + strlen (fmsg)) * sizeof (char)); snprintf (l_str, 128 + strlen (fmsg), "AdUsIRC: error: %s\n", fmsg); va_start (ap, fmsg); vfprintf (stderr, l_str, ap); free (l_str); va_end (ap); } void adusirc_cmd_send (int sock_fd, const char *fmsg, ...) { va_list ap; char buff[IRC_BUFFER]; if ( fmsg == NULL ) return; va_start (ap, fmsg); vsnprintf (buff, IRC_BUFFER, fmsg, ap); va_end (ap); if ( send (sock_fd, buff, strlen (buff), 0) < 0 ) adusirc_error ("writing to socket"); fprintf (stdout, "%s", buff); fflush (stdout); usleep (500000); } int adusirc_substr (char *string, int bytes, char *substring) { int j, len, chk = -1; if ( !(string && substring) ) return -1; len = strlen (substring); if ( len > bytes ) return -1; for ( j = 0; j < bytes; j++ ) { if ( tolower (*substring) == tolower (string[j]) ) { for ( chk = 0; chk < len; chk++ ) { if ( (j + chk) >= bytes ) { chk = -1; break; } if ( tolower (string[j + chk]) != tolower (substring[chk]) ) { chk = -1; break; } } } if ( chk != -1 ) break; } return chk; } void adusirc_main (int sock_fd, char *buffer, int bytes) { char **word, *string, *tmp; int j = 0, code, cnt_words; struct quandan valid_message[] = { { "PRIVMSG", 0 }, { "JOIN", 1 }, { "QUIT", 2 }, { "PART", 2 }, { "MODE", 3 }, { "KICK", 4 }, { "NICK", 5 }, { NULL, -1 } }; for ( j = 0; j < bytes; j++ ) if ( !isprint (buffer[j]) ) buffer[j] = ' '; buffer[bytes - 2] = '\0'; word = g_strsplit (buffer, " ", -1); if ( !strcasecmp (*word, "PING") ) { adusirc_cmd_send (sock_fd, "PONG\r\n"); return; } for ( j = 0; word[j]; j++ ) if ( !strcmp (word[j], "353") ) break; for ( cnt_words = 0; word[cnt_words]; cnt_words++ ); if ( cnt_words > (j + 4) ) adusirc_do_users_list (word, j); else if ( cnt_words > 2 ) { for ( j = 0, code = -1; valid_message[j].name; j++ ) { if ( !strcasecmp (valid_message[j].name, word[1]) ) { code = valid_message[j].code; break; } } switch ( code ) { case 0: string = adusirc_get_name (*word); adusirc_add_message_time (time (NULL), string); adusirc_flood_filter (sock_fd, string); adusirc_vulgarity_filter (sock_fd, word); adusirc_spam_filter (sock_fd, string, word); tmp = (char *) malloc ((2 + strlen (adusirc.cmd_init)) * sizeof (char)); sprintf (tmp, ":!%s", adusirc.cmd_init); if ( !strcasecmp (word[3], tmp) ) adusirc_cmd (sock_fd, word); free (tmp); free (string); break; case 1: string = adusirc_get_name (*word); adusirc_cmd_send (sock_fd, "PRIVMSG %s :Welcome into %s %s!\r\n", adusirc.channel, adusirc.channel, string); adusirc_add_user (string); free (string); break; case 2: string = adusirc_get_name (*word); adusirc_rm_user (string); free (string); break; case 3: for ( j = 1; word[3][j] != '\0'; j++ ) { if ( word[3][j] == 'o' ) { adusirc_set_op (word[4], *word[3]); break; } } break; case 4: adusirc_rm_user (word[3]); break; case 5: string = adusirc_get_name (*word); adusirc_change_name (string, word[2]); free (string); break; } } for ( j = 0; word[j]; j++ ) { #ifdef DEBUG_ENABLE fprintf (stdout, "word[%d] = '%s'\n", j, word[j]); fflush (stdout); #endif free (word[j]); } free (word); } void adusirc_add_message_time (time_t message_time, char *user) { int k = -1, j; GList *element; struct irc_users *user_data; if ( !users_list ) return; element = g_list_find_custom (users_list, user, adusirc_find_username); if ( !element ) return; user_data = (struct irc_users *) element->data; for ( k = adusirc.flood_range - 1; k > 0; k-- ) user_data->last_message[k] = user_data->last_message[k - 1]; user_data->last_message[0] = time (NULL); } char *adusirc_get_name (char *string) { int j; for ( j = ( *string == '@' || *string == ' ' ); string[j] != '!'; j++ ); return strndup (string + ( *string == '@' || *string == ':' ), j - 1); } int adusirc_is_op (char *raw_name) { int j; char *string; GList *element; struct irc_users *user_data; if ( !users_list ) return 0; string = adusirc_get_name (raw_name); element = g_list_find_custom (users_list, string, adusirc_find_username); if ( !element ) return 0; user_data = (struct irc_users *) element->data; free (string); return user_data->op; } void adusirc_add_user (char *name) { struct irc_users *user = NULL; if ( !users_list ) return; user = (struct irc_users *) malloc (sizeof (struct irc_users)); user->name = strdup (name); user->op = 0; user->warning = 0; user->protect = 0; user->last_message = (time_t *) calloc (adusirc.flood_range, sizeof (time_t)); users_list = g_list_append (users_list, user); } void adusirc_change_name (char *old_name, char *new_name) { int j; GList *element; struct irc_users *user_data; if ( !users_list ) return; element = g_list_find_custom (users_list, old_name, adusirc_find_username); if ( !element ) return; user_data = (struct irc_users *) element->data; free (user_data->name); user_data->name = strdup (new_name + 1); } gint adusirc_find_username (gconstpointer a, gconstpointer b) { char *username; struct irc_users *user_data; username = (char *) b; user_data = (struct irc_users *) a; return strcasecmp (username, user_data->name); } void adusirc_rm_user (char *name) { int j, k; GList *element; struct irc_users *user_data; if ( !users_list ) return; element = g_list_find_custom (users_list, name, adusirc_find_username); if ( !element ) return; user_data = (struct irc_users *) element->data; users_list = g_list_remove (users_list, element->data); free (user_data->name); free (user_data->last_message); free (user_data); } void adusirc_set_op (char *name, char set_type) { int j; GList *element; struct irc_users *user_data; if ( !users_list ) return; element = g_list_find_custom (users_list, name, adusirc_find_username); if ( !element ) return; user_data = (struct irc_users *) element->data; user_data->op = set_type == '+'; } void adusirc_do_users_list (char **word, int start) { int j, mem = 1, k; struct irc_users *user = NULL; for ( j = start + 4; word[j]; j++ ) { if ( !strcasecmp (word[j], "") ) break; user = (struct irc_users *) malloc (sizeof (struct irc_users)); user->op = *word[j] == '@'; user->name = strdup (word[j] + (*word[j] == '@' || *word[j] == ':')); user->warning = 0; user->protect = 0; user->last_message = (time_t *) calloc (adusirc.flood_range, sizeof (time_t)); users_list = g_list_append (users_list, user); } } void adusirc_list_user (void *data, void *user_data) { char l_str[IRC_BUFFER]; struct irc_users *user; struct tm *tmp; int sock_fd; user = (struct irc_users *) data; sock_fd = GPOINTER_TO_INT (user_data); if ( user->last_message[0] ) { tmp = localtime (&(user->last_message[0])); strftime (l_str, IRC_BUFFER, "%F %T", tmp); } else snprintf (l_str, IRC_BUFFER, "No Message"); adusirc_cmd_send (sock_fd, "PRIVMSG %s : [%c] %s: W(%d)%s- LAST: %s\r\n", adusirc.channel, user->op ? '@' : '-', user->name, user->warning, user->protect ? "-P " : " ", l_str); } void adusirc_cmd (int sock_fd, char **word) { int j, k, code, cnt_words; time_t t; char *l_str, **mp, *e_str; GList *element; struct tm *tmp; struct irc_users *user_data; struct quandan chance[] = { { "PING", CODE_PING }, { "PONG", CODE_PONG }, { "RAND", CODE_RAND }, { "ENABLE", CODE_ENABLE }, { "DISABLE", CODE_DISABLE }, { "FILTERS", CODE_FILTER }, { "USERS", CODE_USER }, { "TIME", CODE_TIME }, { "ENCODE", CODE_ENCODE }, { "HELP", CODE_HELP }, { "QUIT", CODE_QUIT }, { "PROT", CODE_PROT }, { "UNPROT", CODE_UNPROT }, { NULL, UNKNOWN_CODE } }, encode[] = { { "BASE64", 0 }, { "MD5", 1 }, { "SHA1", 2 }, { "SHA256", 3 }, { NULL, -1 } }; for ( cnt_words = 0; word[cnt_words]; cnt_words++ ); for ( j = 0, code = -1; chance[j].name; j++ ) { if ( !strcasecmp (word[4], chance[j].name) ) { code = chance[j].code; break; } } switch ( code ) { case CODE_PING: adusirc_cmd_send (sock_fd, "PRIVMSG %s :PONG\r\n", adusirc.channel); break; case CODE_PONG: adusirc_cmd_send (sock_fd, "PRIVMSG %s :PING\r\n", adusirc.channel); break; case CODE_RAND: if ( cnt_words < 7 || strcasecmp (word[6], "TO") ) adusirc_cmd_send (sock_fd, "PRIVMSG %s :Malformed Request\r\n", adusirc.channel); else { j = atoi (word[5]); k = atoi (word[7]); if ( j >= k ) adusirc_cmd_send (sock_fd, "PRIVMSG %s :Malformed Request (%d >= %d)\r\n", adusirc.channel, j, k); else adusirc_cmd_send (sock_fd, "PRIVMSG %s :%d\r\n", adusirc.channel, (rand () % (k + 1 - j)) + j); } break; case CODE_ENABLE: if ( !adusirc_is_op (word[0]) ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :You're not my mom!\r\n", adusirc.channel); break; } if ( cnt_words < 6 || (j = adusirc_valid_set (word[5])) == -1 ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :Malformed Request\r\n", adusirc.channel); break; } switch ( j ) { case 0: filters.vulgarity = 1; adusirc_cmd_send (sock_fd, "PRIVMSG %s :Vulgarity filter set to %s\r\n", adusirc.channel, filters.vulgarity ? "On" : "Off"); break; case 1: filters.flood = 1; adusirc_cmd_send (sock_fd, "PRIVMSG %s :Flood filter set to %s\r\n", adusirc.channel, filters.flood ? "On" : "Off"); break; case 2: filters.spam = 1; adusirc_cmd_send (sock_fd, "PRIVMSG %s :Spam filter set to %s\r\n", adusirc.channel, filters.spam ? "On" : "Off"); break; default: adusirc_cmd_send (sock_fd, "PRIVMSG %s :I don't know what means %d..\n", adusirc.channel, j); break; } break; case CODE_DISABLE: if ( !adusirc_is_op (word[0]) ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :You're not my mom!\r\n", adusirc.channel); break; } if ( cnt_words < 6 || (j = adusirc_valid_set (word[5])) == -1 ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :Malformed Request\r\n", adusirc.channel); break; } switch ( j ) { case 0: filters.vulgarity = 0; adusirc_cmd_send (sock_fd, "PRIVMSG %s :Vulgarity filter set to %s\r\n", adusirc.channel, filters.vulgarity ? "On" : "Off"); break; case 1: filters.flood = 0; adusirc_cmd_send (sock_fd, "PRIVMSG %s :Flood filter set to %s\r\n", adusirc.channel, filters.flood ? "On" : "Off"); break; case 2: filters.spam = 0; adusirc_cmd_send (sock_fd, "PRIVMSG %s :Spam filter set to %s\r\n", adusirc.channel, filters.spam ? "On" : "Off"); break; default: adusirc_cmd_send (sock_fd, "PRIVMSG %s :I don't know what means %d..\r\n", adusirc.channel, j); break; } break; case CODE_FILTER: adusirc_cmd_send (sock_fd, "PRIVMSG %s :Active Filters:\r\n", adusirc.channel); if ( filters.flood ) adusirc_cmd_send (sock_fd, "PRIVMSG %s : Flood\r\n", adusirc.channel); if ( filters.vulgarity ) adusirc_cmd_send (sock_fd, "PRIVMSG %s : Vulgarity\r\n", adusirc.channel); if ( filters.spam ) adusirc_cmd_send (sock_fd, "PRIVMSG %s : Spam\r\n", adusirc.channel); break; case CODE_QUIT: if ( !adusirc_is_op (word[0]) ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :You're not my mom!\r\n", adusirc.channel); break; } adusirc_cmd_send (sock_fd, "PART %s Bye", adusirc.channel); exit (EXIT_SUCCESS); break; case CODE_USER: if ( !users_list ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :I've not any users list.. :(\r\n", adusirc.channel); break; } adusirc_cmd_send (sock_fd, "PRIVMSG %s :USERS LIST\r\n", adusirc.channel); g_list_foreach (users_list, adusirc_list_user, GINT_TO_POINTER (sock_fd)); break; case CODE_TIME: l_str = (char *) malloc (IRC_BUFFER * sizeof (char)); t = time (NULL); tmp = localtime(&t); strftime (l_str, IRC_BUFFER, "%F %T", tmp); adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s\r\n", adusirc.channel, l_str); free (l_str); break; case CODE_ENCODE: if ( cnt_words < 6 ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :Malformed Request\r\n", adusirc.channel); break; } mp = (char **) malloc ((cnt_words - 5) * sizeof (char *)); for ( j = 6; j < cnt_words; j++ ) mp[j - 6] = word[j]; mp[j - 6] = NULL; l_str = g_strjoinv (" ", mp); free (mp); for ( j = 0; encode[j].name; j++ ) if ( !strcasecmp (encode[j].name, word[5]) ) break; e_str = NULL; switch ( j ) { case 0: e_str = g_base64_encode (l_str, strlen (l_str)); break; case 1: e_str = g_compute_checksum_for_string (G_CHECKSUM_MD5, l_str, -1); break; case 2: e_str = g_compute_checksum_for_string (G_CHECKSUM_SHA1, l_str, -1); break; case 3: e_str = g_compute_checksum_for_string (G_CHECKSUM_SHA256, l_str, -1); break; } adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s\r\n", adusirc.channel, e_str); if ( e_str ) free (e_str); free (l_str); break; case CODE_HELP: adusirc_cmd_send (sock_fd, "PRIVMSG %s :BOT HELP\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : PING - Returns PONG\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : PONG - Returns PING\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : RAND <j> TO <k> - Returns a pseudo-random " "number between j and k ( integer numbers )\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : ENABLE <filter> - Only Op\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : DISABLE <filter> - Only Op\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : FILTERS - List of active filters\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : QUIT - Only Op, send bot in another world\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : TIME - Returns current time (YYYY/DD/MM HH:MM:SS)\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : USER - Returns the list of channel users\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : ENCODE <type> [phrase] - Encode [phrase] in <type>\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : PROT <user> - Only Op, protect <user> from kick\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s : UNPROT <user> - Only Op, unprotect <user> from kick\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s :--------------------------------\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s :AVAILABLE FILTERS: vulgarity, flood, spam\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s :AVAILABLE ENCODE: Base64, MD5, SHA1, SHA256\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s :--------------------------------\r\n", adusirc.channel); adusirc_cmd_send (sock_fd, "PRIVMSG %s :Created by Style { HdS619 } - Ver. 2.1\r\n", adusirc.channel); break; case CODE_PROT: if ( !adusirc_is_op (word[0]) ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :You're not my mom!\r\n", adusirc.channel); break; } element = g_list_find_custom (users_list, word[5], adusirc_find_username); if ( !element ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :No '%s' found!\r\n", adusirc.channel, word[5]); break; } user_data = (struct irc_users *) element->data; user_data->protect = 1; adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s has the energy shield!\r\n", adusirc.channel, word[5]); break; case CODE_UNPROT: if ( !adusirc_is_op (word[0]) ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :You're not my mom!\r\n", adusirc.channel); break; } element = g_list_find_custom (users_list, word[5], adusirc_find_username); if ( !element ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :No '%s' found!\r\n", adusirc.channel, word[5]); break; } user_data = (struct irc_users *) element->data; user_data->protect = 0; adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s has lost the energy shield!\r\n", adusirc.channel, word[5]); break; default: adusirc_cmd_send (sock_fd, "PRIVMSG %s :Unknown Command\r\n", adusirc.channel); break; } } int adusirc_valid_set (char *setting) { int j, chk = -1; for ( j = 0; filters.name[j]; j++ ) { if ( !strcasecmp (setting, filters.name[j]) ) { chk = j; break; } } return chk; } void adusirc_spam_filter (int sock_fd, char *name, char **word) { regex_t r; regmatch_t *m; int k, j, cnt = 0, c, len; char *p; char **regex_text; if ( !filters.spam ) return; regex_text = adusirc_get_array_from_file (adusirc.file_spam); if ( !regex_text ) { adusirc_error ("File '%s' not found.", adusirc.file_spam); return; } m = (regmatch_t *) malloc (adusirc.spam_match * sizeof (regmatch_t)); *word[3] = ' '; for ( k = 0; regex_text[k]; k++ ) { if ( regcomp (&r, regex_text[k], REG_EXTENDED|REG_ICASE|REG_NEWLINE) ) continue; for ( j = 3; word[j]; j++ ) { p = word[j]; while ( 1 ) { c = regexec (&r, p, adusirc.spam_match, m, 0); if ( c == REG_NOMATCH || c || m[0].rm_so < 0 || m[0].rm_eo < 1 ) break; if ( m[0].rm_so > -1 ) cnt++; p += m[0].rm_eo; } } regfree (&r); } if ( cnt >= adusirc.spam_match ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s don't spam in this channel..\r\n", adusirc.channel, name); adusirc_add_warning (sock_fd, name, "SPAM"); } *word[3] = ':'; free (m); g_strfreev (regex_text); } void adusirc_flood_filter (int sock_fd, char *name) { int j, k = -1; time_t time_sum; GList *element; struct irc_users *user_data; if ( !users_list || !filters.flood ) return; element = g_list_find_custom (users_list, name, adusirc_find_username); if ( !element ) return; user_data = (struct irc_users *) element->data; for ( k = time_sum = 0; k < adusirc.flood_range; k++ ) time_sum += time (NULL) - user_data->last_message[k]; if ( time_sum < adusirc.flood_time ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s don't use flood in this channel..\r\n", adusirc.channel, name); adusirc_add_warning (sock_fd, name, "Flood"); } } char **adusirc_get_array_from_file (char *filename) { char **l_array, *content; FILE *of; int size; if ( !(of = fopen (filename, "rb")) ) return NULL; fseek (of, 0, SEEK_END); size = ftell (of); rewind (of); content = (char *) malloc (size * sizeof (char)); fread (content, sizeof (char), size, of); fclose (of); l_array = g_strsplit (content, "\n", -1); free (content); return l_array; } void adusirc_vulgarity_filter (int sock_fd, char **word) { int j, k, len; char *string; char **vulgarity_list; if ( !filters.vulgarity ) return; vulgarity_list = adusirc_get_array_from_file (adusirc.file_vulgarity); if ( !vulgarity_list ) { adusirc_error ("File '%s' not found.", adusirc.file_vulgarity); return; } string = adusirc_get_name (*word); for ( k = 0; k < len; k++ ) { if ( adusirc_substr (*word, strlen (*word), vulgarity_list[k]) != -1 ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s your nick contains vulgarity, change it!\r\n", adusirc.channel, string); adusirc_add_warning (sock_fd, string, "Vulgarity"); k = -1; break; } } for ( j = 3; word[j] && k != -1; j++ ) { for ( k = 0; k < len; k++ ) { if ( adusirc_substr (word[j], strlen (word[j]), vulgarity_list[k]) != -1 ) { adusirc_cmd_send (sock_fd, "PRIVMSG %s :%s don't use vulgarity in this channel..\r\n", adusirc.channel, string); adusirc_add_warning (sock_fd, string, "Vulgarity"); k = -1; break; } } } free (string); for ( k =0; k < len; k++ ) free (vulgarity_list[k]); free (vulgarity_list); } void adusirc_add_warning (int sock_fd, char *string, char *reason) { int j, k = -1; GList *element; struct irc_users *user_data; if ( !users_list ) return; element = g_list_find_custom (users_list, string, adusirc_find_username); if ( !element ) return; user_data = (struct irc_users *) element->data; user_data->warning++; if ( user_data->warning > adusirc.max_warning && !user_data->op && !user_data->protect ) { adusirc_cmd_send (sock_fd, "KICK %s %s %s\n", adusirc.channel, string, reason); adusirc_rm_user (string); } }