1 /* expert_info_model.cpp
2 * Data model for Expert Info tap data.
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 "expert_info_model.h"
12
13 #include "file.h"
14
ExpertPacketItem(const expert_info_t & expert_info,column_info * cinfo,ExpertPacketItem * parent)15 ExpertPacketItem::ExpertPacketItem(const expert_info_t& expert_info, column_info *cinfo, ExpertPacketItem* parent) :
16 packet_num_(expert_info.packet_num),
17 group_(expert_info.group),
18 severity_(expert_info.severity),
19 hf_id_(expert_info.hf_index),
20 protocol_(expert_info.protocol),
21 summary_(expert_info.summary),
22 parentItem_(parent)
23 {
24 if (cinfo) {
25 info_ = col_get_text(cinfo, COL_INFO);
26 }
27 }
28
~ExpertPacketItem()29 ExpertPacketItem::~ExpertPacketItem()
30 {
31 for (int row = 0; row < childItems_.count(); row++)
32 {
33 delete childItems_.value(row);
34 }
35
36 childItems_.clear();
37 }
38
groupKey(bool group_by_summary,int severity,int group,QString protocol,int expert_hf)39 QString ExpertPacketItem::groupKey(bool group_by_summary, int severity, int group, QString protocol, int expert_hf)
40 {
41 QString key = QString("%1|%2|%3")
42 .arg(severity)
43 .arg(group)
44 .arg(protocol);
45 if (group_by_summary) {
46 key += QString("|%1").arg(expert_hf);
47 }
48 return key;
49 }
50
groupKey(bool group_by_summary)51 QString ExpertPacketItem::groupKey(bool group_by_summary) {
52 return groupKey(group_by_summary, severity_, group_, protocol_, hf_id_);
53 }
54
appendChild(ExpertPacketItem * child,QString hash)55 void ExpertPacketItem::appendChild(ExpertPacketItem* child, QString hash)
56 {
57 childItems_.append(child);
58 hashChild_[hash] = child;
59 }
60
child(int row)61 ExpertPacketItem* ExpertPacketItem::child(int row)
62 {
63 return childItems_.value(row);
64 }
65
child(QString hash)66 ExpertPacketItem* ExpertPacketItem::child(QString hash)
67 {
68 return hashChild_[hash];
69 }
70
childCount() const71 int ExpertPacketItem::childCount() const
72 {
73 return childItems_.count();
74 }
75
row() const76 int ExpertPacketItem::row() const
77 {
78 if (parentItem_)
79 return parentItem_->childItems_.indexOf(const_cast<ExpertPacketItem*>(this));
80
81 return 0;
82 }
83
parentItem()84 ExpertPacketItem* ExpertPacketItem::parentItem()
85 {
86 return parentItem_;
87 }
88
89
90
91
ExpertInfoModel(CaptureFile & capture_file,QObject * parent)92 ExpertInfoModel::ExpertInfoModel(CaptureFile& capture_file, QObject *parent) :
93 QAbstractItemModel(parent),
94 capture_file_(capture_file),
95 group_by_summary_(true),
96 root_(createRootItem())
97 {
98 }
99
~ExpertInfoModel()100 ExpertInfoModel::~ExpertInfoModel()
101 {
102 delete root_;
103 }
104
clear()105 void ExpertInfoModel::clear()
106 {
107 emit beginResetModel();
108
109 eventCounts_.clear();
110 delete root_;
111 root_ = createRootItem();
112
113 emit endResetModel();
114 }
115
createRootItem()116 ExpertPacketItem* ExpertInfoModel::createRootItem()
117 {
118 static const char* rootName = "ROOT";
119 DIAG_OFF_CAST_AWAY_CONST
120 static expert_info_t root_expert = { 0, -1, -1, -1, rootName, (gchar*)rootName, NULL };
121 DIAG_ON_CAST_AWAY_CONST
122
123 return new ExpertPacketItem(root_expert, NULL, NULL);
124 }
125
126
127
numEvents(enum ExpertSeverity severity)128 int ExpertInfoModel::numEvents(enum ExpertSeverity severity)
129 {
130 return eventCounts_[severity];
131 }
132
index(int row,int column,const QModelIndex & parent) const133 QModelIndex ExpertInfoModel::index(int row, int column, const QModelIndex& parent) const
134 {
135 if (!hasIndex(row, column, parent))
136 return QModelIndex();
137
138 ExpertPacketItem *parent_item, *child_item;
139
140 if (!parent.isValid())
141 parent_item = root_;
142 else
143 parent_item = static_cast<ExpertPacketItem*>(parent.internalPointer());
144
145 Q_ASSERT(parent_item);
146 if (group_by_summary_) {
147 //don't allow group layer
148 if (parent_item == root_) {
149 int row_count = 0;
150 ExpertPacketItem *grandchild_item;
151
152 for (int subrow = 0; subrow < parent_item->childCount(); subrow++) {
153 child_item = parent_item->child(subrow);
154 //summary children are always stored in first child of group
155 grandchild_item = child_item->child(0);
156
157 if (row_count+grandchild_item->childCount() > row) {
158 return createIndex(row, column, grandchild_item->child(row-row_count));
159 }
160 row_count += grandchild_item->childCount();
161 }
162
163 //shouldn't happen
164 return QModelIndex();
165 }
166
167 int root_level = 0;
168 ExpertPacketItem *item = parent_item;
169 while (item != root_)
170 {
171 root_level++;
172 item = item->parentItem();
173 }
174
175 if (root_level == 3) {
176 child_item = parent_item->child(row);
177 if (child_item) {
178 return createIndex(row, column, child_item);
179 }
180 }
181
182 } else {
183 child_item = parent_item->child(row);
184 if (child_item) {
185 //only allow 2 levels deep
186 if (((parent_item == root_) || (parent_item->parentItem() == root_)))
187 return createIndex(row, column, child_item);
188 }
189 }
190 return QModelIndex();
191 }
192
parent(const QModelIndex & index) const193 QModelIndex ExpertInfoModel::parent(const QModelIndex& index) const
194 {
195 if (!index.isValid())
196 return QModelIndex();
197
198 ExpertPacketItem *item = static_cast<ExpertPacketItem*>(index.internalPointer());
199 ExpertPacketItem *parent_item = item->parentItem();
200
201 if (group_by_summary_)
202 {
203 //don't allow group layer
204 int root_level = 0;
205 item = parent_item;
206 while ((item != root_) && (item != NULL))
207 {
208 root_level++;
209 item = item->parentItem();
210 }
211
212 if (root_level == 3)
213 return createIndex(parent_item->row(), 0, parent_item);
214
215 } else {
216 if (parent_item == root_)
217 return QModelIndex();
218
219 return createIndex(parent_item->row(), 0, parent_item);
220 }
221
222 return QModelIndex();
223 }
224
225 #if 0
226 Qt::ItemFlags ExpertInfoModel::flags(const QModelIndex &index) const
227 {
228 if (!index.isValid())
229 return 0;
230
231 ExpertPacketItem* item = static_cast<ExpertPacketItem*>(index.internalPointer());
232 Qt::ItemFlags flags = QAbstractTableModel::flags(index);
233
234 //collapse???
235 return flags;
236 }
237 #endif
238
data(const QModelIndex & index,int role) const239 QVariant ExpertInfoModel::data(const QModelIndex &index, int role) const
240 {
241 if (!index.isValid() || role != Qt::DisplayRole)
242 return QVariant();
243
244 ExpertPacketItem* item = static_cast<ExpertPacketItem*>(index.internalPointer());
245 if (item == NULL)
246 return QVariant();
247
248 switch ((enum ExpertColumn)index.column()) {
249 case colSeverity:
250 return QString(val_to_str_const(item->severity(), expert_severity_vals, "Unknown"));
251 case colSummary:
252 if (index.parent().isValid())
253 {
254 if (item->severity() == PI_COMMENT)
255 return item->summary().simplified();
256 if (group_by_summary_)
257 return item->colInfo().simplified();
258
259 return item->summary().simplified();
260 }
261 else
262 {
263 if (group_by_summary_)
264 {
265 if (item->severity() == PI_COMMENT)
266 return "Packet comments listed below.";
267 return item->summary().simplified();
268 }
269 }
270 return QVariant();
271 case colGroup:
272 return QString(val_to_str_const(item->group(), expert_group_vals, "Unknown"));
273 case colProtocol:
274 return item->protocol();
275 case colCount:
276 if (!index.parent().isValid())
277 {
278 return item->childCount();
279 }
280 break;
281 case colPacket:
282 return item->packetNum();
283 case colHf:
284 return item->hfId();
285 default:
286 break;
287 }
288
289 return QVariant();
290 }
291
292 //GUI helpers
setGroupBySummary(bool group_by_summary)293 void ExpertInfoModel::setGroupBySummary(bool group_by_summary)
294 {
295 emit beginResetModel();
296 group_by_summary_ = group_by_summary;
297 emit endResetModel();
298 }
299
rowCount(const QModelIndex & parent) const300 int ExpertInfoModel::rowCount(const QModelIndex &parent) const
301 {
302 ExpertPacketItem *parent_item;
303 if (parent.column() > 0)
304 return 0;
305
306 if (!parent.isValid())
307 parent_item = root_;
308 else
309 parent_item = static_cast<ExpertPacketItem*>(parent.internalPointer());
310
311 if (group_by_summary_) {
312 int row_count = 0;
313
314 //don't allow group layer
315 if (parent_item == root_) {
316 ExpertPacketItem *child_item, *grandchild_item;
317
318 for (int row = 0; row < parent_item->childCount(); row++) {
319 child_item = parent_item->child(row);
320 grandchild_item = child_item->child(0);
321 row_count += grandchild_item->childCount();
322 }
323
324 return row_count;
325 }
326
327 return parent_item->childCount();
328
329 } else {
330 //only allow 2 levels deep
331 if ((parent_item == root_) || (parent_item->parentItem() == root_))
332 return parent_item->childCount();
333 }
334
335 return 0;
336 }
337
columnCount(const QModelIndex &) const338 int ExpertInfoModel::columnCount(const QModelIndex&) const
339 {
340 return colLast;
341 }
342
addExpertInfo(const struct expert_info_s & expert_info)343 void ExpertInfoModel::addExpertInfo(const struct expert_info_s& expert_info)
344 {
345 QString groupKey = ExpertPacketItem::groupKey(FALSE, expert_info.severity, expert_info.group, QString(expert_info.protocol), expert_info.hf_index);
346 QString summaryKey = ExpertPacketItem::groupKey(TRUE, expert_info.severity, expert_info.group, QString(expert_info.protocol), expert_info.hf_index);
347
348 ExpertPacketItem* expert_root = root_->child(groupKey);
349 if (expert_root == NULL) {
350 ExpertPacketItem *new_item = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), root_);
351
352 root_->appendChild(new_item, groupKey);
353
354 expert_root = new_item;
355 }
356
357 ExpertPacketItem *expert = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), expert_root);
358 expert_root->appendChild(expert, groupKey);
359
360 //add the summary children off of the first child of the root children
361 ExpertPacketItem* summary_root = expert_root->child(0);
362
363 //make a summary child
364 ExpertPacketItem* expert_summary_root = summary_root->child(summaryKey);
365 if (expert_summary_root == NULL) {
366 ExpertPacketItem *new_summary = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), summary_root);
367
368 summary_root->appendChild(new_summary, summaryKey);
369 expert_summary_root = new_summary;
370 }
371
372 ExpertPacketItem *expert_summary = new ExpertPacketItem(expert_info, &(capture_file_.capFile()->cinfo), expert_summary_root);
373 expert_summary_root->appendChild(expert_summary, summaryKey);
374 }
375
tapReset(void * eid_ptr)376 void ExpertInfoModel::tapReset(void *eid_ptr)
377 {
378 ExpertInfoModel *model = static_cast<ExpertInfoModel*>(eid_ptr);
379 if (!model)
380 return;
381
382 model->clear();
383 }
384
tapPacket(void * eid_ptr,struct _packet_info * pinfo,struct epan_dissect *,const void * data)385 tap_packet_status ExpertInfoModel::tapPacket(void *eid_ptr, struct _packet_info *pinfo, struct epan_dissect *, const void *data)
386 {
387 ExpertInfoModel *model = static_cast<ExpertInfoModel*>(eid_ptr);
388 const expert_info_t *expert_info = (const expert_info_t *) data;
389 tap_packet_status status = TAP_PACKET_DONT_REDRAW;
390
391 if (!pinfo || !model || !expert_info)
392 return TAP_PACKET_DONT_REDRAW;
393
394 model->addExpertInfo(*expert_info);
395
396 if (model->numEvents((enum ExpertSeverity)expert_info->severity) < 1)
397 status = TAP_PACKET_REDRAW;
398
399 model->eventCounts_[(enum ExpertSeverity)expert_info->severity]++;
400
401 return status;
402 }
403
tapDraw(void * eid_ptr)404 void ExpertInfoModel::tapDraw(void *eid_ptr)
405 {
406 ExpertInfoModel *model = static_cast<ExpertInfoModel*>(eid_ptr);
407 if (!model)
408 return;
409
410 emit model->beginResetModel();
411 emit model->endResetModel();
412 }
413