about summary refs log tree commit diff
path: root/handle.c
diff options
context:
space:
mode:
Diffstat (limited to 'handle.c')
-rw-r--r--handle.c158
1 files changed, 57 insertions, 101 deletions
diff --git a/handle.c b/handle.c
index b8434c6..0cc7c04 100644
--- a/handle.c
+++ b/handle.c
@@ -32,7 +32,6 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <sysexits.h>
 #include <wchar.h>
 
 #include "chat.h"
@@ -83,7 +82,7 @@ static void require(struct Message *msg, bool origin, uint len) {
 	}
 	for (uint i = 0; i < len; ++i) {
 		if (msg->params[i]) continue;
-		errx(EX_PROTOCOL, "%s missing parameter %u", msg->cmd, 1 + i);
+		errx(1, "%s missing parameter %u", msg->cmd, 1 + i);
 	}
 }
 
@@ -162,7 +161,7 @@ static void handleErrorNicknameInUse(struct Message *msg) {
 static void handleErrorErroneousNickname(struct Message *msg) {
 	require(msg, false, 3);
 	if (!strcmp(self.nick, "*")) {
-		errx(EX_CONFIG, "%s: %s", msg->params[1], msg->params[2]);
+		errx(1, "%s: %s", msg->params[1], msg->params[2]);
 	} else {
 		handleErrorGeneric(msg);
 	}
@@ -193,7 +192,7 @@ static void handleCap(struct Message *msg) {
 		}
 		if (!(self.caps & CapSASL)) ircFormat("CAP END\r\n");
 	} else if (!strcmp(msg->params[1], "NAK")) {
-		errx(EX_CONFIG, "server does not support %s", msg->params[2]);
+		errx(1, "server does not support %s", msg->params[2]);
 	}
 }
 
