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