Store pointers to previously displayed and captured packet, not nstime_t deltas.
[metze/wireshark/wip.git] / ui / gtk / time_shift_dlg.c
1 /* time_shift_dlg.c
2  * Routines for "Time Shift" window
3  * Submitted by Edwin Groothuis <wireshark@mavetju.org>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <string.h>
29 #include <ctype.h>
30 #include <math.h>
31
32 #include <gtk/gtk.h>
33
34 #include <epan/proto.h>
35 #include <epan/dfilter/dfilter.h>
36 #include <epan/nstime.h>
37 #include <epan/strutil.h>
38 #include <epan/prefs.h>
39
40 #include "../globals.h"
41
42 #include "ui/alert_box.h"
43 #include "ui/simple_dialog.h"
44 #include "ui/main_statusbar.h"
45 #include "ui/ui_util.h"
46
47 #include "ui/gtk/gui_utils.h"
48 #include "ui/gtk/time_shift_dlg.h"
49 #include "ui/gtk/dlg_utils.h"
50 #include "ui/gtk/stock_icons.h"
51 #include "ui/gtk/prefs_dlg.h"
52 #include "ui/gtk/keys.h"
53 #include "ui/gtk/help_dlg.h"
54
55 /* Capture callback data keys */
56 #define E_TIMESHIFT_SELECT          "timeshift_select"
57 #define E_TIMESHIFT_OFFSET_KEY      "timeshift_offset_te"
58 #define E_SETTIME_SELECT            "settime_select"
59 #define E_SETTIME_TIME_KEY          "settime_time_te"
60 #define E_SETTIME_PACKETNUMBER_KEY  "settime_packetnumber_te"
61 #define E_ADJTIME_SELECT            "adjtime_select"
62 #define E_ADJTIME_TIME1_KEY         "adjtime_time1_te"
63 #define E_ADJTIME_PACKETNUMBER1_KEY "adjtime_packetnumber1_te"
64 #define E_ADJTIME_TIME2_KEY         "adjtime_time2_te"
65 #define E_ADJTIME_PACKETNUMBER2_KEY "adjtime_packetnumber2_te"
66 #define E_UNDO_SELECT               "undo_select"
67 #define E_UNDO_SHIFT_KEY            "undo_shift_cb"
68
69 static void time_shift_apply_cb(GtkWidget *ok_bt, GtkWindow *parent_w);
70 static void time_shift_close_cb(GtkWidget *close_bt, gpointer parent_w);
71 static void time_shift_frame_destroy_cb(GtkWidget *win, gpointer user_data);
72
73 static void error_message(const gchar *msg);
74
75 #define SHIFT_POS               0
76 #define SHIFT_NEG               1
77 #define SHIFT_SETTOZERO         1
78 #define SHIFT_KEEPOFFSET        0
79 static void modify_time_init(frame_data *fd);
80 static void modify_time_perform(frame_data *fd, int neg, nstime_t *offset,
81     int settozero);
82
83 /*
84  * Keep a static pointer to the current "Time Shift" window, if any, so
85  * that if somebody tries to do "Time Shift" while there's already a
86  * "Time Shift" window up, we just pop up the existing one, rather than
87  * creating a new one.
88  */
89 static GtkWidget *time_shift_frame_w;
90
91 void
92 time_shift_cb(GtkWidget *w _U_, gpointer d _U_)
93 {
94   GtkWidget     *main_vb, *main_hb, *label,
95                 *types_frame, *types_vb,
96
97                 *timeshift_offset_hb,
98                 *timeshift_offset_text_box,
99
100                 *settime_time_hb,
101                 *settime_packetnumber_text_box,
102                 *settime_time_text_box,
103
104                 *adjtime_offset_hb,
105                 *adjtime_packetnumber1_text_box,
106                 *adjtime_packetnumber2_text_box,
107                 *adjtime_time1_text_box,
108                 *adjtime_time2_text_box,
109
110                 *undo_offset_hb,
111                 *undo_type_hb,
112
113                 *timeshift_rb, *settime_rb,
114                 *adjtime_rb, *undo_rb,
115
116                 *bbox, *apply_bt, *close_bt, *help_bt;
117  
118   if (time_shift_frame_w != NULL) {
119     /* There's already a "Time Shift" dialog box; reactivate it. */
120     reactivate_window(time_shift_frame_w);
121     return;
122   }
123  
124   time_shift_frame_w = dlg_window_new("Wireshark: Time Shift");
125  
126   /* Container for each row of widgets */
127   main_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
128   gtk_container_set_border_width(GTK_CONTAINER(main_vb), 5);
129   gtk_container_add(GTK_CONTAINER(time_shift_frame_w), main_vb);
130   gtk_widget_show(main_vb);
131
132
133   /*
134    * Shift All Packets frame
135    */
136   main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
137   gtk_box_pack_start(GTK_BOX(main_vb), main_hb, TRUE, TRUE, 0);
138   gtk_widget_show(main_hb);
139
140   types_frame = gtk_frame_new(NULL);
141   gtk_box_pack_start(GTK_BOX(main_hb), types_frame, TRUE, TRUE, 0);
142   gtk_widget_show(types_frame);
143
144   types_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
145   gtk_container_set_border_width(GTK_CONTAINER(types_vb), 3);
146   gtk_container_add(GTK_CONTAINER(types_frame), types_vb);
147   gtk_widget_show(types_vb);
148
149   /* Radio button row */
150   timeshift_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
151   gtk_box_pack_start(GTK_BOX(types_vb), timeshift_offset_hb, FALSE, FALSE, 0);
152   gtk_widget_show(timeshift_offset_hb);
153
154   timeshift_rb = gtk_radio_button_new_with_label (NULL, "Shift all packets");
155   gtk_box_pack_start(GTK_BOX(timeshift_offset_hb), timeshift_rb, TRUE, TRUE, 0);
156   gtk_widget_show(timeshift_rb);
157   gtk_widget_set_tooltip_text(timeshift_rb, "Shift the time on the frames.");
158
159   /* Time Shift entry row */
160   timeshift_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
161   gtk_box_pack_start(GTK_BOX(types_vb), timeshift_offset_hb, FALSE, FALSE, 0);
162   gtk_widget_show(timeshift_offset_hb);
163
164   label = gtk_label_new("Time offset in the format [+-][[hh:]mm:]ss[.ddd]");
165   gtk_box_pack_start(GTK_BOX(timeshift_offset_hb), label, FALSE, FALSE, 0);
166   gtk_widget_show(label);
167
168   timeshift_offset_text_box = gtk_entry_new();
169   gtk_box_pack_start(GTK_BOX(timeshift_offset_hb), timeshift_offset_text_box,
170     TRUE, TRUE, 0);
171   gtk_widget_show(timeshift_offset_text_box);
172   gtk_widget_set_tooltip_text(timeshift_offset_text_box,
173     "Enter the time to shift here. The format is "
174     "[+-][[hh:]mm:]ss.[.ddddddddd].");
175
176   /*
177    * Set Packet Number to Time frame
178    */
179   main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
180   gtk_box_pack_start(GTK_BOX(main_vb), main_hb, TRUE, TRUE, 0);
181   gtk_widget_show(main_hb);
182
183   types_frame = gtk_frame_new(NULL);
184   gtk_box_pack_start(GTK_BOX(main_hb), types_frame, TRUE, TRUE, 0);
185   gtk_widget_show(types_frame);
186
187   types_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
188   gtk_container_set_border_width(GTK_CONTAINER(types_vb), 3);
189   gtk_container_add(GTK_CONTAINER(types_frame), types_vb);
190   gtk_widget_show(types_vb);
191
192   /* time shift type row */
193   settime_time_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
194   gtk_box_pack_start(GTK_BOX(types_vb), settime_time_hb, FALSE,
195     FALSE, 0);
196   gtk_widget_show(settime_time_hb);
197
198   settime_rb = gtk_radio_button_new_with_label(gtk_radio_button_get_group(
199     GTK_RADIO_BUTTON(timeshift_rb)), "Set packet to time");
200   gtk_box_pack_start(GTK_BOX(settime_time_hb), settime_rb, TRUE, TRUE, 0);
201   gtk_widget_show(settime_rb);
202   gtk_widget_set_tooltip_text(settime_rb,
203     "Set the time of a certain frame and adjust the rest of the frames "
204     "automatically.");
205
206   settime_time_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
207   gtk_box_pack_start(GTK_BOX(types_vb), settime_time_hb, FALSE,
208     FALSE, 0);
209   gtk_widget_show(settime_time_hb);
210
211   label = gtk_label_new("Packet number");
212   gtk_box_pack_start(GTK_BOX(settime_time_hb), label, FALSE, FALSE, 0);
213   gtk_widget_show(label);
214
215   settime_packetnumber_text_box = gtk_entry_new();
216   gtk_box_pack_start(GTK_BOX(settime_time_hb), settime_packetnumber_text_box,
217     TRUE, TRUE, 0);
218   gtk_entry_set_text(GTK_ENTRY(settime_packetnumber_text_box), "");
219   gtk_widget_show(settime_packetnumber_text_box);
220   gtk_widget_set_tooltip_text(settime_packetnumber_text_box,
221     "The frame which will be set to the time.");
222
223   /* time shift row */
224   settime_time_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
225   gtk_box_pack_start(GTK_BOX(types_vb), settime_time_hb, FALSE, FALSE,
226     0);
227   gtk_widget_show(settime_time_hb);
228
229   label = gtk_label_new("Set packet to time [YYYY-MM-DD] hh:mm:ss[.ddd]");
230   gtk_box_pack_start(GTK_BOX(settime_time_hb), label, FALSE, FALSE, 0);
231   gtk_widget_show(label);
232
233   settime_time_text_box = gtk_entry_new();
234   gtk_box_pack_start(GTK_BOX(settime_time_hb), settime_time_text_box, TRUE,
235     TRUE, 0);
236   gtk_widget_show(settime_time_text_box);
237   gtk_widget_set_tooltip_text(settime_time_text_box,
238     "The time for the frame in the format of [YYYY-MM-DD] "
239     "hh:mm:ss[.ddddddddd]");
240  
241   /*
242    * Set two Packet Numbers to Time frame and extrapolate
243    */
244   main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
245   gtk_box_pack_start(GTK_BOX(main_vb), main_hb, TRUE, TRUE, 0);
246   gtk_widget_show(main_hb);
247
248   types_frame = gtk_frame_new(NULL);
249   gtk_box_pack_start(GTK_BOX(main_hb), types_frame, TRUE, TRUE, 0);
250   gtk_widget_show(types_frame);
251
252   types_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
253   gtk_container_set_border_width(GTK_CONTAINER(types_vb), 3);
254   gtk_container_add(GTK_CONTAINER(types_frame), types_vb);
255   gtk_widget_show(types_vb);
256
257   /* packet number row 1 */
258   adjtime_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
259   gtk_box_pack_start(GTK_BOX(types_vb), adjtime_offset_hb, FALSE, FALSE, 0);
260   gtk_widget_show(adjtime_offset_hb);
261
262   adjtime_rb = gtk_radio_button_new_with_label(gtk_radio_button_get_group(
263     GTK_RADIO_BUTTON(timeshift_rb)), "Set packets to time and extrapolate");
264   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), adjtime_rb, TRUE, TRUE, 0);
265   gtk_widget_show(adjtime_rb);
266   gtk_widget_set_tooltip_text(adjtime_rb,
267     "Set the time of two frames and adjust the rest of the frames "
268     "automatically.");
269
270   adjtime_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
271   gtk_box_pack_start(GTK_BOX(types_vb), adjtime_offset_hb, FALSE, FALSE, 0);
272   gtk_widget_show(adjtime_offset_hb);
273
274   label = gtk_label_new("Packet number");
275   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), label, FALSE, FALSE, 0);
276   gtk_widget_show(label);
277
278   adjtime_packetnumber1_text_box = gtk_entry_new();
279   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), adjtime_packetnumber1_text_box,
280     TRUE, TRUE, 0);
281   gtk_entry_set_text(GTK_ENTRY(adjtime_packetnumber1_text_box), "");
282   gtk_widget_show(adjtime_packetnumber1_text_box);
283   gtk_widget_set_tooltip_text(adjtime_packetnumber1_text_box,
284     "The frame which will be set to the time.");
285
286   /* time shift row */
287   adjtime_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
288   gtk_box_pack_start(GTK_BOX(types_vb), adjtime_offset_hb, FALSE, FALSE,
289     0);
290   gtk_widget_show(adjtime_offset_hb);
291
292   label = gtk_label_new("Set packet to time [YYYY-MM-DD] hh:mm:ss[.ddd]");
293   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), label, FALSE, FALSE, 0);
294   gtk_widget_show(label);
295
296   adjtime_time1_text_box = gtk_entry_new();
297   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), adjtime_time1_text_box, TRUE,
298     TRUE, 0);
299   gtk_entry_set_text(GTK_ENTRY(adjtime_time1_text_box), "");
300   gtk_widget_show(adjtime_time1_text_box);
301   gtk_widget_set_tooltip_text(adjtime_time1_text_box,
302     "The time for the frame in the format of [YYYY-MM-DD] "
303     "hh:mm:ss[.ddddddddd]");
304
305   /* packet number row 2 */
306   adjtime_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
307   gtk_box_pack_start(GTK_BOX(types_vb), adjtime_offset_hb, FALSE,
308     FALSE, 0);
309   gtk_widget_show(adjtime_offset_hb);
310
311   label = gtk_label_new("Packet number");
312   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), label, FALSE, FALSE, 0);
313   gtk_widget_show(label);
314
315   adjtime_packetnumber2_text_box = gtk_entry_new();
316   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), adjtime_packetnumber2_text_box,
317     TRUE, TRUE, 0);
318   gtk_entry_set_text(GTK_ENTRY(adjtime_packetnumber2_text_box), "");
319   gtk_widget_show(adjtime_packetnumber2_text_box);
320   gtk_widget_set_tooltip_text(adjtime_packetnumber2_text_box,
321     "The frame which will be set to the time.");
322
323   /* time shift row */
324   adjtime_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
325   gtk_box_pack_start(GTK_BOX(types_vb), adjtime_offset_hb, FALSE, FALSE,
326     0);
327   gtk_widget_show(adjtime_offset_hb);
328
329   label = gtk_label_new("Set packet to time [YYYY-MM-DD] hh:mm:ss[.ddd]");
330   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), label, FALSE, FALSE, 0);
331   gtk_widget_show(label);
332
333   adjtime_time2_text_box = gtk_entry_new();
334   gtk_box_pack_start(GTK_BOX(adjtime_offset_hb), adjtime_time2_text_box, TRUE,
335     TRUE, 0);
336   gtk_entry_set_text(GTK_ENTRY(adjtime_time2_text_box), "");
337   gtk_widget_show(adjtime_time2_text_box);
338   gtk_widget_set_tooltip_text(adjtime_time2_text_box,
339     "The time for the frame in the format of [YYYY-MM-DD] "
340     "hh:mm:ss[.ddddddddd]");
341
342   /*
343    * Undo all shifts
344    */
345   main_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
346   gtk_box_pack_start(GTK_BOX(main_vb), main_hb, TRUE, TRUE, 0);
347   gtk_widget_show(main_hb);
348
349   types_frame = gtk_frame_new(NULL);
350   gtk_box_pack_start(GTK_BOX(main_hb), types_frame, TRUE, TRUE, 0);
351   gtk_widget_show(types_frame);
352
353   types_vb = ws_gtk_box_new(GTK_ORIENTATION_VERTICAL, 3, FALSE);
354   gtk_container_set_border_width(GTK_CONTAINER(types_vb), 3);
355   gtk_container_add(GTK_CONTAINER(types_frame), types_vb);
356   gtk_widget_show(types_vb);
357
358   /* time shift type row */
359   undo_type_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
360   gtk_box_pack_start(GTK_BOX(types_vb), undo_type_hb, TRUE, TRUE, 0);
361   gtk_widget_show(undo_type_hb);
362
363   /* time shift row */
364   undo_offset_hb = ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 3, FALSE);
365   gtk_box_pack_start(GTK_BOX(types_vb), undo_offset_hb, FALSE,
366     FALSE, 0);
367   gtk_widget_show(undo_offset_hb);
368
369   undo_rb = gtk_radio_button_new_with_label(gtk_radio_button_get_group(
370     GTK_RADIO_BUTTON(timeshift_rb)), "Undo all shifts");
371   gtk_box_pack_start(GTK_BOX(undo_offset_hb), undo_rb, TRUE, TRUE, 0);
372   gtk_widget_show(undo_rb);
373   gtk_widget_set_tooltip_text(undo_rb,
374     "Undo all the Time Shift offsets on the frames.");
375  
376   /*
377    * Button row
378    */
379   bbox = dlg_button_row_new(GTK_STOCK_APPLY, GTK_STOCK_CLOSE, GTK_STOCK_HELP,
380     NULL);
381   gtk_box_pack_start(GTK_BOX(main_vb), bbox, FALSE, FALSE, 0);
382   gtk_widget_show(bbox);
383
384   apply_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_APPLY);
385   g_signal_connect(apply_bt, "clicked", G_CALLBACK(time_shift_apply_cb),
386     time_shift_frame_w);
387   gtk_widget_set_tooltip_text(apply_bt,
388     "Apply the Time Shift options to the frame data.");
389
390   close_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_CLOSE);
391   g_signal_connect(close_bt, "clicked", G_CALLBACK(time_shift_close_cb),
392     time_shift_frame_w);
393   gtk_widget_set_tooltip_text(close_bt, "Close this dialogbox.");
394
395   help_bt = g_object_get_data(G_OBJECT(bbox), GTK_STOCK_HELP);
396   g_signal_connect(help_bt, "clicked", G_CALLBACK(topic_cb),
397     (gpointer)HELP_TIME_SHIFT_DIALOG);
398   gtk_widget_set_tooltip_text(help_bt,
399     "Help on how the Time Shift feature works.");
400
401   /* Link everything together */
402
403   g_object_set_data(G_OBJECT(time_shift_frame_w), E_TIMESHIFT_SELECT,
404     timeshift_rb);
405   g_object_set_data(G_OBJECT(time_shift_frame_w), E_TIMESHIFT_OFFSET_KEY,
406     timeshift_offset_text_box);
407   g_object_set_data(G_OBJECT(time_shift_frame_w), E_SETTIME_SELECT, settime_rb);
408   g_object_set_data(G_OBJECT(time_shift_frame_w), E_SETTIME_TIME_KEY,
409     settime_time_text_box);
410   g_object_set_data(G_OBJECT(time_shift_frame_w), E_SETTIME_PACKETNUMBER_KEY,
411     settime_packetnumber_text_box);
412   g_object_set_data(G_OBJECT(time_shift_frame_w), E_ADJTIME_SELECT, adjtime_rb);
413   g_object_set_data(G_OBJECT(time_shift_frame_w), E_ADJTIME_TIME1_KEY,
414     adjtime_time1_text_box);
415   g_object_set_data(G_OBJECT(time_shift_frame_w), E_ADJTIME_PACKETNUMBER1_KEY,
416     adjtime_packetnumber1_text_box);
417   g_object_set_data(G_OBJECT(time_shift_frame_w), E_ADJTIME_TIME2_KEY,
418     adjtime_time2_text_box);
419   g_object_set_data(G_OBJECT(time_shift_frame_w), E_ADJTIME_PACKETNUMBER2_KEY,
420     adjtime_packetnumber2_text_box);
421   g_object_set_data(G_OBJECT(time_shift_frame_w), E_UNDO_SELECT, undo_rb);
422
423   dlg_set_activate(timeshift_offset_text_box, apply_bt);
424
425   /* Give the initial focus to the "offset" entry box. */
426   gtk_widget_grab_focus(timeshift_offset_text_box);
427
428   g_signal_connect(time_shift_frame_w, "delete_event",
429     G_CALLBACK(window_delete_event_cb), NULL);
430   g_signal_connect(time_shift_frame_w, "destroy",
431     G_CALLBACK(time_shift_frame_destroy_cb), NULL);
432
433   gtk_widget_show(time_shift_frame_w);
434   window_present(time_shift_frame_w);
435 }
436
437 static void
438 error_message(const gchar *msg)
439 {
440   simple_dialog(ESD_TYPE_ERROR, ESD_BTN_OK, "%s", msg);
441 }
442
443 static int  action_timeshift(GtkWindow *parent_w);
444 static void action_settime(GtkWindow *parent_w);
445 static void action_adjtime(GtkWindow *parent_w);
446 static void action_undo(GtkWindow *parent_w);
447
448 static void
449 time_shift_apply_cb(GtkWidget *ok_bt _U_, GtkWindow *parent_w)
450 {
451   GtkWidget *flag_rb;
452
453   if (cfile.state == FILE_CLOSED) {
454     /* Nothing to do here */
455     return;
456   }
457   if (cfile.state == FILE_READ_IN_PROGRESS) {
458     error_message("The Time Shift functions are not available on live captures.");
459     return;
460   }
461
462
463   flag_rb = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
464     E_TIMESHIFT_SELECT);
465   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(flag_rb)) == TRUE) {
466     action_timeshift(parent_w);
467     return;
468   }
469
470   flag_rb = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
471     E_SETTIME_SELECT);
472   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(flag_rb)) == TRUE) {
473     action_settime(parent_w);
474     return;
475   }
476
477   flag_rb = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
478     E_ADJTIME_SELECT);
479   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(flag_rb)) == TRUE) {
480     action_adjtime(parent_w);
481     return;
482   }
483
484   flag_rb = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w), E_UNDO_SELECT);
485   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(flag_rb)) == TRUE) {
486     action_undo(parent_w);
487     return;
488   }
489 }
490
491 #define CHECK_YEARS(Y)                                                  \
492   if (Y < 1970) {                                                       \
493     error_message("years must be larger than 1970");                    \
494     return(1);                                                          \
495   }
496 #define CHECK_MONTHS(M)                                                 \
497   if (M < 1 || M > 12) {                                                \
498     error_message("months must be between [1..12]");                    \
499     return(1);                                                          \
500   }
501 #define CHECK_DAYS(D)                                                   \
502   if (D < 1 || D > 31) {                                                \
503     error_message("days must be between [1..31]");                      \
504     return(1);                                                          \
505   }
506 #define CHECK_HOURS(h)                                                  \
507   if (h < 0 || h > 23) {                                                \
508     error_message("hours must be between [0..23]");                     \
509     return(1);                                                          \
510   }
511 #define CHECK_HOUR(h)                                                   \
512   if (h < 0) {                                                          \
513     error_message("negative hours, you have have specified more than "  \
514       "one minus character?");                                          \
515     return(1);                                                          \
516   }                                                                     \
517   offset_float += h * 3600
518 #define CHECK_MINUTE(m)                                     \
519   if (m < 0 || m > 59) {                                    \
520     error_message("minutes must be between [0..59]");       \
521     return(1);                                              \
522   }                                                         \
523   offset_float += m * 60
524 #define CHECK_SECOND(s)                                     \
525   if (s < 0 || s > 59) {                                    \
526     error_message("seconds must be between [0..59]");       \
527     return(1);                                              \
528   }                                                         \
529   offset_float += s
530 #define CHECK_SEC_DEC(f)                                   \
531   if (f < 0) {                                             \
532     error_message("fractional seconds must be > 0");       \
533     return(1);                                             \
534   }                                                        \
535   offset_float += f
536
537 static int
538 action_timeshift(GtkWindow *parent_w)
539 {
540   GtkWidget     *offset_te;
541   const gchar   *offset_text;
542   gchar         *poffset_text;
543   nstime_t      offset;
544   long double   offset_float = 0;
545   guint32       i;
546   frame_data    *fd;
547   int           neg;
548   int           h, m;
549   long double   f;
550
551   /*
552    * The following offset types are allowed:
553    * -?((hh:)mm:)ss(.decimals)?
554    *
555    * Since Wireshark doesn't support regular expressions (please prove me
556    * wrong :-) we will have to figure it out ourselves in the
557    * following order:
558    *
559    * 1. hh:mm:ss.decimals
560    * 2.    mm:ss.decimals
561    * 3.       ss.decimals
562    *
563    */
564
565   offset_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
566     E_TIMESHIFT_OFFSET_KEY);
567   offset_text = gtk_entry_get_text(GTK_ENTRY(offset_te));
568   poffset_text = (gchar *)offset_text;
569
570   /* strip whitespace */
571   while (isspace(poffset_text[0]))
572     ++poffset_text;
573
574   /* check for minus sign */
575   neg = FALSE;
576   if (poffset_text[0] == '-') {
577     neg = TRUE;
578     poffset_text++;
579   }
580
581   /* check for empty string */
582   if (poffset_text[0] == '\0')
583     return(1);
584
585   h = m = 0;
586   f = 0.0;
587   if (sscanf(poffset_text, "%d:%d:%Lf", &h, &m, &f) == 3) {
588     /* printf("%%d:%%d:%%d.%%d\n"); */
589     CHECK_HOUR(h);
590     CHECK_MINUTE(m);
591     CHECK_SEC_DEC(f);
592   } else if (sscanf(poffset_text, "%d:%Lf", &m, &f) == 2) {
593     /* printf("%%d:%%d.%%d\n"); */
594     CHECK_MINUTE(m);
595     CHECK_SEC_DEC(f);
596   } else if (sscanf(poffset_text, "%Lf", &f) == 1) {
597     /* printf("%%d.%%d\n"); */
598     CHECK_SEC_DEC(f);
599   } else {
600     error_message("Could not parse the time: Expected ((hh:)mm:)ss.(dec).");
601     return(1);
602   }
603
604   if (offset_float == 0)
605     return(1);
606
607   nstime_set_zero(&offset);
608   offset.secs = (time_t)floorl(offset_float);
609   offset_float -= offset.secs;
610   offset.nsecs = (int)(offset_float * 1000000000);
611
612   if ((fd = frame_data_sequence_find(cfile.frames, 1)) == NULL)
613     return(1); /* Shouldn't happen */
614   modify_time_init(fd);
615
616   for (i = 1; i <= cfile.count; i++) {
617     if ((fd = frame_data_sequence_find(cfile.frames, i)) == NULL)
618       continue; /* Shouldn't happen */
619     modify_time_perform(fd, neg, &offset, SHIFT_KEEPOFFSET);
620   }
621   packet_list_queue_draw();
622   
623   return(0);
624 }
625
626 static int
627 timestring2nstime(const gchar *ts, nstime_t *packettime, nstime_t *nstime)
628 {
629   gchar         *pts;
630   int           h, m, Y, M, D;
631   long double   f;
632   struct tm     tm, *tmptm;
633   time_t        tt;
634   long double   offset_float = 0;
635
636   /*
637    * The following time format is allowed:
638    * [YYYY-MM-DD] hh:mm:ss(.decimals)?
639    *
640    * Since Wireshark doesn't support regular expressions (please prove me
641    * wrong :-) we will have to figure it out ourselves in the
642    * following order:
643    *
644    * 1. YYYY-MM-DD hh:mm:ss.decimals
645    * 2.            hh:mm:ss.decimals
646    *
647    */
648
649   pts = (gchar *)ts;
650
651   /* strip whitespace */
652   while (isspace(pts[0]))
653     ++pts;
654
655   /* check for empty string */
656   if (pts[0] == '\0')
657     return(1);
658
659   if (sscanf(pts, "%d-%d-%d %d:%d:%Lf", &Y, &M, &D, &h, &m, &f) == 6) {
660     /* printf("%%d-%%d-%%d %%d:%%d:%%f\n"); */
661     CHECK_YEARS(Y);
662     CHECK_MONTHS(M);
663     CHECK_DAYS(D);
664     CHECK_HOURS(h);
665     CHECK_MINUTE(m);
666     CHECK_SEC_DEC(f);
667   } else if (sscanf(pts, "%d:%d:%Lf", &h, &m, &f) == 3) {
668     /* printf("%%d:%%d:%%f\n"); */
669     Y = M = D = 0;
670     CHECK_HOUR(h);
671     CHECK_MINUTE(m);
672     CHECK_SEC_DEC(f);
673   } else {
674     error_message("Could not parse the time: Expected (YYYY-MM-DD) "
675       "hh:mm:ss(.dec)");
676     return(1);
677   }
678
679   /* Convert the time entered in an epoch offset */
680   tmptm = localtime(&(packettime->secs));
681   if (tmptm) {
682     tm = *tmptm;
683   } else {
684     memset (&tm, 0, sizeof (tm));
685   }
686   if (Y != 0) {
687     tm.tm_year = Y - 1900;
688     tm.tm_mon = M - 1;
689     tm.tm_mday = D;
690   }
691   tm.tm_hour = h;
692   tm.tm_min = m;
693   tm.tm_sec = (int)floorl(f);
694   tt = mktime(&tm);
695   if (tt == -1) {
696     error_message("mktime went wrong. Was the time invalid?");
697     return(1);
698   }
699
700   nstime->secs = tt;
701   f -= tm.tm_sec;
702   nstime->nsecs = (int)(f * 1000000000);
703
704   return(0);
705 }
706
707 static void
708 action_settime(GtkWindow *parent_w)
709 {
710   GtkWidget     *packetnumber_te;
711   const gchar   *packetnumber_text;
712   long          packetnumber;
713   GtkWidget     *time_te;
714   const gchar   *time_text;
715   nstime_t      settime, difftime, packettime;
716   frame_data    *fd, *packetfd;
717   guint32       i;
718
719   packetnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
720     E_SETTIME_PACKETNUMBER_KEY);
721   packetnumber_text = gtk_entry_get_text(GTK_ENTRY(packetnumber_te));
722   packetnumber = strtol((char *)packetnumber_text, NULL, 10);
723
724   time_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
725     E_SETTIME_TIME_KEY);
726   time_text = gtk_entry_get_text(GTK_ENTRY(time_te));
727
728   /*
729    * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
730    * difference between the specified time and the original packet
731    */
732   if ((packetfd = frame_data_sequence_find(cfile.frames, packetnumber)) == NULL)
733     return;
734   nstime_delta(&packettime, &(packetfd->abs_ts), &(packetfd->shift_offset));
735
736   if (timestring2nstime(time_text, &packettime, &settime) != 0)
737     return;
738
739   /* Calculate difference between packet time and requested time */
740   nstime_delta(&difftime, &settime, &packettime); 
741
742   /* Up to here nothing is changed */
743
744   if ((fd = frame_data_sequence_find(cfile.frames, 1)) == NULL)
745     return; /* Shouldn't happen */
746   modify_time_init(fd);
747
748   /* Set everything back to the original time */
749   for (i = 1; i <= cfile.count; i++) {
750     if ((fd = frame_data_sequence_find(cfile.frames, i)) == NULL)
751       continue; /* Shouldn't happen */
752     modify_time_perform(fd, SHIFT_POS, &difftime, SHIFT_SETTOZERO);
753   }
754
755   packet_list_queue_draw();
756 }
757
758 /*
759  * If the line between (OT1, NT1) and (OT2, NT2) is a straight line
760  * and (OT3, NT3) is on that line,
761  * then (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) / (OT3 - OT1) and 
762  * then (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) and
763  * then NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = NT3 and
764  * then NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) and 
765  * thus NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT1)
766  *   or NT3 = NT1 + (OT3 - OT1) * ( deltaNT12 / deltaOT12)
767  *
768  * All the things you come up when waiting for the train to come...
769  */
770 static void
771 calcNT3(nstime_t *OT1, nstime_t *OT3, nstime_t *NT1, nstime_t *NT3,
772   nstime_t *deltaOT, nstime_t *deltaNT)
773 {
774   long double fnt, fot, f, secs, nsecs;
775
776   fnt = (long double)deltaNT->secs + (deltaNT->nsecs / 1000000000.0L);
777   fot = (long double)deltaOT->secs + (deltaOT->nsecs / 1000000000.0L);
778   f = fnt / fot;
779
780   nstime_copy(NT3, OT3);
781   nstime_subtract(NT3, OT1);
782
783   secs = f * (long double)NT3->secs;
784   nsecs = f * (long double)NT3->nsecs;
785   nsecs += (secs - floorl(secs)) * 1000000000.0L;
786   while (nsecs > 1000000000L) {
787     secs += 1;
788     nsecs -= 1000000000L;
789   }
790   while (nsecs < 0) {
791     secs -= 1;
792     nsecs += 1000000000L;
793   }
794   NT3->secs = (time_t)secs;
795   NT3->nsecs = (int)nsecs;
796   nstime_add(NT3, NT1);
797 }
798
799 static void
800 action_adjtime(GtkWindow *parent_w _U_)
801 {
802   GtkWidget     *packetnumber_te;
803   const gchar   *packetnumber_text;
804   long          packetnumber1, packetnumber2;
805   GtkWidget     *time_te;
806   const gchar   *time1_text, *time2_text;
807   nstime_t      nt1, nt2, ot1, ot2, nt3;
808   nstime_t      dnt, dot, d3t;
809   frame_data    *fd, *packet1fd, *packet2fd;
810   guint32       i;
811
812   packetnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
813     E_ADJTIME_PACKETNUMBER1_KEY);
814   packetnumber_text = gtk_entry_get_text(GTK_ENTRY(packetnumber_te));
815   packetnumber1 = strtol((char *)packetnumber_text, NULL, 10);
816   packetnumber_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
817     E_ADJTIME_PACKETNUMBER2_KEY);
818   packetnumber_text = gtk_entry_get_text(GTK_ENTRY(packetnumber_te));
819   packetnumber2 = strtol((char *)packetnumber_text, NULL, 10);
820
821   /*
822    * The following time format is allowed:
823    * [YYYY-MM-DD] hh:mm:ss(.decimals)?
824    *
825    * Since Wireshark doesn't support regular expressions (please prove me
826    * wrong :-) we will have to figure it out ourselves in the
827    * following order:
828    *
829    * 1. YYYY-MM-DD hh:mm:ss.decimals
830    * 2.            hh:mm:ss.decimals
831    *
832    */
833
834   time_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
835     E_ADJTIME_TIME1_KEY);
836   time1_text = gtk_entry_get_text(GTK_ENTRY(time_te));
837   time_te = (GtkWidget *)g_object_get_data(G_OBJECT(parent_w),
838     E_ADJTIME_TIME2_KEY);
839   time2_text = gtk_entry_get_text(GTK_ENTRY(time_te));
840
841   /*
842    * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
843    * difference between the specified time and the original packet
844    */
845   if ((packet1fd = frame_data_sequence_find(cfile.frames, packetnumber1)) == NULL)
846     return;
847   nstime_copy(&ot1, &(packet1fd->abs_ts));
848   nstime_subtract(&ot1, &(packet1fd->shift_offset));
849
850   if (timestring2nstime(time1_text, &ot1, &nt1) != 0)
851     return;
852
853   /*
854    * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
855    * difference between the specified time and the original packet
856    */
857   if ((packet2fd = frame_data_sequence_find(cfile.frames, packetnumber2)) == NULL)
858     return;
859   nstime_copy(&ot2, &(packet2fd->abs_ts));
860   nstime_subtract(&ot2, &(packet2fd->shift_offset));
861
862   if (timestring2nstime(time2_text, &ot2, &nt2) != 0)
863     return;
864  
865   nstime_copy(&dot, &ot2);
866   nstime_subtract(&dot, &ot1);
867
868   nstime_copy(&dnt, &nt2);
869   nstime_subtract(&dnt, &nt1);
870
871   /* Up to here nothing is changed */
872   if ((fd = frame_data_sequence_find(cfile.frames, 1)) == NULL)
873     return; /* Shouldn't happen */
874   modify_time_init(fd);
875
876   for (i = 1; i <= cfile.count; i++) {
877     if ((fd = frame_data_sequence_find(cfile.frames, i)) == NULL)
878       continue; /* Shouldn't happen */
879
880     /* Set everything back to the original time */
881     nstime_subtract(&(fd->abs_ts), &(fd->shift_offset));
882     nstime_set_zero(&(fd->shift_offset));
883
884     /* Add the difference to each packet */
885     calcNT3(&ot1, &(fd->abs_ts), &nt1, &nt3, &dot, &dnt);
886
887     nstime_copy(&d3t, &nt3);
888     nstime_subtract(&d3t, &(fd->abs_ts));
889
890     modify_time_perform(fd, SHIFT_POS, &d3t, SHIFT_SETTOZERO);
891   }
892
893   packet_list_queue_draw();
894 }
895
896 static void
897 action_undo(GtkWindow *parent_w _U_)
898 {
899   guint32       i;
900   frame_data    *fd;
901   nstime_t      nulltime;
902
903   nulltime.secs = nulltime.nsecs = 0;
904
905   if ((fd = frame_data_sequence_find(cfile.frames, 1)) == NULL)
906     return; /* Shouldn't happen */
907   modify_time_init(fd);
908
909   for (i = 1; i <= cfile.count; i++) {
910     if ((fd = frame_data_sequence_find(cfile.frames, i)) == NULL)
911       continue; /* Shouldn't happen */
912     modify_time_perform(fd, SHIFT_NEG, &nulltime, SHIFT_SETTOZERO);
913   }
914   packet_list_queue_draw();
915 }
916
917 static void
918 time_shift_close_cb(GtkWidget *close_bt _U_, gpointer parent_w _U_)
919 {
920   gtk_grab_remove(GTK_WIDGET(parent_w));
921   window_destroy(GTK_WIDGET(parent_w));
922 }
923
924 static void
925 time_shift_frame_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
926 {
927   /* Note that we no longer have a "Time Shift" dialog box. */
928   time_shift_frame_w = NULL;
929 }
930
931 static void
932 modify_time_init(frame_data *fd)
933 {
934   modify_time_perform(fd, SHIFT_NEG, NULL, SHIFT_KEEPOFFSET);
935 }
936
937 static void
938 modify_time_perform(frame_data *fd, int neg, nstime_t *offset, int settozero)
939 {
940   static frame_data *first_packet = NULL;
941   static nstime_t nulltime;
942
943   /* Only for initializing */
944   if (offset == NULL) {
945     first_packet = fd;
946     nulltime.secs = nulltime.nsecs = 0;
947     return;
948   }
949   if (first_packet == NULL) {
950     fprintf(stderr, "modify_time_perform: not initialized?\n");
951     return;
952   }
953
954   /* The actual shift */
955
956   if (settozero == SHIFT_SETTOZERO) {
957     nstime_subtract(&(fd->abs_ts), &(fd->shift_offset));
958     nstime_copy(&(fd->shift_offset), &nulltime);
959   }
960
961   if (neg == SHIFT_POS) {
962     nstime_add(&(fd->abs_ts), offset);
963     nstime_add(&(fd->shift_offset), offset);
964   } else if (neg == SHIFT_NEG) {
965     nstime_subtract(&(fd->abs_ts), offset);
966     nstime_subtract(&(fd->shift_offset), offset);
967   } else {
968     fprintf(stderr, "modify_time_perform: neg = %d?\n", neg);
969   }
970
971   /*
972    * rel_ts     - Relative timestamp to first packet
973    */
974   if (first_packet != NULL) {
975     nstime_copy(&(fd->rel_ts), &(fd->abs_ts));
976     nstime_subtract(&(fd->rel_ts), &(first_packet->abs_ts));
977   } else
978     nstime_copy(&(fd->rel_ts), &nulltime);
979 }