Checking whether a initSetMethod exists before bluntly invoking it. (fixes a new...
[quassel.git] / src / common / ignorelistmanager.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-09 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  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "ignorelistmanager.h"
22
23 #include <QDebug>
24 #include <QStringList>
25 #include <QRegExp>
26
27 INIT_SYNCABLE_OBJECT(IgnoreListManager)
28 IgnoreListManager &IgnoreListManager::operator=(const IgnoreListManager &other) {
29   if(this == &other)
30     return *this;
31
32   SyncableObject::operator=(other);
33   _ignoreList = other._ignoreList;
34   return *this;
35 }
36
37 int IgnoreListManager::indexOf(const QString &ignore) const {
38   for(int i = 0; i < _ignoreList.count(); i++) {
39     if(_ignoreList[i].ignoreRule == ignore)
40       return i;
41   }
42   return -1;
43 }
44
45 QVariantMap IgnoreListManager::initIgnoreList() const {
46   QVariantMap ignoreListMap;
47   QVariantList ignoreTypeList;
48   QStringList ignoreRuleList;
49   QStringList scopeRuleList;
50   QVariantList isRegExList;
51   QVariantList scopeList;
52   QVariantList strictnessList;
53   QVariantList isActiveList;
54
55   for(int i = 0; i < _ignoreList.count(); i++) {
56     ignoreTypeList << _ignoreList[i].type;
57     ignoreRuleList << _ignoreList[i].ignoreRule;
58     scopeRuleList << _ignoreList[i].scopeRule;
59     isRegExList << _ignoreList[i].isRegEx;
60     scopeList << _ignoreList[i].scope;
61     strictnessList << _ignoreList[i].strictness;
62     isActiveList << _ignoreList[i].isActive;
63   }
64
65   ignoreListMap["ignoreType"] = ignoreTypeList;
66   ignoreListMap["ignoreRule"] = ignoreRuleList;
67   ignoreListMap["scopeRule"] = scopeRuleList;
68   ignoreListMap["isRegEx"] = isRegExList;
69   ignoreListMap["scope"] = scopeList;
70   ignoreListMap["strictness"] = strictnessList;
71   ignoreListMap["isActive"] = isActiveList;
72   return ignoreListMap;
73 }
74
75 void IgnoreListManager::initSetIgnoreList(const QVariantMap &ignoreList) {
76   QVariantList ignoreType = ignoreList["ignoreType"].toList();
77   QStringList ignoreRule = ignoreList["ignoreRule"].toStringList();
78   QStringList scopeRule = ignoreList["scopeRule"].toStringList();
79   QVariantList isRegEx = ignoreList["isRegEx"].toList();
80   QVariantList scope = ignoreList["scope"].toList();
81   QVariantList strictness = ignoreList["strictness"].toList();
82   QVariantList isActive = ignoreList["isActive"].toList();
83
84   int count = ignoreRule.count();
85   if(count != scopeRule.count() || count != isRegEx.count() ||
86      count != scope.count() || count != strictness.count() || count != ignoreType.count() || count != isActive.count()) {
87     qWarning() << "Corrupted IgnoreList settings! (Count missmatch)";
88     return;
89   }
90
91   _ignoreList.clear();
92   for(int i = 0; i < ignoreRule.count(); i++) {
93     _ignoreList << IgnoreListItem(static_cast<IgnoreType>(ignoreType[i].toInt()), ignoreRule[i], isRegEx[i].toBool(),
94                               static_cast<StrictnessType>(strictness[i].toInt()), static_cast<ScopeType>(scope[i].toInt()),
95                               scopeRule[i], isActive[i].toBool());
96   }
97 }
98
99 /* since overloaded methods aren't syncable (yet?) we can't use that anymore
100 void IgnoreListManager::addIgnoreListItem(const IgnoreListItem &item) {
101   addIgnoreListItem(item.type, item.ignoreRule, item.isRegEx, item.strictness, item.scope, item.scopeRule, item.isActive);
102 }
103 */
104 void IgnoreListManager::addIgnoreListItem(int type, const QString &ignoreRule, bool isRegEx, int strictness,
105                                       int scope, const QString &scopeRule, bool isActive) {
106   if(contains(ignoreRule)) {
107     return;
108   }
109
110   IgnoreListItem newItem = IgnoreListItem(static_cast<IgnoreType>(type), ignoreRule, isRegEx, static_cast<StrictnessType>(strictness),
111                                           static_cast<ScopeType>(scope), scopeRule, isActive);
112   _ignoreList << newItem;
113
114   SYNC(ARG(type), ARG(ignoreRule), ARG(isRegEx), ARG(strictness), ARG(scope), ARG(scopeRule), ARG(isActive))
115 }
116
117 IgnoreListManager::StrictnessType IgnoreListManager::_match(const QString &msgContents, const QString &msgSender, Message::Type msgType, const QString &network, const QString &bufferName) {
118   // We method don't rely on a proper Message object to make this method more versatile.
119   // This allows us to use it in the core with unprocessed Messages or in the Client
120   // with properly preprocessed Messages.
121   if(!(msgType & (Message::Plain | Message::Notice | Message::Action)))
122     return UnmatchedStrictness;
123
124   foreach(IgnoreListItem item, _ignoreList) {
125     if(!item.isActive || item.type == CtcpIgnore)
126       continue;
127     if(item.scope == GlobalScope
128        || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network))
129        || (item.scope == ChannelScope && scopeMatch(item.scopeRule, bufferName))) {
130
131       QString str;
132       if(item.type == MessageIgnore)
133         str = msgContents;
134       else
135         str = msgSender;
136
137       QRegExp ruleRx = QRegExp(item.ignoreRule);
138       ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
139       if(!item.isRegEx) {
140         ruleRx.setPatternSyntax(QRegExp::Wildcard);
141       }
142
143 //      qDebug() << "IgnoreListManager::match: ";
144 //      qDebug() << "string: " << str;
145 //      qDebug() << "pattern: " << ruleRx.pattern();
146 //      qDebug() << "scopeRule: " << item.scopeRule;
147 //      qDebug() << "now testing";
148       if((!item.isRegEx && ruleRx.exactMatch(str)) ||
149           (item.isRegEx && ruleRx.indexIn(str) != -1)) {
150 //        qDebug() << "MATCHED!";
151         return item.strictness;
152       }
153     }
154   }
155   return UnmatchedStrictness;
156 }
157
158
159 bool IgnoreListManager::scopeMatch(const QString &scopeRule, const QString &string) const {
160   foreach(QString rule, scopeRule.split(";")) {
161     QRegExp ruleRx = QRegExp(rule.trimmed());
162     ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
163     ruleRx.setPatternSyntax(QRegExp::Wildcard);
164     if(ruleRx.exactMatch(string)) {
165       return true;
166     }
167   }
168   return false;
169 }
170
171 void IgnoreListManager::removeIgnoreListItem(const QString &ignoreRule) {
172   removeAt(indexOf(ignoreRule));
173   SYNC(ARG(ignoreRule))
174 }
175
176 void IgnoreListManager::toggleIgnoreRule(const QString &ignoreRule) {
177   int idx = indexOf(ignoreRule);
178   if(idx == -1)
179     return;
180   _ignoreList[idx].isActive = !_ignoreList[idx].isActive;
181   SYNC(ARG(ignoreRule))
182 }
183
184 bool IgnoreListManager::ctcpMatch(const QString sender, const QString &network, const QString &type) {
185   foreach(IgnoreListItem item, _ignoreList) {
186     if(!item.isActive)
187       continue;
188     if(item.scope == GlobalScope || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network))) {
189       QString sender_;
190       QStringList types = item.ignoreRule.split(QRegExp("\\s+"), QString::SkipEmptyParts);
191
192       sender_ = types.takeAt(0);
193
194       QRegExp ruleRx = QRegExp(sender_);
195       ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
196       if(!item.isRegEx)
197         ruleRx.setPatternSyntax(QRegExp::Wildcard);
198       if((!item.isRegEx && ruleRx.exactMatch(sender)) ||
199           (item.isRegEx && ruleRx.indexIn(sender) != -1)) {
200
201         if(types.isEmpty() || types.contains(type, Qt::CaseInsensitive))
202           return true;
203       }
204     }
205   }
206   return false;
207 }