Quassel IRC  Pre-Release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
aliasmanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005-2015 by the Quassel Project *
3  * devel@quassel-irc.org *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) version 3. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19  ***************************************************************************/
20 
21 #include <QDebug>
22 #include <QStringList>
23 
24 #include "aliasmanager.h"
25 #include "network.h"
26 
28 AliasManager &AliasManager::operator=(const AliasManager &other)
29 {
30  if (this == &other)
31  return *this;
32 
34  _aliases = other._aliases;
35  return *this;
36 }
37 
38 
39 int AliasManager::indexOf(const QString &name) const
40 {
41  for (int i = 0; i < _aliases.count(); i++) {
42  if (_aliases[i].name == name)
43  return i;
44  }
45  return -1;
46 }
47 
48 
49 QVariantMap AliasManager::initAliases() const
50 {
51  QVariantMap aliases;
52  QStringList names;
53  QStringList expansions;
54 
55  for (int i = 0; i < _aliases.count(); i++) {
56  names << _aliases[i].name;
57  expansions << _aliases[i].expansion;
58  }
59 
60  aliases["names"] = names;
61  aliases["expansions"] = expansions;
62  return aliases;
63 }
64 
65 
66 void AliasManager::initSetAliases(const QVariantMap &aliases)
67 {
68  QStringList names = aliases["names"].toStringList();
69  QStringList expansions = aliases["expansions"].toStringList();
70 
71  if (names.count() != expansions.count()) {
72  qWarning() << "AliasesManager::initSetAliases: received" << names.count() << "alias names but only" << expansions.count() << "expansions!";
73  return;
74  }
75 
76  _aliases.clear();
77  for (int i = 0; i < names.count(); i++) {
78  _aliases << Alias(names[i], expansions[i]);
79  }
80 }
81 
82 
83 void AliasManager::addAlias(const QString &name, const QString &expansion)
84 {
85  if (contains(name)) {
86  return;
87  }
88 
89  _aliases << Alias(name, expansion);
90 
91  SYNC(ARG(name), ARG(expansion))
92 }
93 
94 
96 {
98  aliases << Alias("j", "/join $0")
99  << Alias("ns", "/msg nickserv $0")
100  << Alias("nickserv", "/msg nickserv $0")
101  << Alias("cs", "/msg chanserv $0")
102  << Alias("chanserv", "/msg chanserv $0")
103  << Alias("hs", "/msg hostserv $0")
104  << Alias("hostserv", "/msg hostserv $0")
105  << Alias("wii", "/whois $0 $0")
106  << Alias("back", "/quote away");
107 
108 #ifdef Q_OS_LINUX
109  // let's add aliases for scripts that only run on linux
110  aliases << Alias("inxi", "/exec inxi $0")
111  << Alias("sysinfo", "/exec inxi -d");
112 #endif
113 
114  return aliases;
115 }
116 
117 
119 {
120  CommandList result;
121  processInput(info, msg, result);
122  return result;
123 }
124 
125 
126 void AliasManager::processInput(const BufferInfo &info, const QString &msg_, CommandList &list)
127 {
128  QString msg = msg_;
129 
130  // leading slashes indicate there's a command to call unless there is another one in the first section (like a path /proc/cpuinfo)
131  int secondSlashPos = msg.indexOf('/', 1);
132  int firstSpacePos = msg.indexOf(' ');
133  if (!msg.startsWith('/') || (secondSlashPos != -1 && (secondSlashPos < firstSpacePos || firstSpacePos == -1))) {
134  if (msg.startsWith("//"))
135  msg.remove(0, 1); // //asdf is transformed to /asdf
136  msg.prepend("/SAY "); // make sure we only send proper commands to the core
137  }
138  else {
139  // check for aliases
140  QString cmd = msg.section(' ', 0, 0).remove(0, 1).toUpper();
141  for (int i = 0; i < count(); i++) {
142  if ((*this)[i].name.toUpper() == cmd) {
143  expand((*this)[i].expansion, info, msg.section(' ', 1), list);
144  return;
145  }
146  }
147  }
148 
149  list.append(qMakePair(info, msg));
150 }
151 
152 
153 void AliasManager::expand(const QString &alias, const BufferInfo &bufferInfo, const QString &msg, CommandList &list)
154 {
155  const Network *net = network(bufferInfo.networkId());
156  if (!net) {
157  // FIXME send error as soon as we have a method for that!
158  return;
159  }
160 
161  QRegExp paramRangeR("\\$(\\d+)\\.\\.(\\d*)");
162  QStringList commands = alias.split(QRegExp("; ?"));
163  QStringList params = msg.split(' ');
164  QStringList expandedCommands;
165  for (int i = 0; i < commands.count(); i++) {
166  QString command = commands[i];
167 
168  // replace ranges like $1..3
169  if (!params.isEmpty()) {
170  int pos;
171  while ((pos = paramRangeR.indexIn(command)) != -1) {
172  int start = paramRangeR.cap(1).toInt();
173  bool ok;
174  int end = paramRangeR.cap(2).toInt(&ok);
175  if (!ok) {
176  end = params.count();
177  }
178  if (end < start)
179  command = command.replace(pos, paramRangeR.matchedLength(), QString());
180  else {
181  command = command.replace(pos, paramRangeR.matchedLength(), QStringList(params.mid(start - 1, end - start + 1)).join(" "));
182  }
183  }
184  }
185 
186  for (int j = params.count(); j > 0; j--) {
187  IrcUser *ircUser = net->ircUser(params[j - 1]);
188  command = command.replace(QString("$%1:hostname").arg(j), ircUser ? ircUser->host() : QString("*"));
189  command = command.replace(QString("$%1").arg(j), params[j - 1]);
190  }
191  command = command.replace("$0", msg);
192  command = command.replace("$channelname", bufferInfo.bufferName()); // legacy
193  command = command.replace("$channel", bufferInfo.bufferName());
194  command = command.replace("$currentnick", net->myNick()); // legacy
195  command = command.replace("$nick", net->myNick());
196  expandedCommands << command;
197  }
198 
199  while (!expandedCommands.isEmpty()) {
200  QString command;
201  if (expandedCommands[0].trimmed().toLower().startsWith("/wait")) {
202  command = expandedCommands.join("; ");
203  expandedCommands.clear();
204  }
205  else {
206  command = expandedCommands.takeFirst();
207  }
208  list.append(qMakePair(bufferInfo, command));
209  }
210 }