eafaf80cb08f5b2f301dbfb082ef8f94d9df4780
[metze/wireshark/wip.git] / ui / qt / import_text_dialog.cpp
1 /* import_text_dialog.cpp
2  *
3  * $Id$
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 "wsutil/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
51 ImportTextDialog::ImportTextDialog(QWidget *parent) :
52     QDialog(parent),
53     ti_ui_(new Ui::ImportTextDialog),
54     import_info_()
55 {
56     int encap;
57     int i;
58
59     ti_ui_->setupUi(this);
60     memset(&import_info_, 0, sizeof(import_info_));
61
62     ok_button_ = ti_ui_->buttonBox->button(QDialogButtonBox::Ok);
63     ok_button_->setEnabled(false);
64
65 #ifdef Q_OS_MAC
66     // The grid layout squishes each line edit otherwise.
67     int le_height = ti_ui_->textFileLineEdit->sizeHint().height();
68     ti_ui_->ethertypeLineEdit->setMinimumHeight(le_height);
69     ti_ui_->protocolLineEdit->setMinimumHeight(le_height);
70     ti_ui_->sourcePortLineEdit->setMinimumHeight(le_height);
71     ti_ui_->destinationPortLineEdit->setMinimumHeight(le_height);
72     ti_ui_->tagLineEdit->setMinimumHeight(le_height);
73     ti_ui_->ppiLineEdit->setMinimumHeight(le_height);
74 #endif
75
76     on_dateTimeLineEdit_textChanged(ti_ui_->dateTimeLineEdit->text());
77
78     for (i = 0; i < ti_ui_->headerGridLayout->count(); i++) {
79         QRadioButton *rb = qobject_cast<QRadioButton *>(ti_ui_->headerGridLayout->itemAt(i)->widget());
80
81         if (rb) encap_buttons_.append(rb);
82     }
83
84     /* Scan all Wiretap encapsulation types */
85     import_info_.encapsulation = WTAP_ENCAP_ETHERNET;
86     for (encap = import_info_.encapsulation; encap < wtap_get_num_encap_types(); encap++)
87     {
88         /* Check if we can write to a PCAP file
89          *
90          * Exclude wtap encapsulations that require a pseudo header,
91          * because we won't setup one from the text we import and
92          * wiretap doesn't allow us to write 'raw' frames
93          */
94         if ((wtap_wtap_encap_to_pcap_encap(encap) > 0) && !wtap_encap_requires_phdr(encap)) {
95             const char *name;
96             /* If it has got a name */
97             if ((name = wtap_encap_string(encap)))
98             {
99                 ti_ui_->encapComboBox->addItem(name, QVariant(encap));
100             }
101         }
102     }
103     ti_ui_->encapComboBox->model()->sort(0);
104 }
105
106 ImportTextDialog::~ImportTextDialog()
107 {
108     delete ti_ui_;
109 }
110
111 QString &ImportTextDialog::capfileName() {
112     return capfile_name_;
113 }
114
115 void ImportTextDialog::convertTextFile() {
116     int import_file_fd;
117     char *tmpname;
118     int err;
119
120     capfile_name_.clear();
121     /* Choose a random name for the temporary import buffer */
122     import_file_fd = create_tempfile(&tmpname, "import");
123     capfile_name_.append(tmpname);
124
125     import_info_.wdh = wtap_dump_fdopen(import_file_fd, WTAP_FILE_PCAP, import_info_.encapsulation, import_info_.max_frame_length, FALSE, &err);
126     qDebug() << capfile_name_ << ":" << import_info_.wdh << import_info_.encapsulation << import_info_.max_frame_length;
127     if (import_info_.wdh == NULL) {
128         open_failure_alert_box(capfile_name_.toUtf8().constData(), err, TRUE);
129         fclose(import_info_.import_text_file);
130         setResult(QDialog::Rejected);
131         return;
132     }
133
134     text_import_setup(&import_info_);
135
136     text_importin = import_info_.import_text_file;
137
138     text_importlex();
139
140     text_import_cleanup();
141
142     if (fclose(import_info_.import_text_file))
143     {
144         read_failure_alert_box(import_info_.import_text_filename, errno);
145     }
146
147     if (!wtap_dump_close(import_info_.wdh, &err))
148     {
149         write_failure_alert_box(capfile_name_.toUtf8().constData(), err);
150     }
151 }
152
153
154 void ImportTextDialog::enableHeaderWidgets(bool enable_buttons) {
155     bool ethertype = false;
156     bool ipv4_proto = false;
157     bool port = false;
158     bool sctp_tag = false;
159     bool sctp_ppi = false;
160
161     if (enable_buttons) {
162         if (ti_ui_->ethernetButton->isChecked()) {
163             ethertype = true;
164             on_ethertypeLineEdit_textChanged(ti_ui_->ethertypeLineEdit->text());
165         } else  if (ti_ui_->ipv4Button->isChecked()) {
166             ipv4_proto = true;
167             on_protocolLineEdit_textChanged(ti_ui_->protocolLineEdit->text());
168         } else if (ti_ui_->udpButton->isChecked() || ti_ui_->tcpButton->isChecked()) {
169             port = true;
170             on_sourcePortLineEdit_textChanged(ti_ui_->sourcePortLineEdit->text());
171             on_destinationPortLineEdit_textChanged(ti_ui_->destinationPortLineEdit->text());
172         } else if (ti_ui_->sctpButton->isChecked()) {
173             port = true;
174             sctp_tag = true;
175             on_sourcePortLineEdit_textChanged(ti_ui_->sourcePortLineEdit->text());
176             on_destinationPortLineEdit_textChanged(ti_ui_->destinationPortLineEdit->text());
177             on_tagLineEdit_textChanged(ti_ui_->tagLineEdit->text());
178         }
179         if (ti_ui_->sctpDataButton->isChecked()) {
180             port = true;
181             sctp_ppi = true;
182             on_sourcePortLineEdit_textChanged(ti_ui_->sourcePortLineEdit->text());
183             on_destinationPortLineEdit_textChanged(ti_ui_->destinationPortLineEdit->text());
184             on_ppiLineEdit_textChanged(ti_ui_->ppiLineEdit->text());
185         }
186     }
187
188     foreach (QRadioButton *rb, encap_buttons_) {
189         rb->setEnabled(enable_buttons);
190     }
191
192     ti_ui_->ethertypeLabel->setEnabled(ethertype);
193     ti_ui_->ethertypeLineEdit->setEnabled(ethertype);
194     ti_ui_->protocolLabel->setEnabled(ipv4_proto);
195     ti_ui_->protocolLineEdit->setEnabled(ipv4_proto);
196     ti_ui_->sourcePortLabel->setEnabled(port);
197     ti_ui_->sourcePortLineEdit->setEnabled(port);
198     ti_ui_->destinationPortLabel->setEnabled(port);
199     ti_ui_->destinationPortLineEdit->setEnabled(port);
200     ti_ui_->tagLabel->setEnabled(sctp_tag);
201     ti_ui_->tagLineEdit->setEnabled(sctp_tag);
202     ti_ui_->ppiLabel->setEnabled(sctp_ppi);
203     ti_ui_->ppiLineEdit->setEnabled(sctp_ppi);
204 }
205
206 int ImportTextDialog::exec() {
207     QVariant encap_val;
208
209     QDialog::exec();
210
211     if (result() != QDialog::Accepted) {
212         return result();
213     }
214
215     import_info_.import_text_filename = strdup(ti_ui_->textFileLineEdit->text().toUtf8().data());
216     import_info_.import_text_file = ws_fopen(import_info_.import_text_filename, "rb");
217     if (!import_info_.import_text_file) {
218         open_failure_alert_box(import_info_.import_text_filename, errno, FALSE);
219         setResult(QDialog::Rejected);
220         return QDialog::Rejected;
221     }
222
223     import_info_.offset_type =
224         ti_ui_->hexOffsetButton->isChecked()     ? OFFSET_HEX :
225         ti_ui_->decimalOffsetButton->isChecked() ? OFFSET_DEC :
226         ti_ui_->octalOffsetButton->isChecked()   ? OFFSET_OCT :
227         OFFSET_NONE;
228     import_info_.date_timestamp = ti_ui_->dateTimeLineEdit->text().length() > 0;
229     import_info_.date_timestamp_format = strdup(ti_ui_->dateTimeLineEdit->text().toUtf8().data());
230
231     encap_val = ti_ui_->encapComboBox->itemData(ti_ui_->encapComboBox->currentIndex());
232     import_info_.dummy_header_type = HEADER_NONE;
233     if (encap_val.isValid() && encap_val.toUInt() == WTAP_ENCAP_ETHERNET && !ti_ui_->noDummyButton->isChecked()) {
234         // Inputs were validated in the on_xxx_textChanged slots.
235         if (ti_ui_->ethernetButton->isChecked()) {
236             import_info_.dummy_header_type = HEADER_ETH;
237         } else if (ti_ui_->ipv4Button->isChecked()) {
238             import_info_.dummy_header_type = HEADER_IPV4;
239         } else if(ti_ui_->udpButton->isChecked()) {
240             import_info_.dummy_header_type = HEADER_UDP;
241         } else if(ti_ui_->tcpButton->isChecked()) {
242             import_info_.dummy_header_type = HEADER_TCP;
243         } else if(ti_ui_->sctpButton->isChecked()) {
244             import_info_.dummy_header_type = HEADER_SCTP;
245         } else if(ti_ui_->sctpDataButton->isChecked()) {
246             import_info_.dummy_header_type = HEADER_SCTP_DATA;
247         }
248     }
249     if (import_info_.max_frame_length == 0) {
250         import_info_.max_frame_length = IMPORT_MAX_PACKET;
251     }
252
253     convertTextFile();
254     return QDialog::Accepted;
255 }
256
257 void ImportTextDialog::on_textFileBrowseButton_clicked()
258 {
259     char *open_dir = NULL;
260
261     switch (prefs.gui_fileopen_style) {
262
263     case FO_STYLE_LAST_OPENED:
264         /* The user has specified that we should start out in the last directory
265            we looked in.  If we've already opened a file, use its containing
266            directory, if we could determine it, as the directory, otherwise
267            use the "last opened" directory saved in the preferences file if
268            there was one. */
269         /* This is now the default behaviour in file_selection_new() */
270         open_dir = get_last_open_dir();
271         break;
272
273     case FO_STYLE_SPECIFIED:
274         /* The user has specified that we should always start out in a
275            specified directory; if they've specified that directory,
276            start out by showing the files in that dir. */
277         if (prefs.gui_fileopen_dir[0] != '\0')
278             open_dir = prefs.gui_fileopen_dir;
279         break;
280     }
281
282     QString file_name = QFileDialog::getOpenFileName(this, tr("Wireshark: Import text file"), open_dir);
283     ti_ui_->textFileLineEdit->setText(file_name);
284 }
285
286 void ImportTextDialog::on_textFileLineEdit_textChanged(const QString &file_name)
287 {
288     QFile *text_file;
289
290     text_file = new QFile(file_name);
291     if (text_file->open(QIODevice::ReadOnly)) {
292         ok_button_->setEnabled(true);
293         text_file->close();
294     } else {
295         ok_button_->setEnabled(false);
296     }
297 }
298
299 void ImportTextDialog::on_encapComboBox_currentIndexChanged(int index)
300 {
301     QVariant val = ti_ui_->encapComboBox->itemData(index);
302     bool enabled = false;
303
304     if (val != QVariant::Invalid) {
305         import_info_.encapsulation = val.toUInt();
306
307         if (import_info_.encapsulation == WTAP_ENCAP_ETHERNET) enabled = true;
308     }
309
310     enableHeaderWidgets(enabled);
311 }
312
313 void ImportTextDialog::on_dateTimeLineEdit_textChanged(const QString &time_format)
314 {
315     if (time_format.length() > 0) {
316         time_t cur_time;
317         struct tm *cur_tm;
318         char time_str[100];
319
320         time(&cur_time);
321         cur_tm = localtime(&cur_time);
322         strftime(time_str, 100, ti_ui_->dateTimeLineEdit->text().toUtf8().constData(), cur_tm);
323         ti_ui_->timestampExampleLabel->setText(QString(tr("Example: %1")).arg(time_str));
324     } else {
325         ti_ui_->timestampExampleLabel->setText(tr("<i>(No format will be applied)</i>"));
326     }
327 }
328
329 void ImportTextDialog::on_directionIndicationCheckBox_toggled(bool checked)
330 {
331     import_info_.has_direction = checked;
332 }
333
334 void ImportTextDialog::on_noDummyButton_toggled(bool checked)
335 {
336     if (checked) enableHeaderWidgets();
337 }
338
339 void ImportTextDialog::on_ethernetButton_toggled(bool checked)
340 {
341     on_noDummyButton_toggled(checked);
342 }
343
344 void ImportTextDialog::on_ipv4Button_toggled(bool checked)
345 {
346     on_noDummyButton_toggled(checked);
347 }
348
349 void ImportTextDialog::on_udpButton_toggled(bool checked)
350 {
351     on_noDummyButton_toggled(checked);
352 }
353
354 void ImportTextDialog::on_tcpButton_toggled(bool checked)
355 {
356     on_noDummyButton_toggled(checked);
357 }
358
359 void ImportTextDialog::on_sctpButton_toggled(bool checked)
360 {
361     on_noDummyButton_toggled(checked);
362 }
363
364 void ImportTextDialog::on_sctpDataButton_toggled(bool checked)
365 {
366     on_noDummyButton_toggled(checked);
367 }
368
369 void ImportTextDialog::check_line_edit(SyntaxLineEdit *le, const QString &num_str, int base, guint max_val, bool is_short, guint *val_ptr) {
370     bool conv_ok;
371     SyntaxLineEdit::SyntaxState syntax_state = SyntaxLineEdit::Empty;
372     bool ok_enabled = true;
373
374     if (!le || !val_ptr)
375         return;
376
377     if (num_str.length() < 1) {
378         *val_ptr = 0;
379     } else {
380         if (is_short) {
381             *val_ptr = num_str.toUShort(&conv_ok, base);
382         } else {
383             *val_ptr = num_str.toULong(&conv_ok, base);
384         }
385         if (conv_ok && *val_ptr <= max_val) {
386             syntax_state = SyntaxLineEdit::Valid;
387         } else {
388             syntax_state = SyntaxLineEdit::Invalid;
389             ok_enabled = false;
390         }
391     }
392     le->setSyntaxState(syntax_state);
393     ok_button_->setEnabled(ok_enabled);
394 }
395
396 void ImportTextDialog::on_ethertypeLineEdit_textChanged(const QString &ethertype_str)
397 {
398     check_line_edit(ti_ui_->ethertypeLineEdit, ethertype_str, 16, 0xffff, true, &import_info_.pid);
399 }
400
401 void ImportTextDialog::on_protocolLineEdit_textChanged(const QString &protocol_str)
402 {
403     check_line_edit(ti_ui_->protocolLineEdit, protocol_str, 10, 0xff, true, &import_info_.protocol);
404 }
405
406 void ImportTextDialog::on_sourcePortLineEdit_textChanged(const QString &source_port_str)
407 {
408     check_line_edit(ti_ui_->sourcePortLineEdit, source_port_str, 10, 0xffff, true, &import_info_.src_port);
409 }
410
411 void ImportTextDialog::on_destinationPortLineEdit_textChanged(const QString &destination_port_str)
412 {
413     check_line_edit(ti_ui_->destinationPortLineEdit, destination_port_str, 10, 0xffff, true, &import_info_.dst_port);
414 }
415
416 void ImportTextDialog::on_tagLineEdit_textChanged(const QString &tag_str)
417 {
418     check_line_edit(ti_ui_->tagLineEdit, tag_str, 10, 0xffffffff, false, &import_info_.tag);
419 }
420
421 void ImportTextDialog::on_ppiLineEdit_textChanged(const QString &ppi_str)
422 {
423     check_line_edit(ti_ui_->ppiLineEdit, ppi_str, 10, 0xffffffff, false, &import_info_.ppi);
424 }
425
426 void ImportTextDialog::on_maxLengthLineEdit_textChanged(const QString &max_frame_len_str)
427 {
428     check_line_edit(ti_ui_->maxLengthLineEdit, max_frame_len_str, 10, IMPORT_MAX_PACKET, true, &import_info_.max_frame_length);
429 }
430
431 void ImportTextDialog::on_buttonBox_helpRequested()
432 {
433     wsApp->helpTopicAction(HELP_IMPORT_DIALOG);
434 }
435
436 /*
437  * Editor modelines
438  *
439  * Local Variables:
440  * c-basic-offset: 4
441  * tab-width: 8
442  * indent-tabs-mode: nil
443  * End:
444  *
445  * ex: set shiftwidth=4 tabstop=8 expandtab:
446  * :indentSize=4:tabSize=8:noTabs=true:
447  */