]> PatchyGit - patchyircd.git/commitdiff
improve NAMES
authorEgor <egor@patchysicp.xyz>
Fri, 6 May 2022 09:13:45 +0000 (12:13 +0300)
committerEgor <egor@patchysicp.xyz>
Fri, 6 May 2022 09:13:45 +0000 (12:13 +0300)
now it's almost complete, only missing +s chan mode

common.h
irc.c
irc.h
ircfmt.c
ircfmt.h

index ed89f98..5349cf2 100644 (file)
--- 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 (file)
--- 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 (file)
--- 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;
index 14b5c86..6e98ae6 100644 (file)
--- 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
index a9bd157..d7b4dd7 100644 (file)
--- 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