packet-smb2: fix lease epoch fields
[metze/wireshark/wip.git] / ui / time_shift.c
1 /* time_shift.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 <stdio.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include <math.h>
32
33 #include <glib.h>
34
35 #include "time_shift.h"
36
37 #include "ui/ui_util.h"
38
39 #define SHIFT_POS               0
40 #define SHIFT_NEG               1
41 #define SHIFT_SETTOZERO         1
42 #define SHIFT_KEEPOFFSET        0
43
44 #define CHECK_YEARS(Y)                                                  \
45   if (*Y < 1970) {                                                      \
46     return "Years must be larger than 1970";                            \
47   }
48 #define CHECK_MONTHS(M)                                                 \
49   if (*M < 1 || *M > 12) {                                              \
50     return "Months must be between [1..12]";                            \
51   }
52 #define CHECK_DAYS(D)                                                   \
53   if (*D < 1 || *D > 31) {                                              \
54     return "Days must be between [1..31]";                              \
55   }
56 #define CHECK_HOURS(h)                                                  \
57   if (*h < 0 || *h > 23) {                                              \
58     return "Hours must be between [0..23]";                             \
59   }
60 #define CHECK_HOUR(h)                                                   \
61   if (*h < 0) {                                                         \
62     return "Negative hours. Have you specified more than "              \
63       "one minus character?";                                           \
64   }
65 #define CHECK_MINUTE(m)                                     \
66   if (*m < 0 || *m > 59) {                                  \
67     return "Minutes must be between [0..59]";               \
68   }
69 #define CHECK_SECOND(s)                                     \
70   if (*s < 0 || *s > 59) {                                  \
71     return "Seconds must be between [0..59]";               \
72   }
73
74 static void
75 modify_time_perform(frame_data *fd, int neg, nstime_t *offset, int settozero)
76 {
77   /* The actual shift */
78   if (settozero == SHIFT_SETTOZERO) {
79     nstime_subtract(&(fd->abs_ts), &(fd->shift_offset));
80     nstime_set_zero(&(fd->shift_offset));
81   }
82
83   if (neg == SHIFT_POS) {
84     nstime_add(&(fd->abs_ts), offset);
85     nstime_add(&(fd->shift_offset), offset);
86   } else if (neg == SHIFT_NEG) {
87     nstime_subtract(&(fd->abs_ts), offset);
88     nstime_subtract(&(fd->shift_offset), offset);
89   } else {
90     fprintf(stderr, "Modify_time_perform: neg = %d?\n", neg);
91   }
92 }
93
94 /*
95  * If the line between (OT1, NT1) and (OT2, NT2) is a straight line
96  * and (OT3, NT3) is on that line,
97  * then (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) / (OT3 - OT1) and
98  * then (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = (NT3 - NT1) and
99  * then NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) = NT3 and
100  * then NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT2) and
101  * thus NT3 = NT1 + (OT3 - OT1) * (NT2 - NT1) / (OT2 - OT1)
102  *   or NT3 = NT1 + (OT3 - OT1) * ( deltaNT12 / deltaOT12)
103  *
104  * All the things you come up when waiting for the train to come...
105  */
106 static void
107 calcNT3(nstime_t *OT1, nstime_t *OT3, nstime_t *NT1, nstime_t *NT3,
108   nstime_t *deltaOT, nstime_t *deltaNT)
109 {
110   long double fnt, fot, f, secs, nsecs;
111
112   fnt = (long double)deltaNT->secs + (deltaNT->nsecs / 1000000000.0L);
113   fot = (long double)deltaOT->secs + (deltaOT->nsecs / 1000000000.0L);
114   f = fnt / fot;
115
116   nstime_copy(NT3, OT3);
117   nstime_subtract(NT3, OT1);
118
119   secs = f * (long double)NT3->secs;
120   nsecs = f * (long double)NT3->nsecs;
121   nsecs += (secs - floorl(secs)) * 1000000000.0L;
122   while (nsecs > 1000000000L) {
123     secs += 1;
124     nsecs -= 1000000000L;
125   }
126   while (nsecs < 0) {
127     secs -= 1;
128     nsecs += 1000000000L;
129   }
130   NT3->secs = (time_t)secs;
131   NT3->nsecs = (int)nsecs;
132   nstime_add(NT3, NT1);
133 }
134
135 const gchar *
136 time_string_parse(const gchar *time_text, int *year, int *month, int *day, gboolean *negative, int *hour, int *minute, long double *second) {
137     const gchar *pts = time_text;
138
139     if (!time_text || !hour || !minute || !second)
140         return "Unable to convert time.";
141
142     /* strip whitespace */
143     while (isspace(pts[0]))
144         ++pts;
145
146     if (year && month && day) {
147         /*
148          * The following time format is allowed:
149          * [YYYY-MM-DD] hh:mm:ss(.decimals)?
150          *
151          * Since Wireshark doesn't support regular expressions (please prove me
152          * wrong :-) we will have to figure it out ourselves in the
153          * following order:
154          *
155          * 1. YYYY-MM-DD hh:mm:ss.decimals
156          * 2.            hh:mm:ss.decimals
157          *
158          */
159
160         /* check for empty string */
161         if (pts[0] == '\0')
162             return "Time is empty.";
163
164         if (sscanf(pts, "%d-%d-%d %d:%d:%Lf", year, month, day, hour, minute, second) == 6) {
165             /* printf("%%d-%%d-%%d %%d:%%d:%%f\n"); */
166             CHECK_YEARS(year);
167             CHECK_MONTHS(month);
168             CHECK_DAYS(day);
169             CHECK_HOURS(hour);
170             CHECK_MINUTE(minute);
171             CHECK_SECOND(second);
172         } else if (sscanf(pts, "%d:%d:%Lf", hour, minute, second) == 3) {
173             /* printf("%%d:%%d:%%f\n"); */
174             *year = *month = *day = 0;
175             CHECK_HOUR(hour);
176             CHECK_MINUTE(minute);
177             CHECK_SECOND(second);
178         } else {
179             return "Could not parse the time. Expected [YYYY-MM-DD] "
180                     "hh:mm:ss[.dec].";
181         }
182     } else {
183         if (!negative)
184             return "Unable to convert time.";
185
186         /*
187          * The following offset types are allowed:
188          * -?((hh:)mm:)ss(.decimals)?
189          *
190          * Since Wireshark doesn't support regular expressions (please prove me
191          * wrong :-) we will have to figure it out ourselves in the
192          * following order:
193          *
194          * 1. hh:mm:ss.decimals
195          * 2.    mm:ss.decimals
196          * 3.       ss.decimals
197          *
198          */
199
200         /* check for minus sign */
201         *negative = FALSE;
202         if (pts[0] == '-') {
203             *negative = TRUE;
204             pts++;
205         }
206
207         /* check for empty string */
208         if (pts[0] == '\0')
209             return "Time is empty.";
210
211         if (sscanf(pts, "%d:%d:%Lf", hour, minute, second) == 3) {
212             /* printf("%%d:%%d:%%d.%%d\n"); */
213             CHECK_HOUR(hour);
214             CHECK_MINUTE(minute);
215             CHECK_SECOND(second);
216         } else if (sscanf(pts, "%d:%Lf", minute, second) == 2) {
217             /* printf("%%d:%%d.%%d\n"); */
218             CHECK_MINUTE(minute);
219             CHECK_SECOND(second);
220         *hour = 0;
221         } else if (sscanf(pts, "%Lf", second) == 1) {
222             /* printf("%%d.%%d\n"); */
223             CHECK_SECOND(second);
224         *hour = *minute = 0;
225         } else {
226             return "Could not parse the time: Expected [[hh:]mm:]ss.[dec].";
227         }
228     }
229
230     return NULL;
231 }
232
233 static const gchar *
234 time_string_to_nstime(const gchar *time_text, nstime_t *packettime, nstime_t *nstime)
235 {
236     int         h, m, Y, M, D;
237     long double f;
238     struct tm   tm, *tmptm;
239     time_t      tt;
240     const gchar *err_str;
241
242     if ((err_str = time_string_parse(time_text, &Y, &M, &D, NULL, &h, &m, &f)) != NULL)
243         return err_str;
244
245     /* Convert the time entered in an epoch offset */
246     tmptm = localtime(&(packettime->secs));
247     if (tmptm) {
248         tm = *tmptm;
249     } else {
250         memset (&tm, 0, sizeof (tm));
251     }
252     if (Y != 0) {
253         tm.tm_year = Y - 1900;
254         tm.tm_mon = M - 1;
255         tm.tm_mday = D;
256     }
257     tm.tm_hour = h;
258     tm.tm_min = m;
259     tm.tm_sec = (int)floorl(f);
260     tt = mktime(&tm);
261     if (tt == -1) {
262         return "Mktime went wrong. Is the time valid?";
263     }
264
265     nstime->secs = tt;
266     f -= tm.tm_sec;
267     nstime->nsecs = (int)(f * 1000000000);
268
269     return NULL;
270 }
271
272 const gchar *
273 time_shift_all(capture_file *cf, const gchar *offset_text)
274 {
275     nstime_t    offset;
276     long double offset_float = 0;
277     guint32     i;
278     frame_data  *fd;
279     gboolean    neg;
280     int         h, m;
281     long double f;
282     const gchar *err_str;
283
284     if (!cf || !offset_text)
285         return "Nothing to work with.";
286
287     if ((err_str = time_string_parse(offset_text, NULL, NULL, NULL, &neg, &h, &m, &f)) != NULL)
288         return err_str;
289
290     offset_float = h * 3600 + m * 60 + f;
291
292     if (offset_float == 0)
293         return "Offset is zero.";
294
295     nstime_set_zero(&offset);
296     offset.secs = (time_t)floorl(offset_float);
297     offset_float -= offset.secs;
298     offset.nsecs = (int)(offset_float * 1000000000);
299
300     if (!frame_data_sequence_find(cf->frames, 1))
301         return "No frames found."; /* Shouldn't happen */
302
303     for (i = 1; i <= cf->count; i++) {
304         if ((fd = frame_data_sequence_find(cf->frames, i)) == NULL)
305             continue;   /* Shouldn't happen */
306         modify_time_perform(fd, neg ? SHIFT_NEG : SHIFT_POS, &offset, SHIFT_KEEPOFFSET);
307     }
308     packet_list_queue_draw();
309
310     return NULL;
311 }
312
313 const gchar *
314 time_shift_settime(capture_file *cf, guint packet_num, const gchar *time_text)
315 {
316     nstime_t    set_time, diff_time, packet_time;
317     frame_data  *fd, *packetfd;
318     guint32     i;
319     const gchar *err_str;
320
321     if (!cf || !time_text)
322         return "Nothing to work with.";
323
324     if (packet_num < 1 || packet_num > cf->count)
325         return "Packet out of range.";
326
327     /*
328      * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
329      * difference between the specified time and the original packet
330      */
331     if ((packetfd = frame_data_sequence_find(cf->frames, packet_num)) == NULL)
332         return "No packets found.";
333     nstime_delta(&packet_time, &(packetfd->abs_ts), &(packetfd->shift_offset));
334
335     if ((err_str = time_string_to_nstime(time_text, &packet_time, &set_time)) != NULL)
336         return err_str;
337
338     /* Calculate difference between packet time and requested time */
339     nstime_delta(&diff_time, &set_time, &packet_time);
340
341     /* Up to here nothing is changed */
342
343     if (!frame_data_sequence_find(cf->frames, 1))
344         return "No frames found."; /* Shouldn't happen */
345
346     /* Set everything back to the original time */
347     for (i = 1; i <= cf->count; i++) {
348         if ((fd = frame_data_sequence_find(cf->frames, i)) == NULL)
349             continue;   /* Shouldn't happen */
350         modify_time_perform(fd, SHIFT_POS, &diff_time, SHIFT_SETTOZERO);
351     }
352
353     packet_list_queue_draw();
354     return NULL;
355 }
356
357 const gchar *
358 time_shift_adjtime(capture_file *cf, guint packet1_num, const gchar *time1_text, guint packet2_num, const gchar *time2_text)
359 {
360     nstime_t    nt1, nt2, ot1, ot2, nt3;
361     nstime_t    dnt, dot, d3t;
362     frame_data  *fd, *packet1fd, *packet2fd;
363     guint32     i;
364     const gchar *err_str;
365
366     if (!cf || !time1_text || !time2_text)
367         return "Nothing to work with.";
368
369     if (packet1_num < 1 || packet1_num > cf->count || packet2_num < 1 || packet2_num > cf->count)
370         return "Packet out of range.";
371
372     /*
373      * The following time format is allowed:
374      * [YYYY-MM-DD] hh:mm:ss(.decimals)?
375      *
376      * Since Wireshark doesn't support regular expressions (please prove me
377      * wrong :-) we will have to figure it out ourselves in the
378      * following order:
379      *
380      * 1. YYYY-MM-DD hh:mm:ss.decimals
381      * 2.            hh:mm:ss.decimals
382      *
383      */
384
385     /*
386      * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
387      * difference between the specified time and the original packet
388      */
389     if ((packet1fd = frame_data_sequence_find(cf->frames, packet1_num)) == NULL)
390         return "No frames found.";
391     nstime_copy(&ot1, &(packet1fd->abs_ts));
392     nstime_subtract(&ot1, &(packet1fd->shift_offset));
393
394     if ((err_str = time_string_to_nstime(time1_text, &ot1, &nt1)) != NULL)
395         return err_str;
396
397     /*
398      * Get a copy of the real time (abs_ts - shift_offset) do we can find out the
399      * difference between the specified time and the original packet
400      */
401     if ((packet2fd = frame_data_sequence_find(cf->frames, packet2_num)) == NULL)
402         return "No frames found.";
403     nstime_copy(&ot2, &(packet2fd->abs_ts));
404     nstime_subtract(&ot2, &(packet2fd->shift_offset));
405
406     if ((err_str = time_string_to_nstime(time2_text, &ot2, &nt2)) != NULL)
407         return err_str;
408
409     nstime_copy(&dot, &ot2);
410     nstime_subtract(&dot, &ot1);
411
412     nstime_copy(&dnt, &nt2);
413     nstime_subtract(&dnt, &nt1);
414
415     /* Up to here nothing is changed */
416     if (!frame_data_sequence_find(cf->frames, 1))
417         return "No frames found."; /* Shouldn't happen */
418
419     for (i = 1; i <= cf->count; i++) {
420         if ((fd = frame_data_sequence_find(cf->frames, i)) == NULL)
421             continue;   /* Shouldn't happen */
422
423         /* Set everything back to the original time */
424         nstime_subtract(&(fd->abs_ts), &(fd->shift_offset));
425         nstime_set_zero(&(fd->shift_offset));
426
427         /* Add the difference to each packet */
428         calcNT3(&ot1, &(fd->abs_ts), &nt1, &nt3, &dot, &dnt);
429
430         nstime_copy(&d3t, &nt3);
431         nstime_subtract(&d3t, &(fd->abs_ts));
432
433         modify_time_perform(fd, SHIFT_POS, &d3t, SHIFT_SETTOZERO);
434     }
435
436     packet_list_queue_draw();
437     return NULL;
438 }
439
440 const gchar *
441 time_shift_undo(capture_file *cf)
442 {
443     guint32     i;
444     frame_data  *fd;
445     nstime_t    nulltime;
446
447     if (!cf)
448         return "Nothing to work with.";
449
450     nulltime.secs = nulltime.nsecs = 0;
451
452     if (!frame_data_sequence_find(cf->frames, 1))
453         return "No frames found."; /* Shouldn't happen */
454
455     for (i = 1; i <= cf->count; i++) {
456         if ((fd = frame_data_sequence_find(cf->frames, i)) == NULL)
457             continue;   /* Shouldn't happen */
458         modify_time_perform(fd, SHIFT_NEG, &nulltime, SHIFT_SETTOZERO);
459     }
460     packet_list_queue_draw();
461     return NULL;
462 }
463
464 /*
465  * Editor modelines
466  *
467  * Local Variables:
468  * c-basic-offset: 4
469  * tab-width: 8
470  * indent-tabs-mode: nil
471  * End:
472  *
473  * ex: set shiftwidth=4 tabstop=8 expandtab:
474  * :indentSize=4:tabSize=8:noTabs=true:
475  */