d0dbad9a99d9bebda37ed099072113a08c47bd93
[obnox/wireshark/wip.git] / gtk / rtp_analysis.c
1 /* rtp_analysis.c
2  * RTP analysis addition for ethereal
3  *
4  * $Id: rtp_analysis.c,v 1.6 2003/10/03 22:38:56 guy Exp $
5  *
6  * Copyright 2003, Alcatel Business Systems
7  * By Lars Ruoff <lars.ruoff@gmx.net>
8  *
9  * based on tap_rtp.c
10  * Copyright 2003, Iskratel, Ltd, Kranj
11  * By Miha Jemec <m.jemec@iskratel.si>
12  *
13  * Ethereal - Network traffic analyzer
14  * By Gerald Combs <gerald@ethereal.com>
15  * Copyright 1998 Gerald Combs
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 /*do not define this symbol. will be added soon*/
37 /*#define USE_CONVERSATION_GRAPH 1*/
38
39 #include "rtp_analysis.h"
40 #include "rtp_stream.h"
41 #include "rtp_stream_dlg.h"
42
43 #ifdef USE_CONVERSATION_GRAPH
44 #include "../graph/graph.h"
45 #endif
46
47 #include "epan/epan_dissect.h"
48 #include "epan/filesystem.h"
49 #include "tap.h"
50 #include "register.h"
51 #include "packet-rtp.h"
52 #include "g711.h"
53 #include "rtp_pt.h"
54
55 #ifdef NEED_MKSTEMP
56 #include "mkstemp.h"
57 #endif
58
59 /* in /gtk ... */
60 #include "dlg_utils.h"
61 #include "ui_util.h"
62 #include "simple_dialog.h"
63 #include "menu.h"
64 #include "main.h"
65 #include "progress_dlg.h"
66 #include "compat_macros.h"
67
68 #include <math.h>
69 #include <fcntl.h>
70 #include <string.h>
71
72 #ifdef HAVE_UNISTD_H
73 #include <unistd.h>
74 #endif
75
76 #ifdef HAVE_IO_H
77 #include <io.h> /* open/close on win32 */
78 #endif
79
80 #ifndef O_BINARY
81 #define O_BINARY 0
82 #endif
83
84 /****************************************************************************/
85
86 typedef struct _dialog_data_t {
87         GtkWidget *window;
88         GtkCList *clist_fwd;
89         GtkCList *clist_rev;
90         GtkWidget *label_stats_fwd;
91         GtkWidget *label_stats_rev;
92         GtkWidget *notebook;
93         GtkCList *selected_clist;
94         GtkWidget *save_voice_as_w;
95         GtkWidget *save_csv_as_w;
96         gint selected_row;
97 #ifdef USE_CONVERSATION_GRAPH
98         GtkWidget *graph_window;
99 #endif
100 } dialog_data_t;
101
102 #define OK_TEXT "Ok"
103
104 /* type of error when saving voice in a file didn't succeed */
105 typedef enum {
106         TAP_RTP_WRONG_CODEC,
107         TAP_RTP_WRONG_LENGTH,
108         TAP_RTP_PADDING_ERROR,
109         TAP_RTP_FILE_OPEN_ERROR,
110         TAP_RTP_NO_DATA
111 } error_type_t; 
112
113
114 /****************************************************************************/
115 /* structure that holds the information about the forward and reversed direction */
116 typedef struct _tap_rtp_stat_t {
117         guint32 flags;             /* see STAT_FLAG-defines below */
118         gboolean first_packet;
119         guint16 seq_num;
120         guint32 timestamp;
121         guint32 delta_timestamp;
122         double delay;
123         double jitter;
124         double time;
125         double start_time;
126         double max_delay;
127         guint32 max_nr;
128         guint16 start_seq_nr;
129         guint16 stop_seq_nr;
130         guint32 total_nr;
131         guint32 sequence;
132         gboolean under;
133         gint cycles;
134         guint16 pt;
135 } tap_rtp_stat_t;
136
137 /* status flags for the flags parameter in tap_rtp_stat_t */
138 #define STAT_FLAG_FIRST       0x01
139 #define STAT_FLAG_MARKER      0x02
140 #define STAT_FLAG_WRONG_SEQ   0x04
141 #define STAT_FLAG_PT_CHANGE   0x08
142 #define STAT_FLAG_PT_CN       0x10
143
144 typedef struct _tap_rtp_save_info_t {
145         FILE *fp;
146         guint32 count;
147         error_type_t error_type;
148         gboolean saved;
149 } tap_rtp_save_info_t;
150
151
152 /* structure that holds the information about the forward and reversed direction */
153 struct _info_direction {
154         tap_rtp_stat_t statinfo;
155         tap_rtp_save_info_t saveinfo;
156 };
157
158 #define TMPNAMSIZE 100
159
160 /* structure that holds general information about the connection 
161 * and structures for both directions */
162 typedef struct _user_data_t {
163         /* tap associated data*/
164         guint32 ip_src_fwd;
165         guint16 port_src_fwd;
166         guint32 ip_dst_fwd;
167         guint16 port_dst_fwd;
168         guint32 ssrc_fwd;
169         guint32 ip_src_rev;
170         guint16 port_src_rev;
171         guint32 ip_dst_rev;
172         guint16 port_dst_rev;
173         guint32 ssrc_rev;
174
175         struct _info_direction forward;
176         struct _info_direction reversed;
177
178         char f_tempname[TMPNAMSIZE];
179         char r_tempname[TMPNAMSIZE];
180
181         /* dialog associated data */
182         dialog_data_t dlg;
183
184 #ifdef USE_CONVERSATION_GRAPH
185         time_series_t series_fwd;
186         time_series_t series_rev;
187 #endif
188 } user_data_t;
189
190
191 typedef const guint8 * ip_addr_p;
192
193
194 /****************************************************************************/
195 /* TAP FUNCTIONS */
196
197 /****************************************************************************/
198 /* when there is a [re]reading of packet's */
199 static void
200 rtp_reset(user_data_t *user_data _U_)
201 {
202         user_data->forward.statinfo.first_packet = TRUE;
203         user_data->reversed.statinfo.first_packet = TRUE;
204         user_data->forward.statinfo.max_delay = 0;
205         user_data->reversed.statinfo.max_delay = 0;
206         user_data->forward.statinfo.delay = 0;
207         user_data->reversed.statinfo.delay = 0;
208         user_data->forward.statinfo.jitter = 0;
209         user_data->reversed.statinfo.jitter = 0;
210         user_data->forward.statinfo.timestamp = 0;
211         user_data->reversed.statinfo.timestamp = 0;
212         user_data->forward.statinfo.max_nr = 0;
213         user_data->reversed.statinfo.max_nr = 0;
214         user_data->forward.statinfo.total_nr = 0;
215         user_data->reversed.statinfo.total_nr = 0;
216         user_data->forward.statinfo.sequence = 0;
217         user_data->reversed.statinfo.sequence = 0;
218         user_data->forward.statinfo.start_seq_nr = 0;
219         user_data->reversed.statinfo.start_seq_nr = 1; /* 1 is ok (for statistics in reversed direction) */
220         user_data->forward.statinfo.stop_seq_nr = 0;
221         user_data->reversed.statinfo.stop_seq_nr = 0;
222         user_data->forward.statinfo.cycles = 0;
223         user_data->reversed.statinfo.cycles = 0;
224         user_data->forward.statinfo.under = FALSE;
225         user_data->reversed.statinfo.under = FALSE;
226         user_data->forward.statinfo.start_time = 0;
227         user_data->reversed.statinfo.start_time = 0;
228         user_data->forward.statinfo.time = 0;
229         user_data->reversed.statinfo.time = 0;
230
231         user_data->forward.saveinfo.count = 0;
232         user_data->reversed.saveinfo.count = 0;
233         user_data->forward.saveinfo.saved = FALSE;
234         user_data->reversed.saveinfo.saved = FALSE;
235
236 #ifdef USE_CONVERSATION_GRAPH
237         if (user_data->dlg.graph_window != NULL)
238                 gtk_widget_destroy(user_data->dlg.graph_window);
239         
240         g_array_free(user_data->series_fwd.value_pairs, TRUE);
241         user_data->series_fwd.value_pairs = g_array_new(FALSE, FALSE, sizeof(value_pair_t));
242
243         g_array_free(user_data->series_rev.value_pairs, TRUE);
244         user_data->series_rev.value_pairs = g_array_new(FALSE, FALSE, sizeof(value_pair_t));
245 #endif
246
247         /* XXX check for error at fclose? */
248         if (user_data->forward.saveinfo.fp != NULL)
249                 fclose(user_data->forward.saveinfo.fp); 
250         if (user_data->reversed.saveinfo.fp != NULL)
251                 fclose(user_data->reversed.saveinfo.fp); 
252         user_data->forward.saveinfo.fp = fopen(user_data->f_tempname, "wb"); 
253         if (user_data->forward.saveinfo.fp == NULL)
254                 user_data->forward.saveinfo.error_type = TAP_RTP_FILE_OPEN_ERROR;
255         user_data->reversed.saveinfo.fp = fopen(user_data->r_tempname, "wb");
256         if (user_data->reversed.saveinfo.fp == NULL)
257                 user_data->reversed.saveinfo.error_type = TAP_RTP_FILE_OPEN_ERROR;
258         return;
259 }
260
261 /****************************************************************************/
262 /* here we can redraw the output */
263 /* not used yet */
264 static void rtp_draw(void *prs _U_)
265 {
266         return;
267 }
268
269 /* forward declarations */
270 static void add_to_clist(GtkCList *clist, guint32 number, guint16 seq_num,
271                          double delay, double jitter, gchar *status, gboolean marker,
272                          gchar *timeStr, guint32 pkt_len, GdkColor *color);
273
274 static int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
275                                                           packet_info *pinfo, struct _rtp_info *rtpinfo);
276 static int rtp_packet_add_info(GtkCList *clist,
277         tap_rtp_stat_t *statinfo, packet_info *pinfo, struct _rtp_info *rtpinfo);
278 static int rtp_packet_save_payload(tap_rtp_save_info_t *saveinfo, 
279                                                                    tap_rtp_stat_t *statinfo,
280                                                                    packet_info *pinfo, struct _rtp_info *rtpinfo);
281
282
283 /****************************************************************************/
284 /* whenever a RTP packet is seen by the tap listener */
285 static int rtp_packet(user_data_t *user_data, packet_info *pinfo, epan_dissect_t *edt _U_, struct _rtp_info *rtpinfo)
286 {
287 #ifdef USE_CONVERSATION_GRAPH
288         value_pair_t vp;
289 #endif
290
291         /* we ignore packets that are not displayed */
292         if (pinfo->fd->flags.passed_dfilter == 0)
293                 return 0;
294
295         /* is it the forward direction?  */
296         else if (user_data->ssrc_fwd == rtpinfo->info_sync_src)  {
297 #ifdef USE_CONVERSATION_GRAPH
298                 vp.time = ((double)pinfo->fd->rel_secs + (double)pinfo->fd->rel_usecs/1000000);
299                 vp.fnumber = pinfo->fd->num;
300                 g_array_append_val(user_data->series_fwd.value_pairs, vp);
301 #endif
302                 rtp_packet_analyse(&(user_data->forward.statinfo), pinfo, rtpinfo);
303                 rtp_packet_add_info(user_data->dlg.clist_fwd,
304                         &(user_data->forward.statinfo), pinfo, rtpinfo);
305                 rtp_packet_save_payload(&(user_data->forward.saveinfo),
306                         &(user_data->forward.statinfo), pinfo, rtpinfo);
307         }
308         /* is it the reversed direction? */
309         else if (user_data->ssrc_rev == rtpinfo->info_sync_src) {
310 #ifdef USE_CONVERSATION_GRAPH
311                 vp.time = ((double)pinfo->fd->rel_secs + (double)pinfo->fd->rel_usecs/1000000);
312                 vp.fnumber = pinfo->fd->num;
313                 g_array_append_val(user_data->series_rev.value_pairs, vp);
314 #endif
315                 rtp_packet_analyse(&(user_data->reversed.statinfo), pinfo, rtpinfo);
316                 rtp_packet_add_info(user_data->dlg.clist_rev,
317                         &(user_data->reversed.statinfo), pinfo, rtpinfo);
318                 rtp_packet_save_payload(&(user_data->reversed.saveinfo),
319                         &(user_data->reversed.statinfo), pinfo, rtpinfo);
320         }
321
322         return 0;
323 }
324
325
326 /****************************************************************************/
327 static int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
328                                                           packet_info *pinfo, struct _rtp_info *rtpinfo)
329 {
330         double current_time;
331         double current_jitter;
332         gboolean first_packet = statinfo->first_packet;
333
334         statinfo->flags = 0;
335
336         /* check payload type */
337         if (rtpinfo->info_payload_type == PT_CN
338                 || rtpinfo->info_payload_type == PT_CN_OLD)
339                 statinfo->flags |= STAT_FLAG_PT_CN;
340         if (rtpinfo->info_payload_type != statinfo->pt)
341                 statinfo->flags |= STAT_FLAG_PT_CHANGE;
342
343         statinfo->pt = rtpinfo->info_payload_type;
344         
345         /* store the current time and calculate the current jitter */
346         current_time = (double)pinfo->fd->rel_secs + (double) pinfo->fd->rel_usecs/1000000;
347         current_jitter = statinfo->jitter + ( fabs (current_time - (statinfo->time) -
348                 ((double)(rtpinfo->info_timestamp)-(double)(statinfo->timestamp))/8000)- statinfo->jitter)/16;
349         statinfo->delay = current_time-(statinfo->time);
350         statinfo->jitter = current_jitter;
351
352         /*  is this the first packet we got in this direction? */
353         if (first_packet) {
354                 statinfo->first_packet = FALSE;
355                 statinfo->start_seq_nr = rtpinfo->info_seq_num;
356                 statinfo->start_time = current_time;
357                 statinfo->delay = 0;
358                 statinfo->jitter = 0;
359                 statinfo->flags |= STAT_FLAG_FIRST;
360         }
361         /* is it a packet with the mark bit set? */
362         if (rtpinfo->info_marker_set) {
363                 statinfo->delta_timestamp = rtpinfo->info_timestamp - statinfo->timestamp;
364                 statinfo->flags |= STAT_FLAG_MARKER;
365         }
366         /* if neither then it is a normal packet */
367         {
368                 if (statinfo->delay > statinfo->max_delay) {
369                         statinfo->max_delay = statinfo->delay;
370                         statinfo->max_nr = pinfo->fd->num;
371                 }
372         }
373
374         /* When calculating expected rtp packets the seq number can wrap around
375         * so we have to count the number of cycles
376         * Variable cycles counts the wraps around in forwarding connection and
377         * under is flag that indicates where we are
378         *
379         * XXX how to determine number of cycles with all possible lost, late
380         * and duplicated packets without any doubt? It seems to me, that
381         * because of all possible combination of late, duplicated or lost
382         * packets, this can only be more or less good approximation
383         *
384         * There are some combinations (rare but theoretically possible),
385         * where below code won't work correctly - statistic may be wrong then.
386         */
387
388         /* so if the current sequence number is less than the start one
389         * we assume, that there is another cycle running */
390         if ((rtpinfo->info_seq_num < statinfo->start_seq_nr) && (statinfo->under == FALSE)){
391                 statinfo->cycles++;
392                 statinfo->under = TRUE;
393         }
394         /* what if the start seq nr was 0? Then the above condition will never
395         * be true, so we add another condition. XXX The problem would arise
396         * if one of the packets with seq nr 0 or 65535 would be lost or late */
397         else if ((rtpinfo->info_seq_num == 0) && (statinfo->stop_seq_nr == 65535) &&
398                 (statinfo->under == FALSE)){
399                 statinfo->cycles++;
400                 statinfo->under = TRUE;
401         }
402         /* the whole round is over, so reset the flag */
403         else if ((rtpinfo->info_seq_num > statinfo->start_seq_nr) && (statinfo->under != FALSE)) {
404                 statinfo->under = FALSE;
405         }
406
407         /* Since it is difficult to count lost, duplicate or late packets separately,
408         * we would like to know at least how many times the sequence number was not ok */
409
410         /* if the current seq number equals the last one or if we are here for
411         * the first time, then it is ok, we just store the current one as the last one */
412         if ( (statinfo->seq_num+1 == rtpinfo->info_seq_num) || (first_packet) )
413                 statinfo->seq_num = rtpinfo->info_seq_num;
414         /* if the first one is 65535. XXX same problem as above: if seq 65535 or 0 is lost... */
415         else if ( (statinfo->seq_num == 65535) && (rtpinfo->info_seq_num == 0) )
416                 statinfo->seq_num = rtpinfo->info_seq_num;
417         /* lost packets */
418         else if (statinfo->seq_num+1 < rtpinfo->info_seq_num) {
419                 statinfo->seq_num = rtpinfo->info_seq_num;
420                 statinfo->sequence++;
421                 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
422         }
423         /* late or duplicated */
424         else if (statinfo->seq_num+1 > rtpinfo->info_seq_num) {
425                 statinfo->sequence++;
426                 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
427         }
428
429         statinfo->time = current_time;
430         statinfo->timestamp = rtpinfo->info_timestamp;
431         statinfo->stop_seq_nr = rtpinfo->info_seq_num;
432         statinfo->total_nr++;
433
434         return 0;
435 }
436
437
438 /****************************************************************************/
439 /* adds statistics information from the packet to the clist */
440 static int rtp_packet_add_info(GtkCList *clist,
441         tap_rtp_stat_t *statinfo, packet_info *pinfo, struct _rtp_info *rtpinfo)
442 {
443         guint16 msecs;
444         gchar timeStr[32];
445         struct tm *tm_tmp;
446         time_t then;
447         gchar status[40];
448         GdkColor color = {0, 0xffff, 0xffff, 0xffff};
449
450         then = pinfo->fd->abs_secs;
451         msecs = (guint16)(pinfo->fd->abs_usecs/1000);
452         tm_tmp = localtime(&then);
453         snprintf(timeStr,32,"%02d/%02d/%04d %02d:%02d:%02d.%03d",
454                 tm_tmp->tm_mon + 1,
455                 tm_tmp->tm_mday,
456                 tm_tmp->tm_year + 1900,
457                 tm_tmp->tm_hour,
458                 tm_tmp->tm_min,
459                 tm_tmp->tm_sec,
460                 msecs);
461
462         if (statinfo->pt == PT_CN) {
463                 snprintf(status,40,"Comfort noise (PT=13, RFC 3389)");
464                 color.pixel = 0;
465                 color.red = 0x7fff;
466                 color.green = 0x7fff;
467                 color.blue = 0xffff;
468         }
469         else if (statinfo->pt == PT_CN_OLD) {
470                 snprintf(status,40,"Comfort noise (PT=19, reserved)");
471                 color.pixel = 0;
472                 color.red = 0x7fff;
473                 color.green = 0x7fff;
474                 color.blue = 0xffff;
475         }
476         else if (statinfo->flags & STAT_FLAG_WRONG_SEQ) {
477                 snprintf(status,40,"Wrong sequence nr.");
478                 color.pixel = 0;
479                 color.red = 0xffff;
480                 color.green = 0x7fff;
481                 color.blue = 0x7fff;
482         }
483         else if ((statinfo->flags & STAT_FLAG_PT_CHANGE)
484                 &&  !(statinfo->flags & STAT_FLAG_FIRST)
485                 &&  !(statinfo->flags & STAT_FLAG_PT_CN)) {
486                 snprintf(status,40,"Payload type changed to PT=%u", statinfo->pt);
487                 color.pixel = 0;
488                 color.red = 0xffff;
489                 color.green = 0x7fff;
490                 color.blue = 0x7fff;
491         }
492         else {
493                 snprintf(status,40,OK_TEXT);
494         }
495
496         /*  is this the first packet we got in this direction? */
497         if (statinfo->first_packet) {
498                 add_to_clist(clist,
499                         pinfo->fd->num, rtpinfo->info_seq_num,
500                         0,
501                         0,
502                         status,
503                         rtpinfo->info_marker_set,
504                         timeStr, pinfo->fd->pkt_len,
505                         &color);
506         }
507         else {
508                 add_to_clist(clist,
509                         pinfo->fd->num, rtpinfo->info_seq_num,
510                         statinfo->delay,
511                         statinfo->jitter,
512                         status,
513                         rtpinfo->info_marker_set,
514                         timeStr, pinfo->fd->pkt_len,
515                         &color);
516         }
517
518         return 0;
519 }
520
521
522 /****************************************************************************/
523 static int rtp_packet_save_payload(tap_rtp_save_info_t *saveinfo, 
524                                                                    tap_rtp_stat_t *statinfo,
525                                                                    packet_info *pinfo, struct _rtp_info *rtpinfo)
526 {
527         guint i;
528         guint8 *data;
529         gint16 tmp;
530
531         /*  is this the first packet we got in this direction? */
532         if (statinfo->first_packet) {
533                 if (saveinfo->fp == NULL) {
534                         saveinfo->saved = FALSE;
535                         saveinfo->error_type = TAP_RTP_FILE_OPEN_ERROR;
536                 }
537                 else
538                         saveinfo->saved = TRUE;
539         }
540
541         /* save the voice information */
542         /* if there was already an error, we quit */
543         if (saveinfo->saved == FALSE)
544                 return 0;
545
546         /* if the captured length and packet length aren't equal, we quit
547         * because there is some information missing */
548         if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
549                 saveinfo->saved = FALSE;
550                 saveinfo->error_type = TAP_RTP_WRONG_LENGTH;
551                 return 0;
552         }
553
554         /* if padding bit is set, but the padding count is bigger
555         * then the whole RTP data - error with padding count */
556         if ( (rtpinfo->info_padding_set != FALSE) &&
557                 (rtpinfo->info_padding_count > rtpinfo->info_payload_len) ) {
558                 saveinfo->saved = FALSE;
559                 saveinfo->error_type = TAP_RTP_PADDING_ERROR;
560                 return 0;
561         }
562
563         /* do we need to insert some silence? */
564         if ((rtpinfo->info_marker_set) &&
565                 (statinfo->delta_timestamp > (rtpinfo->info_payload_len - rtpinfo->info_padding_count)) )  {
566                 /* the amount of silence should be the difference between
567                 * the last timestamp and the current one minus x
568                 * x should equal the amount of information in the last frame
569                 * XXX not done yet */
570                 for(i=0; i < (statinfo->delta_timestamp - rtpinfo->info_payload_len -
571                         rtpinfo->info_padding_count); i++) {
572                         tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
573                         fwrite(&tmp, 2, 1, saveinfo->fp);
574                         saveinfo->count++;
575                 }
576                 fflush(saveinfo->fp);
577         }
578
579         /* ulaw? */
580         if (rtpinfo->info_payload_type == 0) {
581                 /* we put the pointer at the beggining of the RTP data, that is
582                 * at the end of the current frame minus the length of the
583                 * padding count minus length of the RTP data */
584                 data = cfile.pd + (pinfo->fd->pkt_len - rtpinfo->info_payload_len);
585                 for(i=0; i < (rtpinfo->info_payload_len - rtpinfo->info_padding_count); i++, data++) {
586                         tmp = (gint16 )ulaw2linear((unsigned char)*data);
587                         fwrite(&tmp, 2, 1, saveinfo->fp);
588                         saveinfo->count++;
589                 }
590                 fflush(saveinfo->fp);
591                 saveinfo->saved = TRUE;
592                 return 0;
593         }
594
595         /* alaw? */
596         else if (rtpinfo->info_payload_type == 8) {
597                 data = cfile.pd + (pinfo->fd->pkt_len - rtpinfo->info_payload_len);
598                 for(i=0; i < (rtpinfo->info_payload_len - rtpinfo->info_padding_count); i++, data++) {
599                         tmp = (gint16 )alaw2linear((unsigned char)*data);
600                         fwrite(&tmp, 2, 1, saveinfo->fp);
601                         saveinfo->count++;
602                 }
603                 fflush(saveinfo->fp);
604                 saveinfo->saved = TRUE;
605                 return 0;
606         }
607         /* comfort noise? - do nothing */
608         else if (rtpinfo->info_payload_type == PT_CN
609                 && rtpinfo->info_payload_type == PT_CN_OLD) {
610         }
611         /* unsupported codec or XXX other error */
612         else {
613                 saveinfo->saved = FALSE;
614                 saveinfo->error_type = TAP_RTP_WRONG_CODEC;
615                 return 0;
616         }
617
618         return 0;
619 }
620
621
622 /****************************************************************************/
623 /* CALLBACKS */
624
625 /****************************************************************************/
626 /* XXX just copied from gtk/rpc_stat.c */
627 void protect_thread_critical_region(void);
628 void unprotect_thread_critical_region(void);
629
630
631 /****************************************************************************/
632 /* close the dialog window and remove the tap listener */
633 static void on_destroy(GtkWidget *win _U_, user_data_t *user_data _U_)
634 {
635         protect_thread_critical_region();
636         remove_tap_listener(user_data);
637         unprotect_thread_critical_region();
638
639         if (user_data->forward.saveinfo.fp != NULL)
640                 fclose(user_data->forward.saveinfo.fp);
641         if (user_data->reversed.saveinfo.fp != NULL)
642                 fclose(user_data->reversed.saveinfo.fp);
643         remove(user_data->f_tempname);
644         remove(user_data->r_tempname);
645
646         /* Is there a save voice window open? */
647         if (user_data->dlg.save_voice_as_w != NULL)
648                 gtk_widget_destroy(user_data->dlg.save_voice_as_w);
649
650 #ifdef USE_CONVERSATION_GRAPH
651         /* Is there a graph window open? */
652         if (user_data->dlg.graph_window != NULL)
653                 gtk_widget_destroy(user_data->dlg.graph_window);
654 #endif
655
656         g_free(user_data);
657 }
658
659
660 /****************************************************************************/
661 static void on_notebook_switch_page(GtkNotebook *notebook _U_,
662                                     GtkNotebookPage *page _U_,
663                                     gint page_num _U_,
664                                     user_data_t *user_data _U_)
665 {
666         user_data->dlg.selected_clist =
667                 (page_num==0) ? user_data->dlg.clist_fwd : user_data->dlg.clist_rev ;
668         user_data->dlg.selected_row = 0;
669 }
670
671 /****************************************************************************/
672 static void on_clist_select_row(GtkCList        *clist _U_,
673                                 gint             row _U_,
674                                 gint             column _U_,
675                                 GdkEvent        *event _U_,
676                                 user_data_t     *user_data _U_)
677 {
678         user_data->dlg.selected_clist = clist;
679         user_data->dlg.selected_row = row;
680 }
681
682
683 #ifdef USE_CONVERSATION_GRAPH
684 /****************************************************************************/
685 /* when the graph window gets destroyed */
686 static void on_destroy_graph(GtkWidget *win _U_, user_data_t *user_data _U_)
687 {
688         /* note that graph window has been destroyed */
689         user_data->dlg.graph_window = NULL;
690 }
691
692 /****************************************************************************/
693 static void graph_selection_callback(value_pair_t vp, user_data_t *user_data)
694 {
695         guint row;
696         GtkCList *clist = NULL;
697         if (vp.fnumber != 0) {
698                 clist = GTK_CLIST(user_data->dlg.clist_fwd);
699                 row = gtk_clist_find_row_from_data(clist,
700                                 GUINT_TO_POINTER(vp.fnumber));
701                 if (row==-1) {
702                         clist = GTK_CLIST(user_data->dlg.clist_rev);
703                         row = gtk_clist_find_row_from_data(clist,
704                                         GUINT_TO_POINTER(vp.fnumber));
705                 }
706                 if (row!=-1) {
707                         gtk_notebook_set_page(GTK_NOTEBOOK(user_data->dlg.notebook),
708                                 (clist == GTK_CLIST(user_data->dlg.clist_fwd)) ? 0 : 1);
709                         gtk_clist_select_row(clist, row, 0);
710                         gtk_clist_moveto(clist, row, 0, 0.5, 0);
711                 }
712         }
713 }
714
715
716 /****************************************************************************/
717 static void on_graph_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
718 {
719         gchar title1[80];
720         gchar title2[80];
721         GList *list = NULL;
722         
723         if (user_data->dlg.graph_window != NULL) {
724                 /* There's already a graph window; reactivate it. */
725                 reactivate_window(user_data->dlg.graph_window);
726                 return;
727         }
728                 
729         list = g_list_append(list, &(user_data->series_fwd));
730         list = g_list_append(list, &(user_data->series_rev));
731
732         user_data->series_fwd.color.pixel = 0;
733         user_data->series_fwd.color.red = 0x80ff;
734         user_data->series_fwd.color.green = 0xe0ff;
735         user_data->series_fwd.color.blue = 0xffff;
736         user_data->series_fwd.yvalue = 0.5;
737
738         user_data->series_rev.color.pixel = 0;
739         user_data->series_rev.color.red = 0x60ff;
740         user_data->series_rev.color.green = 0xc0ff;
741         user_data->series_rev.color.blue = 0xffff;
742         user_data->series_rev.yvalue = -0.5;
743
744         g_snprintf(title1, 80, "Forward: %s:%u to %s:%u (SSRC=%u)",
745                 ip_to_str((ip_addr_p)&(user_data->ip_src_fwd)),
746                 user_data->port_src_fwd,
747                 ip_to_str((ip_addr_p)&(user_data->ip_dst_fwd)),
748                 user_data->port_dst_fwd,
749                 user_data->ssrc_fwd);
750
751         g_snprintf(title2, 80, "Reverse: %s:%u to %s:%u (SSRC=%u)",
752                 ip_to_str((ip_addr_p)&(user_data->ip_src_rev)),
753                 user_data->port_src_rev,
754                 ip_to_str((ip_addr_p)&(user_data->ip_dst_rev)),
755                 user_data->port_dst_rev,
756                 user_data->ssrc_rev);
757
758         user_data->dlg.graph_window = show_conversation_graph(list, title1, title2,
759                 &graph_selection_callback, user_data);
760         gtk_signal_connect(GTK_OBJECT(user_data->dlg.graph_window), "destroy",
761                 GTK_SIGNAL_FUNC(on_destroy_graph), user_data);
762 }
763 #endif /*USE_CONVERSATION_GRAPH*/
764
765
766 /****************************************************************************/
767 static void on_goto_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
768 {
769         guint fnumber;
770
771         if (user_data->dlg.selected_clist!=NULL) {
772                 fnumber = GPOINTER_TO_UINT(gtk_clist_get_row_data(
773                         GTK_CLIST(user_data->dlg.selected_clist), user_data->dlg.selected_row) );
774                 goto_frame(&cfile, fnumber);
775         }
776 }
777
778
779 static void draw_stat(user_data_t *user_data);
780
781 /****************************************************************************/
782 /* re-dissects all packets */
783 static void on_refresh_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
784 {
785         gtk_clist_clear(GTK_CLIST(user_data->dlg.clist_fwd));
786         gtk_clist_clear(GTK_CLIST(user_data->dlg.clist_rev));
787         redissect_packets(&cfile);
788         draw_stat(user_data);
789 }
790
791 /****************************************************************************/
792 /* on_destroy is automatically called after that */
793 static void on_close_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
794 {
795         gtk_grab_remove(GTK_WIDGET(user_data->dlg.window));
796         gtk_widget_destroy(GTK_WIDGET(user_data->dlg.window));
797 }
798
799 /****************************************************************************/
800 static void on_next_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
801 {
802         GtkCList *clist;
803         gchar *text;
804         gint row;
805         if (user_data->dlg.selected_clist==NULL)
806                 return;
807 /*
808         if (user_data->dlg.selected_row==-1)
809                 user_data->dlg.selected_row = 0;
810 */
811         clist = user_data->dlg.selected_clist;
812         row = user_data->dlg.selected_row + 1;
813
814         while (gtk_clist_get_text(clist,row,5,&text)) {
815                 if (strcmp(text, OK_TEXT) != 0) {
816                         gtk_clist_select_row(clist, row, 0);
817                         gtk_clist_moveto(clist, row, 0, 0.5, 0);
818                         return;
819                 }
820                 ++row;
821         }
822
823         /* wrap around */
824         row = 0;
825         while (gtk_clist_get_text(clist,row,5,&text) && row<user_data->dlg.selected_row) {
826                 if (strcmp(text, OK_TEXT) != 0) {
827                         gtk_clist_select_row(clist, row, 0);
828                         gtk_clist_moveto(clist, row, 0, 0.5, 0);
829                         return;
830                 }
831                 ++row;
832         }
833 }
834
835 /****************************************************************************/
836 /* when we want to save the information */
837 static void save_csv_as_ok_cb(GtkWidget *bt _U_, gpointer fs /*user_data_t *user_data*/ _U_)
838 {
839         gchar *g_dest;
840         GtkWidget *rev, *forw, *both;
841         user_data_t *user_data;
842         
843         FILE *fp;
844         char *columnText;
845         int i,j;
846         
847         g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
848         
849         /* Perhaps the user specified a directory instead of a file.
850         Check whether they did. */
851         if (test_for_directory(g_dest) == EISDIR) {
852                 /* It's a directory - set the file selection box to display it. */
853                 set_last_open_dir(g_dest);
854                 g_free(g_dest);
855                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
856                 return;
857         }
858         
859         rev = (GtkWidget*)OBJECT_GET_DATA(bt, "reversed_rb");
860         forw = (GtkWidget*)OBJECT_GET_DATA(bt, "forward_rb");
861         both = (GtkWidget*)OBJECT_GET_DATA(bt, "both_rb");
862         user_data = (user_data_t*)OBJECT_GET_DATA(bt, "user_data");
863         
864         if (GTK_TOGGLE_BUTTON(forw)->active || GTK_TOGGLE_BUTTON(both)->active) {
865                 fp = fopen(g_dest, "w");
866                 
867                 if (GTK_TOGGLE_BUTTON(both)->active) {
868                         fprintf(fp, "Forward\n");
869                 }
870                 
871                 for(j = 0; j < GTK_CLIST(user_data->dlg.clist_fwd)->columns; j++) {
872                         if (j == 0) {
873                                 fprintf(fp,"%s",GTK_CLIST(user_data->dlg.clist_fwd)->column[j].title);
874                         } else {
875                                 fprintf(fp,",%s",GTK_CLIST(user_data->dlg.clist_fwd)->column[j].title);
876                         }
877                 }
878                 fprintf(fp,"\n");
879                 for (i = 0; i < GTK_CLIST(user_data->dlg.clist_fwd)->rows; i++) {
880                         for(j = 0; j < GTK_CLIST(user_data->dlg.clist_fwd)->columns; j++) {
881                                 gtk_clist_get_text(GTK_CLIST(user_data->dlg.clist_fwd),i,j,&columnText);
882                                 if (j == 0) {
883                                         fprintf(fp,"%s",columnText);
884                                 } else {
885                                         fprintf(fp,",%s",columnText);
886                                 }
887                         }
888                         fprintf(fp,"\n");
889                 }
890                 
891                 fclose(fp);
892         }
893         
894         if (GTK_TOGGLE_BUTTON(rev)->active || GTK_TOGGLE_BUTTON(both)->active) {
895                 
896                 if (GTK_TOGGLE_BUTTON(both)->active) {
897                         fp = fopen(g_dest, "a");
898                         fprintf(fp, "\nReverse\n");
899                 } else {
900                         fp = fopen(g_dest, "w");
901                 }
902                 for(j = 0; j < GTK_CLIST(user_data->dlg.clist_rev)->columns; j++) {
903                         if (j == 0) {
904                                 fprintf(fp,"%s",GTK_CLIST(user_data->dlg.clist_rev)->column[j].title);
905                         } else {
906                                 fprintf(fp,",%s",GTK_CLIST(user_data->dlg.clist_rev)->column[j].title);
907                         }
908                 }
909                 fprintf(fp,"\n");
910                 for (i = 0; i < GTK_CLIST(user_data->dlg.clist_rev)->rows; i++) {
911                         for(j = 0; j < GTK_CLIST(user_data->dlg.clist_rev)->columns; j++) {
912                                 gtk_clist_get_text(GTK_CLIST(user_data->dlg.clist_rev),i,j,&columnText);
913                                 if (j == 0) {
914                                         fprintf(fp,"%s",columnText);
915                                 } else {
916                                         fprintf(fp,",%s",columnText);
917                                 }
918                         }
919                         fprintf(fp,"\n");
920                 }
921                 fclose(fp);
922         }
923
924         gtk_widget_destroy(GTK_WIDGET(user_data->dlg.save_csv_as_w));
925 }
926
927 static void save_csv_as_destroy_cb(GtkWidget *win _U_, user_data_t *user_data _U_)
928 {
929         user_data->dlg.save_csv_as_w = NULL;
930 }
931
932 /* when the user wants to save the csv information in a file */
933 static void save_csv_as_cb(GtkWidget *bt _U_, user_data_t *user_data _U_)
934 {
935         GtkWidget *vertb;
936         GtkWidget *table1;
937         GtkWidget *label_format;
938         GtkWidget *channels_label;
939         GSList *channels_group = NULL;
940         GtkWidget *forward_rb;
941         GtkWidget *reversed_rb;
942         GtkWidget *both_rb;
943         GtkWidget *ok_bt;
944         
945         if (user_data->dlg.save_csv_as_w != NULL) {
946                 /* There's already a Save CSV info dialog box; reactivate it. */
947                 reactivate_window(user_data->dlg.save_csv_as_w);
948                 return;
949         }
950         
951         user_data->dlg.save_csv_as_w = gtk_file_selection_new("Ethereal: Save Data As CSV");
952         gtk_signal_connect(GTK_OBJECT(user_data->dlg.save_csv_as_w), "destroy",
953                 GTK_SIGNAL_FUNC(save_csv_as_destroy_cb), user_data);
954         
955         /* Container for each row of widgets */
956         vertb = gtk_vbox_new(FALSE, 0);
957         gtk_container_border_width(GTK_CONTAINER(vertb), 5);
958         gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->action_area),
959                 vertb, FALSE, FALSE, 0);
960         gtk_widget_show (vertb);
961         
962         table1 = gtk_table_new (2, 4, FALSE);
963         gtk_widget_show (table1);
964         gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
965         gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
966         gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
967         
968         label_format = gtk_label_new ("Format: Comma Separated Values");
969         gtk_widget_show (label_format);
970         gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
971                 (GtkAttachOptions) (GTK_FILL),
972                 (GtkAttachOptions) (0), 0, 0);
973         
974         
975         channels_label = gtk_label_new ("Channels:");
976         gtk_widget_show (channels_label);
977         gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
978                 (GtkAttachOptions) (GTK_FILL),
979                 (GtkAttachOptions) (0), 0, 0);
980         gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
981         
982         forward_rb = gtk_radio_button_new_with_label (channels_group, "forward  ");
983         channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
984         gtk_widget_show (forward_rb);
985         gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
986                 (GtkAttachOptions) (GTK_FILL),
987                 (GtkAttachOptions) (0), 0, 0);
988         
989         reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
990         channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
991         gtk_widget_show (reversed_rb);
992         gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
993                 (GtkAttachOptions) (GTK_FILL),
994                 (GtkAttachOptions) (0), 0, 0);
995         
996         both_rb = gtk_radio_button_new_with_label (channels_group, "both");
997         channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
998         gtk_widget_show (both_rb);
999         gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
1000                 (GtkAttachOptions) (GTK_FILL),
1001                 (GtkAttachOptions) (0), 0, 0);
1002         
1003         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
1004         
1005         ok_bt = GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->ok_button;
1006         OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
1007         OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
1008         OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
1009         OBJECT_SET_DATA(ok_bt, "user_data", user_data);
1010         
1011         /* Connect the cancel_button to destroy the widget */
1012         SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->cancel_button,
1013                 "clicked", (GtkSignalFunc)gtk_widget_destroy,
1014                 user_data->dlg.save_csv_as_w);
1015         
1016         /* Catch the "key_press_event" signal in the window, so that we can catch
1017         the ESC key being pressed and act as if the "Cancel" button had
1018         been selected. */
1019         dlg_set_cancel(user_data->dlg.save_csv_as_w, GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->cancel_button);
1020         
1021         gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
1022                 GTK_SIGNAL_FUNC(save_csv_as_ok_cb), user_data->dlg.save_csv_as_w);
1023         
1024         gtk_widget_show(user_data->dlg.save_csv_as_w);
1025 }
1026
1027
1028 /****************************************************************************/
1029 static void save_voice_as_destroy_cb(GtkWidget *win _U_, user_data_t *user_data _U_)
1030 {
1031         /* Note that we no longer have a Save voice info dialog box. */
1032         user_data->dlg.save_voice_as_w = NULL;
1033 }
1034
1035 /****************************************************************************/
1036 /* here we save it into a file that user specified */
1037 /* XXX what about endians here? could go something wrong? */
1038 static gboolean copy_file(gchar *dest, gint channels, /*gint format,*/ user_data_t *user_data)
1039 {
1040         int to_fd, forw_fd, rev_fd, fread = 0, rread = 0, fwritten, rwritten;
1041         gint16 f_pd;
1042         gint16 r_pd;
1043         gchar pd[1];
1044         guint32 f_write_silence = 0;
1045         guint32 r_write_silence = 0;
1046         progdlg_t *progbar;
1047         guint32 progbar_count, progbar_quantum, progbar_nextstep = 0, count = 0;
1048         gboolean stop_flag = FALSE;
1049
1050         forw_fd = open(user_data->f_tempname, O_RDONLY | O_BINARY);
1051         if (forw_fd < 0) 
1052                 return FALSE;
1053         rev_fd = open(user_data->r_tempname, O_RDONLY | O_BINARY);
1054         if (rev_fd < 0) {
1055                 close(forw_fd); 
1056                 return FALSE;
1057         }
1058
1059         /* open file for saving */
1060         to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
1061         if (to_fd < 0) {
1062                 close(forw_fd);
1063                 close(rev_fd);
1064                 return FALSE;
1065         }
1066
1067         progbar = create_progress_dlg("Saving voice in a file", dest, "Stop", &stop_flag);
1068
1069         /* First we write the .au header. XXX Hope this is endian independant */
1070         /* the magic word 0x2e736e64 == .snd */
1071         *pd = (unsigned char)0x2e; write(to_fd, pd, 1);
1072         *pd = (unsigned char)0x73; write(to_fd, pd, 1);
1073         *pd = (unsigned char)0x6e; write(to_fd, pd, 1);
1074         *pd = (unsigned char)0x64; write(to_fd, pd, 1);
1075         /* header offset == 24 bytes */
1076         *pd = (unsigned char)0x00; write(to_fd, pd, 1);
1077         write(to_fd, pd, 1);
1078         write(to_fd, pd, 1);
1079         *pd = (unsigned char)0x18; write(to_fd, pd, 1);
1080         /* total length, it is permited to set this to 0xffffffff */
1081         *pd = (unsigned char)0xff; write(to_fd, pd, 1); 
1082         write(to_fd, pd, 1); 
1083         write(to_fd, pd, 1); 
1084         write(to_fd, pd, 1);
1085         /* encoding format == 8 bit ulaw */
1086         *pd = (unsigned char)0x00; write(to_fd, pd, 1);
1087         write(to_fd, pd, 1);
1088         write(to_fd, pd, 1);
1089         *pd = (unsigned char)0x01; write(to_fd, pd, 1);
1090         /* sample rate == 8000 Hz */
1091         *pd = (unsigned char)0x00; write(to_fd, pd, 1);
1092         write(to_fd, pd, 1);
1093         *pd = (unsigned char)0x1f; write(to_fd, pd, 1);
1094         *pd = (unsigned char)0x40; write(to_fd, pd, 1);
1095         /* channels == 1 */
1096         *pd = (unsigned char)0x00; write(to_fd, pd, 1);
1097         write(to_fd, pd, 1);
1098         write(to_fd, pd, 1);
1099         *pd = (unsigned char)0x01; write(to_fd, pd, 1);
1100         
1101         switch (channels) {
1102                 /* only forward direction */
1103                 case 1: {
1104                         progbar_count = user_data->forward.saveinfo.count;
1105                         progbar_quantum = user_data->forward.saveinfo.count/100;
1106                         while ((fread = read(forw_fd, &f_pd, 2)) > 0) {
1107                                 if(stop_flag) 
1108                                         break;
1109                                 if((count > progbar_nextstep) && (count <= progbar_count)) {
1110                                         update_progress_dlg(progbar, 
1111                                                 (gfloat) count/progbar_count, "Saving");
1112                                         progbar_nextstep = progbar_nextstep + progbar_quantum;
1113                                 }
1114                                 count++;
1115                                 *pd = (unsigned char)linear2ulaw(f_pd);
1116                                 fwritten = write(to_fd, pd, 1);
1117                                 if ((fwritten*2 < fread) || (fwritten < 0) || (fread < 0)) {
1118                                         close(forw_fd);
1119                                         close(rev_fd);
1120                                         close(to_fd);
1121                                         destroy_progress_dlg(progbar);
1122                                         return FALSE;
1123                                 }
1124                         }
1125                         break;
1126                 }
1127                 /* only reversed direction */
1128                 case 2: {
1129                         progbar_count = user_data->reversed.saveinfo.count;
1130                         progbar_quantum = user_data->reversed.saveinfo.count/100;
1131                         while ((rread = read(rev_fd, &r_pd, 2)) > 0) {
1132                                 if(stop_flag) 
1133                                         break;
1134                                 if((count > progbar_nextstep) && (count <= progbar_count)) {
1135                                         update_progress_dlg(progbar, 
1136                                                 (gfloat) count/progbar_count, "Saving");
1137                                         progbar_nextstep = progbar_nextstep + progbar_quantum;
1138                                 }
1139                                 count++;
1140                                 *pd = (unsigned char)linear2ulaw(r_pd);
1141                                 rwritten = write(to_fd, pd, 1);
1142                                 if ((rwritten*2 < rread) || (rwritten < 0) || (rread < 0)) {
1143                                         close(forw_fd);
1144                                         close(rev_fd);
1145                                         close(to_fd);
1146                                         destroy_progress_dlg(progbar);
1147                                         return FALSE;
1148                                 }
1149                         }
1150                         break;
1151                 }
1152                 /* both directions */
1153                 default: {
1154                         (user_data->forward.saveinfo.count > user_data->reversed.saveinfo.count) ? 
1155                                         (progbar_count = user_data->forward.saveinfo.count) : 
1156                                                 (progbar_count = user_data->reversed.saveinfo.count);
1157                         progbar_quantum = progbar_count/100;
1158                         /* since conversation in one way can start later than in the other one, 
1159                          * we have to write some silence information for one channel */
1160                         if (user_data->forward.statinfo.start_time > user_data->reversed.statinfo.start_time) {
1161                                 f_write_silence = 
1162                                         (user_data->forward.statinfo.start_time-user_data->reversed.statinfo.start_time)*8000;
1163                         }
1164                         else if (user_data->forward.statinfo.start_time < user_data->reversed.statinfo.start_time) {
1165                                 r_write_silence = 
1166                                         (user_data->reversed.statinfo.start_time-user_data->forward.statinfo.start_time)*8000;
1167                         }
1168                         for(;;) {
1169                                 if(stop_flag) 
1170                                         break;
1171                                 if((count > progbar_nextstep) && (count <= progbar_count)) {
1172                                         update_progress_dlg(progbar, 
1173                                                 (gfloat) count/progbar_count, "Saving");
1174                                         progbar_nextstep = progbar_nextstep + progbar_quantum;
1175                                 }
1176                                 count++;
1177                                 if(f_write_silence > 0) {
1178                                         rread = read(rev_fd, &r_pd, 2);
1179                                         f_pd = 0;
1180                                         fread = 1;
1181                                         f_write_silence--;
1182                                 }
1183                                 else if(r_write_silence > 0) {
1184                                         fread = read(forw_fd, &f_pd, 2);
1185                                         r_pd = 0;
1186                                         rread = 1;
1187                                         r_write_silence--;
1188                                 }
1189                                 else {
1190                                         fread = read(forw_fd, &f_pd, 2); 
1191                                         rread = read(rev_fd, &r_pd, 2);
1192                                 }
1193                                 if ((rread == 0) && (fread == 0)) 
1194                                         break;
1195                                 *pd = (unsigned char)linear2ulaw( (f_pd + r_pd)/2 );
1196                                 rwritten = write(to_fd, pd, 1);
1197                                 if ((rwritten < 0) || (rread < 0) || (fread < 0)) {
1198                                         close(forw_fd);
1199                                         close(rev_fd);
1200                                         close(to_fd);
1201                                         destroy_progress_dlg(progbar);
1202                                         return FALSE;
1203                                 }
1204                         }
1205                 }
1206         }
1207         destroy_progress_dlg(progbar);
1208         close(forw_fd);
1209         close(rev_fd);
1210         close(to_fd);
1211         return TRUE;
1212 }
1213
1214
1215 /****************************************************************************/
1216 /* the user wants to save in a file */
1217 /* XXX support for different formats is currently commented out */
1218 static void save_voice_as_ok_cb(GtkWidget *ok_bt _U_, gpointer fs _U_)
1219 {
1220         gchar *g_dest;
1221         /*GtkWidget *wav, *au, *sw;*/
1222         GtkWidget *rev, *forw, *both;
1223         user_data_t *user_data;
1224         gint channels /*, format*/;
1225         
1226         g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
1227         
1228         /* Perhaps the user specified a directory instead of a file.
1229         Check whether they did. */
1230         if (test_for_directory(g_dest) == EISDIR) {
1231                 /* It's a directory - set the file selection box to display it. */
1232                 set_last_open_dir(g_dest);
1233                 g_free(g_dest);
1234                 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
1235                 return;
1236         }
1237         
1238         /*wav = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "wav_rb");
1239         au = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "au_rb");
1240         sw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "sw_rb");*/
1241         rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");
1242         forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");
1243         both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");
1244         user_data = (user_data_t *)OBJECT_GET_DATA(ok_bt, "user_data");
1245         
1246         /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.
1247         * we don't support that codec. So we pop up a warning. Maybe it would be better to
1248         * disable the ok button or disable the buttons for direction if only one is not ok. The
1249         * problem is if we open the save voice dialog and then click the refresh button and maybe 
1250         * the state changes, so we can't save anymore. In this case we should be able to update
1251         * the buttons. For now it is easier if we put the warning when the ok button is pressed.
1252         */
1253         
1254         /* we can not save in both dirctions */
1255         if ((user_data->forward.saveinfo.saved == FALSE) && (user_data->reversed.saveinfo.saved == FALSE) && (GTK_TOGGLE_BUTTON (both)->active)) {
1256                 /* there are many combinations here, we just exit when first matches */
1257                 if ((user_data->forward.saveinfo.error_type == TAP_RTP_WRONG_CODEC) || 
1258                         (user_data->reversed.saveinfo.error_type == TAP_RTP_WRONG_CODEC))
1259                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, 
1260                         "Can't save in a file: Unsupported codec!");
1261                 else if ((user_data->forward.saveinfo.error_type == TAP_RTP_WRONG_LENGTH) || 
1262                         (user_data->reversed.saveinfo.error_type == TAP_RTP_WRONG_LENGTH))
1263                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, 
1264                         "Can't save in a file: Wrong length of captured packets!");
1265                 else if ((user_data->forward.saveinfo.error_type == TAP_RTP_PADDING_ERROR) || 
1266                         (user_data->reversed.saveinfo.error_type == TAP_RTP_PADDING_ERROR))
1267                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, 
1268                         "Can't save in a file: RTP data with padding!");
1269                 else  
1270                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, 
1271                         "Can't save in a file: File I/O problem!");
1272                 return;
1273         }
1274         /* we can not save forward direction */
1275         else if ((user_data->forward.saveinfo.saved == FALSE) && ((GTK_TOGGLE_BUTTON (forw)->active) ||
1276                 (GTK_TOGGLE_BUTTON (both)->active))) {  
1277                 if (user_data->forward.saveinfo.error_type == TAP_RTP_WRONG_CODEC)
1278                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, 
1279                         "Can't save forward direction in a file: Unsupported codec!");
1280                 else if (user_data->forward.saveinfo.error_type == TAP_RTP_WRONG_LENGTH)
1281                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1282                         "Can't save forward direction in a file: Wrong length of captured packets!");
1283                 else if (user_data->forward.saveinfo.error_type == TAP_RTP_PADDING_ERROR)
1284                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, 
1285                         "Can't save forward direction in a file: RTP data with padding!");
1286                 else
1287                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, 
1288                         "Can't save forward direction in a file: File I/O problem!");
1289                 return;
1290         }
1291         /* we can not save reversed direction */
1292         else if ((user_data->reversed.saveinfo.saved == FALSE) && ((GTK_TOGGLE_BUTTON (rev)->active) ||
1293                 (GTK_TOGGLE_BUTTON (both)->active))) {  
1294                 if (user_data->reversed.saveinfo.error_type == TAP_RTP_WRONG_CODEC)
1295                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1296                         "Can't save reversed direction in a file: Unsupported codec!");
1297                 else if (user_data->reversed.saveinfo.error_type == TAP_RTP_WRONG_LENGTH)
1298                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1299                         "Can't save reversed direction in a file: Wrong length of captured packets!");
1300                 else if (user_data->reversed.saveinfo.error_type == TAP_RTP_PADDING_ERROR)
1301                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1302                         "Can't save reversed direction in a file: RTP data with padding!");
1303                 else if (user_data->reversed.saveinfo.error_type == TAP_RTP_NO_DATA)
1304                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1305                         "Can't save reversed direction in a file: No RTP data!");
1306                 else
1307                         simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1308                         "Can't save reversed direction in a file: File I/O problem!");
1309                 return;
1310         }
1311         
1312         /*if (GTK_TOGGLE_BUTTON (wav)->active)
1313         format = 1;
1314         else if (GTK_TOGGLE_BUTTON (au)->active)
1315         format = 2;
1316         else if (GTK_TOGGLE_BUTTON (sw)->active)
1317         format = 3;*/
1318         
1319         if (GTK_TOGGLE_BUTTON (rev)->active)
1320                 channels = 2;
1321         else if (GTK_TOGGLE_BUTTON (both)->active)
1322                 channels = 3;
1323         else 
1324                 channels = 1;
1325         
1326         if(!copy_file(g_dest, channels/*, format*/, user_data)) {
1327                 simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1328                         "An error occured while saving voice in a file!");
1329                 return;
1330         }
1331         
1332         gtk_widget_destroy(GTK_WIDGET(user_data->dlg.save_voice_as_w));
1333 }
1334
1335 /****************************************************************************/
1336 /* when the user wants to save the voice information in a file */
1337 /* XXX support for different formats is currently commented out */
1338 static void on_save_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
1339 {
1340         GtkWidget *vertb;
1341         GtkWidget *table1;
1342         GtkWidget *label_format;
1343         GtkWidget *channels_label;
1344         /*GSList *format_group = NULL;*/
1345         GSList *channels_group = NULL;
1346         GtkWidget *forward_rb;
1347         GtkWidget *reversed_rb;
1348         GtkWidget *both_rb;
1349         /*GtkWidget *wav_rb; GtkWidget *au_rb; GtkWidget *sw_rb;*/
1350         GtkWidget *ok_bt;
1351         
1352         /* if we can't save in a file: wrong codec, cut packets or other errors */
1353         /* shold the error arise here or later when you click ok button ? 
1354         * if we do it here, then we must disable the refresh button, so we don't do it here */
1355         
1356         if (user_data->dlg.save_voice_as_w != NULL) {
1357                 /* There's already a Save voice info dialog box; reactivate it. */
1358                 reactivate_window(user_data->dlg.save_voice_as_w);
1359                 return;
1360         }
1361         
1362         user_data->dlg.save_voice_as_w = gtk_file_selection_new("Ethereal: Save Payload As ...");
1363         gtk_signal_connect(GTK_OBJECT(user_data->dlg.save_voice_as_w), "destroy",
1364                 GTK_SIGNAL_FUNC(save_voice_as_destroy_cb), user_data);
1365         
1366         /* Container for each row of widgets */
1367         vertb = gtk_vbox_new(FALSE, 0);
1368         gtk_container_border_width(GTK_CONTAINER(vertb), 5);
1369         gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->action_area),
1370                 vertb, FALSE, FALSE, 0);
1371         gtk_widget_show (vertb);
1372         
1373         table1 = gtk_table_new (2, 4, FALSE);
1374         gtk_widget_show (table1);
1375         gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
1376         gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
1377         gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
1378         
1379         label_format = gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");
1380         gtk_widget_show (label_format);
1381         gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
1382                 (GtkAttachOptions) (GTK_FILL),
1383                 (GtkAttachOptions) (0), 0, 0);
1384         
1385         /* we support .au - ulaw*/ 
1386         /*      wav_rb = gtk_radio_button_new_with_label (format_group, ".wav");
1387         format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (wav_rb));
1388         gtk_widget_show (wav_rb);
1389         gtk_table_attach (GTK_TABLE (table1), wav_rb, 1, 2, 0, 1,
1390         (GtkAttachOptions) (GTK_FILL),
1391         (GtkAttachOptions) (0), 0, 0);
1392         
1393           sw_rb = gtk_radio_button_new_with_label (format_group, "8 kHz, 16 bit  ");
1394           format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sw_rb));
1395           gtk_widget_show (sw_rb);
1396           gtk_table_attach (GTK_TABLE (table1), sw_rb, 2, 3, 0, 1,
1397           (GtkAttachOptions) (GTK_FILL),
1398           (GtkAttachOptions) (0), 0, 0);
1399           au_rb = gtk_radio_button_new_with_label (format_group, ".au");
1400           format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (au_rb));
1401           gtk_widget_show (au_rb);
1402           gtk_table_attach (GTK_TABLE (table1), au_rb, 3, 4, 0, 1,
1403           (GtkAttachOptions) (GTK_FILL),
1404           (GtkAttachOptions) (0), 0, 0);
1405         */ 
1406         
1407         channels_label = gtk_label_new ("Channels:");
1408         gtk_widget_show (channels_label);
1409         gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
1410                 (GtkAttachOptions) (GTK_FILL),
1411                 (GtkAttachOptions) (0), 0, 0);
1412         gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
1413         
1414         forward_rb = gtk_radio_button_new_with_label (channels_group, "forward  ");
1415         channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
1416         gtk_widget_show (forward_rb);
1417         gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
1418                 (GtkAttachOptions) (GTK_FILL),
1419                 (GtkAttachOptions) (0), 0, 0);
1420         
1421         reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
1422         channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
1423         gtk_widget_show (reversed_rb);
1424         gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
1425                 (GtkAttachOptions) (GTK_FILL),
1426                 (GtkAttachOptions) (0), 0, 0);
1427         
1428         both_rb = gtk_radio_button_new_with_label (channels_group, "both");
1429         channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
1430         gtk_widget_show (both_rb);
1431         gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
1432                 (GtkAttachOptions) (GTK_FILL),
1433                 (GtkAttachOptions) (0), 0, 0);
1434         
1435         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
1436         
1437         /* if one direction is nok we don't allow saving 
1438         XXX this is not ok since the user can click the refresh button and cause changes
1439         but we can not update this window. So we move all the decision on the time the ok
1440         button is clicked
1441         if (user_data->forward.saved == FALSE) {
1442         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb), TRUE);
1443         gtk_widget_set_sensitive(forward_rb, FALSE);
1444         gtk_widget_set_sensitive(both_rb, FALSE);
1445         }
1446         else if (user_data->reversed.saved == FALSE) {
1447         gtk_widget_set_sensitive(reversed_rb, FALSE);
1448         gtk_widget_set_sensitive(both_rb, FALSE);
1449         }
1450         */
1451         
1452         ok_bt = GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->ok_button;
1453         /*OBJECT_SET_DATA(ok_bt, "wav_rb", wav_rb);
1454         OBJECT_SET_DATA(ok_bt, "au_rb", au_rb);
1455         OBJECT_SET_DATA(ok_bt, "sw_rb", sw_rb);*/
1456         OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
1457         OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
1458         OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
1459         OBJECT_SET_DATA(ok_bt, "user_data", user_data);
1460         
1461         /* Connect the cancel_button to destroy the widget */
1462         SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->cancel_button,
1463                 "clicked", (GtkSignalFunc)gtk_widget_destroy,
1464                 user_data->dlg.save_voice_as_w);
1465         
1466                 /* Catch the "key_press_event" signal in the window, so that we can catch
1467                 the ESC key being pressed and act as if the "Cancel" button had
1468         been selected. */
1469         dlg_set_cancel(user_data->dlg.save_voice_as_w, GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->cancel_button);
1470         
1471         gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
1472                 GTK_SIGNAL_FUNC(save_voice_as_ok_cb), user_data->dlg.save_voice_as_w);
1473         
1474         gtk_widget_show(user_data->dlg.save_voice_as_w);
1475 }
1476
1477
1478 /****************************************************************************/
1479 /* when we are finished with redisection, we add the label for the statistic */
1480 static void draw_stat(user_data_t *user_data)
1481 {
1482         gchar label_max[200];
1483         guint32 f_expected = (user_data->forward.statinfo.stop_seq_nr + user_data->forward.statinfo.cycles*65536)
1484                 - user_data->forward.statinfo.start_seq_nr + 1;
1485         guint32 r_expected = (user_data->reversed.statinfo.stop_seq_nr + user_data->reversed.statinfo.cycles*65536)
1486                 - user_data->reversed.statinfo.start_seq_nr + 1;
1487         gint32 f_lost = f_expected - user_data->forward.statinfo.total_nr;
1488         gint32 r_lost = r_expected - user_data->reversed.statinfo.total_nr;
1489
1490         g_snprintf(label_max, 199, "Max delay = %f sec at packet no. %u \n\n"
1491                 "Total RTP packets = %u   (expected %u)   Lost RTP packets = %d"
1492                 "   Sequence errors = %u",
1493                 user_data->forward.statinfo.max_delay, user_data->forward.statinfo.max_nr, user_data->forward.statinfo.total_nr,
1494                 f_expected, f_lost, user_data->forward.statinfo.sequence);
1495
1496         gtk_label_set_text(GTK_LABEL(user_data->dlg.label_stats_fwd), label_max);
1497
1498         g_snprintf(label_max, 199, "Max delay = %f sec at packet no. %u \n\n"
1499                 "Total RTP packets = %u   (expected %u)   Lost RTP packets = %d"
1500                 "   Sequence errors = %u",
1501                 user_data->reversed.statinfo.max_delay, user_data->reversed.statinfo.max_nr, user_data->reversed.statinfo.total_nr,
1502                 r_expected, r_lost, user_data->reversed.statinfo.sequence);
1503
1504         gtk_label_set_text(GTK_LABEL(user_data->dlg.label_stats_rev), label_max);
1505
1506         return ;
1507 }
1508
1509 /****************************************************************************/
1510 /* append a line to clist */
1511 static void add_to_clist(GtkCList *clist, guint32 number, guint16 seq_num,
1512                          double delay, double jitter, gchar *status, gboolean marker,
1513                          gchar *timeStr, guint32 pkt_len, GdkColor *color)
1514 {
1515         guint added_row;
1516         gchar *data[8];
1517         gchar field[8][32];
1518
1519         data[0]=&field[0][0];
1520         data[1]=&field[1][0];
1521         data[2]=&field[2][0];
1522         data[3]=&field[3][0];
1523         data[4]=&field[4][0];
1524         data[5]=&field[5][0];
1525         data[6]=&field[6][0];
1526         data[7]=&field[7][0];
1527
1528         g_snprintf(field[0], 20, "%u", number);
1529         g_snprintf(field[1], 20, "%u", seq_num);
1530         g_snprintf(field[2], 20, "%f", delay);
1531         g_snprintf(field[3], 20, "%f", jitter);
1532         g_snprintf(field[4], 20, "%s", marker? "SET" : "");
1533         g_snprintf(field[5], 40, "%s", status);
1534         g_snprintf(field[6], 32, "%s", timeStr);
1535         g_snprintf(field[7], 20, "%u", pkt_len);
1536
1537         added_row = gtk_clist_append(GTK_CLIST(clist), data);
1538         gtk_clist_set_row_data(GTK_CLIST(clist), added_row, GUINT_TO_POINTER(number));
1539         gtk_clist_set_background(GTK_CLIST(clist), added_row, color);
1540 }
1541
1542 /****************************************************************************/
1543 /* Create the dialog box with all widgets */
1544 void create_rtp_dialog(user_data_t* user_data)
1545 {
1546         GtkWidget *window = NULL;
1547         GtkWidget *clist_fwd;
1548         GtkWidget *clist_rev;
1549         GtkWidget *label_stats_fwd;
1550         GtkWidget *label_stats_rev;
1551         GtkWidget *notebook;
1552
1553         GtkWidget *main_vb, *page, *page_r, *label, *label1, *label2, *label3;
1554         GtkWidget *scrolled_window, *scrolled_window_r/*, *frame, *text, *label4, *page_help*/;
1555         GtkWidget *box4, *voice_bt, *refresh_bt, *goto_bt, *close_bt, *csv_bt, *next_bt;
1556 #ifdef USE_CONVERSATION_GRAPH
1557         GtkWidget *graph_bt;
1558 #endif
1559
1560         gchar *titles[8] =  {"Packet", "Sequence",  "Delay (s)", "Jitter (s)", "Marker", "Status", "Date", "Length"};
1561         gchar label_forward[150];
1562         gchar label_reverse[150];
1563
1564         gchar str_ip_src[16];
1565         gchar str_ip_dst[16];
1566         
1567
1568         window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1569         gtk_window_set_title (GTK_WINDOW (window), "Ethereal: RTP Stream Analysis");
1570         gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
1571         gtk_signal_connect(GTK_OBJECT(window), "destroy",
1572                 GTK_SIGNAL_FUNC(on_destroy), user_data);
1573
1574         /* Container for each row of widgets */
1575         main_vb = gtk_vbox_new(FALSE, 3);
1576         gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
1577         gtk_container_add(GTK_CONTAINER(window), main_vb);
1578         gtk_widget_show(main_vb);
1579
1580
1581         /* Notebooks... */
1582         strcpy(str_ip_src, ip_to_str((ip_addr_p)&user_data->ip_src_fwd));
1583         strcpy(str_ip_dst, ip_to_str((ip_addr_p)&user_data->ip_dst_fwd));
1584
1585         g_snprintf(label_forward, 149, 
1586                 "Analysing connection from  %s port %u  to  %s port %u   SSRC = %u\n", 
1587                 str_ip_src, user_data->port_src_fwd, str_ip_dst, user_data->port_dst_fwd, user_data->ssrc_fwd);
1588
1589         strcpy(str_ip_src, ip_to_str((ip_addr_p)&user_data->ip_src_rev));
1590         strcpy(str_ip_dst, ip_to_str((ip_addr_p)&user_data->ip_dst_rev));
1591
1592         g_snprintf(label_reverse, 149,
1593                 "Analysing connection from  %s port %u  to  %s port %u   SSRC = %u\n", 
1594                 str_ip_src, user_data->port_src_rev, str_ip_dst, user_data->port_dst_rev, user_data->ssrc_rev);
1595
1596         /* Start a notebook for flipping between sets of changes */
1597         notebook = gtk_notebook_new();
1598         gtk_container_add(GTK_CONTAINER(main_vb), notebook);
1599         gtk_object_set_data(GTK_OBJECT(window), "notebook", notebook);
1600         gtk_signal_connect(GTK_OBJECT (notebook), "switch_page",
1601                                           GTK_SIGNAL_FUNC (on_notebook_switch_page),
1602                                           user_data);
1603
1604         /* page for forward connection */
1605         page = gtk_vbox_new(FALSE, 5);
1606         gtk_container_set_border_width(GTK_CONTAINER(page), 20);
1607
1608         /* scrolled window */
1609         scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1610         gtk_widget_set_usize(scrolled_window, 600, 200);
1611         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), 
1612                 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1613
1614         /* direction label */
1615         label1 = gtk_label_new(label_forward);
1616         gtk_box_pack_start(GTK_BOX(page), label1, FALSE, FALSE, 0);
1617
1618         /* place for some statistics */
1619         label_stats_fwd = gtk_label_new("\n\n");
1620         gtk_box_pack_end(GTK_BOX(page), label_stats_fwd, FALSE, FALSE, 5);
1621
1622         /* clist for the information */
1623         clist_fwd = gtk_clist_new_with_titles(8, titles);
1624         gtk_widget_show(clist_fwd);
1625         gtk_container_add(GTK_CONTAINER(scrolled_window), clist_fwd);
1626         gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
1627         gtk_signal_connect(GTK_OBJECT (clist_fwd), "select_row",
1628                                           GTK_SIGNAL_FUNC (on_clist_select_row),
1629                                           user_data);
1630         /* Hide date and length column */
1631         gtk_clist_set_column_visibility(GTK_CLIST(clist_fwd), 6, FALSE);
1632         gtk_clist_set_column_visibility(GTK_CLIST(clist_fwd), 7, FALSE);
1633
1634         /* label */
1635         label = gtk_label_new("     Forward Direction     ");
1636         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
1637
1638         /* column width and justification */
1639         gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 0, 80);
1640         gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 1, 80);
1641         gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 2, 80);
1642         gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 3, 80);
1643         gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 4, 40);
1644         gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 0, GTK_JUSTIFY_CENTER);
1645         gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 1, GTK_JUSTIFY_CENTER);
1646         gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 2, GTK_JUSTIFY_CENTER);
1647         gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 3, GTK_JUSTIFY_CENTER);
1648         gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 4, GTK_JUSTIFY_CENTER);
1649         gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 5, GTK_JUSTIFY_CENTER);
1650
1651         /* same page for reversed connection */
1652         page_r = gtk_vbox_new(FALSE, 5);
1653         gtk_container_set_border_width(GTK_CONTAINER(page_r), 20);
1654         scrolled_window_r = gtk_scrolled_window_new(NULL, NULL);
1655         gtk_widget_set_usize(scrolled_window_r, 600, 200);
1656         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_r), 
1657                 GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
1658         label3 = gtk_label_new(label_reverse);
1659         gtk_box_pack_start(GTK_BOX(page_r), label3, FALSE, FALSE, 0);
1660         label_stats_rev = gtk_label_new("\n\n");
1661         gtk_box_pack_end(GTK_BOX(page_r), label_stats_rev, FALSE, FALSE, 5);
1662         clist_rev = gtk_clist_new_with_titles(8, titles);
1663         gtk_widget_show(clist_rev);
1664         gtk_clist_set_column_visibility(GTK_CLIST(clist_rev), 6, FALSE);
1665         gtk_clist_set_column_visibility(GTK_CLIST(clist_rev), 7, FALSE);
1666
1667         gtk_signal_connect(GTK_OBJECT (clist_rev), "select_row",
1668                                   GTK_SIGNAL_FUNC (on_clist_select_row),
1669                                   user_data);
1670
1671         gtk_container_add(GTK_CONTAINER(scrolled_window_r), clist_rev);
1672         gtk_box_pack_start(GTK_BOX(page_r), scrolled_window_r, TRUE, TRUE, 0);
1673         label2 = gtk_label_new("     Reversed Direction     ");
1674         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_r, label2);
1675
1676         gtk_clist_set_column_width(GTK_CLIST(clist_rev), 0, 80);
1677         gtk_clist_set_column_width(GTK_CLIST(clist_rev), 1, 80);
1678         gtk_clist_set_column_width(GTK_CLIST(clist_rev), 2, 80);
1679         gtk_clist_set_column_width(GTK_CLIST(clist_rev), 3, 80);
1680         gtk_clist_set_column_width(GTK_CLIST(clist_rev), 4, 40);
1681         gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 0, GTK_JUSTIFY_CENTER);
1682         gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 1, GTK_JUSTIFY_CENTER);
1683         gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 2, GTK_JUSTIFY_CENTER);
1684         gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 3, GTK_JUSTIFY_CENTER);
1685         gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 4, GTK_JUSTIFY_CENTER);
1686         gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 5, GTK_JUSTIFY_CENTER);
1687
1688         /* page for help&about or future
1689         page_help = gtk_hbox_new(FALSE, 5);
1690         label4 = gtk_label_new("     Future    ");
1691         gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_help, label4);
1692         frame = gtk_frame_new("");
1693         text = gtk_label_new("\n\nMaybe some more statistics: delay and jitter distribution,...");
1694         gtk_label_set_justify(GTK_LABEL(text), GTK_JUSTIFY_LEFT);
1695         gtk_container_add(GTK_CONTAINER(frame), text);
1696         gtk_container_set_border_width(GTK_CONTAINER(frame), 20);
1697         gtk_box_pack_start(GTK_BOX(page_help), frame, TRUE, TRUE, 0);
1698         */
1699
1700         /* show all notebooks */
1701         gtk_widget_show_all(notebook);
1702
1703         /* buttons */
1704         box4 = gtk_hbutton_box_new();
1705         gtk_box_pack_start(GTK_BOX(main_vb), box4, FALSE, FALSE, 0);
1706         gtk_container_set_border_width(GTK_CONTAINER(box4), 10);
1707         gtk_button_box_set_layout(GTK_BUTTON_BOX (box4), GTK_BUTTONBOX_EDGE);
1708         gtk_button_box_set_spacing(GTK_BUTTON_BOX (box4), 0);
1709         gtk_button_box_set_child_ipadding(GTK_BUTTON_BOX (box4), 4, 0);
1710         gtk_widget_show(box4);
1711
1712         voice_bt = gtk_button_new_with_label("Save payload...");
1713         gtk_container_add(GTK_CONTAINER(box4), voice_bt);
1714         gtk_widget_show(voice_bt);
1715         gtk_signal_connect(GTK_OBJECT(voice_bt), "clicked",
1716                 GTK_SIGNAL_FUNC(on_save_bt_clicked), user_data);
1717
1718         csv_bt = gtk_button_new_with_label("Save as CSV...");
1719         gtk_container_add(GTK_CONTAINER(box4), csv_bt);
1720         gtk_widget_show(csv_bt);
1721         gtk_signal_connect(GTK_OBJECT(csv_bt), "clicked",
1722                 GTK_SIGNAL_FUNC(save_csv_as_cb), user_data);
1723
1724         refresh_bt = gtk_button_new_with_label("Refresh");
1725         gtk_container_add(GTK_CONTAINER(box4), refresh_bt);
1726         gtk_widget_show(refresh_bt);
1727         gtk_signal_connect(GTK_OBJECT(refresh_bt), "clicked",
1728                 GTK_SIGNAL_FUNC(on_refresh_bt_clicked), user_data);
1729
1730         goto_bt = gtk_button_new_with_label("Go to frame");
1731         gtk_container_add(GTK_CONTAINER(box4), goto_bt);
1732         gtk_widget_show(goto_bt);
1733         gtk_signal_connect(GTK_OBJECT(goto_bt), "clicked",
1734                 GTK_SIGNAL_FUNC(on_goto_bt_clicked), user_data);
1735
1736 #ifdef USE_CONVERSATION_GRAPH
1737         graph_bt = gtk_button_new_with_label("Graph");
1738         gtk_container_add(GTK_CONTAINER(box4), graph_bt);
1739         gtk_widget_show(graph_bt);
1740         gtk_signal_connect(GTK_OBJECT(graph_bt), "clicked",
1741                 GTK_SIGNAL_FUNC(on_graph_bt_clicked), user_data);
1742 #endif
1743
1744         next_bt = gtk_button_new_with_label("Next");
1745         gtk_container_add(GTK_CONTAINER(box4), next_bt);
1746         gtk_widget_show(next_bt);
1747         gtk_signal_connect(GTK_OBJECT(next_bt), "clicked",
1748                 GTK_SIGNAL_FUNC(on_next_bt_clicked), user_data);
1749
1750         close_bt = gtk_button_new_with_label("Close");
1751         gtk_container_add(GTK_CONTAINER(box4), close_bt);
1752         gtk_widget_show(close_bt);
1753         gtk_signal_connect(GTK_OBJECT(close_bt), "clicked",
1754                 GTK_SIGNAL_FUNC(on_close_bt_clicked), user_data);
1755
1756         gtk_widget_show(window);
1757
1758         user_data->dlg.window = window;
1759         user_data->dlg.clist_fwd = GTK_CLIST(clist_fwd);
1760         user_data->dlg.clist_rev = GTK_CLIST(clist_rev);
1761         user_data->dlg.label_stats_fwd = label_stats_fwd;
1762         user_data->dlg.label_stats_rev = label_stats_rev;
1763         user_data->dlg.notebook = notebook;
1764         user_data->dlg.selected_clist = GTK_CLIST(clist_fwd);
1765         user_data->dlg.selected_row = 0;
1766 }
1767
1768
1769 /****************************************************************************/
1770 static gboolean process_node(proto_item *ptree_node, header_field_info *hfinformation,
1771                                                         const gchar* proto_field, guint32* p_result)
1772 {
1773         field_info            *finfo;
1774         proto_item            *proto_sibling_node;
1775         header_field_info     *hfssrc;
1776         ipv4_addr             *ipv4;
1777
1778         finfo = PITEM_FINFO(ptree_node);
1779
1780         if (hfinformation==(finfo->hfinfo)) {
1781                 hfssrc = proto_registrar_get_byname((gchar*) proto_field);
1782                 if (hfssrc == NULL)
1783                         return FALSE;
1784                 for(ptree_node=g_node_first_child(ptree_node); ptree_node!=NULL; 
1785                                         ptree_node=g_node_next_sibling(ptree_node)) {
1786                         finfo=PITEM_FINFO(ptree_node);
1787                         if (hfssrc==finfo->hfinfo) {
1788                                 if (hfinformation->type==FT_IPv4) {
1789                                         ipv4 = fvalue_get(finfo->value);
1790                                         *p_result = ipv4_get_net_order_addr(ipv4);
1791                                 }
1792                                 else {
1793                                         *p_result = fvalue_get_integer(finfo->value);
1794                                 }
1795                                 return TRUE;
1796                         }
1797                 }
1798         }
1799
1800         proto_sibling_node = g_node_next_sibling(ptree_node);
1801
1802         if (proto_sibling_node) {
1803                 return process_node(proto_sibling_node, hfinformation, proto_field, p_result);
1804         }
1805         else
1806         return FALSE;
1807 }
1808
1809 /****************************************************************************/
1810 static gboolean get_int_value_from_proto_tree(proto_tree *protocol_tree,
1811                                                                                          const gchar* proto_name,
1812                                                                                          const gchar* proto_field,
1813                                                                                          guint32* p_result)
1814 {
1815         proto_item      *ptree_node;
1816         header_field_info     *hfinformation;
1817
1818         hfinformation = proto_registrar_get_byname((gchar*) proto_name);
1819         if (hfinformation == NULL)
1820                 return FALSE;
1821
1822         ptree_node = g_node_first_child(protocol_tree);
1823         if (!ptree_node)
1824                 return FALSE;
1825
1826         return process_node(ptree_node, hfinformation, proto_field, p_result);
1827 }
1828
1829
1830 /****************************************************************************/
1831 /* XXX only handles RTP over IPv4, should add IPv6 support */
1832 void rtp_analysis(
1833                 guint32 ip_src_fwd,
1834                 guint16 port_src_fwd,
1835                 guint32 ip_dst_fwd,
1836                 guint16 port_dst_fwd,
1837                 guint32 ssrc_fwd,
1838                 guint32 ip_src_rev,
1839                 guint16 port_src_rev,
1840                 guint32 ip_dst_rev,
1841                 guint16 port_dst_rev,
1842                 guint32 ssrc_rev
1843                 )
1844 {
1845         user_data_t *user_data;
1846         gchar filter_text[256];
1847         dfilter_t *sfcode;
1848         GString *error_string;
1849
1850         user_data = g_malloc(sizeof(user_data_t));
1851
1852         user_data->ip_src_fwd = ip_src_fwd;
1853         user_data->port_src_fwd = port_src_fwd;
1854         user_data->ip_dst_fwd = ip_dst_fwd;
1855         user_data->port_dst_fwd = port_dst_fwd;
1856         user_data->ssrc_fwd = ssrc_fwd;
1857         user_data->ip_src_rev = ip_src_rev;
1858         user_data->port_src_rev = port_src_rev;
1859         user_data->ip_dst_rev = ip_dst_rev;
1860         user_data->port_dst_rev = port_dst_rev;
1861         user_data->ssrc_rev = ssrc_rev;
1862
1863         create_rtp_dialog(user_data);
1864
1865         /* Try to compile the filter. */
1866         strcpy(filter_text,"rtp && ip");
1867         if (!dfilter_compile(filter_text, &sfcode)) {
1868                 simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, dfilter_error_msg);
1869                 return;
1870         }
1871
1872         sprintf(filter_text,"rtp && ip && !icmp && (( ip.src==%s && udp.srcport==%u && ip.dst==%s && udp.dstport==%u ) || ( ip.src==%s && udp.srcport==%u && ip.dst==%s && udp.dstport==%u ))",
1873                 ip_to_str((ip_addr_p)&ip_src_fwd),
1874                 port_src_fwd,
1875                 ip_to_str((ip_addr_p)&ip_dst_fwd),
1876                 port_dst_fwd,
1877                 ip_to_str((ip_addr_p)&ip_src_rev),
1878                 port_src_rev,
1879                 ip_to_str((ip_addr_p)&ip_dst_rev),
1880                 port_dst_rev
1881                 );
1882
1883         error_string = register_tap_listener("rtp", user_data, filter_text,
1884                 (void*)rtp_reset, (void*)rtp_packet, (void*)rtp_draw);
1885         if (error_string != NULL) {
1886                 simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, error_string->str);
1887                         g_string_free(error_string, TRUE);
1888                 g_free(user_data);
1889                 return;
1890                 /*exit(1);*/
1891         }
1892
1893         /* file names for storing sound data */
1894         strncpy(user_data->f_tempname, "f_tempnameXXXXXX", TMPNAMSIZE);
1895         strncpy(user_data->r_tempname, "r_tempnameXXXXXX", TMPNAMSIZE);
1896         mkstemp(user_data->f_tempname);
1897         mkstemp(user_data->r_tempname);
1898         user_data->forward.saveinfo.fp = NULL;
1899         user_data->reversed.saveinfo.fp = NULL;
1900         user_data->dlg.save_voice_as_w = NULL;
1901         user_data->dlg.save_csv_as_w = NULL;
1902 #ifdef USE_CONVERSATION_GRAPH
1903         user_data->dlg.graph_window = NULL;
1904         user_data->series_fwd.value_pairs = NULL;
1905         user_data->series_rev.value_pairs = NULL;
1906 #endif
1907
1908         redissect_packets(&cfile);
1909
1910         draw_stat(user_data);
1911 }
1912
1913 /****************************************************************************/
1914 /* entry point from main menu */
1915 void rtp_analysis_cb(GtkWidget *w _U_, gpointer data _U_) 
1916 {
1917         guint32 ip_src_fwd;
1918         guint16 port_src_fwd;
1919         guint32 ip_dst_fwd;
1920         guint16 port_dst_fwd;
1921         guint32 ssrc_fwd = 0;
1922         guint32 ip_src_rev;
1923         guint16 port_src_rev;
1924         guint32 ip_dst_rev;
1925         guint16 port_dst_rev;
1926         guint32 ssrc_rev = 0;
1927
1928         gchar filter_text[256];
1929         dfilter_t *sfcode;
1930         capture_file *cf;
1931         epan_dissect_t *edt;
1932         gint err;
1933         gboolean frame_matched;
1934         frame_data *fdata;
1935         GList *strinfo_list;
1936         GList *filtered_list = NULL;
1937         rtp_stream_info_t *strinfo;
1938         guint nfound;
1939
1940         /* Try to compile the filter. */
1941         strcpy(filter_text,"rtp && ip");
1942         if (!dfilter_compile(filter_text, &sfcode)) {
1943                 simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, dfilter_error_msg);
1944                 return;
1945         }
1946         /* we load the current file into cf variable */
1947         cf = &cfile;
1948         fdata = cf->current_frame;
1949         
1950         /* we are on the selected frame now */
1951         if (fdata == NULL)
1952                 return; /* if we exit here it's an error */
1953
1954         /* dissect the current frame */
1955         if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err)) {
1956                 simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
1957                         file_read_error_message(err), cf->filename);
1958                 return;
1959         }
1960         edt = epan_dissect_new(TRUE, FALSE);
1961         epan_dissect_prime_dfilter(edt, sfcode);
1962         epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
1963         frame_matched = dfilter_apply_edt(sfcode, edt);
1964         
1965         /* if it is not an rtp frame, show the rtpstream dialog */
1966         frame_matched = dfilter_apply_edt(sfcode, edt);
1967         if (frame_matched != 1) {
1968                 rtpstream_dlg_show(rtpstream_get_info()->strinfo_list);
1969                 return;
1970 /*
1971                 epan_dissect_free(edt);
1972                 simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, "You didn't choose a RTP packet!");
1973                 return;
1974 */
1975         }
1976
1977         /* ok, it is a RTP frame, so let's get the ip and port values */
1978         g_memmove(&ip_src_fwd, edt->pi.src.data, 4);
1979         g_memmove(&ip_dst_fwd, edt->pi.dst.data, 4);
1980         port_src_fwd = edt->pi.srcport;
1981         port_dst_fwd = edt->pi.destport;
1982
1983         /* assume the inverse ip/port combination for the reverse direction */
1984         g_memmove(&ip_src_rev, edt->pi.dst.data, 4);
1985         g_memmove(&ip_dst_rev, edt->pi.src.data, 4);
1986         port_src_rev = edt->pi.destport;
1987         port_dst_rev = edt->pi.srcport;
1988         
1989         /* now we need the SSRC value of the current frame */
1990         if (!get_int_value_from_proto_tree(edt->tree, "rtp", "rtp.ssrc", &ssrc_fwd)) {
1991                 simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, "SSRC value couldn't be found!");
1992                 return;
1993         }
1994
1995         /* search for reversed direction in the global rtp streams list */
1996         nfound = 0;
1997         strinfo_list = g_list_first(rtpstream_get_info()->strinfo_list);
1998         while (strinfo_list)
1999         {
2000                 strinfo = (rtp_stream_info_t*)(strinfo_list->data);
2001                 if (strinfo->src_addr==ip_src_fwd
2002                         && strinfo->src_port==port_src_fwd
2003                         && strinfo->dest_addr==ip_dst_fwd
2004                         && strinfo->dest_port==port_dst_fwd)
2005                 {
2006                         filtered_list = g_list_prepend(filtered_list, strinfo);
2007                 }
2008
2009                 if (strinfo->src_addr==ip_src_rev
2010                         && strinfo->src_port==port_src_rev
2011                         && strinfo->dest_addr==ip_dst_rev
2012                         && strinfo->dest_port==port_dst_rev)
2013                 {
2014                         ++nfound;
2015                         filtered_list = g_list_append(filtered_list, strinfo);
2016                         if (ssrc_rev==0)
2017                                 ssrc_rev = strinfo->ssrc;
2018                 }
2019
2020                 strinfo_list = g_list_next(strinfo_list);
2021         }
2022
2023         /* if more than one reverse streams found, we let the user choose the right one */
2024         if (nfound>1) {
2025                 rtpstream_dlg_show(filtered_list);
2026                 return;
2027         }
2028         else {
2029                 rtp_analysis(
2030                         ip_src_fwd,
2031                         port_src_fwd,
2032                         ip_dst_fwd,
2033                         port_dst_fwd,
2034                         ssrc_fwd,
2035                         ip_src_rev,
2036                         port_src_rev,
2037                         ip_dst_rev,
2038                         port_dst_rev,
2039                         ssrc_rev
2040                         );
2041         }
2042 }
2043
2044 /****************************************************************************/
2045 static void
2046 rtp_analysis_init(char *dummy _U_)
2047 {
2048         rtp_analysis_cb(NULL, NULL);
2049 }
2050
2051 /****************************************************************************/
2052 void
2053 register_tap_listener_rtp_analysis(void)
2054 {
2055         register_ethereal_tap("rtp", rtp_analysis_init);
2056 }
2057
2058 void
2059 register_tap_menu_rtp_analysis(void)
2060 {
2061         register_tap_menu_item("Statistics/RTP Streams/Analyse...",
2062             rtp_analysis_cb, NULL, NULL);
2063 }