diff options
author | June McEnroe <june@causal.agency> | 2019-10-26 04:57:33 -0400 |
---|---|---|
committer | June McEnroe <june@causal.agency> | 2019-10-26 04:57:33 -0400 |
commit | 648c5cc21484a4f0d9846f04bc47c1e35fa18234 (patch) | |
tree | 02847d4c25ec01c65ce3db9b0ab2cc5e61dbb568 | |
parent | Set AWAY when no clients are connected (diff) | |
download | pounce-648c5cc21484a4f0d9846f04bc47c1e35fa18234.tar.gz pounce-648c5cc21484a4f0d9846f04bc47c1e35fa18234.zip |
Track channel topics
-rw-r--r-- | bounce.c | 3 | ||||
-rw-r--r-- | bounce.h | 1 | ||||
-rw-r--r-- | pounce.1 | 7 | ||||
-rw-r--r-- | state.c | 75 |
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); } } |