10c9aa08d65892f5ca34868c688353b73dc92260
[quassel.git] / src / client / messagefilter.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2019 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 "messagefilter.h"
22
23 #include <algorithm>
24
25 #include "buffermodel.h"
26 #include "buffersettings.h"
27 #include "client.h"
28 #include "clientignorelistmanager.h"
29 #include "messagemodel.h"
30 #include "networkmodel.h"
31
32 MessageFilter::MessageFilter(QAbstractItemModel* source, QObject* parent)
33     : QSortFilterProxyModel(parent)
34     , _messageTypeFilter(0)
35 {
36     init();
37     setSourceModel(source);
38 }
39
40 MessageFilter::MessageFilter(MessageModel* source, const QList<BufferId>& buffers, QObject* parent)
41     : QSortFilterProxyModel(parent)
42     , _validBuffers(buffers.toSet())
43     , _messageTypeFilter(0)
44 {
45     init();
46     setSourceModel(source);
47 }
48
49 void MessageFilter::init()
50 {
51     setDynamicSortFilter(true);
52
53     _userNoticesTarget = _serverNoticesTarget = _errorMsgsTarget = -1;
54
55     BufferSettings defaultSettings;
56     defaultSettings.notify("UserNoticesTarget", this, &MessageFilter::messageRedirectionChanged);
57     defaultSettings.notify("ServerNoticesTarget", this, &MessageFilter::messageRedirectionChanged);
58     defaultSettings.notify("ErrorMsgsTarget", this, &MessageFilter::messageRedirectionChanged);
59     messageRedirectionChanged();
60
61     _messageTypeFilter = defaultSettings.messageFilter();
62     defaultSettings.notify("MessageTypeFilter", this, &MessageFilter::messageTypeFilterChanged);
63
64     BufferSettings mySettings(MessageFilter::idString());
65     if (mySettings.hasFilter())
66         _messageTypeFilter = mySettings.messageFilter();
67     mySettings.notify("MessageTypeFilter", this, &MessageFilter::messageTypeFilterChanged);
68     mySettings.notify("hasMessageTypeFilter", this, &MessageFilter::messageTypeFilterChanged);
69 }
70
71 void MessageFilter::messageTypeFilterChanged()
72 {
73     int newFilter;
74     BufferSettings defaultSettings;
75     newFilter = BufferSettings().messageFilter();
76
77     BufferSettings mySettings(idString());
78     if (mySettings.hasFilter())
79         newFilter = mySettings.messageFilter();
80
81     if (_messageTypeFilter != newFilter) {
82         _messageTypeFilter = newFilter;
83         _filteredQuitMsgTime.clear();
84         invalidateFilter();
85     }
86 }
87
88 void MessageFilter::messageRedirectionChanged()
89 {
90     BufferSettings bufferSettings;
91     bool changed = false;
92
93     if (_userNoticesTarget != bufferSettings.userNoticesTarget()) {
94         _userNoticesTarget = bufferSettings.userNoticesTarget();
95         changed = true;
96     }
97
98     if (_serverNoticesTarget != bufferSettings.serverNoticesTarget()) {
99         _serverNoticesTarget = bufferSettings.serverNoticesTarget();
100         changed = true;
101     }
102
103     if (_errorMsgsTarget != bufferSettings.errorMsgsTarget()) {
104         _errorMsgsTarget = bufferSettings.errorMsgsTarget();
105         changed = true;
106     }
107
108     if (changed)
109         invalidateFilter();
110 }
111
112 QString MessageFilter::idString() const
113 {
114     if (_validBuffers.isEmpty())
115         return "*";
116
117     QList<BufferId> bufferIds = _validBuffers.toList();
118     qSort(bufferIds);
119
120     QStringList bufferIdStrings;
121     foreach (BufferId id, bufferIds)
122         bufferIdStrings << QString::number(id.toInt());
123
124     return bufferIdStrings.join("|");
125 }
126
127 bool MessageFilter::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
128 {
129     Q_UNUSED(sourceParent);
130     QModelIndex sourceIdx = sourceModel()->index(sourceRow, 2);
131     Message::Type messageType = (Message::Type)sourceIdx.data(MessageModel::TypeRole).toInt();
132
133     // apply message type filter
134     if (_messageTypeFilter & messageType)
135         return false;
136
137     if (_validBuffers.isEmpty())
138         return true;
139
140     BufferId bufferId = sourceIdx.data(MessageModel::BufferIdRole).value<BufferId>();
141     if (!bufferId.isValid()) {
142         return true;
143     }
144
145     // MsgId msgId = sourceIdx.data(MessageModel::MsgIdRole).value<MsgId>();
146     Message::Flags flags = (Message::Flags)sourceIdx.data(MessageModel::FlagsRole).toInt();
147
148     NetworkId myNetworkId = networkId();
149     NetworkId msgNetworkId = Client::networkModel()->networkId(bufferId);
150     if (myNetworkId != msgNetworkId)
151         return false;
152
153     // ignorelist handling
154     // only match if message is not flagged as server msg
155     if (!(flags & Message::ServerMsg) && Client::ignoreListManager()
156         && Client::ignoreListManager()->match(sourceIdx.data(MessageModel::MessageRole).value<Message>(),
157                                               Client::networkModel()->networkName(bufferId)))
158         return false;
159
160     if (flags & Message::Redirected) {
161         int redirectionTarget = 0;
162         switch (messageType) {
163         case Message::Notice:
164             if (Client::networkModel()->bufferType(bufferId) != BufferInfo::ChannelBuffer) {
165                 if (flags & Message::ServerMsg) {
166                     // server notice
167                     redirectionTarget = _serverNoticesTarget;
168                 }
169                 else {
170                     redirectionTarget = _userNoticesTarget;
171                 }
172             }
173             break;
174         case Message::Error:
175             redirectionTarget = _errorMsgsTarget;
176             break;
177         default:
178             break;
179         }
180
181         if (redirectionTarget & BufferSettings::DefaultBuffer && _validBuffers.contains(bufferId))
182             return true;
183
184         if (redirectionTarget & BufferSettings::CurrentBuffer && !(flags & Message::Backlog)) {
185             BufferId redirectedTo = sourceModel()->data(sourceIdx, MessageModel::RedirectedToRole).value<BufferId>();
186             if (!redirectedTo.isValid()) {
187                 BufferId redirectedTo = Client::bufferModel()->currentIndex().data(NetworkModel::BufferIdRole).value<BufferId>();
188                 if (redirectedTo.isValid())
189                     sourceModel()->setData(sourceIdx, QVariant::fromValue<BufferId>(redirectedTo), MessageModel::RedirectedToRole);
190             }
191
192             if (_validBuffers.contains(redirectedTo))
193                 return true;
194         }
195
196         if (redirectionTarget & BufferSettings::StatusBuffer) {
197             QSet<BufferId>::const_iterator idIter = _validBuffers.constBegin();
198             while (idIter != _validBuffers.constEnd()) {
199                 if (Client::networkModel()->bufferType(*idIter) == BufferInfo::StatusBuffer)
200                     return true;
201                 ++idIter;
202             }
203         }
204
205         return false;
206     }
207
208     if (_validBuffers.contains(bufferId)) {
209         return true;
210     }
211     else {
212         // show Quit messages in Query buffers:
213         if (bufferType() != BufferInfo::QueryBuffer)
214             return false;
215         if (!(messageType & Message::Quit))
216             return false;
217
218         if (myNetworkId != msgNetworkId)
219             return false;
220
221         // Extract timestamp and nickname from the new quit message
222         qint64 messageTimestamp = sourceModel()->data(sourceIdx, MessageModel::TimestampRole).value<QDateTime>().toMSecsSinceEpoch();
223         QString quiter = nickFromMask(sourceModel()->data(sourceIdx, MessageModel::MessageRole).value<Message>().sender()).toLower();
224
225         // Check that nickname matches query name
226         if (quiter != bufferName().toLower())
227             return false;
228
229         // Check if a quit message was already forwarded within +/- 1000 ms
230         static constexpr qint64 MAX_QUIT_DELTA_MS = 1 * 1000;
231         // No need to check if it's the appropriate buffer, each query has a unique message filter
232         if (std::binary_search(_filteredQuitMsgTime.begin(), _filteredQuitMsgTime.end(), messageTimestamp, [](qint64 a, qint64 b) {
233                 return ((a + MAX_QUIT_DELTA_MS) < b);
234             })) {
235             // New element is less than if at least 1000 ms older/newer
236             // Match found, no need to forward another quit message
237             return false;
238         }
239
240         // Mark query as having a quit message inserted
241         auto* that = const_cast<MessageFilter*>(this);
242         that->_filteredQuitMsgTime.insert(messageTimestamp);
243         return true;
244     }
245 }
246
247 void MessageFilter::requestBacklog()
248 {
249     QSet<BufferId>::const_iterator bufferIdIter = _validBuffers.constBegin();
250     while (bufferIdIter != _validBuffers.constEnd()) {
251         Client::messageModel()->requestBacklog(*bufferIdIter);
252         ++bufferIdIter;
253     }
254 }