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