1 /* export_objects_model.cpp
2 * Data model for Export Objects.
3 *
4 * Wireshark - Network traffic analyzer
5 * By Gerald Combs <gerald@wireshark.org>
6 * Copyright 1998 Gerald Combs
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "export_objects_model.h"
12
13 #include <ui/qt/utils/qt_ui_utils.h>
14 #include <ui/qt/utils/variant_pointer.h>
15 #include <wsutil/filesystem.h>
16 #include <epan/prefs.h>
17
18 #include <QDir>
19
20 extern "C" {
21
22 static void
object_list_add_entry(void * gui_data,export_object_entry_t * entry)23 object_list_add_entry(void *gui_data, export_object_entry_t *entry) {
24 export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data;
25
26 if (object_list && object_list->model)
27 object_list->model->addObjectEntry(entry);
28 }
29
30 static export_object_entry_t*
object_list_get_entry(void * gui_data,int row)31 object_list_get_entry(void *gui_data, int row) {
32 export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data;
33
34 if (object_list && object_list->model)
35 return object_list->model->objectEntry(row);
36
37 return NULL;
38 }
39
40 } // extern "C"
41
42
43
44
ExportObjectModel(register_eo_t * eo,QObject * parent)45 ExportObjectModel::ExportObjectModel(register_eo_t* eo, QObject *parent) :
46 QAbstractTableModel(parent),
47 eo_(eo)
48 {
49 eo_gui_data_.model = this;
50
51 export_object_list_.add_entry = object_list_add_entry;
52 export_object_list_.get_entry = object_list_get_entry;
53 export_object_list_.gui_data = (void*)&eo_gui_data_;
54 }
55
data(const QModelIndex & index,int role) const56 QVariant ExportObjectModel::data(const QModelIndex &index, int role) const
57 {
58 if ((!index.isValid()) || ((role != Qt::DisplayRole) && (role != Qt::UserRole))) {
59 return QVariant();
60 }
61
62 if (role == Qt::DisplayRole)
63 {
64 export_object_entry_t *entry = VariantPointer<export_object_entry_t>::asPtr(objects_.value(index.row()));
65 if (entry == NULL)
66 return QVariant();
67
68 switch(index.column())
69 {
70 case colPacket:
71 return QString::number(entry->pkt_num);
72 case colHostname:
73 return entry->hostname;
74 case colContent:
75 return entry->content_type;
76 case colSize:
77 return file_size_to_qstring(entry->payload_len);
78 case colFilename:
79 return entry->filename;
80 }
81 }
82 else if (role == Qt::UserRole)
83 {
84 return objects_.value(index.row());
85 }
86
87 return QVariant();
88 }
89
headerData(int section,Qt::Orientation orientation,int role) const90 QVariant ExportObjectModel::headerData(int section, Qt::Orientation orientation, int role) const
91 {
92 if (role != Qt::DisplayRole || orientation != Qt::Horizontal)
93 return QVariant();
94
95 switch (section) {
96 case colPacket:
97 return tr("Packet");
98 case colHostname:
99 return tr("Hostname");
100 case colContent:
101 return tr("Content Type");
102 case colSize:
103 return tr("Size");
104 case colFilename:
105 return tr("Filename");
106 }
107
108 return QVariant();
109 }
110
rowCount(const QModelIndex & parent) const111 int ExportObjectModel::rowCount(const QModelIndex &parent) const
112 {
113 // there are no children
114 if (parent.isValid()) {
115 return 0;
116 }
117
118 return objects_.count();
119 }
120
columnCount(const QModelIndex &) const121 int ExportObjectModel::columnCount(const QModelIndex&) const
122 {
123 return colExportObjectMax;
124 }
125
addObjectEntry(export_object_entry_t * entry)126 void ExportObjectModel::addObjectEntry(export_object_entry_t *entry)
127 {
128 if (entry == NULL)
129 return;
130
131 int count = objects_.count();
132 beginInsertRows(QModelIndex(), count, count);
133 objects_.append(VariantPointer<export_object_entry_t>::asQVariant(entry));
134 endInsertRows();
135 }
136
objectEntry(int row)137 export_object_entry_t* ExportObjectModel::objectEntry(int row)
138 {
139 return VariantPointer<export_object_entry_t>::asPtr(objects_.value(row));
140 }
141
saveEntry(QModelIndex & index,QString filename)142 bool ExportObjectModel::saveEntry(QModelIndex &index, QString filename)
143 {
144 if (!index.isValid() || filename.isEmpty())
145 return false;
146
147 export_object_entry_t *entry = VariantPointer<export_object_entry_t>::asPtr(objects_.value(index.row()));
148 if (entry == NULL)
149 return false;
150
151 if (filename.length() > 0) {
152 write_file_binary_mode(qUtf8Printable(filename), entry->payload_data, entry->payload_len);
153 }
154
155 return true;
156 }
157
saveAllEntries(QString path)158 void ExportObjectModel::saveAllEntries(QString path)
159 {
160 if (path.isEmpty())
161 return;
162
163 QDir save_dir(path);
164 export_object_entry_t *entry;
165
166 for (QList<QVariant>::iterator it = objects_.begin(); it != objects_.end(); ++it)
167 {
168 entry = VariantPointer<export_object_entry_t>::asPtr(*it);
169 if (entry == NULL)
170 continue;
171
172 guint count = 0;
173 QString filename;
174
175 do {
176 GString *safe_filename;
177
178 if (entry->filename)
179 safe_filename = eo_massage_str(entry->filename,
180 EXPORT_OBJECT_MAXFILELEN, count);
181 else {
182 char generic_name[EXPORT_OBJECT_MAXFILELEN+1];
183 const char *ext;
184 ext = eo_ct2ext(entry->content_type);
185 g_snprintf(generic_name, sizeof(generic_name),
186 "object%u%s%s", entry->pkt_num, ext ? "." : "",
187 ext ? ext : "");
188 safe_filename = eo_massage_str(generic_name,
189 EXPORT_OBJECT_MAXFILELEN, count);
190 }
191 filename = QString::fromUtf8(safe_filename->str);
192 g_string_free(safe_filename, TRUE);
193 } while (save_dir.exists(filename) && ++count < prefs.gui_max_export_objects);
194 write_file_binary_mode(qUtf8Printable(save_dir.filePath(filename)),
195 entry->payload_data, entry->payload_len);
196 }
197 }
198
resetObjects()199 void ExportObjectModel::resetObjects()
200 {
201 export_object_gui_reset_cb reset_cb = get_eo_reset_func(eo_);
202
203 emit beginResetModel();
204 objects_.clear();
205 emit endResetModel();
206
207 if (reset_cb)
208 reset_cb();
209 }
210
211 // Called by taps
212 /* Runs at the beginning of tapping only */
resetTap(void * tapdata)213 void ExportObjectModel::resetTap(void *tapdata)
214 {
215 export_object_list_t *tap_object = (export_object_list_t *)tapdata;
216 export_object_list_gui_t *object_list = (export_object_list_gui_t *)tap_object->gui_data;
217 if (object_list && object_list->model)
218 object_list->model->resetObjects();
219 }
220
getTapListenerName()221 const char* ExportObjectModel::getTapListenerName()
222 {
223 return get_eo_tap_listener_name(eo_);
224 }
225
getTapData()226 void* ExportObjectModel::getTapData()
227 {
228 return &export_object_list_;
229 }
230
getTapPacketFunc()231 tap_packet_cb ExportObjectModel::getTapPacketFunc()
232 {
233 return get_eo_packet_func(eo_);
234 }
235
removeTap()236 void ExportObjectModel::removeTap()
237 {
238 eo_gui_data_.model = NULL;
239 }
240
241
242
ExportObjectProxyModel(QObject * parent)243 ExportObjectProxyModel::ExportObjectProxyModel(QObject * parent)
244 : QSortFilterProxyModel(parent)
245 {
246
247 }
248
lessThan(const QModelIndex & source_left,const QModelIndex & source_right) const249 bool ExportObjectProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
250 {
251 export_object_entry_t *left_entry = VariantPointer<export_object_entry_t>::asPtr(sourceModel()->data(source_left, Qt::UserRole)),
252 *right_entry = VariantPointer<export_object_entry_t>::asPtr(sourceModel()->data(source_right, Qt::UserRole));
253
254 if ((left_entry != NULL) && (right_entry != NULL))
255 {
256 switch (source_left.column())
257 {
258 case ExportObjectModel::colPacket:
259 return left_entry->pkt_num < right_entry->pkt_num;
260 case ExportObjectModel::colSize:
261 return left_entry->payload_len < right_entry->payload_len;
262 case ExportObjectModel::colFilename:
263 break;
264 }
265 }
266
267 return QSortFilterProxyModel::lessThan(source_left, source_right);
268 }
269
setContentFilterString(QString filter_)270 void ExportObjectProxyModel::setContentFilterString(QString filter_)
271 {
272 contentFilter_ = filter_;
273 invalidateFilter();
274 }
275
setTextFilterString(QString filter_)276 void ExportObjectProxyModel::setTextFilterString(QString filter_)
277 {
278 textFilter_ = filter_;
279 invalidateFilter();
280 }
281
filterAcceptsRow(int source_row,const QModelIndex &) const282 bool ExportObjectProxyModel::filterAcceptsRow(int source_row, const QModelIndex &/*source_parent*/) const
283 {
284 if (contentFilter_.length() > 0)
285 {
286 QModelIndex idx = sourceModel()->index(source_row, ExportObjectModel::colContent);
287 if (!idx.isValid())
288 return false;
289
290 if (contentFilter_.compare(idx.data().toString()) != 0)
291 return false;
292 }
293
294 if (textFilter_.length() > 0)
295 {
296 QModelIndex hostIdx = sourceModel()->index(source_row, ExportObjectModel::colHostname);
297 QModelIndex fileIdx = sourceModel()->index(source_row, ExportObjectModel::colFilename);
298 if (!hostIdx.isValid() || !fileIdx.isValid())
299 return false;
300
301 QString host = hostIdx.data().toString();
302 QString file = fileIdx.data().toString();
303
304 if (!host.contains(textFilter_) && !file.contains(textFilter_))
305 return false;
306 }
307
308 return true;
309 }
310