about summary refs log tree commit diff
path: root/server.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-10-22 22:49:05 -0400
committerJune McEnroe <june@causal.agency>2019-10-22 22:49:05 -0400
commit72cee2b26449468734de68c797d0cc6945f176f9 (patch)
treee89834666eef7a5615cfc8857c3592d2aa37bfec /server.c
parentMention server-time in manual page (diff)
downloadpounce-72cee2b26449468734de68c797d0cc6945f176f9.tar.gz
pounce-72cee2b26449468734de68c797d0cc6945f176f9.zip
Implement serverLogin
Diffstat (limited to 'server.c')
-rw-r--r--server.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/server.c b/server.c
index b86d769..4c22287 100644
--- a/server.c
+++ b/server.c
@@ -17,7 +17,10 @@
 #include <err.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 #include <sys/socket.h>
 #include <sysexits.h>
 #include <tls.h>
@@ -25,6 +28,8 @@
 
 #include "bounce.h"
 
+typedef unsigned char byte;
+
 static struct tls *client;
 
 int serverConnect(const char *host, const char *port) {
@@ -69,3 +74,77 @@ int serverConnect(const char *host, const char *port) {
 
 	return sock;
 }
+
+void serverSend(const char *ptr, size_t len) {
+	while (len) {
+		ssize_t ret = tls_write(client, ptr, len);
+		if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) continue;
+		if (ret < 0) errx(EX_IOERR, "tls_write: %s", tls_error(client));
+		ptr += ret;
+		len -= ret;
+	}
+}
+
+static void format(const char *format, ...) {
+	char *buf;
+	va_list ap;
+	va_start(ap, format);
+	int len = vasprintf(&buf, format, ap);
+	va_end(ap);
+	if (!buf) err(EX_OSERR, "vasprintf");
+	serverSend(format, len);
+	free(buf);
+}
+
+static const char Base64[64] = {
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
+};
+
+static char *base64(const byte *src, size_t len) {
+	char *dst = malloc(1 + (len + 2) / 3 * 4);
+	if (!dst) err(EX_OSERR, "malloc");
+
+	size_t i = 0;
+	while (len > 2) {
+		dst[i++] = Base64[0x3F & (src[0] >> 2)];
+		dst[i++] = Base64[0x3F & (src[0] << 4 | src[1] >> 4)];
+		dst[i++] = Base64[0x3F & (src[1] << 2 | src[2] >> 6)];
+		dst[i++] = Base64[0x3F & src[2]];
+		src += 3;
+		len -= 3;
+	}
+
+	if (len) {
+		dst[i++] = Base64[0x3F & (src[0] >> 2)];
+		if (len > 1) {
+			dst[i++] = Base64[0x3F & (src[0] << 4 | src[1] >> 4)];
+			dst[i++] = Base64[0x3F & (src[1] << 2)];
+		} else {
+			dst[i++] = Base64[0x3F & (src[0] << 4)];
+			dst[i++] = '=';
+		}
+		dst[i++] = '=';
+	}
+
+	dst[i] = '\0';
+	return dst;
+}
+
+static char *authBase64;
+
+void serverLogin(
+	const char *pass, const char *auth,
+	const char *nick, const char *user, const char *real
+) {
+	if (pass) format("PASS :%s\r\n", pass);
+	if (auth) {
+		byte plain[1 + strlen(auth)];
+		plain[0] = 0;
+		for (size_t i = 0; auth[i]; ++i) {
+			plain[1 + i] = (auth[i] == ':' ? 0 : auth[i]);
+		}
+		authBase64 = base64(plain, sizeof(plain));
+		format("CAP REQ :sasl\r\n");
+	}
+	format("NICK %s\r\nUSER %s 0 * :%s\r\n", nick, user, real);
+}