summaryrefslogtreecommitdiff
path: root/src/main.c
blob: bb47da413c4d9649bafa3a932681e615ccceb272 (plain)
    1 /**
    2  * Copyright (C) 2016 Aaron Ball <nullspoon@oper.io>
    3  *
    4  * Ircbot is free software: you can redistribute it and/or modify
    5  * it under the terms of the GNU General Public License as published by
    6  * the Free Software Foundation, either version 3 of the License, or
    7  * (at your option) any later version.
    8  *
    9  * Ircbot is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with ircbot.  If not, see <http://www.gnu.org/licenses/>.
   16  */
   17 #include <stdio.h>
   18 #include <stdlib.h>
   19 #include <unistd.h>
   20 #include <string.h>
   21 #include <errno.h>
   22 #include <unistd.h>
   23 
   24 /* Networking libs */
   25 #include <arpa/inet.h>
   26 #include <sys/types.h>
   27 #include <sys/socket.h>
   28 #include <netdb.h>
   29 
   30 
   31 // For trapping Ctrl+c
   32 #include <signal.h>
   33 
   34 #include "common.h"
   35 
   36 #define buflen 512
   37 
   38 static int socket_desc;
   39 
   40 int newconn(char* addr, char* port) {
   41   int status;
   42   int socket_desc;
   43   struct addrinfo hints, *p;
   44   struct addrinfo *servinfo;
   45 
   46   // Ensure our struct is empty
   47   memset(&hints, 0, sizeof(hints));
   48 
   49   // Set hints struct
   50   hints.ai_flags    = AI_PASSIVE;
   51   hints.ai_family   = AF_UNSPEC;
   52   hints.ai_socktype = SOCK_STREAM;
   53 
   54   if((status = getaddrinfo(addr, port, &hints, &servinfo)) != 0) {
   55     fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
   56     exit(1);
   57   }
   58 
   59   // Iterrate the dns entries
   60   for(p = servinfo;p != NULL; p = p->ai_next) {
   61     // Attempt to create socket
   62     socket_desc = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
   63 
   64     // If socket creation failed, skip entry
   65     if (socket_desc == -1) continue;
   66 
   67     // Attempt to connect. If successful, break out of loop
   68     if (connect(socket_desc, p->ai_addr, p->ai_addrlen) != -1) break;
   69   }
   70 
   71   return socket_desc;
   72 }
   73 
   74 
   75 int recv_line(int sockd, char* out) {
   76   int i = 0;
   77   char c = '\0';
   78 
   79   while(c != '\n') {
   80     recv(sockd, &c, 1, 0);
   81     out[i] = c;
   82     i++;
   83   }
   84   out[i] = '\0';
   85   return i;
   86 }
   87 
   88 
   89 char* irc_get_msg(char* str, char* buf ) {
   90   int i = 2;
   91   int bufi = 0;
   92   // Place the start cursor
   93   while(i < strlen(str)) {
   94     if(str[i] == ':') {
   95       i++;
   96       printf("Found beginning of message at index %d\n", i);
   97       break;
   98     }
   99     i++;
  100   }
  101 
  102   while(str[i] != '\r' && str[i] != '\n' && str[i] != '\0') {
  103     buf[bufi] = str[i];
  104     bufi++;
  105     i++;
  106   }
  107 
  108   buf[bufi] = '\0';
  109   return buf;
  110 }
  111 
  112 
  113 int doloop(int sockd, int ret, char* chan) {
  114   char buf[buflen];
  115   char resp[buflen];
  116   char msg[1024];
  117   int len;
  118 
  119   while(1) {
  120     len = recv_line(sockd, buf);
  121     if(len == 0) continue;
  122 
  123     if(strncmp(buf, "PING", 4) == 0) {
  124       sprintf(&resp[0], "PONG %s", &buf[5]);
  125       printf("pong: %s", resp);
  126       send(sockd, resp, strlen(resp), 0);
  127       if(ret == 1) return 0;
  128     } else if(strstr(buf, "ircbot quit") != NULL) {
  129       // Quit command
  130       break;
  131     } else if(strstr(buf, "ircbot say ") != NULL) {
  132       // The say command
  133       irc_get_msg(buf, msg);
  134       sprintf(&resp[0], "PRIVMSG %s :%s\n", chan, &msg[11]);
  135       printf("Say command received. Saying \"%s\"\n", &msg[11]);
  136       send(sockd, resp, strlen(resp), 0);
  137     } else if(strstr(buf, "ircbot meaning of life") != NULL) {
  138       // The mol command
  139       sprintf(&resp[0], "PRIVMSG %s :%d\n", chan, 42);
  140       send(sockd, resp, strlen(resp), 0);
  141     } else if(strstr(buf, "Looking up your hostname") != NULL) {
  142       // Receive next line
  143       recv_line(sockd, buf);
  144       printf(buf);
  145       break;
  146     } else if(strstr(buf, "Nickname is already in use.") != NULL) {
  147       // We can't proceed if nickname is already in use.
  148       printf(buf);
  149       return -1;
  150     }
  151 
  152     printf(buf);
  153     //len = 0;
  154   }
  155 
  156   return 0;
  157 }
  158 
  159 
  160 int irc_auth(int sockd, char* nick, char* user, char* chan) {
  161   int status;
  162   char nickstr[buflen];
  163   char userstr[buflen];
  164   char joinstr[buflen];
  165 
  166   // Compose NICK statement
  167   sprintf(nickstr, "NICK %s\n", nick);
  168   // Compose NICK statement
  169   sprintf(userstr, "USER %s 0 * : %s\n", nick, user);
  170   // Compose the JOIN statement
  171   sprintf(joinstr, "JOIN %s\n", chan);
  172 
  173   // Wait for hostname identification
  174   doloop(sockd, 1, chan);
  175 
  176   // Send NICK command
  177   send(sockd, nickstr, strlen(nickstr), 0);
  178   printf("%s\n", nickstr);
  179 
  180   // Send USER command
  181   send(sockd, userstr, strlen(userstr), 0);
  182   printf("%s\n", userstr);
  183 
  184   // Wait for ping and send pong response
  185   printf("Waiting for initial ping\n");
  186   status = doloop(sockd, 1, chan);
  187   if(status == -1) return -1;
  188 
  189   // Send JOIN command
  190   printf("Joining channel %s\n", chan);
  191   send(sockd, joinstr, strlen(joinstr), 0);
  192 
  193   printf("Entering main watcher loop\n");
  194   doloop(sockd, 0, chan);
  195 
  196   // send quit message
  197   char quitstr[512];
  198   sprintf(quitstr, "QUIT :Blowing this popsicle stand\n");
  199   send(sockd, quitstr, strlen(quitstr), 0);
  200   close(sockd);
  201 
  202   return 0;
  203 }
  204 
  205 void quit(int signal) {
  206   char quitstr[512];
  207   sprintf(quitstr, "QUIT :Force quit!\n");
  208   send(socket_desc, quitstr, strlen(quitstr), 0);
  209   printf("\n\nQuitting, signal %d\n\n\n", signal);
  210 
  211   //doloop(socket_desc, 1);
  212   close(socket_desc);
  213   exit(128 + signal);
  214 }
  215 
  216 
  217 int main(int argc, char* argv[]) {
  218   char *server = argv[1];
  219   char *port = argv[2];
  220   char *nick = argv[3];
  221   char *chan = argv[4];
  222   int status;
  223 
  224   if(argc < 4) {
  225     printf("\nERROR: Irc server, port, and nick required to connect\n\n");
  226     printf("Usage:\n  ircbot irc.server.tld 6667 jcricket\n\n");
  227     return 1;
  228   }
  229 
  230   //int socket_desc;
  231 
  232   socket_desc = newconn(server, port);
  233 
  234   if(socket_desc == -1) {
  235     printf("Connection error\n");
  236     return 1;
  237   }
  238 
  239   signal(SIGINT, quit);
  240 
  241 
  242   status = irc_auth(socket_desc, nick, nick, chan);
  243   if(status == -1) return 1;
  244 
  245   // Cleanup
  246   close(socket_desc);
  247 
  248   return 0;
  249 }

Generated by cgit