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