author | Markus Bröker <mbroeker@largo.dyndns.tv> |
Sat, 13 Dec 2008 15:40:14 +0100 | |
changeset 11 | a769385a59c6 |
parent 10 | 311ea5fa60dd |
child 12 | 213c3d4abc66 |
permissions | -rw-r--r-- |
/** * $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 ("INET_NTOA"); 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 ... */ #ifdef NETBSD /* * BEGIN OF STREAM */ stream = fdopen (csocket, "r+"); #else /* * END OF STREAM */ stream = fdopen (csocket, "a+"); #endif csocket = fileno (stream); printf ("Using filedescriptor %d for stream operations\n", csocket); return stream; } int irc_login (FILE * stream, char *server, char *nick, char *password) { MSG message = { NULL, 0, 0, 0, 0, 0, 0 }; char msg[513]; char *user; struct passwd *pwd; if ((user = getenv ("USER")) == NULL) return IRC_GENERAL_ERROR; if ((pwd = getpwnam (user)) == NULL) return IRC_GENERAL_ERROR; if (password == NULL) return IRC_LOGIN_ERROR; if (stream == NULL) return IRC_GENERAL_ERROR; else message.stream = stream; fprintf (stream, "NICK %s\r\n", nick); fprintf (stream, "USER %s 0 %s %s\r\n", user, server, pwd->pw_gecos); fprintf (stream, "PRIVMSG NICKSERV :IDENTIFY %s\r\n", password); for (;;) { *msg = '\0'; 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, ":You are now logged in.") != 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 /* * DONT NERVE WITH PING PONG MESSAGES */ 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 */ return command; 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->current_channel = message->channel; 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; 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", message->current_channel, message->line); return command; case 320: case 328: /* INFORMATION */ 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; case 353: case 365: case 366: /* END OF NAMES */ message->channel = strtok (message->line, " "); message->line = strtok (NULL, "\r\n"); return command; case 372: /* MOTD MESSAGES */ case 375: case 376: /* END OF MOTD */ return command; case 401: /* NO SUCH NICK/CHANNEL */ case 403: /* THAT CHANNEL DOESN'T EXIST */ case 441: /* THEY AREN'T ON THIS CHANNEL */ return command; case 474: case 475: case 476: case 477: case 482: message->channel = strtok (message->line, " "); message->line = strtok (NULL, "\r\n"); return command; case 901: /* notify or some crap */ message->channel = strtok (message->line, " "); message->line = strtok (NULL, "\r\n"); return command; default: printf ("DEBUG %s", line); printf ("Unknown Command Value: %d\n", value); } } printf ("DEBUG %s", line); printf ("Unknown Command: %s\n", command); return command; } printf ("NOT PARSEABLE %s", line); return NULL; }