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;
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;
// 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)
{
// 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
// 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