Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / qt / models / interface_tree_cache_model.cpp
blobc14f7385e5f8b146eb6163dc23aede41aa733c96
1 /* interface_tree_cache_model.cpp
2 * Model caching interface changes before sending them to global storage
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
12 #include <ui/qt/models/interface_tree_cache_model.h>
14 #include "epan/prefs.h"
16 #include <ui/qt/utils/qt_ui_utils.h>
17 #include "ui/capture_globals.h"
18 #include "wsutil/utf8_entities.h"
20 #include "wiretap/wtap.h"
22 #include "main_application.h"
24 #include <QIdentityProxyModel>
26 InterfaceTreeCacheModel::InterfaceTreeCacheModel(QObject *parent) :
27 QIdentityProxyModel(parent)
29 /* ATTENTION: This cache model is not intended to be used with anything
30 * else then InterfaceTreeModel, and will break with anything else
31 * leading to unintended results. */
32 sourceModel = new InterfaceTreeModel(parent);
34 QIdentityProxyModel::setSourceModel(sourceModel);
35 storage = new QMap<int, QSharedPointer<QMap<InterfaceTreeColumns, QVariant> > >();
37 checkableColumns << IFTREE_COL_HIDDEN << IFTREE_COL_PROMISCUOUSMODE;
38 #ifdef HAVE_PCAP_CREATE
39 checkableColumns << IFTREE_COL_MONITOR_MODE;
40 #endif
42 editableColumns << IFTREE_COL_COMMENT << IFTREE_COL_SNAPLEN << IFTREE_COL_PIPE_PATH;
44 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
45 editableColumns << IFTREE_COL_BUFFERLEN;
46 #endif
49 InterfaceTreeCacheModel::~InterfaceTreeCacheModel()
51 #ifdef HAVE_LIBPCAP
52 /* This list should only exist, if the dialog is closed, without calling save first */
53 newDevices.clear();
54 #endif
56 delete storage;
57 delete sourceModel;
60 QVariant InterfaceTreeCacheModel::getColumnContent(int idx, int col, int role)
62 return InterfaceTreeCacheModel::data(index(idx, col), role);
65 #ifdef HAVE_LIBPCAP
66 void InterfaceTreeCacheModel::reset(int row)
68 if (row < 0)
70 storage->clear();
72 else
74 if (storage->count() > row)
75 storage->remove(storage->keys().at(row));
79 void InterfaceTreeCacheModel::saveNewDevices()
81 QList<interface_t>::const_iterator it = newDevices.constBegin();
82 /* idx is used for iterating only over the indices of the new devices. As all new
83 * devices are stored with an index higher then sourceModel->rowCount(), we start
84 * only with those storage indices.
85 * it is just the iterator over the new devices. A new device must not necessarily
86 * have storage, which will lead to that device not being stored in global_capture_opts */
87 for (int idx = sourceModel->rowCount(); it != newDevices.constEnd(); ++it, idx++)
89 interface_t *device = const_cast<interface_t *>(&(*it));
90 bool useDevice = false;
92 QSharedPointer<QMap<InterfaceTreeColumns, QVariant> > dataField = storage->value(idx, 0);
93 /* When devices are being added, they are added using generic values. So only devices
94 * whose data have been changed should be used from here on out. */
95 if (dataField != 0)
97 if (device->if_info.type != IF_PIPE)
99 continue;
102 if (device->if_info.type == IF_PIPE)
104 QVariant saveValue = dataField->value(IFTREE_COL_PIPE_PATH);
105 if (saveValue.isValid())
107 g_free(device->if_info.name);
108 device->if_info.name = qstring_strdup(saveValue.toString());
110 g_free(device->name);
111 device->name = qstring_strdup(saveValue.toString());
113 g_free(device->display_name);
114 device->display_name = qstring_strdup(saveValue.toString());
115 useDevice = true;
119 if (useDevice)
120 g_array_append_val(global_capture_opts.all_ifaces, *device);
124 /* All entries of this new devices have been considered */
125 storage->remove(idx);
128 newDevices.clear();
131 void InterfaceTreeCacheModel::save()
133 if (storage->count() == 0)
134 return;
136 QMap<char**, QStringList> prefStorage;
138 /* No devices are hidden until checking "Show" state */
139 prefStorage[&prefs.capture_devices_hide] = QStringList();
141 /* Some of the columns we only add entries to the QStringList for
142 * interfaces that have a non-default value, so we need to ensure
143 * that we set the pref string to empty if no interface is set.
145 prefStorage[&prefs.capture_devices_descr] = QStringList();
146 prefStorage[&prefs.capture_devices_monitor_mode] << QStringList();
148 /* Storing new devices first including their changed values */
149 saveNewDevices();
152 for (unsigned int idx = 0; idx < global_capture_opts.all_ifaces->len; idx++)
154 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
156 if (! device->name)
157 continue;
159 /* Try to load a saved value row for this index */
160 QSharedPointer<QMap<InterfaceTreeColumns, QVariant> > dataField = storage->value(idx, 0);
162 /* Handle the storing of values for this device here */
163 if (dataField)
165 QMap<InterfaceTreeColumns, QVariant>::const_iterator it = dataField->constBegin();
166 while (it != dataField->constEnd())
168 InterfaceTreeColumns col = it.key();
169 QVariant saveValue = it.value();
171 /* Setting the field values for each individual saved value cannot be generic, as the
172 * struct cannot be accessed in a generic way. Therefore below, each individually changed
173 * value has to be handled separately. Comments are stored only in the preference file
174 * and applied to the data name during loading. Therefore comments are not handled here */
176 if (col == IFTREE_COL_HIDDEN)
178 /* Hidden is de-selection, therefore inverted logic here */
179 device->hidden = (saveValue == Qt::Unchecked);
181 else if (device->if_info.type == IF_EXTCAP)
183 /* extcap interfaces do not have the following columns.
184 * ATTENTION: all generic columns must be added, BEFORE this
185 * if-clause, or they will be ignored for extcap interfaces */
187 else if (col == IFTREE_COL_PROMISCUOUSMODE)
189 device->pmode = saveValue.toBool();
191 #ifdef HAVE_PCAP_CREATE
192 else if (col == IFTREE_COL_MONITOR_MODE)
194 device->monitor_mode_enabled = saveValue.toBool();
196 #endif
197 else if (col == IFTREE_COL_SNAPLEN)
199 int iVal = saveValue.toInt();
200 if (iVal != WTAP_MAX_PACKET_SIZE_STANDARD)
202 device->has_snaplen = true;
203 device->snaplen = iVal;
205 else
207 device->has_snaplen = false;
208 device->snaplen = WTAP_MAX_PACKET_SIZE_STANDARD;
211 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
212 else if (col == IFTREE_COL_BUFFERLEN)
214 device->buffer = saveValue.toInt();
216 #endif
217 ++it;
221 QVariant content = getColumnContent(idx, IFTREE_COL_HIDDEN, Qt::CheckStateRole);
222 if (content.isValid() && static_cast<Qt::CheckState>(content.toInt()) == Qt::Unchecked)
223 prefStorage[&prefs.capture_devices_hide] << QString(device->name);
225 content = getColumnContent(idx, IFTREE_COL_COMMENT);
226 if (content.isValid() && content.toString().size() > 0)
227 prefStorage[&prefs.capture_devices_descr] << QStringLiteral("%1(%2)").arg(device->name).arg(content.toString());
229 bool allowExtendedColumns = true;
231 if (device->if_info.type == IF_EXTCAP)
232 allowExtendedColumns = false;
234 if (allowExtendedColumns)
236 content = getColumnContent(idx, IFTREE_COL_PROMISCUOUSMODE, Qt::CheckStateRole);
237 if (content.isValid())
239 bool value = static_cast<Qt::CheckState>(content.toInt()) == Qt::Checked;
240 prefStorage[&prefs.capture_devices_pmode] << QStringLiteral("%1(%2)").arg(device->name).arg(value ? 1 : 0);
243 #ifdef HAVE_PCAP_CREATE
244 content = getColumnContent(idx, IFTREE_COL_MONITOR_MODE, Qt::CheckStateRole);
245 if (content.isValid() && static_cast<Qt::CheckState>(content.toInt()) == Qt::Checked)
246 prefStorage[&prefs.capture_devices_monitor_mode] << QString(device->name);
247 #endif
249 content = getColumnContent(idx, IFTREE_COL_SNAPLEN);
250 if (content.isValid())
252 int value = content.toInt();
253 prefStorage[&prefs.capture_devices_snaplen] <<
254 QStringLiteral("%1:%2(%3)").arg(device->name).
255 arg(device->has_snaplen ? 1 : 0).
256 arg(device->has_snaplen ? value : WTAP_MAX_PACKET_SIZE_STANDARD);
259 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
260 content = getColumnContent(idx, IFTREE_COL_BUFFERLEN);
261 if (content.isValid())
263 int value = content.toInt();
264 if (value != -1)
266 prefStorage[&prefs.capture_devices_buffersize] <<
267 QStringLiteral("%1(%2)").arg(device->name).
268 arg(value);
271 #endif
275 QMap<char**, QStringList>::const_iterator it = prefStorage.constBegin();
276 while (it != prefStorage.constEnd())
278 char ** key = it.key();
280 g_free(*key);
281 *key = qstring_strdup(it.value().join(","));
283 ++it;
286 mainApp->emitAppSignal(MainApplication::LocalInterfacesChanged);
288 #endif
290 int InterfaceTreeCacheModel::rowCount(const QModelIndex & parent) const
292 int totalCount = sourceModel->rowCount(parent);
293 #ifdef HAVE_LIBPCAP
294 totalCount += newDevices.size();
295 #endif
296 return totalCount;
299 bool InterfaceTreeCacheModel::changeIsAllowed(InterfaceTreeColumns col) const
301 if (editableColumns.contains(col) || checkableColumns.contains(col))
302 return true;
303 return false;
306 #ifdef HAVE_LIBPCAP
307 const interface_t * InterfaceTreeCacheModel::lookup(const QModelIndex &index) const
309 const interface_t * result = 0;
311 if (! index.isValid() || ! global_capture_opts.all_ifaces)
312 return result;
314 int idx = index.row();
316 if ((unsigned int) idx >= global_capture_opts.all_ifaces->len)
318 idx = idx - global_capture_opts.all_ifaces->len;
319 if (idx < newDevices.size())
320 result = &newDevices[idx];
322 else
324 result = &g_array_index(global_capture_opts.all_ifaces, interface_t, idx);
327 return result;
329 #endif
331 /* This checks if the column can be edited for the given index. This differs from
332 * isAvailableField in such a way, that it is only used in flags and not any
333 * other method.*/
334 bool InterfaceTreeCacheModel::isAllowedToBeEdited(const QModelIndex &index) const
336 #ifndef HAVE_LIBPCAP
337 Q_UNUSED(index);
338 #else
339 const interface_t * device = lookup(index);
340 if (device == 0)
341 return false;
343 InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
344 if (device->if_info.type == IF_EXTCAP)
346 /* extcap interfaces do not have those settings */
347 if (col == IFTREE_COL_PROMISCUOUSMODE || col == IFTREE_COL_SNAPLEN)
348 return false;
349 #ifdef CAN_SET_CAPTURE_BUFFER_SIZE
350 if (col == IFTREE_COL_BUFFERLEN)
351 return false;
352 #endif
354 #endif
355 return true;
358 // Whether this field is available for modification and display.
359 bool InterfaceTreeCacheModel::isAvailableField(const QModelIndex &index) const
361 #ifndef HAVE_LIBPCAP
362 Q_UNUSED(index);
363 #else
364 const interface_t * device = lookup(index);
366 if (device == 0)
367 return false;
369 InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
370 if (col == IFTREE_COL_HIDDEN)
372 // Do not allow default capture interface to be hidden.
373 if (! g_strcmp0(prefs.capture_device, device->display_name))
374 return false;
376 #endif
378 return true;
381 Qt::ItemFlags InterfaceTreeCacheModel::flags(const QModelIndex &index) const
383 if (! index.isValid())
384 return Qt::ItemFlags();
386 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
388 InterfaceTreeColumns col = (InterfaceTreeColumns) index.column();
390 if (changeIsAllowed(col) && isAvailableField(index) && isAllowedToBeEdited(index))
392 if (checkableColumns.contains(col))
394 flags |= Qt::ItemIsUserCheckable;
396 else
398 flags |= Qt::ItemIsEditable;
402 return flags;
405 bool InterfaceTreeCacheModel::setData(const QModelIndex &index, const QVariant &value, int role)
407 if (! index.isValid())
408 return false;
410 if (! isAvailableField(index))
411 return false;
413 int row = index.row();
414 InterfaceTreeColumns col = (InterfaceTreeColumns)index.column();
416 if (role == Qt::CheckStateRole || role == Qt::EditRole)
418 if (changeIsAllowed(col) )
420 QVariant saveValue = value;
422 QSharedPointer<QMap<InterfaceTreeColumns, QVariant> > dataField = nullptr;
423 /* obtain the list of already stored changes for this row. If none exist
424 * create a new storage row for this entry */
425 if ((dataField = storage->value(row, 0)) == nullptr)
427 dataField = QSharedPointer<QMap<InterfaceTreeColumns, QVariant> >(new QMap<InterfaceTreeColumns, QVariant>);
428 storage->insert(row, dataField);
431 dataField->insert(col, saveValue);
433 return true;
437 return false;
440 QVariant InterfaceTreeCacheModel::data(const QModelIndex &index, int role) const
442 if (! index.isValid())
443 return QVariant();
445 int row = index.row();
447 InterfaceTreeColumns col = (InterfaceTreeColumns)index.column();
449 if (isAvailableField(index) && isAllowedToBeEdited(index))
451 if (((role == Qt::DisplayRole || role == Qt::EditRole) && editableColumns.contains(col)) ||
452 (role == Qt::CheckStateRole && checkableColumns.contains(col)) )
454 QSharedPointer<QMap<InterfaceTreeColumns, QVariant> > dataField = nullptr;
455 if ((dataField = storage->value(row, 0)) != nullptr)
457 if (dataField->contains(col))
459 return dataField->value(col, QVariant());
464 else
466 if (role == Qt::CheckStateRole)
467 return QVariant();
468 else if (role == Qt::DisplayRole)
469 return QString(UTF8_EM_DASH);
472 if (row < sourceModel->rowCount())
474 return sourceModel->data(index, role);
476 #ifdef HAVE_LIBPCAP
477 else
479 /* Handle all fields, which will have to be displayed for new devices. Only pipes
480 * are supported at the moment, so the information to be displayed is pretty limited.
481 * After saving, the devices are stored in global_capture_opts and no longer
482 * classify as new devices. */
483 const interface_t * device = lookup(index);
485 if (device != 0)
487 if (role == Qt::DisplayRole || role == Qt::EditRole)
489 if (col == IFTREE_COL_PIPE_PATH ||
490 col == IFTREE_COL_NAME ||
491 col == IFTREE_COL_DESCRIPTION)
494 QSharedPointer<QMap<InterfaceTreeColumns, QVariant> > dataField = nullptr;
495 if ((dataField = storage->value(row, 0)) != nullptr &&
496 dataField->contains(IFTREE_COL_PIPE_PATH))
498 return dataField->value(IFTREE_COL_PIPE_PATH, QVariant());
500 else
501 return QString(device->name);
503 else if (col == IFTREE_COL_TYPE)
505 return QVariant::fromValue((int)device->if_info.type);
508 else if (role == Qt::CheckStateRole)
510 if (col == IFTREE_COL_HIDDEN)
512 // Do not allow default capture interface to be hidden.
513 if (! g_strcmp0(prefs.capture_device, device->display_name))
514 return QVariant();
516 /* Hidden is a de-selection, therefore inverted logic here */
517 return device->hidden ? Qt::Unchecked : Qt::Checked;
522 #endif
524 return QVariant();
527 #ifdef HAVE_PCAP_REMOTE
528 bool InterfaceTreeCacheModel::isRemote(const QModelIndex &index) const
530 const interface_t *device = lookup(index);
531 if (device != nullptr && device->remote_opts.src_type == CAPTURE_IFREMOTE) {
532 return true;
534 return false;
536 #endif
538 #ifdef HAVE_LIBPCAP
539 QModelIndex InterfaceTreeCacheModel::index(int row, int column, const QModelIndex &parent) const
541 if (row >= sourceModel->rowCount() && (row - sourceModel->rowCount()) < newDevices.count())
543 return createIndex(row, column, (void *)0);
546 return QIdentityProxyModel::index(row, column, parent);
549 void InterfaceTreeCacheModel::addDevice(const interface_t * newDevice)
551 emit beginInsertRows(QModelIndex(), rowCount(), rowCount());
552 newDevices << *newDevice;
553 emit endInsertRows();
556 void InterfaceTreeCacheModel::deleteDevice(const QModelIndex &index)
558 if (! index.isValid())
559 return;
561 emit beginRemoveRows(QModelIndex(), index.row(), index.row());
563 int row = index.row();
565 /* device is in newDevices */
566 if (row >= sourceModel->rowCount())
568 int newDeviceIdx = row - sourceModel->rowCount();
570 newDevices.removeAt(newDeviceIdx);
571 if (storage->contains(index.row()))
572 storage->remove(index.row());
574 /* The storage array has to be resorted, if the index, that was removed
575 * had been in the middle of the array. Can't start at index.row(), as
576 * it may not be contained in storage
577 * We must iterate using a list, not an iterator, otherwise the change
578 * will fold on itself. */
579 QList<int> storageKeys = storage->keys();
580 for (int i = 0; i < storageKeys.size(); ++i)
582 int key = storageKeys.at(i);
583 if (key > index.row())
585 storage->insert(key - 1, storage->value(key));
586 storage->remove(key);
590 emit endRemoveRows();
592 else
594 interface_t *device = &g_array_index(global_capture_opts.all_ifaces, interface_t, row);
595 capture_opts_free_interface_t(device);
596 global_capture_opts.all_ifaces = g_array_remove_index(global_capture_opts.all_ifaces, row);
597 emit endRemoveRows();
598 mainApp->emitAppSignal(MainApplication::LocalInterfacesChanged);
601 #endif