aboutsummaryrefslogtreecommitdiffstats
path: root/gtk
diff options
context:
space:
mode:
Diffstat (limited to 'gtk')
-rw-r--r--gtk/Makefile.am14
-rw-r--r--gtk/Makefile.nmake6
-rw-r--r--gtk/rtp_analysis.c1895
-rw-r--r--gtk/rtp_analysis.h50
-rw-r--r--gtk/rtp_stream.c407
-rw-r--r--gtk/rtp_stream.h140
-rw-r--r--gtk/rtp_stream_dlg.c806
-rw-r--r--gtk/rtp_stream_dlg.h45
-rw-r--r--gtk/tap_rtp.c1761
9 files changed, 3358 insertions, 1766 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 1935b851d6..c8cdd6fe00 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -1,7 +1,7 @@
# Makefile.am
# Automake file for the GTK interface routines for Ethereal
#
-# $Id: Makefile.am,v 1.69 2003/09/24 06:15:51 oabad Exp $
+# $Id: Makefile.am,v 1.70 2003/09/24 07:48:10 guy Exp $
#
# Ethereal - Network traffic analyzer
# By Gerald Combs <gerald@ethereal.com>
@@ -45,7 +45,9 @@ ETHEREAL_TAP_SRC = \
rpc_stat.c \
rpc_progs.c \
smb_stat.c \
- tap_rtp.c \
+ rtp_analysis.c \
+ rtp_stream.c \
+ rtp_stream_dlg.c \
wsp_stat.c
ethereal-tap-register.c: $(ETHEREAL_TAP_SRC) $(top_srcdir)/make-tapreg-dotc
@@ -122,9 +124,12 @@ libui_a_SOURCES = \
proto_draw.h \
proto_hier_stats_dlg.h \
proto_hier_stats_dlg.c \
- simple_dialog.c \
+ rtp_analysis.h \
+ rtp_stream.h \
+ rtp_stream_dlg.h \
service_response_time_table.c \
service_response_time_table.h \
+ simple_dialog.c \
stream_prefs.c \
stream_prefs.h \
summary_dlg.c \
@@ -205,6 +210,9 @@ libui_a_SOURCES = \
proto_draw.h \
proto_hier_stats_dlg.h \
proto_hier_stats_dlg.c \
+ rtp_analysis.h \
+ rtp_stream.h \
+ rtp_stream_dlg.h \
service_response_time_table.c \
service_response_time_table.h \
simple_dialog.c \
diff --git a/gtk/Makefile.nmake b/gtk/Makefile.nmake
index 28787f8081..878eabcefb 100644
--- a/gtk/Makefile.nmake
+++ b/gtk/Makefile.nmake
@@ -1,7 +1,7 @@
## Makefile for building ethereal.exe with Microsoft C and nmake
## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
#
-# $Id: Makefile.nmake,v 1.52 2003/09/10 05:35:25 guy Exp $
+# $Id: Makefile.nmake,v 1.53 2003/09/24 07:48:11 guy Exp $
include ..\config.nmake
@@ -37,7 +37,9 @@ ETHEREAL_TAP_SRC = \
rpc_stat.c \
rpc_progs.c \
smb_stat.c \
- tap_rtp.c \
+ rtp_analysis.c \
+ rtp_stream.c \
+ rtp_stream_dlg.c \
wsp_stat.c
ETHEREAL_TAP_OBJECTS = $(ETHEREAL_TAP_SRC:.c=.obj)
diff --git a/gtk/rtp_analysis.c b/gtk/rtp_analysis.c
new file mode 100644
index 0000000000..95f20db06a
--- /dev/null
+++ b/gtk/rtp_analysis.c
@@ -0,0 +1,1895 @@
+/* rtp_analysis.c
+ * RTP analysis addition for ethereal
+ *
+ * $Id: rtp_analysis.c,v 1.1 2003/09/24 07:48:11 guy Exp $
+ *
+ * Copyright 2003, Alcatel Business Systems
+ * By Lars Ruoff <lars.ruoff@gmx.net>
+ *
+ * based on tap_rtp.c
+ * Copyright 2003, Iskratel, Ltd, Kranj
+ * By Miha Jemec <m.jemec@iskratel.si>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*do not define this symbol. will be added soon*/
+/*#define USE_CONVERSATION_GRAPH 1*/
+
+#include "rtp_analysis.h"
+#include "rtp_stream.h"
+#include "rtp_stream_dlg.h"
+
+#ifdef USE_CONVERSATION_GRAPH
+#include "../graph/graph.h"
+#endif
+
+#include "epan/epan_dissect.h"
+#include "epan/filesystem.h"
+#include "tap.h"
+#include "register.h"
+#include "packet-rtp.h"
+#include "g711.h"
+
+/* in /gtk ... */
+#include "dlg_utils.h"
+#include "ui_util.h"
+#include "simple_dialog.h"
+#include "menu.h"
+#include "main.h"
+#include "progress_dlg.h"
+#include "compat_macros.h"
+
+#include <math.h>
+#include <fcntl.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_IO_H
+#include <io.h> /* open/close on win32 */
+#endif
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/****************************************************************************/
+
+typedef struct _dialog_data_t {
+ GtkWidget *window;
+ GtkWidget *clist_fwd;
+ GtkWidget *clist_rev;
+ GtkWidget *label_stats_fwd;
+ GtkWidget *label_stats_rev;
+ GtkWidget *notebook;
+ GtkCList *selected_clist;
+ GtkWidget *save_voice_as_w;
+ GtkWidget *save_csv_as_w;
+ gint selected_row;
+#ifdef USE_CONVERSATION_GRAPH
+ GtkWidget *graph_window;
+#endif
+} dialog_data_t;
+
+/* type of error when saving voice in a file didn't succeed */
+typedef enum {
+ TAP_RTP_WRONG_CODEC,
+ TAP_RTP_WRONG_LENGTH,
+ TAP_RTP_PADDING_ERROR,
+ TAP_RTP_FILE_OPEN_ERROR,
+ TAP_RTP_NO_DATA
+} error_type_t;
+
+typedef enum {
+ FIRST_PACKET,
+ MARK_SET,
+ NORMAL_PACKET
+} packet_type;
+
+/* structure that holds the information about the forward and reversed direction */
+struct _info_direction {
+ gboolean first_packet;
+ guint16 seq_num;
+ guint32 timestamp;
+ guint32 delta_timestamp;
+ double delay;
+ double jitter;
+ double time;
+ double start_time;
+ double max_delay;
+ guint32 max_nr;
+ guint16 start_seq_nr;
+ guint16 stop_seq_nr;
+ guint32 total_nr;
+ guint32 sequence;
+ gboolean under;
+ gint cycles;
+ FILE *fp;
+ guint32 count;
+ error_type_t error_type;
+ gboolean saved;
+};
+
+/* structure that holds general information about the connection
+* and structures for both directions */
+typedef struct _user_data_t {
+ /* tap associated data*/
+ guint32 ip_src_fwd;
+ guint16 port_src_fwd;
+ guint32 ip_dst_fwd;
+ guint16 port_dst_fwd;
+ guint32 ssrc_fwd;
+ guint32 ip_src_rev;
+ guint16 port_src_rev;
+ guint32 ip_dst_rev;
+ guint16 port_dst_rev;
+ guint32 ssrc_rev;
+
+ struct _info_direction forward;
+ struct _info_direction reversed;
+
+ char f_tempname[100];
+ char r_tempname[100];
+
+ /* dialog associated data */
+ dialog_data_t dlg;
+
+#ifdef USE_CONVERSATION_GRAPH
+ time_series_t series_fwd;
+ time_series_t series_rev;
+#endif
+} user_data_t;
+
+
+typedef const guint8 * ip_addr_p;
+
+
+/****************************************************************************/
+/* TAP FUNCTIONS */
+
+/****************************************************************************/
+/* when there is a [re]reading of packet's */
+static void
+rtp_reset(user_data_t *user_data _U_)
+{
+ user_data->forward.first_packet = TRUE;
+ user_data->reversed.first_packet = TRUE;
+ user_data->forward.max_delay = 0;
+ user_data->reversed.max_delay = 0;
+ user_data->forward.delay = 0;
+ user_data->reversed.delay = 0;
+ user_data->forward.jitter = 0;
+ user_data->reversed.jitter = 0;
+ user_data->forward.timestamp = 0;
+ user_data->reversed.timestamp = 0;
+ user_data->forward.max_nr = 0;
+ user_data->reversed.max_nr = 0;
+ user_data->forward.total_nr = 0;
+ user_data->reversed.total_nr = 0;
+ user_data->forward.sequence = 0;
+ user_data->reversed.sequence = 0;
+ user_data->forward.start_seq_nr = 0;
+ user_data->reversed.start_seq_nr = 1; /* 1 is ok (for statistics in reversed direction) */
+ user_data->forward.stop_seq_nr = 0;
+ user_data->reversed.stop_seq_nr = 0;
+ user_data->forward.cycles = 0;
+ user_data->reversed.cycles = 0;
+ user_data->forward.under = FALSE;
+ user_data->reversed.under = FALSE;
+ user_data->forward.saved = FALSE;
+ user_data->reversed.saved = FALSE;
+ user_data->forward.start_time = 0;
+ user_data->reversed.start_time = 0;
+ user_data->forward.time = 0;
+ user_data->reversed.time = 0;
+ user_data->forward.count = 0;
+ user_data->reversed.count = 0;
+
+#ifdef USE_CONVERSATION_GRAPH
+ if (user_data->dlg.graph_window != NULL)
+ gtk_widget_destroy(user_data->dlg.graph_window);
+
+ g_array_free(user_data->series_fwd.value_pairs, TRUE);
+ user_data->series_fwd.value_pairs = g_array_new(FALSE, FALSE, sizeof(value_pair_t));
+
+ g_array_free(user_data->series_rev.value_pairs, TRUE);
+ user_data->series_rev.value_pairs = g_array_new(FALSE, FALSE, sizeof(value_pair_t));
+#endif
+
+ /* XXX check for error at fclose? */
+ if (user_data->forward.fp != NULL)
+ fclose(user_data->forward.fp);
+ if (user_data->reversed.fp != NULL)
+ fclose(user_data->reversed.fp);
+ user_data->forward.fp = fopen(user_data->f_tempname, "wb");
+ if (user_data->forward.fp == NULL)
+ user_data->forward.error_type = TAP_RTP_FILE_OPEN_ERROR;
+ user_data->reversed.fp = fopen(user_data->r_tempname, "wb");
+ if (user_data->reversed.fp == NULL)
+ user_data->reversed.error_type = TAP_RTP_FILE_OPEN_ERROR;
+ return;
+}
+
+/****************************************************************************/
+/* here we can redraw the output */
+/* not used yet */
+static void rtp_draw(void *prs _U_)
+{
+ return;
+}
+
+static int do_calculation(GtkWidget *clist, packet_type pkt_type, void *ptrs, void *vpri, void *vpinfo);
+static void add_to_clist(GtkWidget *clist, guint32 number, guint16 seq_num,
+ double delay, double jitter, gboolean status, gboolean marker,
+ gchar *timeStr, guint32 pkt_len);
+
+/****************************************************************************/
+/* whenever a RTP packet is seen by the tap listener */
+/* this function works as follows:
+* 1) packets that are not displayed are ignored
+* return
+* 3) if not, is current packet matching the forward direction
+* if yes, call the function that does the calculation and saves the voice info
+* 4) if not, is current packet matching the reversed connection
+* if yes, call the function that does the calculation and saves the voice info
+*/
+static int rtp_packet(user_data_t *user_data, packet_info *pinfo, epan_dissect_t *edt _U_, struct _rtp_info *rtpinfo)
+{
+#ifdef USE_CONVERSATION_GRAPH
+ value_pair_t vp;
+#endif
+
+ /* we ignore packets that are not displayed */
+ if (pinfo->fd->flags.passed_dfilter == 0)
+ return 0;
+
+ /* is it the forward direction? */
+ else if (user_data->ssrc_fwd == rtpinfo->info_sync_src) {
+#ifdef USE_CONVERSATION_GRAPH
+ vp.time = ((double)pinfo->fd->rel_secs + (double)pinfo->fd->rel_usecs/1000000);
+ vp.fnumber = pinfo->fd->num;
+ g_array_append_val(user_data->series_fwd.value_pairs, vp);
+#endif
+
+ if (user_data->forward.first_packet != FALSE)
+ /* first argument is the direction TRUE == forward */
+ return do_calculation(user_data->dlg.clist_fwd, FIRST_PACKET, &user_data->forward, rtpinfo, pinfo);
+ else if (rtpinfo->info_marker_set != FALSE)
+ return do_calculation(user_data->dlg.clist_fwd, MARK_SET, &user_data->forward, rtpinfo, pinfo);
+ else
+ return do_calculation(user_data->dlg.clist_fwd, NORMAL_PACKET, &user_data->forward, rtpinfo, pinfo);
+ }
+ /* is it the reversed direction? */
+ else if (user_data->ssrc_rev == rtpinfo->info_sync_src) {
+#ifdef USE_CONVERSATION_GRAPH
+ vp.time = ((double)pinfo->fd->rel_secs + (double)pinfo->fd->rel_usecs/1000000);
+ vp.fnumber = pinfo->fd->num;
+ g_array_append_val(user_data->series_rev.value_pairs, vp);
+#endif
+
+ if (user_data->reversed.first_packet != FALSE)
+ return do_calculation(user_data->dlg.clist_rev, FIRST_PACKET, &user_data->reversed, rtpinfo, pinfo);
+ else if (rtpinfo->info_marker_set != FALSE)
+ return do_calculation(user_data->dlg.clist_rev, MARK_SET, &user_data->reversed, rtpinfo, pinfo);
+ else
+ return do_calculation(user_data->dlg.clist_rev, NORMAL_PACKET, &user_data->reversed, rtpinfo, pinfo);
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************/
+static int do_calculation(GtkWidget *clist, packet_type pkt_type, void *ptrs, void *vpri, void *vpinfo)
+{
+ struct _info_direction *ptr=ptrs;
+ struct _rtp_info *pri=vpri;
+ packet_info *pinfo = vpinfo;
+ guint i;
+ double current_time;
+ double current_jitter;
+ guint8 *data;
+ gint16 tmp;
+
+ guint16 msecs;
+ gchar timeStr[32];
+
+ struct tm *tm_tmp;
+ time_t then;
+
+ then = pinfo->fd->abs_secs;
+ msecs = (guint16)(pinfo->fd->abs_usecs/1000);
+
+ tm_tmp = localtime(&then);
+ snprintf(timeStr,32,"%02d/%02d/%04d %02d:%02d:%02d.%03d",
+ tm_tmp->tm_mon + 1,
+ tm_tmp->tm_mday,
+ tm_tmp->tm_year + 1900,
+ tm_tmp->tm_hour,
+ tm_tmp->tm_min,
+ tm_tmp->tm_sec,
+ msecs);
+
+ /* store the current time and calculate the current jitter */
+ current_time = (double)pinfo->fd->rel_secs + (double) pinfo->fd->rel_usecs/1000000;
+ current_jitter = ptr->jitter + ( fabs (current_time - (ptr->time) -
+ ((double)(pri->info_timestamp)-(double)(ptr->timestamp))/8000)- ptr->jitter)/16;
+ ptr->delay = current_time-(ptr->time);
+
+ /* We have 3 possibilities:
+ * is this the first packet we got in this direction? */
+ if (pkt_type == FIRST_PACKET) {
+ ptr->first_packet = FALSE;
+ ptr->start_seq_nr = pri->info_seq_num;
+ ptr->start_time = current_time;
+ add_to_clist(clist,
+ pinfo->fd->num, pri->info_seq_num, 0,
+ pri->info_marker_set? TRUE: FALSE, TRUE, FALSE,
+ timeStr, pinfo->fd->pkt_len);
+ if (ptr->fp == NULL) {
+ ptr->saved = FALSE;
+ ptr->error_type = TAP_RTP_FILE_OPEN_ERROR;
+ }
+ else
+ ptr->saved = TRUE;
+ }
+ /* or is it a packet with the mark bit set? */
+ else if (pkt_type == MARK_SET) {
+ ptr->delta_timestamp = pri->info_timestamp - ptr->timestamp;
+ add_to_clist(clist,
+ pinfo->fd->num, pri->info_seq_num, current_time - (ptr->time),
+ current_jitter, ptr->seq_num+1 == pri->info_seq_num? TRUE: FALSE, TRUE,
+ timeStr, pinfo->fd->pkt_len);
+ }
+ /* if neither then it is a "normal" packet pkt_type == NORMAL_PACKET */
+ else {
+ if (ptr->delay > ptr->max_delay) {
+ ptr->max_delay = ptr->delay;
+ ptr->max_nr = pinfo->fd->num;
+ }
+ add_to_clist(clist,
+ pinfo->fd->num, pri->info_seq_num, current_time -(ptr->time),
+ current_jitter , ptr->seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE,
+ timeStr, pinfo->fd->pkt_len);
+ }
+
+ /* When calculating expected rtp packets the seq number can wrap around
+ * so we have to count the number of cycles
+ * Variable cycles counts the wraps around in forwarding connection and
+ * under is flag that indicates where we are
+ *
+ * XXX how to determine number of cycles with all possible lost, late
+ * and duplicated packets without any doubt? It seems to me, that
+ * because of all possible combination of late, duplicated or lost
+ * packets, this can only be more or less good approximation
+ *
+ * There are some combinations (rare but theoretically possible),
+ * where below code won't work correctly - statistic may be wrong then.
+ */
+
+ /* so if the current sequence number is less than the start one
+ * we assume, that there is another cycle running */
+ if ((pri->info_seq_num < ptr->start_seq_nr) && (ptr->under == FALSE)){
+ ptr->cycles++;
+ ptr->under = TRUE;
+ }
+ /* what if the start seq nr was 0? Then the above condition will never
+ * be true, so we add another condition. XXX The problem would arise
+ * if one of the packets with seq nr 0 or 65535 would be lost or late */
+ else if ((pri->info_seq_num == 0) && (ptr->stop_seq_nr == 65535) &&
+ (ptr->under == FALSE)){
+ ptr->cycles++;
+ ptr->under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num > ptr->start_seq_nr) && (ptr->under != FALSE)) {
+ ptr->under = FALSE;
+ }
+
+ /* Since it is difficult to count lost, duplicate or late packets separately,
+ * we would like to know at least how many times the sequence number was not ok */
+
+ /* if the current seq number equals the last one or if we are here for
+ * the first time, then it is ok, we just store the current one as the last one */
+ if ( ( ptr->seq_num+1 == pri->info_seq_num) || (pkt_type == FIRST_PACKET) )
+ ptr->seq_num = pri->info_seq_num;
+ /* if the first one is 65535. XXX same problem as above: if seq 65535 or 0 is lost... */
+ else if ( (ptr->seq_num == 65535) && (pri->info_seq_num == 0) )
+ ptr->seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (ptr->seq_num+1 < pri->info_seq_num) {
+ ptr->seq_num = pri->info_seq_num;
+ ptr->sequence++;
+ }
+ /* late or duplicated */
+ else if (ptr->seq_num+1 > pri->info_seq_num)
+ ptr->sequence++;
+
+ ptr->time = current_time;
+ ptr->timestamp = pri->info_timestamp;
+ ptr->stop_seq_nr = pri->info_seq_num;
+ ptr->total_nr++;
+
+ /* save the voice information */
+ /* if there was already an error, we quit */
+ if (ptr->saved == FALSE)
+ return 0;
+
+ /* if the captured length and packet length aren't equal, we quit
+ * because there is some information missing */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ ptr->saved = FALSE;
+ ptr->error_type = TAP_RTP_WRONG_LENGTH;
+ return 0;
+ }
+
+ /* if padding bit is set, but the padding count is bigger
+ * then the whole RTP data - error with padding count */
+ if ( (pri->info_padding_set != FALSE) &&
+ (pri->info_padding_count > pri->info_payload_len) ) {
+ ptr->saved = FALSE;
+ ptr->error_type = TAP_RTP_PADDING_ERROR;
+ return 0;
+ }
+
+ /* do we need to insert some silence? */
+ if ((pkt_type == MARK_SET) &&
+ (ptr->delta_timestamp > (pri->info_payload_len - pri->info_padding_count)) ) {
+ /* the amount of silence should be the difference between
+ * the last timestamp and the current one minus x
+ * x should equal the amount of information in the last frame
+ * XXX not done yet */
+ for(i=0; i < (ptr->delta_timestamp - pri->info_payload_len -
+ pri->info_padding_count); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, ptr->fp);
+ ptr->count++;
+ }
+ fflush(ptr->fp);
+ }
+
+ /* ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* we put the pointer at the beggining of the RTP data, that is
+ * at the end of the current frame minus the length of the
+ * padding count minus length of the RTP data */
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_payload_len);
+ for(i=0; i < (pri->info_payload_len - pri->info_padding_count); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, ptr->fp);
+ ptr->count++;
+ }
+ fflush(ptr->fp);
+ ptr->saved = TRUE;
+ return 0;
+ }
+
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_payload_len);
+ for(i=0; i < (pri->info_payload_len - pri->info_padding_count); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, ptr->fp);
+ ptr->count++;
+ }
+ fflush(ptr->fp);
+ ptr->saved = TRUE;
+ return 0;
+ }
+
+ /* unsupported codec or XXX other error */
+ else {
+ ptr->saved = FALSE;
+ ptr->error_type = TAP_RTP_WRONG_CODEC;
+ return 0;
+ }
+ return 0;
+}
+
+
+/****************************************************************************/
+/* CALLBACKS */
+
+/****************************************************************************/
+/* XXX just copied from gtk/rpc_stat.c */
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
+
+
+/****************************************************************************/
+/* close the dialog window and remove the tap listener */
+static void on_destroy(GtkWidget *win _U_, user_data_t *user_data _U_)
+{
+ protect_thread_critical_region();
+ remove_tap_listener(user_data);
+ unprotect_thread_critical_region();
+
+ if (user_data->forward.fp != NULL)
+ fclose(user_data->forward.fp);
+ if (user_data->reversed.fp != NULL)
+ fclose(user_data->reversed.fp);
+ remove(user_data->f_tempname);
+ remove(user_data->r_tempname);
+
+ /* Is there a save voice window open? */
+ if (user_data->dlg.save_voice_as_w != NULL)
+ gtk_widget_destroy(user_data->dlg.save_voice_as_w);
+
+#ifdef USE_CONVERSATION_GRAPH
+ /* Is there a graph window open? */
+ if (user_data->dlg.graph_window != NULL)
+ gtk_widget_destroy(user_data->dlg.graph_window);
+#endif
+
+ g_free(user_data);
+}
+
+
+/****************************************************************************/
+static void on_clist_select_row(GtkCList *clist _U_,
+ gint row _U_,
+ gint column _U_,
+ GdkEvent *event _U_,
+ user_data_t *user_data _U_)
+{
+ user_data->dlg.selected_clist = clist;
+ user_data->dlg.selected_row = row;
+}
+
+
+#ifdef USE_CONVERSATION_GRAPH
+/****************************************************************************/
+/* when the graph window gets destroyed */
+static void on_destroy_graph(GtkWidget *win _U_, user_data_t *user_data _U_)
+{
+ /* note that graph window has been destroyed */
+ user_data->dlg.graph_window = NULL;
+}
+
+/****************************************************************************/
+static void graph_selection_callback(value_pair_t vp, user_data_t *user_data)
+{
+ guint row;
+ GtkCList *clist = NULL;
+ if (vp.fnumber != 0) {
+ clist = GTK_CLIST(user_data->dlg.clist_fwd);
+ row = gtk_clist_find_row_from_data(clist,
+ GUINT_TO_POINTER(vp.fnumber));
+ if (row==-1) {
+ clist = GTK_CLIST(user_data->dlg.clist_rev);
+ row = gtk_clist_find_row_from_data(clist,
+ GUINT_TO_POINTER(vp.fnumber));
+ }
+ if (row!=-1) {
+ gtk_notebook_set_page(GTK_NOTEBOOK(user_data->dlg.notebook),
+ (clist == GTK_CLIST(user_data->dlg.clist_fwd)) ? 0 : 1);
+ gtk_clist_select_row(clist, row, 0);
+ gtk_clist_moveto(clist, row, 0, 0.5, 0);
+ }
+ }
+}
+
+
+/****************************************************************************/
+static void on_graph_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
+{
+ gchar title1[80];
+ gchar title2[80];
+ GList *list = NULL;
+
+ if (user_data->dlg.graph_window != NULL) {
+ /* There's already a graph window; reactivate it. */
+ reactivate_window(user_data->dlg.graph_window);
+ return;
+ }
+
+ list = g_list_append(list, &(user_data->series_fwd));
+ list = g_list_append(list, &(user_data->series_rev));
+
+ user_data->series_fwd.color.pixel = 0;
+ user_data->series_fwd.color.red = 0x80ff;
+ user_data->series_fwd.color.green = 0xe0ff;
+ user_data->series_fwd.color.blue = 0xffff;
+ user_data->series_fwd.yvalue = 0.5;
+
+ user_data->series_rev.color.pixel = 0;
+ user_data->series_rev.color.red = 0x60ff;
+ user_data->series_rev.color.green = 0xc0ff;
+ user_data->series_rev.color.blue = 0xffff;
+ user_data->series_rev.yvalue = -0.5;
+
+ g_snprintf(title1, 80, "Forward: %s:%u to %s:%u (SSRC=%u)",
+ ip_to_str((ip_addr_p)&(user_data->ip_src_fwd)),
+ user_data->port_src_fwd,
+ ip_to_str((ip_addr_p)&(user_data->ip_dst_fwd)),
+ user_data->port_dst_fwd,
+ user_data->ssrc_fwd);
+
+ g_snprintf(title2, 80, "Reverse: %s:%u to %s:%u (SSRC=%u)",
+ ip_to_str((ip_addr_p)&(user_data->ip_src_rev)),
+ user_data->port_src_rev,
+ ip_to_str((ip_addr_p)&(user_data->ip_dst_rev)),
+ user_data->port_dst_rev,
+ user_data->ssrc_rev);
+
+ user_data->dlg.graph_window = show_conversation_graph(list, title1, title2,
+ &graph_selection_callback, user_data);
+ gtk_signal_connect(GTK_OBJECT(user_data->dlg.graph_window), "destroy",
+ GTK_SIGNAL_FUNC(on_destroy_graph), user_data);
+}
+#endif /*USE_CONVERSATION_GRAPH*/
+
+
+/****************************************************************************/
+static void on_goto_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
+{
+ guint fnumber;
+
+ if (user_data->dlg.selected_clist!=NULL) {
+ fnumber = GPOINTER_TO_UINT(gtk_clist_get_row_data(
+ GTK_CLIST(user_data->dlg.selected_clist), user_data->dlg.selected_row) );
+ goto_frame(&cfile, fnumber);
+ }
+}
+
+
+static void draw_stat(user_data_t *user_data);
+
+/****************************************************************************/
+/* re-dissects all packets */
+static void on_refresh_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
+{
+ gtk_clist_clear(GTK_CLIST(user_data->dlg.clist_fwd));
+ gtk_clist_clear(GTK_CLIST(user_data->dlg.clist_rev));
+ redissect_packets(&cfile);
+ draw_stat(user_data);
+}
+
+/****************************************************************************/
+/* on_destroy is automatically called after that */
+static void on_close_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
+{
+ gtk_grab_remove(GTK_WIDGET(user_data->dlg.window));
+ gtk_widget_destroy(GTK_WIDGET(user_data->dlg.window));
+}
+
+
+/****************************************************************************/
+/* when we want to save the information */
+static void save_csv_as_ok_cb(GtkWidget *bt _U_, gpointer fs /*user_data_t *user_data*/ _U_)
+{
+ gchar *g_dest;
+ GtkWidget *rev, *forw, *both;
+ user_data_t *user_data;
+
+ FILE *fp;
+ char *columnText;
+ int i,j;
+
+ g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
+
+ /* Perhaps the user specified a directory instead of a file.
+ Check whether they did. */
+ if (test_for_directory(g_dest) == EISDIR) {
+ /* It's a directory - set the file selection box to display it. */
+ set_last_open_dir(g_dest);
+ g_free(g_dest);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
+ return;
+ }
+
+ rev = (GtkWidget*)OBJECT_GET_DATA(bt, "reversed_rb");
+ forw = (GtkWidget*)OBJECT_GET_DATA(bt, "forward_rb");
+ both = (GtkWidget*)OBJECT_GET_DATA(bt, "both_rb");
+ user_data = (user_data_t*)OBJECT_GET_DATA(bt, "user_data");
+
+ if (GTK_TOGGLE_BUTTON(forw)->active || GTK_TOGGLE_BUTTON(both)->active) {
+ fp = fopen(g_dest, "w");
+
+ if (GTK_TOGGLE_BUTTON(both)->active) {
+ fprintf(fp, "Forward\n");
+ }
+
+ for(j = 0; j < GTK_CLIST(user_data->dlg.clist_fwd)->columns; j++) {
+ if (j == 0) {
+ fprintf(fp,"%s",GTK_CLIST(user_data->dlg.clist_fwd)->column[j].title);
+ } else {
+ fprintf(fp,",%s",GTK_CLIST(user_data->dlg.clist_fwd)->column[j].title);
+ }
+ }
+ fprintf(fp,"\n");
+ for (i = 0; i < GTK_CLIST(user_data->dlg.clist_fwd)->rows; i++) {
+ for(j = 0; j < GTK_CLIST(user_data->dlg.clist_fwd)->columns; j++) {
+ gtk_clist_get_text(GTK_CLIST(user_data->dlg.clist_fwd),i,j,&columnText);
+ if (j == 0) {
+ fprintf(fp,"%s",columnText);
+ } else {
+ fprintf(fp,",%s",columnText);
+ }
+ }
+ fprintf(fp,"\n");
+ }
+
+ fclose(fp);
+ }
+
+ if (GTK_TOGGLE_BUTTON(rev)->active || GTK_TOGGLE_BUTTON(both)->active) {
+
+ if (GTK_TOGGLE_BUTTON(both)->active) {
+ fp = fopen(g_dest, "a");
+ fprintf(fp, "\nReverse\n");
+ } else {
+ fp = fopen(g_dest, "w");
+ }
+ for(j = 0; j < GTK_CLIST(user_data->dlg.clist_rev)->columns; j++) {
+ if (j == 0) {
+ fprintf(fp,"%s",GTK_CLIST(user_data->dlg.clist_rev)->column[j].title);
+ } else {
+ fprintf(fp,",%s",GTK_CLIST(user_data->dlg.clist_rev)->column[j].title);
+ }
+ }
+ fprintf(fp,"\n");
+ for (i = 0; i < GTK_CLIST(user_data->dlg.clist_rev)->rows; i++) {
+ for(j = 0; j < GTK_CLIST(user_data->dlg.clist_rev)->columns; j++) {
+ gtk_clist_get_text(GTK_CLIST(user_data->dlg.clist_rev),i,j,&columnText);
+ if (j == 0) {
+ fprintf(fp,"%s",columnText);
+ } else {
+ fprintf(fp,",%s",columnText);
+ }
+ }
+ fprintf(fp,"\n");
+ }
+ fclose(fp);
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(user_data->dlg.save_csv_as_w));
+}
+
+static void save_csv_as_destroy_cb(GtkWidget *win _U_, user_data_t *user_data _U_)
+{
+ user_data->dlg.save_csv_as_w = NULL;
+}
+
+/* when the user wants to save the csv information in a file */
+static void save_csv_as_cb(GtkWidget *bt _U_, user_data_t *user_data _U_)
+{
+ GtkWidget *vertb;
+ GtkWidget *table1;
+ GtkWidget *label_format;
+ GtkWidget *channels_label;
+ GSList *channels_group = NULL;
+ GtkWidget *forward_rb;
+ GtkWidget *reversed_rb;
+ GtkWidget *both_rb;
+ GtkWidget *ok_bt;
+
+ if (user_data->dlg.save_csv_as_w != NULL) {
+ /* There's already a Save CSV info dialog box; reactivate it. */
+ reactivate_window(user_data->dlg.save_csv_as_w);
+ return;
+ }
+
+ user_data->dlg.save_csv_as_w = gtk_file_selection_new("Ethereal: Save Data As CSV");
+ gtk_signal_connect(GTK_OBJECT(user_data->dlg.save_csv_as_w), "destroy",
+ GTK_SIGNAL_FUNC(save_csv_as_destroy_cb), user_data);
+
+ /* Container for each row of widgets */
+ vertb = gtk_vbox_new(FALSE, 0);
+ gtk_container_border_width(GTK_CONTAINER(vertb), 5);
+ gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->action_area),
+ vertb, FALSE, FALSE, 0);
+ gtk_widget_show (vertb);
+
+ table1 = gtk_table_new (2, 4, FALSE);
+ gtk_widget_show (table1);
+ gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
+ gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
+
+ label_format = gtk_label_new ("Format: Comma Separated Values");
+ gtk_widget_show (label_format);
+ gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+
+ channels_label = gtk_label_new ("Channels:");
+ gtk_widget_show (channels_label);
+ gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
+
+ forward_rb = gtk_radio_button_new_with_label (channels_group, "forward ");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
+ gtk_widget_show (forward_rb);
+ gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
+ gtk_widget_show (reversed_rb);
+ gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ both_rb = gtk_radio_button_new_with_label (channels_group, "both");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
+ gtk_widget_show (both_rb);
+ gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
+
+ ok_bt = GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->ok_button;
+ OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
+ OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
+ OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
+ OBJECT_SET_DATA(ok_bt, "user_data", user_data);
+
+ /* Connect the cancel_button to destroy the widget */
+ SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->cancel_button,
+ "clicked", (GtkSignalFunc)gtk_widget_destroy,
+ user_data->dlg.save_csv_as_w);
+
+ /* Catch the "key_press_event" signal in the window, so that we can catch
+ the ESC key being pressed and act as if the "Cancel" button had
+ been selected. */
+ dlg_set_cancel(user_data->dlg.save_csv_as_w, GTK_FILE_SELECTION(user_data->dlg.save_csv_as_w)->cancel_button);
+
+ gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+ GTK_SIGNAL_FUNC(save_csv_as_ok_cb), user_data->dlg.save_csv_as_w);
+
+ gtk_widget_show(user_data->dlg.save_csv_as_w);
+}
+
+
+/****************************************************************************/
+static void save_voice_as_destroy_cb(GtkWidget *win _U_, user_data_t *user_data _U_)
+{
+ /* Note that we no longer have a Save voice info dialog box. */
+ user_data->dlg.save_voice_as_w = NULL;
+}
+
+/****************************************************************************/
+/* here we save it into a file that user specified */
+/* XXX what about endians here? could go something wrong? */
+static gboolean copy_file(gchar *dest, gint channels, /*gint format,*/ user_data_t *user_data)
+{
+ int to_fd, forw_fd, rev_fd, fread = 0, rread = 0, fwritten, rwritten;
+ gint16 f_pd;
+ gint16 r_pd;
+ gchar pd[1];
+ guint32 f_write_silence = 0;
+ guint32 r_write_silence = 0;
+ progdlg_t *progbar;
+ guint32 progbar_count, progbar_quantum, progbar_nextstep = 0, count = 0;
+ gboolean stop_flag = FALSE;
+
+ forw_fd = open(user_data->f_tempname, O_RDONLY | O_BINARY);
+ if (forw_fd < 0)
+ return FALSE;
+ rev_fd = open(user_data->r_tempname, O_RDONLY | O_BINARY);
+ if (rev_fd < 0) {
+ close(forw_fd);
+ return FALSE;
+ }
+
+ /* open file for saving */
+ to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ if (to_fd < 0) {
+ close(forw_fd);
+ close(rev_fd);
+ return FALSE;
+ }
+
+ progbar = create_progress_dlg("Saving voice in a file", dest, "Stop", &stop_flag);
+
+ /* First we write the .au header. XXX Hope this is endian independant */
+ /* the magic word 0x2e736e64 == .snd */
+ *pd = (unsigned char)0x2e; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x73; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x6e; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x64; write(to_fd, pd, 1);
+ /* header offset == 24 bytes */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x18; write(to_fd, pd, 1);
+ /* total length, it is permited to set this to 0xffffffff */
+ *pd = (unsigned char)0xff; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ /* encoding format == 8 bit ulaw */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x01; write(to_fd, pd, 1);
+ /* sample rate == 8000 Hz */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x1f; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x40; write(to_fd, pd, 1);
+ /* channels == 1 */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x01; write(to_fd, pd, 1);
+
+ switch (channels) {
+ /* only forward direction */
+ case 1: {
+ progbar_count = user_data->forward.count;
+ progbar_quantum = user_data->forward.count/100;
+ while ((fread = read(forw_fd, &f_pd, 2)) > 0) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ *pd = (unsigned char)linear2ulaw(f_pd);
+ fwritten = write(to_fd, pd, 1);
+ if ((fwritten*2 < fread) || (fwritten < 0) || (fread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ /* only reversed direction */
+ case 2: {
+ progbar_count = user_data->reversed.count;
+ progbar_quantum = user_data->reversed.count/100;
+ while ((rread = read(rev_fd, &r_pd, 2)) > 0) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ *pd = (unsigned char)linear2ulaw(r_pd);
+ rwritten = write(to_fd, pd, 1);
+ if ((rwritten*2 < rread) || (rwritten < 0) || (rread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ /* both directions */
+ default: {
+ (user_data->forward.count > user_data->reversed.count) ?
+ (progbar_count = user_data->forward.count) :
+ (progbar_count = user_data->reversed.count);
+ progbar_quantum = progbar_count/100;
+ /* since conversation in one way can start later than in the other one,
+ * we have to write some silence information for one channel */
+ if (user_data->forward.start_time > user_data->reversed.start_time) {
+ f_write_silence =
+ (user_data->forward.start_time-user_data->reversed.start_time)*8000;
+ }
+ else if (user_data->forward.start_time < user_data->reversed.start_time) {
+ r_write_silence =
+ (user_data->reversed.start_time-user_data->forward.start_time)*8000;
+ }
+ for(;;) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ if(f_write_silence > 0) {
+ rread = read(rev_fd, &r_pd, 2);
+ f_pd = 0;
+ fread = 1;
+ f_write_silence--;
+ }
+ else if(r_write_silence > 0) {
+ fread = read(forw_fd, &f_pd, 2);
+ r_pd = 0;
+ rread = 1;
+ r_write_silence--;
+ }
+ else {
+ fread = read(forw_fd, &f_pd, 2);
+ rread = read(rev_fd, &r_pd, 2);
+ }
+ if ((rread == 0) && (fread == 0))
+ break;
+ *pd = (unsigned char)linear2ulaw( (f_pd + r_pd)/2 );
+ rwritten = write(to_fd, pd, 1);
+ if ((rwritten < 0) || (rread < 0) || (fread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ }
+ }
+ destroy_progress_dlg(progbar);
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ return TRUE;
+}
+
+
+/****************************************************************************/
+/* the user wants to save in a file */
+/* XXX support for different formats is currently commented out */
+static void save_voice_as_ok_cb(GtkWidget *ok_bt _U_, gpointer fs _U_)
+{
+ gchar *g_dest;
+ /*GtkWidget *wav, *au, *sw;*/
+ GtkWidget *rev, *forw, *both;
+ user_data_t *user_data;
+ gint channels /*, format*/;
+
+ g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
+
+ /* Perhaps the user specified a directory instead of a file.
+ Check whether they did. */
+ if (test_for_directory(g_dest) == EISDIR) {
+ /* It's a directory - set the file selection box to display it. */
+ set_last_open_dir(g_dest);
+ g_free(g_dest);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
+ return;
+ }
+
+ /*wav = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "wav_rb");
+ au = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "au_rb");
+ sw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "sw_rb");*/
+ rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");
+ forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");
+ both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");
+ user_data = (user_data_t *)OBJECT_GET_DATA(ok_bt, "user_data");
+
+ /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.
+ * we don't support that codec. So we pop up a warning. Maybe it would be better to
+ * disable the ok button or disable the buttons for direction if only one is not ok. The
+ * problem is if we open the save voice dialog and then click the refresh button and maybe
+ * the state changes, so we can't save anymore. In this case we should be able to update
+ * the buttons. For now it is easier if we put the warning when the ok button is pressed.
+ */
+
+ /* we can not save in both dirctions */
+ if ((user_data->forward.saved == FALSE) && (user_data->reversed.saved == FALSE) && (GTK_TOGGLE_BUTTON (both)->active)) {
+ /* there are many combinations here, we just exit when first matches */
+ if ((user_data->forward.error_type == TAP_RTP_WRONG_CODEC) ||
+ (user_data->reversed.error_type == TAP_RTP_WRONG_CODEC))
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save in a file: Unsupported codec!");
+ else if ((user_data->forward.error_type == TAP_RTP_WRONG_LENGTH) ||
+ (user_data->reversed.error_type == TAP_RTP_WRONG_LENGTH))
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save in a file: Wrong length of captured packets!");
+ else if ((user_data->forward.error_type == TAP_RTP_PADDING_ERROR) ||
+ (user_data->reversed.error_type == TAP_RTP_PADDING_ERROR))
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save in a file: RTP data with padding!");
+ else
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save in a file: File I/O problem!");
+ return;
+ }
+ /* we can not save forward direction */
+ else if ((user_data->forward.saved == FALSE) && ((GTK_TOGGLE_BUTTON (forw)->active) ||
+ (GTK_TOGGLE_BUTTON (both)->active))) {
+ if (user_data->forward.error_type == TAP_RTP_WRONG_CODEC)
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save forward direction in a file: Unsupported codec!");
+ else if (user_data->forward.error_type == TAP_RTP_WRONG_LENGTH)
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save forward direction in a file: Wrong length of captured packets!");
+ else if (user_data->forward.error_type == TAP_RTP_PADDING_ERROR)
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save forward direction in a file: RTP data with padding!");
+ else
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save forward direction in a file: File I/O problem!");
+ return;
+ }
+ /* we can not save reversed direction */
+ else if ((user_data->reversed.saved == FALSE) && ((GTK_TOGGLE_BUTTON (rev)->active) ||
+ (GTK_TOGGLE_BUTTON (both)->active))) {
+ if (user_data->reversed.error_type == TAP_RTP_WRONG_CODEC)
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save reversed direction in a file: Unsupported codec!");
+ else if (user_data->reversed.error_type == TAP_RTP_WRONG_LENGTH)
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save reversed direction in a file: Wrong length of captured packets!");
+ else if (user_data->reversed.error_type == TAP_RTP_PADDING_ERROR)
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save reversed direction in a file: RTP data with padding!");
+ else if (user_data->reversed.error_type == TAP_RTP_NO_DATA)
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save reversed direction in a file: No RTP data!");
+ else
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "Can't save reversed direction in a file: File I/O problem!");
+ return;
+ }
+
+ /*if (GTK_TOGGLE_BUTTON (wav)->active)
+ format = 1;
+ else if (GTK_TOGGLE_BUTTON (au)->active)
+ format = 2;
+ else if (GTK_TOGGLE_BUTTON (sw)->active)
+ format = 3;*/
+
+ if (GTK_TOGGLE_BUTTON (rev)->active)
+ channels = 2;
+ else if (GTK_TOGGLE_BUTTON (both)->active)
+ channels = 3;
+ else
+ channels = 1;
+
+ if(!copy_file(g_dest, channels/*, format*/, user_data)) {
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ "An error occured while saving voice in a file!");
+ return;
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(user_data->dlg.save_voice_as_w));
+}
+
+/****************************************************************************/
+/* when the user wants to save the voice information in a file */
+/* XXX support for different formats is currently commented out */
+static void on_save_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data _U_)
+{
+ GtkWidget *vertb;
+ GtkWidget *table1;
+ GtkWidget *label_format;
+ GtkWidget *channels_label;
+ /*GSList *format_group = NULL;*/
+ GSList *channels_group = NULL;
+ GtkWidget *forward_rb;
+ GtkWidget *reversed_rb;
+ GtkWidget *both_rb;
+ /*GtkWidget *wav_rb; GtkWidget *au_rb; GtkWidget *sw_rb;*/
+ GtkWidget *ok_bt;
+
+ /* if we can't save in a file: wrong codec, cut packets or other errors */
+ /* shold the error arise here or later when you click ok button ?
+ * if we do it here, then we must disable the refresh button, so we don't do it here */
+
+ if (user_data->dlg.save_voice_as_w != NULL) {
+ /* There's already a Save voice info dialog box; reactivate it. */
+ reactivate_window(user_data->dlg.save_voice_as_w);
+ return;
+ }
+
+ user_data->dlg.save_voice_as_w = gtk_file_selection_new("Ethereal: Save Payload As ...");
+ gtk_signal_connect(GTK_OBJECT(user_data->dlg.save_voice_as_w), "destroy",
+ GTK_SIGNAL_FUNC(save_voice_as_destroy_cb), user_data);
+
+ /* Container for each row of widgets */
+ vertb = gtk_vbox_new(FALSE, 0);
+ gtk_container_border_width(GTK_CONTAINER(vertb), 5);
+ gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->action_area),
+ vertb, FALSE, FALSE, 0);
+ gtk_widget_show (vertb);
+
+ table1 = gtk_table_new (2, 4, FALSE);
+ gtk_widget_show (table1);
+ gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
+ gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
+
+ label_format = gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");
+ gtk_widget_show (label_format);
+ gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ /* we support .au - ulaw*/
+ /* wav_rb = gtk_radio_button_new_with_label (format_group, ".wav");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (wav_rb));
+ gtk_widget_show (wav_rb);
+ gtk_table_attach (GTK_TABLE (table1), wav_rb, 1, 2, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ sw_rb = gtk_radio_button_new_with_label (format_group, "8 kHz, 16 bit ");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sw_rb));
+ gtk_widget_show (sw_rb);
+ gtk_table_attach (GTK_TABLE (table1), sw_rb, 2, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ au_rb = gtk_radio_button_new_with_label (format_group, ".au");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (au_rb));
+ gtk_widget_show (au_rb);
+ gtk_table_attach (GTK_TABLE (table1), au_rb, 3, 4, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ */
+
+ channels_label = gtk_label_new ("Channels:");
+ gtk_widget_show (channels_label);
+ gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
+
+ forward_rb = gtk_radio_button_new_with_label (channels_group, "forward ");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
+ gtk_widget_show (forward_rb);
+ gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
+ gtk_widget_show (reversed_rb);
+ gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ both_rb = gtk_radio_button_new_with_label (channels_group, "both");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
+ gtk_widget_show (both_rb);
+ gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
+
+ /* if one direction is nok we don't allow saving
+ XXX this is not ok since the user can click the refresh button and cause changes
+ but we can not update this window. So we move all the decision on the time the ok
+ button is clicked
+ if (user_data->forward.saved == FALSE) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb), TRUE);
+ gtk_widget_set_sensitive(forward_rb, FALSE);
+ gtk_widget_set_sensitive(both_rb, FALSE);
+ }
+ else if (user_data->reversed.saved == FALSE) {
+ gtk_widget_set_sensitive(reversed_rb, FALSE);
+ gtk_widget_set_sensitive(both_rb, FALSE);
+ }
+ */
+
+ ok_bt = GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->ok_button;
+ /*OBJECT_SET_DATA(ok_bt, "wav_rb", wav_rb);
+ OBJECT_SET_DATA(ok_bt, "au_rb", au_rb);
+ OBJECT_SET_DATA(ok_bt, "sw_rb", sw_rb);*/
+ OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
+ OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
+ OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
+ OBJECT_SET_DATA(ok_bt, "user_data", user_data);
+
+ /* Connect the cancel_button to destroy the widget */
+ SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->cancel_button,
+ "clicked", (GtkSignalFunc)gtk_widget_destroy,
+ user_data->dlg.save_voice_as_w);
+
+ /* Catch the "key_press_event" signal in the window, so that we can catch
+ the ESC key being pressed and act as if the "Cancel" button had
+ been selected. */
+ dlg_set_cancel(user_data->dlg.save_voice_as_w, GTK_FILE_SELECTION(user_data->dlg.save_voice_as_w)->cancel_button);
+
+ gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+ GTK_SIGNAL_FUNC(save_voice_as_ok_cb), user_data->dlg.save_voice_as_w);
+
+ gtk_widget_show(user_data->dlg.save_voice_as_w);
+}
+
+
+/****************************************************************************/
+/* when we are finished with redisection, we add the label for the statistic */
+static void draw_stat(user_data_t *user_data)
+{
+ gchar label_max[200];
+ guint32 f_expected = (user_data->forward.stop_seq_nr + user_data->forward.cycles*65536)
+ - user_data->forward.start_seq_nr + 1;
+ guint32 r_expected = (user_data->reversed.stop_seq_nr + user_data->reversed.cycles*65536)
+ - user_data->reversed.start_seq_nr + 1;
+ gint32 f_lost = f_expected - user_data->forward.total_nr;
+ gint32 r_lost = r_expected - user_data->reversed.total_nr;
+
+ g_snprintf(label_max, 199, "Max delay = %f sec at packet no. %u \n\n"
+ "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
+ " Sequence errors = %u",
+ user_data->forward.max_delay, user_data->forward.max_nr, user_data->forward.total_nr,
+ f_expected, f_lost, user_data->forward.sequence);
+
+ gtk_label_set_text(GTK_LABEL(user_data->dlg.label_stats_fwd), label_max);
+
+ g_snprintf(label_max, 199, "Max delay = %f sec at packet no. %u \n\n"
+ "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
+ " Sequence errors = %u",
+ user_data->reversed.max_delay, user_data->reversed.max_nr, user_data->reversed.total_nr,
+ r_expected, r_lost, user_data->reversed.sequence);
+
+ gtk_label_set_text(GTK_LABEL(user_data->dlg.label_stats_rev), label_max);
+
+ return ;
+}
+
+/****************************************************************************/
+/* append a line to clist */
+static void add_to_clist(GtkWidget *clist, guint32 number, guint16 seq_num,
+ double delay, double jitter, gboolean status, gboolean marker,
+ gchar *timeStr, guint32 pkt_len)
+{
+ guint added_row;
+ gchar *data[8];
+ gchar field[8][32];
+
+ data[0]=&field[0][0];
+ data[1]=&field[1][0];
+ data[2]=&field[2][0];
+ data[3]=&field[3][0];
+ data[4]=&field[4][0];
+ data[5]=&field[5][0];
+ data[6]=&field[6][0];
+ data[7]=&field[7][0];
+
+ g_snprintf(field[0], 20, "%u", number);
+ g_snprintf(field[1], 20, "%u", seq_num);
+ g_snprintf(field[2], 20, "%f", delay);
+ g_snprintf(field[3], 20, "%f", jitter);
+ g_snprintf(field[4], 20, "%s", marker? "SET" : "");
+ g_snprintf(field[5], 29, "%s", status? "OK" : "NOK - Wrong sequence nr.");
+ g_snprintf(field[6], 32, "%s", timeStr);
+ g_snprintf(field[7], 20, "%u", pkt_len);
+
+ added_row = gtk_clist_append(GTK_CLIST(clist), data);
+ gtk_clist_set_row_data(GTK_CLIST(clist), added_row, GUINT_TO_POINTER(number));
+}
+
+/****************************************************************************/
+/* Create the dialog box with all widgets */
+void create_rtp_dialog(user_data_t* user_data)
+{
+ GtkWidget *window = NULL;
+ GtkWidget *clist_fwd;
+ GtkWidget *clist_rev;
+ GtkWidget *label_stats_fwd;
+ GtkWidget *label_stats_rev;
+ GtkWidget *notebook;
+
+ GtkWidget *main_vb, *page, *page_r, *label, *label1, *label2, *label3;
+ GtkWidget *scrolled_window, *scrolled_window_r/*, *frame, *text, *label4, *page_help*/;
+ GtkWidget *box4, *voice_bt, *refresh_bt, *goto_bt, *close_bt, *csv_bt;
+#ifdef USE_CONVERSATION_GRAPH
+ GtkWidget *graph_bt;
+#endif
+
+ gchar *titles[8] = {"Packet", "Sequence", "Delay (s)", "Jitter (s)", "Marker", "Status", "Date", "Length"};
+ gchar label_forward[150];
+ gchar label_reverse[150];
+
+ gchar str_ip_src[16];
+ gchar str_ip_dst[16];
+
+
+ window = dlg_window_new("Ethereal: RTP Stream Analysis");
+ gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
+ gtk_signal_connect(GTK_OBJECT(window), "destroy",
+ GTK_SIGNAL_FUNC(on_destroy), user_data);
+
+ /* Container for each row of widgets */
+ main_vb = gtk_vbox_new(FALSE, 3);
+ gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+ gtk_container_add(GTK_CONTAINER(window), main_vb);
+ gtk_widget_show(main_vb);
+
+
+ /* Notebooks... */
+ strcpy(str_ip_src, ip_to_str((ip_addr_p)&user_data->ip_src_fwd));
+ strcpy(str_ip_dst, ip_to_str((ip_addr_p)&user_data->ip_dst_fwd));
+
+ g_snprintf(label_forward, 149,
+ "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
+ str_ip_src, user_data->port_src_fwd, str_ip_dst, user_data->port_dst_fwd, user_data->ssrc_fwd);
+
+ strcpy(str_ip_src, ip_to_str((ip_addr_p)&user_data->ip_src_rev));
+ strcpy(str_ip_dst, ip_to_str((ip_addr_p)&user_data->ip_dst_rev));
+
+ g_snprintf(label_reverse, 149,
+ "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
+ str_ip_src, user_data->port_src_rev, str_ip_dst, user_data->port_dst_rev, user_data->ssrc_rev);
+
+ /* Start a notebook for flipping between sets of changes */
+ notebook = gtk_notebook_new();
+ gtk_container_add(GTK_CONTAINER(main_vb), notebook);
+ gtk_object_set_data(GTK_OBJECT(window), "notebook", notebook);
+
+ /* page for forward connection */
+ page = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(page), 20);
+
+ /* scrolled window */
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_usize(scrolled_window, 600, 200);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ /* direction label */
+ label1 = gtk_label_new(label_forward);
+ gtk_box_pack_start(GTK_BOX(page), label1, FALSE, FALSE, 0);
+
+ /* place for some statistics */
+ label_stats_fwd = gtk_label_new("\n\n");
+ gtk_box_pack_end(GTK_BOX(page), label_stats_fwd, FALSE, FALSE, 5);
+
+ /* clist for the information */
+ clist_fwd = gtk_clist_new_with_titles(8, titles);
+ gtk_widget_show(clist_fwd);
+ gtk_container_add(GTK_CONTAINER(scrolled_window), clist_fwd);
+ gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
+ gtk_signal_connect(GTK_OBJECT (clist_fwd), "select_row",
+ GTK_SIGNAL_FUNC (on_clist_select_row),
+ user_data);
+ /* Hide date and length column */
+ gtk_clist_set_column_visibility(GTK_CLIST(clist_fwd), 6, FALSE);
+ gtk_clist_set_column_visibility(GTK_CLIST(clist_fwd), 7, FALSE);
+
+ /* label */
+ label = gtk_label_new(" Forward Direction ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
+
+ /* column width and justification */
+ gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 0, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 1, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 2, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 3, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_fwd), 4, 40);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 0, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 1, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 2, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 3, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 4, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_fwd), 5, GTK_JUSTIFY_CENTER);
+
+ /* same page for reversed connection */
+ page_r = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(page_r), 20);
+ scrolled_window_r = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_usize(scrolled_window_r, 600, 200);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_r),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ label3 = gtk_label_new(label_reverse);
+ gtk_box_pack_start(GTK_BOX(page_r), label3, FALSE, FALSE, 0);
+ label_stats_rev = gtk_label_new("\n\n");
+ gtk_box_pack_end(GTK_BOX(page_r), label_stats_rev, FALSE, FALSE, 5);
+ clist_rev = gtk_clist_new_with_titles(8, titles);
+ gtk_widget_show(clist_rev);
+ gtk_clist_set_column_visibility(GTK_CLIST(clist_rev), 6, FALSE);
+ gtk_clist_set_column_visibility(GTK_CLIST(clist_rev), 7, FALSE);
+
+ gtk_signal_connect(GTK_OBJECT (clist_rev), "select_row",
+ GTK_SIGNAL_FUNC (on_clist_select_row),
+ user_data);
+
+ gtk_container_add(GTK_CONTAINER(scrolled_window_r), clist_rev);
+ gtk_box_pack_start(GTK_BOX(page_r), scrolled_window_r, TRUE, TRUE, 0);
+ label2 = gtk_label_new(" Reversed Direction ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_r, label2);
+
+ gtk_clist_set_column_width(GTK_CLIST(clist_rev), 0, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_rev), 1, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_rev), 2, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_rev), 3, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_rev), 4, 40);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 0, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 1, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 2, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 3, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 4, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_rev), 5, GTK_JUSTIFY_CENTER);
+
+ /* page for help&about or future
+ page_help = gtk_hbox_new(FALSE, 5);
+ label4 = gtk_label_new(" Future ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_help, label4);
+ frame = gtk_frame_new("");
+ text = gtk_label_new("\n\nMaybe some more statistics: delay and jitter distribution,...");
+ gtk_label_set_justify(GTK_LABEL(text), GTK_JUSTIFY_LEFT);
+ gtk_container_add(GTK_CONTAINER(frame), text);
+ gtk_container_set_border_width(GTK_CONTAINER(frame), 20);
+ gtk_box_pack_start(GTK_BOX(page_help), frame, TRUE, TRUE, 0);
+ */
+
+ /* show all notebooks */
+ gtk_widget_show_all(notebook);
+
+ /* buttons */
+ box4 = gtk_hbutton_box_new();
+ gtk_box_pack_start(GTK_BOX(main_vb), box4, FALSE, FALSE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(box4), 10);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX (box4), GTK_BUTTONBOX_EDGE);
+ gtk_button_box_set_spacing(GTK_BUTTON_BOX (box4), 0);
+ gtk_button_box_set_child_ipadding(GTK_BUTTON_BOX (box4), 4, 0);
+ gtk_widget_show(box4);
+
+ voice_bt = gtk_button_new_with_label("Save payload...");
+ gtk_container_add(GTK_CONTAINER(box4), voice_bt);
+ gtk_widget_show(voice_bt);
+ gtk_signal_connect(GTK_OBJECT(voice_bt), "clicked",
+ GTK_SIGNAL_FUNC(on_save_bt_clicked), user_data);
+
+ csv_bt = gtk_button_new_with_label("Save as CSV...");
+ gtk_container_add(GTK_CONTAINER(box4), csv_bt);
+ gtk_widget_show(csv_bt);
+ gtk_signal_connect(GTK_OBJECT(csv_bt), "clicked",
+ GTK_SIGNAL_FUNC(save_csv_as_cb), user_data);
+
+ refresh_bt = gtk_button_new_with_label("Refresh");
+ gtk_container_add(GTK_CONTAINER(box4), refresh_bt);
+ gtk_widget_show(refresh_bt);
+ gtk_signal_connect(GTK_OBJECT(refresh_bt), "clicked",
+ GTK_SIGNAL_FUNC(on_refresh_bt_clicked), user_data);
+
+ goto_bt = gtk_button_new_with_label("Go to frame");
+ gtk_container_add(GTK_CONTAINER(box4), goto_bt);
+ gtk_widget_show(goto_bt);
+ gtk_signal_connect(GTK_OBJECT(goto_bt), "clicked",
+ GTK_SIGNAL_FUNC(on_goto_bt_clicked), user_data);
+
+#ifdef USE_CONVERSATION_GRAPH
+ graph_bt = gtk_button_new_with_label("Graph");
+ gtk_container_add(GTK_CONTAINER(box4), graph_bt);
+ gtk_widget_show(graph_bt);
+ gtk_signal_connect(GTK_OBJECT(graph_bt), "clicked",
+ GTK_SIGNAL_FUNC(on_graph_bt_clicked), user_data);
+#endif
+
+ close_bt = gtk_button_new_with_label("Close");
+ gtk_container_add(GTK_CONTAINER(box4), close_bt);
+ gtk_widget_show(close_bt);
+ gtk_signal_connect(GTK_OBJECT(close_bt), "clicked",
+ GTK_SIGNAL_FUNC(on_close_bt_clicked), user_data);
+
+ gtk_widget_show(window);
+
+ user_data->dlg.window = window;
+ user_data->dlg.clist_fwd = clist_fwd;
+ user_data->dlg.clist_rev = clist_rev;
+ user_data->dlg.label_stats_fwd = label_stats_fwd;
+ user_data->dlg.label_stats_rev = label_stats_rev;
+ user_data->dlg.notebook = notebook;
+ user_data->dlg.selected_clist = NULL;
+ user_data->dlg.selected_row = -1;
+}
+
+
+/****************************************************************************/
+static gboolean process_node(proto_item *ptree_node, header_field_info *hfinformation,
+ const gchar* proto_field, guint32* p_result)
+{
+ field_info *finfo;
+ proto_item *proto_sibling_node;
+ header_field_info *hfssrc;
+ ipv4_addr *ipv4;
+
+ finfo = PITEM_FINFO(ptree_node);
+
+ if (hfinformation==(finfo->hfinfo)) {
+ hfssrc = proto_registrar_get_byname((gchar*) proto_field);
+ if (hfssrc == NULL)
+ return FALSE;
+ for(ptree_node=g_node_first_child(ptree_node); ptree_node!=NULL;
+ ptree_node=g_node_next_sibling(ptree_node)) {
+ finfo=PITEM_FINFO(ptree_node);
+ if (hfssrc==finfo->hfinfo) {
+ if (hfinformation->type==FT_IPv4) {
+ ipv4 = fvalue_get(finfo->value);
+ *p_result = ipv4_get_net_order_addr(ipv4);
+ }
+ else {
+ *p_result = fvalue_get_integer(finfo->value);
+ }
+ return TRUE;
+ }
+ }
+ }
+
+ proto_sibling_node = g_node_next_sibling(ptree_node);
+
+ if (proto_sibling_node) {
+ return process_node(proto_sibling_node, hfinformation, proto_field, p_result);
+ }
+ else
+ return FALSE;
+}
+
+/****************************************************************************/
+static gboolean get_int_value_from_proto_tree(proto_tree *protocol_tree,
+ const gchar* proto_name,
+ const gchar* proto_field,
+ guint32* p_result)
+{
+ proto_item *ptree_node;
+ header_field_info *hfinformation;
+
+ hfinformation = proto_registrar_get_byname((gchar*) proto_name);
+ if (hfinformation == NULL)
+ return FALSE;
+
+ ptree_node = g_node_first_child(protocol_tree);
+ if (!ptree_node)
+ return FALSE;
+
+ return process_node(ptree_node, hfinformation, proto_field, p_result);
+}
+
+
+/****************************************************************************/
+/* XXX only handles RTP over IPv4, should add IPv6 support */
+void rtp_analysis(
+ guint32 ip_src_fwd,
+ guint16 port_src_fwd,
+ guint32 ip_dst_fwd,
+ guint16 port_dst_fwd,
+ guint32 ssrc_fwd,
+ guint32 ip_src_rev,
+ guint16 port_src_rev,
+ guint32 ip_dst_rev,
+ guint16 port_dst_rev,
+ guint32 ssrc_rev
+ )
+{
+ user_data_t *user_data;
+ gchar filter_text[256];
+ dfilter_t *sfcode;
+ GString *error_string;
+
+ user_data = g_malloc(sizeof(user_data_t));
+
+ user_data->ip_src_fwd = ip_src_fwd;
+ user_data->port_src_fwd = port_src_fwd;
+ user_data->ip_dst_fwd = ip_dst_fwd;
+ user_data->port_dst_fwd = port_dst_fwd;
+ user_data->ssrc_fwd = ssrc_fwd;
+ user_data->ip_src_rev = ip_src_rev;
+ user_data->port_src_rev = port_src_rev;
+ user_data->ip_dst_rev = ip_dst_rev;
+ user_data->port_dst_rev = port_dst_rev;
+ user_data->ssrc_rev = ssrc_rev;
+
+ create_rtp_dialog(user_data);
+
+ /* Try to compile the filter. */
+ strcpy(filter_text,"rtp && ip");
+ if (!dfilter_compile(filter_text, &sfcode)) {
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, dfilter_error_msg);
+ return;
+ }
+
+ sprintf(filter_text,"rtp && ip && !icmp && (( ip.src==%s && udp.srcport==%d && ip.dst==%s && udp.dstport==%d ) || ( ip.src==%s && udp.srcport==%d && ip.dst==%s && udp.dstport==%d ))",
+ ip_to_str((ip_addr_p)&ip_src_fwd),
+ port_src_fwd,
+ ip_to_str((ip_addr_p)&ip_dst_fwd),
+ port_dst_fwd,
+ ip_to_str((ip_addr_p)&ip_src_rev),
+ port_src_rev,
+ ip_to_str((ip_addr_p)&ip_dst_rev),
+ port_dst_rev
+ );
+
+ error_string = register_tap_listener("rtp", user_data, filter_text,
+ (void*)rtp_reset, (void*)rtp_packet, (void*)rtp_draw);
+ if (error_string != NULL) {
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, error_string->str);
+ g_string_free(error_string, TRUE);
+ g_free(user_data);
+ return;
+ /*exit(1);*/
+ }
+
+ /* file names for storing sound data */
+ tmpnam(user_data->f_tempname);
+ tmpnam(user_data->r_tempname);
+ user_data->forward.fp = NULL;
+ user_data->reversed.fp = NULL;
+ user_data->dlg.save_voice_as_w = NULL;
+ user_data->dlg.save_csv_as_w = NULL;
+#ifdef USE_CONVERSATION_GRAPH
+ user_data->dlg.graph_window = NULL;
+ user_data->series_fwd.value_pairs = NULL;
+ user_data->series_rev.value_pairs = NULL;
+#endif
+
+ redissect_packets(&cfile);
+
+ draw_stat(user_data);
+}
+
+/****************************************************************************/
+/* entry point from main menu */
+void rtp_analysis_cb(GtkWidget *w _U_, gpointer data _U_)
+{
+ guint32 ip_src_fwd;
+ guint16 port_src_fwd;
+ guint32 ip_dst_fwd;
+ guint16 port_dst_fwd;
+ guint32 ssrc_fwd = 0;
+ guint32 ip_src_rev;
+ guint16 port_src_rev;
+ guint32 ip_dst_rev;
+ guint16 port_dst_rev;
+ guint32 ssrc_rev = 0;
+
+ gchar filter_text[256];
+ dfilter_t *sfcode;
+ capture_file *cf;
+ epan_dissect_t *edt;
+ gint err;
+ gboolean frame_matched;
+ frame_data *fdata;
+ GList *strinfo_list;
+ GList *filtered_list = NULL;
+ rtp_stream_info_t *strinfo;
+ guint nfound;
+
+ /* Try to compile the filter. */
+ strcpy(filter_text,"rtp && ip");
+ if (!dfilter_compile(filter_text, &sfcode)) {
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, dfilter_error_msg);
+ return;
+ }
+ /* we load the current file into cf variable */
+ cf = &cfile;
+ fdata = cf->current_frame;
+
+ /* we are on the selected frame now */
+ if (fdata == NULL)
+ return; /* if we exit here it's an error */
+
+ /* dissect the current frame */
+ if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err)) {
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL,
+ file_read_error_message(err), cf->filename);
+ return;
+ }
+ edt = epan_dissect_new(TRUE, FALSE);
+ epan_dissect_prime_dfilter(edt, sfcode);
+ epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
+ frame_matched = dfilter_apply_edt(sfcode, edt);
+
+ /* if it is not an rtp frame, show the rtpstream dialog */
+ frame_matched = dfilter_apply_edt(sfcode, edt);
+ if (frame_matched != 1) {
+ rtpstream_dlg_show(rtpstream_get_info()->strinfo_list);
+ return;
+/*
+ epan_dissect_free(edt);
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, "You didn't choose a RTP packet!");
+ return;
+*/
+ }
+
+ /* ok, it is a RTP frame, so let's get the ip and port values */
+ g_memmove(&ip_src_fwd, edt->pi.src.data, 4);
+ g_memmove(&ip_dst_fwd, edt->pi.dst.data, 4);
+ port_src_fwd = edt->pi.srcport;
+ port_dst_fwd = edt->pi.destport;
+
+ /* assume the inverse ip/port combination for the reverse direction */
+ g_memmove(&ip_src_rev, edt->pi.dst.data, 4);
+ g_memmove(&ip_dst_rev, edt->pi.src.data, 4);
+ port_src_rev = edt->pi.destport;
+ port_dst_rev = edt->pi.srcport;
+
+ /* now we need the SSRC value of the current frame */
+ if (!get_int_value_from_proto_tree(edt->tree, "rtp", "rtp.ssrc", &ssrc_fwd)) {
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, "SSRC value couldn't be found!");
+ return;
+ }
+
+ /* search for reversed direction in the global rtp streams list */
+ nfound = 0;
+ strinfo_list = g_list_first(rtpstream_get_info()->strinfo_list);
+ while (strinfo_list)
+ {
+ strinfo = (rtp_stream_info_t*)(strinfo_list->data);
+ if (strinfo->src_addr==ip_src_fwd
+ && strinfo->src_port==port_src_fwd
+ && strinfo->dest_addr==ip_dst_fwd
+ && strinfo->dest_port==port_dst_fwd)
+ {
+ filtered_list = g_list_prepend(filtered_list, strinfo);
+ }
+
+ if (strinfo->src_addr==ip_src_rev
+ && strinfo->src_port==port_src_rev
+ && strinfo->dest_addr==ip_dst_rev
+ && strinfo->dest_port==port_dst_rev)
+ {
+ ++nfound;
+ filtered_list = g_list_append(filtered_list, strinfo);
+ if (ssrc_rev==0)
+ ssrc_rev = strinfo->ssrc;
+ }
+
+ strinfo_list = g_list_next(strinfo_list);
+ }
+
+ /* if more than one reverse streams found, we let the user choose the right one */
+ if (nfound>1) {
+ rtpstream_dlg_show(filtered_list);
+ return;
+ }
+ else {
+ rtp_analysis(
+ ip_src_fwd,
+ port_src_fwd,
+ ip_dst_fwd,
+ port_dst_fwd,
+ ssrc_fwd,
+ ip_src_rev,
+ port_src_rev,
+ ip_dst_rev,
+ port_dst_rev,
+ ssrc_rev
+ );
+ }
+}
+
+/****************************************************************************/
+static void
+rtp_analysis_init(char *dummy _U_)
+{
+ rtp_analysis_cb(NULL, NULL);
+}
+
+/****************************************************************************/
+void
+register_tap_listener_rtp_analysis(void)
+{
+ register_ethereal_tap("rtp", rtp_analysis_init);
+}
+
+void
+register_tap_menu_rtp_analysis(void)
+{
+ register_tap_menu_item("Statistics/RTP Streams/Analyse...",
+ rtp_analysis_cb, NULL, NULL);
+}
diff --git a/gtk/rtp_analysis.h b/gtk/rtp_analysis.h
new file mode 100644
index 0000000000..ae5afc571f
--- /dev/null
+++ b/gtk/rtp_analysis.h
@@ -0,0 +1,50 @@
+/* rtp_analysis.h
+ * RTP analysis addition for ethereal
+ *
+ * $Id: rtp_analysis.h,v 1.1 2003/09/24 07:48:11 guy Exp $
+ *
+ * Copyright 2003, Alcatel Business Systems
+ * By Lars Ruoff <lars.ruoff@gmx.net>
+ *
+ * based on tap_rtp.c
+ * Copyright 2003, Iskratel, Ltd, Kranj
+ * By Miha Jemec <m.jemec@iskratel.si>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef RTP_ANALYSIS_H_INCLUDED
+#define RTP_ANALYSIS_H_INCLUDED
+
+#include <glib.h>
+
+void rtp_analysis(
+ guint32 ip_src_fwd, /* network-order IPv4 address */
+ guint16 port_src_fwd,
+ guint32 ip_dst_fwd, /* network-order IPv4 address */
+ guint16 port_dst_fwd,
+ guint32 ssrc_fwd,
+ guint32 ip_src_rev, /* network-order IPv4 address */
+ guint16 port_src_rev,
+ guint32 ip_dst_rev, /* network-order IPv4 address */
+ guint16 port_dst_rev,
+ guint32 ssrc_rev
+ );
+
+#endif /*RTP_ANALYSIS_H_INCLUDED*/
diff --git a/gtk/rtp_stream.c b/gtk/rtp_stream.c
new file mode 100644
index 0000000000..b662cb6db3
--- /dev/null
+++ b/gtk/rtp_stream.c
@@ -0,0 +1,407 @@
+/* rtp_stream.c
+ * RTP streams summary addition for ethereal
+ *
+ * $Id: rtp_stream.c,v 1.1 2003/09/24 07:48:11 guy Exp $
+ *
+ * Copyright 2003, Alcatel Business Systems
+ * By Lars Ruoff <lars.ruoff@gmx.net>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "rtp_stream.h"
+#include "rtp_stream_dlg.h"
+
+#include "globals.h"
+
+#include "tap.h"
+#include "register.h"
+#include "packet-rtp.h"
+
+#include "simple_dialog.h"
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <string.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+
+/****************************************************************************/
+/* the one and only global rtpstream_tapinfo_t structure */
+static rtpstream_tapinfo_t the_tapinfo_struct =
+ {0, NULL, 0, TAP_ANALYSE, NULL, NULL, NULL, 0, FALSE};
+
+
+/****************************************************************************/
+/* GCompareFunc style comparison function for _rtp_stream_info */
+gint rtp_stream_info_cmp(gconstpointer aa, gconstpointer bb)
+{
+ const struct _rtp_stream_info* a = aa;
+ const struct _rtp_stream_info* b = bb;
+
+ if (a==b)
+ return 0;
+ if (a==NULL || b==NULL)
+ return 1;
+ if ((a->src_addr == b->src_addr)
+ && (a->src_port == b->src_port)
+ && (a->dest_addr == b->dest_addr)
+ && (a->dest_port == b->dest_port)
+ && (a->ssrc == b->ssrc)
+ && (a->pt == b->pt))
+ return 0;
+ else
+ return 1;
+}
+
+
+/****************************************************************************/
+/* when there is a [re]reading of packet's */
+void rtpstream_reset(rtpstream_tapinfo_t *tapinfo _U_)
+{
+ GList* list;
+
+ if (tapinfo->mode == TAP_ANALYSE) {
+ /* free the data items first */
+ list = g_list_first(tapinfo->strinfo_list);
+ while (list)
+ {
+ g_free(list->data);
+ list = g_list_next(list);
+ }
+ g_list_free(tapinfo->strinfo_list);
+ tapinfo->strinfo_list = NULL;
+ tapinfo->nstreams = 0;
+ tapinfo->npackets = 0;
+ }
+
+ ++(tapinfo->launch_count);
+
+ return;
+}
+
+/****************************************************************************/
+/* redraw the output */
+void rtpstream_draw(rtpstream_tapinfo_t *tapinfo _U_)
+{
+/* XXX: see rtpstream_on_update in rtp_streams_dlg.c for comments
+ gtk_signal_emit_by_name(top_level, "signal_rtpstream_update");
+*/
+ rtpstream_dlg_update(the_tapinfo_struct.strinfo_list);
+ return;
+}
+
+
+/*
+* rtpdump file format
+*
+* The file starts with the tool to be used for playing this file,
+* the multicast/unicast receive address and the port.
+*
+* #!rtpplay1.0 224.2.0.1/3456\n
+*
+* This is followed by one binary header (RD_hdr_t) and one RD_packet_t
+* structure for each received packet. All fields are in network byte
+* order. We don't need the source IP address since we can do mapping
+* based on SSRC. This saves (a little) space, avoids non-IPv4
+* problems and privacy/security concerns. The header is followed by
+* the RTP/RTCP header and (optionally) the actual payload.
+*/
+
+#define RTPFILE_VERSION "1.0"
+
+/*
+* Write a header to the current output file.
+* The header consists of an identifying string, followed
+* by a binary structure.
+*/
+static void rtp_write_header(rtp_stream_info_t *strinfo, FILE *file)
+{
+ guint32 start_sec; /* start of recording (GMT) (seconds) */
+ guint32 start_usec; /* start of recording (GMT) (microseconds)*/
+ guint32 source; /* network source (multicast address) */
+ guint16 port; /* UDP port */
+ guint16 padding; /* 2 padding bytes */
+
+ fprintf(file, "#!rtpplay%s %s/%d\n", RTPFILE_VERSION,
+ ip_to_str((guint8*) &strinfo->dest_addr),
+ strinfo->dest_port);
+
+ start_sec = g_htonl(strinfo->start_sec);
+ start_usec = g_htonl(strinfo->start_usec);
+ source = strinfo->src_addr; /* already is in network order */
+ port = g_htons(strinfo->src_port);
+ padding = 0;
+
+ fwrite(&start_sec, 4, 1, file);
+ fwrite(&start_usec, 4, 1, file);
+ fwrite(&source, 4, 1, file);
+ fwrite(&port, 2, 1, file);
+ fwrite(&padding, 2, 1, file);
+}
+
+/* utility function for writing a sample to file in rtpdump -F dump format (.rtp)*/
+static void rtp_write_sample(rtp_sample_t* sample, FILE* file)
+{
+ guint16 length; /* length of packet, including this header (may
+ be smaller than plen if not whole packet recorded) */
+ guint16 plen; /* actual header+payload length for RTP, 0 for RTCP */
+ guint32 offset; /* milliseconds since the start of recording */
+
+ length = g_htons(sample->header.frame_length + 8);
+ plen = g_htons(sample->header.frame_length);
+ offset = g_htonl(sample->header.rec_time);
+
+ fwrite(&length, 2, 1, file);
+ fwrite(&plen, 2, 1, file);
+ fwrite(&offset, 4, 1, file);
+ fwrite(sample->frame, sample->header.frame_length, 1, file);
+}
+
+
+/* utility function for writing a sample to file in RAS format */
+static
+void ras_write_sample(rtp_sample_t* sample, FILE* file)
+{
+ rtp_sample_header_t net_order_header;
+
+ net_order_header.rec_time = g_htonl(sample->header.rec_time);
+ net_order_header.frame_length = g_htons(sample->header.frame_length);
+
+ fwrite(&(net_order_header.rec_time), 1, 4, file);
+ fwrite(&(net_order_header.frame_length), 1, 2, file);
+ fwrite(sample->frame, 1, sample->header.frame_length, file);
+}
+
+
+/****************************************************************************/
+/* whenever a RTP packet is seen by the tap listener */
+int rtpstream_packet(rtpstream_tapinfo_t *tapinfo _U_, packet_info *pinfo, epan_dissect_t *edt _U_, struct _rtp_info *rtpinfo _U_)
+{
+ rtp_stream_info_t tmp_strinfo;
+ rtp_stream_info_t *strinfo = NULL;
+ GList* list;
+
+ rtp_sample_t sample;
+
+ /* we ignore packets that are not displayed */
+/*
+ if (pinfo->fd->flags.passed_dfilter == 0)
+ return 0;
+*/
+
+ /* gather infos on the stream this packet is part of */
+ g_memmove(&(tmp_strinfo.src_addr), pinfo->src.data, 4);
+ tmp_strinfo.src_port = pinfo->srcport;
+ g_memmove(&(tmp_strinfo.dest_addr), pinfo->dst.data, 4);
+ tmp_strinfo.dest_port = pinfo->destport;
+ tmp_strinfo.ssrc = rtpinfo->info_sync_src;
+ tmp_strinfo.pt = rtpinfo->info_payload_type;
+
+ if (tapinfo->mode == TAP_ANALYSE) {
+ /* check wether we already have a stream with these parameters in the list */
+ list = g_list_first(tapinfo->strinfo_list);
+ while (list)
+ {
+ if (rtp_stream_info_cmp(&tmp_strinfo, (rtp_stream_info_t*)(list->data))==0)
+ {
+ strinfo = (rtp_stream_info_t*)(list->data); /*found!*/
+ break;
+ }
+ list = g_list_next(list);
+ }
+
+ /* not in the list? then create a new entry */
+ if (!strinfo) {
+ tmp_strinfo.npackets = 0;
+ tmp_strinfo.first_frame_num = pinfo->fd->num;
+ tmp_strinfo.start_sec = pinfo->fd->abs_secs;
+ tmp_strinfo.start_usec = pinfo->fd->abs_usecs;
+ tmp_strinfo.tag_vlan_error = 0;
+ tmp_strinfo.tag_diffserv_error = 0;
+ tmp_strinfo.vlan_id = 0;
+ strinfo = g_malloc(sizeof(rtp_stream_info_t));
+ *strinfo = tmp_strinfo; /* memberwise copy of struct */
+ tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo);
+ }
+
+ /* increment the packets counter for this stream */
+ ++(strinfo->npackets);
+
+ /* increment the packets counter of all streams */
+ ++(tapinfo->npackets);
+ }
+ else if (tapinfo->mode == TAP_SAVE) {
+ if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0) {
+/* sample.header.rec_time = pinfo->fd->abs_secs*1000 + pinfo->fd->abs_usecs;*/
+ sample.header.rec_time =
+ (pinfo->fd->abs_usecs + 1000000 - tapinfo->filter_stream_fwd->start_usec)/1000
+ + (pinfo->fd->abs_secs - tapinfo->filter_stream_fwd->start_sec - 1)*1000;
+ sample.header.frame_length = rtpinfo->info_data_len;
+ sample.frame = cfile.pd + pinfo->fd->pkt_len - rtpinfo->info_data_len;
+ rtp_write_sample(&sample, tapinfo->save_file);
+/* ras_write_sample(&sample, tapinfo->save_file);*/
+ }
+ }
+ else if (tapinfo->mode == TAP_MARK) {
+ if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0
+ || rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_rev)==0)
+ {
+ mark_frame(&cfile, pinfo->fd);
+ }
+ }
+
+ return 0;
+}
+
+/****************************************************************************/
+/* scan for RTP streams */
+void rtpstream_scan()
+{
+ gboolean was_registered = the_tapinfo_struct.is_registered;
+ if (!the_tapinfo_struct.is_registered)
+ register_tap_listener_rtp_stream();
+
+ the_tapinfo_struct.mode = TAP_ANALYSE;
+ redissect_packets(&cfile);
+
+ if (!was_registered)
+ remove_tap_listener_rtp_stream();
+}
+
+
+/****************************************************************************/
+/* save rtp dump of stream_fwd */
+void rtpstream_save(rtp_stream_info_t* stream, const gchar *filename)
+{
+ gboolean was_registered = the_tapinfo_struct.is_registered;
+ /* open file for saving */
+ the_tapinfo_struct.save_file = fopen(filename, "wb");
+ if (the_tapinfo_struct.save_file==NULL) {
+ return;
+ }
+
+ rtp_write_header(stream, the_tapinfo_struct.save_file);
+
+ if (!the_tapinfo_struct.is_registered)
+ register_tap_listener_rtp_stream();
+
+ the_tapinfo_struct.mode = TAP_SAVE;
+ the_tapinfo_struct.filter_stream_fwd = stream;
+ redissect_packets(&cfile);
+ the_tapinfo_struct.mode = TAP_ANALYSE;
+
+ if (!was_registered)
+ remove_tap_listener_rtp_stream();
+
+ /* XXX check for error at fclose? */
+ fclose(the_tapinfo_struct.save_file);
+}
+
+
+/****************************************************************************/
+/* mark packets in stream_fwd or stream_rev */
+void rtpstream_mark(rtp_stream_info_t* stream_fwd, rtp_stream_info_t* stream_rev)
+{
+ gboolean was_registered = the_tapinfo_struct.is_registered;
+ if (!the_tapinfo_struct.is_registered)
+ register_tap_listener_rtp_stream();
+
+ the_tapinfo_struct.mode = TAP_MARK;
+ the_tapinfo_struct.filter_stream_fwd = stream_fwd;
+ the_tapinfo_struct.filter_stream_rev = stream_rev;
+ redissect_packets(&cfile);
+ the_tapinfo_struct.mode = TAP_ANALYSE;
+
+ if (!was_registered)
+ remove_tap_listener_rtp_stream();
+}
+
+
+/****************************************************************************/
+const rtpstream_tapinfo_t* rtpstream_get_info()
+{
+ return &the_tapinfo_struct;
+}
+
+
+/****************************************************************************/
+/* TAP INTERFACE */
+/****************************************************************************/
+
+/****************************************************************************/
+static void
+rtpstream_init_tap(char *dummy _U_)
+{
+ /* XXX: never called? */
+}
+
+
+/* XXX just copied from gtk/rpc_stat.c */
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
+
+/****************************************************************************/
+void
+remove_tap_listener_rtp_stream(void)
+{
+ if (the_tapinfo_struct.is_registered) {
+ protect_thread_critical_region();
+ remove_tap_listener(&the_tapinfo_struct);
+ unprotect_thread_critical_region();
+
+ the_tapinfo_struct.is_registered = FALSE;
+ }
+}
+
+
+/****************************************************************************/
+void
+register_tap_listener_rtp_stream(void)
+{
+ gchar filter_text[256];
+ GString *error_string;
+
+ if (!the_tapinfo_struct.is_registered) {
+ register_ethereal_tap("rtp", rtpstream_init_tap);
+
+ sprintf(filter_text, "rtp && ip && !icmp");
+
+ error_string = register_tap_listener("rtp", &the_tapinfo_struct,
+ filter_text,
+ (void*)rtpstream_reset, (void*)rtpstream_packet, (void*)rtpstream_draw);
+
+ if (error_string != NULL) {
+ simple_dialog(ESD_TYPE_WARN | ESD_TYPE_MODAL, NULL, error_string->str);
+ g_string_free(error_string, TRUE);
+ exit(1);
+ }
+
+ the_tapinfo_struct.is_registered = TRUE;
+ }
+}
diff --git a/gtk/rtp_stream.h b/gtk/rtp_stream.h
new file mode 100644
index 0000000000..3817268543
--- /dev/null
+++ b/gtk/rtp_stream.h
@@ -0,0 +1,140 @@
+/* rtp_stream.h
+ * RTP streams summary addition for ethereal
+ *
+ * $Id: rtp_stream.h,v 1.1 2003/09/24 07:48:11 guy Exp $
+ *
+ * Copyright 2003, Alcatel Business Systems
+ * By Lars Ruoff <lars.ruoff@gmx.net>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef RTP_STREAM_H_INCLUDED
+#define RTP_STREAM_H_INCLUDED
+
+#include <glib.h>
+#include <stdio.h>
+
+/****************************************************************************/
+/* type for storing rtp frame information */
+typedef struct st_rtp_sample_header {
+ guint32 rec_time; /* miliseconds since start of recording */
+ guint16 frame_length; /* number of bytes in *frame */
+} rtp_sample_header_t;
+
+/* type for storing rtp frame information */
+typedef struct st_rtp_sample {
+ rtp_sample_header_t header; /* date and size */
+ char *frame; /* data bytes */
+} rtp_sample_t;
+
+typedef rtp_sample_t* rtp_sample_p;
+
+
+/* defines an rtp stream */
+typedef struct _rtp_stream_info {
+ guint32 src_addr;
+ guint16 src_port;
+ guint32 dest_addr;
+ guint16 dest_port;
+ guint32 ssrc;
+ guint8 pt;
+ guint32 npackets;
+
+ guint32 first_frame_num; /* frame number of first frame */
+ /* start of recording (GMT) of this stream */
+ guint32 start_sec; /* seconds */
+ guint32 start_usec; /* microseconds */
+ gboolean tag_vlan_error;
+ gboolean tag_diffserv_error;
+ guint16 vlan_id;
+
+} rtp_stream_info_t;
+
+
+/* tapping modes */
+typedef enum
+{
+ TAP_ANALYSE,
+ TAP_SAVE,
+ TAP_MARK
+} tap_mode_t;
+
+
+/* structure that holds the information about all detected streams */
+/* struct holding all information of the tap */
+typedef struct _rtpstream_tapinfo {
+ int nstreams; /* number of streams in the list */
+ GList* strinfo_list; /* list with all streams */
+ int npackets; /* total number of rtp packets of all streams */
+ /* used while tapping. user shouldnt modify these */
+ tap_mode_t mode;
+ rtp_stream_info_t* filter_stream_fwd; /* used as filter in some tap modes */
+ rtp_stream_info_t* filter_stream_rev; /* used as filter in some tap modes */
+ FILE* save_file;
+ guint32 launch_count; /* number of times the tap has been run */
+ gboolean is_registered; /* if the tap listener is currently registered or not */
+} rtpstream_tapinfo_t;
+
+
+/****************************************************************************/
+/* INTERFACE */
+
+/*
+* Registers the rtp_streams tap listener (if not already done).
+* From that point on, the RTP streams list will be updated with every redissection.
+* This function is also the entry point for the initialization routine of the tap system.
+* So whenever rtp_stream.c is added to the list of ETHEREAL_TAP_SRCs, the tap will be registered on startup.
+* If not, it will be registered on demand by the rtp_streams and rtp_analysis functions that need it.
+*/
+void register_tap_listener_rtp_stream(void);
+
+/*
+* Removes the rtp_streams tap listener (if not already done)
+* From that point on, the RTP streams list won't be updated any more.
+*/
+void remove_tap_listener_rtp_stream(void);
+
+/*
+* Retrieves a constant reference to the unique info structure of the rtp_streams tap listener.
+* The user should not modify the data pointed to.
+*/
+const rtpstream_tapinfo_t* rtpstream_get_info();
+
+/*
+* Scans all packets for RTP streams and updates the RTP streams list.
+* (redissects all packets)
+*/
+void rtpstream_scan();
+
+/*
+* Saves an RTP stream as raw data stream with timestamp information for later RTP playback.
+* (redissects all packets)
+*/
+void rtpstream_save(rtp_stream_info_t* stream, const gchar *filename);
+
+/*
+* Marks all packets belonging to either of stream_fwd or stream_rev.
+* (both can be NULL)
+* (redissects all packets)
+*/
+void rtpstream_mark(rtp_stream_info_t* stream_fwd, rtp_stream_info_t* stream_rev);
+
+
+#endif /*RTP_STREAM_H_INCLUDED*/
diff --git a/gtk/rtp_stream_dlg.c b/gtk/rtp_stream_dlg.c
new file mode 100644
index 0000000000..8811cf3892
--- /dev/null
+++ b/gtk/rtp_stream_dlg.c
@@ -0,0 +1,806 @@
+/* rtp_stream_dlg.c
+ * RTP streams summary addition for ethereal
+ *
+ * $Id: rtp_stream_dlg.c,v 1.1 2003/09/24 07:48:11 guy Exp $
+ *
+ * Copyright 2003, Alcatel Business Systems
+ * By Lars Ruoff <lars.ruoff@gmx.net>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "rtp_stream_dlg.h"
+#include "rtp_stream.h"
+#include "rtp_analysis.h"
+
+#include "globals.h"
+#include "epan/filesystem.h"
+
+#include "menu.h"
+#include "dlg_utils.h"
+#include "ui_util.h"
+#include "main.h"
+#include "compat_macros.h"
+
+#include <string.h>
+
+extern GtkWidget *main_display_filter_widget;
+
+
+/****************************************************************************/
+/*
+ * RTP Payload types
+ * Table B.2 / H.225.0
+ * Also RFC 1890, and
+ *
+ * http://www.iana.org/assignments/rtp-parameters
+ */
+#define PT_PCMU 0 /* RFC 1890 */
+#define PT_1016 1 /* RFC 1890 */
+#define PT_G721 2 /* RFC 1890 */
+#define PT_GSM 3 /* RFC 1890 */
+#define PT_G723 4 /* From Vineet Kumar of Intel; see the Web page */
+#define PT_DVI4_8000 5 /* RFC 1890 */
+#define PT_DVI4_16000 6 /* RFC 1890 */
+#define PT_LPC 7 /* RFC 1890 */
+#define PT_PCMA 8 /* RFC 1890 */
+#define PT_G722 9 /* RFC 1890 */
+#define PT_L16_STEREO 10 /* RFC 1890 */
+#define PT_L16_MONO 11 /* RFC 1890 */
+#define PT_QCELP 12 /* Qualcomm Code Excited Linear Predictive coding? */
+#define PT_CN 13 /* RFC 3389 */
+#define PT_MPA 14 /* RFC 1890, RFC 2250 */
+#define PT_G728 15 /* RFC 1890 */
+#define PT_DVI4_11025 16 /* from Joseph Di Pol of Sun; see the Web page */
+#define PT_DVI4_22050 17 /* from Joseph Di Pol of Sun; see the Web page */
+#define PT_G729 18
+#define PT_CELB 25 /* RFC 2029 */
+#define PT_JPEG 26 /* RFC 2435 */
+#define PT_NV 28 /* RFC 1890 */
+#define PT_H261 31 /* RFC 2032 */
+#define PT_MPV 32 /* RFC 2250 */
+#define PT_MP2T 33 /* RFC 2250 */
+#define PT_H263 34 /* from Chunrong Zhu of Intel; see the Web page */
+
+static const value_string rtp_payload_type_vals[] =
+{
+ { PT_PCMU, "ITU-T G.711 PCMU" },
+ { PT_1016, "USA Federal Standard FS-1016" },
+ { PT_G721, "ITU-T G.721" },
+ { PT_GSM, "GSM 06.10" },
+ { PT_G723, "ITU-T G.723" },
+ { PT_DVI4_8000, "DVI4 8000 samples/s" },
+ { PT_DVI4_16000, "DVI4 16000 samples/s" },
+ { PT_LPC, "Experimental linear predictive encoding from Xerox PARC" },
+ { PT_PCMA, "ITU-T G.711 PCMA" },
+ { PT_G722, "ITU-T G.722" },
+ { PT_L16_STEREO, "16-bit uncompressed audio, stereo" },
+ { PT_L16_MONO, "16-bit uncompressed audio, monaural" },
+ { PT_QCELP, "Qualcomm Code Excited Linear Predictive coding" },
+ { PT_CN, "Comfort noise" },
+ { PT_MPA, "MPEG-I/II Audio"},
+ { PT_G728, "ITU-T G.728" },
+ { PT_DVI4_11025, "DVI4 11025 samples/s" },
+ { PT_DVI4_22050, "DVI4 22050 samples/s" },
+ { PT_G729, "ITU-T G.729" },
+ { PT_CELB, "Sun CellB video encoding" },
+ { PT_JPEG, "JPEG-compressed video" },
+ { PT_NV, "'nv' program" },
+ { PT_H261, "ITU-T H.261" },
+ { PT_MPV, "MPEG-I/II Video"},
+ { PT_MP2T, "MPEG-II transport streams"},
+ { PT_H263, "ITU-T H.263" },
+ { 0, NULL },
+};
+
+
+typedef const guint8 * ip_addr_p;
+
+static const gchar FWD_LABEL_TEXT[] = "Select a forward stream with left mouse button";
+static const gchar REV_LABEL_TEXT[] = "Select a reverse stream with SHIFT + left mouse button";
+
+/****************************************************************************/
+/* pointer to the one and only dialog window */
+static GtkWidget *rtp_stream_dlg = NULL;
+
+/* save as dialog box */
+static GtkWidget *rtpstream_save_dlg = NULL;
+static GtkWidget *clist = NULL;
+static GtkWidget *label_fwd = NULL;
+static GtkWidget *label_rev = NULL;
+
+static rtp_stream_info_t* selected_stream_fwd = NULL; /* current selection */
+static rtp_stream_info_t* selected_stream_rev = NULL; /* current selection for reversed */
+static GList *last_list = NULL;
+
+
+/****************************************************************************/
+/* append a line to clist */
+static void add_to_clist(rtp_stream_info_t* strinfo)
+{
+ gint added_row;
+ gchar *data[8];
+ gchar field[8][30];
+
+ data[0]=&field[0][0];
+ data[1]=&field[1][0];
+ data[2]=&field[2][0];
+ data[3]=&field[3][0];
+ data[4]=&field[4][0];
+ data[5]=&field[5][0];
+ data[6]=&field[6][0];
+ data[7]=&field[7][0];
+
+ g_snprintf(field[0], 20, "%s", ip_to_str((const guint8*)&(strinfo->src_addr)));
+ g_snprintf(field[1], 20, "%u", strinfo->src_port);
+ g_snprintf(field[2], 20, "%s", ip_to_str((const guint8*)&(strinfo->dest_addr)));
+ g_snprintf(field[3], 20, "%u", strinfo->dest_port);
+ g_snprintf(field[4], 20, "%u", strinfo->ssrc);
+ g_snprintf(field[5], 30, "%s", val_to_str(strinfo->pt, rtp_payload_type_vals,
+ "Unknown (%u)"));
+ g_snprintf(field[6], 20, "%u", strinfo->npackets);
+ /* XXX: Comment field is not used for the moment */
+/* g_snprintf(field[7], 20, "%s", "");*/
+
+ added_row = gtk_clist_append(GTK_CLIST(clist), data);
+
+ /* set data pointer of last row to point to user data for that row */
+ gtk_clist_set_row_data(GTK_CLIST(clist), added_row, strinfo);
+}
+
+/****************************************************************************/
+static void save_stream_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+ /* Note that we no longer have a Save voice info dialog box. */
+ rtpstream_save_dlg = NULL;
+}
+
+/****************************************************************************/
+/* save in a file */
+static void save_stream_ok_cb(GtkWidget *ok_bt _U_, gpointer user_data _U_)
+{
+ gchar *g_dest;
+
+ if (!selected_stream_fwd)
+ return;
+
+ g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (rtpstream_save_dlg)));
+
+ /* Perhaps the user specified a directory instead of a file.
+ Check whether they did. */
+ if (test_for_directory(g_dest) == EISDIR) {
+ /* It's a directory - set the file selection box to display it. */
+ set_last_open_dir(g_dest);
+ g_free(g_dest);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(rtpstream_save_dlg), last_open_dir);
+ return;
+ }
+
+ rtpstream_save(selected_stream_fwd, g_dest);
+
+ gtk_widget_destroy(GTK_WIDGET(rtpstream_save_dlg));
+}
+
+
+/****************************************************************************/
+/* CALLBACKS */
+/****************************************************************************/
+static void
+rtpstream_on_destroy (GtkObject *object _U_,
+ gpointer user_data _U_)
+{
+ /* Is there a save voice window open? */
+ if (rtpstream_save_dlg != NULL)
+ gtk_widget_destroy(rtpstream_save_dlg);
+
+ /* Note that we no longer have a "RTP Analyse" dialog box. */
+ rtp_stream_dlg = NULL;
+}
+
+
+/****************************************************************************/
+static void
+rtpstream_on_unselect (GtkButton *button _U_,
+ gpointer user_data _U_)
+{
+ selected_stream_fwd = NULL;
+ selected_stream_rev = NULL;
+ gtk_clist_unselect_all(GTK_CLIST(clist));
+ gtk_label_set_text(GTK_LABEL(label_fwd), FWD_LABEL_TEXT);
+ gtk_label_set_text(GTK_LABEL(label_rev), REV_LABEL_TEXT);
+}
+
+
+/****************************************************************************/
+/*
+static void
+rtpstream_on_goto (GtkButton *button _U_,
+ gpointer user_data _U_)
+{
+ if (selected_stream_fwd)
+ {
+ goto_frame(&cfile, selected_stream_fwd->first_frame_num);
+ }
+}
+*/
+
+
+/****************************************************************************/
+static void
+rtpstream_on_save (GtkButton *button _U_,
+ gpointer data _U_)
+{
+ rtpstream_tapinfo_t* tapinfo = data;
+
+ GtkWidget *vertb;
+ GtkWidget *ok_bt;
+
+ if (!selected_stream_fwd)
+ return;
+
+ if (rtpstream_save_dlg != NULL) {
+ /* There's already a Save dialog box; reactivate it. */
+ reactivate_window(rtpstream_save_dlg);
+ return;
+ }
+
+ rtpstream_save_dlg = gtk_file_selection_new("Ethereal: Save selected stream in rtpdump ('-F dump') format");
+ gtk_signal_connect(GTK_OBJECT(rtpstream_save_dlg), "destroy",
+ GTK_SIGNAL_FUNC(save_stream_destroy_cb), NULL);
+
+ /* Container for each row of widgets */
+ vertb = gtk_vbox_new(FALSE, 0);
+ gtk_container_border_width(GTK_CONTAINER(vertb), 5);
+ gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(rtpstream_save_dlg)->action_area),
+ vertb, FALSE, FALSE, 0);
+ gtk_widget_show (vertb);
+
+ ok_bt = GTK_FILE_SELECTION(rtpstream_save_dlg)->ok_button;
+/* OBJECT_SET_DATA(ok_bt, "user_data", tapinfo);*/
+
+ /* Connect the cancel_button to destroy the widget */
+ SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(rtpstream_save_dlg)->cancel_button,
+ "clicked", (GtkSignalFunc)gtk_widget_destroy,
+ rtpstream_save_dlg);
+
+ /* Catch the "key_press_event" signal in the window, so that we can catch
+ the ESC key being pressed and act as if the "Cancel" button had
+ been selected. */
+ dlg_set_cancel(rtpstream_save_dlg, GTK_FILE_SELECTION(rtpstream_save_dlg)->cancel_button);
+
+ gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+ GTK_SIGNAL_FUNC(save_stream_ok_cb), tapinfo);
+
+ gtk_widget_show(rtpstream_save_dlg);
+}
+
+
+/****************************************************************************/
+static void
+rtpstream_on_mark (GtkButton *button _U_,
+ gpointer user_data _U_)
+{
+ if (selected_stream_fwd==NULL && selected_stream_rev==NULL)
+ return;
+ rtpstream_mark(selected_stream_fwd, selected_stream_rev);
+}
+
+
+#define MAX_FILTER_LENGTH 320
+
+/****************************************************************************/
+static void
+rtpstream_on_filter (GtkButton *button _U_,
+ gpointer user_data _U_)
+{
+ gchar filter_string[MAX_FILTER_LENGTH] = "";
+ gchar filter_string_rev[MAX_FILTER_LENGTH] = "";
+
+ if (selected_stream_fwd==NULL && selected_stream_rev==NULL)
+ return;
+
+ if (selected_stream_fwd)
+ {
+ g_snprintf(filter_string, MAX_FILTER_LENGTH,
+ "(ip.src==%s && udp.srcport==%u && ip.dst==%s && udp.dstport==%u && rtp.ssrc==%u)",
+ ip_to_str((const guint8*)&(selected_stream_fwd->src_addr)),
+ selected_stream_fwd->src_port,
+ ip_to_str((const guint8*)&(selected_stream_fwd->dest_addr)),
+ selected_stream_fwd->dest_port,
+ selected_stream_fwd->ssrc);
+
+ if (selected_stream_rev)
+ {
+ strcat(filter_string, " || ");
+ }
+ }
+
+ if (selected_stream_rev)
+ {
+ g_snprintf(filter_string_rev, MAX_FILTER_LENGTH,
+ "(ip.src==%s && udp.srcport==%u && ip.dst==%s && udp.dstport==%u && rtp.ssrc==%u)",
+ ip_to_str((const guint8*)&(selected_stream_rev->src_addr)),
+ selected_stream_rev->src_port,
+ ip_to_str((const guint8*)&(selected_stream_rev->dest_addr)),
+ selected_stream_rev->dest_port,
+ selected_stream_rev->ssrc);
+ strcat(filter_string, filter_string_rev);
+ }
+
+ gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), filter_string);
+/*
+ filter_packets(&cfile, filter_string);
+ rtpstream_dlg_update(rtpstream_get_info()->strinfo_list);
+*/
+}
+
+
+/****************************************************************************/
+static void
+rtpstream_on_close (GtkButton *button _U_,
+ gpointer user_data _U_)
+{
+ gtk_grab_remove(rtp_stream_dlg);
+ gtk_widget_destroy(rtp_stream_dlg);
+}
+
+
+/****************************************************************************/
+static void
+rtpstream_on_analyse (GtkButton *button _U_,
+ gpointer user_data _U_)
+{
+ guint32 ip_src_fwd = 0;
+ guint16 port_src_fwd = 0;
+ guint32 ip_dst_fwd = 0;
+ guint16 port_dst_fwd = 0;
+ guint32 ssrc_fwd = 0;
+ guint32 ip_src_rev = 0;
+ guint16 port_src_rev = 0;
+ guint32 ip_dst_rev = 0;
+ guint16 port_dst_rev = 0;
+ guint32 ssrc_rev = 0;
+
+ if (selected_stream_fwd) {
+ ip_src_fwd = selected_stream_fwd->src_addr;
+ port_src_fwd = selected_stream_fwd->src_port;
+ ip_dst_fwd = selected_stream_fwd->dest_addr;
+ port_dst_fwd = selected_stream_fwd->dest_port;
+ ssrc_fwd = selected_stream_fwd->ssrc;
+ }
+
+ if (selected_stream_rev) {
+ ip_src_rev = selected_stream_rev->src_addr;
+ port_src_rev = selected_stream_rev->src_port;
+ ip_dst_rev = selected_stream_rev->dest_addr;
+ port_dst_rev = selected_stream_rev->dest_port;
+ ssrc_rev = selected_stream_rev->ssrc;
+ }
+
+ rtp_analysis(
+ ip_src_fwd,
+ port_src_fwd,
+ ip_dst_fwd,
+ port_dst_fwd,
+ ssrc_fwd,
+ ip_src_rev,
+ port_src_rev,
+ ip_dst_rev,
+ port_dst_rev,
+ ssrc_rev
+ );
+}
+
+
+/****************************************************************************/
+/* This should be the callback function called upon a user-defined
+ * event "signal_rtpstream_update", but i didn't knoow how to do with GTK
+static void
+rtpstream_on_update (GtkButton *button _U_,
+ gpointer user_data _U_)
+{
+ rtpstream_dlg_update(rtpstream_get_info()->strinfo_list);
+}
+*/
+
+/****************************************************************************/
+/* when the user selects a row in the stream list */
+static void
+rtpstream_on_select_row(GtkCList *clist,
+ gint row _U_,
+ gint column _U_,
+ GdkEventButton *event _U_,
+ gpointer user_data _U_)
+{
+ gchar label_text[80];
+
+ /* update the labels */
+ if (event->state & GDK_SHIFT_MASK) {
+ selected_stream_rev = gtk_clist_get_row_data(GTK_CLIST(clist), row);
+ g_snprintf(label_text, 80, "Reverse: %s:%u -> %s:%u, SSRC=%u",
+ ip_to_str((ip_addr_p)&selected_stream_rev->src_addr),
+ selected_stream_rev->src_port,
+ ip_to_str((ip_addr_p)&selected_stream_rev->dest_addr),
+ selected_stream_rev->dest_port,
+ selected_stream_rev->ssrc
+ );
+ gtk_label_set_text(GTK_LABEL(label_rev), label_text);
+ }
+ else {
+ selected_stream_fwd = gtk_clist_get_row_data(GTK_CLIST(clist), row);
+ g_snprintf(label_text, 80, "Forward: %s:%u -> %s:%u, SSRC=%u",
+ ip_to_str((ip_addr_p)&selected_stream_fwd->src_addr),
+ selected_stream_fwd->src_port,
+ ip_to_str((ip_addr_p)&selected_stream_fwd->dest_addr),
+ selected_stream_fwd->dest_port,
+ selected_stream_fwd->ssrc
+ );
+ gtk_label_set_text(GTK_LABEL(label_fwd), label_text);
+ }
+
+/*
+ gtk_widget_set_sensitive(save_bt, TRUE);
+ gtk_widget_set_sensitive(filter_bt, TRUE);
+ gtk_widget_set_sensitive(mark_bt, TRUE);
+*/
+ /* TODO: activate other buttons when implemented */
+}
+
+
+/****************************************************************************/
+/* INTERFACE */
+/****************************************************************************/
+
+static void rtpstream_dlg_create (void)
+{
+ /* these are global static now:
+ GtkWidget *clist = NULL;
+ GtkWidget *label_fwd = NULL;
+ GtkWidget *label_rev = NULL;
+ */
+ GtkWidget *rtpstream_dlg_w;
+ GtkWidget *dialog_vbox1;
+ GtkWidget *vbox1;
+ GtkWidget *label10;
+ GtkWidget *scrolledwindow1;
+ GtkWidget *label2;
+ GtkWidget *label3;
+ GtkWidget *label4;
+ GtkWidget *label5;
+ GtkWidget *label6;
+ GtkWidget *label7;
+ GtkWidget *label8;
+/* GtkWidget *label9;*/
+ GtkWidget *dialog_action_area1;
+ GtkWidget *hbuttonbox2;
+/* GtkWidget *bt_goto;*/
+ GtkWidget *bt_unselect;
+ GtkWidget *bt_save;
+ GtkWidget *bt_frames;
+ GtkWidget *bt_filter;
+ GtkWidget *bt_analyse;
+ GtkWidget *bt_close;
+
+ rtpstream_dlg_w = gtk_dialog_new ();
+ gtk_window_set_title (GTK_WINDOW (rtpstream_dlg_w), "Ethereal: RTP Streams");
+
+ dialog_vbox1 = GTK_DIALOG (rtpstream_dlg_w)->vbox;
+ gtk_widget_show (dialog_vbox1);
+
+ vbox1 = gtk_vbox_new (FALSE, 0);
+ gtk_widget_ref (vbox1);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "vbox1", vbox1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (vbox1);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), vbox1, TRUE, TRUE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox1), 8);
+
+ label10 = gtk_label_new ("Detected RTP streams. Choose one for forward and reverse direction for analysis");
+ gtk_widget_ref (label10);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label10", label10,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label10);
+ gtk_box_pack_start (GTK_BOX (vbox1), label10, FALSE, FALSE, 0);
+ gtk_widget_set_usize (label10, -2, 32);
+
+ scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_ref (scrolledwindow1);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "scrolledwindow1", scrolledwindow1,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (scrolledwindow1);
+ gtk_box_pack_start (GTK_BOX (vbox1), scrolledwindow1, TRUE, TRUE, 0);
+
+ clist = gtk_clist_new (7); /* defines number of columns */
+ gtk_widget_ref (clist);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "clist", clist,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (clist);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow1), clist);
+ gtk_widget_set_usize (clist, 640, 200);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 0, 100);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 1, 50);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 2, 100);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 3, 50);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 4, 80);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 5, 118);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 6, 60);
+/* gtk_clist_set_column_width (GTK_CLIST (clist), 7, 51);*/
+ gtk_clist_column_titles_show (GTK_CLIST (clist));
+
+ label2 = gtk_label_new ("Src IP addr");
+ gtk_widget_ref (label2);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label2", label2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label2);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 0, label2);
+
+ label3 = gtk_label_new ("Src port");
+ gtk_widget_ref (label3);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label3", label3,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label3);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 1, label3);
+
+ label4 = gtk_label_new ("Dest IP addr");
+ gtk_widget_ref (label4);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label4", label4,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label4);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 2, label4);
+
+ label5 = gtk_label_new ("Dest port");
+ gtk_widget_ref (label5);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label5", label5,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label5);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 3, label5);
+
+ label6 = gtk_label_new ("SSRC");
+ gtk_widget_ref (label6);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label6", label6,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label6);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 4, label6);
+ gtk_widget_set_usize (label6, 80, -2);
+
+ label7 = gtk_label_new ("Payload");
+ gtk_widget_ref (label7);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label7", label7,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label7);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 5, label7);
+
+ label8 = gtk_label_new ("Packets");
+ gtk_widget_ref (label8);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label8", label8,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label8);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 6, label8);
+/*
+ label9 = gtk_label_new ("Comment");
+ gtk_widget_ref (label9);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label9", label9,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label9);
+ gtk_clist_set_column_widget (GTK_CLIST (clist), 7, label9);
+*/
+ label_fwd = gtk_label_new (FWD_LABEL_TEXT);
+ gtk_widget_ref (label_fwd);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label_fwd", label_fwd,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label_fwd);
+ gtk_box_pack_start (GTK_BOX (vbox1), label_fwd, FALSE, FALSE, 0);
+ gtk_label_set_justify (GTK_LABEL (label_fwd), GTK_JUSTIFY_LEFT);
+
+ label_rev = gtk_label_new (REV_LABEL_TEXT);
+ gtk_widget_ref (label_rev);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "label_rev", label_rev,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (label_rev);
+ gtk_box_pack_start (GTK_BOX (vbox1), label_rev, FALSE, FALSE, 0);
+ gtk_label_set_justify (GTK_LABEL (label_rev), GTK_JUSTIFY_LEFT);
+
+ dialog_action_area1 = GTK_DIALOG (rtpstream_dlg_w)->action_area;
+ gtk_widget_show (dialog_action_area1);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog_action_area1), 10);
+
+ hbuttonbox2 = gtk_hbutton_box_new ();
+ gtk_widget_ref (hbuttonbox2);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "hbuttonbox2", hbuttonbox2,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (hbuttonbox2);
+ gtk_box_pack_start (GTK_BOX (dialog_action_area1), hbuttonbox2, FALSE, FALSE, 0);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox2), GTK_BUTTONBOX_END);
+ gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox2), 0);
+
+ bt_unselect = gtk_button_new_with_label ("Unselect");
+ gtk_widget_ref (bt_unselect);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "bt_unselect", bt_unselect,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (bt_unselect);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), bt_unselect);
+ GTK_WIDGET_SET_FLAGS (bt_unselect, GTK_CAN_DEFAULT);
+/*
+ bt_goto = gtk_button_new_with_label ("Go to Frame");
+ gtk_widget_ref (bt_goto);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "bt_goto", bt_goto,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (bt_goto);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), bt_goto);
+ GTK_WIDGET_SET_FLAGS (bt_goto, GTK_CAN_DEFAULT);
+*/
+ bt_save = gtk_button_new_with_label ("Save as...");
+ gtk_widget_ref (bt_save);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "bt_save", bt_save,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (bt_save);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), bt_save);
+ GTK_WIDGET_SET_FLAGS (bt_save, GTK_CAN_DEFAULT);
+
+ bt_frames = gtk_button_new_with_label ("Mark frames");
+ gtk_widget_ref (bt_frames);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "bt_frames", bt_frames,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (bt_frames);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), bt_frames);
+ GTK_WIDGET_SET_FLAGS (bt_frames, GTK_CAN_DEFAULT);
+
+ bt_filter = gtk_button_new_with_label ("Set filter");
+ gtk_widget_ref (bt_filter);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "bt_filter", bt_filter,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (bt_filter);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), bt_filter);
+ GTK_WIDGET_SET_FLAGS (bt_filter, GTK_CAN_DEFAULT);
+
+ bt_analyse = gtk_button_new_with_label ("Analyse");
+ gtk_widget_ref (bt_analyse);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "bt_analyse", bt_analyse,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (bt_analyse);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), bt_analyse);
+ GTK_WIDGET_SET_FLAGS (bt_analyse, GTK_CAN_DEFAULT);
+
+ bt_close = gtk_button_new_with_label ("Close");
+ gtk_widget_ref (bt_close);
+ gtk_object_set_data_full (GTK_OBJECT (rtpstream_dlg_w), "bt_close", bt_close,
+ (GtkDestroyNotify) gtk_widget_unref);
+ gtk_widget_show (bt_close);
+ gtk_container_add (GTK_CONTAINER (hbuttonbox2), bt_close);
+ GTK_WIDGET_SET_FLAGS (bt_close, GTK_CAN_DEFAULT);
+
+ gtk_signal_connect (GTK_OBJECT (rtpstream_dlg_w), "destroy",
+ GTK_SIGNAL_FUNC (rtpstream_on_destroy),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (clist), "select_row",
+ GTK_SIGNAL_FUNC (rtpstream_on_select_row),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (bt_unselect), "clicked",
+ GTK_SIGNAL_FUNC (rtpstream_on_unselect),
+ NULL);
+/*
+ gtk_signal_connect (GTK_OBJECT (bt_goto), "clicked",
+ GTK_SIGNAL_FUNC (rtpstream_on_goto),
+ NULL);
+*/
+ gtk_signal_connect (GTK_OBJECT (bt_save), "clicked",
+ GTK_SIGNAL_FUNC (rtpstream_on_save),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (bt_frames), "clicked",
+ GTK_SIGNAL_FUNC (rtpstream_on_mark),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (bt_filter), "clicked",
+ GTK_SIGNAL_FUNC (rtpstream_on_filter),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (bt_analyse), "clicked",
+ GTK_SIGNAL_FUNC (rtpstream_on_analyse),
+ NULL);
+ gtk_signal_connect (GTK_OBJECT (bt_close), "clicked",
+ GTK_SIGNAL_FUNC (rtpstream_on_close),
+ NULL);
+/* XXX: see rtpstream_on_update for comment
+ gtk_signal_connect (GTK_OBJECT (top_level), "signal_rtpstream_update",
+ GTK_SIGNAL_FUNC (rtpstream_on_update),
+ NULL);
+*/
+
+ if (clist) {
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 2, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 3, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_LEFT);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 6, GTK_JUSTIFY_RIGHT);
+/* gtk_clist_set_column_justification(GTK_CLIST(clist), 7, GTK_JUSTIFY_CENTER);*/
+ }
+
+ rtpstream_on_unselect(NULL, NULL);
+
+ rtp_stream_dlg = rtpstream_dlg_w;
+}
+
+
+/****************************************************************************/
+/* PUBLIC */
+/****************************************************************************/
+
+/****************************************************************************/
+/* update the contents of the dialog box clist */
+/* list: pointer to list of rtp_stream_info_t* */
+void rtpstream_dlg_update(GList *list)
+{
+ if (rtp_stream_dlg != NULL) {
+ gtk_clist_clear(GTK_CLIST(clist));
+
+ list = g_list_first(list);
+ while (list)
+ {
+ add_to_clist((rtp_stream_info_t*)(list->data));
+ list = g_list_next(list);
+ }
+
+ rtpstream_on_unselect(NULL, NULL);
+ }
+
+ last_list = list;
+}
+
+
+/****************************************************************************/
+/* update the contents of the dialog box clist */
+/* list: pointer to list of rtp_stream_info_t* */
+void rtpstream_dlg_show(GList *list)
+{
+ if (rtp_stream_dlg != NULL) {
+ /* There's already a dialog box; reactivate it. */
+ reactivate_window(rtp_stream_dlg);
+ /* Another list since last call? */
+ if (list != last_list) {
+ rtpstream_dlg_update(list);
+ }
+ }
+ else {
+ /* Create and show the dialog box */
+ rtpstream_dlg_create();
+ rtpstream_dlg_update(list);
+ gtk_widget_show(rtp_stream_dlg);
+ }
+}
+
+
+/****************************************************************************/
+/* entry point when called via the GTK menu */
+void rtpstream_launch(GtkWidget *w _U_, gpointer data _U_)
+{
+ /* Show the dialog box */
+ rtpstream_dlg_show(rtpstream_get_info()->strinfo_list);
+}
+
+/****************************************************************************/
+void
+register_tap_menu_rtp_stream(void)
+{
+ register_tap_menu_item("Statistics/RTP Streams/Show All...",
+ rtpstream_launch, NULL, NULL);
+}
diff --git a/gtk/rtp_stream_dlg.h b/gtk/rtp_stream_dlg.h
new file mode 100644
index 0000000000..69f7dd9cee
--- /dev/null
+++ b/gtk/rtp_stream_dlg.h
@@ -0,0 +1,45 @@
+/* rtp_stream_dlg.h
+ * RTP streams summary addition for ethereal
+ *
+ * $Id: rtp_stream_dlg.h,v 1.1 2003/09/24 07:48:11 guy Exp $
+ *
+ * Copyright 2003, Alcatel Business Systems
+ * By Lars Ruoff <lars.ruoff@gmx.net>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef RTP_STREAM_DLG_H_INCLUDED
+#define RTP_STREAM_DLG_H_INCLUDED
+
+#include <gtk/gtk.h>
+
+/*
+* Create or reactivate the rtp streams dialog box.
+* list: pointer to list of rtp_stream_info_t*
+*/
+void rtpstream_dlg_show(GList *list);
+
+/*
+* Update the contents of the dialog box clist with that of list.
+* list: pointer to list of rtp_stream_info_t*
+*/
+void rtpstream_dlg_update(GList *list);
+
+#endif /*RTP_STREAM_DLG_H_INCLUDED*/
diff --git a/gtk/tap_rtp.c b/gtk/tap_rtp.c
deleted file mode 100644
index 0682b5400f..0000000000
--- a/gtk/tap_rtp.c
+++ /dev/null
@@ -1,1761 +0,0 @@
-/*
- * tap_rtp.c
- *
- * $Id: tap_rtp.c,v 1.17 2003/09/19 07:24:39 guy Exp $
- *
- * RTP analysing addition for ethereal
- *
- * Copyright 2003, Iskratel, Ltd, Kranj
- * By Miha Jemec <m.jemec@iskratel.si>
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
- * Copyright 1998 Gerald Combs
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * This tap works as follows:
- * When the user clicks on the RTP analisys button, we first check if it is a RTP packet.
- * If yes we store the SSRC, ip, and port values. Then the tap is registered and the
- * redissect_packets() routine is called. So we go through all the RTP packets and search
- * for SSRC of reversed connection (it has inversed socket parameters). If more than one
- * is found a window is displayed where the user can select the appropriate from the list.
- * Rigth now we have the information about the converstion we are looking for (both SSRC).
- * The redissect_packets() routine is called again. This time whenever a RTP packet with
- * matching SSRC values arrives, we store all the information we need (number, sequence
- * number, arrival time, ...) and compute the delay, jitter and wrong sequence number.
- * We add this values to CList. If the RTP packet carries voice in g711 alaw or ulaw, we
- * also store this voice information in a temp file. Window is displayed.
- * Then three buttons are available: Close, Refresh and Save voice.
- * The Refresh button calls the redissect_packets() routine again. It goes through the packets
- * again and does all the calculation again (if capturing in real time this means that some
- * more packets could come and can be computed in statistic). It also writes the sound
- * data again.
- * The Save voice button opens the dialog where we can choose the file name, format (not yet)
- * and direction we want to save. Currently it works only with g711 alaw and ulaw, and if the
- * length of captured packets is equal the length of packets on wire
- *
- * To do:
- * - Support for saving voice in more different formats and with more different codecs:
- * Since this should be portable to all OS, there is only possibility to save the
- * voice in a file and not play it directly through the sound card. There are enough
- * players on all platforms, that are doing right this. What about the format?
- * Currently there is only support for saving as an .au file (ulaw, 8000 Hz, 8bit)
- * There are many players for this format on all platforms (for example Windows Media Player
- * under Windows, command play under Linux). Support will be added for wav format and
- * possibility to save with two channels (separate channel for each direction)
- *
- * - Support for more codecs. Now you can save voice only if the codec is g.711 alaw or ulaw.
- *
- * - right now, the reversed connection must have the same (only inversed) ip and port numbers.
- * I think that there is no reason that in special cases the reversed connection would not use
- * some different port or even the IP combination (please correct me if I am wrong).
- * So this will be added soon.
- *
- * - some more statistics (delay and jitter distribution)
- *
- * - GTK2 implementation
- *
- * - grammar correction
- *
- * - some more testing (other OS)
- *
- * XXX Problems:
- *
- * - problem with statistics for lost (late, duplicated) packets. How to make the statistic
- * more resistant to special (bizarre) arrival of sequence numbers
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdio.h>
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#include <gtk/gtk.h>
-#include "globals.h"
-#include <string.h>
-#include "epan/packet_info.h"
-#include <epan/epan_dissect.h>
-#include <epan/filesystem.h>
-#include "../tap.h"
-#include "../register.h"
-#include "../packet-rtp.h"
-#include "file_dlg.h"
-#include "dlg_utils.h"
-#include "ui_util.h"
-#include "simple_dialog.h"
-#include "menu.h"
-#include "main.h"
-#include <math.h>
-#include "progress_dlg.h"
-#include "compat_macros.h"
-#include "../g711.h"
-#include "../util.h"
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <fcntl.h>
-
-#ifdef HAVE_IO_H
-#include <io.h> /* open/close on win32 */
-#endif
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-static GtkWidget *rtp_w = NULL;
-static GtkWidget *save_voice_as_w = NULL;
-static GtkWidget *save_csv_as_w = NULL;
-static GtkWidget *main_vb;
-static GtkWidget *clist;
-static GtkWidget *clist_r;
-static GtkWidget *max;
-static GtkWidget *max_r;
-
-static char f_tempname[128+1], r_tempname[128+1];
-
-/* type of error when saving voice in a file didn't succeed */
-typedef enum {
- TAP_RTP_WRONG_CODEC,
- TAP_RTP_WRONG_LENGTH,
- TAP_RTP_PADDING_ERROR,
- TAP_RTP_FILE_OPEN_ERROR,
- TAP_RTP_NO_DATA
-} error_type_t;
-
-typedef enum {
- FIRST_PACKET,
- MARK_SET,
- NORMAL_PACKET
-} packet_type;
-
-/* structure that holds the information about the forward and reversed connection */
-struct _info_direction {
- gboolean first_packet;
- guint16 seq_num;
- guint32 timestamp;
- guint32 delta_timestamp;
- double delay;
- double jitter;
- double time;
- double start_time;
- double max_delay;
- guint32 max_nr;
- guint16 start_seq_nr;
- guint16 stop_seq_nr;
- guint32 total_nr;
- guint32 sequence;
- gboolean under;
- gint cycles;
- FILE *fp;
- guint32 count;
- error_type_t error_type;
- gboolean saved;
-};
-
-/* structure that holds general information about the connection
- * and structures for both directions */
-typedef struct _info_stat {
- gchar source[16];
- gchar destination[16];
- guint16 srcport;
- guint16 dstport;
- guint32 ssrc_forward;
- guint32 ssrc_reversed;
- guint32 *ssrc_tmp;
- gboolean search_ssrc;
- guint reversed_ip;
- guint reversed_ip_and_port;
- struct _info_direction forward;
- struct _info_direction reversed;
-} info_stat;
-
-int do_calculation(gboolean direc, packet_type pkt_type, void *ptrs, void *vpri, void *vpinfo);
-static gboolean copy_file(gchar *, /*gint,*/ gint, void *);
-
-/* when there is a [re]reading of packet's */
-static void
-rtp_reset(void *prs)
-{
- info_stat *rs=prs;
-
- rs->forward.first_packet = TRUE;
- rs->reversed.first_packet = TRUE;
- rs->forward.max_delay = 0;
- rs->reversed.max_delay = 0;
- rs->forward.delay = 0;
- rs->reversed.delay = 0;
- rs->forward.jitter = 0;
- rs->reversed.jitter = 0;
- rs->forward.timestamp = 0;
- rs->reversed.timestamp = 0;
- rs->forward.max_nr = 0;
- rs->reversed.max_nr = 0;
- rs->forward.total_nr = 0;
- rs->reversed.total_nr = 0;
- rs->forward.sequence = 0;
- rs->reversed.sequence = 0;
- rs->forward.start_seq_nr = 0;
- rs->reversed.start_seq_nr = 1; /* 1 is ok (for statistics in reversed direction) */
- rs->forward.stop_seq_nr = 0;
- rs->reversed.stop_seq_nr = 0;
- rs->forward.cycles = 0;
- rs->reversed.cycles = 0;
- rs->forward.under = FALSE;
- rs->reversed.under = FALSE;
- rs->forward.saved = FALSE;
- rs->reversed.saved = FALSE;
- rs->forward.start_time = 0;
- rs->reversed.start_time = 0;
- rs->forward.time = 0;
- rs->reversed.time = 0;
- rs->forward.count = 0;
- rs->reversed.count = 0;
- /* XXX check for error at fclose? */
- rs->forward.fp = freopen(f_tempname, "wb", rs->forward.fp);
- if (rs->forward.fp == NULL)
- rs->forward.error_type = TAP_RTP_FILE_OPEN_ERROR;
- rs->reversed.fp = freopen(r_tempname, "wb", rs->reversed.fp);
- if (rs->reversed.fp == NULL)
- rs->reversed.error_type = TAP_RTP_FILE_OPEN_ERROR;
- return;
-}
-
-/* here we can redraw the output */
-/* not used yet */
-static void rtp_draw(void *prs _U_)
-{
- return;
-}
-
-/* when we are finished with redisection, we add the label for the statistic */
-static void draw_stat(void *prs)
-{
- info_stat *rs=prs;
- gchar label_max[200];
- guint32 f_expected = (rs->forward.stop_seq_nr + rs->forward.cycles*65536)
- - rs->forward.start_seq_nr + 1;
- guint32 r_expected = (rs->reversed.stop_seq_nr + rs->reversed.cycles*65536)
- - rs->reversed.start_seq_nr + 1;
- gint32 f_lost = f_expected - rs->forward.total_nr;
- gint32 r_lost = r_expected - rs->reversed.total_nr;
-
- g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
- "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
- " Sequence error = %u",
- rs->forward.max_delay, rs->forward.max_nr, rs->forward.total_nr,
- f_expected, f_lost, rs->forward.sequence);
-
- gtk_label_set_text(GTK_LABEL(max), label_max);
-
- g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
- "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
- " Sequence error = %u",
- rs->reversed.max_delay, rs->reversed.max_nr, rs->reversed.total_nr,
- r_expected, r_lost, rs->reversed.sequence);
-
- gtk_label_set_text(GTK_LABEL(max_r), label_max);
-
- /* could be done somewhere else, but can be here as well */
- /* if this is true, then we don't have any reversed connection, so the error type
- * will be no data. This applies only the reversed connection */
- if (rs->reversed_ip_and_port == 0)
- rs->reversed.error_type = TAP_RTP_NO_DATA;
-
- return ;
-}
-
-/* append a line to clist */
-/* XXX is there a nicer way to make these assignements? */
-static void add_to_clist(gboolean forward, guint32 number, guint16 seq_num,
- double delay, double jitter, gboolean status, gboolean marker, gchar *timeStr, guint32 pkt_len)
-{
- gchar *data[8];
- gchar field[8][30];
-
- data[0]=&field[0][0];
- data[1]=&field[1][0];
- data[2]=&field[2][0];
- data[3]=&field[3][0];
- data[4]=&field[4][0];
- data[5]=&field[5][0];
- data[6]=&field[6][0];
- data[7]=&field[7][0];
-
- g_snprintf(field[0], 20, "%u", number);
- g_snprintf(field[1], 20, "%u", seq_num);
- g_snprintf(field[2], 20, "%f", delay);
- g_snprintf(field[3], 20, "%f", jitter);
- g_snprintf(field[4], 20, "%s", marker? "SET" : "");
- g_snprintf(field[5], 29, "%s", status? "OK" : "NOK - Wrong sequence nr.");
- g_snprintf(field[6], 32, "%s", timeStr);
- g_snprintf(field[7], 20, "%u", pkt_len);
-
- gtk_clist_append(GTK_CLIST(forward? clist : clist_r), data);
-
-}
-
-/* whenever a RTP packet is seen by the tap listener */
-/* this function works as follows:
- * 1) packets that are not displayed are ignored
- * return
- * 2) are we searching what could be the reversed connection (looking for reversed SSRC)
- * if yes, do the parameters match (inversed IP and port combination from the forward one)?
- * if yes, do we already have this SSRC stored
- * if not store it
- * 3) if not, is current packet matching the forward direction
- * if yes, call the function that does the calculation and saves the voice info
- * 4) if not, is current packet matching the reversed connection
- * if yes, call the function that does the calculation and saves the voice info
- */
-static int rtp_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, void *vpri)
-{
- info_stat *rs=prs;
- struct _rtp_info *pri=vpri;
- guint i;
-
- /* we ignore packets that are not displayed */
- if (pinfo->fd->flags.passed_dfilter == 0)
- return 0;
-
- /* are we looking for the SSRC of the reversed connection? */
- if (rs->search_ssrc != FALSE) {
- /* XXX what should be the rules for reversed connection?
- * 1. It should should have same inversed IP and port numbers
- * 2. If none are found, only inversed IP's - is this possible?
- * 3. If none are found, there isn't any reversed connection
- * XXX is it possible that the conversation is not P2P?
- * Curretly it works only if it matches the number 1. */
-
- /* have we found inverse parameters? */
- if ( strcmp(ip_to_str(pinfo->src.data), rs->destination) == 0 &&
- strcmp( ip_to_str(pinfo->dst.data), rs->source) == 0 ) {
-
- /* do the ports also match? */
- if ((rs->srcport == pinfo->destport) && (rs->dstport == pinfo->srcport)) {
- /* ok, the ip and port combination does match
- * do we already have this ssrc stored */
- for(i=0; i< rs->reversed_ip_and_port; i++) {
- if (pri->info_sync_src == *(rs->ssrc_tmp+i) )
- return 0;
- }
-
- /* no, we found new ssrc, let's store it */
- rs->ssrc_tmp = (guint32*)g_realloc(rs->ssrc_tmp,
- (i+1)*sizeof(guint32));
- *(rs->ssrc_tmp+i) = pri->info_sync_src;
- rs->reversed_ip_and_port++;
- return 0;
- }
- /* no, only ip addresses match */
- /* XXX not implemented yet */
- else {
- rs->reversed_ip++;
- return 0;
- }
-
- }
- }
-
- /* ok, we are not looking for SSRC of the reversed connection */
- /* is it the forward direction? */
- else if (rs->ssrc_forward == pri->info_sync_src) {
- if (rs->forward.first_packet != FALSE)
- /* first argument is the direction TRUE == forward */
- return do_calculation(TRUE, FIRST_PACKET, &rs->forward, pri, pinfo);
- else if (pri->info_marker_set != FALSE)
- return do_calculation(TRUE, MARK_SET, &rs->forward, pri, pinfo);
- else
- return do_calculation(TRUE, NORMAL_PACKET, &rs->forward, pri, pinfo);
- }
- /* is it the reversed direction? */
- else if (rs->ssrc_reversed == pri->info_sync_src) {
- if (rs->reversed.first_packet != FALSE)
- return do_calculation(FALSE, FIRST_PACKET, &rs->reversed, pri, pinfo);
- else if (pri->info_marker_set != FALSE)
- return do_calculation(FALSE, MARK_SET, &rs->reversed, pri, pinfo);
- else
- return do_calculation(FALSE, NORMAL_PACKET, &rs->reversed, pri, pinfo);
- }
-
- return 0;
-}
-
-
-int do_calculation(gboolean direc, packet_type pkt_type, void *ptrs, void *vpri, void *vpinfo) {
-
- struct _info_direction *ptr=ptrs;
- struct _rtp_info *pri=vpri;
- packet_info *pinfo = vpinfo;
- guint i;
- double current_time;
- double current_jitter;
- guint8 *data;
- gint16 tmp;
- guint16 msecs;
- gchar timeStr[32];
-
- struct tm *tm_tmp;
- time_t then;
-
- then = pinfo->fd->abs_secs;
- msecs = (guint16)(pinfo->fd->abs_usecs/1000);
-
- tm_tmp = localtime(&then);
- snprintf(timeStr,32,"%02d/%02d/%04d %02d:%02d:%02d.%03d",
- tm_tmp->tm_mon + 1,
- tm_tmp->tm_mday,
- tm_tmp->tm_year + 1900,
- tm_tmp->tm_hour,
- tm_tmp->tm_min,
- tm_tmp->tm_sec,
- msecs);
- /* store the current time and calculate the current jitter */
- current_time = (double)pinfo->fd->rel_secs + (double) pinfo->fd->rel_usecs/1000000;
- current_jitter = ptr->jitter + ( fabs (current_time - (ptr->time) -
- ((double)(pri->info_timestamp)-(double)(ptr->timestamp))/8000)- ptr->jitter)/16;
- ptr->delay = current_time-(ptr->time);
-
- /* We have 3 possibilities:
- * is this the first packet we got in this direction? */
- if (pkt_type == FIRST_PACKET) {
- ptr->first_packet = FALSE;
- ptr->start_seq_nr = pri->info_seq_num;
- ptr->start_time = current_time;
- add_to_clist(direc, pinfo->fd->num, pri->info_seq_num, 0,
- pri->info_marker_set? TRUE: FALSE, TRUE, FALSE,
- timeStr, pinfo->fd->pkt_len);
- if (ptr->fp == NULL) {
- ptr->saved = FALSE;
- ptr->error_type = TAP_RTP_FILE_OPEN_ERROR;
- }
- else
- ptr->saved = TRUE;
- }
- /* or is it a packet with the mark bit set? */
- else if (pkt_type == MARK_SET) {
- ptr->delta_timestamp = pri->info_timestamp - ptr->timestamp;
- add_to_clist(direc, pinfo->fd->num, pri->info_seq_num, current_time - (ptr->time),
- current_jitter, ptr->seq_num+1 == pri->info_seq_num? TRUE: FALSE, TRUE, timeStr, pinfo->fd->pkt_len);
- }
- /* if neither then it is a "normal" packet pkt_type == NORMAL_PACKET */
- else {
- if (ptr->delay > ptr->max_delay) {
- ptr->max_delay = ptr->delay;
- ptr->max_nr = pinfo->fd->num;
- }
- add_to_clist(direc, pinfo->fd->num, pri->info_seq_num, current_time -(ptr->time),
- current_jitter , ptr->seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE, timeStr, pinfo->fd->pkt_len);
- }
-
- /* When calculating expected rtp packets the seq number can wrap around
- * so we have to count the number of cycles
- * Variable cycles counts the wraps around in forwarding connection and
- * under is flag that indicates where we are
- *
- * XXX how to determine number of cycles with all possible lost, late
- * and duplicated packets without any doubt? It seems to me, that
- * because of all possible combination of late, duplicated or lost
- * packets, this can only be more or less good approximation
- *
- * There are some combinations (rare but theoretically possible),
- * where below code won't work correctly - statistic may be wrong then.
- */
-
- /* so if the current sequence number is less than the start one
- * we assume, that there is another cycle running */
- if ((pri->info_seq_num < ptr->start_seq_nr) && (ptr->under == FALSE)){
- ptr->cycles++;
- ptr->under = TRUE;
- }
- /* what if the start seq nr was 0? Then the above condition will never
- * be true, so we add another condition. XXX The problem would arise
- * if one of the packets with seq nr 0 or 65535 would be lost or late */
- else if ((pri->info_seq_num == 0) && (ptr->stop_seq_nr == 65535) &&
- (ptr->under == FALSE)){
- ptr->cycles++;
- ptr->under = TRUE;
- }
- /* the whole round is over, so reset the flag */
- else if ((pri->info_seq_num > ptr->start_seq_nr) && (ptr->under != FALSE)) {
- ptr->under = FALSE;
- }
-
- /* Since it is difficult to count lost, duplicate or late packets separately,
- * we would like to know at least how many times the sequence number was not ok */
-
- /* if the current seq number equals the last one or if we are here for
- * the first time, then it is ok, we just store the current one as the last one */
- if ( ( ptr->seq_num+1 == pri->info_seq_num) || (pkt_type == FIRST_PACKET) )
- ptr->seq_num = pri->info_seq_num;
- /* if the first one is 65535. XXX same problem as above: if seq 65535 or 0 is lost... */
- else if ( (ptr->seq_num == 65535) && (pri->info_seq_num == 0) )
- ptr->seq_num = pri->info_seq_num;
- /* lost packets */
- else if (ptr->seq_num+1 < pri->info_seq_num) {
- ptr->seq_num = pri->info_seq_num;
- ptr->sequence++;
- }
- /* late or duplicated */
- else if (ptr->seq_num+1 > pri->info_seq_num)
- ptr->sequence++;
-
- ptr->time = current_time;
- ptr->timestamp = pri->info_timestamp;
- ptr->stop_seq_nr = pri->info_seq_num;
- ptr->total_nr++;
-
- /* save the voice information */
- /* if there was already an error, we quit */
- if (ptr->saved == FALSE)
- return 0;
-
- /* if the captured length and packet length aren't equal, we quit
- * because there is some information missing */
- if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
- ptr->saved = FALSE;
- ptr->error_type = TAP_RTP_WRONG_LENGTH;
- return 0;
- }
-
- /* if padding bit is set, but the padding count is bigger
- * then the whole RTP data - error with padding count */
- if ( (pri->info_padding_set != FALSE) &&
- (pri->info_padding_count > pri->info_payload_len) ) {
- ptr->saved = FALSE;
- ptr->error_type = TAP_RTP_PADDING_ERROR;
- return 0;
- }
-
- /* do we need to insert some silence? */
- if (pkt_type == MARK_SET) {
- /* the amount of silence should be the difference between
- * the last timestamp and the current one minus x
- * x should equal the amount of information in the last frame
- * XXX not done yet */
- for(i=0; i < (ptr->delta_timestamp - pri->info_payload_len -
- pri->info_padding_count); i++) {
- tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
- fwrite(&tmp, 2, 1, ptr->fp);
- ptr->count++;
- }
- fflush(ptr->fp);
- }
-
- /* is it the ulaw? */
- if (pri->info_payload_type == 0) {
- /* we put the pointer at the beggining of the RTP data, that is
- * at the end of the current frame minus the length of the
- * padding count minus length of the RTP data */
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_payload_len);
- for(i=0; i < (pri->info_payload_len - pri->info_padding_count); i++, data++) {
- tmp = (gint16 )ulaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, ptr->fp);
- ptr->count++;
- }
- fflush(ptr->fp);
- ptr->saved = TRUE;
- return 0;
- }
-
- /* alaw? */
- else if (pri->info_payload_type == 8) {
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_payload_len);
- for(i=0; i < (pri->info_payload_len - pri->info_padding_count); i++, data++) {
- tmp = (gint16 )alaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, ptr->fp);
- ptr->count++;
- }
- fflush(ptr->fp);
- ptr->saved = TRUE;
- return 0;
- }
-
- /* unsupported codec or XXX other error */
- else {
- ptr->saved = FALSE;
- ptr->error_type = TAP_RTP_WRONG_CODEC;
- return 0;
- }
-}
-
-/* XXX just copied from gtk/rpc_stat.c */
-void protect_thread_critical_region(void);
-void unprotect_thread_critical_region(void);
-
-/* here we close the rtp analysis dialog window and remove the tap listener */
-static void rtp_destroy_cb(GtkWidget *win _U_, gpointer data _U_)
-{
- info_stat *rs=(info_stat *)data;
-
- protect_thread_critical_region();
- remove_tap_listener(rs);
- unprotect_thread_critical_region();
-
- /* xxx is this enough? */
- g_free(rs->ssrc_tmp);
- g_free(rs);
-
- if (rs->forward.fp != NULL)
- fclose(rs->forward.fp);
- if (rs->reversed.fp != NULL)
- fclose(rs->reversed.fp);
- remove(f_tempname);
- remove(r_tempname);
-
- /* Is there a save voice window open? */
- if (save_voice_as_w != NULL)
- gtk_widget_destroy(save_voice_as_w);
-
- /* Note that we no longer have a "RTP Analyse" dialog box. */
- rtp_w = NULL;
-}
-
-/* when the close button in rtp window was clicked */
-/* it seems to me that rtp_destroy_cb is automatically called, so we don't
- * need to do the g_free... and rtp_w = NULL ... */
-static void rtp_destroy (GtkWidget *close_bt _U_, gpointer parent_w)
-{
- gtk_grab_remove(GTK_WIDGET(parent_w));
- gtk_widget_destroy(GTK_WIDGET(parent_w));
-}
-
-/* we search the rtp.ssrc node here (thanks to Guy Harris - code here is magic for me */
-static guint32 process_node(proto_item *ptree_node, header_field_info *hfinformation)
-{
- field_info *finfo;
- proto_item *proto_sibling_node;
- header_field_info *hfssrc;
- guint32 ssrc;
-
- finfo = PITEM_FINFO(ptree_node);
-
- if (hfinformation==(finfo->hfinfo)) {
- hfssrc = proto_registrar_get_byname("rtp.ssrc");
- if (hfssrc == NULL)
- return 0;
- for(ptree_node=g_node_first_child(ptree_node); ptree_node!=NULL;
- ptree_node=g_node_next_sibling(ptree_node)) {
- finfo=PITEM_FINFO(ptree_node);
- if (hfssrc==finfo->hfinfo) {
- ssrc = fvalue_get_integer(finfo->value);
- return ssrc;
- }
- }
- }
-
- proto_sibling_node = g_node_next_sibling(ptree_node);
-
- if (proto_sibling_node) {
- ssrc = process_node(proto_sibling_node, hfinformation);
- return ssrc;
- }
- else
- return 0;
-}
-
-/* here we search the rtp protocol */
-static guint32 process_tree(proto_tree *protocol_tree)
-{
- proto_item *ptree_node;
- header_field_info *hfinformation;
-
- hfinformation = proto_registrar_get_byname("rtp");
- if (hfinformation == NULL)
- return 0;
-
- ptree_node = g_node_first_child(protocol_tree);
- if (!ptree_node)
- return 0;
-
- return process_node(ptree_node, hfinformation);
-}
-
-/* when we want to update the information */
-static void refresh_cb(GtkWidget *w _U_, void *pri)
-{
- info_stat *rs=pri;
-
- gtk_clist_clear(GTK_CLIST(clist));
- gtk_clist_clear(GTK_CLIST(clist_r));
- redissect_packets(&cfile);
- draw_stat(rs);
-}
-
-/* when we want to save the information */
-static void save_csv_as_ok_cb(GtkWidget *ok_bt, gpointer fs)
-{
- gchar *g_dest;
- GtkWidget *rev, *forw, *both;
- info_stat *rs;
-
- FILE *fp;
- char *columnText;
- int i,j;
-
- g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(g_dest) == EISDIR) {
- /* It's a directory - set the file selection box to display it. */
- set_last_open_dir(g_dest);
- g_free(g_dest);
- gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
- return;
- }
-
- rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");
- forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");
- both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");
- rs = (info_stat *)OBJECT_GET_DATA(ok_bt, "info_stat");
-
- if (GTK_TOGGLE_BUTTON(forw)->active || GTK_TOGGLE_BUTTON(both)->active) {
- fp = fopen(g_dest, "w");
-
- if (GTK_TOGGLE_BUTTON(both)->active) {
- fprintf(fp, "Forward\n");
- }
-
- for(j = 0; j < GTK_CLIST(clist)->columns; j++) {
- if (j == 0) {
- fprintf(fp,"%s",GTK_CLIST(clist)->column[j].title);
- } else {
- fprintf(fp,",%s",GTK_CLIST(clist)->column[j].title);
- }
- }
- fprintf(fp,"\n");
- for (i = 0; i < GTK_CLIST(clist)->rows; i++) {
- for(j = 0; j < GTK_CLIST(clist)->columns; j++) {
- gtk_clist_get_text(GTK_CLIST(clist),i,j,&columnText);
- if (j == 0) {
- fprintf(fp,"%s",columnText);
- } else {
- fprintf(fp,",%s",columnText);
- }
- }
- fprintf(fp,"\n");
- }
-
- fclose(fp);
- }
-
- if (GTK_TOGGLE_BUTTON(rev)->active || GTK_TOGGLE_BUTTON(both)->active) {
-
- if (GTK_TOGGLE_BUTTON(both)->active) {
- fp = fopen(g_dest, "a");
- fprintf(fp, "\nReverse\n");
- } else {
- fp = fopen(g_dest, "w");
- }
- for(j = 0; j < GTK_CLIST(clist_r)->columns; j++) {
- if (j == 0) {
- fprintf(fp,"%s",GTK_CLIST(clist_r)->column[j].title);
- } else {
- fprintf(fp,",%s",GTK_CLIST(clist_r)->column[j].title);
- }
- }
- fprintf(fp,"\n");
- for (i = 0; i < GTK_CLIST(clist_r)->rows; i++) {
- for(j = 0; j < GTK_CLIST(clist_r)->columns; j++) {
- gtk_clist_get_text(GTK_CLIST(clist_r),i,j,&columnText);
- if (j == 0) {
- fprintf(fp,"%s",columnText);
- } else {
- fprintf(fp,",%s",columnText);
- }
- }
- fprintf(fp,"\n");
- }
- fclose(fp);
- }
- /* XXX I get GTK warning (sometimes?)!!! */
- gtk_widget_destroy(GTK_WIDGET(save_csv_as_w));
-}
-
-static void save_csv_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
-{
- save_csv_as_w = NULL;
-}
-
-/* when the user wants to save the csv information in a file */
-static void save_csv_as_cb(GtkWidget *w _U_, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
-
- GtkWidget *vertb;
- GtkWidget *table1;
- GtkWidget *label_format;
- GtkWidget *channels_label;
- GSList *channels_group = NULL;
- GtkWidget *forward_rb;
- GtkWidget *reversed_rb;
- GtkWidget *both_rb;
- GtkWidget *ok_bt;
-
- if (save_csv_as_w != NULL) {
- /* There's already a Save CSV info dialog box; reactivate it. */
- reactivate_window(save_csv_as_w);
- return;
- }
-
- save_csv_as_w = gtk_file_selection_new("Ethereal: Save Data As CSV");
- gtk_signal_connect(GTK_OBJECT(save_csv_as_w), "destroy",
- GTK_SIGNAL_FUNC(save_csv_as_destroy_cb), NULL);
-
- /* Container for each row of widgets */
- vertb = gtk_vbox_new(FALSE, 0);
- gtk_container_border_width(GTK_CONTAINER(vertb), 5);
- gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(save_csv_as_w)->action_area),
- vertb, FALSE, FALSE, 0);
- gtk_widget_show (vertb);
-
- table1 = gtk_table_new (2, 4, FALSE);
- gtk_widget_show (table1);
- gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
- gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
-
- label_format = gtk_label_new ("Format: Comma Separated Values");
- gtk_widget_show (label_format);
- gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
-
- channels_label = gtk_label_new ("Channels:");
- gtk_widget_show (channels_label);
- gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
-
- forward_rb = gtk_radio_button_new_with_label (channels_group, "forward ");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
- gtk_widget_show (forward_rb);
- gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
- gtk_widget_show (reversed_rb);
- gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- both_rb = gtk_radio_button_new_with_label (channels_group, "both");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
- gtk_widget_show (both_rb);
- gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
-
- ok_bt = GTK_FILE_SELECTION(save_csv_as_w)->ok_button;
- OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
- OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
- OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
- OBJECT_SET_DATA(ok_bt, "info_stat", rs);
-
- /* Connect the cancel_button to destroy the widget */
- SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(save_csv_as_w)->cancel_button,
- "clicked", (GtkSignalFunc)gtk_widget_destroy,
- save_csv_as_w);
-
- /* Catch the "key_press_event" signal in the window, so that we can catch
- the ESC key being pressed and act as if the "Cancel" button had
- been selected. */
- dlg_set_cancel(save_csv_as_w, GTK_FILE_SELECTION(save_csv_as_w)->cancel_button);
-
- gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
- GTK_SIGNAL_FUNC(save_csv_as_ok_cb), save_csv_as_w);
-
- gtk_widget_show(save_csv_as_w);
-}
-
-static void save_voice_as_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
-{
- /* Note that we no longer have a Save voice info dialog box. */
- save_voice_as_w = NULL;
-}
-
-/* the user wants to save in a file */
-/* XXX support for different formats is currently commented out */
-static void save_voice_as_ok_cb(GtkWidget *ok_bt, gpointer fs)
-{
- gchar *g_dest;
- /*GtkWidget *wav, *au, *sw;*/
- GtkWidget *rev, *forw, *both;
- info_stat *rs;
- gint channels /*, format*/;
-
- g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs)));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(g_dest) == EISDIR) {
- /* It's a directory - set the file selection box to display it. */
- set_last_open_dir(g_dest);
- g_free(g_dest);
- gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), last_open_dir);
- return;
- }
-
- /*wav = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "wav_rb");
- au = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "au_rb");
- sw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "sw_rb");*/
- rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");
- forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");
- both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");
- rs = (info_stat *)OBJECT_GET_DATA(ok_bt, "info_stat");
-
- /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.
- * we don't support that codec. So we pop up a warning. Maybe it would be better to
- * disable the ok button or disable the buttons for direction if only one is not ok. The
- * problem is if we open the save voice dialog and then click the refresh button and maybe
- * the state changes, so we can't save anymore. In this case we should be able to update
- * the buttons. For now it is easier if we put the warning when the ok button is pressed.
- */
-
- /* we can not save in both dirctions */
- if ((rs->forward.saved == FALSE) && (rs->reversed.saved == FALSE) && (GTK_TOGGLE_BUTTON (both)->active)) {
- /* there are many combinations here, we just exit when first matches */
- if ((rs->forward.error_type == TAP_RTP_WRONG_CODEC) ||
- (rs->reversed.error_type == TAP_RTP_WRONG_CODEC))
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: Unsupported codec!");
- else if ((rs->forward.error_type == TAP_RTP_WRONG_LENGTH) ||
- (rs->reversed.error_type == TAP_RTP_WRONG_LENGTH))
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: Wrong length of captured packets!");
- else if ((rs->forward.error_type == TAP_RTP_PADDING_ERROR) ||
- (rs->reversed.error_type == TAP_RTP_PADDING_ERROR))
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: RTP data with padding!");
- else
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: File I/O problem!");
- return;
- }
- /* we can not save forward direction */
- else if ((rs->forward.saved == FALSE) && ((GTK_TOGGLE_BUTTON (forw)->active) ||
- (GTK_TOGGLE_BUTTON (both)->active))) {
- if (rs->forward.error_type == TAP_RTP_WRONG_CODEC)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: Unsupported codec!");
- else if (rs->forward.error_type == TAP_RTP_WRONG_LENGTH)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: Wrong length of captured packets!");
- else if (rs->forward.error_type == TAP_RTP_PADDING_ERROR)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: RTP data with padding!");
- else
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: File I/O problem!");
- return;
- }
- /* we can not save reversed direction */
- else if ((rs->reversed.saved == FALSE) && ((GTK_TOGGLE_BUTTON (rev)->active) ||
- (GTK_TOGGLE_BUTTON (both)->active))) {
- if (rs->reversed.error_type == TAP_RTP_WRONG_CODEC)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: Unsupported codec!");
- else if (rs->reversed.error_type == TAP_RTP_WRONG_LENGTH)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: Wrong length of captured packets!");
- else if (rs->reversed.error_type == TAP_RTP_PADDING_ERROR)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: RTP data with padding!");
- else if (rs->reversed.error_type == TAP_RTP_NO_DATA)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: No RTP data!");
- else
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: File I/O problem!");
- return;
- }
-
- /*if (GTK_TOGGLE_BUTTON (wav)->active)
- format = 1;
- else if (GTK_TOGGLE_BUTTON (au)->active)
- format = 2;
- else if (GTK_TOGGLE_BUTTON (sw)->active)
- format = 3;*/
-
- if (GTK_TOGGLE_BUTTON (rev)->active)
- channels = 2;
- else if (GTK_TOGGLE_BUTTON (both)->active)
- channels = 3;
- else
- channels = 1;
-
- if(!copy_file(g_dest, channels/*, format*/, rs)) {
- simple_dialog(ESD_TYPE_CRIT, NULL, "An error occured while saving voice in a file!");
- return;
- }
-
- /* XXX I get GTK warning (sometimes?)!!! */
- gtk_widget_destroy(GTK_WIDGET(save_voice_as_w));
-}
-
-/* when the user wants to save the voice information in a file */
-/* XXX support for different formats is currently commented out */
-static void save_voice_as_cb(GtkWidget *w _U_, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
-
- GtkWidget *vertb;
- GtkWidget *table1;
- GtkWidget *label_format;
- GtkWidget *channels_label;
- /*GSList *format_group = NULL;*/
- GSList *channels_group = NULL;
- GtkWidget *forward_rb;
- GtkWidget *reversed_rb;
- GtkWidget *both_rb;
- /*GtkWidget *wav_rb; GtkWidget *au_rb; GtkWidget *sw_rb;*/
- GtkWidget *ok_bt;
-
- /* if we can't save in a file: wrong codec, cut packets or other errors */
- /* shold the error arise here or later when you click ok button ?
- * if we do it here, then we must disable the refresh button, so we don't do it here */
-
- if (save_voice_as_w != NULL) {
- /* There's already a Save voice info dialog box; reactivate it. */
- reactivate_window(save_voice_as_w);
- return;
- }
-
- save_voice_as_w = gtk_file_selection_new("Ethereal: Save Voice Data As");
- gtk_signal_connect(GTK_OBJECT(save_voice_as_w), "destroy",
- GTK_SIGNAL_FUNC(save_voice_as_destroy_cb), NULL);
-
- /* Container for each row of widgets */
- vertb = gtk_vbox_new(FALSE, 0);
- gtk_container_border_width(GTK_CONTAINER(vertb), 5);
- gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(save_voice_as_w)->action_area),
- vertb, FALSE, FALSE, 0);
- gtk_widget_show (vertb);
-
- table1 = gtk_table_new (2, 4, FALSE);
- gtk_widget_show (table1);
- gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
- gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
-
- label_format = gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");
- gtk_widget_show (label_format);
- gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- /* we support .au - ulaw*/
-/* wav_rb = gtk_radio_button_new_with_label (format_group, ".wav");
- format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (wav_rb));
- gtk_widget_show (wav_rb);
- gtk_table_attach (GTK_TABLE (table1), wav_rb, 1, 2, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- sw_rb = gtk_radio_button_new_with_label (format_group, "8 kHz, 16 bit ");
- format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sw_rb));
- gtk_widget_show (sw_rb);
- gtk_table_attach (GTK_TABLE (table1), sw_rb, 2, 3, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- au_rb = gtk_radio_button_new_with_label (format_group, ".au");
- format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (au_rb));
- gtk_widget_show (au_rb);
- gtk_table_attach (GTK_TABLE (table1), au_rb, 3, 4, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- */
-
- channels_label = gtk_label_new ("Channels:");
- gtk_widget_show (channels_label);
- gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
-
- forward_rb = gtk_radio_button_new_with_label (channels_group, "forward ");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
- gtk_widget_show (forward_rb);
- gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
- gtk_widget_show (reversed_rb);
- gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- both_rb = gtk_radio_button_new_with_label (channels_group, "both");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
- gtk_widget_show (both_rb);
- gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
-
- /* if one direction is nok we don't allow saving
- XXX this is not ok since the user can click the refresh button and cause changes
- but we can not update this window. So we move all the decision on the time the ok
- button is clicked
- if (rs->forward.saved == FALSE) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb), TRUE);
- gtk_widget_set_sensitive(forward_rb, FALSE);
- gtk_widget_set_sensitive(both_rb, FALSE);
- }
- else if (rs->reversed.saved == FALSE) {
- gtk_widget_set_sensitive(reversed_rb, FALSE);
- gtk_widget_set_sensitive(both_rb, FALSE);
- }
- */
-
- ok_bt = GTK_FILE_SELECTION(save_voice_as_w)->ok_button;
- /*OBJECT_SET_DATA(ok_bt, "wav_rb", wav_rb);
- OBJECT_SET_DATA(ok_bt, "au_rb", au_rb);
- OBJECT_SET_DATA(ok_bt, "sw_rb", sw_rb);*/
- OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
- OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
- OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
- OBJECT_SET_DATA(ok_bt, "info_stat", rs);
-
- /* Connect the cancel_button to destroy the widget */
- SIGNAL_CONNECT_OBJECT(GTK_FILE_SELECTION(save_voice_as_w)->cancel_button,
- "clicked", (GtkSignalFunc)gtk_widget_destroy,
- save_voice_as_w);
-
- /* Catch the "key_press_event" signal in the window, so that we can catch
- the ESC key being pressed and act as if the "Cancel" button had
- been selected. */
- dlg_set_cancel(save_voice_as_w, GTK_FILE_SELECTION(save_voice_as_w)->cancel_button);
-
- gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
- GTK_SIGNAL_FUNC(save_voice_as_ok_cb), save_voice_as_w);
-
- gtk_widget_show(save_voice_as_w);
-}
-
-/* all the graphics on the window is done here */
-static void add_rtp_notebook(void *pri)
-{
- info_stat *rs=pri;
-
- GtkWidget *notebook, *page, *page_r, *label, *label1, *label2, *label3;
- GtkWidget *scrolled_window, *scrolled_window_r/*, *frame, *text, *label4, *page_help*/;
- GtkWidget *box4, *voice_bt, *refresh_bt, *close_bn, *csv_bt;
-
- gchar *titles[8] = {"Packet nr.", "Sequence", "Delay (s)", "Jitter (s)", "Marker", "Status", "Date", "Length"};
- gchar label_forward[150];
- gchar label_reverse[150];
-
- g_snprintf(label_forward, 149,
- "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
- rs->source, rs->srcport, rs->destination, rs->dstport, rs->ssrc_forward);
- g_snprintf(label_reverse, 149,
- "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
- rs->destination, rs->dstport, rs->source, rs->srcport, rs->ssrc_reversed);
-
- gtk_widget_destroy(main_vb);
- main_vb = gtk_vbox_new(FALSE, 3);
- gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
- gtk_widget_show(main_vb);
-
- /* Start a nootbook for flipping between sets of changes */
- notebook = gtk_notebook_new();
- gtk_container_add(GTK_CONTAINER(main_vb), notebook);
- gtk_object_set_data(GTK_OBJECT(rtp_w), "notebook", notebook);
-
- /* page for forward connection */
- page = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(page), 20);
-
- /* scrolled window */
- scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- gtk_widget_set_usize(scrolled_window, 600, 200);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-
- /* direction label */
- label1 = gtk_label_new(label_forward);
- gtk_box_pack_start(GTK_BOX(page), label1, FALSE, FALSE, 0);
-
- /* place for some statistics */
- max = gtk_label_new("\n\n");
- gtk_box_pack_end(GTK_BOX(page), max, FALSE, FALSE, 5);
-
- /* clist for the information */
- clist = gtk_clist_new_with_titles(8, titles);
- gtk_widget_show(clist);
- gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
- gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
-
- /* and the label */
- label = gtk_label_new(" Forward Direction ");
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
-
- /* Hide date and length column */
- gtk_clist_set_column_visibility(GTK_CLIST(clist), 6, FALSE);
- gtk_clist_set_column_visibility(GTK_CLIST(clist), 7, FALSE);
-
- /* column width and justification */
- gtk_clist_set_column_width(GTK_CLIST(clist), 0, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 1, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 2, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 3, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 4, 40);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 2, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 3, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_CENTER);
-
- /* same page for reversed connection */
- page_r = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(page_r), 20);
- scrolled_window_r = gtk_scrolled_window_new(NULL, NULL);
- gtk_widget_set_usize(scrolled_window_r, 600, 200);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_r),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
- label3 = gtk_label_new(label_reverse);
- gtk_box_pack_start(GTK_BOX(page_r), label3, FALSE, FALSE, 0);
- max_r = gtk_label_new("\n\n");
- gtk_box_pack_end(GTK_BOX(page_r), max_r, FALSE, FALSE, 5);
- clist_r = gtk_clist_new_with_titles(8, titles);
- gtk_widget_show(clist_r);
- gtk_container_add(GTK_CONTAINER(scrolled_window_r), clist_r);
- gtk_box_pack_start(GTK_BOX(page_r), scrolled_window_r, TRUE, TRUE, 0);
- label2 = gtk_label_new(" Reversed Direction ");
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_r, label2);
-
- /* Hide date and length column */
- gtk_clist_set_column_visibility(GTK_CLIST(clist_r), 6, FALSE);
- gtk_clist_set_column_visibility(GTK_CLIST(clist_r), 7, FALSE);
-
- /* column width and justification */
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 1, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 2, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 3, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 4, 40);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 0, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 1, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 2, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 3, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 4, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 5, GTK_JUSTIFY_CENTER);
-
- /* page for help&about or future
- page_help = gtk_hbox_new(FALSE, 5);
- label4 = gtk_label_new(" Future ");
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_help, label4);
- frame = gtk_frame_new("");
- text = gtk_label_new("\n\nMaybe some more statistics: delay and jitter distribution,...");
- gtk_label_set_justify(GTK_LABEL(text), GTK_JUSTIFY_LEFT);
- gtk_container_add(GTK_CONTAINER(frame), text);
- gtk_container_set_border_width(GTK_CONTAINER(frame), 20);
- gtk_box_pack_start(GTK_BOX(page_help), frame, TRUE, TRUE, 0);
-*/
- /* show all notebooks */
- gtk_widget_show_all(notebook);
-
- /* and the buttons */
- box4 = gtk_hbutton_box_new();
- gtk_box_pack_start(GTK_BOX(main_vb), box4, FALSE, TRUE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(box4), 10);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(box4), GTK_BUTTONBOX_SPREAD);
- gtk_widget_show(box4);
-
- voice_bt = gtk_button_new_with_label("Save voice data as...");
- gtk_container_add(GTK_CONTAINER(box4), voice_bt);
- gtk_widget_show(voice_bt);
- gtk_signal_connect(GTK_OBJECT(voice_bt), "clicked",
- GTK_SIGNAL_FUNC(save_voice_as_cb), rs);
-
- refresh_bt = gtk_button_new_with_label("Refresh");
- gtk_container_add(GTK_CONTAINER(box4), refresh_bt);
- gtk_widget_show(refresh_bt);
- gtk_signal_connect(GTK_OBJECT(refresh_bt), "clicked",
- GTK_SIGNAL_FUNC(refresh_cb), rs);
-
- csv_bt = gtk_button_new_with_label("Save As CSV...");
- gtk_container_add(GTK_CONTAINER(box4), csv_bt);
- gtk_widget_show(csv_bt);
- gtk_signal_connect(GTK_OBJECT(csv_bt), "clicked",
- GTK_SIGNAL_FUNC(save_csv_as_cb), rs);
-
- close_bn = gtk_button_new_with_label("Close");
- gtk_container_add(GTK_CONTAINER(box4), close_bn);
- gtk_widget_show(close_bn);
- gtk_signal_connect(GTK_OBJECT(close_bn), "clicked",
- GTK_SIGNAL_FUNC(rtp_destroy), GTK_OBJECT(rtp_w));
-
- redissect_packets(&cfile);
-
- draw_stat(rs);
-}
-
-
-/* when we click on the selected row it copies that ssrc value into ssrc_reversed */
-static void get_selected_ssrc(GtkWidget *clist_r, gint row, gint column,
- GdkEventButton *event _U_, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
- gchar *text;
-
- gtk_clist_get_text(GTK_CLIST(clist_r), row, column, &text);
- /* XXX is this strtoul portable for guint32? */
- rs->ssrc_reversed = strtoul(text, (char **)NULL, 10);
- return;
-}
-
-/* when we click apply button in ssrc reversed dialog */
-static void apply_selected_ssrc(GtkWidget *w _U_, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
- add_rtp_notebook(rs);
-}
-
-/* this function goes through all the packets that have the same ip and port combination
- * (only inversed) as the forward direction (XXX what if the reversed direction doesn't use
- * the same ports???) and looks for different SSRC values. This can happen if you capture
- * two RTP conversations one after another from the same pair of phones (PC's).
- * Both have same IP's and can also have same port numbers, so they (should) differ only
- * in SSRC values. In such case we get a list of ssrc values and we have to choose the right
- * one from the list. If there is only one or none, we do it automatically */
-static void get_reversed_ssrc(void *prs)
-{
- info_stat *ri = prs;
- GtkWidget *scroll_r, *clist_r, *ok_bt, *label, *label2, *label1, *main_hbnbox;
- gchar temp[150];
- guint i;
-
- switch(ri->reversed_ip_and_port)
- {
- /* in case we haven't found any reversed ssrc */
- /* XXX in this case we could look for the inversed IP only */
- case 0: {
- ri->ssrc_reversed = 0;
- ri->search_ssrc = FALSE;
- add_rtp_notebook(ri);
- return;
- }
- /* in case we found exactly one matching ssrc for reversed connection */
- case 1: {
- ri->ssrc_reversed = ri->ssrc_tmp[0];
- ri->search_ssrc = FALSE;
- add_rtp_notebook(ri);
- return;
- }
- /* there is more then one matching ssrc, so we have to choose between them */
- default: {
- ri->search_ssrc = FALSE;
- /* let's draw the window */
- label = gtk_label_new("Found more SSRC values for the reversed\n"
- "connection with following parameters:\n");
- g_snprintf(temp, 149, "Source %s port %u Destination %s port %u",
- ri->destination, ri->dstport, ri->source, ri->srcport);
- label2 = gtk_label_new(temp);
- gtk_box_pack_start(GTK_BOX(main_vb), label, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(main_vb), label2, FALSE, FALSE, 0);
- scroll_r = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_r),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- clist_r = gtk_clist_new(1);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
- gtk_container_add(GTK_CONTAINER(scroll_r), clist_r);
- gtk_box_pack_start(GTK_BOX(main_vb), scroll_r, TRUE, TRUE, 0);
- label1 = gtk_label_new("Select one value and click apply");
- gtk_box_pack_start(GTK_BOX(main_vb), label1, FALSE, FALSE, 0);
-
- main_hbnbox = gtk_hbutton_box_new();
- gtk_box_pack_start(GTK_BOX(main_vb), main_hbnbox, FALSE, TRUE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(main_hbnbox), 10);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(main_hbnbox),
- GTK_BUTTONBOX_SPREAD);
- gtk_widget_show(main_hbnbox);
-
- ok_bt = gtk_button_new_with_label("Apply");
- gtk_container_add(GTK_CONTAINER(main_hbnbox), ok_bt);
- gtk_signal_connect(GTK_OBJECT(clist_r), "select_row",
- GTK_SIGNAL_FUNC(get_selected_ssrc), ri);
- gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
- GTK_SIGNAL_FUNC(apply_selected_ssrc), ri);
-
- /* add all the ssrc values in the clist */
- /* XXX I'm sure the tmp variable could be avoided here
- * i tried to assign guint32 from ri->ssrc_tmp somehow to gchar **text
- * but gave up. So if you can do this, just go ahead */
- for (i=0; i < ri->reversed_ip_and_port; i++) {
- gchar *text[1];
- gchar tmp[20];
- g_snprintf(tmp, 20, "%u", ri->ssrc_tmp[i]);
- text[0] = (gchar *)&tmp;
- gtk_clist_append(GTK_CLIST(clist_r), text);
- }
-
- gtk_clist_select_row(GTK_CLIST(clist_r), 0, 0);
-
- gtk_widget_show(label);
- gtk_widget_show(label1);
- gtk_widget_show(label2);
- gtk_widget_show(ok_bt);
- gtk_widget_show(clist_r);
- gtk_widget_show(scroll_r);
- }
- }
-}
-
-/* XXX only handles RTP over IPv4, should add IPv6 support */
-/* when the user clicks the RTP dialog button */
-static void rtp_analyse_cb(GtkWidget *w _U_, gpointer data _U_)
-{
- info_stat *rs;
- gchar filter_text[256];
- dfilter_t *sfcode;
- capture_file *cf;
- epan_dissect_t *edt;
- gint err;
- gboolean frame_matched;
- frame_data *fdata;
- GString *error_string;
- int fd;
-
- /* There's already a "Display Options" dialog box; reactivate it. */
- if (rtp_w != NULL) {
- reactivate_window(rtp_w);
- return;
- }
-
- /* Try to compile the filter. */
- strcpy(filter_text,"rtp && ip");
- if (!dfilter_compile(filter_text, &sfcode)) {
- simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
- return;
- }
- /* we load the current file into cf variable */
- cf = &cfile;
- fdata = cf->current_frame;
-
- /* we are on the selected frame now */
- if (fdata == NULL)
- return; /* if we exit here it's an error */
-
- /* XXX instead of looking for RTP protocol like this, we could do the process_node() staff */
- /* dissect the current frame */
- if (!wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err)) {
- simple_dialog(ESD_TYPE_CRIT, NULL,
- file_read_error_message(err), cf->filename);
- return;
- }
- edt = epan_dissect_new(TRUE, FALSE);
- epan_dissect_prime_dfilter(edt, sfcode);
- epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
- frame_matched = dfilter_apply_edt(sfcode, edt);
-
- /* if it is not an rtp frame, exit */
- frame_matched = dfilter_apply_edt(sfcode, edt);
- if (frame_matched != 1) {
- epan_dissect_free(edt);
- simple_dialog(ESD_TYPE_CRIT, NULL, "You didn't choose a RTP packet!");
- return;
- }
-
- /* in rs we put all the info */
- rs=g_malloc(sizeof(info_stat));
-
- /* ok, it is a RTP frame, so let's get the ip and port values */
- rs->srcport = edt->pi.srcport;
- rs->dstport = edt->pi.destport;
- strncpy(rs->source, ip_to_str(edt->pi.src.data), 16);
- strncpy(rs->destination, ip_to_str(edt->pi.dst.data), 16);
-
- /* now we need the SSRC value of the current frame */
- rs->ssrc_forward = process_tree(edt->tree);
- if (rs->ssrc_forward == 0) {
- simple_dialog(ESD_TYPE_CRIT, NULL, "SSRC value couldn't be found!");
- return;
- }
-
- /* now we have all the information about the forwarding connection
- * we need to go through all the packets and search for reversed connection
- */
- rs->search_ssrc = TRUE;
- rs->ssrc_reversed = 0;
- rs->reversed_ip = 0;
- rs->reversed_ip_and_port = 0;
- rs->ssrc_tmp = NULL;
-
- sprintf(filter_text,"rtp && ip && !icmp && (( ip.src==%s && udp.srcport==%d && ip.dst==%s && udp.dstport==%d ) || ( ip.src==%s && udp.srcport==%d && ip.dst==%s && udp.dstport==%d ))",
- ip_to_str(edt->pi.src.data),
- edt->pi.srcport,
- ip_to_str(edt->pi.dst.data),
- edt->pi.destport,
- ip_to_str(edt->pi.dst.data),
- edt->pi.destport,
- ip_to_str(edt->pi.src.data),
- edt->pi.srcport
- );
-/* XXX compiler warning:passing arg 5 of `register_tap_listener' from incompatible pointer type */
- error_string = register_tap_listener("rtp", rs, filter_text, rtp_reset, rtp_packet, rtp_draw);
- if (error_string != NULL) {
- simple_dialog(ESD_TYPE_WARN, NULL, error_string->str);
- /* XXX is this enough or do I have to free anything else? */
- g_string_free(error_string, TRUE);
- g_free(rs);
- exit(1);
- }
-
- /* let's draw the window */
- rtp_w = dlg_window_new("Ethereal: RTP Analyse");
- gtk_window_set_position (GTK_WINDOW (rtp_w), GTK_WIN_POS_CENTER);
- gtk_signal_connect(GTK_OBJECT(rtp_w), "destroy",
- GTK_SIGNAL_FUNC(rtp_destroy_cb), rs);
-
- /* Container for each row of widgets */
- main_vb = gtk_vbox_new(FALSE, 3);
- gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
- gtk_widget_show(main_vb);
-
- /* file names for storing sound data */
- fd = create_tempfile(f_tempname, sizeof(f_tempname), "ethereal_rtp_fwd");
- rs->forward.fp = fdopen(fd, "wb");
- fd = create_tempfile(r_tempname, sizeof(f_tempname), "ethereal_rtp_rev");
- rs->reversed.fp = fdopen(fd, "wb");
-
- redissect_packets(cf);
-
- /* so how many reversed connection we have ? */
- get_reversed_ssrc(rs);
-
- /* and finally display this window */
- gtk_widget_show(rtp_w);
-}
-
-static void
-rtp_analyse_init(char *dummy _U_)
-{
- rtp_analyse_cb(NULL, NULL);
-}
-
-void
-register_tap_listener_gtkrtp(void)
-{
- register_ethereal_tap("rtp", rtp_analyse_init);
-}
-
-void
-register_tap_menu_gtkrtp(void)
-{
- register_tap_menu_item("Statistics/RTP Analysis...", rtp_analyse_cb,
- NULL, NULL);
-}
-
-
-/* here we save it into a file that user specified */
-/* XXX what about endians here? could go something wrong? */
-static gboolean copy_file(gchar *dest, gint channels, /*gint format,*/ void *data)
-{
- info_stat *rs=(info_stat *)data;
- int to_fd, forw_fd, rev_fd, fread = 0, rread = 0, fwritten, rwritten;
- gint16 f_pd;
- gint16 r_pd;
- gchar pd[1];
- guint32 f_write_silence = 0;
- guint32 r_write_silence = 0;
- progdlg_t *progbar;
- guint32 progbar_count, progbar_quantum, progbar_nextstep = 0, count = 0;
- gboolean stop_flag = FALSE;
-
- forw_fd = open(f_tempname, O_RDONLY | O_BINARY);
- if (forw_fd < 0)
- return FALSE;
- rev_fd = open(r_tempname, O_RDONLY | O_BINARY);
- if (rev_fd < 0) {
- close(forw_fd);
- return FALSE;
- }
-
- /* open file for saving */
- to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (to_fd < 0) {
- close(forw_fd);
- close(rev_fd);
- return FALSE;
- }
-
- progbar = create_progress_dlg("Saving voice in a file", dest, "Stop", &stop_flag);
-
- /* First we write the .au header. XXX Hope this is endian independant */
- /* the magic word 0x2e736e64 == .snd */
- *pd = (unsigned char)0x2e; write(to_fd, pd, 1);
- *pd = (unsigned char)0x73; write(to_fd, pd, 1);
- *pd = (unsigned char)0x6e; write(to_fd, pd, 1);
- *pd = (unsigned char)0x64; write(to_fd, pd, 1);
- /* header offset == 24 bytes */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x18; write(to_fd, pd, 1);
- /* total length, it is permited to set this to 0xffffffff */
- *pd = (unsigned char)0xff; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- /* encoding format == 8 bit ulaw */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x01; write(to_fd, pd, 1);
- /* sample rate == 8000 Hz */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x1f; write(to_fd, pd, 1);
- *pd = (unsigned char)0x40; write(to_fd, pd, 1);
- /* channels == 1 */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x01; write(to_fd, pd, 1);
-
- switch (channels) {
- /* only forward direction */
- case 1: {
- progbar_count = rs->forward.count;
- progbar_quantum = rs->forward.count/100;
- while ((fread = read(forw_fd, &f_pd, 2)) > 0) {
- if(stop_flag)
- break;
- if((count > progbar_nextstep) && (count <= progbar_count)) {
- update_progress_dlg(progbar,
- (gfloat) count/progbar_count, "Saving");
- progbar_nextstep = progbar_nextstep + progbar_quantum;
- }
- count++;
- *pd = (unsigned char)linear2ulaw(f_pd);
- fwritten = write(to_fd, pd, 1);
- if ((fwritten*2 < fread) || (fwritten < 0) || (fread < 0)) {
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- destroy_progress_dlg(progbar);
- return FALSE;
- }
- }
- break;
- }
- /* only reversed direction */
- case 2: {
- progbar_count = rs->reversed.count;
- progbar_quantum = rs->reversed.count/100;
- while ((rread = read(rev_fd, &r_pd, 2)) > 0) {
- if(stop_flag)
- break;
- if((count > progbar_nextstep) && (count <= progbar_count)) {
- update_progress_dlg(progbar,
- (gfloat) count/progbar_count, "Saving");
- progbar_nextstep = progbar_nextstep + progbar_quantum;
- }
- count++;
- *pd = (unsigned char)linear2ulaw(r_pd);
- rwritten = write(to_fd, pd, 1);
- if ((rwritten*2 < rread) || (rwritten < 0) || (rread < 0)) {
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- destroy_progress_dlg(progbar);
- return FALSE;
- }
- }
- break;
- }
- /* both directions */
- default: {
- (rs->forward.count > rs->reversed.count) ?
- (progbar_count = rs->forward.count) :
- (progbar_count = rs->reversed.count);
- progbar_quantum = progbar_count/100;
- /* since conversation in one way can start later than in the other one,
- * we have to write some silence information for one channel */
- if (rs->forward.start_time > rs->reversed.start_time) {
- f_write_silence =
- (rs->forward.start_time-rs->reversed.start_time)*8000;
- }
- else if (rs->forward.start_time < rs->reversed.start_time) {
- r_write_silence =
- (rs->reversed.start_time-rs->forward.start_time)*8000;
- }
- for(;;) {
- if(stop_flag)
- break;
- if((count > progbar_nextstep) && (count <= progbar_count)) {
- update_progress_dlg(progbar,
- (gfloat) count/progbar_count, "Saving");
- progbar_nextstep = progbar_nextstep + progbar_quantum;
- }
- count++;
- if(f_write_silence > 0) {
- rread = read(rev_fd, &r_pd, 2);
- f_pd = 0;
- fread = 1;
- f_write_silence--;
- }
- else if(r_write_silence > 0) {
- fread = read(forw_fd, &f_pd, 2);
- r_pd = 0;
- rread = 1;
- r_write_silence--;
- }
- else {
- fread = read(forw_fd, &f_pd, 2);
- rread = read(rev_fd, &r_pd, 2);
- }
- if ((rread == 0) && (fread == 0))
- break;
- *pd = (unsigned char)linear2ulaw( (f_pd + r_pd)/2 );
- rwritten = write(to_fd, pd, 1);
- if ((rwritten < 0) || (rread < 0) || (fread < 0)) {
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- destroy_progress_dlg(progbar);
- return FALSE;
- }
- }
- }
- }
- destroy_progress_dlg(progbar);
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- return TRUE;
-
-}