From 3c586141c2d64fb40b846b06eafb9d20bbbf7e7b Mon Sep 17 00:00:00 2001 From: Aaron Blakely Date: Tue, 24 Mar 2015 05:12:35 -0500 Subject: [PATCH] Initial commit --- .gitignore | 3 ++ Makefile | 19 ++++++++ README.md | 1 + lib/irc.h | 32 ++++++++++++++ lib/util.h | 15 +++++++ src/irc.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 71 +++++++++++++++++++++++++++++ src/util.c | 63 ++++++++++++++++++++++++++ xbot.cfg | 13 ++++++ 9 files changed, 345 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.md create mode 100644 lib/irc.h create mode 100644 lib/util.h create mode 100644 src/irc.c create mode 100644 src/main.c create mode 100644 src/util.c create mode 100644 xbot.cfg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..abfd277 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +xbot +build + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..da0767b --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +CC=gcc +CFLAGS=-c -lconfig -I./lib +BINFLAGS=-lconfig +SRC=./src +OBJ=./build +OBJECTS=$(OBJ)/*.o +EXEC=xbot + +main: + @rm -rf build + @mkdir build + $(CC) $(CFLAGS) $(SRC)/main.c -o $(OBJ)/main.o + $(CC) $(CFLAGS) $(SRC)/irc.c -o $(OBJ)/irc.o + $(CC) $(CFLAGS) $(SRC)/util.c -o $(OBJ)/util.o + $(CC) -o $(EXEC) $(OBJECTS) $(BINFLAGS) + @echo "All Done!" + +clean: + @rm -rf build $(EXEC) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4782e4 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# xbot diff --git a/lib/irc.h b/lib/irc.h new file mode 100644 index 0000000..b9b1151 --- /dev/null +++ b/lib/irc.h @@ -0,0 +1,32 @@ +/* + * xbot: Just another IRC bot + * + * Written by Aaron Blakely +**/ + +#ifndef IRC_H +#define IRC_H + +#include + +struct irc_conn +{ + FILE *srv_fd; + + char nick[32]; + char *host; + char *port; + char *real_name; + + // I/O Buffers + char out[4096]; + char in[4096]; + +}; + +void irc_connect(struct irc_conn *bot); +void irc_auth(struct irc_conn *bot); +void irc_raw(struct irc_conn *bot, char *fmt, ...); +void irc_parse_raw(struct irc_conn *bot, char *raw); + +#endif \ No newline at end of file diff --git a/lib/util.h b/lib/util.h new file mode 100644 index 0000000..49e2860 --- /dev/null +++ b/lib/util.h @@ -0,0 +1,15 @@ +/* + * xbot: Just another IRC bot + * + * Written by Aaron Blakely +**/ + +#ifndef UTIL_H +#define UTIL_H + +void eprint(char *fmt, ...); +void strlcpy(char *to, const char *from, int len); +char *skip(char *s, char c); +void trim(char *s); + +#endif \ No newline at end of file diff --git a/src/irc.c b/src/irc.c new file mode 100644 index 0000000..74eea2c --- /dev/null +++ b/src/irc.c @@ -0,0 +1,128 @@ +/* + * irc.c: IRC connection and parser + * xbot: Just another IRC bot + * + * Written by Aaron Blakely +**/ + +#include "irc.h" +#include "util.h" +#include +#include +#include +#include +#include +#include +#include + +void irc_connect(struct irc_conn *bot) +{ + int srv_fd; + struct addrinfo hints; + struct addrinfo *res, *r; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo(bot->host, bot->port, &hints, &res) != 0) + { + eprint("Error: Cannot resolve hostname '%s':", bot->host); + } + + for (r = res; r; r->ai_next) + { + if ((srv_fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) + { + continue; + } + + if (connect(srv_fd, r->ai_addr, r->ai_addrlen) == 0) + { + break; + } + + close(srv_fd); + } + + freeaddrinfo(res); + if (!r) + { + eprint("Error: Cannot connect to host '%s'\n", bot->host); + } + + bot->srv_fd = fdopen(srv_fd, "r+"); +} + +void irc_auth(struct irc_conn *bot) +{ + irc_raw(bot, "NICK %s", bot->nick); + irc_raw(bot, "USER %s localhost %s :xbot (v0.1) - developed by @Dark_Aaron", bot->nick, bot->host); + fflush(bot->srv_fd); +} + +void irc_raw(struct irc_conn *bot, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsnprintf(bot->out, sizeof bot->out, fmt, ap); + va_end(ap); + + + fprintf(bot->srv_fd, "%s\r\n", bot->out); +} + +void irc_parse_raw(struct irc_conn *bot, char *raw) +{ + char *user, *par, *text; + user = bot->host; + + if (!raw || !*raw) + { + return; + } + + if (raw[0] == ':') + { + user = raw + 1; + raw = skip(user, ' '); + + if (raw[0] == '\0') + { + return; + } + + skip(user, '!'); + } + + skip(raw, '\r'); + par = skip(raw, ' '); + text = skip(par, ':'); + trim(par); + + if (!strcmp("PONG", raw)) + { + return; + } + + if (!strcmp("PRIVMSG", raw)) + { + //handle_privmsg(user, par, text) + if (!strcmp("Dark_Aaron", user)) + { + irc_raw(bot, "JOIN #bots"); + } + } + else if (!strcmp("PING", raw)) + { + irc_raw(bot, "PONG %s", text); + } + else + { + if (!strcmp("NICK", raw) && !strcmp(user, bot->nick)) + { + strlcpy(bot->nick, text, sizeof bot->nick); + } + } +} \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..f82b0c2 --- /dev/null +++ b/src/main.c @@ -0,0 +1,71 @@ +/* + * xbot: Just another IRC bot + * + * Written by Aaron Blakely +**/ + +#include +#include +#include +#include +#include "irc.h" + + +int main() +{ + fd_set rd; + config_t cfg, *cf; + const config_setting_t *retries; + const char *base = NULL; + struct irc_conn bot; + + // Init the config parser + cf = &cfg; + config_init(cf); + + if (!config_read_file(cf, "xbot.cfg")) + { + printf("xbot.cfg:%d - %s\n", + config_error_line(cf), + config_error_text(cf)); + + config_destroy(cf); + return -1; + } + + // Fill our bot struct with values from the config + if (config_lookup_string(cf, "bot.nick", &base)) + strlcpy(bot.nick, base, sizeof bot.nick); + + if (config_lookup_string(cf, "server.host", &base)) + bot.host = (char *)base; + + if (config_lookup_string(cf, "server.port", &base)) + bot.port = (char *)base; + + // Connect to the server + printf("Connecting to %s...\n", bot.host); + irc_connect(&bot); + irc_auth(&bot); + + // Free the config before entering the main loop + config_destroy(cf); + + for (;;) + { + FD_ZERO(&rd); + FD_SET(fileno(bot.srv_fd), &rd); + + if (FD_ISSET(fileno(bot.srv_fd), &rd)) + { + if (fgets(bot.in, sizeof bot.in, bot.srv_fd) == NULL) + { + eprint("xbot: remote host closed connection\n"); + } + + irc_parse_raw(&bot, bot.in); + } + } + + return 0; +} \ No newline at end of file diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..952b590 --- /dev/null +++ b/src/util.c @@ -0,0 +1,63 @@ +/* + * xbot: Just another IRC bot + * + * Written by Aaron Blakely +**/ + +#include +#include +#include +#include +#include + +void eprint(char *fmt, ...) +{ + char bufout[4096]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(bufout, sizeof bufout, fmt, ap); + va_end(ap); + + fprintf(stderr, "%s", bufout); + if (fmt[0] && fmt[strlen(fmt) - 1] == ':') + { + fprintf(stderr, "%s\n", strerror(errno)); + } + + exit(1); +} + +void strlcpy(char *to, const char *from, int len) +{ + memccpy(to, from, '\0', len); + to[len-1] = '\0'; +} + +char *skip(char *s, char c) +{ + while (*s != c && *s != '\0') + { + s++; + } + + if (*s != '\0') + { + *s++ = '\0'; + } + + return s; +} + +void trim(char *s) +{ + char *e; + + e = s + strlen(s) - 1; + while (isspace(*e) && e > s) + { + e--; + } + + *(e + 1) = '\0'; +} \ No newline at end of file diff --git a/xbot.cfg b/xbot.cfg new file mode 100644 index 0000000..ed640a8 --- /dev/null +++ b/xbot.cfg @@ -0,0 +1,13 @@ +# xbot configuration file + +bot: +{ + nick = "xbot"; + user = "xbot"; +}; + +server: +{ + host = "irc.alphachat.net"; + port = "6667"; +}; \ No newline at end of file