X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fcommon%2Faliasmanager.cpp;h=d8dd082f9119f8ae703031002c65e6ee1bc74a3f;hp=c627e70348cafe2a12b28d55e03dc46456915772;hb=cc6e7c08709c4e761e2fd9c2e322751015497003;hpb=f824db0e31b54969e0b7fa0b5405b1e9173d482c diff --git a/src/common/aliasmanager.cpp b/src/common/aliasmanager.cpp index c627e703..d8dd082f 100644 --- a/src/common/aliasmanager.cpp +++ b/src/common/aliasmanager.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-09 by the Quassel Project * + * Copyright (C) 2005-2019 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "aliasmanager.h" @@ -23,73 +23,205 @@ #include #include -AliasManager &AliasManager::operator=(const AliasManager &other) { - if(this == &other) +#include "network.h" + +AliasManager& AliasManager::operator=(const AliasManager& other) +{ + if (this == &other) + return *this; + + SyncableObject::operator=(other); + _aliases = other._aliases; return *this; - - SyncableObject::operator=(other); - _aliases = other._aliases; - return *this; } -int AliasManager::indexOf(const QString &name) const { - for(int i = 0; i < _aliases.count(); i++) { - if(_aliases[i].name == name) - return i; - } - return -1; +int AliasManager::indexOf(const QString& name) const +{ + for (int i = 0; i < _aliases.count(); i++) { + if (_aliases[i].name == name) + return i; + } + return -1; +} + +QVariantMap AliasManager::initAliases() const +{ + QVariantMap aliases; + QStringList names; + QStringList expansions; + + for (int i = 0; i < _aliases.count(); i++) { + names << _aliases[i].name; + expansions << _aliases[i].expansion; + } + + aliases["names"] = names; + aliases["expansions"] = expansions; + return aliases; +} + +void AliasManager::initSetAliases(const QVariantMap& aliases) +{ + QStringList names = aliases["names"].toStringList(); + QStringList expansions = aliases["expansions"].toStringList(); + + if (names.count() != expansions.count()) { + qWarning() << "AliasesManager::initSetAliases: received" << names.count() << "alias names but only" << expansions.count() + << "expansions!"; + return; + } + + _aliases.clear(); + for (int i = 0; i < names.count(); i++) { + _aliases << Alias(names[i], expansions[i]); + } } -QVariantMap AliasManager::initAliases() const { - QVariantMap aliases; - QStringList names; - QStringList expansions; +void AliasManager::addAlias(const QString& name, const QString& expansion) +{ + if (contains(name)) { + return; + } - for(int i = 0; i < _aliases.count(); i++) { - names << _aliases[i].name; - expansions << _aliases[i].expansion; - } + _aliases << Alias(name, expansion); - aliases["names"] = names; - aliases["expansions"] = expansions; - return aliases; + SYNC(ARG(name), ARG(expansion)) } -void AliasManager::initSetAliases(const QVariantMap &aliases) { - QStringList names = aliases["names"].toStringList(); - QStringList expansions = aliases["expansions"].toStringList(); +AliasManager::AliasList AliasManager::defaults() +{ + AliasList aliases; + aliases << Alias("j", "/join $0") << Alias("ns", "/msg nickserv $0") << Alias("nickserv", "/msg nickserv $0") + << Alias("cs", "/msg chanserv $0") << Alias("chanserv", "/msg chanserv $0") << Alias("hs", "/msg hostserv $0") + << Alias("hostserv", "/msg hostserv $0") << Alias("wii", "/whois $0 $0") << Alias("back", "/quote away"); - if(names.count() != expansions.count()) { - qWarning() << "AliasesManager::initSetAliases: received" << names.count() << "alias names but only" << expansions.count() << "expansions!"; - return; - } +#ifdef Q_OS_LINUX + // let's add aliases for scripts that only run on linux + aliases << Alias("inxi", "/exec inxi $0") << Alias("sysinfo", "/exec inxi -d"); +#endif - _aliases.clear(); - for(int i = 0; i < names.count(); i++) { - _aliases << Alias(names[i], expansions[i]); - } + return aliases; } +AliasManager::CommandList AliasManager::processInput(const BufferInfo& info, const QString& msg) +{ + CommandList result; + processInput(info, msg, result); + return result; +} -void AliasManager::addAlias(const QString &name, const QString &expansion) { - if(contains(name)) { - return; - } +void AliasManager::processInput(const BufferInfo& info, const QString& msg_, CommandList& list) +{ + QString msg = msg_; - _aliases << Alias(name, expansion); + // leading slashes indicate there's a command to call unless there is another one in the first section (like a path /proc/cpuinfo) + // For those habitally tied to irssi, "/ " also makes the rest of the line a literal message + int secondSlashPos = msg.indexOf('/', 1); + int firstSpacePos = msg.indexOf(' '); + if (!msg.startsWith('/') || firstSpacePos == 1 || (secondSlashPos != -1 && (secondSlashPos < firstSpacePos || firstSpacePos == -1))) { + if (msg.startsWith("//")) + msg.remove(0, 1); // "//asdf" is transformed to "/asdf" + else if (msg.startsWith("/ ")) + msg.remove(0, 2); // "/ /asdf" is transformed to "/asdf" + msg.prepend("/SAY "); // make sure we only send proper commands to the core + } + else { + // check for aliases + QString cmd = msg.section(' ', 0, 0).remove(0, 1).toUpper(); + for (int i = 0; i < count(); i++) { + if ((*this)[i].name.toUpper() == cmd) { + expand((*this)[i].expansion, info, msg.section(' ', 1), list); + return; + } + } + } - emit aliasAdded(name, expansion); + list.append(qMakePair(info, msg)); } -AliasManager::AliasList AliasManager::defaults() { - AliasList aliases; - aliases << Alias("j", "/join $0") - << Alias("ns", "/msg nickserv $0") - << Alias("nickserv", "/msg nickserv $0") - << Alias("cs", "/msg chanserv $0") - << Alias("chanserv", "/msg chanserv $0") - << Alias("hs", "/msg hostserv $0") - << Alias("hostserv", "/msg hostserv $0") - << Alias("back", "/quote away"); - return aliases; +void AliasManager::expand(const QString& alias, const BufferInfo& bufferInfo, const QString& msg, CommandList& list) +{ + const Network* net = network(bufferInfo.networkId()); + if (!net) { + // FIXME send error as soon as we have a method for that! + return; + } + + QRegExp paramRangeR(R"(\$(\d+)\.\.(\d*))"); + QStringList commands = alias.split(QRegExp("; ?")); + QStringList params = msg.split(' '); + QStringList expandedCommands; + for (int i = 0; i < commands.count(); i++) { + QString command = commands[i]; + + // replace ranges like $1..3 + if (!params.isEmpty()) { + int pos; + while ((pos = paramRangeR.indexIn(command)) != -1) { + int start = paramRangeR.cap(1).toInt(); + bool ok; + int end = paramRangeR.cap(2).toInt(&ok); + if (!ok) { + end = params.count(); + } + if (end < start) + command = command.replace(pos, paramRangeR.matchedLength(), QString()); + else { + command = command.replace(pos, paramRangeR.matchedLength(), QStringList(params.mid(start - 1, end - start + 1)).join(" ")); + } + } + } + + for (int j = params.count(); j > 0; j--) { + // Find the referenced IRC user... + IrcUser* ircUser = net->ircUser(params[j - 1]); + // ...and replace components, using short-circuit evaluation as ircUser might be null + + // Account, or "*" if blank/nonexistent/logged out + command = command.replace(QString("$%1:account").arg(j), + (ircUser && !ircUser->account().isEmpty()) ? ircUser->account() : QString("*")); + + // Hostname, or "*" if blank/nonexistent + command = command.replace(QString("$%1:hostname").arg(j), + (ircUser && !ircUser->host().isEmpty()) ? ircUser->host() : QString("*")); + + // Identd + // Ident if verified, or "*" if blank/unknown/unverified (prefixed with "~") + // + // Most IRC daemons have the option to prefix an ident with "~" if it could not be + // verified via an identity daemon such as oidentd. In these cases, it can be handy to + // have a way to ban via ident if verified, or all idents if not verified. If the + // server does not verify idents, it usually won't add "~". + // + // Identd must be replaced before ident to avoid being treated as "$i:ident" + "d" + command = command.replace(QString("$%1:identd").arg(j), + (ircUser && !ircUser->user().isEmpty() && !ircUser->user().startsWith("~")) ? ircUser->user() + : QString("*")); + + // Ident, or "*" if blank/nonexistent + command = command.replace(QString("$%1:ident").arg(j), (ircUser && !ircUser->user().isEmpty()) ? ircUser->user() : QString("*")); + + // Nickname + // Must be replaced last to avoid interferring with more specific aliases + command = command.replace(QString("$%1").arg(j), params[j - 1]); + } + command = command.replace("$0", msg); + command = command.replace("$channelname", bufferInfo.bufferName()); // legacy + command = command.replace("$channel", bufferInfo.bufferName()); + command = command.replace("$currentnick", net->myNick()); // legacy + command = command.replace("$nick", net->myNick()); + expandedCommands << command; + } + + while (!expandedCommands.isEmpty()) { + QString command; + if (expandedCommands[0].trimmed().toLower().startsWith("/wait ")) { + command = expandedCommands.join("; "); + expandedCommands.clear(); + } + else { + command = expandedCommands.takeFirst(); + } + list.append(qMakePair(bufferInfo, command)); + } }