summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-10-23 20:37:23 -0400
committerJune McEnroe <june@causal.agency>2019-10-23 20:37:23 -0400
commitb7aee7b2bfa68be4afba70ec30269be1568473b8 (patch)
treed5bfd25d28db3d01611a50c18262a40fe06a9e72
parentTrack nick changes (diff)
downloadpounce-b7aee7b2bfa68be4afba70ec30269be1568473b8.tar.gz
pounce-b7aee7b2bfa68be4afba70ec30269be1568473b8.zip
Track channels and sync ISUPPORT
-rw-r--r--state.c149
1 files changed, 114 insertions, 35 deletions
diff --git a/state.c b/state.c
index e86cf01..b85d66c 100644
--- a/state.c
+++ b/state.c
@@ -16,6 +16,7 @@
 
 #include <assert.h>
 #include <err.h>
+#include <stdarg.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -24,10 +25,6 @@
 
 #include "bounce.h"
 
-static char *nick;
-
-// TODO: Channels.
-
 static struct {
 	char *origin;
 	char *welcome;
@@ -36,12 +33,55 @@ static struct {
 	char *myInfo[4];
 } intro;
 
-enum { SupportCap = 32 };
+static char *nick;
+
+static void set(char **field, const char *value) {
+	if (*field) free(*field);
+	*field = strdup(value);
+	if (!*field) err(EX_OSERR, "strdup");
+}
+
+static struct {
+	char **names;
+	size_t cap, len;
+} chan;
+
+static void chanAdd(const char *name) {
+	if (chan.len == chan.cap) {
+		chan.cap = (chan.cap ? chan.cap * 2 : 8);
+		chan.names = realloc(chan.names, sizeof(char *) * chan.cap);
+		if (!chan.names) err(EX_OSERR, "realloc");
+	}
+	chan.names[chan.len] = strdup(name);
+	if (!chan.names[chan.len]) err(EX_OSERR, "strdup");
+	chan.len++;
+}
+
+static void chanRemove(const char *name) {
+	for (size_t i = 0; i < chan.len; ++i) {
+		if (strcmp(chan.names[i], name)) continue;
+		free(chan.names[i]);
+		chan.names[i] = chan.names[--chan.len];
+		return;
+	}
+}
+
 static struct {
-	char *tokens[SupportCap];
-	size_t len;
+	char **tokens;
+	size_t cap, len;
 } support;
 
+static void supportAdd(const char *token) {
+	if (support.len == support.cap) {
+		support.cap = (support.cap ? support.cap * 2 : 8);
+		support.tokens = realloc(support.tokens, sizeof(char *) * support.cap);
+		if (!support.tokens) err(EX_OSERR, "realloc");
+	}
+	support.tokens[support.len] = strdup(token);
+	if (!support.tokens[support.len]) err(EX_OSERR, "strdup");
+	support.len++;
+}
+
 bool stateReady(void) {
 	return nick
 		&& intro.origin
@@ -52,20 +92,6 @@ bool stateReady(void) {
 		&& support.len;
 }
 
-static void set(char **field, const char *value) {
-	if (*field) free(*field);
-	*field = strdup(value);
-	if (!*field) err(EX_OSERR, "strdup");
-}
-
-static void supportSet(const char *token) {
-	if (support.len == SupportCap) {
-		warnx("dropping ISUPPORT token %s", token);
-		return;
-	}
-	set(&support.tokens[support.len++], token);
-}
-
 typedef void Handler(struct Message);
 
 static void handleCap(struct Message msg) {
@@ -100,7 +126,7 @@ static void handleReplyMyInfo(struct Message msg) {
 static void handleReplyISupport(struct Message msg) {
 	for (size_t i = 1; i < ParamCap; ++i) {
 		if (!msg.params[i] || strchr(msg.params[i], ' ')) break;
-		supportSet(msg.params[i]);
+		supportAdd(msg.params[i]);
 	}
 }
 
@@ -118,6 +144,24 @@ static void handleNick(struct Message msg) {
 	if (self(msg)) set(&nick, msg.params[0]);
 }
 
+static void handleJoin(struct Message msg) {
+	if (!msg.origin) errx(EX_PROTOCOL, "JOIN without origin");
+	if (!msg.params[0]) errx(EX_PROTOCOL, "JOIN without channel");
+	if (self(msg)) chanAdd(msg.params[0]);
+}
+
+static void handlePart(struct Message msg) {
+	if (!msg.origin) errx(EX_PROTOCOL, "PART without origin");
+	if (!msg.params[0]) errx(EX_PROTOCOL, "PART without channel");
+	if (self(msg)) chanRemove(msg.params[0]);
+}
+
+static void handleKick(struct Message msg) {
+	if (!msg.params[0]) errx(EX_PROTOCOL, "KICK without channel");
+	if (!msg.params[1]) errx(EX_PROTOCOL, "KICK without nick");
+	if (!strcmp(msg.params[1], nick)) chanRemove(msg.params[0]);
+}
+
 static void handleError(struct Message msg) {
 	errx(EX_UNAVAILABLE, "%s", msg.params[0]);
 }
@@ -133,7 +177,10 @@ static const struct {
 	{ "005", handleReplyISupport },
 	{ "CAP", handleCap },
 	{ "ERROR", handleError },
+	{ "JOIN", handleJoin },
+	{ "KICK", handleKick },
 	{ "NICK", handleNick },
+	{ "PART", handlePart },
 };
 
 void stateParse(char *line) {
@@ -146,23 +193,55 @@ void stateParse(char *line) {
 	}
 }
 
+// FIXME: Deduplicate this.
+static void format(struct Client *client, const char *format, ...) {
+	char buf[513];
+	va_list ap;
+	va_start(ap, format);
+	int len = vsnprintf(buf, sizeof(buf), format, ap);
+	va_end(ap);
+	assert(len > 0 && (size_t)len < sizeof(buf));
+	clientSend(client, buf, len);
+}
+
 void stateSync(struct Client *client) {
-	char buf[4096];
-	int len = snprintf(
-		buf, sizeof(buf),
-		":%s 001 %s :%s\r\n"
-		":%s 002 %s :%s\r\n"
-		":%s 003 %s :%s\r\n"
-		":%s 004 %s %s %s %s %s\r\n",
-		intro.origin, nick, intro.welcome,
-		intro.origin, nick, intro.yourHost,
-		intro.origin, nick, intro.created,
+	format(client, ":%s 001 %s :%s\r\n", intro.origin, nick, intro.welcome);
+	format(client, ":%s 002 %s :%s\r\n", intro.origin, nick, intro.yourHost);
+	format(client, ":%s 003 %s :%s\r\n", intro.origin, nick, intro.created);
+	format(
+		client, ":%s 004 %s %s %s %s\r\n",
 		intro.origin, nick,
 		intro.myInfo[0], intro.myInfo[1], intro.myInfo[2], intro.myInfo[3]
 	);
-	assert(len > 0 && (size_t)len < sizeof(buf));
 
-	// TODO: Send ISUPPORT.
+	size_t i;
+	for (i = 0; support.len - i >= 13; i += 13) {
+		format(
+			client,
+			":%s 005 %s"
+			" %s %s %s %s %s %s %s %s %s %s %s %s %s"
+			" :are supported by this server\r\n",
+			intro.origin, nick,
+			support.tokens[i + 0], support.tokens[i + 1],
+			support.tokens[i + 2], support.tokens[i + 3],
+			support.tokens[i + 4], support.tokens[i + 5],
+			support.tokens[i + 6], support.tokens[i + 7],
+			support.tokens[i + 8], support.tokens[i + 9],
+			support.tokens[i + 10], support.tokens[i + 11],
+			support.tokens[i + 12]
+		);
+	}
+	// FIXME: Do something about this?
+	if (i < support.len) {
+		format(client, ":%s 005 %s", intro.origin, nick);
+		for (; i < support.len; ++i) {
+			format(client, " %s", support.tokens[i]);
+		}
+		format(client, " :are supported by this server\r\n");
+	}
 
-	clientSend(client, buf, len);
+	// FIXME: Send a proper self origin.
+	for (size_t i = 0; i < chan.len; ++i) {
+		format(client, ":%s JOIN %s\r\n", nick, chan.names[i]);
+	}
 }
ight'> Upstream will stop providing gz compressed source tarballs [0], so stop using them. [0] https://lists.zx2c4.com/pipermail/cgit/2018-November/004254.html Signed-off-by: Christian Hesse <mail@eworm.de> 2018-10-12git: update to v2.19.1Christian Hesse Update to git version v2.19.1. Required changes follow upstream commits: * commit: add repository argument to get_cached_commit_buffer (3ce85f7e5a41116145179f0fae2ce6d86558d099) * commit: add repository argument to lookup_commit_reference (2122f6754c93be8f02bfb5704ed96c88fc9837a8) * object: add repository argument to parse_object (109cd76dd3467bd05f8d2145b857006649741d5c) * tag: add repository argument to deref_tag (a74093da5ed601a09fa158e5ba6f6f14c1142a3e) * tag: add repository argument to lookup_tag (ce71efb713f97f476a2d2ab541a0c73f684a5db3) * tree: add repository argument to lookup_tree (f86bcc7b2ce6cad68ba1a48a528e380c6126705e) * archive.c: avoid access to the_index (b612ee202a48f129f81f8f6a5af6cf71d1a9caef) * for_each_*_object: move declarations to object-store.h (0889aae1cd18c1804ba01c1a4229e516dfb9fe9b) Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11ui-ssdiff: ban strcat()Christian Hesse Git upstream bans strcat() with commit: banned.h: mark strcat() as banned 1b11b64b815db62f93a04242e4aed5687a448748 Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11ui-ssdiff: ban strncpy()Christian Hesse Git upstream bans strncpy() with commit: banned.h: mark strncpy() as banned e488b7aba743d23b830d239dcc33d9ca0745a9ad Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11ui-shared: ban strcat()Christian Hesse Git upstream bans strcat() with commit: banned.h: mark strcat() as banned 1b11b64b815db62f93a04242e4aed5687a448748 To avoid compiler warnings from gcc 8.1.x we get the hard way. Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11ui-patch: ban sprintf()Christian Hesse Git upstream bans sprintf() with commit: banned.h: mark sprintf() as banned cc8fdaee1eeaf05d8dd55ff11f111b815f673c58 Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11ui-log: ban strncpy()Christian Hesse Git upstream bans strncpy() with commit: banned.h: mark strncpy() as banned e488b7aba743d23b830d239dcc33d9ca0745a9ad Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11ui-log: ban strcpy()Christian Hesse Git upstream bans strcpy() with commit: automatically ban strcpy() c8af66ab8ad7cd78557f0f9f5ef6a52fd46ee6dd Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11parsing: ban sprintf()Christian Hesse Git upstream bans sprintf() with commit: banned.h: mark sprintf() as banned cc8fdaee1eeaf05d8dd55ff11f111b815f673c58 Signed-off-by: Christian Hesse <mail@eworm.de> 2018-09-11parsing: ban strncpy()Christian Hesse Git upstream bans strncpy() with commit: banned.h: mark strncpy() as banned e488b7aba743d23b830d239dcc33d9ca0745a9ad Signed-off-by: Christian Hesse <mail@eworm.de> 2018-08-28filters: generate anchor links from markdownChristian Hesse This makes the markdown filter generate anchor links for headings. Signed-off-by: Christian Hesse <mail@eworm.de> Tested-by: jean-christophe manciot <actionmystique@gmail.com> 2018-08-03Bump version.Jason A. Donenfeld Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2018-08-03clone: fix directory traversalJason A. Donenfeld This was introduced in the initial version of this code, way back when in 2008. $ curl http://127.0.0.1/cgit/repo/objects/?path=../../../../../../../../../etc/passwd root:x:0:0:root:/root:/bin/sh ... Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> Reported-by: Jann Horn <jannh@google.com> 2018-08-03config: record repo.snapshot-prefix in the per-repo configKonstantin Ryabitsev