1 /* capture_file_properties_dialog.cpp
2  *
3  * GSoC 2013 - QtShark
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * SPDX-License-Identifier: GPL-2.0-or-later
10  */
11 
12 #include "capture_file_properties_dialog.h"
13 #include <ui_capture_file_properties_dialog.h>
14 
15 #include "ui/summary.h"
16 
17 #include "wsutil/str_util.h"
18 #include "wsutil/utf8_entities.h"
19 #include "ui/version_info.h"
20 
21 #include <ui/qt/utils/qt_ui_utils.h>
22 #include "wireshark_application.h"
23 
24 #include <QPushButton>
25 #include <QScrollBar>
26 #include <QTextStream>
27 
28 // To do:
29 // - Add file hashes
30 // - Add formats (HTML, plain text, YAML)?
31 
CaptureFilePropertiesDialog(QWidget & parent,CaptureFile & capture_file)32 CaptureFilePropertiesDialog::CaptureFilePropertiesDialog(QWidget &parent, CaptureFile &capture_file) :
33     WiresharkDialog(parent, capture_file),
34     ui(new Ui::CaptureFilePropertiesDialog)
35 {
36     ui->setupUi(this);
37     loadGeometry(parent.width() * 2 / 3, parent.height());
38 
39     ui->detailsTextEdit->setAcceptRichText(true);
40 
41     // make the details box larger than the comments
42     ui->splitter->setStretchFactor(0, 6);
43     ui->splitter->setStretchFactor(1, 1);
44 
45     QPushButton *button = ui->buttonBox->button(QDialogButtonBox::Reset);
46     if (button) {
47         button->setText(tr("Refresh"));
48     }
49 
50     button = ui->buttonBox->button(QDialogButtonBox::Apply);
51     if (button) {
52         button->setText(tr("Copy To Clipboard"));
53     }
54 
55     button = ui->buttonBox->button(QDialogButtonBox::Save);
56     if (button) {
57         button->setText(tr("Save Comments"));
58     }
59 
60     button = ui->buttonBox->button(QDialogButtonBox::Close);
61     if (button) {
62         button->setDefault(true);
63     }
64 
65     setWindowSubtitle(tr("Capture File Properties"));
66     QTimer::singleShot(0, this, SLOT(updateWidgets()));
67 }
68 
69 /*
70  * Slots
71  */
72 
~CaptureFilePropertiesDialog()73 CaptureFilePropertiesDialog::~CaptureFilePropertiesDialog()
74 {
75     delete ui;
76 }
77 
78 /**/
79 
updateWidgets()80 void CaptureFilePropertiesDialog::updateWidgets()
81 {
82     QPushButton *refresh_bt = ui->buttonBox->button(QDialogButtonBox::Reset);
83     QPushButton *save_bt = ui->buttonBox->button(QDialogButtonBox::Save);
84 
85     if (file_closed_ || !cap_file_.isValid()) {
86         if (refresh_bt) {
87             refresh_bt->setEnabled(false);
88         }
89         ui->commentsTextEdit->setReadOnly(true);
90         if (save_bt) {
91             save_bt->setEnabled(false);
92         }
93         WiresharkDialog::updateWidgets();
94         return;
95     }
96 
97     bool enable = wtap_dump_can_write(cap_file_.capFile()->linktypes, WTAP_COMMENT_PER_SECTION);
98     save_bt->setEnabled(enable);
99     ui->commentsTextEdit->setEnabled(enable);
100 
101     fillDetails();
102     // XXX - this just handles the first comment in the first section;
103     // add support for multiple sections with multiple comments.
104     wtap_block_t shb = wtap_file_get_shb(cap_file_.capFile()->provider.wth, 0);
105     char *shb_comment;
106     if (wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, 0,
107                                                &shb_comment) == WTAP_OPTTYPE_SUCCESS)
108         ui->commentsTextEdit->setText(shb_comment);
109     else
110         ui->commentsTextEdit->setText(NULL);
111 
112     WiresharkDialog::updateWidgets();
113 }
114 
115 static const QString section_tmpl_ = "<p><strong>%1</strong></p>\n";
116 static const QString para_tmpl_ = "<p>%1</p>\n";
117 
summaryToHtml()118 QString CaptureFilePropertiesDialog::summaryToHtml()
119 {
120     summary_tally summary;
121     double seconds = 0.0;
122     double disp_seconds = 0.0;
123     double marked_seconds = 0.0;
124 
125     memset(&summary, 0, sizeof(summary_tally));
126 
127     QString table_begin, table_end;
128     QString table_row_begin, table_ul_row_begin, table_row_end;
129     QString table_vheader_tmpl, table_hheader20_tmpl, table_hheader25_tmpl;
130     QString table_data_tmpl;
131 
132     table_begin = "<p><table>\n";
133     table_end = "</table></p>\n";
134     table_row_begin = "<tr>\n";
135     table_ul_row_begin = "<tr style=\"border-bottom: 1px solid gray;\">\n";
136     table_row_end = "</tr>\n";
137     table_vheader_tmpl = "<td width=\"20%\">%1:</td>"; // <th align="left"> looked odd
138     table_hheader20_tmpl = "<td width=\"20%\"><u>%1</u></td>";
139     table_hheader25_tmpl = "<td width=\"25%\"><u>%1</u></td>";
140     table_data_tmpl = "<td>%1</td>";
141 
142     if (!file_closed_) {
143         /* initial computations */
144         summary_fill_in(cap_file_.capFile(), &summary);
145 #ifdef HAVE_LIBPCAP
146         summary_fill_in_capture(cap_file_.capFile(), &global_capture_opts, &summary);
147 #endif
148     }
149 
150     seconds = summary.stop_time - summary.start_time;
151     disp_seconds = summary.filtered_stop - summary.filtered_start;
152     marked_seconds = summary.marked_stop - summary.marked_start;
153 
154     QString summary_str;
155     QTextStream out(&summary_str);
156     QString unknown = tr("Unknown");
157 
158     // File Section
159     out << section_tmpl_.arg(tr("File"));
160     out << table_begin;
161 
162     out << table_row_begin
163         << table_vheader_tmpl.arg(tr("Name"))
164         << table_data_tmpl.arg(summary.filename)
165         << table_row_end;
166 
167     out << table_row_begin
168         << table_vheader_tmpl.arg(tr("Length"))
169         << table_data_tmpl.arg(file_size_to_qstring(summary.file_length))
170         << table_row_end;
171 
172     out << table_row_begin
173         << table_vheader_tmpl.arg(tr("Hash (SHA256)"))
174         << table_data_tmpl.arg(summary.file_sha256)
175         << table_row_end;
176 
177     out << table_row_begin
178         << table_vheader_tmpl.arg(tr("Hash (RIPEMD160)"))
179         << table_data_tmpl.arg(summary.file_rmd160)
180         << table_row_end;
181 
182     out << table_row_begin
183         << table_vheader_tmpl.arg(tr("Hash (SHA1)"))
184         << table_data_tmpl.arg(summary.file_sha1)
185         << table_row_end;
186 
187     QString format_str = wtap_file_type_subtype_description(summary.file_type);
188     const char *compression_type_description = wtap_compression_type_description(summary.compression_type);
189     if (compression_type_description != nullptr) {
190         format_str += QString(" (%1)").arg(compression_type_description);
191     }
192     out << table_row_begin
193         << table_vheader_tmpl.arg(tr("Format"))
194         << table_data_tmpl.arg(format_str)
195         << table_row_end;
196 
197     QString encaps_str;
198     if (summary.file_encap_type == WTAP_ENCAP_PER_PACKET) {
199         for (guint i = 0; i < summary.packet_encap_types->len; i++)
200         {
201             encaps_str = QString(wtap_encap_description(g_array_index(summary.packet_encap_types, int, i)));
202         }
203     } else {
204         encaps_str = QString(wtap_encap_description(summary.file_encap_type));
205     }
206     out << table_row_begin
207         << table_vheader_tmpl.arg(tr("Encapsulation"))
208         << table_data_tmpl.arg(encaps_str)
209         << table_row_end;
210 
211     if (summary.snap != 0) {
212         out << table_row_begin
213             << table_vheader_tmpl.arg(tr("Snapshot length"))
214             << table_data_tmpl.arg(summary.snap)
215             << table_row_end;
216     }
217 
218     out << table_end;
219 
220     // Time Section
221     if (summary.packet_count_ts == summary.packet_count &&
222             summary.packet_count >= 1)
223     {
224         out << section_tmpl_.arg(tr("Time"));
225         out << table_begin;
226 
227         // start time
228         out << table_row_begin
229             << table_vheader_tmpl.arg(tr("First packet"))
230             << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.start_time))
231             << table_row_end;
232 
233         // stop time
234         out << table_row_begin
235             << table_vheader_tmpl.arg(tr("Last packet"))
236             << table_data_tmpl.arg(time_t_to_qstring((time_t)summary.stop_time))
237             << table_row_end;
238 
239         // elapsed seconds (capture duration)
240         if (summary.packet_count_ts >= 2)
241         {
242             /* elapsed seconds */
243             QString elapsed_str;
244             unsigned int elapsed_time = (unsigned int)summary.elapsed_time;
245             if (elapsed_time/86400)
246             {
247                 elapsed_str = QString("%1 days ").arg(elapsed_time / 86400);
248             }
249 
250             elapsed_str += QString("%1:%2:%3")
251                     .arg(elapsed_time % 86400 / 3600, 2, 10, QChar('0'))
252                     .arg(elapsed_time % 3600 / 60, 2, 10, QChar('0'))
253                     .arg(elapsed_time % 60, 2, 10, QChar('0'));
254             out << table_row_begin
255                 << table_vheader_tmpl.arg(tr("Elapsed"))
256                 << table_data_tmpl.arg(elapsed_str)
257                 << table_row_end;
258         }
259 
260         out << table_end;
261     }
262 
263     // Information from file sections.
264     for (guint section_number = 0;
265          section_number < wtap_file_get_num_shbs(cap_file_.capFile()->provider.wth);
266          section_number++) {
267 
268         // If we have more than one section, add headers for each section.
269         if (wtap_file_get_num_shbs(cap_file_.capFile()->provider.wth) > 1)
270             out << section_tmpl_.arg(QString(tr("Section %1"))
271                                      .arg(section_number));
272 
273         // Capture Section
274         out << section_tmpl_.arg(tr("Capture"));
275         out << table_begin;
276 
277         wtap_block_t shb_inf = wtap_file_get_shb(cap_file_.capFile()->provider.wth, section_number);
278         char *str;
279 
280         if (shb_inf != nullptr) {
281             QString capture_hardware(unknown);
282             if (wtap_block_get_string_option_value(shb_inf, OPT_SHB_HARDWARE, &str) == WTAP_OPTTYPE_SUCCESS) {
283                 if (str[0] != '\0') {
284                     capture_hardware = str;
285                 }
286             }
287             // capture HW
288             out << table_row_begin
289                 << table_vheader_tmpl.arg(tr("Hardware"))
290                 << table_data_tmpl.arg(capture_hardware)
291                 << table_row_end;
292 
293             QString capture_os(unknown);
294             if (wtap_block_get_string_option_value(shb_inf, OPT_SHB_OS, &str) == WTAP_OPTTYPE_SUCCESS) {
295                 if (str[0] != '\0') {
296                     capture_os = str;
297                 }
298             }
299             out << table_row_begin
300                 << table_vheader_tmpl.arg(tr("OS"))
301                 << table_data_tmpl.arg(capture_os)
302                 << table_row_end;
303 
304             QString capture_app(unknown);
305             if (wtap_block_get_string_option_value(shb_inf, OPT_SHB_USERAPPL, &str) == WTAP_OPTTYPE_SUCCESS) {
306                 if (str[0] != '\0') {
307                     capture_app = str;
308                 }
309             }
310             out << table_row_begin
311                 << table_vheader_tmpl.arg(tr("Application"))
312                 << table_data_tmpl.arg(capture_app)
313                 << table_row_end;
314         }
315 
316         out << table_end;
317 
318         // capture interfaces info
319         if (summary.ifaces->len > 0) {
320             out << section_tmpl_.arg(tr("Interfaces"));
321             out << table_begin;
322 
323             out << table_ul_row_begin
324                 << table_hheader20_tmpl.arg(tr("Interface"))
325                 << table_hheader20_tmpl.arg(tr("Dropped packets"))
326                 << table_hheader20_tmpl.arg(tr("Capture filter"))
327                 << table_hheader20_tmpl.arg(tr("Link type"))
328                 << table_hheader20_tmpl.arg(tr("Packet size limit (snaplen)"))
329                 << table_row_end;
330         }
331 
332         for (guint i = 0; i < summary.ifaces->len; i++) {
333             iface_summary_info iface;
334             iface = g_array_index(summary.ifaces, iface_summary_info, i);
335 
336             /* interface */
337             QString interface_name(unknown);
338             if (iface.descr) {
339                 interface_name = iface.descr;
340             } else if (iface.name) {
341                 interface_name = iface.name;
342             }
343 
344             /* Dropped count */
345             QString interface_drops(unknown);
346             if (iface.drops_known) {
347                 interface_drops = QString("%1 (%2%)").arg(iface.drops).arg(QString::number(
348                     /* MSVC cannot convert from unsigned __int64 to float, so first convert to signed __int64 */
349                     summary.packet_count ? (100.0 * (gint64)iface.drops)/summary.packet_count : 0, 'f', 1));
350             }
351 
352             /* Capture filter */
353             QString interface_cfilter(unknown);
354             if (iface.cfilter && iface.cfilter[0] != '\0') {
355                 interface_cfilter = iface.cfilter;
356             } else if (iface.name) {
357                 interface_cfilter = QString(tr("none"));
358             }
359 
360             QString interface_snaplen = QString(tr("%1 bytes").arg(iface.snap));
361 
362             out << table_row_begin
363                 << table_data_tmpl.arg(interface_name)
364                 << table_data_tmpl.arg(interface_drops)
365                 << table_data_tmpl.arg(interface_cfilter)
366                 << table_data_tmpl.arg(wtap_encap_description(iface.encap_type))
367                 << table_data_tmpl.arg(interface_snaplen)
368                 << table_row_end;
369         }
370         if (summary.ifaces->len > 0) {
371             out << table_end;
372         }
373     }
374 
375     // Statistics Section
376     out << section_tmpl_.arg(tr("Statistics"));
377     out << table_begin;
378 
379     out << table_ul_row_begin
380         << table_hheader25_tmpl.arg(tr("Measurement"))
381         << table_hheader25_tmpl.arg(tr("Captured"))
382         << table_hheader25_tmpl.arg(tr("Displayed"))
383         << table_hheader25_tmpl.arg(tr("Marked"))
384         << table_row_end;
385 
386     QString n_a = UTF8_EM_DASH;
387     QString captured_str, displayed_str, marked_str;
388 
389     // Packets
390     displayed_str = marked_str = n_a;
391     if (summary.filtered_count > 0 && summary.packet_count > 0) {
392             displayed_str = QString("%1 (%2%)")
393             .arg(summary.filtered_count)
394             .arg(100.0 * summary.filtered_count / summary.packet_count, 1, 'f', 1);
395     }
396     if (summary.packet_count > 0 && summary.marked_count > 0) {
397             marked_str = QString("%1 (%2%)")
398             .arg(summary.marked_count)
399             .arg(100.0 * summary.marked_count / summary.packet_count, 1, 'f', 1);
400     }
401 
402     out << table_row_begin
403         << table_data_tmpl.arg(tr("Packets"))
404         << table_data_tmpl.arg(summary.packet_count)
405         << table_data_tmpl.arg(displayed_str)
406         << table_data_tmpl.arg(marked_str)
407         << table_row_end;
408 
409     // Time between first and last
410     captured_str = displayed_str = marked_str = n_a;
411     if (seconds > 0) {
412             captured_str = QString("%1").arg(seconds, 1, 'f', 3);
413     }
414     if (disp_seconds > 0) {
415             displayed_str = QString("%1").arg(disp_seconds, 1, 'f', 3);
416     }
417     if (marked_seconds > 0) {
418             marked_str = QString("%1").arg(marked_seconds, 1, 'f', 3);
419     }
420     out << table_row_begin
421         << table_data_tmpl.arg(tr("Time span, s"))
422         << table_data_tmpl.arg(captured_str)
423         << table_data_tmpl.arg(displayed_str)
424         << table_data_tmpl.arg(marked_str)
425         << table_row_end;
426 
427     // Average packets per second
428     captured_str = displayed_str = marked_str = n_a;
429     if (seconds > 0) {
430             captured_str = QString("%1").arg(summary.packet_count/seconds, 1, 'f', 1);
431     }
432     if (disp_seconds > 0) {
433             displayed_str = QString("%1").arg(summary.filtered_count/disp_seconds, 1, 'f', 1);
434     }
435     if (marked_seconds > 0) {
436             marked_str = QString("%1").arg(summary.marked_count/marked_seconds, 1, 'f', 1);
437     }
438     out << table_row_begin
439         << table_data_tmpl.arg(tr("Average pps"))
440         << table_data_tmpl.arg(captured_str)
441         << table_data_tmpl.arg(displayed_str)
442         << table_data_tmpl.arg(marked_str)
443         << table_row_end;
444 
445     // Average packet size
446     captured_str = displayed_str = marked_str = n_a;
447     if (summary.packet_count > 0) {
448             captured_str = QString::number((guint64) ((double)summary.bytes/summary.packet_count + 0.5));
449     }
450     if (summary.filtered_count > 0) {
451             displayed_str = QString::number((guint64) ((double)summary.filtered_bytes/summary.filtered_count + 0.5));
452     }
453     if (summary.marked_count > 0) {
454             marked_str = QString::number((guint64) ((double)summary.marked_bytes/summary.marked_count + 0.5));
455     }
456     out << table_row_begin
457         << table_data_tmpl.arg(tr("Average packet size, B"))
458         << table_data_tmpl.arg(captured_str)
459         << table_data_tmpl.arg(displayed_str)
460         << table_data_tmpl.arg(marked_str)
461         << table_row_end;
462 
463     // Byte count
464     displayed_str = marked_str = "0";
465     if (summary.bytes > 0 && summary.filtered_bytes > 0) {
466         displayed_str = QString("%1 (%2%)")
467                 .arg(summary.filtered_bytes)
468                 .arg(100.0 * summary.filtered_bytes / summary.bytes, 1, 'f', 1);
469     }
470     if (summary.bytes > 0 && summary.marked_bytes > 0) {
471         marked_str = QString("%1 (%2%)")
472                 .arg(summary.marked_bytes)
473                 .arg(100.0 * summary.marked_bytes / summary.bytes, 1, 'f', 1);
474     }
475     out << table_row_begin
476         << table_data_tmpl.arg(tr("Bytes"))
477         << table_data_tmpl.arg(summary.bytes)
478         << table_data_tmpl.arg(displayed_str)
479         << table_data_tmpl.arg(marked_str)
480         << table_row_end;
481 
482     // Bytes per second
483     captured_str = displayed_str = marked_str = n_a;
484     if (seconds > 0) {
485         captured_str =
486                 gchar_free_to_qstring(format_size(summary.bytes / seconds, format_size_unit_none|format_size_prefix_si));
487     }
488     if (disp_seconds > 0) {
489         displayed_str =
490                 gchar_free_to_qstring(format_size(summary.filtered_bytes / disp_seconds, format_size_unit_none|format_size_prefix_si));
491     }
492     if (marked_seconds > 0) {
493         marked_str =
494                 gchar_free_to_qstring(format_size(summary.marked_bytes / marked_seconds, format_size_unit_none|format_size_prefix_si));
495     }
496     out << table_row_begin
497         << table_data_tmpl.arg(tr("Average bytes/s"))
498         << table_data_tmpl.arg(captured_str)
499         << table_data_tmpl.arg(displayed_str)
500         << table_data_tmpl.arg(marked_str)
501         << table_row_end;
502 
503     // Bits per second
504     captured_str = displayed_str = marked_str = n_a;
505     if (seconds > 0) {
506             captured_str =
507                     gchar_free_to_qstring(format_size(summary.bytes * 8 / seconds, format_size_unit_none|format_size_prefix_si));
508     }
509     if (disp_seconds > 0) {
510             displayed_str =
511                     gchar_free_to_qstring(format_size(summary.filtered_bytes * 8 / disp_seconds, format_size_unit_none|format_size_prefix_si));
512     }
513     if (marked_seconds > 0) {
514             marked_str =
515                     gchar_free_to_qstring(format_size(summary.marked_bytes * 8 / marked_seconds, format_size_unit_none|format_size_prefix_si));
516     }
517     out << table_row_begin
518         << table_data_tmpl.arg(tr("Average bits/s"))
519         << table_data_tmpl.arg(captured_str)
520         << table_data_tmpl.arg(displayed_str)
521         << table_data_tmpl.arg(marked_str)
522         << table_row_end;
523 
524     out << table_end;
525 
526     return summary_str;
527 }
528 
fillDetails()529 void CaptureFilePropertiesDialog::fillDetails()
530 {
531     if (!cap_file_.isValid()) return;
532 
533     ui->detailsTextEdit->clear();
534 
535     QTextCursor cursor = ui->detailsTextEdit->textCursor();
536     QString summary = summaryToHtml();
537     cursor.insertHtml(summary);
538     cursor.insertBlock(); // Work around rendering oddity.
539 
540     // XXX - this just shows the first comment in the first section;
541     // add support for multiple sections with multiple comments.
542     wtap_block_t shb = wtap_file_get_shb(cap_file_.capFile()->provider.wth, 0);
543     char *shb_comment;
544     if (wtap_block_get_nth_string_option_value(shb, OPT_COMMENT, 0,
545                                                &shb_comment) == WTAP_OPTTYPE_SUCCESS) {
546         QString section_comment = shb_comment;
547         QString section_comment_html;
548 
549         if (!section_comment.isEmpty()) {
550             QString comment_escaped = html_escape(section_comment).replace('\n', "<br>");
551             section_comment_html += section_tmpl_.arg(QString(tr("Section Comment")));
552             section_comment_html += para_tmpl_.arg(comment_escaped);
553 
554             cursor.insertBlock();
555             cursor.insertHtml(section_comment_html);
556         }
557     }
558 
559     if (cap_file_.capFile()->packet_comment_count > 0) {
560         cursor.insertBlock();
561         cursor.insertHtml(section_tmpl_.arg(tr("Packet Comments")));
562 
563         for (guint32 framenum = 1; framenum <= cap_file_.capFile()->count ; framenum++) {
564             frame_data *fdata = frame_data_sequence_find(cap_file_.capFile()->provider.frames, framenum);
565             wtap_block_t pkt_block = cf_get_packet_block(cap_file_.capFile(), fdata);
566 
567             if (pkt_block) {
568                 guint n_comments = wtap_block_count_option(pkt_block, OPT_COMMENT);
569                 for (guint i = 0; i < n_comments; i++) {
570                     char *comment_text;
571                     if (WTAP_OPTTYPE_SUCCESS == wtap_block_get_nth_string_option_value(pkt_block, OPT_COMMENT, i, &comment_text)) {
572                         QString frame_comment_html = tr("<p>Frame %1: ").arg(framenum);
573                         QString raw_comment = comment_text;
574 
575                         frame_comment_html += html_escape(raw_comment).replace('\n', "<br>");
576                         frame_comment_html += "</p>\n";
577                         cursor.insertBlock();
578                         cursor.insertHtml(frame_comment_html);
579                     }
580                 }
581             }
582             wtap_block_unref(pkt_block);
583         }
584     }
585     ui->detailsTextEdit->verticalScrollBar()->setValue(0);
586 }
587 
changeEvent(QEvent * event)588 void CaptureFilePropertiesDialog::changeEvent(QEvent* event)
589 {
590     if (event != nullptr)
591     {
592         switch (event->type())
593         {
594         case QEvent::LanguageChange:
595             ui->retranslateUi(this);
596             updateWidgets();
597             break;
598         default:
599             break;
600         }
601     }
602     QDialog::changeEvent(event);
603 }
604 
on_buttonBox_helpRequested()605 void CaptureFilePropertiesDialog::on_buttonBox_helpRequested()
606 {
607     wsApp->helpTopicAction(HELP_STATS_SUMMARY_DIALOG);
608 }
609 
on_buttonBox_accepted()610 void CaptureFilePropertiesDialog::on_buttonBox_accepted()
611 {
612     if (file_closed_ || !cap_file_.capFile()->filename) {
613         return;
614     }
615 
616     if (wtap_dump_can_write(cap_file_.capFile()->linktypes, WTAP_COMMENT_PER_SECTION))
617     {
618         gchar *str = qstring_strdup(ui->commentsTextEdit->toPlainText());
619         cf_update_section_comment(cap_file_.capFile(), str);
620         emit captureCommentChanged();
621         fillDetails();
622     }
623 }
624 
on_buttonBox_clicked(QAbstractButton * button)625 void CaptureFilePropertiesDialog::on_buttonBox_clicked(QAbstractButton *button)
626 {
627     if (button == ui->buttonBox->button(QDialogButtonBox::Apply)) {
628         QClipboard *clipboard = QApplication::clipboard();
629         QString details = tr("Created by Wireshark %1\n\n").arg(get_ws_vcs_version_info());
630         details.append(ui->detailsTextEdit->toPlainText());
631         clipboard->setText(details);
632     } else if (button == ui->buttonBox->button(QDialogButtonBox::Reset)) {
633         updateWidgets();
634     }
635 }
636 
on_buttonBox_rejected()637 void CaptureFilePropertiesDialog::on_buttonBox_rejected()
638 {
639     reject();
640 }
641