summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2019-10-26 04:57:33 -0400
committerJune McEnroe <june@causal.agency>2019-10-26 04:57:33 -0400
commit648c5cc21484a4f0d9846f04bc47c1e35fa18234 (patch)
tree02847d4c25ec01c65ce3db9b0ab2cc5e61dbb568
parentSet AWAY when no clients are connected (diff)
downloadpounce-648c5cc21484a4f0d9846f04bc47c1e35fa18234.tar.gz
pounce-648c5cc21484a4f0d9846f04bc47c1e35fa18234.zip
Track channel topics
Diffstat (limited to '')
-rw-r--r--bounce.c3
-rw-r--r--bounce.h1
-rw-r--r--pounce.17
-rw-r--r--state.c75
4 files changed, 58 insertions, 28 deletions
diff --git a/bounce.c b/bounce.c
index 648a17b..8d9a4b5 100644
--- a/bounce.c
+++ b/bounce.c
@@ -94,7 +94,7 @@ int main(int argc, char *argv[]) {
 	const char *away = "pounced :3";
 
 	int opt;
-	while (0 < (opt = getopt(argc, argv, "A:C:H:K:NTP:W:a:h:j:n:p:r:u:vw:"))) {
+	while (0 < (opt = getopt(argc, argv, "A:C:H:K:NP:W:a:h:j:n:p:r:u:vw:"))) {
 		switch (opt) {
 			break; case 'A': away = optarg;
 			break; case 'C': strlcpy(certPath, optarg, sizeof(certPath));
@@ -102,7 +102,6 @@ int main(int argc, char *argv[]) {
 			break; case 'K': strlcpy(privPath, optarg, sizeof(privPath));
 			break; case 'N': stateJoinNames = true;
 			break; case 'P': localPort = optarg;
-			break; case 'T': stateJoinTopic = true;
 			break; case 'W': clientPass = sensitive(optarg);
 			break; case 'a': auth = sensitive(optarg);
 			break; case 'h': host = optarg;
diff --git a/bounce.h b/bounce.h
index 4945931..26e62df 100644
--- a/bounce.h
+++ b/bounce.h
@@ -88,7 +88,6 @@ size_t clientDiff(const struct Client *client);
 void clientConsume(struct Client *client);
 
 bool stateJoinNames;
-bool stateJoinTopic;
 bool stateReady(void);
 void stateParse(char *line);
 void stateSync(struct Client *client);
diff --git a/pounce.1 b/pounce.1
index 95e554b..b76d819 100644
--- a/pounce.1
+++ b/pounce.1
@@ -8,7 +8,7 @@
 .
 .Sh SYNOPSIS
 .Nm
-.Op Fl NTv
+.Op Fl Nv
 .Op Fl A Ar away
 .Op Fl C Ar cert
 .Op Fl H Ar host
@@ -80,11 +80,6 @@ Bind to local
 .Ar port .
 The default port is 6697.
 .
-.It Fl T
-Request
-.Ql TOPIC
-for each channel when a client connects.
-.
 .It Fl W Ar pass
 Require the password
 .Ar pass
diff --git a/state.c b/state.c
index 02eaf72..a5bdaee 100644
--- a/state.c
+++ b/state.c
@@ -43,28 +43,45 @@ static void set(char **field, const char *value) {
 	if (!*field) err(EX_OSERR, "strdup");
 }
 
+struct Channel {
+	char *name;
+	char *topic;
+};
+
 static struct {
-	char **names;
+	struct Channel *ptr;
 	size_t cap, len;
-} chan;
+} chans;
 
 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");
+	if (chans.len == chans.cap) {
+		chans.cap = (chans.cap ? chans.cap * 2 : 8);
+		chans.ptr = realloc(chans.ptr, sizeof(*chans.ptr) * chans.cap);
+		if (!chans.ptr) err(EX_OSERR, "realloc");
+	}
+	struct Channel *chan = &chans.ptr[chans.len++];
+	chan->name = strdup(name);
+	if (!chan->name) err(EX_OSERR, "strdup");
+	chan->topic = NULL;
+}
+
+static void chanTopic(const char *name, const char *topic) {
+	for (size_t i = 0; i < chans.len; ++i) {
+		if (strcmp(chans.ptr[i].name, name)) continue;
+		free(chans.ptr[i].topic);
+		chans.ptr[i].topic = strdup(topic);
+		if (!chans.ptr[i].topic) err(EX_OSERR, "strdup");
+		break;
 	}
-	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;
+	for (size_t i = 0; i < chans.len; ++i) {
+		if (strcmp(chans.ptr[i].name, name)) continue;
+		free(chans.ptr[i].name);
+		free(chans.ptr[i].topic);
+		chans.ptr[i] = chans.ptr[--chans.len];
+		break;
 	}
 }
 
@@ -179,6 +196,18 @@ static void handleKick(struct Message *msg) {
 	}
 }
 
+static void handleTopic(struct Message *msg) {
+	if (!msg->params[0]) errx(EX_PROTOCOL, "TOPIC without channel");
+	if (!msg->params[1]) errx(EX_PROTOCOL, "TOPIC without topic");
+	chanTopic(msg->params[0], msg->params[1]);
+}
+
+static void handleReplyTopic(struct Message *msg) {
+	if (!msg->params[1]) errx(EX_PROTOCOL, "RPL_TOPIC without channel");
+	if (!msg->params[2]) errx(EX_PROTOCOL, "RPL_TOPIC without topic");
+	chanTopic(msg->params[1], msg->params[2]);
+}
+
 static void handleError(struct Message *msg) {
 	errx(EX_UNAVAILABLE, "%s", msg->params[0]);
 }
@@ -192,12 +221,14 @@ static const struct {
 	{ "003", handleReplyCreated },
 	{ "004", handleReplyMyInfo },
 	{ "005", handleReplyISupport },
+	{ "332", handleReplyTopic },
 	{ "CAP", handleCap },
 	{ "ERROR", handleError },
 	{ "JOIN", handleJoin },
 	{ "KICK", handleKick },
 	{ "NICK", handleNick },
 	{ "PART", handlePart },
+	{ "TOPIC", handleTopic },
 };
 
 void stateParse(char *line) {
@@ -260,10 +291,16 @@ void stateSync(struct Client *client) {
 		clientFormat(client, " :are supported by this server\r\n");
 	}
 
-	if (chan.len) assert(self.origin);
-	for (size_t i = 0; i < chan.len; ++i) {
-		clientFormat(client, ":%s JOIN %s\r\n", self.origin, chan.names[i]);
-		if (stateJoinTopic) serverFormat("TOPIC %s\r\n", chan.names[i]);
-		if (stateJoinNames) serverFormat("NAMES %s\r\n", chan.names[i]);
+	if (chans.len) assert(self.origin);
+	for (size_t i = 0; i < chans.len; ++i) {
+		const struct Channel *chan = &chans.ptr[i];
+		clientFormat(client, ":%s JOIN %s\r\n", self.origin, chan->name);
+		if (chan->topic) {
+			clientFormat(
+				client, ":%s 332 %s %s :%s\r\n",
+				Origin, self.nick, chan->name, chan->topic
+			);
+		}
+		if (stateJoinNames) serverFormat("NAMES %s\r\n", chan->name);
 	}
 }
ry commit whenever we want to show a commit. The drawback is that the "Log" link in the top bar of such a page links to the log limited by the old name, so it will only show pre-rename commits. I consider this a reasonable trade-off since the "Back" button still works and the log matches the path displayed in the top bar. Since following renames requires running diff on every commit we consider, I've added a knob to the configuration file to globally enable/disable this feature. Note that we may consider a large number of commits the revision walking machinery no longer performs any path limitation so we have to examine every commit until we find a page full of commits that affect the target path or something related to it. Suggested-by: René Neumann <necoro@necoro.eu> Signed-off-by: John Keeping <john@keeping.me.uk> 2015-08-12shared: make cgit_diff_tree_cb publicJohn Keeping This will allow us to use this nice wrapper function elsewhere, avoiding dealing with the diff queue when we only need to inspect a filepair. Signed-off-by: John Keeping <john@keeping.me.uk> 2015-08-12t0110: Chain together using &&Jason A. Donenfeld 2015-08-12about: always ensure page has a trailing slashJason A. Donenfeld Otherwise we can't easily embed links to other /about/ pages. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com> 2015-08-12filters: apply HTML escapingLazaros Koromilas http://www.w3.org/International/questions/qa-escapes#use 2015-08-12git: update to v2.5.0Christian Hesse Update to git version v2.5.0. * Upstream commit 5455ee0573a22bb793a7083d593ae1ace909cd4c (Merge branch 'bc/object-id') changed API: for_each_ref() callback functions were taught to name the objects not with "unsigned char sha1[20]" but with "struct object_id". * Upstream commit dcf692625ac569fefbe52269061230f4fde10e47 (path.c: make get_pathname() call sites return const char *) Signed-off-by: Christian Hesse <mail@eworm.de> 2015-08-12Fix processing of repo.hide and repo.ignoreDaniel Reichelt