From: Egor Date: Fri, 6 May 2022 09:13:45 +0000 (+0300) Subject: improve NAMES X-Git-Url: https://git.patchysicp.xyz/?a=commitdiff_plain;h=3ce7dd5a67a94c7b7cfc0c588ef57b08135817c2;p=patchyircd.git improve NAMES now it's almost complete, only missing +s chan mode --- diff --git a/common.h b/common.h index ed89f98..5349cf2 100644 --- a/common.h +++ b/common.h @@ -41,6 +41,8 @@ struct channel { int member_count; char dmode; }; +#define is_chanop(chan, client) (trie_get(&(chan)->o, (client)->key)) +#define is_chanvoice(chan, client) (trie_get(&(chan)->v, (client)->key)) extern struct trie_node *client_map; extern struct trie_node *channel_map; extern struct client_data *clients[CLIENTS]; diff --git a/irc.c b/irc.c index 6228066..2acbedc 100644 --- a/irc.c +++ b/irc.c @@ -347,20 +347,25 @@ int processPacket(struct client_data *client, char *source, char *command, int a copy_strf(&databuf, ":%s 323 %s :End of /LIST\n", hostname, client->nick); sendbuf(client); } else if(strcmp(command, "NAMES") == 0) { - // TODO: actual channel support if (!is_registered(client)) return err_notregistered(client), sendbuf(client), 0; if (argc == 0) // FIXME: error message return 0; - struct trie_find *f = NULL; - if (trie_findfirst(&f, &client_map) == 1) - do { - struct client_data *cl = f->n->value; - copy_strf(&databuf, ":%s 353 %s = %s :%s\n", hostname, client->nick, args[0], cl->nick); + char *p = args[0]-1; + do { + char *channel = p+1; + p = strchr(channel, ','); + if (p) + *p = '\0'; + struct channel *chan = findChannel(channel); + if (chan) { + // TODO: check +s mode + channel_sendnames(client, chan); + } else { + rpl_endofnames(client, channel); sendbuf(client); - } while(trie_findnext(&f) == 1); - copy_strf(&databuf, ":%s 366 %s :End of /NAMES list\n", hostname, client->nick); - sendbuf(client); + } + } while (p); } else if(strcmp(command, "USERHOST") == 0) { if (!is_registered(client)) return err_notregistered(client), sendbuf(client), 0; @@ -525,15 +530,30 @@ void setNick(struct client_data *client, char* nickname) { void channel_sendtopic(struct client_data *client, struct channel *chan, int joining) { if (chan->topic) { - copy_strf(&databuf, ":%s 332 %s %s :%s\n", hostname, client->nick, chan->name, chan->topic); - sendbuf(client); - copy_strf(&databuf, ":%s 333 %s %s %s %u\n", hostname, client->nick, chan->name, chan->topic_who, (unsigned)chan->topic_when); - sendbuf(client); + rpl_topic(client, chan), sendbuf(client); + rpl_topicwhotime(client, chan), sendbuf(client); } else if (!joining) { - copy_strf(&databuf, ":%s 331 %s %s :No topic is set\n", hostname, client->nick, chan->name); - sendbuf(client); + rpl_notopic(client, chan), sendbuf(client); } } +void channel_sendnames(struct client_data *client, struct channel *chan) +{ + struct trie_find *f = NULL; + databuf.len = 0; + if (trie_findfirst(&f, &client_map) == 1) + do { + struct client_data *cl = f->n->value; + if (rpl_namreply(client, chan, cl)) { + sendbuf(client); + databuf.len = 0; + rpl_namreply(client, chan, cl); + } + } while(trie_findnext(&f) == 1); + if (rpl_namreply(client, chan, NULL)) + sendbuf(client); + rpl_endofnames(client, chan->name); + sendbuf(client); +} void channel_join(struct client_data *client, const char *channel, const char *chankey) { (void)chankey; @@ -584,21 +604,7 @@ void channel_join(struct client_data *client, const char *channel, const char *c // send topic channel_sendtopic(client, chan, 1); // send names - if (trie_findfirst(&f, &client_map) == 1) - do { - struct client_data *cl = f->n->value; - const char *prefix = NULL; - if (trie_get(&chan->o, cl->key)) - prefix = "@"; - else if (trie_get(&chan->v, cl->key)) - prefix = "+"; - else - prefix = ""; - copy_strf(&databuf, ":%s 353 %s = %s :%s%s\n", hostname, client->nick, chan->name, prefix, cl->nick); - sendbuf(client); - } while(trie_findnext(&f) == 1); - copy_strf(&databuf, ":%s 366 %s %s :End of /NAMES list\n", hostname, client->nick, chan->name); - sendbuf(client); + channel_sendnames(client, chan); } void channel_part(struct client_data *client, struct channel *chan, const char *reason) { diff --git a/irc.h b/irc.h index 45efa7d..95df9ce 100644 --- a/irc.h +++ b/irc.h @@ -13,6 +13,7 @@ void setNick(struct client_data *client, char* nickname); struct client_data *findClient(const char *nickname); struct channel *findChannel(const char *channel); void channel_sendtopic(struct client_data *client, struct channel *chan, int joining); +void channel_sendnames(struct client_data *client, struct channel *chan); void channel_join(struct client_data *client, const char *channel, const char *chankey); void channel_part(struct client_data *client, struct channel *chan, const char *reason); extern struct dynarr databuf; diff --git a/ircfmt.c b/ircfmt.c index 14b5c86..6e98ae6 100644 --- a/ircfmt.c +++ b/ircfmt.c @@ -141,9 +141,22 @@ void rpl_isupport(struct client_data *client) // 005 // 324 RPL_CHANNELMODEIS // 329 RPL_CREATIONTIME // 330 RPL_WHOISACCOUNT -// 331 RPL_NOTOPIC -// 332 RPL_TOPIC -// 333 RPL_TOPICWHOTIME +void rpl_notopic(struct client_data *client, struct channel *chan) // 331 +{ + copy_strf(&databuf, ":%s 331 %s %s :No topic is set\r\n", hostname, client->nick, + chan->name); +} +void rpl_topic(struct client_data *client, struct channel *chan) // 332 +{ + copy_strf(&databuf, ":%s 332 %s %s :%s\r\n", hostname, client->nick, + chan->name, chan->topic); +} +void rpl_topicwhotime(struct client_data *client, struct channel *chan) // 333 +{ + // FIXME: 64-bit time_t support + copy_strf(&databuf, ":%s 333 %s %s %s %u\r\n", hostname, client->nick, + chan->name, chan->topic_who, (unsigned)chan->topic_when); +} // 336 RPL_INVITELIST // 337 RPL_ENDOFINVITELIST // 338 RPL_WHOISACTUALLY @@ -154,7 +167,40 @@ void rpl_isupport(struct client_data *client) // 005 // 349 RPL_ENDOFEXCEPTLIST // 351 RPL_VERSION // 353 RPL_NAMREPLY -// 366 RPL_ENDOFNAMES +int rpl_namreply(struct client_data *client, struct channel *chan, struct client_data *cl) // 353 +{ + if (!cl) { + if (databuf.len) { + append_str(&databuf, "\r\n"); + return 1; + } else { + return 0; + } + } + const char *prefix = NULL; + if (is_chanop(chan, cl)) + prefix = "@"; + else if (is_chanvoice(chan, cl)) + prefix = "+"; + else + prefix = ""; + if (databuf.len == 0) { + // TODO: secret channel "@" + copy_strf(&databuf, ":%s 353 %s = %s :", hostname, client->nick, chan->name); + } else { + if (databuf.len + 1 + strlen(prefix) + strlen(cl->nick) > 510) { + append_str(&databuf, "\r\n"); + return 1; + } + append_str(&databuf, " "); + } + append_strf(&databuf, "%s%s", prefix, cl->nick); + return 0; +} +void rpl_endofnames(struct client_data *client, const char *channel) // 366 +{ + copy_strf(&databuf, ":%s 366 %s %s :End of /NAMES list\r\n", hostname, client->nick, channel); +} // 364 RPL_LINKS // 365 RPL_ENDOFLINKS // 367 RPL_BANLIST diff --git a/ircfmt.h b/ircfmt.h index a9bd157..d7b4dd7 100644 --- a/ircfmt.h +++ b/ircfmt.h @@ -57,9 +57,9 @@ void rpl_isupport(struct client_data *client); // 005 // 324 RPL_CHANNELMODEIS // 329 RPL_CREATIONTIME // 330 RPL_WHOISACCOUNT -// 331 RPL_NOTOPIC -// 332 RPL_TOPIC -// 333 RPL_TOPICWHOTIME +void rpl_notopic(struct client_data *client, struct channel *chan); // 331 +void rpl_topic(struct client_data *client, struct channel *chan); // 332 +void rpl_topicwhotime(struct client_data *client, struct channel *chan); // 333 // 336 RPL_INVITELIST // 337 RPL_ENDOFINVITELIST // 338 RPL_WHOISACTUALLY @@ -69,8 +69,8 @@ void rpl_isupport(struct client_data *client); // 005 // 348 RPL_EXCEPTLIST // 349 RPL_ENDOFEXCEPTLIST // 351 RPL_VERSION -// 353 RPL_NAMREPLY -// 366 RPL_ENDOFNAMES +int rpl_namreply(struct client_data *client, struct channel *chan, struct client_data *cl); // 353 +void rpl_endofnames(struct client_data *client, const char *channel); // 366 // 364 RPL_LINKS // 365 RPL_ENDOFLINKS // 367 RPL_BANLIST