src/irc.c
changeset 0 586472add385
child 1 5d249c79842d
new file mode 100644
--- /dev/null
+++ b/src/irc.c
@@ -0,0 +1,323 @@
+/**
+ *  $Id: irc.c 51 2008-01-10 00:19:39Z mbroeker $
+ * $URL: http://localhost/svn/c/mcbot/trunk/src/irc.c $
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <pwd.h>
+
+#include <irc.h>
+
+#define VERSION_STRING "MCBOT on GNU/LINUX"
+
+const char *IRC_Commands[] = {
+    "NOTICE", "MODE", "JOIN", "PART",
+    "TOPIC", "PING", "ENOMEM", "ERROR",
+    "VERSION", "PRIVMSG", "QUIT", "NICK",
+    NULL,
+};
+
+FILE *irc_connect (char *server, unsigned int port)
+{
+    struct hostent *he;
+    char *ip;
+    struct sockaddr_in ca;
+    int csocket;
+    FILE *stream;
+
+    he = gethostbyname (server);
+    if (he == NULL) {
+        perror ("GETHOSTBYNAME");
+        return NULL;
+    }
+
+    if ((ip = inet_ntoa (*((struct in_addr *)he->h_addr_list[0]))) == NULL) {
+        perror ("GETHOSTBYNAME");
+        return NULL;
+    } else
+        printf ("IP: %s\n", ip);
+
+    ca.sin_family = AF_INET;
+    ca.sin_addr.s_addr = inet_addr (ip);
+    ca.sin_port = htons (port);
+
+    csocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (connect (csocket, (struct sockaddr *)&ca, (socklen_t) sizeof (ca)) == -1) {
+        perror ("CONNECT");
+        return NULL;
+    }
+
+    /*
+     * rw mode,but many seek errors ...
+     */
+    stream = fdopen (csocket, "a+");
+    return stream;
+}
+
+int irc_login (FILE * stream, char *nick, char *password)
+{
+    MSG message;
+    char msg[513];
+    char *user;
+    struct passwd *pwd = NULL;
+
+    if ((user = getenv ("USER")) != NULL)
+        if ((pwd = getpwnam (user)) == NULL)
+            return IRC_GENERAL_ERROR;
+
+    if (strlen (password) == 0)
+        return IRC_LOGIN_ERROR;
+
+    if (stream == NULL)
+        return IRC_GENERAL_ERROR;
+
+    fprintf (stream, "NICK %s\r\n", nick);
+
+    fprintf (stream, "USER %s 0 irc.freenode.net %s\r\n", user, pwd->pw_gecos);
+
+    fprintf (stream, "PRIVMSG NICKSERV :IDENTIFY %s\r\n", password);
+
+    for (;;) {
+        fgets (msg, 512, stream);
+        if ((user = irc_parsemessage (msg, &message)) != NULL)
+            printf ("%10s %s\n", user, message.line);
+
+        if (strstr (msg, "VERSION") != NULL) {
+            printf ("%10s %s", "VERSION", msg);
+            printf ("%10s %s %s :%s\n", "WRITE", message.command, message.user, VERSION_STRING);
+            fprintf (stream, "VERSION :%s\r\n", VERSION_STRING);
+        }
+
+        if (strstr (msg, ":Password accepted") != NULL) {
+            break;
+        }
+
+        if (strstr (msg, ":Password Incorrect") != NULL) {
+            return IRC_LOGIN_ERROR;
+        }
+
+        if (strstr (msg, "ERROR :Closing Link") != NULL) {
+            return IRC_GENERAL_ERROR;
+        }
+
+        if (strstr (msg, "is not registered") != NULL) {
+            return IRC_LOGIN_ERROR;
+        }
+    }
+
+    sleep (2);
+    return 0;
+}
+
+static char *irc_getmessage (const char *line, MSG * message)
+{
+    char *theLine;
+    char *token;
+    char *ptr;
+
+    if ((theLine = strdup (line)) == NULL)
+        return "ENOMEM";
+
+    message->user = message->email = NULL;
+    message->command = NULL;
+    message->channel = message->line = NULL;
+
+    token = strtok (theLine, " ");
+    if (*token != ':') {
+        /*
+         * SERVER MESSAGES
+         */
+        if ((ptr = strtok (NULL, "\r\n")) != NULL)
+            ++ptr;
+        message->line = ptr;
+        return token;
+    }
+
+    message->user = ++token;
+    message->command = strtok (NULL, " ");
+
+    message->line = strtok (NULL, "\r\n");
+
+    return message->command;
+}
+
+/*
+ * Main prints ("%10s %s %s\n", MSG->command MSG->channel MSG->line).
+ * This functions makes sure, that there will be someting to print...
+ */
+
+char *irc_parsemessage (const char *line, MSG * message)
+{
+    int i;
+    char *command;
+    char *ptr;
+    int value;
+
+    i = 0;
+    if ((command = irc_getmessage (line, message)) != NULL) {
+        while (IRC_Commands[i] != NULL) {
+            if (strcmp (IRC_Commands[i], command) == 0) {
+                switch (i) {
+
+                case 0:        /* NOTICE */
+                    if (message->line == NULL) {
+                        message->channel = "*";
+                        message->line = "*";
+                    } else {
+                        message->channel = strtok (message->line, " ");
+                        if ((message->line = strtok (NULL, "\r\n")) != NULL)
+                            ++message->line;
+                    }
+                    return command;
+                case 1:        /* MODE */
+                    message->channel = strtok (message->line, " ");
+                    message->line = strtok (NULL, "\r\n");
+                    return command;
+                case 2:        /* JOIN */
+                case 3:        /* PART */
+                    if ((message->channel = strchr (message->line, ':')))
+                        ++message->channel;
+                    message->line = message->user;
+                    return command;
+                case 4:        /* TOPIC */
+                    message->channel = strtok (message->line, " ");
+                    if ((message->line = strtok (NULL, "\r\n")))
+                        ++message->line;
+                    return command;
+                case 5:        /* PING */
+#ifdef DEBUG
+                    printf ("%10s %s localhost\n", "PING", message->line);
+#endif
+                    fprintf (message->stream, "PONG :%s\r\n", message->line);
+                    message->channel = "localhost";
+#ifdef DEBUG
+                    return "PONG";
+#else
+                    return NULL;
+#endif
+                case 6:        /* ENOMEM */
+                case 7:        /* ERROR */
+                    exit (-1);
+                    break;
+                case 8:        /* VERSION */
+                    if ((ptr = strchr (message->user, ' ')))
+                        *ptr = 0;
+                    return command;
+                case 9:        /* PRIVMSG */
+                    if ((message->email = strchr (message->user, '=')))
+                        ++message->email;
+                    if ((ptr = strchr (message->user, '!')))
+                        *ptr = 0;
+
+                    message->channel = strtok (message->line, " ");
+                    message->line = strtok (NULL, "\r\n");
+                    message->line++;
+                    printf ("%10s %s %s :%s\n", "READ", message->command, message->channel, message->line);
+                    return NULL;
+                case 10:       /* QUIT */
+                    message->channel = message->user;
+                    return command;
+                case 11:       /* NICK */
+                    message->channel = message->user;
+                    return command;
+                }
+            }
+            i++;
+        }
+
+        if ((value = atoi (command)) != 0) {
+            switch (value) {
+            case 1:            /* CONNECTION INFOS */
+            case 2:
+            case 3:
+            case 4:
+            case 5:
+            case 250:
+            case 251:
+            case 252:
+            case 254:
+            case 255:
+            case 265:
+            case 266:
+                /*
+                 * prints as is in irc_login
+                 */
+                return command;
+                break;
+            case 311:
+            case 312:
+            case 315:          /* END OF WHO */
+            case 318:
+                message->channel = strtok (message->line, " ");
+                message->line = strtok (NULL, "\r\n");
+                return command;
+            case 319:
+                message->channel = strtok (message->line, " ");
+                message->line = strtok (NULL, "\r\n");
+                fprintf (message->stream, "PRIVMSG %s :%s\r\n", "#mcbot", message->line);
+                return command;
+            case 320:
+            case 332:          /* TOPIC OF CHANNEL */
+            case 333:          /* NAMES IN CHANNEL */
+                message->channel = strtok (message->line, " ");
+                message->line = strtok (NULL, "\r\n");
+                return command;
+            case 351:          /* SVERSION */
+                message->channel = strtok (message->line, " ");
+                message->line = strtok (NULL, "\r\n");
+                return command;
+            case 352:          /* WHO LIST */
+                message->channel = strtok (message->line, " ");
+                message->line = strtok (NULL, "\r\n");
+                /*
+                 * MORE THAN 3 LINES AND YOU WILL be KICKED
+                 */
+                return command;
+                break;
+            case 353:
+            case 365:
+            case 366:          /* END OF NAMES */
+                message->channel = strtok (message->line, " ");
+                message->line = strtok (NULL, "\r\n");
+                return command;
+                break;
+            case 372:          /* MOTD MESSAGES */
+            case 375:
+            case 376:          /* END OF MOTD */
+                return command;
+                break;
+            case 401:          /* NO SUCH NICK/CHANNEL */
+            case 403:          /* That CHANNEL doesnt exist */
+                return command;
+                break;
+            case 474:
+            case 475:
+            case 476:
+            case 477:
+                message->channel = strtok (message->line, " ");
+                message->line = strtok (NULL, "\r\n");
+                return command;
+                break;
+            default:
+                printf ("DEBUG   %s", line);
+                printf ("Unknown Value: %d\n", value);
+            }
+        }
+        printf ("DEBUG   %s", line);
+        printf ("Unknown Command: %s\n", command);
+        return command;
+    }
+    printf ("DEBUG   %s", line);
+    return NULL;
+}