AdUsIRC

GlibGNU RegexGNU Socket

Description

Bot for IRC channels with different interactive commands and automatic functions to manage the IRC channel.


Source

/*
 * 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);
 }
}