1 /* address_editor_frame.cpp
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9 
10 #include "config.h"
11 
12 #include <glib.h>
13 
14 #include "file.h"
15 #include "frame_tvbuff.h"
16 
17 #include "epan/addr_resolv.h"
18 #include "epan/epan_dissect.h"
19 #include "epan/frame_data.h"
20 
21 #include "address_editor_frame.h"
22 #include <ui_address_editor_frame.h>
23 
24 #include <QPushButton>
25 #include <QKeyEvent>
26 
27 #include <ui/qt/utils/qt_ui_utils.h>
28 #include <ui/qt/wireshark_application.h>
29 
30 // To do:
31 // - Fill in currently resolved address.
32 
AddressEditorFrame(QWidget * parent)33 AddressEditorFrame::AddressEditorFrame(QWidget *parent) :
34     AccordionFrame(parent),
35     ui(new Ui::AddressEditorFrame),
36     cap_file_(NULL)
37 {
38     ui->setupUi(this);
39 
40 #ifdef Q_OS_MAC
41     foreach (QWidget *w, findChildren<QWidget *>()) {
42         w->setAttribute(Qt::WA_MacSmallSize, true);
43     }
44 #endif
45 }
46 
~AddressEditorFrame()47 AddressEditorFrame::~AddressEditorFrame()
48 {
49     delete ui;
50 }
51 
editAddresses(CaptureFile & cf,int column)52 void AddressEditorFrame::editAddresses(CaptureFile &cf, int column)
53 {
54     cap_file_ = cf.capFile();
55 
56     if (!cap_file_->current_frame) {
57         on_buttonBox_rejected();
58         return;
59     }
60 
61     if (!cf_read_current_record(cap_file_)) {
62         on_buttonBox_rejected();
63         return; // error reading the frame
64     }
65 
66     epan_dissect_t edt;
67     QStringList addresses;
68 
69     ui->addressComboBox->clear();
70 
71     epan_dissect_init(&edt, cap_file_->epan, FALSE, FALSE);
72     col_custom_prime_edt(&edt, &cap_file_->cinfo);
73 
74     epan_dissect_run(&edt, cap_file_->cd_t, &cap_file_->rec,
75         frame_tvbuff_new_buffer(&cap_file_->provider, cap_file_->current_frame, &cap_file_->buf),
76         cap_file_->current_frame, &cap_file_->cinfo);
77     epan_dissect_fill_in_columns(&edt, TRUE, TRUE);
78 
79     /* First check selected column */
80     if (isAddressColumn(&cap_file_->cinfo, column)) {
81         addresses << cap_file_->cinfo.col_expr.col_expr_val[column];
82     }
83 
84     for (int col = 0; col < cap_file_->cinfo.num_cols; col++) {
85         /* Then check all columns except the selected */
86         if ((col != column) && (isAddressColumn(&cap_file_->cinfo, col))) {
87             addresses << cap_file_->cinfo.col_expr.col_expr_val[col];
88         }
89     }
90 
91     epan_dissect_cleanup(&edt);
92 
93     displayPreviousUserDefinedHostname();
94 
95     ui->addressComboBox->addItems(addresses);
96     ui->nameLineEdit->setFocus();
97     updateWidgets();
98 }
99 
showEvent(QShowEvent * event)100 void AddressEditorFrame::showEvent(QShowEvent *event)
101 {
102     ui->nameLineEdit->setFocus();
103     ui->nameLineEdit->selectAll();
104 
105     AccordionFrame::showEvent(event);
106 }
107 
keyPressEvent(QKeyEvent * event)108 void AddressEditorFrame::keyPressEvent(QKeyEvent *event)
109 {
110     if (event->modifiers() == Qt::NoModifier) {
111         if (event->key() == Qt::Key_Escape) {
112             on_buttonBox_rejected();
113         } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
114             if (ui->buttonBox->button(QDialogButtonBox::Ok)->isEnabled()) {
115                 on_buttonBox_accepted();
116             }
117         }
118     }
119 
120     AccordionFrame::keyPressEvent(event);
121 }
122 
displayPreviousUserDefinedHostname()123 void AddressEditorFrame::displayPreviousUserDefinedHostname()
124 {
125     QString addr = ui->addressComboBox->currentText();
126     resolved_name_t* previous_entry = get_edited_resolved_name(addr.toUtf8().constData());
127     if (previous_entry)
128     {
129         ui->nameLineEdit->setText(previous_entry->name);
130     }
131     else
132     {
133         ui->nameLineEdit->setText("");
134     }
135 }
136 
updateWidgets()137 void AddressEditorFrame::updateWidgets()
138 {
139     bool ok_enable = false;
140     if (ui->addressComboBox->count() > 0) {
141         ok_enable = true;
142     }
143 
144     ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok_enable);
145 }
146 
on_nameResolutionPreferencesToolButton_clicked()147 void AddressEditorFrame::on_nameResolutionPreferencesToolButton_clicked()
148 {
149     on_buttonBox_rejected();
150     emit showNameResolutionPreferences("nameres");
151 }
152 
on_addressComboBox_currentIndexChanged(const QString &)153 void AddressEditorFrame::on_addressComboBox_currentIndexChanged(const QString &)
154 {
155     displayPreviousUserDefinedHostname();
156     updateWidgets();
157 }
158 
on_nameLineEdit_textEdited(const QString &)159 void AddressEditorFrame::on_nameLineEdit_textEdited(const QString &)
160 {
161     updateWidgets();
162 }
163 
on_buttonBox_accepted()164 void AddressEditorFrame::on_buttonBox_accepted()
165 {
166     if (ui->addressComboBox->count() < 1) {
167         return;
168     }
169     QString addr = ui->addressComboBox->currentText();
170     QString name = ui->nameLineEdit->text();
171     if (!cf_add_ip_name_from_string(cap_file_, addr.toUtf8().constData(), name.toUtf8().constData())) {
172         QString error_msg = tr("Can't assign %1 to %2.").arg(name).arg(addr);
173         wsApp->pushStatus(WiresharkApplication::TemporaryStatus, error_msg);
174         ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
175         return;
176     }
177     on_buttonBox_rejected();
178     emit redissectPackets();
179 }
180 
on_buttonBox_rejected()181 void AddressEditorFrame::on_buttonBox_rejected()
182 {
183     ui->addressComboBox->clear();
184     ui->nameLineEdit->clear();
185     animatedHide();
186 }
187 
isAddressColumn(epan_column_info * cinfo,int column)188 bool AddressEditorFrame::isAddressColumn(epan_column_info *cinfo, int column)
189 {
190     if (!cinfo || column < 0 || column >= cinfo->num_cols) return false;
191 
192     if (((cinfo->columns[column].col_fmt == COL_DEF_SRC) ||
193          (cinfo->columns[column].col_fmt == COL_RES_SRC) ||
194          (cinfo->columns[column].col_fmt == COL_DEF_DST) ||
195          (cinfo->columns[column].col_fmt == COL_RES_DST)) &&
196         strlen(cinfo->col_expr.col_expr_val[column]))
197     {
198         return true;
199     }
200 
201     return false;
202 }
203