+ // From RFC 1459.
+ RPL_ENDOFWHO = 315,
+ RPL_WHOREPLY = 352,
+
+ // From ircu.
+ RPL_WHOSPCRPL = 354
+};
+
+static const char whox_field_order[] = "tcuihsnfdlaor";
+static const char who_field_order[] = "cuhsnf";
+
+struct WhoData : public Who::Request
+{
+ bool GetFieldIndex(char flag, size_t& out) const CXX11_OVERRIDE
+ {
+ if (!whox)
+ {
+ const char* pos = strchr(who_field_order, flag);
+ if (pos == NULL)
+ return false;
+
+ out = pos - who_field_order;
+ return true;
+ }
+
+ if (!whox_fields[flag])
+ return false;
+
+ out = 0;
+ for (const char* c = whox_field_order; *c && *c != flag; ++c)
+ {
+ if (whox_fields[*c])
+ ++out;
+ }
+
+ return whox_field_order[out];
+ }
+
+ WhoData(const CommandBase::Params& parameters)
+ {
+ // Find the matchtext and swap the 0 for a * so we can use InspIRCd::Match on it.
+ matchtext = parameters.size() > 2 ? parameters[2] : parameters[0];
+ if (matchtext == "0")
+ matchtext = "*";
+
+ // Fuzzy matches are when the source has not specified a specific user.
+ fuzzy_match = (parameters.size() > 1) || (matchtext.find_first_of("*?.") != std::string::npos);
+
+ // If flags have been specified by the source.
+ if (parameters.size() > 1)
+ {
+ std::bitset<UCHAR_MAX>* current_bitset = &flags;
+ for (std::string::const_iterator iter = parameters[1].begin(); iter != parameters[1].end(); ++iter)
+ {
+ unsigned char chr = static_cast<unsigned char>(*iter);
+
+ // If the source specifies a percentage the rest of the flags are WHOX fields.
+ if (chr == '%')
+ {
+ whox = true;
+ current_bitset = &whox_fields;
+ continue;
+ }
+
+ // If we are in WHOX mode and the source specifies a comma
+ // the rest of the parameter is the query type.
+ if (whox && chr == ',')
+ {
+ whox_querytype.assign(++iter, parameters[1].end());
+ break;
+ }
+
+ // The source specified a matching flag.
+ current_bitset->set(chr);
+ }
+ }
+ }
+};
+
+class CommandWho : public SplitCommand
+{
+ private: