+ /* Get target server for this command */
+ if (Req->argc > 1) {
+ /* Search the target server, which can be specified as a
+ * nickname on that server as well: */
+ target = Client_Search(Req->argv[0]);
+ if (!target)
+ return IRC_WriteStrClient(from, ERR_NOSUCHSERVER_MSG,
+ Client_ID(from), Req->argv[0]);
+ } else
+ target = Client_ThisServer();
+ assert(target != NULL);
+
+ /* Forward to other server? */
+ if (Client_NextHop(target) != Client_ThisServer() &&
+ Client_Type(Client_NextHop(target)) == CLIENT_SERVER)
+ return IRC_WriteStrClientPrefix(target, from,
+ "WHOIS %s :%s",
+ Req->argv[0], Req->argv[1]);
+
+ is_remote = Client_Conn(from) < 0;
+ strlcpy(mask, Req->argv[Req->argc - 1], sizeof(mask));
+ for (query = strtok(ngt_LowerStr(mask), ",");
+ query && found < 3;
+ query = strtok(NULL, ","), found++)
+ {
+ has_wildcards = query[strcspn(query, "*?")] != 0;
+ /*
+ * follows ircd 2.10 implementation:
+ * - handle up to 3 targets
+ * - no wildcards for remote clients
+ * - only one wildcard target per local client
+ *
+ * Also, at most MAX_RPL_WHOIS matches are returned.
+ */
+ if (!has_wildcards || is_remote) {
+ c = Client_Search(query);
+ if (c && (Client_Type(c) == CLIENT_USER
+ || Client_Type(c) == CLIENT_SERVICE)) {
+ if (!IRC_WHOIS_SendReply(Client, from, c))
+ return DISCONNECTED;
+ } else {
+ if (!IRC_WriteStrClient(Client,
+ ERR_NOSUCHNICK_MSG,
+ Client_ID(Client),
+ query))
+ return DISCONNECTED;
+ }
+ continue;
+ }
+ if (got_wildcard) {
+ /* we already handled one wildcard query */
+ if (!IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+ Client_ID(Client), query))
+ return DISCONNECTED;
+ continue;
+ }
+ got_wildcard = true;
+ IRC_SetPenalty(Client, 3);
+
+ for (c = Client_First(); c; c = Client_Next(c)) {
+ if (IRC_CheckListTooBig(Client, match_count,
+ MAX_RPL_WHOIS, "WHOIS"))
+ break;
+
+ if (Client_Type(c) != CLIENT_USER)
+ continue;
+ if (!MatchCaseInsensitive(query, Client_ID(c)))
+ continue;
+ if (!IRC_WHOIS_SendReply(Client, from, c))
+ return DISCONNECTED;
+
+ match_count++;
+ }
+
+ if (match_count == 0)
+ IRC_WriteStrClient(Client, ERR_NOSUCHNICK_MSG,
+ Client_ID(Client),
+ Req->argv[Req->argc - 1]);
+ }
+ return IRC_WriteStrClient(from, RPL_ENDOFWHOIS_MSG,
+ Client_ID(from), Req->argv[Req->argc - 1]);