src/irc.c
changeset 0 586472add385
child 1 5d249c79842d
equal deleted inserted replaced
-1:000000000000 0:586472add385
       
     1 /**
       
     2  *  $Id: irc.c 51 2008-01-10 00:19:39Z mbroeker $
       
     3  * $URL: http://localhost/svn/c/mcbot/trunk/src/irc.c $
       
     4  *
       
     5  */
       
     6 
       
     7 #include <stdio.h>
       
     8 #include <stdlib.h>
       
     9 #include <unistd.h>
       
    10 #include <string.h>
       
    11 
       
    12 #include <sys/types.h>
       
    13 #include <sys/socket.h>
       
    14 #include <netinet/in.h>
       
    15 #include <arpa/inet.h>
       
    16 #include <netdb.h>
       
    17 
       
    18 #include <pwd.h>
       
    19 
       
    20 #include <irc.h>
       
    21 
       
    22 #define VERSION_STRING "MCBOT on GNU/LINUX"
       
    23 
       
    24 const char *IRC_Commands[] = {
       
    25     "NOTICE", "MODE", "JOIN", "PART",
       
    26     "TOPIC", "PING", "ENOMEM", "ERROR",
       
    27     "VERSION", "PRIVMSG", "QUIT", "NICK",
       
    28     NULL,
       
    29 };
       
    30 
       
    31 FILE *irc_connect (char *server, unsigned int port)
       
    32 {
       
    33     struct hostent *he;
       
    34     char *ip;
       
    35     struct sockaddr_in ca;
       
    36     int csocket;
       
    37     FILE *stream;
       
    38 
       
    39     he = gethostbyname (server);
       
    40     if (he == NULL) {
       
    41         perror ("GETHOSTBYNAME");
       
    42         return NULL;
       
    43     }
       
    44 
       
    45     if ((ip = inet_ntoa (*((struct in_addr *)he->h_addr_list[0]))) == NULL) {
       
    46         perror ("GETHOSTBYNAME");
       
    47         return NULL;
       
    48     } else
       
    49         printf ("IP: %s\n", ip);
       
    50 
       
    51     ca.sin_family = AF_INET;
       
    52     ca.sin_addr.s_addr = inet_addr (ip);
       
    53     ca.sin_port = htons (port);
       
    54 
       
    55     csocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
       
    56     if (connect (csocket, (struct sockaddr *)&ca, (socklen_t) sizeof (ca)) == -1) {
       
    57         perror ("CONNECT");
       
    58         return NULL;
       
    59     }
       
    60 
       
    61     /*
       
    62      * rw mode,but many seek errors ...
       
    63      */
       
    64     stream = fdopen (csocket, "a+");
       
    65     return stream;
       
    66 }
       
    67 
       
    68 int irc_login (FILE * stream, char *nick, char *password)
       
    69 {
       
    70     MSG message;
       
    71     char msg[513];
       
    72     char *user;
       
    73     struct passwd *pwd = NULL;
       
    74 
       
    75     if ((user = getenv ("USER")) != NULL)
       
    76         if ((pwd = getpwnam (user)) == NULL)
       
    77             return IRC_GENERAL_ERROR;
       
    78 
       
    79     if (strlen (password) == 0)
       
    80         return IRC_LOGIN_ERROR;
       
    81 
       
    82     if (stream == NULL)
       
    83         return IRC_GENERAL_ERROR;
       
    84 
       
    85     fprintf (stream, "NICK %s\r\n", nick);
       
    86 
       
    87     fprintf (stream, "USER %s 0 irc.freenode.net %s\r\n", user, pwd->pw_gecos);
       
    88 
       
    89     fprintf (stream, "PRIVMSG NICKSERV :IDENTIFY %s\r\n", password);
       
    90 
       
    91     for (;;) {
       
    92         fgets (msg, 512, stream);
       
    93         if ((user = irc_parsemessage (msg, &message)) != NULL)
       
    94             printf ("%10s %s\n", user, message.line);
       
    95 
       
    96         if (strstr (msg, "VERSION") != NULL) {
       
    97             printf ("%10s %s", "VERSION", msg);
       
    98             printf ("%10s %s %s :%s\n", "WRITE", message.command, message.user, VERSION_STRING);
       
    99             fprintf (stream, "VERSION :%s\r\n", VERSION_STRING);
       
   100         }
       
   101 
       
   102         if (strstr (msg, ":Password accepted") != NULL) {
       
   103             break;
       
   104         }
       
   105 
       
   106         if (strstr (msg, ":Password Incorrect") != NULL) {
       
   107             return IRC_LOGIN_ERROR;
       
   108         }
       
   109 
       
   110         if (strstr (msg, "ERROR :Closing Link") != NULL) {
       
   111             return IRC_GENERAL_ERROR;
       
   112         }
       
   113 
       
   114         if (strstr (msg, "is not registered") != NULL) {
       
   115             return IRC_LOGIN_ERROR;
       
   116         }
       
   117     }
       
   118 
       
   119     sleep (2);
       
   120     return 0;
       
   121 }
       
   122 
       
   123 static char *irc_getmessage (const char *line, MSG * message)
       
   124 {
       
   125     char *theLine;
       
   126     char *token;
       
   127     char *ptr;
       
   128 
       
   129     if ((theLine = strdup (line)) == NULL)
       
   130         return "ENOMEM";
       
   131 
       
   132     message->user = message->email = NULL;
       
   133     message->command = NULL;
       
   134     message->channel = message->line = NULL;
       
   135 
       
   136     token = strtok (theLine, " ");
       
   137     if (*token != ':') {
       
   138         /*
       
   139          * SERVER MESSAGES
       
   140          */
       
   141         if ((ptr = strtok (NULL, "\r\n")) != NULL)
       
   142             ++ptr;
       
   143         message->line = ptr;
       
   144         return token;
       
   145     }
       
   146 
       
   147     message->user = ++token;
       
   148     message->command = strtok (NULL, " ");
       
   149 
       
   150     message->line = strtok (NULL, "\r\n");
       
   151 
       
   152     return message->command;
       
   153 }
       
   154 
       
   155 /*
       
   156  * Main prints ("%10s %s %s\n", MSG->command MSG->channel MSG->line).
       
   157  * This functions makes sure, that there will be someting to print...
       
   158  */
       
   159 
       
   160 char *irc_parsemessage (const char *line, MSG * message)
       
   161 {
       
   162     int i;
       
   163     char *command;
       
   164     char *ptr;
       
   165     int value;
       
   166 
       
   167     i = 0;
       
   168     if ((command = irc_getmessage (line, message)) != NULL) {
       
   169         while (IRC_Commands[i] != NULL) {
       
   170             if (strcmp (IRC_Commands[i], command) == 0) {
       
   171                 switch (i) {
       
   172 
       
   173                 case 0:        /* NOTICE */
       
   174                     if (message->line == NULL) {
       
   175                         message->channel = "*";
       
   176                         message->line = "*";
       
   177                     } else {
       
   178                         message->channel = strtok (message->line, " ");
       
   179                         if ((message->line = strtok (NULL, "\r\n")) != NULL)
       
   180                             ++message->line;
       
   181                     }
       
   182                     return command;
       
   183                 case 1:        /* MODE */
       
   184                     message->channel = strtok (message->line, " ");
       
   185                     message->line = strtok (NULL, "\r\n");
       
   186                     return command;
       
   187                 case 2:        /* JOIN */
       
   188                 case 3:        /* PART */
       
   189                     if ((message->channel = strchr (message->line, ':')))
       
   190                         ++message->channel;
       
   191                     message->line = message->user;
       
   192                     return command;
       
   193                 case 4:        /* TOPIC */
       
   194                     message->channel = strtok (message->line, " ");
       
   195                     if ((message->line = strtok (NULL, "\r\n")))
       
   196                         ++message->line;
       
   197                     return command;
       
   198                 case 5:        /* PING */
       
   199 #ifdef DEBUG
       
   200                     printf ("%10s %s localhost\n", "PING", message->line);
       
   201 #endif
       
   202                     fprintf (message->stream, "PONG :%s\r\n", message->line);
       
   203                     message->channel = "localhost";
       
   204 #ifdef DEBUG
       
   205                     return "PONG";
       
   206 #else
       
   207                     return NULL;
       
   208 #endif
       
   209                 case 6:        /* ENOMEM */
       
   210                 case 7:        /* ERROR */
       
   211                     exit (-1);
       
   212                     break;
       
   213                 case 8:        /* VERSION */
       
   214                     if ((ptr = strchr (message->user, ' ')))
       
   215                         *ptr = 0;
       
   216                     return command;
       
   217                 case 9:        /* PRIVMSG */
       
   218                     if ((message->email = strchr (message->user, '=')))
       
   219                         ++message->email;
       
   220                     if ((ptr = strchr (message->user, '!')))
       
   221                         *ptr = 0;
       
   222 
       
   223                     message->channel = strtok (message->line, " ");
       
   224                     message->line = strtok (NULL, "\r\n");
       
   225                     message->line++;
       
   226                     printf ("%10s %s %s :%s\n", "READ", message->command, message->channel, message->line);
       
   227                     return NULL;
       
   228                 case 10:       /* QUIT */
       
   229                     message->channel = message->user;
       
   230                     return command;
       
   231                 case 11:       /* NICK */
       
   232                     message->channel = message->user;
       
   233                     return command;
       
   234                 }
       
   235             }
       
   236             i++;
       
   237         }
       
   238 
       
   239         if ((value = atoi (command)) != 0) {
       
   240             switch (value) {
       
   241             case 1:            /* CONNECTION INFOS */
       
   242             case 2:
       
   243             case 3:
       
   244             case 4:
       
   245             case 5:
       
   246             case 250:
       
   247             case 251:
       
   248             case 252:
       
   249             case 254:
       
   250             case 255:
       
   251             case 265:
       
   252             case 266:
       
   253                 /*
       
   254                  * prints as is in irc_login
       
   255                  */
       
   256                 return command;
       
   257                 break;
       
   258             case 311:
       
   259             case 312:
       
   260             case 315:          /* END OF WHO */
       
   261             case 318:
       
   262                 message->channel = strtok (message->line, " ");
       
   263                 message->line = strtok (NULL, "\r\n");
       
   264                 return command;
       
   265             case 319:
       
   266                 message->channel = strtok (message->line, " ");
       
   267                 message->line = strtok (NULL, "\r\n");
       
   268                 fprintf (message->stream, "PRIVMSG %s :%s\r\n", "#mcbot", message->line);
       
   269                 return command;
       
   270             case 320:
       
   271             case 332:          /* TOPIC OF CHANNEL */
       
   272             case 333:          /* NAMES IN CHANNEL */
       
   273                 message->channel = strtok (message->line, " ");
       
   274                 message->line = strtok (NULL, "\r\n");
       
   275                 return command;
       
   276             case 351:          /* SVERSION */
       
   277                 message->channel = strtok (message->line, " ");
       
   278                 message->line = strtok (NULL, "\r\n");
       
   279                 return command;
       
   280             case 352:          /* WHO LIST */
       
   281                 message->channel = strtok (message->line, " ");
       
   282                 message->line = strtok (NULL, "\r\n");
       
   283                 /*
       
   284                  * MORE THAN 3 LINES AND YOU WILL be KICKED
       
   285                  */
       
   286                 return command;
       
   287                 break;
       
   288             case 353:
       
   289             case 365:
       
   290             case 366:          /* END OF NAMES */
       
   291                 message->channel = strtok (message->line, " ");
       
   292                 message->line = strtok (NULL, "\r\n");
       
   293                 return command;
       
   294                 break;
       
   295             case 372:          /* MOTD MESSAGES */
       
   296             case 375:
       
   297             case 376:          /* END OF MOTD */
       
   298                 return command;
       
   299                 break;
       
   300             case 401:          /* NO SUCH NICK/CHANNEL */
       
   301             case 403:          /* That CHANNEL doesnt exist */
       
   302                 return command;
       
   303                 break;
       
   304             case 474:
       
   305             case 475:
       
   306             case 476:
       
   307             case 477:
       
   308                 message->channel = strtok (message->line, " ");
       
   309                 message->line = strtok (NULL, "\r\n");
       
   310                 return command;
       
   311                 break;
       
   312             default:
       
   313                 printf ("DEBUG   %s", line);
       
   314                 printf ("Unknown Value: %d\n", value);
       
   315             }
       
   316         }
       
   317         printf ("DEBUG   %s", line);
       
   318         printf ("Unknown Command: %s\n", command);
       
   319         return command;
       
   320     }
       
   321     printf ("DEBUG   %s", line);
       
   322     return NULL;
       
   323 }