1 /* enabled_protocols_model.cpp
2 *
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include <QSortFilterProxyModel>
11
12 #include <ui/qt/models/enabled_protocols_model.h>
13 #include <epan/packet.h>
14 #include <epan/disabled_protos.h>
15
16 #include <ui/qt/utils/variant_pointer.h>
17 #include "wireshark_application.h"
18
19 class ProtocolTreeItem : public EnabledProtocolItem
20 {
21 public:
ProtocolTreeItem(protocol_t * proto,EnabledProtocolItem * parent)22 ProtocolTreeItem(protocol_t* proto, EnabledProtocolItem* parent)
23 : EnabledProtocolItem(proto_get_protocol_short_name(proto), proto_get_protocol_long_name(proto), proto_is_protocol_enabled(proto), parent),
24 proto_(proto)
25 {
26
27 }
28
~ProtocolTreeItem()29 virtual ~ProtocolTreeItem() {}
30
31 protected:
applyValuePrivate(gboolean value)32 virtual void applyValuePrivate(gboolean value)
33 {
34 if (! proto_can_toggle_protocol(proto_get_id(proto_)) || proto_is_pino(proto_)) {
35 return;
36 }
37 proto_set_decoding(proto_get_id(proto_), value);
38 }
39
40 private:
41 protocol_t* proto_;
42 };
43
44 class HeuristicTreeItem : public EnabledProtocolItem
45 {
46 public:
HeuristicTreeItem(heur_dtbl_entry_t * heuristic,EnabledProtocolItem * parent)47 HeuristicTreeItem(heur_dtbl_entry_t *heuristic, EnabledProtocolItem* parent)
48 : EnabledProtocolItem(heuristic->short_name, heuristic->display_name, heuristic->enabled, parent),
49 heuristic_table_(heuristic)
50 {
51 type_ = EnabledProtocolItem::Heuristic;
52 }
53
~HeuristicTreeItem()54 virtual ~HeuristicTreeItem() {}
55
56 protected:
applyValuePrivate(gboolean value)57 virtual void applyValuePrivate(gboolean value)
58 {
59 heuristic_table_->enabled = value;
60 }
61
62 private:
63 heur_dtbl_entry_t *heuristic_table_;
64 };
65
66
EnabledProtocolItem(QString name,QString description,bool enabled,EnabledProtocolItem * parent)67 EnabledProtocolItem::EnabledProtocolItem(QString name, QString description, bool enabled, EnabledProtocolItem* parent) :
68 ModelHelperTreeItem<EnabledProtocolItem>(parent),
69 name_(name),
70 description_(description),
71 enabled_(enabled),
72 enabledInit_(enabled),
73 type_(EnabledProtocolItem::Standard)
74 {
75 }
76
~EnabledProtocolItem()77 EnabledProtocolItem::~EnabledProtocolItem()
78 {
79 }
80
type() const81 EnabledProtocolItem::EnableProtocolType EnabledProtocolItem::type() const
82 {
83 return type_;
84 }
85
applyValue()86 bool EnabledProtocolItem::applyValue()
87 {
88 if (enabledInit_ != enabled_) {
89 applyValuePrivate(enabled_);
90 return true;
91 }
92
93 return false;
94 }
95
96
97
98
EnabledProtocolsModel(QObject * parent)99 EnabledProtocolsModel::EnabledProtocolsModel(QObject *parent) :
100 QAbstractItemModel(parent),
101 root_(new ProtocolTreeItem(NULL, NULL))
102 {
103 }
104
~EnabledProtocolsModel()105 EnabledProtocolsModel::~EnabledProtocolsModel()
106 {
107 delete root_;
108 }
109
rowCount(const QModelIndex & parent) const110 int EnabledProtocolsModel::rowCount(const QModelIndex &parent) const
111 {
112 EnabledProtocolItem *parent_item;
113 if (parent.column() > 0)
114 return 0;
115
116 if (!parent.isValid())
117 parent_item = root_;
118 else
119 parent_item = static_cast<EnabledProtocolItem*>(parent.internalPointer());
120
121 if (parent_item == NULL)
122 return 0;
123
124 return parent_item->childCount();
125 }
126
columnCount(const QModelIndex &) const127 int EnabledProtocolsModel::columnCount(const QModelIndex&) const
128 {
129 return colLast;
130 }
131
headerData(int section,Qt::Orientation orientation,int role) const132 QVariant EnabledProtocolsModel::headerData(int section, Qt::Orientation orientation, int role) const
133 {
134 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
135
136 switch ((enum EnabledProtocolsColumn)section) {
137 case colProtocol:
138 return tr("Protocol");
139 case colDescription:
140 return tr("Description");
141 default:
142 break;
143 }
144 }
145 return QVariant();
146 }
147
parent(const QModelIndex & index) const148 QModelIndex EnabledProtocolsModel::parent(const QModelIndex& index) const
149 {
150 if (!index.isValid())
151 return QModelIndex();
152
153 EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
154 if (item != NULL) {
155 EnabledProtocolItem* parent_item = item->parentItem();
156 if (parent_item != NULL) {
157 if (parent_item == root_)
158 return QModelIndex();
159
160 return createIndex(parent_item->row(), 0, parent_item);
161 }
162 }
163
164 return QModelIndex();
165 }
166
index(int row,int column,const QModelIndex & parent) const167 QModelIndex EnabledProtocolsModel::index(int row, int column, const QModelIndex& parent) const
168 {
169 if (!hasIndex(row, column, parent))
170 return QModelIndex();
171
172 EnabledProtocolItem *parent_item, *child_item;
173
174 if (!parent.isValid())
175 parent_item = root_;
176 else
177 parent_item = static_cast<EnabledProtocolItem*>(parent.internalPointer());
178
179 Q_ASSERT(parent_item);
180
181 child_item = parent_item->child(row);
182 if (child_item) {
183 return createIndex(row, column, child_item);
184 }
185
186 return QModelIndex();
187 }
188
flags(const QModelIndex & index) const189 Qt::ItemFlags EnabledProtocolsModel::flags(const QModelIndex &index) const
190 {
191 if (!index.isValid())
192 return Qt::ItemFlags();
193
194 Qt::ItemFlags flags = QAbstractItemModel::flags(index);
195 switch(index.column())
196 {
197 case colProtocol:
198 flags |= Qt::ItemIsUserCheckable;
199 break;
200 default:
201 break;
202 }
203
204 return flags;
205 }
206
data(const QModelIndex & index,int role) const207 QVariant EnabledProtocolsModel::data(const QModelIndex &index, int role) const
208 {
209 if (!index.isValid())
210 return QVariant();
211
212 EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
213 if (item == NULL)
214 return QVariant();
215
216 switch (role)
217 {
218 case Qt::DisplayRole:
219 switch ((enum EnabledProtocolsColumn)index.column())
220 {
221 case colProtocol:
222 return item->name();
223 case colDescription:
224 return item->description();
225 default:
226 break;
227 }
228 break;
229 case Qt::CheckStateRole:
230 switch ((enum EnabledProtocolsColumn)index.column())
231 {
232 case colProtocol:
233 return item->enabled() ? Qt::Checked : Qt::Unchecked;
234 default:
235 break;
236 }
237 break;
238 case DATA_PROTOCOL_TYPE:
239 return QVariant::fromValue(item->type());
240 break;
241 default:
242 break;
243 }
244
245 return QVariant();
246 }
247
setData(const QModelIndex & index,const QVariant & value,int role)248 bool EnabledProtocolsModel::setData(const QModelIndex &index, const QVariant &value, int role)
249 {
250 if (!index.isValid())
251 return false;
252
253 if ((role != Qt::EditRole) &&
254 ((index.column() == colProtocol) && (role != Qt::CheckStateRole)))
255 return false;
256
257 if (data(index, role) == value) {
258 // Data appears unchanged, do not do additional checks.
259 return true;
260 }
261
262 EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(index.internalPointer());
263 if (item == NULL)
264 return false;
265
266 item->setEnabled(value == Qt::Checked ? true : false);
267
268 QVector<int> roles;
269 roles << role;
270
271 emit dataChanged(index, index, roles);
272
273 return true;
274 }
275
addHeuristicItem(gpointer data,gpointer user_data)276 static void addHeuristicItem(gpointer data, gpointer user_data)
277 {
278 heur_dtbl_entry_t* heur = (heur_dtbl_entry_t*)data;
279 ProtocolTreeItem* protocol_item = (ProtocolTreeItem*)user_data;
280
281 HeuristicTreeItem* heuristic_row = new HeuristicTreeItem(heur, protocol_item);
282 protocol_item->prependChild(heuristic_row);
283 }
284
populate()285 void EnabledProtocolsModel::populate()
286 {
287 void *cookie;
288 protocol_t *protocol;
289
290 emit beginResetModel();
291
292 // Iterate over all the protocols
293 for (int i = proto_get_first_protocol(&cookie); i != -1; i = proto_get_next_protocol(&cookie))
294 {
295 if (proto_can_toggle_protocol(i))
296 {
297 protocol = find_protocol_by_id(i);
298 ProtocolTreeItem* protocol_row = new ProtocolTreeItem(protocol, root_);
299 root_->prependChild(protocol_row);
300
301 proto_heuristic_dissector_foreach(protocol, addHeuristicItem, protocol_row);
302 }
303 }
304
305 emit endResetModel();
306 }
307
applyChanges(bool writeChanges)308 void EnabledProtocolsModel::applyChanges(bool writeChanges)
309 {
310 bool redissect = false;
311
312 for (int proto_index = 0; proto_index < root_->childCount(); proto_index++) {
313 EnabledProtocolItem* proto = root_->child(proto_index);
314 redissect |= proto->applyValue();
315 for (int heur_index = 0; heur_index < proto->childCount(); heur_index++) {
316 EnabledProtocolItem* heur = proto->child(heur_index);
317 redissect |= heur->applyValue();
318 }
319 }
320
321 if (redissect) {
322 saveChanges(writeChanges);
323 }
324 }
325
disableProtocol(struct _protocol * protocol)326 void EnabledProtocolsModel::disableProtocol(struct _protocol *protocol)
327 {
328 ProtocolTreeItem disabled_proto(protocol, NULL);
329 disabled_proto.setEnabled(false);
330 if (disabled_proto.applyValue()) {
331 saveChanges();
332 }
333 }
334
saveChanges(bool writeChanges)335 void EnabledProtocolsModel::saveChanges(bool writeChanges)
336 {
337 if (writeChanges) {
338 save_enabled_and_disabled_lists();
339 }
340 wsApp->emitAppSignal(WiresharkApplication::PacketDissectionChanged);
341 }
342
343
EnabledProtocolsProxyModel(QObject * parent)344 EnabledProtocolsProxyModel::EnabledProtocolsProxyModel(QObject * parent)
345 : QSortFilterProxyModel(parent),
346 type_(EnabledProtocolsProxyModel::EveryWhere),
347 protocolType_(EnabledProtocolItem::Any),
348 filter_()
349 {}
350
lessThan(const QModelIndex & left,const QModelIndex & right) const351 bool EnabledProtocolsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
352 {
353 //Use EnabledProtocolItem directly for better performance
354 EnabledProtocolItem* left_item = static_cast<EnabledProtocolItem*>(left.internalPointer());
355 EnabledProtocolItem* right_item = static_cast<EnabledProtocolItem*>(right.internalPointer());
356
357 if ((left_item != NULL) && (right_item != NULL)) {
358
359 int compare_ret = 0;
360
361 if (left.column() == EnabledProtocolsModel::colProtocol)
362 compare_ret = left_item->name().compare(right_item->name(), Qt::CaseInsensitive);
363 else if (left.column() == EnabledProtocolsModel::colDescription)
364 compare_ret = left_item->description().compare(right_item->description(), Qt::CaseInsensitive);
365
366 if (compare_ret < 0)
367 return true;
368 }
369
370 return false;
371 }
372
flags(const QModelIndex & index) const373 Qt::ItemFlags EnabledProtocolsProxyModel::flags(const QModelIndex &index) const
374 {
375 Qt::ItemFlags flags = Qt::NoItemFlags;
376 if (index.isValid())
377 {
378 QModelIndex source = mapToSource(index);
379 if (filterAcceptsSelf(source.row(), source.parent()) )
380 {
381 flags = Qt::ItemIsEnabled;
382 flags |= Qt::ItemIsSelectable;
383 flags |= Qt::ItemIsUserCheckable;
384 }
385 }
386
387 return flags;
388 }
389
filterAcceptsRow(int sourceRow,const QModelIndex & sourceParent) const390 bool EnabledProtocolsProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
391 {
392 if (filterAcceptsSelf(sourceRow, sourceParent))
393 return true;
394
395 #if 0
396 QModelIndex parent = sourceParent;
397 while (parent.isValid())
398 {
399 if (filterAcceptsSelf(parent.row(), parent.parent()))
400 return true;
401 parent = parent.parent();
402 }
403 #endif
404
405 if (filterAcceptsChild(sourceRow, sourceParent))
406 return true;
407
408 return false;
409 }
410
filterAcceptsSelf(int sourceRow,const QModelIndex & sourceParent) const411 bool EnabledProtocolsProxyModel::filterAcceptsSelf(int sourceRow, const QModelIndex &sourceParent) const
412 {
413 QModelIndex nameIdx = sourceModel()->index(sourceRow, EnabledProtocolsModel::colProtocol, sourceParent);
414 if (! nameIdx.isValid())
415 return false;
416 EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(nameIdx.internalPointer());
417 if (! item)
418 return false;
419
420 QRegExp regex(filter_, Qt::CaseInsensitive);
421
422 if ((type_ != EnabledProtocolsProxyModel::EnabledItems && type_ != EnabledProtocolsProxyModel::DisabledItems) &&
423 (protocolType_ == EnabledProtocolItem::Any || protocolType_ == item->type()) )
424 {
425 if (! filter_.isEmpty())
426 {
427 if (item->name().contains(regex) && type_ != OnlyDescription)
428 return true;
429
430 if (item->description().contains(regex) && type_ != OnlyProtocol)
431 return true;
432 }
433 else
434 return true;
435 }
436 else if (type_ == EnabledProtocolsProxyModel::EnabledItems && item->enabled())
437 return true;
438 else if (type_ == EnabledProtocolsProxyModel::DisabledItems && ! item->enabled())
439 return true;
440
441 return false;
442 }
443
filterAcceptsChild(int sourceRow,const QModelIndex & sourceParent) const444 bool EnabledProtocolsProxyModel::filterAcceptsChild(int sourceRow, const QModelIndex &sourceParent) const
445 {
446 QModelIndex item = sourceModel()->index(sourceRow, EnabledProtocolsModel::colProtocol, sourceParent);
447 if (! item.isValid())
448 return false;
449
450 int childCount = item.model()->rowCount(item);
451 if (childCount == 0)
452 return false;
453
454 for (int i = 0; i < childCount; i++)
455 {
456 if (filterAcceptsSelf(i, item))
457 return true;
458 #if 0
459 /* Recursive search disabled for performance reasons */
460 if (filterAcceptsChild(i, item))
461 return true;
462 #endif
463 }
464
465 return false;
466 }
467
setFilter(const QString & filter,EnabledProtocolsProxyModel::SearchType type,EnabledProtocolItem::EnableProtocolType protocolType)468 void EnabledProtocolsProxyModel::setFilter(const QString& filter, EnabledProtocolsProxyModel::SearchType type,
469 EnabledProtocolItem::EnableProtocolType protocolType)
470 {
471 filter_ = filter;
472 type_ = type;
473 protocolType_ = protocolType;
474 invalidateFilter();
475 }
476
setItemsEnable(EnabledProtocolsProxyModel::EnableType enableType,QModelIndex parent)477 void EnabledProtocolsProxyModel::setItemsEnable(EnabledProtocolsProxyModel::EnableType enableType, QModelIndex parent)
478 {
479 if (! sourceModel())
480 return;
481
482 if (! parent.isValid())
483 emit beginResetModel();
484
485 for (int row = 0; row < rowCount(parent); row++)
486 {
487 QModelIndex idx = index(row, EnabledProtocolsModel::colProtocol, parent);
488
489 QModelIndex sIdx = mapToSource(idx);
490 if (sIdx.isValid())
491 {
492 EnabledProtocolItem* item = static_cast<EnabledProtocolItem*>(sIdx.internalPointer());
493 if (item && (protocolType_ == EnabledProtocolItem::Any || protocolType_ == item->type()) )
494 {
495 Qt::CheckState enable = idx.data(Qt::CheckStateRole).value<Qt::CheckState>();
496 if (enableType == Enable)
497 enable = Qt::Checked;
498 else if (enableType == Disable)
499 enable = Qt::Unchecked;
500 else
501 enable = enable == Qt::Checked ? Qt::Unchecked : Qt::Checked;
502
503 sourceModel()->setData(mapToSource(idx), QVariant::fromValue(enable), Qt::CheckStateRole);
504 }
505 }
506
507 setItemsEnable(enableType, idx);
508 }
509
510
511 if (! parent.isValid())
512 emit endResetModel();
513 }
514