1 /* capture_file.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 "capture_file.h"
11 
12 /*
13  * @file Capture file class
14  *
15  * Wraps the capture_file struct, cfile global, and callbacks.
16  */
17 
18 #include "globals.h"
19 capture_file cfile;
20 
21 #include "file.h"
22 
23 #include "epan/epan_dissect.h"
24 
25 #include "ui/capture.h"
26 
27 #include <QFileInfo>
28 #include <QTimer>
29 #include <QDebug>
30 
31 CaptureEvent::CaptureEvent(Context ctx, EventType evt) :
32     _ctx(ctx),
33     _evt(evt),
34     _session(Q_NULLPTR)
35 {
36 }
37 
38 CaptureEvent::CaptureEvent(Context ctx, EventType evt, QString file) :
39     _ctx(ctx),
40     _evt(evt),
41     _filePath(file),
42     _session(Q_NULLPTR)
43 {
44 }
45 
46 CaptureEvent::CaptureEvent(Context ctx, EventType evt, capture_session * session) :
47     _ctx(ctx),
48     _evt(evt),
49     _session(session)
50 {
51 }
52 
53 CaptureEvent::CaptureEvent(const CaptureEvent &ce) :
54     _ctx(ce._ctx),
55     _evt(ce._evt),
56     _filePath(ce._filePath),
57     _session(ce._session)
58 {
59 }
60 
61 CaptureEvent::Context CaptureEvent::captureContext() const
62 { return _ctx; }
63 
64 CaptureEvent::EventType CaptureEvent::eventType() const
65 { return _evt; }
66 
67 QString CaptureEvent::filePath() const
68 { return _filePath; }
69 
70 capture_session * CaptureEvent::capSession() const
71 { return _session; }
72 
73 // To do:
74 // - Add getters and (if needed) setters:
75 //   - Full filename
76 //   - Capture state (stopped, prepared, running).
77 // - Call common_create_progress_dlg. This would let us manage the stop
78 //   flag here as well as emit progress signals.
79 
80 QString CaptureFile::no_capture_file_ = QObject::tr("[no capture file]");
81 
82 CaptureFile::CaptureFile(QObject *parent, capture_file *cap_file) :
83     QObject(parent),
84     cap_file_(cap_file),
85     file_state_(QString())
86 {
87 #ifdef HAVE_LIBPCAP
88     capture_callback_add(captureCallback, (gpointer) this);
89 #endif
90     cf_callback_add(captureFileCallback, (gpointer) this);
91 }
92 
93 CaptureFile::~CaptureFile()
94 {
95     cf_callback_remove(captureFileCallback, this);
96 }
97 
98 bool CaptureFile::isValid() const
99 {
100     if (cap_file_ && cap_file_->state != FILE_CLOSED) { // XXX FILE_READ_IN_PROGRESS as well?
101         return true;
102     }
103     return false;
104 }
105 
106 int CaptureFile::currentRow()
107 {
108     if (isValid())
109         return cap_file_->current_row;
110     return -1;
111 }
112 
113 const QString CaptureFile::filePath()
114 {
115     QString path;
116 
117     if (isValid()) {
118         //
119         // Sadly, some UN*Xes don't necessarily use UTF-8
120         // for their file names, so we have to map the
121         // file path to UTF-8.  If that fails, we're somewhat
122         // stuck.
123         //
124         char *utf8_filename = g_filename_to_utf8(cap_file_->filename,
125                                                  -1,
126                                                  NULL,
127                                                  NULL,
128                                                  NULL);
129         if (utf8_filename) {
130             path = QString::fromUtf8(utf8_filename);
131             g_free(utf8_filename);
132         } else {
133             // So what the heck else can we do here?
134             path = QString();
135         }
136     } else {
137         path = QString();
138     }
139     return path;
140 }
141 
142 const QString CaptureFile::fileName()
143 {
144     QString path, name;
145 
146     path = filePath();
147     if (!path.isEmpty()) {
148         QFileInfo cfi(path);
149         name = cfi.fileName();
150     } else {
151         name = QString();
152     }
153 
154     return name;
155 }
156 
157 const QString CaptureFile::fileBaseName()
158 {
159     QString baseName;
160 
161     if (isValid()) {
162         char *basename = cf_get_basename(cap_file_);
163         baseName = basename;
164         g_free(basename);
165     } else {
166         baseName = QString();
167     }
168     return baseName;
169 }
170 
171 const QString CaptureFile::fileDisplayName()
172 {
173     QString displayName;
174 
175     if (isValid()) {
176         char *display_name = cf_get_display_name(cap_file_);
177         displayName = display_name;
178         g_free(display_name);
179     } else {
180         displayName = QString();
181     }
182     return displayName;
183 }
184 
185 const QString CaptureFile::fileTitle()
186 {
187     QString title;
188 
189     if (isValid()) {
190         title = fileDisplayName() + file_state_;
191     } else {
192         title = no_capture_file_;
193     }
194     return title;
195 }
196 
197 struct _packet_info *CaptureFile::packetInfo()
198 {
199     if (capFile() && capFile()->edt) {
200         return &(capFile()->edt->pi);
201     }
202     return NULL;
203 }
204 
205 int CaptureFile::timestampPrecision()
206 {
207     if (capFile() && capFile()->provider.wth) {
208         return wtap_file_tsprec(capFile()->provider.wth);
209     }
210     return WTAP_TSPREC_UNKNOWN;
211 }
212 
213 void CaptureFile::retapPackets()
214 {
215     if (cap_file_) {
216         cf_retap_packets(cap_file_);
217     }
218 }
219 
220 void CaptureFile::delayedRetapPackets()
221 {
222     QTimer::singleShot(0, this, SLOT(retapPackets()));
223 }
224 
225 void CaptureFile::reload()
226 {
227     if (cap_file_ && cap_file_->state == FILE_READ_DONE) {
228         cf_reload(cap_file_);
229     }
230 }
231 
232 void CaptureFile::stopLoading()
233 {
234     setCaptureStopFlag(true);
235 }
236 
237 capture_file *CaptureFile::globalCapFile()
238 {
239     return &cfile;
240 }
241 
242 gpointer CaptureFile::window()
243 {
244     if (cap_file_) return cap_file_->window;
245     return NULL;
246 }
247 
248 void CaptureFile::setCaptureStopFlag(bool stop_flag)
249 {
250     if (cap_file_) cap_file_->stop_flag = stop_flag;
251 }
252 
253 void CaptureFile::captureFileCallback(gint event, gpointer data, gpointer user_data)
254 {
255     CaptureFile *capture_file = static_cast<CaptureFile *>(user_data);
256     if (!capture_file) return;
257 
258     capture_file->captureFileEvent(event, data);
259 }
260 
261 #ifdef HAVE_LIBPCAP
262 void CaptureFile::captureCallback(gint event, capture_session *cap_session, gpointer user_data)
263 {
264     CaptureFile *capture_file = static_cast<CaptureFile *>(user_data);
265     if (!capture_file) return;
266 
267     capture_file->captureSessionEvent(event, cap_session);
268 }
269 #endif
270 
271 void CaptureFile::captureFileEvent(int event, gpointer data)
272 {
273     switch(event) {
274     case(cf_cb_file_opened):
275         cap_file_ = (capture_file *) data;
276         emit captureEvent(CaptureEvent(CaptureEvent::File, CaptureEvent::Opened));
277         break;
278     case(cf_cb_file_closing):
279         file_state_ = tr(" [closing]");
280         emit captureEvent(CaptureEvent(CaptureEvent::File, CaptureEvent::Closing));
281         break;
282     case(cf_cb_file_closed):
283         file_state_ = tr(" [closed]");
284         emit captureEvent(CaptureEvent(CaptureEvent::File, CaptureEvent::Closed));
285         cap_file_ = NULL;
286         file_state_ = QString();
287         break;
288     case(cf_cb_file_read_started):
289         emit captureEvent(CaptureEvent(CaptureEvent::File, CaptureEvent::Started));
290         break;
291     case(cf_cb_file_read_finished):
292         emit captureEvent(CaptureEvent(CaptureEvent::File, CaptureEvent::Finished));
293         break;
294     case(cf_cb_file_reload_started):
295         emit captureEvent(CaptureEvent(CaptureEvent::Reload, CaptureEvent::Started));
296         break;
297     case(cf_cb_file_reload_finished):
298         emit captureEvent(CaptureEvent(CaptureEvent::Reload, CaptureEvent::Finished));
299         break;
300     case(cf_cb_file_rescan_started):
301         emit captureEvent(CaptureEvent(CaptureEvent::Rescan, CaptureEvent::Started));
302         break;
303     case(cf_cb_file_rescan_finished):
304         emit captureEvent(CaptureEvent(CaptureEvent::Rescan, CaptureEvent::Finished));
305         break;
306     case(cf_cb_file_retap_started):
307         emit captureEvent(CaptureEvent(CaptureEvent::Retap, CaptureEvent::Started));
308         break;
309     case(cf_cb_file_retap_finished):
310         /* Flush any pending tapped packet before emitting captureFileRetapFinished() */
311         emit captureEvent(CaptureEvent(CaptureEvent::Retap, CaptureEvent::Finished));
312         emit captureEvent(CaptureEvent(CaptureEvent::Retap, CaptureEvent::Flushed));
313         break;
314     case(cf_cb_file_merge_started):
315         emit captureEvent(CaptureEvent(CaptureEvent::Merge, CaptureEvent::Started));
316         break;
317     case(cf_cb_file_merge_finished):
318         emit captureEvent(CaptureEvent(CaptureEvent::Merge, CaptureEvent::Finished));
319         break;
320 
321     case(cf_cb_file_fast_save_finished):
322         // gtk/main.c calls main_cf_cb_file_rescan_finished. Should we do
323         // the equivalent?
324         break;
325 
326     case(cf_cb_file_save_started):
327     {
328         emit captureEvent(CaptureEvent(CaptureEvent::Save, CaptureEvent::Started, QString((const char *)data)));
329         break;
330     }
331     case(cf_cb_file_save_finished):
332         emit captureEvent(CaptureEvent(CaptureEvent::Save, CaptureEvent::Finished));
333         break;
334     case(cf_cb_file_save_failed):
335         emit captureEvent(CaptureEvent(CaptureEvent::Save, CaptureEvent::Failed));
336         break;
337     case(cf_cb_file_save_stopped):
338         emit captureEvent(CaptureEvent(CaptureEvent::Save, CaptureEvent::Stopped));
339         break;
340 
341     default:
342         qWarning() << "CaptureFile::captureFileCallback: event " << event << " unknown";
343         Q_ASSERT(false);
344         break;
345     }
346 }
347 
348 #ifdef HAVE_LIBPCAP
349 void CaptureFile::captureSessionEvent(int event, capture_session *cap_session)
350 {
351     switch(event) {
352     case(capture_cb_capture_prepared):
353         emit captureEvent(CaptureEvent(CaptureEvent::Capture, CaptureEvent::Prepared, cap_session));
354         cap_file_ = cap_session->cf;
355         break;
356     case(capture_cb_capture_update_started):
357         emit captureEvent(CaptureEvent(CaptureEvent::Update, CaptureEvent::Started, cap_session));
358         break;
359     case(capture_cb_capture_update_continue):
360         emit captureEvent(CaptureEvent(CaptureEvent::Update, CaptureEvent::Continued, cap_session));
361         break;
362     case(capture_cb_capture_update_finished):
363         emit captureEvent(CaptureEvent(CaptureEvent::Update, CaptureEvent::Finished, cap_session));
364         break;
365     case(capture_cb_capture_fixed_started):
366         emit captureEvent(CaptureEvent(CaptureEvent::Fixed, CaptureEvent::Started, cap_session));
367         break;
368     case(capture_cb_capture_fixed_continue):
369         emit captureEvent(CaptureEvent(CaptureEvent::Fixed, CaptureEvent::Continued, cap_session));
370         break;
371     case(capture_cb_capture_fixed_finished):
372         emit captureEvent(CaptureEvent(CaptureEvent::Fixed, CaptureEvent::Finished, cap_session));
373         break;
374     case(capture_cb_capture_stopping):
375         /* Beware: this state won't be called, if the capture child
376              * closes the capturing on it's own! */
377         emit captureEvent(CaptureEvent(CaptureEvent::Capture, CaptureEvent::Stopping, cap_session));
378         break;
379     case(capture_cb_capture_failed):
380         emit captureEvent(CaptureEvent(CaptureEvent::Capture, CaptureEvent::Failed, cap_session));
381         break;
382     default:
383         qWarning() << "main_capture_callback: event " << event << " unknown";
384     }
385 }
386 #endif // HAVE_LIBPCAP
387