IRCWebHooks
Barry Adding files 3f04e22 (4 years ago)
diff --git a/src/irc.c b/src/irc.c
new file mode 100644
index 0000000..5ab201b
--- /dev/null
+++ b/src/irc.c
@@ -0,0 +1,240 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <string.h>
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+
+#include "config.h"
+#include "list.h"
+#include "irc.h"
+
+SSL_CTX *ctx;
+SSL *ssl;
+int conn;
+char sbuf[512];
+struct Node *head = NULL;
+struct Node *current = NULL;
+
+/* Auth a user */
+int
+auth(char *ident, char *vhost)
+{
+ char *pt;
+ char *identlist = strdup(ADMIN_IDENT);
+ char *vhostlist = strdup(ADMIN_VHOST);
+
+ pt = strtok(identlist,",");
+ while (pt != NULL) {
+ if (!strncmp(ident, pt, strlen(pt))) return 1;
+ pt = strtok(NULL, ",");
+ }
+
+ pt = strtok(vhostlist,",");
+ while (pt != NULL) {
+ if (!strncmp(vhost, pt, strlen(pt))) return 1;
+ pt = strtok(NULL, ",");
+ }
+
+ return 0;
+}
+
+/* Send data to server */
+void
+raw(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(sbuf, 512, fmt, ap);
+ va_end(ap);
+#ifdef VERBOSE
+ printf("<< %s", sbuf);
+#endif
+ SSL_write(ssl, sbuf, strlen(sbuf));
+}
+
+/* Bot code */
+void
+bot(void)
+{
+ BIO *certbio = NULL, *outbio = NULL;
+ X509 *cert = NULL;
+ X509_NAME *certname = NULL;
+ const SSL_METHOD *method;
+
+ char *user, *ident, *vhost, *command, *where, *message, *sep, *target;
+ int i, j, l, sl, o = -1, start, wordcount;
+ char buf[513];
+ struct addrinfo hints, *res;
+
+ /* Connect to IRC */
+ printf("Connecting to IRC...\n");
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ getaddrinfo(HOST, PORT, &hints, &res);
+ conn = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ connect(conn, res->ai_addr, res->ai_addrlen);
+
+ /* SSL connection */
+ {
+ OpenSSL_add_all_algorithms();
+ ERR_load_BIO_strings();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ certbio = BIO_new(BIO_s_file());
+ outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
+ if (SSL_library_init() < 0) {
+ BIO_printf(outbio, "Could not initialise the OpenSSL library!\n");
+ exit(1);
+ }
+ method = SSLv23_client_method();
+ if ((ctx = SSL_CTX_new(method)) == NULL) {
+ BIO_printf(outbio, "Unable to create a new SSL context!\n");
+ exit(1);
+ }
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+ ssl = SSL_new(ctx);
+ SSL_set_fd(ssl, conn);
+ if (SSL_connect(ssl) != 1) {
+ BIO_printf(outbio, "Error: Could not SSL connect!\n");
+ exit(1);
+ }
+ cert = SSL_get_peer_certificate(ssl);
+ if (cert == NULL) {
+ BIO_printf(outbio, "Error: Could not get certificate!\n");
+ exit(1);
+ }
+ certname = X509_NAME_new();
+ certname = X509_get_subject_name(cert);
+ }
+
+ /* IRC user */
+ raw("USER %s 0 0 :%s\r\n", NICK, NICK);
+ raw("NICK %s\r\n", NICK);
+ printf("Joined IRC!\n");
+
+ /* Add initial channel to list */
+ char *chanlist = strdup(CHAN);
+ char *pt;
+ pt = strtok(chanlist,",");
+ while (pt != NULL) {
+ insert_first(pt);
+ pt = strtok(NULL, ",");
+ }
+
+ /* IRC messages */
+ while (sl = SSL_read(ssl, sbuf, 512))
+ for (i = 0; i < sl; i++) {
+ o++;
+ buf[o] = sbuf[i];
+ if ((i > 0 && sbuf[i] == '\n' && sbuf[i-1] == '\r') || o == 512) {
+ buf[o + 1] = '\0';
+ l = o;
+ o = -1;
+
+#ifdef VERBOSE
+ printf(">> %s", buf);
+#endif
+
+ /* Deal with PINGs */
+ if (!strncmp(buf, "PING", 4)) {
+ buf[1] = 'O';
+ raw(buf);
+ /* Messages */
+ } else if (buf[0] == ':') {
+ wordcount = 0;
+ user = command = where = message = NULL;
+ /* Separate words */
+ for (j = 1; j < l; j++) {
+ if (buf[j] == ' ') {
+ buf[j] = '\0';
+ wordcount++;
+ switch (wordcount) {
+ case 1:
+ user = buf + 1;
+ break;
+ case 2:
+ command = buf + start;
+ break;
+ case 3:
+ where = buf + start;
+ break;
+ }
+ if (j == l - 1)
+ continue;
+ start = j + 1;
+ } else if (buf[j] == ':' && wordcount == 3) {
+ if (j < l - 1)
+ message = buf + j + 1;
+ break;
+ }
+ }
+
+ if (wordcount < 2)
+
+ /* Join a channel */
+ sleep(1);
+ if (!strncmp(command, "001", 3)) {
+#ifdef PASS
+ raw("PRIVMSG NickServ :IDENTIFY %s\r\n", PASS);
+ sleep(1);
+ raw("PRIVMSG HostServ :ON\r\n", PASS);
+ sleep(1);
+#endif
+ raw("JOIN %s\r\n", CHAN);
+ printf("Identified for nick, and joined channel!\n");
+ /* Incoming messages */
+ } else if (!strncmp(command, "PRIVMSG", 7)
+ || !strncmp(command, "NOTICE", 6)) {
+ if (where == NULL || message == NULL)
+ continue;
+ if ((sep = strchr(user, '!')) != NULL) {
+ user[sep - user] = '\0';
+ ident = sep + 1;
+ if ((sep = strchr(ident, '@')) != NULL) {
+ ident[sep - ident] = '\0';
+ vhost = sep + 1;
+ }
+ }
+ if (where[0] == '#' || where[0] == '&' || where[0] == '+' || where[0] == '!')
+ target = where;
+ else
+ target = user;
+
+ if (target == user && !strncmp(message, "JOIN ", 5) && auth(ident, vhost)) {
+ raw("%s\r\n", message);
+ char *p = message+5;
+ while (*p++) if (*p == '\n' || *p == '\r' || *p == ' ') *p = '\0';
+ insert_first(message+5);
+ } else
+ if (target == user && !strncmp(message, "LEAVE ", 6) && auth(ident, vhost)) {
+ raw("PART %s\r\n", message+6);
+ char *p = message+5;
+ while (*p++) if (*p == '\n' || *p == '\r' || *p == ' ') *p = '\0';
+ delete(message+6);
+ }
+
+#ifdef VERBOSE
+ printf(
+ "[from: %s] [reply-with: %s] [where: %s] [reply-to: %s] %s",
+ user, command, where, target, message
+ );
+#endif
+ }
+ }
+ }
+ }
+
+ SSL_free(ssl);
+ close(conn);
+ X509_free(cert);
+ SSL_CTX_free(ctx);
+}