update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / ui / qt / address_editor_frame.cpp
blob034ac27b7c7ece9388fbb0b88ed16bc6d5eedfd6
1 /* address_editor_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 "config.h"
12 #include "file.h"
13 #include "frame_tvbuff.h"
15 #include "epan/addr_resolv.h"
16 #include "epan/epan_dissect.h"
17 #include "epan/frame_data.h"
19 #include "main_application.h"
21 #include "address_editor_frame.h"
22 #include <ui_address_editor_frame.h>
24 #include <QPushButton>
25 #include <QKeyEvent>
27 #include <ui/qt/utils/qt_ui_utils.h>
29 // To do:
30 // - Fill in currently resolved address.
31 // - Allow editing other kinds of addresses.
33 AddressEditorFrame::AddressEditorFrame(QWidget *parent) :
34 AccordionFrame(parent),
35 ui(new Ui::AddressEditorFrame),
36 cap_file_(NULL)
38 ui->setupUi(this);
39 ui->addressComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents);
41 #ifdef Q_OS_MAC
42 foreach (QWidget *w, findChildren<QWidget *>()) {
43 w->setAttribute(Qt::WA_MacSmallSize, true);
45 #endif
48 AddressEditorFrame::~AddressEditorFrame()
50 delete ui;
53 QString AddressEditorFrame::addressToString(const FieldInformation& finfo)
55 address addr;
56 QString addr_str;
57 const ipv4_addr_and_mask *ipv4;
58 const ipv6_addr_and_prefix *ipv6;
60 if (!finfo.isValid()) {
61 return QString();
64 switch (finfo.headerInfo().type) {
66 case FT_IPv4:
67 // FieldInformation.toString gives us the result of
68 // proto_item_fill_display_label, but that gives us
69 // the currently resolved version, if resolution is
70 // available and enabled. We want the unresolved string.
71 ipv4 = fvalue_get_ipv4(finfo.fieldInfo()->value);
72 set_address_ipv4(&addr, ipv4);
73 addr_str = gchar_free_to_qstring(address_to_str(NULL, &addr));
74 free_address(&addr);
75 break;
76 case FT_IPv6:
77 ipv6 = fvalue_get_ipv6(finfo.fieldInfo()->value);
78 set_address_ipv6(&addr, ipv6);
79 addr_str = gchar_free_to_qstring(address_to_str(NULL, &addr));
80 free_address(&addr);
81 break;
82 default:
83 addr_str = QString();
85 return addr_str;
88 // NOLINTNEXTLINE(misc-no-recursion)
89 void AddressEditorFrame::addAddresses(const ProtoNode& node, QStringList& addresses)
91 QString addrString = addressToString(FieldInformation(&node));
92 if (!addrString.isEmpty()) {
93 addresses << addrString;
95 ProtoNode::ChildIterator kids = node.children();
96 while (kids.element().isValid()) {
97 // We recurse here, but we're limited by tree depth checks in epan
98 addAddresses(kids.element(), addresses);
99 kids.next();
103 void AddressEditorFrame::editAddresses(CaptureFile &cf, int column)
105 cap_file_ = cf.capFile();
107 if (!cap_file_->current_frame) {
108 on_buttonBox_rejected();
109 return;
112 if (!cf_read_current_record(cap_file_)) {
113 on_buttonBox_rejected();
114 return; // error reading the frame
117 epan_dissect_t edt;
118 QStringList addresses;
119 QString selectedString;
121 ui->addressComboBox->clear();
123 // Dissect the record with a visible tree and fill in the custom
124 // columns. We don't really need to have a visible tree (we should
125 // have one in cap_file_->edt->tree as we have a current frame), but
126 // this is only a single frame that's previously been dissected so
127 // the performance hit is slight anyway.
128 epan_dissect_init(&edt, cap_file_->epan, true, true);
129 col_custom_prime_edt(&edt, &cap_file_->cinfo);
131 epan_dissect_run(&edt, cap_file_->cd_t, &cap_file_->rec,
132 frame_tvbuff_new_buffer(&cap_file_->provider, cap_file_->current_frame, &cap_file_->buf),
133 cap_file_->current_frame, &cap_file_->cinfo);
134 epan_dissect_fill_in_columns(&edt, true, true);
136 addAddresses(ProtoNode(edt.tree), addresses);
138 if (column >= 0) {
139 // Check selected column
140 if (isAddressColumn(&cap_file_->cinfo, column)) {
141 // This always gets the unresolved value.
142 // XXX: For multifield custom columns, we don't have a good
143 // function to return each string separately before joining
144 // them. Since we know that IP addresses don't include commas,
145 // we could split on commas here, and check each field value
146 // to find the first one that is an IP address in our list.
147 selectedString = cap_file_->cinfo.col_expr.col_expr_val[column];
149 } else if (cap_file_->finfo_selected) {
150 selectedString = addressToString(FieldInformation(cap_file_->finfo_selected));
153 epan_dissect_cleanup(&edt);
155 displayPreviousUserDefinedHostname();
157 addresses.removeDuplicates();
158 ui->addressComboBox->addItems(addresses);
159 int index = ui->addressComboBox->findText(selectedString);
160 if (index != -1) {
161 ui->addressComboBox->setCurrentIndex(index);
163 ui->nameLineEdit->setFocus();
164 updateWidgets();
167 void AddressEditorFrame::showEvent(QShowEvent *event)
169 ui->nameLineEdit->setFocus();
170 ui->nameLineEdit->selectAll();
172 AccordionFrame::showEvent(event);
175 void AddressEditorFrame::keyPressEvent(QKeyEvent *event)
177 if (event->modifiers() == Qt::NoModifier) {
178 if (event->key() == Qt::Key_Escape) {
179 on_buttonBox_rejected();
180 } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) {
181 if (ui->buttonBox->button(QDialogButtonBox::Ok)->isEnabled()) {
182 on_buttonBox_accepted();
187 AccordionFrame::keyPressEvent(event);
190 void AddressEditorFrame::displayPreviousUserDefinedHostname()
192 QString addr = ui->addressComboBox->currentText();
193 // XXX: If there's a resolved name that wasn't manually entered,
194 // we should probably display that too. Possibly even if network
195 // name resolution is off globally, as get_edited_resolved_name() does.
196 // It's possible to have such names from DNS lookups if the global is
197 // turned on then turned back off, from NRBs, or from DNS packets.
198 // There's no clean API call to always get the resolved name, but
199 // we could access the hash tables directly the way that
200 // models/resolved_addresses_models.cpp does.
201 resolved_name_t* previous_entry = get_edited_resolved_name(addr.toUtf8().constData());
202 if (previous_entry)
204 ui->nameLineEdit->setText(previous_entry->name);
206 else
208 ui->nameLineEdit->setText("");
212 void AddressEditorFrame::updateWidgets()
214 bool ok_enable = false;
215 if (ui->addressComboBox->count() > 0) {
216 ok_enable = true;
219 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(ok_enable);
222 void AddressEditorFrame::on_nameResolutionPreferencesToolButton_clicked()
224 on_buttonBox_rejected();
225 emit showNameResolutionPreferences("nameres");
228 void AddressEditorFrame::on_addressComboBox_currentIndexChanged(int)
230 displayPreviousUserDefinedHostname();
231 updateWidgets();
234 void AddressEditorFrame::on_nameLineEdit_textEdited(const QString &)
236 updateWidgets();
239 void AddressEditorFrame::on_buttonBox_accepted()
241 if (ui->addressComboBox->count() < 1) {
242 return;
244 QString addr = ui->addressComboBox->currentText();
245 QString name = ui->nameLineEdit->text();
246 if (!cf_add_ip_name_from_string(cap_file_, addr.toUtf8().constData(), name.toUtf8().constData())) {
247 QString error_msg = tr("Can't assign %1 to %2.").arg(name).arg(addr);
248 mainApp->pushStatus(MainApplication::TemporaryStatus, error_msg);
249 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
250 return;
252 on_buttonBox_rejected();
253 // There's no point in redissecting packets if the network resolution
254 // global is off. There is a use case for editing several names before
255 // turning on the preference to avoid a lot of expensive redissects.
256 // (Statistics->Resolved Addresses still displays them even when
257 // resolution is disabled, so the user can check what has been input.)
259 // XXX: Can entering a new name but having nothing happen because
260 // network name resolution is off be confusing to the user? The GTK
261 // dialog had a simple checkbox, the "Name Resolution Preferences..."
262 // is a little more complicated but hopefully obvious enough.
263 if (gbl_resolv_flags.network_name) {
264 emit redissectPackets();
268 void AddressEditorFrame::on_buttonBox_rejected()
270 ui->addressComboBox->clear();
271 ui->nameLineEdit->clear();
272 animatedHide();
275 bool AddressEditorFrame::isAddressColumn(epan_column_info *cinfo, int column)
277 if (!cinfo || column < 0 || column >= cinfo->num_cols) return false;
279 if (((cinfo->columns[column].col_fmt == COL_DEF_SRC) ||
280 (cinfo->columns[column].col_fmt == COL_RES_SRC) ||
281 (cinfo->columns[column].col_fmt == COL_UNRES_SRC) ||
282 (cinfo->columns[column].col_fmt == COL_DEF_DST) ||
283 (cinfo->columns[column].col_fmt == COL_RES_DST) ||
284 (cinfo->columns[column].col_fmt == COL_UNRES_DST) ||
285 (cinfo->columns[column].col_fmt == COL_DEF_NET_SRC) ||
286 (cinfo->columns[column].col_fmt == COL_RES_NET_SRC) ||
287 (cinfo->columns[column].col_fmt == COL_UNRES_NET_SRC) ||
288 (cinfo->columns[column].col_fmt == COL_DEF_NET_DST) ||
289 (cinfo->columns[column].col_fmt == COL_RES_NET_DST) ||
290 (cinfo->columns[column].col_fmt == COL_UNRES_NET_DST)) &&
291 strlen(cinfo->col_expr.col_expr_val[column]))
293 return true;
296 if ((cinfo->columns[column].col_fmt == COL_CUSTOM) &&
297 cinfo->columns[column].col_custom_fields) {
298 // We could cycle through all the col_custom_fields_ids and
299 // see if proto_registrar_get_ftype() says that any of them
300 // are FT_IPv4 or FT_IPv6, but let's just check the string
301 // against all the addresses we found from the tree.
302 return true;
305 return false;