And don't fuckup '*' rules
[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 #include "message.h"
28
29 INIT_SYNCABLE_OBJECT(IgnoreListManager)
30
31 IgnoreListManager &IgnoreListManager::operator=(const IgnoreListManager &other) {
32   if(this == &other)
33     return *this;
34
35   SyncableObject::operator=(other);
36   _ignoreList = other._ignoreList;
37   return *this;
38 }
39
40 int IgnoreListManager::indexOf(const QString &ignore) const {
41   for(int i = 0; i < _ignoreList.count(); i++) {
42     if(_ignoreList[i].ignoreRule == ignore)
43       return i;
44   }
45   return -1;
46 }
47
48 QVariantMap IgnoreListManager::initIgnoreList() const {
49   QVariantMap ignoreListMap;
50   QVariantList ignoreTypeList;
51   QStringList ignoreRuleList;
52   QStringList scopeRuleList;
53   QVariantList isRegExList;
54   QVariantList scopeList;
55   QVariantList strictnessList;
56   QVariantList isActiveList;
57
58   for(int i = 0; i < _ignoreList.count(); i++) {
59     ignoreTypeList << _ignoreList[i].type;
60     ignoreRuleList << _ignoreList[i].ignoreRule;
61     scopeRuleList << _ignoreList[i].scopeRule;
62     isRegExList << _ignoreList[i].isRegEx;
63     scopeList << _ignoreList[i].scope;
64     strictnessList << _ignoreList[i].strictness;
65     isActiveList << _ignoreList[i].isActive;
66   }
67
68   ignoreListMap["ignoreType"] = ignoreTypeList;
69   ignoreListMap["ignoreRule"] = ignoreRuleList;
70   ignoreListMap["scopeRule"] = scopeRuleList;
71   ignoreListMap["isRegEx"] = isRegExList;
72   ignoreListMap["scope"] = scopeList;
73   ignoreListMap["strictness"] = strictnessList;
74   ignoreListMap["isActive"] = isActiveList;
75   return ignoreListMap;
76 }
77
78 void IgnoreListManager::initSetIgnoreList(const QVariantMap &ignoreList) {
79   QVariantList ignoreType = ignoreList["ignoreType"].toList();
80   QStringList ignoreRule = ignoreList["ignoreRule"].toStringList();
81   QStringList scopeRule = ignoreList["scopeRule"].toStringList();
82   QVariantList isRegEx = ignoreList["isRegEx"].toList();
83   QVariantList scope = ignoreList["scope"].toList();
84   QVariantList strictness = ignoreList["strictness"].toList();
85   QVariantList isActive = ignoreList["isActive"].toList();
86
87   int count = ignoreRule.count();
88   if(count != scopeRule.count() || count != isRegEx.count() ||
89      count != scope.count() || count != strictness.count() || count != ignoreType.count() || count != isActive.count()) {
90     qWarning() << "Corrupted IgnoreList settings! (Count missmatch)";
91     return;
92   }
93
94   _ignoreList.clear();
95   for(int i = 0; i < ignoreRule.count(); i++) {
96     _ignoreList << IgnoreListItem(static_cast<IgnoreType>(ignoreType[i].toInt()), ignoreRule[i], isRegEx[i].toBool(),
97                               static_cast<StrictnessType>(strictness[i].toInt()), static_cast<ScopeType>(scope[i].toInt()),
98                               scopeRule[i], isActive[i].toBool());
99   }
100 }
101
102 /* since overloaded methods aren't syncable (yet?) we can't use that anymore
103 void IgnoreListManager::addIgnoreListItem(const IgnoreListItem &item) {
104   addIgnoreListItem(item.type, item.ignoreRule, item.isRegEx, item.strictness, item.scope, item.scopeRule, item.isActive);
105 }
106 */
107 void IgnoreListManager::addIgnoreListItem(int type, const QString &ignoreRule, bool isRegEx, int strictness,
108                                       int scope, const QString &scopeRule, bool isActive) {
109   if(contains(ignoreRule)) {
110     return;
111   }
112
113   IgnoreListItem newItem = IgnoreListItem(static_cast<IgnoreType>(type), ignoreRule, isRegEx, static_cast<StrictnessType>(strictness),
114                                           static_cast<ScopeType>(scope), scopeRule, isActive);
115   _ignoreList << newItem;
116
117   SYNC(ARG(type), ARG(ignoreRule), ARG(isRegEx), ARG(strictness), ARG(scope), ARG(scopeRule), ARG(isActive))
118 }
119
120 IgnoreListManager::StrictnessType IgnoreListManager::match(const Message &msg, const QString &network) {
121   if(!(msg.type() & (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 || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network)) ||
128        (item.scope == ChannelScope && scopeMatch(item.scopeRule, msg.bufferInfo().bufferName()))) {
129
130       QString str;
131       if(item.type == MessageIgnore)
132         str = msg.contents();
133       else
134         str = msg.sender();
135
136       QRegExp ruleRx = QRegExp(item.ignoreRule);
137       ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
138       if(!item.isRegEx) {
139         ruleRx.setPatternSyntax(QRegExp::Wildcard);
140       }
141
142 //      qDebug() << "IgnoreListManager::match: ";
143 //      qDebug() << "string: " << str;
144 //      qDebug() << "pattern: " << ruleRx.pattern();
145 //      qDebug() << "scopeRule: " << item.scopeRule;
146 //      qDebug() << "now testing";
147       if((!item.isRegEx && ruleRx.exactMatch(str)) ||
148           (item.isRegEx && ruleRx.indexIn(str) != -1)) {
149 //        qDebug() << "MATCHED!";
150         return item.strictness;
151       }
152     }
153   }
154   return UnmatchedStrictness;
155 }
156
157 bool IgnoreListManager::scopeMatch(const QString &scopeRule, const QString &string) const {
158   foreach(QString rule, scopeRule.split(";")) {
159     QRegExp ruleRx = QRegExp(rule.trimmed());
160     ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
161     ruleRx.setPatternSyntax(QRegExp::Wildcard);
162     if(ruleRx.exactMatch(string)) {
163       return true;
164     }
165   }
166   return false;
167 }
168
169 void IgnoreListManager::removeIgnoreListItem(const QString &ignoreRule) {
170   removeAt(indexOf(ignoreRule));
171   SYNC(ARG(ignoreRule))
172 }
173
174 void IgnoreListManager::toggleIgnoreRule(const QString &ignoreRule) {
175   int idx = indexOf(ignoreRule);
176   if(idx == -1)
177     return;
178   _ignoreList[idx].isActive = !_ignoreList[idx].isActive;
179   SYNC(ARG(ignoreRule))
180 }
181
182 bool IgnoreListManager::ctcpMatch(const QString sender, const QString &network, const QString &type) {
183   foreach(IgnoreListItem item, _ignoreList) {
184     if(!item.isActive)
185       continue;
186     if(item.scope == GlobalScope || (item.scope == NetworkScope && scopeMatch(item.scopeRule, network))) {
187       QString sender_;
188       QStringList types = item.ignoreRule.split(QRegExp("\\s+"), QString::SkipEmptyParts);
189
190       sender_ = types.takeAt(0);
191
192       QRegExp ruleRx = QRegExp(sender_);
193       ruleRx.setCaseSensitivity(Qt::CaseInsensitive);
194       if(!item.isRegEx)
195         ruleRx.setPatternSyntax(QRegExp::Wildcard);
196       if((!item.isRegEx && ruleRx.exactMatch(sender)) ||
197           (item.isRegEx && ruleRx.indexIn(sender) != -1)) {
198
199         if(types.isEmpty() || types.contains(type, Qt::CaseInsensitive))
200           return true;
201       }
202     }
203   }
204   return false;
205 }