Kerberos: add kerberos_inject_longterm_key() helper function
[wireshark-sm.git] / ui / qt / search_frame.cpp
blob9cfc04835cf3a7943493e065490ffdaed0615d15
1 /* search_frame.cpp
3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
10 #include "search_frame.h"
11 #include <ui_search_frame.h>
13 #include "file.h"
14 #include "ui/recent.h"
16 #include <epan/proto.h>
17 #include <epan/strutil.h>
19 #include <wsutil/filesystem.h>
20 #include <wsutil/utf8_entities.h>
21 #include <wsutil/regex.h>
23 #include "main_application.h"
24 #include "utils/qt_ui_utils.h"
26 #include <QKeyEvent>
27 #include <QCheckBox>
29 enum {
30 in_packet_list_,
31 in_proto_tree_,
32 in_bytes_
35 enum {
36 df_search_,
37 hex_search_,
38 string_search_,
39 regex_search_
42 enum {
43 narrow_and_wide_chars_,
44 narrow_chars_,
45 wide_chars_
48 SearchFrame::SearchFrame(QWidget *parent) :
49 AccordionFrame(parent),
50 sf_ui_(new Ui::SearchFrame),
51 cap_file_(nullptr),
52 regex_(nullptr)
54 sf_ui_->setupUi(this);
56 #ifdef Q_OS_MAC
57 foreach (QWidget *w, findChildren<QWidget *>()) {
58 w->setAttribute(Qt::WA_MacSmallSize, true);
60 #endif
62 if (!is_packet_configuration_namespace()) {
63 sf_ui_->searchInComboBox->setItemText(0, tr("Event List"));
64 sf_ui_->searchInComboBox->setItemText(1, tr("Event Details"));
65 sf_ui_->searchInComboBox->setItemText(2, tr("Event Bytes"));
66 sf_ui_->searchInComboBox->setToolTip(tr("<html><head/><body>"
67 "<p>Search the Info column of the event list (summary pane), "
68 "decoded event display labels (tree view pane) or the "
69 "ASCII-converted event data (hex view pane).</p>"
70 "</body></html>"));
74 applyRecentSearchSettings();
76 updateWidgets();
79 SearchFrame::~SearchFrame()
81 if (regex_) {
82 ws_regex_free(regex_);
84 delete sf_ui_;
87 void SearchFrame::animatedShow()
89 AccordionFrame::animatedShow();
91 sf_ui_->searchLineEdit->setFocus();
94 void SearchFrame::findNext()
96 if (!cap_file_) return;
98 sf_ui_->dirCheckBox->setChecked(false);
99 if (isHidden()) {
100 animatedShow();
101 return;
103 on_findButton_clicked();
106 void SearchFrame::findPrevious()
108 if (!cap_file_) return;
110 sf_ui_->dirCheckBox->setChecked(true);
111 if (isHidden()) {
112 animatedShow();
113 return;
115 on_findButton_clicked();
118 void SearchFrame::setFocus()
120 sf_ui_->searchLineEdit->setFocus();
121 sf_ui_->searchLineEdit->selectAll();
124 void SearchFrame::setCaptureFile(capture_file *cf)
126 cap_file_ = cf;
127 if (!cf && isVisible()) {
128 animatedHide();
130 updateWidgets();
133 void SearchFrame::findFrameWithFilter(QString &filter)
135 animatedShow();
136 sf_ui_->searchLineEdit->setText(filter);
137 sf_ui_->searchLineEdit->setCursorPosition(0);
138 sf_ui_->searchTypeComboBox->setCurrentIndex(df_search_);
139 updateWidgets();
140 on_findButton_clicked();
143 void SearchFrame::keyPressEvent(QKeyEvent *event)
145 if (event->modifiers() == Qt::NoModifier) {
146 if (event->key() == Qt::Key_Escape) {
147 on_cancelButton_clicked();
148 } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
149 on_findButton_clicked();
153 AccordionFrame::keyPressEvent(event);
156 bool SearchFrame::regexCompile()
158 unsigned flags = 0;
159 if (!sf_ui_->caseCheckBox->isChecked()) {
160 flags |= WS_REGEX_CASELESS;
162 if (sf_ui_->dirCheckBox->isChecked()) {
163 flags |= WS_REGEX_ANCHORED;
166 if (regex_) {
167 ws_regex_free(regex_);
170 if (sf_ui_->searchLineEdit->text().isEmpty()) {
171 regex_ = nullptr;
172 return false;
175 char *errmsg = nullptr;
176 regex_ = ws_regex_compile_ex(sf_ui_->searchLineEdit->text().toUtf8().constData(), -1,
177 &errmsg, flags);
179 if (errmsg != nullptr) {
180 regex_error_ = errmsg;
183 return regex_ ? true : false;
186 void SearchFrame::applyRecentSearchSettings()
188 int search_in_idx = in_packet_list_;
189 int char_encoding_idx = narrow_and_wide_chars_;
190 int search_type_idx = df_search_;
192 switch (recent.gui_search_in) {
193 case SEARCH_IN_PACKET_LIST:
194 search_in_idx = in_packet_list_;
195 break;
196 case SEARCH_IN_PACKET_DETAILS:
197 search_in_idx = in_proto_tree_;
198 break;
199 case SEARCH_IN_PACKET_BYTES:
200 search_in_idx = in_bytes_;
201 break;
202 default:
203 break;
206 switch (recent.gui_search_char_set) {
207 case SEARCH_CHAR_SET_NARROW_AND_WIDE:
208 char_encoding_idx = narrow_and_wide_chars_;
209 break;
210 case SEARCH_CHAR_SET_NARROW:
211 char_encoding_idx = narrow_chars_;
212 break;
213 case SEARCH_CHAR_SET_WIDE:
214 char_encoding_idx = wide_chars_;
215 break;
216 default:
217 break;
220 switch (recent.gui_search_type) {
221 case SEARCH_TYPE_DISPLAY_FILTER:
222 search_type_idx = df_search_;
223 break;
224 case SEARCH_TYPE_HEX_VALUE:
225 search_type_idx = hex_search_;
226 break;
227 case SEARCH_TYPE_STRING:
228 search_type_idx = string_search_;
229 break;
230 case SEARCH_TYPE_REGEX:
231 search_type_idx = regex_search_;
232 break;
233 default:
234 break;
237 sf_ui_->searchInComboBox->setCurrentIndex(search_in_idx);
238 sf_ui_->charEncodingComboBox->setCurrentIndex(char_encoding_idx);
239 sf_ui_->caseCheckBox->setChecked(recent.gui_search_case_sensitive);
240 sf_ui_->searchTypeComboBox->setCurrentIndex(search_type_idx);
241 sf_ui_->dirCheckBox->setChecked(recent.gui_search_reverse_dir);
242 sf_ui_->multipleCheckBox->setChecked(recent.gui_search_multiple_occurs);
245 void SearchFrame::updateWidgets()
247 if (cap_file_) {
248 setEnabled(true);
249 } else {
250 setEnabled(false);
251 return;
254 int search_type = sf_ui_->searchTypeComboBox->currentIndex();
255 sf_ui_->searchInComboBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
256 sf_ui_->caseCheckBox->setEnabled(search_type == string_search_ || search_type == regex_search_);
257 // The encoding only is used when searching the raw Packet Bytes
258 // (otherwise all strings have already been converted to UTF-8)
259 sf_ui_->charEncodingComboBox->setEnabled(search_type == string_search_ && sf_ui_->searchInComboBox->currentIndex() == in_bytes_);
261 // We can search for multiple matches in the same frame if we're doing
262 // a Proto Tree search or a Frame Bytes search, but not a string/regex
263 // search in the Packet List, or a display filter search (since those
264 // don't highlight what fields / offsets caused the match.)
265 sf_ui_->multipleCheckBox->setEnabled((sf_ui_->searchInComboBox->isEnabled() && sf_ui_->searchInComboBox->currentIndex() != in_packet_list_) || search_type == hex_search_);
267 switch (search_type) {
268 case df_search_:
269 sf_ui_->searchLineEdit->checkDisplayFilter(sf_ui_->searchLineEdit->text());
270 break;
271 case hex_search_:
272 if (sf_ui_->searchLineEdit->text().isEmpty()) {
273 sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
274 } else {
275 uint8_t *bytes;
276 size_t nbytes;
277 bytes = convert_string_to_hex(sf_ui_->searchLineEdit->text().toUtf8().constData(), &nbytes);
278 if (bytes == nullptr)
279 sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
280 else {
281 g_free(bytes);
282 sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
285 break;
286 case string_search_:
287 if (sf_ui_->searchLineEdit->text().isEmpty()) {
288 sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
289 } else {
290 sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
292 break;
293 case regex_search_:
294 if (regexCompile()) {
295 sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Valid);
296 } else {
297 sf_ui_->searchLineEdit->setSyntaxState(SyntaxLineEdit::Invalid);
299 break;
300 default:
301 // currentIndex is probably -1. Nothing is selected or list is empty.
302 return;
305 if (sf_ui_->searchLineEdit->text().isEmpty() || sf_ui_->searchLineEdit->syntaxState() == SyntaxLineEdit::Invalid) {
306 sf_ui_->findButton->setEnabled(false);
307 } else {
308 sf_ui_->findButton->setEnabled(true);
312 void SearchFrame::on_searchInComboBox_currentIndexChanged(int idx)
314 switch (idx) {
315 case in_packet_list_:
316 recent.gui_search_in = SEARCH_IN_PACKET_LIST;
317 break;
318 case in_proto_tree_:
319 recent.gui_search_in = SEARCH_IN_PACKET_DETAILS;
320 break;
321 case in_bytes_:
322 recent.gui_search_in = SEARCH_IN_PACKET_BYTES;
323 break;
324 default:
325 break;
328 // We only search for multiple occurrences in packet list and bytes
329 updateWidgets();
332 void SearchFrame::on_charEncodingComboBox_currentIndexChanged(int idx)
334 switch (idx) {
335 case narrow_and_wide_chars_:
336 recent.gui_search_char_set = SEARCH_CHAR_SET_NARROW_AND_WIDE;
337 break;
338 case narrow_chars_:
339 recent.gui_search_char_set = SEARCH_CHAR_SET_NARROW;
340 break;
341 case wide_chars_:
342 recent.gui_search_char_set = SEARCH_CHAR_SET_WIDE;
343 break;
344 default:
345 break;
349 void SearchFrame::on_caseCheckBox_toggled(bool checked)
351 recent.gui_search_case_sensitive = checked;
352 regexCompile();
355 void SearchFrame::on_searchTypeComboBox_currentIndexChanged(int idx)
357 switch (idx) {
358 case df_search_:
359 recent.gui_search_type = SEARCH_TYPE_DISPLAY_FILTER;
360 break;
361 case hex_search_:
362 recent.gui_search_type = SEARCH_TYPE_HEX_VALUE;
363 break;
364 case string_search_:
365 recent.gui_search_type = SEARCH_TYPE_STRING;
366 break;
367 case regex_search_:
368 recent.gui_search_type = SEARCH_TYPE_REGEX;
369 break;
370 default:
371 break;
374 // Enable completion only for display filter search.
375 sf_ui_->searchLineEdit->allowCompletion(idx == df_search_);
377 if (idx == df_search_) {
378 sf_ui_->searchLineEdit->setPlaceholderText(DisplayFilterEdit::tr("Enter a display filter %1").arg(UTF8_HORIZONTAL_ELLIPSIS));
379 sf_ui_->searchLineEdit->checkFilter();
380 } else {
381 sf_ui_->searchLineEdit->setPlaceholderText(QString());
382 sf_ui_->searchLineEdit->setToolTip(QString());
383 mainApp->popStatus(MainApplication::FilterSyntax);
386 updateWidgets();
389 void SearchFrame::on_searchLineEdit_textChanged(const QString &)
391 updateWidgets();
394 void SearchFrame::on_dirCheckBox_toggled(bool checked)
396 recent.gui_search_reverse_dir = checked;
399 void SearchFrame::on_multipleCheckBox_toggled(bool checked)
401 recent.gui_search_multiple_occurs = checked;
404 void SearchFrame::on_findButton_clicked()
406 uint8_t *bytes = nullptr;
407 size_t nbytes = 0;
408 char *string = nullptr;
409 dfilter_t *dfp = nullptr;
410 bool found_packet = false;
411 QString err_string;
413 if (!cap_file_) {
414 return;
417 cap_file_->hex = false;
418 cap_file_->string = false;
419 cap_file_->case_type = false;
420 cap_file_->regex = nullptr;
421 cap_file_->packet_data = false;
422 cap_file_->decode_data = false;
423 cap_file_->summary_data = false;
424 cap_file_->scs_type = SCS_NARROW_AND_WIDE;
425 cap_file_->dir = sf_ui_->dirCheckBox->isChecked() ? SD_BACKWARD : SD_FORWARD;
426 bool multiple_occurrences = sf_ui_->multipleCheckBox->isChecked();
428 int search_type = sf_ui_->searchTypeComboBox->currentIndex();
429 switch (search_type) {
430 case df_search_:
431 if (!dfilter_compile(sf_ui_->searchLineEdit->text().toUtf8().constData(), &dfp, nullptr)) {
432 err_string = tr("Invalid filter.");
433 goto search_done;
436 if (dfp == nullptr) {
437 err_string = tr("That filter doesn't test anything.");
438 goto search_done;
440 break;
441 case hex_search_:
442 bytes = convert_string_to_hex(sf_ui_->searchLineEdit->text().toUtf8().constData(), &nbytes);
443 if (bytes == nullptr) {
444 err_string = tr("That's not a valid hex string.");
445 goto search_done;
447 cap_file_->hex = true;
448 break;
449 case string_search_:
450 case regex_search_:
451 if (sf_ui_->searchLineEdit->text().isEmpty()) {
452 err_string = tr("You didn't specify any text for which to search.");
453 goto search_done;
455 cap_file_->string = true;
456 cap_file_->case_type = sf_ui_->caseCheckBox->isChecked() ? false : true;
457 cap_file_->regex = (search_type == regex_search_ ? regex_ : nullptr);
458 switch (sf_ui_->charEncodingComboBox->currentIndex()) {
459 case narrow_and_wide_chars_:
460 cap_file_->scs_type = SCS_NARROW_AND_WIDE;
461 break;
462 case narrow_chars_:
463 cap_file_->scs_type = SCS_NARROW;
464 break;
465 case wide_chars_:
466 cap_file_->scs_type = SCS_WIDE;
467 break;
468 default:
469 err_string = tr("No valid character set selected. Please report this to the development team.");
470 goto search_done;
472 string = convert_string_case(sf_ui_->searchLineEdit->text().toUtf8().constData(), cap_file_->case_type);
473 break;
474 default:
475 err_string = tr("No valid search type selected. Please report this to the development team.");
476 goto search_done;
479 switch (sf_ui_->searchInComboBox->currentIndex()) {
480 case in_packet_list_:
481 cap_file_->summary_data = true;
482 break;
483 case in_proto_tree_:
484 cap_file_->decode_data = true;
485 break;
486 case in_bytes_:
487 cap_file_->packet_data = true;
488 break;
489 default:
490 err_string = tr("No valid search area selected. Please report this to the development team.");
491 goto search_done;
494 g_free(cap_file_->sfilter);
495 cap_file_->sfilter = qstring_strdup(sf_ui_->searchLineEdit->text());
496 mainApp->popStatus(MainApplication::FileStatus);
497 mainApp->pushStatus(MainApplication::FileStatus, tr("Searching for %1…").arg(sf_ui_->searchLineEdit->text()));
499 if (cap_file_->hex) {
500 /* Hex value in packet data */
501 found_packet = cf_find_packet_data(cap_file_, bytes, nbytes, cap_file_->dir, multiple_occurrences);
502 g_free(bytes);
503 if (!found_packet) {
504 /* We didn't find a packet */
505 err_string = tr("No packet contained those bytes.");
506 goto search_done;
508 } else if (cap_file_->string) {
509 if (search_type == regex_search_ && !cap_file_->regex) {
510 err_string = regex_error_;
511 goto search_done;
513 if (cap_file_->summary_data) {
514 /* String in the Info column of the summary line */
515 found_packet = cf_find_packet_summary_line(cap_file_, string, cap_file_->dir);
516 g_free(string);
517 if (!found_packet) {
518 err_string = tr("No packet contained that string in its Info column.");
519 goto search_done;
521 } else if (cap_file_->decode_data) {
522 /* String in the protocol tree headings */
523 found_packet = cf_find_packet_protocol_tree(cap_file_, string, cap_file_->dir, multiple_occurrences);
524 g_free(string);
525 if (!found_packet) {
526 err_string = tr("No packet contained that string in its dissected display.");
527 goto search_done;
529 } else if (cap_file_->packet_data && string) {
530 /* String in the ASCII-converted packet data */
531 found_packet = cf_find_packet_data(cap_file_, (uint8_t *) string, strlen(string), cap_file_->dir, multiple_occurrences);
532 g_free(string);
533 if (!found_packet) {
534 err_string = tr("No packet contained that string in its converted data.");
535 goto search_done;
538 } else {
539 /* Search via display filter */
540 found_packet = cf_find_packet_dfilter(cap_file_, dfp, cap_file_->dir);
541 dfilter_free(dfp);
542 if (!found_packet) {
543 err_string = tr("No packet matched that filter.");
544 g_free(bytes);
545 goto search_done;
549 search_done:
550 mainApp->popStatus(MainApplication::FileStatus);
551 if (!err_string.isEmpty()) {
552 mainApp->pushStatus(MainApplication::FilterSyntax, err_string);
556 void SearchFrame::on_cancelButton_clicked()
558 mainApp->popStatus(MainApplication::FilterSyntax);
559 animatedHide();
562 void SearchFrame::changeEvent(QEvent* event)
564 if (event)
566 switch (event->type())
568 case QEvent::LanguageChange:
569 sf_ui_->retranslateUi(this);
570 break;
571 default:
572 break;
575 AccordionFrame::changeEvent(event);