diff --git a/src/irc.c b/src/irc.c 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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#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; +}