]> arthur.barton.de Git - ngircd-alex.git/blobdiff - src/ngircd/irc-info.c
Fix NAMES/WHO response when client has multi-prefix
[ngircd-alex.git] / src / ngircd / irc-info.c
index f5139d07ebed78c68953bc56b19ed04424b9c884..4909a96a063a3a9940be0e52d9b9e070925a28c9 100644 (file)
@@ -117,7 +117,7 @@ IRC_INFO(CLIENT * Client, REQUEST * Req)
                target = Client_Search(Req->argv[0]);
        else
                target = Client_ThisServer();
-       
+
        /* Make sure that the target is a server */
        if (target && Client_Type(target) != CLIENT_SERVER)
                target = Client_Introducer(target);
@@ -807,22 +807,48 @@ who_flags_status(const char *client_modes)
 }
 
 
-static const char *
-who_flags_qualifier(CLIENT *Client, const char *chan_user_modes)
+/**
+ * Return channel user mode prefix(es).
+ *
+ * @param Client The client requesting the mode prefixes.
+ * @param chan_user_modes String with channel user modes.
+ * @param str String buffer to which the prefix(es) will be appended.
+ * @param len Size of "str" buffer.
+ * @return Pointer to "str".
+ */
+static char *
+who_flags_qualifier(CLIENT *Client, const char *chan_user_modes,
+                   char *str, size_t len)
 {
        assert(Client != NULL);
 
        if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
-               if (strchr(chan_user_modes, 'o') &&
-                   strchr(chan_user_modes, 'v'))
-                       return "@+";
+               if (strchr(chan_user_modes, 'q'))
+                       strlcat(str, "~", len);
+               if (strchr(chan_user_modes, 'a'))
+                       strlcat(str, "&", len);
+               if (strchr(chan_user_modes, 'o'))
+                       strlcat(str, "@", len);
+               if (strchr(chan_user_modes, 'h'))
+                       strlcat(str, "%", len);
+               if (strchr(chan_user_modes, 'v'))
+                       strlcat(str, "+", len);
+
+               return str;
        }
 
-       if (strchr(chan_user_modes, 'o'))
-               return "@";
+       if (strchr(chan_user_modes, 'q'))
+               strlcat(str, "~", len);
+       else if (strchr(chan_user_modes, 'a'))
+               strlcat(str, "&", len);
+       else if (strchr(chan_user_modes, 'o'))
+               strlcat(str, "@", len);
+       else if (strchr(chan_user_modes, 'h'))
+               strlcat(str, "%", len);
        else if (strchr(chan_user_modes, 'v'))
-               return "+";
-       return "";
+               strlcat(str, "+", len);
+
+       return str;
 }
 
 
@@ -840,14 +866,15 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
        bool is_visible, is_member, is_ircop;
        CL2CHAN *cl2chan;
        const char *client_modes;
-       const char *chan_user_modes;
-       char flags[8];
+       char flags[10];
        CLIENT *c;
        int count = 0;
 
        assert( Client != NULL );
        assert( Chan != NULL );
 
+       IRC_SetPenalty(Client, 1);
+
        is_member = Channel_IsMemberOf(Chan, Client);
 
        /* Secret channel? */
@@ -866,16 +893,12 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 
                is_visible = strchr(client_modes, 'i') == NULL;
                if (is_member || is_visible) {
-                       if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO"))
-                               break;
-
                        strcpy(flags, who_flags_status(client_modes));
                        if (is_ircop)
                                strlcat(flags, "*", sizeof(flags));
 
-                       chan_user_modes = Channel_UserModes(Chan, c);
-                       strlcat(flags, who_flags_qualifier(c, chan_user_modes),
-                               sizeof(flags));
+                       who_flags_qualifier(Client, Channel_UserModes(Chan, c),
+                                           flags, sizeof(flags));
 
                        if (!write_whoreply(Client, c, Channel_Name(Chan),
                                            flags))
@@ -883,6 +906,11 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
                        count++;
                }
        }
+
+       /* If there are a lot of clients, augment penalty a bit */
+       if (count > MAX_RPL_WHO)
+               IRC_SetPenalty(Client, 1);
+
        return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
                                  Channel_Name(Chan));
 }
@@ -911,6 +939,7 @@ IRC_WHO_Mask(CLIENT *Client, char *Mask, bool OnlyOps)
        if (Mask)
                ngt_LowerStr(Mask);
 
+       IRC_SetPenalty(Client, 3);
        for (c = Client_First(); c != NULL; c = Client_Next(c)) {
                if (Client_Type(c) != CLIENT_USER)
                        continue;
@@ -1014,13 +1043,11 @@ IRC_WHO(CLIENT *Client, REQUEST *Req)
                chan = Channel_Search(Req->argv[0]);
                if (chan) {
                        /* Members of a channel have been requested */
-                       IRC_SetPenalty(Client, 1);
                        return IRC_WHO_Channel(Client, chan, only_ops);
                }
                if (strcmp(Req->argv[0], "0") != 0) {
                        /* A mask has been given. But please note this RFC
                         * stupidity: "0" is same as no arguments ... */
-                       IRC_SetPenalty(Client, 3);
                        return IRC_WHO_Mask(Client, Req->argv[0], only_ops);
                }
        }
@@ -1087,8 +1114,8 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
                if (str[strlen(str) - 1] != ':')
                        strlcat(str, " ", sizeof(str));
 
-               strlcat(str, who_flags_qualifier(c, Channel_UserModes(chan, c)),
-                                                sizeof(str));
+               who_flags_qualifier(Client, Channel_UserModes(chan, c),
+                                   str, sizeof(str));
                strlcat(str, Channel_Name(chan), sizeof(str));
 
                if (strlen(str) > (LINE_LEN - CHANNEL_NAME_LEN - 4)) {
@@ -1462,7 +1489,7 @@ IRC_Send_LUSERS(CLIENT *Client)
                        Conn_CountMax(), Conn_CountAccepted()))
                return DISCONNECTED;
 #endif
-       
+
        return CONNECTED;
 } /* IRC_Send_LUSERS */
 
@@ -1483,7 +1510,15 @@ Show_MOTD_Sendline(CLIENT *Client, const char *msg)
 static bool
 Show_MOTD_End(CLIENT *Client)
 {
-       return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
+       if (!IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG, Client_ID(Client)))
+               return DISCONNECTED;
+
+       if (*Conf_CloakHost)
+               return IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
+                                         Client_ID(Client),
+                                         Client_Hostname(Client));
+
+       return CONNECTED;
 }
 
 #ifdef SSL_SUPPORT
@@ -1584,16 +1619,9 @@ IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
                if (is_member || is_visible) {
                        if (str[strlen(str) - 1] != ':')
                                strlcat(str, " ", sizeof(str));
-                       if (Client_Cap(cl) & CLIENT_CAP_MULTI_PREFIX) {
-                               if (strchr(Channel_UserModes(Chan, cl), 'o') &&
-                                   strchr(Channel_UserModes(Chan, cl), 'v'))
-                                       strlcat(str, "@+", sizeof(str));
-                       } else {
-                               if (strchr(Channel_UserModes(Chan, cl), 'o'))
-                                       strlcat(str, "@", sizeof(str));
-                               else if (strchr(Channel_UserModes(Chan, cl), 'v'))
-                                       strlcat(str, "+", sizeof(str));
-                       }
+
+                       who_flags_qualifier(Client, Channel_UserModes(Chan, cl),
+                                           str, sizeof(str));
                        strlcat(str, Client_ID(cl), sizeof(str));
 
                        if (strlen(str) > (LINE_LEN - CLIENT_NICK_LEN - 4)) {