2 * RTP streams summary addition for Wireshark
6 * Copyright 2003, Alcatel Business Systems
7 * By Lars Ruoff <lars.ruoff@gmx.net>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #include "rtp_stream_dlg.h"
33 #include "rtp_stream.h"
34 #include "rtp_analysis.h"
37 #include "epan/filesystem.h"
39 #include "../stat_menu.h"
40 #include "gui_stat_menu.h"
41 #include "dlg_utils.h"
43 #include "gui_utils.h"
44 #include "compat_macros.h"
45 #include "gtkglobals.h"
47 #include "image/clist_ascend.xpm"
48 #include "image/clist_descend.xpm"
50 #include <epan/rtp_pt.h>
52 #include <epan/address.h>
56 #include <epan/addr_resolv.h>
59 static const gchar FWD_LABEL_TEXT[] = "Select a forward stream with left mouse button";
60 static const gchar REV_LABEL_TEXT[] = "Select a reverse stream with SHIFT + left mouse button";
62 /****************************************************************************/
63 /* pointer to the one and only dialog window */
64 static GtkWidget *rtp_stream_dlg = NULL;
66 /* save as dialog box */
67 static GtkWidget *rtpstream_save_dlg = NULL;
68 static GtkWidget *clist = NULL;
69 static GtkWidget *top_label = NULL;
70 static GtkWidget *label_fwd = NULL;
71 static GtkWidget *label_rev = NULL;
73 static rtp_stream_info_t* selected_stream_fwd = NULL; /* current selection */
74 static rtp_stream_info_t* selected_stream_rev = NULL; /* current selection for reversed */
75 static GList *last_list = NULL;
77 static guint32 streams_nb = 0; /* number of displayed streams */
80 static const gchar *titles[NUM_COLS] = {"Src IP addr", "Src port", "Dest IP addr", "Dest port", "SSRC", "Payload", "Packets", "Lost", "Max Delta (ms)", "Max Jitter (ms)", "Mean Jitter (ms)", "Pb?"};
82 /****************************************************************************/
83 /* append a line to clist */
84 static void add_to_clist(rtp_stream_info_t* strinfo)
86 gchar label_text[256];
88 gchar *data[NUM_COLS];
95 /* save the current locale */
96 savelocale = setlocale(LC_NUMERIC, NULL);
97 /* switch to "C" locale to avoid problems with localized decimal separators
98 in g_snprintf("%f") functions */
99 setlocale(LC_NUMERIC, "C");
101 data[0] = g_strdup(get_addr_name(&(strinfo->src_addr)));
102 data[1] = g_strdup_printf("%u", strinfo->src_port);
103 data[2] = g_strdup(get_addr_name(&(strinfo->dest_addr)));
104 data[3] = g_strdup_printf("%u", strinfo->dest_port);
105 data[4] = g_strdup_printf("%u", strinfo->ssrc);
106 data[5] = g_strdup(val_to_str(strinfo->pt, rtp_payload_type_vals,
108 data[6] = g_strdup_printf("%u", strinfo->npackets);
110 expected = (strinfo->rtp_stats.stop_seq_nr + strinfo->rtp_stats.cycles*65536)
111 - strinfo->rtp_stats.start_seq_nr + 1;
112 lost = expected - strinfo->rtp_stats.total_nr;
114 perc = (double)(lost*100)/(double)expected;
118 data[7] = g_strdup_printf("%d (%.1f%%)", lost, perc);
119 data[8] = g_strdup_printf("%.2f", strinfo->rtp_stats.max_delta*1000);
120 data[9] = g_strdup_printf("%.2f", strinfo->rtp_stats.max_jitter*1000);
121 data[10] = g_strdup_printf("%.2f", strinfo->rtp_stats.mean_jitter*1000);
122 if (strinfo->problem)
123 data[11] = g_strdup("X");
125 data[11] = g_strdup("");
127 /* restore previous locale setting */
128 setlocale(LC_NUMERIC, savelocale);
130 added_row = gtk_clist_append(GTK_CLIST(clist), data);
131 for (i = 0; i < NUM_COLS; i++)
134 /* set data pointer of last row to point to user data for that row */
135 gtk_clist_set_row_data(GTK_CLIST(clist), added_row, strinfo);
137 /* Update the top label with the number of detected streams */
139 "Detected %d RTP streams. Choose one for forward and reverse direction for analysis",
141 gtk_label_set(GTK_LABEL(top_label), label_text);
144 /****************************************************************************/
145 static void save_stream_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
147 /* Note that we no longer have a Save voice info dialog box. */
148 rtpstream_save_dlg = NULL;
151 /****************************************************************************/
153 static void save_stream_ok_cb(GtkWidget *ok_bt _U_, gpointer user_data _U_)
157 if (!selected_stream_fwd)
160 g_dest = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (rtpstream_save_dlg)));
162 /* Perhaps the user specified a directory instead of a file.
163 Check whether they did. */
164 if (test_for_directory(g_dest) == EISDIR) {
165 /* It's a directory - set the file selection box to display it. */
166 set_last_open_dir(g_dest);
168 file_selection_set_current_folder(rtpstream_save_dlg, get_last_open_dir());
173 * Don't dismiss the dialog box if the save operation fails.
175 if (!rtpstream_save(selected_stream_fwd, g_dest))
178 window_destroy(GTK_WIDGET(rtpstream_save_dlg));
182 /****************************************************************************/
184 /****************************************************************************/
186 rtpstream_on_destroy (GtkObject *object _U_,
187 gpointer user_data _U_)
189 /* Remove the stream tap listener */
190 remove_tap_listener_rtp_stream();
192 /* Is there a save voice window open? */
193 if (rtpstream_save_dlg != NULL)
194 window_destroy(rtpstream_save_dlg);
196 /* Clean up memory used by stream tap */
197 rtpstream_reset((rtpstream_tapinfo_t*) rtpstream_get_info());
199 /* Note that we no longer have a "RTP Streams" dialog box. */
200 rtp_stream_dlg = NULL;
204 /****************************************************************************/
206 rtpstream_on_unselect (GtkButton *button _U_,
207 gpointer user_data _U_)
209 selected_stream_fwd = NULL;
210 selected_stream_rev = NULL;
211 gtk_clist_unselect_all(GTK_CLIST(clist));
212 gtk_label_set_text(GTK_LABEL(label_fwd), FWD_LABEL_TEXT);
213 gtk_label_set_text(GTK_LABEL(label_rev), REV_LABEL_TEXT);
217 /****************************************************************************/
218 static gint rtp_stream_info_cmp_reverse(gconstpointer aa, gconstpointer bb)
220 const struct _rtp_stream_info* a = aa;
221 const struct _rtp_stream_info* b = bb;
223 if (a==NULL || b==NULL)
225 if ((ADDRESSES_EQUAL(&(a->src_addr), &(b->dest_addr)))
226 && (a->src_port == b->dest_port)
227 && (ADDRESSES_EQUAL(&(a->dest_addr), &(b->src_addr)))
228 && (a->dest_port == b->src_port))
234 /****************************************************************************/
236 rtpstream_on_findrev (GtkButton *button _U_,
237 gpointer user_data _U_)
241 rtp_stream_info_t* pstream = NULL;
243 if (selected_stream_fwd==NULL)
245 if (selected_stream_rev==NULL) {
246 pstream = selected_stream_fwd;
249 pstream = selected_stream_rev;
252 start_row = gtk_clist_find_row_from_data(GTK_CLIST(clist), pstream);
255 for (row=start_row+1;
256 (pstream = gtk_clist_get_row_data(GTK_CLIST(clist), row));
258 if (rtp_stream_info_cmp_reverse(selected_stream_fwd, pstream) == 0) {
259 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
260 gtk_clist_moveto(GTK_CLIST(clist), row, 0, 0.5, 0);
267 (pstream = gtk_clist_get_row_data(GTK_CLIST(clist), row)) && row<start_row;
269 if (rtp_stream_info_cmp_reverse(selected_stream_fwd, pstream) == 0) {
270 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
271 gtk_clist_moveto(GTK_CLIST(clist), row, 0, 0.5, 0);
276 /* if we didnt find another stream, highlight the current reverse stream */
277 if (selected_stream_rev!=NULL) {
278 gtk_clist_select_row(GTK_CLIST(clist), row, 0);
279 gtk_clist_moveto(GTK_CLIST(clist), row, 0, 0.5, 0);
284 /****************************************************************************/
287 rtpstream_on_goto (GtkButton *button _U_,
288 gpointer user_data _U_)
290 if (selected_stream_fwd)
292 cf_goto_frame(&cfile, selected_stream_fwd->first_frame_num);
298 /****************************************************************************/
300 rtpstream_on_save (GtkButton *button _U_,
303 rtpstream_tapinfo_t* tapinfo = data;
308 if (!selected_stream_fwd)
311 if (rtpstream_save_dlg != NULL) {
312 /* There's already a Save dialog box; reactivate it. */
313 reactivate_window(rtpstream_save_dlg);
317 /* XXX - use file_selection from dlg_utils instead! */
318 rtpstream_save_dlg = gtk_file_selection_new("Wireshark: Save selected stream in rtpdump ('-F dump') format");
320 /* Container for each row of widgets */
321 vertb = gtk_vbox_new(FALSE, 0);
322 gtk_container_border_width(GTK_CONTAINER(vertb), 5);
323 gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(rtpstream_save_dlg)->action_area),
324 vertb, FALSE, FALSE, 0);
325 gtk_widget_show (vertb);
327 ok_bt = GTK_FILE_SELECTION(rtpstream_save_dlg)->ok_button;
328 SIGNAL_CONNECT(ok_bt, "clicked", save_stream_ok_cb, tapinfo);
330 window_set_cancel_button(rtpstream_save_dlg,
331 GTK_FILE_SELECTION(rtpstream_save_dlg)->cancel_button, window_cancel_button_cb);
333 SIGNAL_CONNECT(rtpstream_save_dlg, "delete_event", window_delete_event_cb, NULL);
334 SIGNAL_CONNECT(rtpstream_save_dlg, "destroy", save_stream_destroy_cb,
337 gtk_widget_show(rtpstream_save_dlg);
338 window_present(rtpstream_save_dlg);
342 /****************************************************************************/
344 rtpstream_on_mark (GtkButton *button _U_,
345 gpointer user_data _U_)
347 if (selected_stream_fwd==NULL && selected_stream_rev==NULL)
349 rtpstream_mark(selected_stream_fwd, selected_stream_rev);
353 /****************************************************************************/
355 rtpstream_on_filter (GtkButton *button _U_,
356 gpointer user_data _U_)
358 gchar *filter_string = NULL;
359 gchar *filter_string_fwd = NULL;
360 gchar *filter_string_rev = NULL;
363 if (selected_stream_fwd==NULL && selected_stream_rev==NULL)
366 if (selected_stream_fwd)
368 if (selected_stream_fwd->src_addr.type==AT_IPv6){
369 strcpy(ip_version,"v6");
372 strcpy(ip_version,"");
374 filter_string_fwd = g_strdup_printf(
375 "(ip%s.src==%s && udp.srcport==%u && ip%s.dst==%s && udp.dstport==%u && rtp.ssrc==%u)",
377 address_to_str(&(selected_stream_fwd->src_addr)),
378 selected_stream_fwd->src_port,
380 address_to_str(&(selected_stream_fwd->dest_addr)),
381 selected_stream_fwd->dest_port,
382 selected_stream_fwd->ssrc);
383 filter_string = filter_string_fwd;
386 if (selected_stream_rev)
388 if (selected_stream_fwd->src_addr.type==AT_IPv6){
389 strcpy(ip_version,"v6");
392 strcpy(ip_version,"");
394 filter_string_rev = g_strdup_printf(
395 "(ip%s.src==%s && udp.srcport==%u && ip%s.dst==%s && udp.dstport==%u && rtp.ssrc==%u)",
397 address_to_str(&(selected_stream_rev->src_addr)),
398 selected_stream_rev->src_port,
400 address_to_str(&(selected_stream_rev->dest_addr)),
401 selected_stream_rev->dest_port,
402 selected_stream_rev->ssrc);
404 filter_string = filter_string_rev;
406 if (selected_stream_fwd)
408 filter_string = g_strdup_printf("%s || %s", filter_string, filter_string_rev);
409 g_free(filter_string_fwd);
410 g_free(filter_string_rev);
414 gtk_entry_set_text(GTK_ENTRY(main_display_filter_widget), filter_string);
415 g_free(filter_string);
418 main_filter_packets(&cfile, filter_string, FALSE);
419 rtpstream_dlg_update(rtpstream_get_info()->strinfo_list);
424 /****************************************************************************/
425 #if (GTK_MAJOR_VERSION >= 2)
427 rtpstream_on_copy_as_csv(GtkWindow *win _U_, gpointer data _U_)
434 CSV_str = g_string_sized_new(240*(GTK_CLIST(clist)->rows+1));
435 /* Add the column headers to the CSV data */
436 for (j=0; j<NUM_COLS; j++) {
437 g_string_append(CSV_str, titles[j]);
438 g_string_append(CSV_str, ",");
440 g_string_append(CSV_str,"\n");
442 /* Add the column values to the CSV data */
443 for (i=0; i<GTK_CLIST(clist)->rows; i++) {
444 for (j=0; j<NUM_COLS; j++) {
445 gtk_clist_get_text(GTK_CLIST(clist),i,j,&table_entry);
446 g_string_append(CSV_str,table_entry);
447 g_string_append(CSV_str,",");
449 g_string_append(CSV_str,"\n");
452 /* Now that we have the CSV data, copy it into the default clipboard */
453 cb = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
454 gtk_clipboard_set_text(cb, CSV_str->str, CSV_str->len);
455 g_string_free(CSV_str, TRUE);
459 /****************************************************************************/
461 rtpstream_on_analyse (GtkButton *button _U_,
462 gpointer user_data _U_)
465 guint16 port_src_fwd = 0;
467 guint16 port_dst_fwd = 0;
468 guint32 ssrc_fwd = 0;
470 guint16 port_src_rev = 0;
472 guint16 port_dst_rev = 0;
473 guint32 ssrc_rev = 0;
475 if (!(selected_stream_fwd || selected_stream_rev))
480 SET_ADDRESS(&ip_src_fwd,AT_NONE,0,NULL);
481 SET_ADDRESS(&ip_dst_fwd,AT_NONE,0,NULL);
482 SET_ADDRESS(&ip_src_rev,AT_NONE,0,NULL);
483 SET_ADDRESS(&ip_dst_rev,AT_NONE,0,NULL);
485 if (selected_stream_fwd) {
486 COPY_ADDRESS(&(ip_src_fwd), &(selected_stream_fwd->src_addr));
487 port_src_fwd = selected_stream_fwd->src_port;
488 COPY_ADDRESS(&(ip_dst_fwd), &(selected_stream_fwd->dest_addr));
489 port_dst_fwd = selected_stream_fwd->dest_port;
490 ssrc_fwd = selected_stream_fwd->ssrc;
493 if (selected_stream_rev) {
494 COPY_ADDRESS(&(ip_src_rev), &(selected_stream_rev->src_addr));
495 port_src_rev = selected_stream_rev->src_port;
496 COPY_ADDRESS(&(ip_dst_rev), &(selected_stream_rev->dest_addr));
497 port_dst_rev = selected_stream_rev->dest_port;
498 ssrc_rev = selected_stream_rev->ssrc;
517 /****************************************************************************/
518 /* when the user selects a row in the stream list */
520 rtpstream_on_select_row(GtkCList *clist,
523 GdkEventButton *event _U_,
524 gpointer user_data _U_)
526 gchar label_text[80];
528 /* update the labels */
529 if (event==NULL || event->state & GDK_SHIFT_MASK) {
530 selected_stream_rev = gtk_clist_get_row_data(GTK_CLIST(clist), row);
531 g_snprintf(label_text, 80, "Reverse: %s:%u -> %s:%u, SSRC=%u",
532 get_addr_name(&(selected_stream_rev->src_addr)),
533 selected_stream_rev->src_port,
534 get_addr_name(&(selected_stream_rev->dest_addr)),
535 selected_stream_rev->dest_port,
536 selected_stream_rev->ssrc
538 gtk_label_set_text(GTK_LABEL(label_rev), label_text);
541 selected_stream_fwd = gtk_clist_get_row_data(GTK_CLIST(clist), row);
542 g_snprintf(label_text, 80, "Forward: %s:%u -> %s:%u, SSRC=%u",
543 get_addr_name(&(selected_stream_fwd->src_addr)),
544 selected_stream_fwd->src_port,
545 get_addr_name(&(selected_stream_fwd->dest_addr)),
546 selected_stream_fwd->dest_port,
547 selected_stream_fwd->ssrc
549 gtk_label_set_text(GTK_LABEL(label_fwd), label_text);
553 gtk_widget_set_sensitive(save_bt, TRUE);
554 gtk_widget_set_sensitive(filter_bt, TRUE);
555 gtk_widget_set_sensitive(mark_bt, TRUE);
557 /* TODO: activate other buttons when implemented */
561 /****************************************************************************/
562 typedef struct column_arrows {
564 GtkWidget *ascend_pm;
565 GtkWidget *descend_pm;
569 /****************************************************************************/
571 rtpstream_click_column_cb(GtkCList *clist, gint column, gpointer data)
573 column_arrows *col_arrows = (column_arrows *) data;
576 gtk_clist_freeze(clist);
578 for (i=0; i<NUM_COLS; i++) {
579 gtk_widget_hide(col_arrows[i].ascend_pm);
580 gtk_widget_hide(col_arrows[i].descend_pm);
583 if (column == clist->sort_column) {
584 if (clist->sort_type == GTK_SORT_ASCENDING) {
585 clist->sort_type = GTK_SORT_DESCENDING;
586 gtk_widget_show(col_arrows[column].descend_pm);
588 clist->sort_type = GTK_SORT_ASCENDING;
589 gtk_widget_show(col_arrows[column].ascend_pm);
592 clist->sort_type = GTK_SORT_ASCENDING;
593 gtk_widget_show(col_arrows[column].ascend_pm);
594 gtk_clist_set_sort_column(clist, column);
596 gtk_clist_thaw(clist);
598 gtk_clist_sort(clist);
602 /****************************************************************************/
604 rtpstream_sort_column(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
610 const GtkCListRow *row1 = (const GtkCListRow *) ptr1;
611 const GtkCListRow *row2 = (const GtkCListRow *) ptr2;
613 text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
614 text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
616 switch(clist->sort_column){
621 return strcmp (text1, text2);
634 g_assert_not_reached();
639 /****************************************************************************/
641 /****************************************************************************/
643 static void rtpstream_dlg_create (void)
645 GtkWidget *rtpstream_dlg_w;
647 GtkWidget *scrolledwindow;
648 GtkWidget *hbuttonbox;
649 /* GtkWidget *bt_goto;*/
650 GtkWidget *bt_unselect;
651 GtkWidget *bt_findrev;
654 GtkWidget *bt_filter;
655 GtkWidget *bt_analyze;
657 #if (GTK_MAJOR_VERSION >= 2)
660 GtkTooltips *tooltips = gtk_tooltips_new();
662 column_arrows *col_arrows;
663 GtkWidget *column_lb;
666 rtpstream_dlg_w = dlg_window_new("Wireshark: RTP Streams");
667 gtk_window_set_default_size(GTK_WINDOW(rtpstream_dlg_w), 620, 200);
669 main_vb = gtk_vbox_new (FALSE, 0);
670 gtk_container_add(GTK_CONTAINER(rtpstream_dlg_w), main_vb);
671 gtk_container_set_border_width (GTK_CONTAINER (main_vb), 12);
673 top_label = gtk_label_new ("Detected 0 RTP streams. Choose one for forward and reverse direction for analysis");
674 gtk_box_pack_start (GTK_BOX (main_vb), top_label, FALSE, FALSE, 8);
676 scrolledwindow = scrolled_window_new (NULL, NULL);
677 gtk_box_pack_start (GTK_BOX (main_vb), scrolledwindow, TRUE, TRUE, 0);
679 clist = gtk_clist_new (NUM_COLS);
680 gtk_container_add (GTK_CONTAINER (scrolledwindow), clist);
682 gtk_clist_set_column_width (GTK_CLIST (clist), 0, 88);
683 gtk_clist_set_column_width (GTK_CLIST (clist), 1, 44);
684 gtk_clist_set_column_width (GTK_CLIST (clist), 2, 88);
685 gtk_clist_set_column_width (GTK_CLIST (clist), 3, 44);
686 gtk_clist_set_column_width (GTK_CLIST (clist), 4, 64);
687 gtk_clist_set_column_width (GTK_CLIST (clist), 5, 96);
688 gtk_clist_set_column_width (GTK_CLIST (clist), 6, 50);
689 gtk_clist_set_column_width (GTK_CLIST (clist), 7, 50);
690 gtk_clist_set_column_width (GTK_CLIST (clist), 8, 80);
691 gtk_clist_set_column_width (GTK_CLIST (clist), 9, 80);
692 gtk_clist_set_column_width (GTK_CLIST (clist), 10, 80);
693 gtk_clist_set_column_width (GTK_CLIST (clist), 11, 40);
695 gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);
696 gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);
697 gtk_clist_set_column_justification(GTK_CLIST(clist), 2, GTK_JUSTIFY_CENTER);
698 gtk_clist_set_column_justification(GTK_CLIST(clist), 3, GTK_JUSTIFY_CENTER);
699 gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);
700 gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_LEFT);
701 gtk_clist_set_column_justification(GTK_CLIST(clist), 6, GTK_JUSTIFY_RIGHT);
702 gtk_clist_set_column_justification(GTK_CLIST(clist), 7, GTK_JUSTIFY_RIGHT);
703 gtk_clist_set_column_justification(GTK_CLIST(clist), 8, GTK_JUSTIFY_RIGHT);
704 gtk_clist_set_column_justification(GTK_CLIST(clist), 9, GTK_JUSTIFY_RIGHT);
705 gtk_clist_set_column_justification(GTK_CLIST(clist), 10, GTK_JUSTIFY_RIGHT);
706 gtk_clist_set_column_justification(GTK_CLIST(clist), 11, GTK_JUSTIFY_LEFT);
708 gtk_clist_column_titles_show (GTK_CLIST (clist));
710 gtk_clist_set_compare_func(GTK_CLIST(clist), rtpstream_sort_column);
711 gtk_clist_set_sort_column(GTK_CLIST(clist), 0);
712 gtk_clist_set_sort_type(GTK_CLIST(clist), GTK_SORT_ASCENDING);
714 gtk_widget_show(rtpstream_dlg_w);
716 /* sort by column feature */
717 col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * NUM_COLS);
719 for (i=0; i<NUM_COLS; i++) {
720 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
721 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
722 column_lb = gtk_label_new(titles[i]);
723 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
724 gtk_widget_show(column_lb);
726 col_arrows[i].ascend_pm = xpm_to_widget(clist_ascend_xpm);
727 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
728 col_arrows[i].descend_pm = xpm_to_widget(clist_descend_xpm);
729 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
730 /* make src-ip be the default sort order */
732 gtk_widget_show(col_arrows[i].ascend_pm);
734 gtk_clist_set_column_widget(GTK_CLIST(clist), i, col_arrows[i].table);
735 gtk_widget_show(col_arrows[i].table);
738 SIGNAL_CONNECT(clist, "click-column", rtpstream_click_column_cb, col_arrows);
740 label_fwd = gtk_label_new (FWD_LABEL_TEXT);
741 gtk_box_pack_start (GTK_BOX (main_vb), label_fwd, FALSE, FALSE, 0);
743 label_rev = gtk_label_new (REV_LABEL_TEXT);
744 gtk_box_pack_start (GTK_BOX (main_vb), label_rev, FALSE, FALSE, 0);
747 hbuttonbox = gtk_hbutton_box_new ();
748 gtk_box_pack_start (GTK_BOX (main_vb), hbuttonbox, FALSE, FALSE, 0);
749 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_END);
750 gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 0);
752 bt_unselect = gtk_button_new_with_label ("Unselect");
753 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_unselect);
754 gtk_tooltips_set_tip (tooltips, bt_unselect, "Undo stream selection", NULL);
756 bt_findrev = gtk_button_new_with_label ("Find Reverse");
757 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_findrev);
758 gtk_tooltips_set_tip (tooltips, bt_findrev, "Find the reverse stream matching the selected forward stream", NULL);
760 bt_goto = BUTTON_NEW_FROM_STOCK(GTK_STOCK_JUMP_TO);
761 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_goto);
763 bt_save = BUTTON_NEW_FROM_STOCK(GTK_STOCK_SAVE_AS);
764 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_save);
765 gtk_tooltips_set_tip (tooltips, bt_save, "Save stream payload in rtpdump format", NULL);
767 bt_mark = gtk_button_new_with_label ("Mark Packets");
768 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_mark);
769 gtk_tooltips_set_tip (tooltips, bt_mark, "Mark packets of the selected stream(s)", NULL);
771 bt_filter = gtk_button_new_with_label ("Prepare Filter");
772 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_filter);
773 gtk_tooltips_set_tip (tooltips, bt_filter, "Prepare a display filter of the selected stream(s)", NULL);
775 #if (GTK_MAJOR_VERSION >= 2)
776 /* XXX - maybe we want to have a "Copy as CSV" stock button here? */
777 /*bt_copy = gtk_button_new_with_label ("Copy content to clipboard as CSV");*/
778 bt_copy = BUTTON_NEW_FROM_STOCK(GTK_STOCK_COPY);
779 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_copy);
780 gtk_tooltips_set_tip(tooltips, bt_copy,
781 "Copy all statistical values of this page to the clipboard in CSV (Comma Seperated Values) format.", NULL);
784 bt_analyze = gtk_button_new_with_label ("Analyze");
785 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_analyze);
786 gtk_tooltips_set_tip (tooltips, bt_analyze, "Open an analyze window of the selected stream(s)", NULL);
788 bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
789 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
790 gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
791 GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
793 SIGNAL_CONNECT(clist, "select_row", rtpstream_on_select_row, NULL);
794 SIGNAL_CONNECT(bt_unselect, "clicked", rtpstream_on_unselect, NULL);
795 SIGNAL_CONNECT(bt_findrev, "clicked", rtpstream_on_findrev, NULL);
797 SIGNAL_CONNECT(bt_goto, "clicked", rtpstream_on_goto, NULL);
799 SIGNAL_CONNECT(bt_save, "clicked", rtpstream_on_save, NULL);
800 SIGNAL_CONNECT(bt_mark, "clicked", rtpstream_on_mark, NULL);
801 SIGNAL_CONNECT(bt_filter, "clicked", rtpstream_on_filter, NULL);
802 #if (GTK_MAJOR_VERSION >= 2)
803 SIGNAL_CONNECT(bt_copy, "clicked", rtpstream_on_copy_as_csv, NULL);
805 SIGNAL_CONNECT(bt_analyze, "clicked", rtpstream_on_analyse, NULL);
807 window_set_cancel_button(rtpstream_dlg_w, bt_close, window_cancel_button_cb);
809 SIGNAL_CONNECT(rtpstream_dlg_w, "delete_event", window_delete_event_cb, NULL);
810 SIGNAL_CONNECT(rtpstream_dlg_w, "destroy", rtpstream_on_destroy, NULL);
812 gtk_widget_show_all(rtpstream_dlg_w);
813 window_present(rtpstream_dlg_w);
815 rtpstream_on_unselect(NULL, NULL);
817 rtp_stream_dlg = rtpstream_dlg_w;
821 /****************************************************************************/
823 /****************************************************************************/
825 /****************************************************************************/
826 /* update the contents of the dialog box clist */
827 /* list: pointer to list of rtp_stream_info_t* */
828 void rtpstream_dlg_update(GList *list)
830 if (rtp_stream_dlg != NULL) {
831 gtk_clist_clear(GTK_CLIST(clist));
834 list = g_list_first(list);
837 add_to_clist((rtp_stream_info_t*)(list->data));
838 list = g_list_next(list);
841 rtpstream_on_unselect(NULL, NULL);
848 /****************************************************************************/
849 /* update the contents of the dialog box clist */
850 /* list: pointer to list of rtp_stream_info_t* */
851 void rtpstream_dlg_show(GList *list)
853 if (rtp_stream_dlg != NULL) {
854 /* There's already a dialog box; reactivate it. */
855 reactivate_window(rtp_stream_dlg);
856 /* Another list since last call? */
857 if (list != last_list) {
858 rtpstream_dlg_update(list);
862 /* Create and show the dialog box */
863 rtpstream_dlg_create();
864 rtpstream_dlg_update(list);
869 /****************************************************************************/
870 /* entry point when called via the GTK menu */
871 static void rtpstream_launch(GtkWidget *w _U_, gpointer data _U_)
873 /* Register the tap listener */
874 register_tap_listener_rtp_stream();
876 /* Scan for RTP streams (redissect all packets) */
879 /* Show the dialog box with the list of streams */
880 rtpstream_dlg_show(rtpstream_get_info()->strinfo_list);
882 /* Tap listener will be removed and cleaned up in rtpstream_on_destroy */
885 /****************************************************************************/
887 register_tap_listener_rtp_stream_dlg(void)
889 register_stat_menu_item("RTP/Show All Streams", REGISTER_STAT_GROUP_TELEPHONY,
890 rtpstream_launch, NULL, NULL, NULL);