/** * Copyright (C) 2016 Aaron Ball * * Ircbot 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 3 of the License, or * (at your option) any later version. * * Ircbot 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 ircbot. If not, see . */ #include #include #include #include #include #include /* Networking libs */ #include #include #include #include // For trapping Ctrl+c #include #include "common.h" #define buflen 512 static int socket_desc; int newconn(char* addr, char* port) { int status; int socket_desc; struct addrinfo hints, *p; struct addrinfo *servinfo; // Ensure our struct is empty memset(&hints, 0, sizeof(hints)); // Set hints struct hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if((status = getaddrinfo(addr, port, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status)); exit(1); } // Iterrate the dns entries for(p = servinfo;p != NULL; p = p->ai_next) { // Attempt to create socket socket_desc = socket(p->ai_family, p->ai_socktype, p->ai_protocol); // If socket creation failed, skip entry if (socket_desc == -1) continue; // Attempt to connect. If successful, break out of loop if (connect(socket_desc, p->ai_addr, p->ai_addrlen) != -1) break; } return socket_desc; } int recv_line(int sockd, char* out) { int i = 0; char c = '\0'; while(c != '\n') { recv(sockd, &c, 1, 0); out[i] = c; i++; } out[i] = '\0'; return i; } char* irc_get_msg(char* str, char* buf ) { int i = 2; int bufi = 0; // Place the start cursor while(i < strlen(str)) { if(str[i] == ':') { i++; printf("Found beginning of message at index %d\n", i); break; } i++; } while(str[i] != '\r' && str[i] != '\n' && str[i] != '\0') { buf[bufi] = str[i]; bufi++; i++; } buf[bufi] = '\0'; return buf; } int doloop(int sockd, int ret, char* chan) { char buf[buflen]; char resp[buflen]; char msg[1024]; int len; while(1) { len = recv_line(sockd, buf); if(len == 0) continue; if(strncmp(buf, "PING", 4) == 0) { sprintf(&resp[0], "PONG %s", &buf[5]); printf("pong: %s", resp); send(sockd, resp, strlen(resp), 0); if(ret == 1) return 0; } else if(strstr(buf, "ircbot quit") != NULL) { // Quit command break; } else if(strstr(buf, "ircbot say ") != NULL) { // The say command irc_get_msg(buf, msg); sprintf(&resp[0], "PRIVMSG %s :%s\n", chan, &msg[11]); printf("Say command received. Saying \"%s\"\n", &msg[11]); send(sockd, resp, strlen(resp), 0); } else if(strstr(buf, "ircbot meaning of life") != NULL) { // The mol command sprintf(&resp[0], "PRIVMSG %s :%d\n", chan, 42); send(sockd, resp, strlen(resp), 0); } else if(strstr(buf, "Looking up your hostname") != NULL) { // Receive next line recv_line(sockd, buf); printf(buf); break; } else if(strstr(buf, "Nickname is already in use.") != NULL) { // We can't proceed if nickname is already in use. printf(buf); return -1; } printf(buf); //len = 0; } return 0; } int irc_auth(int sockd, char* nick, char* user, char* chan) { int status; char nickstr[buflen]; char userstr[buflen]; char joinstr[buflen]; // Compose NICK statement sprintf(nickstr, "NICK %s\n", nick); // Compose NICK statement sprintf(userstr, "USER %s 0 * : %s\n", nick, user); // Compose the JOIN statement sprintf(joinstr, "JOIN %s\n", chan); // Wait for hostname identification doloop(sockd, 1, chan); // Send NICK command send(sockd, nickstr, strlen(nickstr), 0); printf("%s\n", nickstr); // Send USER command send(sockd, userstr, strlen(userstr), 0); printf("%s\n", userstr); // Wait for ping and send pong response printf("Waiting for initial ping\n"); status = doloop(sockd, 1, chan); if(status == -1) return -1; // Send JOIN command printf("Joining channel %s\n", chan); send(sockd, joinstr, strlen(joinstr), 0); printf("Entering main watcher loop\n"); doloop(sockd, 0, chan); // send quit message char quitstr[512]; sprintf(quitstr, "QUIT :Blowing this popsicle stand\n"); send(sockd, quitstr, strlen(quitstr), 0); close(sockd); return 0; } void quit(int signal) { char quitstr[512]; sprintf(quitstr, "QUIT :Force quit!\n"); send(socket_desc, quitstr, strlen(quitstr), 0); printf("\n\nQuitting, signal %d\n\n\n", signal); //doloop(socket_desc, 1); close(socket_desc); exit(128 + signal); } int main(int argc, char* argv[]) { char *server = argv[1]; char *port = argv[2]; char *nick = argv[3]; char *chan = argv[4]; int status; if(argc < 4) { printf("\nERROR: Irc server, port, and nick required to connect\n\n"); printf("Usage:\n ircbot irc.server.tld 6667 jcricket\n\n"); return 1; } //int socket_desc; socket_desc = newconn(server, port); if(socket_desc == -1) { printf("Connection error\n"); return 1; } signal(SIGINT, quit); status = irc_auth(socket_desc, nick, nick, chan); if(status == -1) return 1; // Cleanup close(socket_desc); return 0; }