#include "parse.h"
#include "irc.h"
#include "irc-write.h"
+#include "client-cap.h"
#include "exp.h"
#include "irc-info.h"
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);
}
-static const char *
-who_flags_qualifier(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)
{
- if (strchr(chan_user_modes, 'o'))
- return "@";
+ assert(Client != NULL);
+
+ if (Client_Cap(Client) & CLIENT_CAP_MULTI_PREFIX) {
+ 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, '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;
}
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? */
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(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))
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));
}
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;
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);
}
}
if (str[strlen(str) - 1] != ':')
strlcat(str, " ", sizeof(str));
- strlcat(str, who_flags_qualifier(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)) {
Client_ID(from), Client_ID(c)))
return DISCONNECTED;
+ /* IRC-Bot? */
+ if (Client_HasMode(c, 'B') &&
+ !IRC_WriteStrClient(from, RPL_WHOISBOT_MSG,
+ Client_ID(from), Client_ID(c)))
+ return DISCONNECTED;
+
/* Connected using SSL? */
if (Conn_UsesSSL(Client_Conn(c)) &&
!IRC_WriteStrClient(from, RPL_WHOISSSL_MSG, Client_ID(from),
Client_ID(from), Client_ID(c)))
return DISCONNECTED;
+ if (Client_Conn(c) > NONE && (Client_OperByMe(from) || from == c) &&
+ !IRC_WriteStrClient(from, RPL_WHOISHOST_MSG, Client_ID(from),
+ Client_ID(c), Client_Hostname(c),
+ Conn_GetIPAInfo(Client_Conn(c))))
+ return DISCONNECTED;
+
/* Idle and signon time (local clients only!) */
if (!Conf_MorePrivacy && Client_Conn(c) > NONE &&
!IRC_WriteStrClient(from, RPL_WHOISIDLE_MSG,
Conn_CountMax(), Conn_CountAccepted()))
return DISCONNECTED;
#endif
-
+
return CONNECTED;
} /* IRC_Send_LUSERS */
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
} /* IRC_Show_MOTD */
+/**
+ * Send NAMES reply for a specific client and channel.
+ *
+ * @param Client The client requesting the NAMES information.
+ * @param Chan The channel
+ * @return CONNECTED or DISCONNECTED.
+ */
GLOBAL bool
-IRC_Send_NAMES( CLIENT *Client, CHANNEL *Chan )
+IRC_Send_NAMES(CLIENT * Client, CHANNEL * Chan)
{
bool is_visible, is_member;
char str[LINE_LEN + 1];
CL2CHAN *cl2chan;
CLIENT *cl;
- assert( Client != NULL );
- assert( Chan != NULL );
+ assert(Client != NULL);
+ assert(Chan != NULL);
- if( Channel_IsMemberOf( Chan, Client )) is_member = true;
- else is_member = false;
+ if (Channel_IsMemberOf(Chan, Client))
+ is_member = true;
+ else
+ is_member = false;
/* Do not print info on channel memberships to anyone that is not member? */
if (Conf_MorePrivacy && !is_member)
return CONNECTED;
/* Secret channel? */
- if( ! is_member && strchr( Channel_Modes( Chan ), 's' )) return CONNECTED;
+ if (!is_member && strchr(Channel_Modes(Chan), 's'))
+ return CONNECTED;
- /* Alle Mitglieder suchen */
- snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
- cl2chan = Channel_FirstMember( Chan );
- while( cl2chan )
- {
- cl = Channel_GetClient( cl2chan );
+ snprintf(str, sizeof(str), RPL_NAMREPLY_MSG, Client_ID(Client), "=",
+ Channel_Name(Chan));
+ cl2chan = Channel_FirstMember(Chan);
+ while (cl2chan) {
+ cl = Channel_GetClient(cl2chan);
- if( strchr( Client_Modes( cl ), 'i' )) is_visible = false;
- else is_visible = true;
+ if (strchr(Client_Modes(cl), 'i'))
+ is_visible = false;
+ else
+ is_visible = true;
- if( is_member || is_visible )
- {
- /* Nick anhaengen */
- if( str[strlen( str ) - 1] != ':' ) strlcat( str, " ", sizeof( str ));
- if( strchr( Channel_UserModes( Chan, cl ), 'o' )) strlcat( str, "@", sizeof( str ));
- else if( strchr( Channel_UserModes( Chan, cl ), 'v' )) strlcat( str, "+", sizeof( str ));
- strlcat( str, Client_ID( cl ), sizeof( str ));
+ if (is_member || is_visible) {
+ if (str[strlen(str) - 1] != ':')
+ strlcat(str, " ", sizeof(str));
- if( strlen( str ) > ( LINE_LEN - CLIENT_NICK_LEN - 4 ))
- {
- /* Zeile wird zu lang: senden! */
- if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
- snprintf( str, sizeof( str ), RPL_NAMREPLY_MSG, Client_ID( Client ), "=", Channel_Name( Chan ));
+ 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)) {
+ if (!IRC_WriteStrClient(Client, "%s", str))
+ return DISCONNECTED;
+ snprintf(str, sizeof(str), RPL_NAMREPLY_MSG,
+ Client_ID(Client), "=",
+ Channel_Name(Chan));
}
}
- /* naechstes Mitglied suchen */
- cl2chan = Channel_NextMember( Chan, cl2chan );
+ cl2chan = Channel_NextMember(Chan, cl2chan);
}
- if( str[strlen( str ) - 1] != ':')
- {
- /* Es sind noch Daten da, die gesendet werden muessen */
- if( ! IRC_WriteStrClient( Client, "%s", str )) return DISCONNECTED;
+ if (str[strlen(str) - 1] != ':') {
+ if (!IRC_WriteStrClient(Client, "%s", str))
+ return DISCONNECTED;
}
return CONNECTED;