@@ -237,7 +236,7 @@ static void handleAuthenticate(struct Message *msg) {
 	size_t userLen = strlen(self.plainUser);
 	size_t passLen = strlen(self.plainPass);
 	size_t len = 1 + userLen + 1 + passLen;
-	if (sizeof(buf) < len) errx(EX_USAGE, "SASL PLAIN is too long");
+	if (sizeof(buf) < len) errx(1, "SASL PLAIN is too long");
 	memcpy(&buf[1], self.plainUser, userLen);
 	memcpy(&buf[1 + userLen + 1], self.plainPass, passLen);
 
@@ -260,13 +259,13 @@ static void handleReplyLoggedIn(struct Message *msg) {
 
 static void handleErrorSASLFail(struct Message *msg) {
 	require(msg, false, 2);
-	errx(EX_CONFIG, "%s", msg->params[1]);
+	errx(1, "%s", msg->params[1]);
 }
 
 static void handleReplyWelcome(struct Message *msg) {
 	require(msg, false, 1);
 	set(&self.nick, msg->params[0]);
-	cacheInsert(true, Network, self.nick);
+	completePull(Network, self.nick, Default);
 	if (self.mode) ircFormat("MODE %s %s\r\n", self.nick, self.mode);
 	if (self.join) {
 		uint count = 1;
@@ -278,7 +277,7 @@ static void handleReplyWelcome(struct Message *msg) {
 		replies[ReplyTopicAuto] += count;
 		replies[ReplyNamesAuto] += count;
 	}
-	commandCache();
+	commandCompletion();
 	handleReplyGeneric(msg);
 }
 
@@ -315,7 +314,7 @@ static void handleReplyISupport(struct Message *msg) {
 			char *modes = strsep(&msg->params[i], ")");
 			char *prefixes = msg->params[i];
 			if (!modes || !prefixes || strlen(modes) != strlen(prefixes)) {
-				errx(EX_PROTOCOL, "invalid PREFIX value");
+				errx(1, "invalid PREFIX value");
 			}
 			set(&network.prefixModes, modes);
 			set(&network.prefixes, prefixes);
@@ -325,7 +324,7 @@ static void handleReplyISupport(struct Message *msg) {
 			char *setParam = strsep(&msg->params[i], ",");
 			char *channel = strsep(&msg->params[i], ",");
 			if (!list || !param || !setParam || !channel) {
-				errx(EX_PROTOCOL, "invalid CHANMODES value");
+				errx(1, "invalid CHANMODES value");
 			}
 			set(&network.listModes, list);
 			set(&network.paramModes, param);
@@ -372,13 +371,13 @@ static void handleJoin(struct Message *msg) {
 			set(&self.host, msg->host);
 		}
 		idColors[id] = hash(msg->params[0]);
-		cacheInsert(true, None, msg->params[0])->color = idColors[id];
+		completePull(None, msg->params[0], idColors[id]);
 		if (replies[ReplyJoin]) {
 			windowShow(windowFor(id));
 			replies[ReplyJoin]--;
 		}
 	}
-	cacheInsert(true, id, msg->nick)->color = hash(msg->user);
+	completePull(id, msg->nick, hash(msg->user));
 	if (msg->params[2] && !strcasecmp(msg->params[2], msg->nick)) {
 		msg->params[2] = NULL;
 	}
@@ -410,9 +409,9 @@ static void handlePart(struct Message *msg) {
 	require(msg, true, 1);
 	uint id = idFor(msg->params[0]);
 	if (!strcmp(msg->nick, self.nick)) {
-		cacheClear(id);
+		completeRemove(id, NULL);
 	}
-	cacheRemove(id, msg->nick);
+	completeRemove(id, msg->nick);
 	enum Heat heat = filterCheck(Cold, id, msg);
 	if (heat > Ice) urlScan(id, msg->nick, msg->params[1]);
 	uiFormat(
@@ -432,14 +431,14 @@ static void handleKick(struct Message *msg) {
 	require(msg, true, 2);
 	uint id = idFor(msg->params[0]);
 	bool kicked = !strcmp(msg->params[1], self.nick);
-	cacheInsert(true, id, msg->nick)->color = hash(msg->user);
+	completePull(id, msg->nick, hash(msg->user));
 	urlScan(id, msg->nick, msg->params[2]);
 	uiFormat(
 		id, (kicked ? Hot : Cold), tagTime(msg),
 		"%s\3%02d%s\17\tkicks \3%02d%s\3 out of \3%02d%s\3%s%s",
 		(kicked ? "\26" : ""),
 		hash(msg->user), msg->nick,
-		cacheGet(id, msg->params[1])->color, msg->params[1],
+		completeColor(id, msg->params[1]), msg->params[1],
 		hash(msg->params[0]), msg->params[0],
 		(msg->params[2] ? ": " : ""), (msg->params[2] ?: "")
 	);
@@ -448,8 +447,8 @@ static void handleKick(struct Message *msg) {
 		msg->nick, msg->params[1], msg->params[0],
 		(msg->params[2] ? ": " : ""), (msg->params[2] ?: "")
 	);
-	cacheRemove(id, msg->params[1]);
-	if (kicked) cacheClear(id);
+	completeRemove(id, msg->params[1]);
+	if (kicked) completeRemove(id, NULL);
 }
 
 static void handleNick(struct Message *msg) {
@@ -459,7 +458,7 @@ static void handleNick(struct Message *msg) {
 		inputUpdate();
 	}
 	struct Cursor curs = {0};
-	for (uint id; (id = cacheID(&curs, msg->nick));) {
+	for (uint id; (id = completeEachID(&curs, msg->nick));) {
 		if (!strcmp(idNames[id], msg->nick)) {
 			set(&idNames[id], msg->params[0]);
 		}
@@ -474,13 +473,13 @@ static void handleNick(struct Message *msg) {
 			msg->nick, msg->params[0]
 		);
 	}
-	cacheReplace(true, msg->nick, msg->params[0]);
+	completeReplace(msg->nick, msg->params[0]);
 }
 
 static void handleSetname(struct Message *msg) {
 	require(msg, true, 1);
 	struct Cursor curs = {0};
-	for (uint id; (id = cacheID(&curs, msg->nick));) {
+	for (uint id; (id = completeEachID(&curs, msg->nick));) {
 		uiFormat(
 			id, filterCheck(Cold, id, msg), tagTime(msg),
 			"\3%02d%s\3\tis now known as \3%02d%s\3 (%s\17)",
@@ -493,7 +492,7 @@ static void handleSetname(struct Message *msg) {
 static void handleQuit(struct Message *msg) {
 	require(msg, true, 0);
 	struct Cursor curs = {0};
-	for (uint id; (id = cacheID(&curs, msg->nick));) {
+	for (uint id; (id = completeEachID(&curs, msg->nick));) {
 		enum Heat heat = filterCheck(Cold, id, msg);
 		if (heat > Ice) urlScan(id, msg->nick, msg->params[0]);
 		uiFormat(
@@ -509,7 +508,7 @@ static void handleQuit(struct Message *msg) {
 			(msg->params[0] ? ": " : ""), (msg->params[0] ?: "")
 		);
 	}
-	cacheRemove(None, msg->nick);
+	completeRemove(None, msg->nick);
 }
 
 static void handleInvite(struct Message *msg) {
@@ -555,17 +554,11 @@ static void handleErrorUserOnChannel(struct Message *msg) {
 	uiFormat(
 		id, Warm, tagTime(msg),
 		"\3%02d%s\3 is already in \3%02d%s\3",
-		cacheGet(id, msg->params[1])->color, msg->params[1],
+		completeColor(id, msg->params[1]), msg->params[1],
 		hash(msg->params[2]), msg->params[2]
 	);
 }
 
-static uint prefixBit(char p) {
-	char *s = strchr(network.prefixes, p);
-	if (!s) return 0;
-	return 1 << (s - network.prefixes);
-}
-
 static void handleReplyNames(struct Message *msg) {
 	require(msg, false, 4);
 	uint id = idFor(msg->params[2]);
@@ -581,9 +574,8 @@ static void handleReplyNames(struct Message *msg) {
 		for (char *p = prefixes; p < nick; ++p) {
 			bits |= prefixBit(*p);
 		}
-		struct Entry *entry = cacheInsert(false, id, nick);
-		if (user) entry->color = color;
-		entry->prefixBits = bits;
+		completePush(id, nick, color);
+		*completeBits(id, nick) = bits;
 		if (!replies[ReplyNames] && !replies[ReplyNamesAuto]) continue;
 		ptr = seprintf(
 			ptr, end, "%s\3%02d%s\3", (ptr > buf ? ", " : ""), color, prefixes
@@ -606,41 +598,6 @@ static void handleReplyEndOfNames(struct Message *msg) {
 	}
 }
 
-static struct {
-	char buf[1024];
-	char *ptr;
-	char *end;
-} who = {
-	.ptr = who.buf,
-	.end = &who.buf[sizeof(who.buf)],
-};
-
-static void handleReplyWho(struct Message *msg) {
-	require(msg, false, 7);
-	if (who.ptr == who.buf) {
-		who.ptr = seprintf(
-			who.ptr, who.end, "The council of \3%02d%s\3 are ",
-			hash(msg->params[1]), msg->params[1]
-		);
-	}
-	char *prefixes = &msg->params[6][1];
-	if (prefixes[0] == '*') prefixes++;
-	prefixes[strspn(prefixes, network.prefixes)] = '\0';
-	if (!prefixes[0] || prefixes[0] == '+') return;
-	who.ptr = seprintf(
-		who.ptr, who.end, "%s\3%02d%s%s\3%s",
-		(who.ptr[-1] == ' ' ? "" : ", "),
-		hash(msg->params[2]), prefixes, msg->params[5],
-		(msg->params[6][0] == 'H' ? "" : " (away)")
-	);
-}
-
-static void handleReplyEndOfWho(struct Message *msg) {
-	require(msg, false, 2);
-	uiWrite(idFor(msg->params[1]), Warm, tagTime(msg), who.buf);
-	who.ptr = who.buf;
-}
-
 static void handleReplyNoTopic(struct Message *msg) {
 	require(msg, false, 2);
 	uiFormat(
@@ -650,24 +607,24 @@ static void handleReplyNoTopic(struct Message *msg) {
 	);
 }
 
-static void topicCache(uint id, const char *topic) {
+static void topicComplete(uint id, const char *topic) {
 	char buf[512];
 	struct Cursor curs = {0};
-	const char *prev = cacheComplete(&curs, id, "/topic ");
+	const char *prev = completePrefix(&curs, id, "/topic ");
 	if (prev) {
 		snprintf(buf, sizeof(buf), "%s", prev);
-		cacheRemove(id, buf);
+		completeRemove(id, buf);
 	}
 	if (topic) {
 		snprintf(buf, sizeof(buf), "/topic %s", topic);
-		cacheInsert(false, id, buf);
+		completePush(id, buf, Default);
 	}
 }
 
 static void handleReplyTopic(struct Message *msg) {
 	require(msg, false, 3);
 	uint id = idFor(msg->params[1]);
-	topicCache(id, msg->params[2]);
+	topicComplete(id, msg->params[2]);
 	if (!replies[ReplyTopic] && !replies[ReplyTopicAuto]) return;
 	urlScan(id, NULL, msg->params[2]);
 	uiFormat(
@@ -718,7 +675,7 @@ static void handleTopic(struct Message *msg) {
 	require(msg, true, 2);
 	uint id = idFor(msg->params[0]);
 	if (!msg->params[1][0]) {
-		topicCache(id, NULL);
+		topicComplete(id, NULL);
 		uiFormat(
 			id, Warm, tagTime(msg),
 			"\3%02d%s\3\tremoves the sign in \3%02d%s\3",
@@ -732,7 +689,7 @@ static void handleTopic(struct Message *msg) {
 	}
 
 	struct Cursor curs = {0};
-	const char *prev = cacheComplete(&curs, id, "/topic ");
+	const char *prev = completePrefix(&curs, id, "/topic ");
 	if (prev) {
 		prev += 7;
 	} else {
@@ -782,7 +739,7 @@ log:
 		id, tagTime(msg), "%s places a new sign in %s: %s",
 		msg->nick, msg->params[0], msg->params[1]
 	);
-	topicCache(id, msg->params[1]);
+	topicComplete(id, msg->params[1]);
 	urlScan(id, msg->nick, msg->params[1]);
 }
 
@@ -899,22 +856,23 @@ static void handleMode(struct Message *msg) {
 
 		if (strchr(network.prefixModes, *ch)) {
 			if (i >= ParamCap || !msg->params[i]) {
-				errx(EX_PROTOCOL, "MODE missing %s parameter", mode);
+				errx(1, "MODE missing %s parameter", mode);
 			}
 			char *nick = msg->params[i++];
 			char prefix = network.prefixes[
 				strchr(network.prefixModes, *ch) - network.prefixModes
 			];
+			completePush(id, nick, Default);
 			if (set) {
-				cacheInsert(false, id, nick)->prefixBits |= prefixBit(prefix);
+				*completeBits(id, nick) |= prefixBit(prefix);
 			} else {
-				cacheInsert(false, id, nick)->prefixBits &= ~prefixBit(prefix);
+				*completeBits(id, nick) &= ~prefixBit(prefix);
 			}
 			uiFormat(
 				id, Cold, tagTime(msg),
 				"\3%02d%s\3\t%s \3%02d%c%s\3 %s%s in \3%02d%s\3",
 				hash(msg->user), msg->nick, verb,
-				cacheGet(id, nick)->color, prefix, nick,
+				completeColor(id, nick), prefix, nick,
 				mode, name, hash(msg->params[0]), msg->params[0]
 			);
 			logFormat(
@@ -925,7 +883,7 @@ static void handleMode(struct Message *msg) {
 
 		if (strchr(network.listModes, *ch)) {
 			if (i >= ParamCap || !msg->params[i]) {
-				errx(EX_PROTOCOL, "MODE missing %s parameter", mode);
+				errx(1, "MODE missing %s parameter", mode);
 			}
 			char *mask = msg->params[i++];
 			if (*ch == 'b') {
@@ -958,7 +916,7 @@ static void handleMode(struct Message *msg) {
 
 		if (strchr(network.paramModes, *ch)) {
 			if (i >= ParamCap || !msg->params[i]) {
-				errx(EX_PROTOCOL, "MODE missing %s parameter", mode);
+				errx(1, "MODE missing %s parameter", mode);
 			}
 			char *param = msg->params[i++];
 			uiFormat(
@@ -975,7 +933,7 @@ static void handleMode(struct Message *msg) {
 
 		if (strchr(network.setParamModes, *ch) && set) {
 			if (i >= ParamCap || !msg->params[i]) {
-				errx(EX_PROTOCOL, "MODE missing %s parameter", mode);
+				errx(1, "MODE missing %s parameter", mode);
 			}
 			char *param = msg->params[i++];
 			uiFormat(
@@ -1052,7 +1010,7 @@ static void handleReplyBanList(struct Message *msg) {
 			id, Warm, tagTime(msg),
 			"Banned from \3%02d%s\3 since %s by \3%02d%s\3: %s",
 			hash(msg->params[1]), msg->params[1],
-			since, cacheGet(id, msg->params[3])->color, msg->params[3],
+			since, completeColor(id, msg->params[3]), msg->params[3],
 			msg->params[2]
 		);
 	} else {
@@ -1075,7 +1033,7 @@ static void onList(const char *list, struct Message *msg) {
 			id, Warm, tagTime(msg),
 			"On the \3%02d%s\3 %s list since %s by \3%02d%s\3: %s",
 			hash(msg->params[1]), msg->params[1], list,
-			since, cacheGet(id, msg->params[3])->color, msg->params[3],
+			since, completeColor(id, msg->params[3]), msg->params[3],
 			msg->params[2]
 		);
 	} else {
@@ -1096,19 +1054,19 @@ static void handleReplyInviteList(struct Message *msg) {
 }
 
 static void handleReplyList(struct Message *msg) {
-	require(msg, false, 4);
+	require(msg, false, 3);
 	uiFormat(
 		Network, Warm, tagTime(msg),
 		"In \3%02d%s\3 are %ld under the banner: %s",
 		hash(msg->params[1]), msg->params[1],
 		strtol(msg->params[2], NULL, 10),
-		msg->params[3]
+		(msg->params[3] ?: "")
 	);
 }
 
 static void handleReplyWhoisUser(struct Message *msg) {
 	require(msg, false, 6);
-	cacheInsert(true, Network, msg->params[1])->color = hash(msg->params[2]);
+	completePull(Network, msg->params[1], hash(msg->params[2]));
 	uiFormat(
 		Network, Warm, tagTime(msg),
 		"\3%02d%s\3\tis %s!%s@%s (%s\17)",
@@ -1123,7 +1081,7 @@ static void handleReplyWhoisServer(struct Message *msg) {
 	uiFormat(
 		Network, Warm, tagTime(msg),
 		"\3%02d%s\3\t%s connected to %s (%s)",
-		cacheGet(Network, msg->params[1])->color, msg->params[1],
+		completeColor(Network, msg->params[1]), msg->params[1],
 		(replies[ReplyWhowas] ? "was" : "is"), msg->params[2], msg->params[3]
 	);
 }
@@ -1147,7 +1105,7 @@ static void handleReplyWhoisIdle(struct Message *msg) {
 	uiFormat(
 		Network, Warm, tagTime(msg),
 		"\3%02d%s\3\tis idle for %lu %s%s%s%s",
-		cacheGet(Network, msg->params[1])->color, msg->params[1],
+		completeColor(Network, msg->params[1]), msg->params[1],
 		idle, unit, (idle != 1 ? "s" : ""),
 		(msg->params[3] ? ", signed on " : ""), (msg->params[3] ? signon : "")
 	);
@@ -1169,7 +1127,7 @@ static void handleReplyWhoisChannels(struct Message *msg) {
 	uiFormat(
 		Network, Warm, tagTime(msg),
 		"\3%02d%s\3\tis in %s",
-		cacheGet(Network, msg->params[1])->color, msg->params[1], buf
+		completeColor(Network, msg->params[1]), msg->params[1], buf
 	);
 }
 
@@ -1183,7 +1141,7 @@ static void handleReplyWhoisGeneric(struct Message *msg) {
 	uiFormat(
 		Network, Warm, tagTime(msg),
 		"\3%02d%s\3\t%s%s%s",
-		cacheGet(Network, msg->params[1])->color, msg->params[1],
+		completeColor(Network, msg->params[1]), msg->params[1],
 		msg->params[2], (msg->params[3] ? " " : ""), (msg->params[3] ?: "")
 	);
 }
@@ -1191,13 +1149,13 @@ static void handleReplyWhoisGeneric(struct Message *msg) {
 static void handleReplyEndOfWhois(struct Message *msg) {
 	require(msg, false, 2);
 	if (strcmp(msg->params[1], self.nick)) {
-		cacheRemove(Network, msg->params[1]);
+		completeRemove(Network, msg->params[1]);
 	}
 }
 
 static void handleReplyWhowasUser(struct Message *msg) {
 	require(msg, false, 6);
-	cacheInsert(true, Network, msg->params[1])->color = hash(msg->params[2]);
+	completePull(Network, msg->params[1], hash(msg->params[2]));
 	uiFormat(
 		Network, Warm, tagTime(msg),
 		"\3%02d%s\3\twas %s!%s@%s (%s)",
@@ -1209,7 +1167,7 @@ static void handleReplyWhowasUser(struct Message *msg) {
 static void handleReplyEndOfWhowas(struct Message *msg) {
 	require(msg, false, 2);
 	if (strcmp(msg->params[1], self.nick)) {
-		cacheRemove(Network, msg->params[1]);
+		completeRemove(Network, msg->params[1]);
 	}
 }
 
@@ -1220,7 +1178,7 @@ static void handleReplyAway(struct Message *msg) {
 	uiFormat(
 		id, (id == Network ? Warm : Cold), tagTime(msg),
 		"\3%02d%s\3\tis away: %s",
-		cacheGet(id, msg->params[1])->color, msg->params[1], msg->params[2]
+		completeColor(id, msg->params[1]), msg->params[1], msg->params[2]
 	);
 	logFormat(
 		id, tagTime(msg), "%s is away: %s",
@@ -1291,7 +1249,7 @@ static char *colorMentions(char *ptr, char *end, uint id, const char *msg) {
 
 		size_t len = strcspn(msg, ",:<> ");
 		char *p = seprintf(ptr, end, "%.*s", (int)len, msg);
-		enum Color color = cacheGet(id, ptr)->color;
+		enum Color color = completeColor(id, ptr);
 		if (color != Default) {
 			ptr = seprintf(ptr, end, "\3%02d%.*s\3", color, (int)len, msg);
 		} else {
@@ -1331,7 +1289,7 @@ static void handlePrivmsg(struct Message *msg) {
 	heat = filterCheck(heat, id, msg);
 	if (heat > Warm && !mine && !query) highlight = true;
 	if (!notice && !mine && heat > Ice) {
-		cacheInsert(true, id, msg->nick)->color = hash(msg->user);
+		completePull(id, msg->nick, hash(msg->user));
 	}
 	if (heat > Ice) urlScan(id, msg->nick, msg->params[1]);
 
@@ -1378,7 +1336,7 @@ static void handlePing(struct Message *msg) {
 
 static void handleError(struct Message *msg) {
 	require(msg, false, 1);
-	errx(EX_UNAVAILABLE, "%s", msg->params[0]);
+	errx(69, "%s", msg->params[0]);
 }
 
 static const struct Handler {
@@ -1398,7 +1356,6 @@ static const struct Handler {
 	{ "312", 0, handleReplyWhoisServer },
 	{ "313", +ReplyWhois, handleReplyWhoisGeneric },
 	{ "314", +ReplyWhowas, handleReplyWhowasUser },
-	{ "315", -ReplyWho, handleReplyEndOfWho },
 	{ "317", +ReplyWhois, handleReplyWhoisIdle },
 	{ "318", -ReplyWhois, handleReplyEndOfWhois },
 	{ "319", +ReplyWhois, handleReplyWhoisChannels },
@@ -1416,7 +1373,6 @@ static const struct Handler {
 	{ "347", -ReplyInvex, NULL },
 	{ "348", +ReplyExcepts, handleReplyExceptList },
 	{ "349", -ReplyExcepts, NULL },
-	{ "352", +ReplyWho, handleReplyWho },
 	{ "353", 0, handleReplyNames },
 	{ "366", 0, handleReplyEndOfNames },
 	{ "367", +ReplyBan, handleReplyBanList },