We always HAVE_CONFIG_H so don't bother checking whether we have it or not.
[metze/wireshark/wip.git] / ui / qt / import_text_dialog.cpp
1 /* import_text_dialog.cpp
2  *
3  * $Id: capture_file_dialog.cpp 44864 2012-09-10 23:03:22Z gerald $
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 #include "config.h"
25
26 #include <time.h>
27
28 #include <import_text_dialog.h>
29
30 #include "wiretap/wtap.h"
31 #include "wiretap/pcap-encap.h"
32
33 #include <epan/prefs.h>
34
35 #include "ui/text_import_scanner.h"
36 #include "ui/last_open_dir.h"
37 #include "ui/alert_box.h"
38 #include "ui/help_url.h"
39
40 #include "file.h"
41 #include "wsutil/file_util.h"
42 #include "tempfile.h"
43
44 #include <ui_import_text_dialog.h>
45 #include <wireshark_application.h>
46
47 #include <QFileDialog>
48 #include <QDebug>
49 #include <QFile>
50 #include <QMessageBox>
51 #include <QDesktopServices>
52 #include <QUrl>
53
54 ImportTextDialog::ImportTextDialog(QWidget *parent) :
55     QDialog(parent),
56     ui(new Ui::ImportTextDialog),
57     import_info_()
58 {
59     int encap;
60     int i;
61
62     ui->setupUi(this);
63     memset(&import_info_, 0, sizeof(import_info_));
64
65     ok_button_ = ui->buttonBox->button(QDialogButtonBox::Ok);
66     ok_button_->setEnabled(false);
67
68 #ifdef Q_WS_MAC
69     // The grid layout squishes each line edit otherwise.
70     int le_height = ui->textFileLineEdit->sizeHint().height();
71     ui->ethertypeLineEdit->setMinimumHeight(le_height);
72     ui->protocolLineEdit->setMinimumHeight(le_height);
73     ui->sourcePortLineEdit->setMinimumHeight(le_height);
74     ui->destinationPortLineEdit->setMinimumHeight(le_height);
75     ui->tagLineEdit->setMinimumHeight(le_height);
76     ui->ppiLineEdit->setMinimumHeight(le_height);
77 #endif
78
79     on_dateTimeLineEdit_textChanged(ui->dateTimeLineEdit->text());
80
81     for (i = 0; i < ui->headerGridLayout->count(); i++) {
82         QRadioButton *rb = qobject_cast<QRadioButton *>(ui->headerGridLayout->itemAt(i)->widget());
83
84         if (rb) encap_buttons_.append(rb);
85     }
86
87     /* Scan all Wiretap encapsulation types */
88     import_info_.encapsulation = WTAP_ENCAP_ETHERNET;
89     for (encap = import_info_.encapsulation; encap < wtap_get_num_encap_types(); encap++)
90     {
91         /* Check if we can write to a PCAP file
92          *
93          * Exclude wtap encapsulations that require a pseudo header,
94          * because we won't setup one from the text we import and
95          * wiretap doesn't allow us to write 'raw' frames
96          */
97         if ((wtap_wtap_encap_to_pcap_encap(encap) > 0) && !wtap_encap_requires_phdr(encap)) {
98             const char *name;
99             /* If it has got a name */
100             if ((name = wtap_encap_string(encap)))
101             {
102                 ui->encapComboBox->addItem(name, QVariant(encap));
103             }
104         }
105     }
106 }
107
108 ImportTextDialog::~ImportTextDialog()
109 {
110     delete ui;
111 }
112
113 QString &ImportTextDialog::capfileName() {
114     return capfile_name_;
115 }
116
117 void ImportTextDialog::convertTextFile() {
118     int import_file_fd;
119     char *tmpname;
120     int err;
121
122     capfile_name_.clear();
123     /* Choose a random name for the temporary import buffer */
124     import_file_fd = create_tempfile(&tmpname, "import");
125     capfile_name_.append(tmpname);
126
127     import_info_.wdh = wtap_dump_fdopen(import_file_fd, WTAP_FILE_PCAP, import_info_.encapsulation, import_info_.max_frame_length, FALSE, &err);
128     qDebug() << capfile_name_ << ":" << import_info_.wdh << import_info_.encapsulation << import_info_.max_frame_length;
129     if (import_info_.wdh == NULL) {
130         open_failure_alert_box(capfile_name_.toUtf8().constData(), err, TRUE);
131         fclose(import_info_.import_text_file);
132         setResult(QDialog::Rejected);
133         return;
134     }
135
136     text_import_setup(&import_info_);
137
138     text_importin = import_info_.import_text_file;
139
140     text_importlex();
141
142     text_import_cleanup();
143
144     if (fclose(import_info_.import_text_file))
145     {
146         read_failure_alert_box(import_info_.import_text_filename, errno);
147     }
148
149     if (!wtap_dump_close(import_info_.wdh, &err))
150     {
151         write_failure_alert_box(capfile_name_.toUtf8().constData(), err);
152     }
153 }
154
155
156 void ImportTextDialog::enableHeaderWidgets(bool enable_buttons) {
157     bool ethertype = false;
158     bool ipv4_proto = false;
159     bool port = false;
160     bool sctp_tag = false;
161     bool sctp_ppi = false;
162
163     if (enable_buttons) {
164         if (ui->ethernetButton->isChecked()) {
165             ethertype = true;
166             on_ethertypeLineEdit_textChanged(ui->ethertypeLabel->text());
167         } else  if (ui->ipv4Button->isChecked()) {
168             ipv4_proto = true;
169             on_protocolLineEdit_textChanged(ui->protocolLineEdit->text());
170         } else if (ui->udpButton->isChecked() || ui->tcpButton->isChecked()) {
171             port = true;
172             on_sourcePortLineEdit_textChanged(ui->sourcePortLineEdit->text());
173             on_destinationPortLineEdit_textChanged(ui->destinationPortLineEdit->text());
174         } else if (ui->sctpButton->isChecked()) {
175             port = true;
176             sctp_tag = true;
177             on_sourcePortLineEdit_textChanged(ui->sourcePortLineEdit->text());
178             on_destinationPortLineEdit_textChanged(ui->destinationPortLineEdit->text());
179             on_tagLineEdit_textChanged(ui->tagLineEdit->text());
180         }
181         if (ui->sctpDataButton->isChecked()) {
182             port = true;
183             sctp_ppi = true;
184             on_sourcePortLineEdit_textChanged(ui->sourcePortLineEdit->text());
185             on_destinationPortLineEdit_textChanged(ui->destinationPortLineEdit->text());
186             on_ppiLineEdit_textChanged(ui->ppiLineEdit->text());
187         }
188     }
189
190     foreach (QRadioButton *rb, encap_buttons_) {
191         rb->setEnabled(enable_buttons);
192     }
193
194     ui->ethertypeLabel->setEnabled(ethertype);
195     ui->ethertypeLineEdit->setEnabled(ethertype);
196     ui->protocolLabel->setEnabled(ipv4_proto);
197     ui->protocolLineEdit->setEnabled(ipv4_proto);
198     ui->sourcePortLabel->setEnabled(port);
199     ui->sourcePortLineEdit->setEnabled(port);
200     ui->destinationPortLabel->setEnabled(port);
201     ui->destinationPortLineEdit->setEnabled(port);
202     ui->tagLabel->setEnabled(sctp_tag);
203     ui->tagLineEdit->setEnabled(sctp_tag);
204     ui->ppiLabel->setEnabled(sctp_ppi);
205     ui->ppiLineEdit->setEnabled(sctp_ppi);
206 }
207
208 void ImportTextDialog::exec() {
209     QVariant encap_val;
210
211     QDialog::exec();
212
213     if (result() != QDialog::Accepted) {
214         return;
215     }
216
217     import_info_.import_text_filename = ui->textFileLineEdit->text().toUtf8().data();
218     import_info_.import_text_file = ws_fopen(import_info_.import_text_filename, "rb");
219     if (!import_info_.import_text_file) {
220         open_failure_alert_box(import_info_.import_text_filename, errno, FALSE);
221         setResult(QDialog::Rejected);
222         return;
223     }
224
225     import_info_.offset_type =
226         ui->hexOffsetButton->isChecked()     ? OFFSET_HEX :
227         ui->decimalOffsetButton->isChecked() ? OFFSET_DEC :
228         ui->octalOffsetButton->isChecked()   ? OFFSET_OCT :
229         OFFSET_NONE;
230     import_info_.date_timestamp = ui->dateTimeLineEdit->text().length() > 0;
231     import_info_.date_timestamp_format = ui->dateTimeLineEdit->text().toUtf8().data();
232
233     encap_val = ui->encapComboBox->itemData(ui->encapComboBox->currentIndex());
234     import_info_.dummy_header_type = HEADER_NONE;
235     if (encap_val.isValid() && encap_val.toUInt() == WTAP_ENCAP_ETHERNET && !ui->noDummyButton->isChecked()) {
236         // Inputs were validated in the on_xxx_textChanged slots.
237         if (ui->ethernetButton->isChecked()) {
238             import_info_.dummy_header_type = HEADER_ETH;
239         } else if (ui->ipv4Button->isChecked()) {
240             import_info_.dummy_header_type = HEADER_IPV4;
241         } else if(ui->udpButton->isChecked()) {
242             import_info_.dummy_header_type = HEADER_UDP;
243         } else if(ui->tcpButton->isChecked()) {
244             import_info_.dummy_header_type = HEADER_TCP;
245         } else if(ui->sctpButton->isChecked()) {
246             import_info_.dummy_header_type = HEADER_SCTP;
247         } else if(ui->sctpDataButton->isChecked()) {
248             import_info_.dummy_header_type = HEADER_SCTP_DATA;
249         }
250     }
251     if (import_info_.max_frame_length == 0) {
252         import_info_.max_frame_length = IMPORT_MAX_PACKET;
253     }
254
255     convertTextFile();
256 }
257
258 void ImportTextDialog::on_textFileBrowseButton_clicked()
259 {
260     char *open_dir = NULL;
261
262     switch (prefs.gui_fileopen_style) {
263
264     case FO_STYLE_LAST_OPENED:
265         /* The user has specified that we should start out in the last directory
266            we looked in.  If we've already opened a file, use its containing
267            directory, if we could determine it, as the directory, otherwise
268            use the "last opened" directory saved in the preferences file if
269            there was one. */
270         /* This is now the default behaviour in file_selection_new() */
271         open_dir = get_last_open_dir();
272         break;
273
274     case FO_STYLE_SPECIFIED:
275         /* The user has specified that we should always start out in a
276            specified directory; if they've specified that directory,
277            start out by showing the files in that dir. */
278         if (prefs.gui_fileopen_dir[0] != '\0')
279             open_dir = prefs.gui_fileopen_dir;
280         break;
281     }
282
283     QString file_name = QFileDialog::getOpenFileName(this, "Wireshark: Import text file", open_dir);
284     ui->textFileLineEdit->setText(file_name);
285 }
286
287 void ImportTextDialog::on_textFileLineEdit_textChanged(const QString &file_name)
288 {
289     QFile *text_file;
290
291     text_file = new QFile(file_name);
292     if (text_file->open(QIODevice::ReadOnly)) {
293         ok_button_->setEnabled(true);
294         text_file->close();
295     } else {
296         ok_button_->setEnabled(false);
297     }
298 }
299
300 void ImportTextDialog::on_encapComboBox_currentIndexChanged(int index)
301 {
302     QVariant val = ui->encapComboBox->itemData(index);
303     bool enabled = false;
304
305     if (val != QVariant::Invalid) {
306         import_info_.encapsulation = val.toUInt();
307
308         if (import_info_.encapsulation == WTAP_ENCAP_ETHERNET) enabled = true;
309     }
310
311     enableHeaderWidgets(enabled);
312 }
313
314 void ImportTextDialog::on_dateTimeLineEdit_textChanged(const QString &time_format)
315 {
316     if (time_format.length() > 0) {
317         time_t cur_time;
318         struct tm *cur_tm;
319         char time_str[100];
320
321         time(&cur_time);
322         cur_tm = localtime(&cur_time);
323         strftime(time_str, 100, ui->dateTimeLineEdit->text().toUtf8().constData(), cur_tm);
324         ui->timestampExampleLabel->setText(QString("Example: %1").arg(time_str));
325     } else {
326         ui->timestampExampleLabel->setText("<i>(No format will be applied)</i>");
327     }
328 }
329
330 void ImportTextDialog::on_noDummyButton_toggled(bool checked)
331 {
332     if (checked) enableHeaderWidgets();
333 }
334
335 void ImportTextDialog::on_ethernetButton_toggled(bool checked)
336 {
337     on_noDummyButton_toggled(checked);
338 }
339
340 void ImportTextDialog::on_ipv4Button_toggled(bool checked)
341 {
342     on_noDummyButton_toggled(checked);
343 }
344
345 void ImportTextDialog::on_udpButton_toggled(bool checked)
346 {
347     on_noDummyButton_toggled(checked);
348 }
349
350 void ImportTextDialog::on_tcpButton_toggled(bool checked)
351 {
352     on_noDummyButton_toggled(checked);
353 }
354
355 void ImportTextDialog::on_sctpButton_toggled(bool checked)
356 {
357     on_noDummyButton_toggled(checked);
358 }
359
360 void ImportTextDialog::on_sctpDataButton_toggled(bool checked)
361 {
362     on_noDummyButton_toggled(checked);
363 }
364
365 void ImportTextDialog::on_ethertypeLineEdit_textChanged(const QString &ethertype_str)
366 {
367     bool conv_ok;
368
369     import_info_.pid = ethertype_str.toUShort(&conv_ok, 16);
370     if (conv_ok && import_info_.pid <= 0xffff) {
371         ok_button_->setEnabled(true);
372     } else {
373         ok_button_->setEnabled(false);
374     }
375 }
376
377 void ImportTextDialog::on_protocolLineEdit_textChanged(const QString &protocol_str)
378 {
379     bool conv_ok;
380
381     import_info_.protocol = protocol_str.toUShort(&conv_ok, 10);
382     if (conv_ok && import_info_.protocol <= 0xff) {
383         ok_button_->setEnabled(true);
384     } else {
385         ok_button_->setEnabled(false);
386     }
387 }
388
389 void ImportTextDialog::on_sourcePortLineEdit_textChanged(const QString &source_port_str)
390 {
391     bool conv_ok;
392
393     import_info_.src_port = source_port_str.toUShort(&conv_ok, 10);
394     if (conv_ok && import_info_.src_port <= 0xffff) {
395         ok_button_->setEnabled(true);
396     } else {
397         ok_button_->setEnabled(false);
398     }
399 }
400
401 void ImportTextDialog::on_destinationPortLineEdit_textChanged(const QString &destination_port_str)
402 {
403     bool conv_ok;
404
405     import_info_.dst_port = destination_port_str.toUShort(&conv_ok, 10);
406     if (conv_ok && import_info_.dst_port <= 0xffff) {
407         ok_button_->setEnabled(true);
408     } else {
409         ok_button_->setEnabled(false);
410     }
411 }
412
413 void ImportTextDialog::on_tagLineEdit_textChanged(const QString &tag_str)
414 {
415     bool conv_ok;
416
417     import_info_.tag = tag_str.toULong(&conv_ok, 10);
418     if (conv_ok && import_info_.tag <= 0xffffffff) {
419         ok_button_->setEnabled(true);
420     } else {
421         ok_button_->setEnabled(false);
422     }
423 }
424
425 void ImportTextDialog::on_ppiLineEdit_textChanged(const QString &ppi_str)
426 {
427     bool conv_ok;
428
429     import_info_.ppi = ppi_str.toULong(&conv_ok, 10);
430     if (conv_ok && import_info_.ppi <= 0xffffffff) {
431         ok_button_->setEnabled(true);
432     } else {
433         ok_button_->setEnabled(false);
434     }
435 }
436
437 void ImportTextDialog::on_maxLengthLineEdit_textChanged(const QString &max_frame_len_str)
438 {
439     bool conv_ok;
440
441     import_info_.max_frame_length = max_frame_len_str.toUShort(&conv_ok, 10);
442     if (conv_ok && import_info_.max_frame_length <= IMPORT_MAX_PACKET) {
443         ok_button_->setEnabled(true);
444     } else {
445         ok_button_->setEnabled(false);
446     }
447 }
448
449 void ImportTextDialog::on_buttonBox_helpRequested()
450 {
451     gchar *url = topic_action_url(HELP_IMPORT_DIALOG);
452
453     if(url != NULL) {
454         QDesktopServices::openUrl(QUrl(url));
455         g_free(url);
456     }
457 }