queueCurrentCap = true;
} else if (availableCapPair.at(0).startsWith("away-notify") ||
availableCapPair.at(0).startsWith("account-notify") ||
- availableCapPair.at(0).startsWith("extended-join")) {
+ availableCapPair.at(0).startsWith("extended-join") ||
+ availableCapPair.at(0).startsWith("userhost-in-names") ||
+ availableCapPair.at(0).startsWith("multi-prefix")) {
// Always request these capabilities if available
queueCurrentCap = true;
}
ircuser->setUser(e->params()[1]);
ircuser->setHost(e->params()[2]);
- bool away = e->params()[5].startsWith("G");
+ bool away = e->params()[5].contains("G", Qt::CaseInsensitive);
ircuser->setAway(away);
ircuser->setServer(e->params()[3]);
ircuser->setRealName(e->params().last().section(" ", 1));
+
+ if (coreNetwork(e)->useCapMultiPrefix()) {
+ // If multi-prefix is enabled, all modes will be sent in WHO replies.
+ // :kenny.chatspike.net 352 guest #test grawity broken.symlink *.chatspike.net grawity H@%+ :0 Mantas M.
+ // See: http://ircv3.net/specs/extensions/multi-prefix-3.1.html
+ QString uncheckedModes = e->params()[5];
+ QString validModes = QString();
+ while (!uncheckedModes.isEmpty()) {
+ // Mode found in 1 left-most character, add it to the list
+ if (e->network()->prefixes().contains(uncheckedModes[0])) {
+ validModes.append(e->network()->prefixToMode(uncheckedModes[0]));
+ }
+ // Remove this mode from the list of unchecked modes
+ uncheckedModes = uncheckedModes.remove(0, 1);
+ }
+
+ // Some IRC servers decide to not follow the spec, returning only -some- of the user
+ // modes in WHO despite listing them all in NAMES. For now, assume it can only add
+ // and not take away. *sigh*
+ if (!validModes.isEmpty()) {
+ if (channel != "*") {
+ // Channel-specific modes received, apply to given channel only
+ IrcChannel *ircChan = e->network()->ircChannel(channel);
+ if (ircChan) {
+ // Do one mode at a time
+ // TODO Better way of syncing this without breaking protocol?
+ for (int i = 0; i < validModes.count(); ++i) {
+ ircChan->addUserMode(ircuser, validModes.at(i));
+ }
+ }
+ } else {
+ // Modes apply to the user everywhere
+ ircuser->addUserModes(validModes);
+ }
+ }
+ }
}
// Check if channel name has a who in progress.
QStringList nicks;
QStringList modes;
+ // Cache result of multi-prefix to avoid unneeded casts and lookups with each iteration.
+ bool _useCapMultiPrefix = coreNetwork(e)->useCapMultiPrefix();
+
foreach(QString nick, e->params()[2].split(' ', QString::SkipEmptyParts)) {
QString mode;
- if (e->network()->prefixes().contains(nick[0])) {
+ if (_useCapMultiPrefix) {
+ // If multi-prefix is enabled, all modes will be sent in NAMES replies.
+ // :hades.arpa 353 guest = #tethys :~&@%+aji &@Attila @+alyx +KindOne Argure
+ // See: http://ircv3.net/specs/extensions/multi-prefix-3.1.html
+ while (e->network()->prefixes().contains(nick[0])) {
+ // Mode found in 1 left-most character, add it to the list.
+ // Note: sending multiple modes may cause a warning in older clients.
+ // In testing, the clients still seemed to function fine.
+ mode.append(e->network()->prefixToMode(nick[0]));
+ // Remove this mode from the nick
+ nick = nick.remove(0, 1);
+ }
+ } else if (e->network()->prefixes().contains(nick[0])) {
+ // Multi-prefix is disabled and a mode prefix was found.
mode = e->network()->prefixToMode(nick[0]);
nick = nick.mid(1);
}
+ // If userhost-in-names capability is enabled, the following will be
+ // in the form "nick!user@host" rather than "nick". This works without
+ // special handling as the following use nickFromHost() as needed.
+ // See: http://ircv3.net/specs/extensions/userhost-in-names-3.2.html
+
nicks << nick;
modes << mode;
}
}
// TODO: check if target is the right thing to use for the partner
- CoreTransfer *transfer = new CoreTransfer(Transfer::Receive, e->target(), filename, address, port, size, this);
+ CoreTransfer *transfer = new CoreTransfer(Transfer::Direction::Receive, e->target(), filename, address, port, size, this);
coreSession()->signalProxy()->synchronize(transfer);
coreSession()->transferManager()->addTransfer(transfer);
}