2 * IAX2 analysis addition for Wireshark
6 * based on rtp_analysis.c
7 * Copyright 2003, Alcatel Business Systems
8 * By Lars Ruoff <lars.ruoff@gmx.net>
11 * Copyright 2003, Iskratel, Ltd, Kranj
12 * By Miha Jemec <m.jemec@iskratel.si>
14 * Graph. Copyright 2004, Verso Technology
15 * By Alejandro Vaquero <alejandro.vaquero@verso.com>
16 * Based on io_stat.c by Ronnie Sahlberg
18 * Wireshark - Network traffic analyzer
19 * By Gerald Combs <gerald@wireshark.org>
20 * Copyright 1998 Gerald Combs
22 * This program is free software; you can redistribute it and/or
23 * modify it under the terms of the GNU General Public License
24 * as published by the Free Software Foundation; either version 2
25 * of the License, or (at your option) any later version.
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
54 #include <wsutil/file_util.h>
55 #include <wsutil/g711.h>
56 #include <wsutil/tempfile.h>
57 #include <wsutil/pint.h>
59 #include <epan/epan_dissect.h>
60 #include <epan/filesystem.h>
62 #include <epan/tap-voip.h>
63 #include <epan/dissectors/packet-iax2.h>
64 #include <epan/iax2_codec_type.h>
65 #include <epan/addr_resolv.h>
66 #include <epan/stat_cmd_args.h>
67 #include <epan/strutil.h>
69 #include "../stat_menu.h"
72 #include "ui/alert_box.h"
73 #include "ui/last_open_dir.h"
74 #include "ui/progress_dlg.h"
75 #include "ui/simple_dialog.h"
76 #include "ui/utf8_entities.h"
78 #include "ui/gtk/gtkglobals.h"
79 #include "ui/gtk/dlg_utils.h"
80 #include "ui/gtk/file_dlg.h"
81 #include "ui/gtk/gui_utils.h"
82 #include "ui/gtk/gui_stat_menu.h"
83 #include "ui/gtk/main.h"
84 #include "ui/rtp_analysis.h"
85 #include "ui/gtk/iax2_analysis.h"
86 #include "ui/rtp_stream.h"
87 #include "ui/gtk/rtp_stream_dlg.h"
88 #include "ui/gtk/old-gtk-compat.h"
89 #include "ui/gtk/gui_utils.h"
91 #include "frame_tvbuff.h"
102 FOREGROUND_COLOR_COL
,
103 BACKGROUND_COLOR_COL
,
104 N_COLUMN
/* The number of columns */
107 /****************************************************************************/
109 #define NUM_GRAPH_ITEMS 100000
110 #define MAX_YSCALE 16
111 #define DEFAULT_YSCALE_INDEX 0 /* AUTO_MAX_YSCALE */
112 #define AUTO_MAX_YSCALE 0
114 #define GRAPH_FWD_JITTER 0
115 #define GRAPH_FWD_DIFF 1
116 #define GRAPH_REV_JITTER 2
117 #define GRAPH_REV_DIFF 3
118 static guint32 yscale_max
[MAX_YSCALE
] = {
119 AUTO_MAX_YSCALE
, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000,
120 1000000, 2000000, 5000000, 10000000, 20000000, 50000000
123 #define MAX_PIXELS_PER_TICK 4
124 #define DEFAULT_PIXELS_PER_TICK_INDEX 1
125 static guint32 pixels_per_tick
[MAX_PIXELS_PER_TICK
] = {1, 2, 5, 10};
126 static const char *graph_descr
[4] = {
127 "Fwd Jitter", "Fwd Difference", "Rvr Jitter", "Rvr Difference"
130 #define MAX_TICK_VALUES 5
131 #define DEFAULT_TICK_VALUE_INDEX 1
132 static guint tick_interval_values
[MAX_TICK_VALUES
] = { 1, 10, 100, 1000, 10000 };
133 typedef struct _dialog_graph_graph_item_t
{
136 } dialog_graph_graph_item_t
;
138 typedef struct _dialog_graph_graph_t
{
139 struct _user_data_t
*ud
;
140 dialog_graph_graph_item_t items
[NUM_GRAPH_ITEMS
];
143 GtkWidget
*display_button
;
148 } dialog_graph_graph_t
;
151 typedef struct _dialog_graph_t
{
152 gboolean needs_redraw
;
153 gint32 interval
; /* measurement interval in ms */
154 guint32 last_interval
;
155 guint32 max_interval
; /* XXX max_interval and num_items are redundant */
159 struct _dialog_graph_graph_t graph
[MAX_GRAPHS
];
161 GtkWidget
*draw_area
;
162 #if GTK_CHECK_VERSION(2,22,0)
163 cairo_surface_t
*surface
;
167 GtkAdjustment
*scrollbar_adjustment
;
168 GtkWidget
*scrollbar
;
175 typedef struct _dialog_data_t
{
180 GtkWidget
*label_stats_fwd
;
181 GtkWidget
*label_stats_rev
;
182 GtkWidget
*selected_list
;
184 GtkTreeSelection
*selected_list_sel
;
185 gint selected_list_row
;
187 GtkWidget
*save_voice_as_w
;
188 GtkWidget
*save_csv_as_w
;
189 gulong notebook_signal_id
;
190 dialog_graph_t dialog_graph
;
193 #define OK_TEXT "[ Ok ]"
195 /* type of error when saving voice in a file didn't succeed */
198 TAP_RTP_WRONG_LENGTH
,
199 TAP_RTP_PADDING_ERROR
,
201 TAP_RTP_FILE_OPEN_ERROR
,
202 TAP_RTP_FILE_WRITE_ERROR
,
206 typedef struct _tap_iax2_save_info_t
{
209 error_type_t error_type
;
211 } tap_iax2_save_info_t
;
214 /* structure that holds the information about the forward and reversed direction */
215 struct _info_direction
{
216 tap_iax2_stat_t statinfo
;
217 tap_iax2_save_info_t saveinfo
;
220 #define SILENCE_PCMU (guint8)0xFF
221 #define SILENCE_PCMA (guint8)0x55
223 /* structure that holds general information about the connection
224 * and structures for both directions */
225 typedef struct _user_data_t
{
226 /* tap associated data*/
228 guint16 port_src_fwd
;
230 guint16 port_dst_fwd
;
232 guint16 port_src_rev
;
234 guint16 port_dst_rev
;
236 struct _info_direction forward
;
237 struct _info_direction reversed
;
242 /* dialog associated data */
249 static const gchar
*titles
[7] = {
259 #define SAVE_FORWARD_DIRECTION_MASK 0x01
260 #define SAVE_REVERSE_DIRECTION_MASK 0x02
261 #define SAVE_BOTH_DIRECTION_MASK (SAVE_FORWARD_DIRECTION_MASK|SAVE_REVERSE_DIRECTION_MASK)
263 #define SAVE_NONE_FORMAT 0
264 #define SAVE_WAV_FORMAT 1
265 #define SAVE_AU_FORMAT 2
266 #define SAVE_SW_FORMAT 3
267 #define SAVE_RAW_FORMAT 4
270 static void on_refresh_bt_clicked(GtkWidget
*bt _U_
, gpointer data
);
271 /****************************************************************************/
273 enable_graph(dialog_graph_graph_t
*dgg
)
280 static void dialog_graph_reset(user_data_t
* user_data
);
284 /****************************************************************************/
287 /****************************************************************************/
288 /* when there is a [re]reading of packet's */
290 iax2_reset(void *user_data_arg
)
292 user_data_t
*user_data
= (user_data_t
*)user_data_arg
;
293 user_data
->forward
.statinfo
.first_packet
= TRUE
;
294 user_data
->reversed
.statinfo
.first_packet
= TRUE
;
295 user_data
->forward
.statinfo
.max_delta
= 0;
296 user_data
->reversed
.statinfo
.max_delta
= 0;
297 user_data
->forward
.statinfo
.max_jitter
= 0;
298 user_data
->reversed
.statinfo
.max_jitter
= 0;
299 user_data
->forward
.statinfo
.mean_jitter
= 0;
300 user_data
->reversed
.statinfo
.mean_jitter
= 0;
301 user_data
->forward
.statinfo
.delta
= 0;
302 user_data
->reversed
.statinfo
.delta
= 0;
303 user_data
->forward
.statinfo
.diff
= 0;
304 user_data
->reversed
.statinfo
.diff
= 0;
305 user_data
->forward
.statinfo
.jitter
= 0;
306 user_data
->reversed
.statinfo
.jitter
= 0;
307 user_data
->forward
.statinfo
.bandwidth
= 0;
308 user_data
->reversed
.statinfo
.bandwidth
= 0;
309 user_data
->forward
.statinfo
.total_bytes
= 0;
310 user_data
->reversed
.statinfo
.total_bytes
= 0;
311 user_data
->forward
.statinfo
.bw_start_index
= 0;
312 user_data
->reversed
.statinfo
.bw_start_index
= 0;
313 user_data
->forward
.statinfo
.bw_index
= 0;
314 user_data
->reversed
.statinfo
.bw_index
= 0;
315 user_data
->forward
.statinfo
.timestamp
= 0;
316 user_data
->reversed
.statinfo
.timestamp
= 0;
317 user_data
->forward
.statinfo
.max_nr
= 0;
318 user_data
->reversed
.statinfo
.max_nr
= 0;
319 user_data
->forward
.statinfo
.total_nr
= 0;
320 user_data
->reversed
.statinfo
.total_nr
= 0;
321 user_data
->forward
.statinfo
.sequence
= 0;
322 user_data
->reversed
.statinfo
.sequence
= 0;
323 user_data
->forward
.statinfo
.start_seq_nr
= 0;
324 user_data
->reversed
.statinfo
.start_seq_nr
= 1; /* 1 is ok (for statistics in reversed direction) */
325 user_data
->forward
.statinfo
.stop_seq_nr
= 0;
326 user_data
->reversed
.statinfo
.stop_seq_nr
= 0;
327 user_data
->forward
.statinfo
.cycles
= 0;
328 user_data
->reversed
.statinfo
.cycles
= 0;
329 user_data
->forward
.statinfo
.under
= FALSE
;
330 user_data
->reversed
.statinfo
.under
= FALSE
;
331 user_data
->forward
.statinfo
.start_time
= 0;
332 user_data
->reversed
.statinfo
.start_time
= 0;
333 user_data
->forward
.statinfo
.time
= 0;
334 user_data
->reversed
.statinfo
.time
= 0;
335 user_data
->forward
.statinfo
.reg_pt
= PT_UNDEFINED
;
336 user_data
->reversed
.statinfo
.reg_pt
= PT_UNDEFINED
;
338 user_data
->forward
.saveinfo
.count
= 0;
339 user_data
->reversed
.saveinfo
.count
= 0;
340 user_data
->forward
.saveinfo
.saved
= FALSE
;
341 user_data
->reversed
.saveinfo
.saved
= FALSE
;
343 /* clear the dialog box lists */
344 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(user_data
->dlg
.list_fwd
))));
345 gtk_list_store_clear(GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(user_data
->dlg
.list_rev
))));
347 /* reset graph info */
348 dialog_graph_reset(user_data
);
351 /* XXX check for error at fclose? */
352 if (user_data
->forward
.saveinfo
.fp
!= NULL
)
353 fclose(user_data
->forward
.saveinfo
.fp
);
354 if (user_data
->reversed
.saveinfo
.fp
!= NULL
)
355 fclose(user_data
->reversed
.saveinfo
.fp
);
356 user_data
->forward
.saveinfo
.fp
= ws_fopen(user_data
->f_tempname
, "wb");
357 if (user_data
->forward
.saveinfo
.fp
== NULL
)
358 user_data
->forward
.saveinfo
.error_type
= TAP_RTP_FILE_OPEN_ERROR
;
359 user_data
->reversed
.saveinfo
.fp
= ws_fopen(user_data
->r_tempname
, "wb");
360 if (user_data
->reversed
.saveinfo
.fp
== NULL
)
361 user_data
->reversed
.saveinfo
.error_type
= TAP_RTP_FILE_OPEN_ERROR
;
365 /****************************************************************************/
367 iax2_packet_add_graph(dialog_graph_graph_t
*dgg
, tap_iax2_stat_t
*statinfo
, packet_info
*pinfo
, guint32 value
)
369 dialog_graph_graph_item_t
*it
;
373 /* we sometimes get called when dgg is disabled.
374 this is a bug since the tap listener should be removed first */
379 dgg
->ud
->dlg
.dialog_graph
.needs_redraw
= TRUE
;
382 * Find which interval this is supposed to go in and store the
383 * interval index as idx
385 if (dgg
->ud
->dlg
.dialog_graph
.start_time
== -1) { /* it is the first */
386 dgg
->ud
->dlg
.dialog_graph
.start_time
= statinfo
->start_time
;
388 rtp_time
= nstime_to_msec(&pinfo
->rel_ts
) - dgg
->ud
->dlg
.dialog_graph
.start_time
;
392 idx
= (guint32
)(rtp_time
)/dgg
->ud
->dlg
.dialog_graph
.interval
;
394 /* some sanity checks */
395 if (idx
>= NUM_GRAPH_ITEMS
) {
399 /* update num_items */
400 if (idx
> dgg
->ud
->dlg
.dialog_graph
.num_items
) {
401 dgg
->ud
->dlg
.dialog_graph
.num_items
= idx
;
402 dgg
->ud
->dlg
.dialog_graph
.max_interval
= idx
*dgg
->ud
->dlg
.dialog_graph
.interval
;
406 * Find the appropriate dialog_graph_graph_item_t structure
408 it
= &dgg
->items
[idx
];
411 * Use the max value to highlight RTP problems
413 if (value
> it
->value
) {
416 it
->flags
= it
->flags
| statinfo
->flags
;
421 /****************************************************************************/
422 /* here we can redraw the output */
425 iax2_draw(void *prs _U_
)
430 /* forward declarations */
431 static void add_to_list(GtkWidget
*list
, user_data_t
* user_data
, guint32 number
,
432 double delta
, double jitter
, double bandwidth
, gchar
*status
,
433 gchar
*timeStr
, guint32 pkt_len
,gchar
*color_str
, guint32 flags
);
435 static int iax2_packet_add_info(GtkWidget
*list
,user_data_t
* user_data
,
436 tap_iax2_stat_t
*statinfo
, packet_info
*pinfo
,
437 const struct _iax2_info_t
*iax2info
);
439 static void iax2_packet_save_payload(tap_iax2_save_info_t
*saveinfo
,
440 tap_iax2_stat_t
*statinfo
,
442 const struct _iax2_info_t
*iax2info
);
445 /****************************************************************************/
446 /* whenever a IAX2 packet is seen by the tap listener */
448 iax2_packet(void *user_data_arg
, packet_info
*pinfo
, epan_dissect_t
*edt _U_
, const void *iax2info_arg
)
450 user_data_t
*user_data
= (user_data_t
*)user_data_arg
;
451 const struct _iax2_info_t
*iax2info
= (struct _iax2_info_t
*)iax2info_arg
;
453 /* we ignore packets that are not displayed */
454 if (pinfo
->fd
->flags
.passed_dfilter
== 0)
457 /* we ignore packets that carry no data */
458 if (iax2info
->payload_len
== 0)
461 /* is it the forward direction? */
462 else if ((CMP_ADDRESS(&(user_data
->ip_src_fwd
), &(pinfo
->net_src
)) == 0)
463 && (user_data
->port_src_fwd
== pinfo
->srcport
)
464 && (CMP_ADDRESS(&(user_data
->ip_dst_fwd
), &(pinfo
->net_dst
)) == 0)
465 && (user_data
->port_dst_fwd
== pinfo
->destport
)) {
466 iax2_packet_analyse(&(user_data
->forward
.statinfo
), pinfo
, iax2info
);
467 iax2_packet_add_graph(&(user_data
->dlg
.dialog_graph
.graph
[GRAPH_FWD_JITTER
]),
468 &(user_data
->forward
.statinfo
),
470 (guint32
)(user_data
->forward
.statinfo
.jitter
*1000000));
471 iax2_packet_add_graph(&(user_data
->dlg
.dialog_graph
.graph
[GRAPH_FWD_DIFF
]),
472 &(user_data
->forward
.statinfo
),
474 (guint32
)(user_data
->forward
.statinfo
.diff
*1000000));
475 iax2_packet_add_info(user_data
->dlg
.list_fwd
, user_data
,
476 &(user_data
->forward
.statinfo
), pinfo
, iax2info
);
477 iax2_packet_save_payload(&(user_data
->forward
.saveinfo
),
478 &(user_data
->forward
.statinfo
), pinfo
, iax2info
);
480 /* is it the reversed direction? */
481 else if (CMP_ADDRESS(&(user_data
->ip_src_rev
), &(pinfo
->net_src
)) == 0
482 && user_data
->port_src_rev
== pinfo
->srcport
483 && CMP_ADDRESS(&(user_data
->ip_dst_rev
), &(pinfo
->net_dst
)) == 0
484 && user_data
->port_dst_rev
== pinfo
->destport
) {
485 iax2_packet_analyse(&(user_data
->reversed
.statinfo
), pinfo
, iax2info
);
486 iax2_packet_add_graph(&(user_data
->dlg
.dialog_graph
.graph
[GRAPH_REV_JITTER
]),
487 &(user_data
->reversed
.statinfo
),
489 (guint32
)(user_data
->reversed
.statinfo
.jitter
*1000000));
490 iax2_packet_add_graph(&(user_data
->dlg
.dialog_graph
.graph
[GRAPH_REV_DIFF
]),
491 &(user_data
->reversed
.statinfo
),
493 (guint32
)(user_data
->reversed
.statinfo
.diff
*1000000));
494 iax2_packet_add_info(user_data
->dlg
.list_rev
, user_data
,
495 &(user_data
->reversed
.statinfo
), pinfo
, iax2info
);
496 iax2_packet_save_payload(&(user_data
->reversed
.saveinfo
),
497 &(user_data
->reversed
.statinfo
), pinfo
, iax2info
);
503 /****************************************************************************/
504 /* This comes from tap-rtp-common.c */
505 /****************************************************************************/
507 int iax2_packet_analyse(tap_iax2_stat_t
*statinfo
,
509 const struct _iax2_info_t
*iax2info
)
512 double current_jitter
;
516 /* check payload type */
517 if (iax2info
->ftype
== AST_FRAME_VOICE
) {
518 if (iax2info
->csub
!= statinfo
->pt
)
519 statinfo
->flags
|= STAT_FLAG_PT_CHANGE
;
520 statinfo
->pt
= iax2info
->csub
;
523 /* store the current time and calculate the current jitter */
524 current_time
= nstime_to_sec(&pinfo
->rel_ts
);
525 current_diff
= fabs (current_time
- statinfo
->time
- (((double)iax2info
->timestamp
- (double)statinfo
->timestamp
)/1000));
526 current_jitter
= statinfo
->jitter
+ ( current_diff
- statinfo
->jitter
)/16;
527 statinfo
->delta
= current_time
- (statinfo
->time
);
528 statinfo
->jitter
= current_jitter
;
529 statinfo
->diff
= current_diff
;
531 /* calculate the BW in Kbps adding the IP+IAX2 header to the RTP -> 20bytes(IP)+ 4bytes(Mini) = 24bytes */
532 statinfo
->bw_history
[statinfo
->bw_index
].bytes
= iax2info
->payload_len
+ 24;
533 statinfo
->bw_history
[statinfo
->bw_index
].time
= current_time
;
534 /* check if there are more than 1sec in the history buffer to calculate BW in bps. If so, remove those for the calculation */
535 while ((statinfo
->bw_history
[statinfo
->bw_start_index
].time
+1) < current_time
) {
536 statinfo
->total_bytes
-= statinfo
->bw_history
[statinfo
->bw_start_index
].bytes
;
537 statinfo
->bw_start_index
++;
538 if (statinfo
->bw_start_index
== BUFF_BW
) statinfo
->bw_start_index
= 0;
540 statinfo
->total_bytes
+= iax2info
->payload_len
+ 24;
541 statinfo
->bandwidth
= (double)(statinfo
->total_bytes
*8)/1000;
542 statinfo
->bw_index
++;
543 if (statinfo
->bw_index
== BUFF_BW
) statinfo
->bw_index
= 0;
546 /* is this the first packet we got in this direction? */
547 if (statinfo
->first_packet
) {
548 statinfo
->start_seq_nr
= 0;
549 statinfo
->start_time
= current_time
;
551 statinfo
->jitter
= 0;
553 statinfo
->flags
|= STAT_FLAG_FIRST
;
554 statinfo
->first_packet
= FALSE
;
556 /* is it a regular packet? */
557 if (!(statinfo
->flags
& STAT_FLAG_FIRST
)
558 && !(statinfo
->flags
& STAT_FLAG_MARKER
)
559 && !(statinfo
->flags
& STAT_FLAG_PT_CN
)
560 && !(statinfo
->flags
& STAT_FLAG_WRONG_TIMESTAMP
)
561 && !(statinfo
->flags
& STAT_FLAG_FOLLOW_PT_CN
)) {
562 /* include it in maximum delta calculation */
563 if (statinfo
->delta
> statinfo
->max_delta
) {
564 statinfo
->max_delta
= statinfo
->delta
;
565 statinfo
->max_nr
= pinfo
->fd
->num
;
567 /* maximum and mean jitter calculation */
568 if (statinfo
->jitter
> statinfo
->max_jitter
) {
569 statinfo
->max_jitter
= statinfo
->jitter
;
571 statinfo
->mean_jitter
= (statinfo
->mean_jitter
*statinfo
->total_nr
+ current_diff
) / (statinfo
->total_nr
+1);
573 /* regular payload change? (CN ignored) */
574 if (!(statinfo
->flags
& STAT_FLAG_FIRST
)
575 && !(statinfo
->flags
& STAT_FLAG_PT_CN
)) {
576 if ((statinfo
->pt
!= statinfo
->reg_pt
)
577 && (statinfo
->reg_pt
!= PT_UNDEFINED
)) {
578 statinfo
->flags
|= STAT_FLAG_REG_PT_CHANGE
;
582 /* set regular payload*/
583 if (!(statinfo
->flags
& STAT_FLAG_PT_CN
)) {
584 statinfo
->reg_pt
= statinfo
->pt
;
587 /* TODO: lost packets / duplicated: we should infer this from timestamp... */
588 statinfo
->time
= current_time
;
589 statinfo
->timestamp
= iax2info
->timestamp
; /* millisecs */
590 statinfo
->stop_seq_nr
= 0;
591 statinfo
->total_nr
++;
598 static const GdkColor COLOR_DEFAULT
= {0, 0xffff, 0xffff, 0xffff};
599 static const GdkColor COLOR_ERROR
= {0, 0xffff, 0xbfff, 0xbfff};
600 static const GdkColor COLOR_WARNING
= {0, 0xffff, 0xdfff, 0xbfff};
601 static const GdkColor COLOR_CN
= {0, 0xbfff, 0xbfff, 0xffff};
602 static const GdkColor COLOR_FOREGROUND
= {0, 0x0000, 0x0000, 0x0000};
605 /****************************************************************************/
606 /* adds statistics information from the packet to the list */
607 static int iax2_packet_add_info(GtkWidget
*list
, user_data_t
* user_data
,
608 tap_iax2_stat_t
*statinfo
, packet_info
*pinfo
,
609 const struct _iax2_info_t
*iax2info _U_
)
616 /* GdkColor color = COLOR_DEFAULT; */
618 then
= pinfo
->fd
->abs_ts
.secs
;
619 msecs
= (guint16
)(pinfo
->fd
->abs_ts
.nsecs
/1000000);
620 tm_tmp
= localtime(&then
);
621 g_snprintf(timeStr
,sizeof(timeStr
),"%02d/%02d/%04d %02d:%02d:%02d.%03d",
624 tm_tmp
->tm_year
+ 1900,
630 /* Default to using black on white text if nothing below overrides it */
631 g_snprintf(color_str
,sizeof(color_str
),"#ffffffffffff");
633 if (statinfo
->flags
& STAT_FLAG_WRONG_SEQ
) {
634 g_snprintf(status
,sizeof(status
),"Wrong sequence nr.");
635 /* color = COLOR_ERROR; */
636 g_snprintf(color_str
,sizeof(color_str
),"#ffffbfffbfff");
638 else if (statinfo
->flags
& STAT_FLAG_REG_PT_CHANGE
) {
639 g_snprintf(status
,sizeof(status
),"Payload changed to PT=%u", statinfo
->pt
);
640 /* color = COLOR_WARNING; */
641 g_snprintf(color_str
,sizeof(color_str
),"#ffffdfffbfff");
643 else if (statinfo
->flags
& STAT_FLAG_WRONG_TIMESTAMP
) {
644 g_snprintf(status
,sizeof(status
),"Incorrect timestamp");
645 /* color = COLOR_WARNING; */
646 g_snprintf(color_str
,sizeof(color_str
),"#ffffdfffbfff");
648 else if ((statinfo
->flags
& STAT_FLAG_PT_CHANGE
)
649 && !(statinfo
->flags
& STAT_FLAG_FIRST
)
650 && !(statinfo
->flags
& STAT_FLAG_PT_CN
)
651 && (statinfo
->flags
& STAT_FLAG_FOLLOW_PT_CN
)
652 && !(statinfo
->flags
& STAT_FLAG_MARKER
)) {
653 g_snprintf(status
,sizeof(status
),"Marker missing?");
654 /* color = COLOR_WARNING; */
655 g_snprintf(color_str
,sizeof(color_str
),"#ffffdfffbfff");
658 if (statinfo
->flags
& STAT_FLAG_MARKER
) {
659 /* color = COLOR_WARNING; */
660 g_snprintf(color_str
,sizeof(color_str
),"#ffffdfffbfff");
662 g_snprintf(status
,sizeof(status
),OK_TEXT
);
664 /* is this the first packet we got in this direction? */
665 if (statinfo
->flags
& STAT_FLAG_FIRST
) {
666 add_to_list(list
, user_data
,
672 timeStr
, pinfo
->fd
->pkt_len
,
677 add_to_list(list
, user_data
,
679 statinfo
->delta
*1000,
680 statinfo
->jitter
*1000,
683 timeStr
, pinfo
->fd
->pkt_len
,
690 #define MAX_SILENCE_TICKS 1000000
691 /****************************************************************************/
693 iax2_packet_save_payload(tap_iax2_save_info_t
*saveinfo
,
694 tap_iax2_stat_t
*statinfo
,
696 const struct _iax2_info_t
*iax2info
)
701 /* is this the first packet we got in this direction? */
702 if (statinfo
->flags
& STAT_FLAG_FIRST
) {
703 if (saveinfo
->fp
== NULL
) {
704 saveinfo
->saved
= FALSE
;
705 saveinfo
->error_type
= TAP_RTP_FILE_OPEN_ERROR
;
708 saveinfo
->saved
= TRUE
;
711 /* save the voice information */
712 /* if there was already an error, we quit */
713 if (saveinfo
->saved
== FALSE
)
716 /* if the captured length and packet length aren't equal, we quit */
717 if (pinfo
->fd
->pkt_len
!= pinfo
->fd
->cap_len
) {
718 saveinfo
->saved
= FALSE
;
719 saveinfo
->error_type
= TAP_RTP_WRONG_LENGTH
;
723 if (iax2info
->payload_len
> 0) {
724 data
= iax2info
->payload_data
;
725 nchars
= fwrite(data
, sizeof(unsigned char), iax2info
->payload_len
, saveinfo
->fp
);
726 if (nchars
!= iax2info
->payload_len
) {
727 /* Write error or short write */
728 saveinfo
->saved
= FALSE
;
729 saveinfo
->error_type
= TAP_RTP_FILE_WRITE_ERROR
;
732 saveinfo
->count
+= iax2info
->payload_len
;
734 if (fflush(saveinfo
->fp
) == EOF
) {
736 saveinfo
->saved
= FALSE
;
737 saveinfo
->error_type
= TAP_RTP_FILE_WRITE_ERROR
;
740 saveinfo
->saved
= TRUE
;
748 /****************************************************************************/
751 /****************************************************************************/
753 /****************************************************************************/
754 /* close the dialog window and remove the tap listener */
756 on_iax2_window_destroy(GtkWidget
*win _U_
, gpointer data
)
758 user_data_t
*user_data
= (user_data_t
*)data
;
760 /* remove tap listener */
761 remove_tap_listener(user_data
);
763 /* close and remove temporary files */
764 if (user_data
->forward
.saveinfo
.fp
!= NULL
)
765 fclose(user_data
->forward
.saveinfo
.fp
);
766 if (user_data
->reversed
.saveinfo
.fp
!= NULL
)
767 fclose(user_data
->reversed
.saveinfo
.fp
);
768 /*XXX: test for error **/
769 ws_remove(user_data
->f_tempname
);
770 ws_remove(user_data
->r_tempname
);
772 #if 0 /* XXX: GtkFileChooserDialog/gtk_dialog_run currently being used is effectively modal so this is not req'd */
773 /* destroy save_csv_as window if open */
774 if (user_data
->dlg
.save_csv_as_w
!= NULL
)
775 window_destroy(user_data
->dlg
.save_csv_as_w
);
777 /* destroy save_voice_as window if open */
778 if (user_data
->dlg
.save_voice_as_w
!= NULL
)
779 window_destroy(user_data
->dlg
.save_voice_as_w
);
781 /* destroy graph window if open */
782 if (user_data
->dlg
.dialog_graph
.window
!= NULL
)
783 window_destroy(user_data
->dlg
.dialog_graph
.window
);
786 /* disable the "switch_page" signal in the dlg, otherwise will be called when the windows is destroy and cause an exception using GTK1*/
787 /* XXX: Is this still true for GTK2 ??? */
788 g_signal_handler_disconnect(user_data
->dlg
.notebook
, user_data
->dlg
.notebook_signal_id
);
790 g_free(user_data
->f_tempname
);
791 g_free(user_data
->r_tempname
);
796 /****************************************************************************/
798 on_notebook_switch_page(GtkNotebook
*notebook _U_
,
803 user_data_t
*user_data
= (user_data_t
*)data
;
805 user_data
->dlg
.selected_list
=
806 (page_num
== 0) ? user_data
->dlg
.list_fwd
: user_data
->dlg
.list_rev
;
808 user_data
->dlg
.selected_list_row
= 0;
811 /****************************************************************************/
813 on_list_select_row(GtkTreeSelection
*selection
,
816 user_data_t
*user_data
= (user_data_t
*)data
;
818 user_data
->dlg
.selected_list_sel
= selection
;
822 /****************************************************************************/
824 dialog_graph_set_title(user_data_t
* user_data
)
828 if (!user_data
->dlg
.dialog_graph
.window
) {
831 title
= g_strdup_printf("IAX2 Graph Analysis Forward: %s:%u to %s:%u Reverse: %s:%u to %s:%u",
832 get_addr_name(&(user_data
->ip_src_fwd
)),
833 user_data
->port_src_fwd
,
834 get_addr_name(&(user_data
->ip_dst_fwd
)),
835 user_data
->port_dst_fwd
,
836 get_addr_name(&(user_data
->ip_src_rev
)),
837 user_data
->port_src_rev
,
838 get_addr_name(&(user_data
->ip_dst_rev
)),
839 user_data
->port_dst_rev
);
841 gtk_window_set_title(GTK_WINDOW(user_data
->dlg
.dialog_graph
.window
), title
);
847 /****************************************************************************/
849 dialog_graph_reset(user_data_t
* user_data
)
853 user_data
->dlg
.dialog_graph
.needs_redraw
= TRUE
;
854 for (i
= 0; i
< MAX_GRAPHS
; i
++) {
855 for (j
= 0; j
< NUM_GRAPH_ITEMS
; j
++) {
856 dialog_graph_graph_item_t
*dggi
;
857 dggi
= &user_data
->dlg
.dialog_graph
.graph
[i
].items
[j
];
862 user_data
->dlg
.dialog_graph
.last_interval
= 0xffffffff;
863 user_data
->dlg
.dialog_graph
.max_interval
= 0;
864 user_data
->dlg
.dialog_graph
.num_items
= 0;
866 /* create the color titles near the filter buttons */
867 for (i
= 0; i
< MAX_GRAPHS
; i
++) {
870 g_snprintf(user_data
->dlg
.dialog_graph
.graph
[i
].title
,
871 sizeof (user_data
->dlg
.dialog_graph
.graph
[0].title
),
872 "%s: %s:%u to %s:%u",
874 get_addr_name(&(user_data
->ip_src_fwd
)),
875 user_data
->port_src_fwd
,
876 get_addr_name(&(user_data
->ip_dst_fwd
)),
877 user_data
->port_dst_fwd
);
880 g_snprintf(user_data
->dlg
.dialog_graph
.graph
[i
].title
,
881 sizeof(user_data
->dlg
.dialog_graph
.graph
[0].title
),
882 "%s: %s:%u to %s:%u",
884 get_addr_name(&(user_data
->ip_src_rev
)),
885 user_data
->port_src_rev
,
886 get_addr_name(&(user_data
->ip_dst_rev
)),
887 user_data
->port_dst_rev
);
891 dialog_graph_set_title(user_data
);
894 /****************************************************************************/
896 get_it_value(dialog_graph_graph_t
*dgg
, int idx
)
898 dialog_graph_graph_item_t
*it
;
900 it
= &dgg
->items
[idx
];
905 /****************************************************************************/
907 print_time_scale_string(char *buf
, int buf_len
, guint32 t
)
910 g_snprintf(buf
, buf_len
, "%ds",t
/1000000);
911 } else if (t
>= 1000000) {
912 g_snprintf(buf
, buf_len
, "%d.%03ds",t
/1000000,(t
%1000000)/1000);
913 } else if (t
>= 10000) {
914 g_snprintf(buf
, buf_len
, "%dms",t
/1000);
915 } else if (t
>= 1000) {
916 g_snprintf(buf
, buf_len
, "%d.%03dms",t
/1000,t
%1000);
918 g_snprintf(buf
, buf_len
, "%dus",t
);
922 /****************************************************************************/
924 dialog_graph_draw(user_data_t
* user_data
)
927 guint32 last_interval
, first_interval
, interval_delta
, delta_multiplier
;
928 gint32 current_interval
;
929 guint32 left_x_border
;
930 guint32 right_x_border
;
931 guint32 top_y_border
;
932 guint32 bottom_y_border
;
934 int label_width
, label_height
;
935 int label_width_mid
, label_height_mid
;
936 guint32 draw_width
, draw_height
;
937 char label_string
[15];
938 GtkAllocation widget_alloc
;
942 guint32 num_time_intervals
;
943 guint32 max_value
; /* max value of seen data */
944 guint32 max_y
; /* max value of the Y scale */
946 if (!user_data
->dlg
.dialog_graph
.needs_redraw
) {
949 user_data
->dlg
.dialog_graph
.needs_redraw
= FALSE
;
952 * Find the length of the intervals we have data for
953 * so we know how large arrays we need to malloc()
955 num_time_intervals
= user_data
->dlg
.dialog_graph
.num_items
;
956 /* if there isnt anything to do, just return */
957 if (num_time_intervals
== 0) {
960 num_time_intervals
+= 1;
961 /* XXX move this check to _packet() */
962 if (num_time_intervals
> NUM_GRAPH_ITEMS
) {
963 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
964 "IAX2 Graph error. There are too many entries, bailing out");
969 * find the max value so we can autoscale the y axis
972 for (i
= 0; i
< MAX_GRAPHS
; i
++) {
975 if (!user_data
->dlg
.dialog_graph
.graph
[i
].display
) {
978 for (idx
= 0; (guint32
) (idx
) < num_time_intervals
; idx
++) {
981 val
= get_it_value(&user_data
->dlg
.dialog_graph
.graph
[i
], idx
);
983 /* keep track of the max value we have encountered */
984 if (val
> max_value
) {
993 #if GTK_CHECK_VERSION(2,22,0)
994 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
996 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
998 cairo_set_source_rgb (cr
, 1, 1, 1);
999 gtk_widget_get_allocation(user_data
->dlg
.dialog_graph
.draw_area
, &widget_alloc
);
1000 cairo_rectangle (cr
,
1004 widget_alloc
.height
);
1010 * Calculate the y scale we should use
1012 if (user_data
->dlg
.dialog_graph
.max_y_units
== AUTO_MAX_YSCALE
) {
1013 max_y
= yscale_max
[MAX_YSCALE
-1];
1014 for (i
= MAX_YSCALE
-1; i
> 0; i
--) {
1015 if (max_value
< yscale_max
[i
]) {
1016 max_y
= yscale_max
[i
];
1020 /* the user had specified an explicit y scale to use */
1021 max_y
= user_data
->dlg
.dialog_graph
.max_y_units
;
1025 * Calculate size of borders surrounding the plot
1026 * The border on the right side needs to be adjusted depending
1027 * on the width of the text labels.
1029 print_time_scale_string(label_string
, sizeof(label_string
), max_y
);
1030 layout
= gtk_widget_create_pango_layout(user_data
->dlg
.dialog_graph
.draw_area
, label_string
);
1031 pango_layout_get_pixel_size(layout
, &label_width
, &label_height
);
1032 print_time_scale_string(label_string
, sizeof(label_string
), max_y
*5/10);
1033 layout
= gtk_widget_create_pango_layout(user_data
->dlg
.dialog_graph
.draw_area
, label_string
);
1034 pango_layout_get_pixel_size(layout
, &label_width_mid
, &label_height_mid
);
1035 if (label_width_mid
> label_width
) {
1036 label_width
= label_width_mid
;
1037 label_height
= label_height_mid
;
1041 right_x_border
= label_width
+20;
1043 bottom_y_border
= label_height
+ 20;
1047 * Calculate the size of the drawing area for the actual plot
1049 draw_width
= user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
- left_x_border
;
1050 draw_height
= user_data
->dlg
.dialog_graph
.surface_height
- top_y_border
- bottom_y_border
;
1054 * Draw the y axis and labels
1055 * (we always draw the y scale with 11 ticks along the axis)
1057 #if GTK_CHECK_VERSION(2,22,0)
1058 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1060 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1062 cairo_set_line_width (cr
, 1.0);
1063 cairo_move_to(cr
, user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+1.5, top_y_border
+0.5);
1064 cairo_line_to(cr
, user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+1.5, user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+0.5);
1068 for (i
= 0; i
<= 10; i
++) {
1073 /* first, middle and last tick are slightly longer */
1077 #if GTK_CHECK_VERSION(2,22,0)
1078 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1080 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1082 cairo_set_line_width (cr
, 1.0);
1084 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+1.5,
1085 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
- draw_height
*i
/10+0.5);
1088 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+1.5 + xwidth
,
1089 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
- draw_height
*i
/10+0.5);
1092 /* draw the labels */
1094 print_time_scale_string(label_string
, sizeof(label_string
), (max_y
*i
/10));
1095 pango_layout_set_text(layout
, label_string
, -1);
1096 pango_layout_get_pixel_size(layout
, &lwidth
, NULL
);
1097 #if GTK_CHECK_VERSION(2,22,0)
1098 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1100 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1103 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+15 + label_width
- lwidth
,
1104 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
- draw_height
*i
/10 - label_height
/2);
1105 pango_cairo_show_layout (cr
, layout
);
1110 print_time_scale_string(label_string
, sizeof(label_string
), (max_y
*i
/10));
1111 pango_layout_set_text(layout
, label_string
, -1);
1112 pango_layout_get_pixel_size(layout
, &lwidth
, NULL
);
1113 #if GTK_CHECK_VERSION(2,22,0)
1114 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1116 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1119 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+15 + label_width
- lwidth
,
1120 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
- draw_height
*i
/10 - label_height
/2);
1121 pango_cairo_show_layout (cr
, layout
);
1126 print_time_scale_string(label_string
, sizeof(label_string
), (max_y
*i
/10));
1127 pango_layout_set_text(layout
, label_string
, -1);
1128 pango_layout_get_pixel_size(layout
, &lwidth
, NULL
);
1129 #if GTK_CHECK_VERSION(2,22,0)
1130 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1132 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1135 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+15 + label_width
- lwidth
,
1136 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
- draw_height
*i
/10 - label_height
/2);
1137 pango_cairo_show_layout (cr
, layout
);
1146 * if we have not specified the last_interval via the gui,
1147 * then just pick the current end of the capture so that is scrolls
1148 * nicely when doing live captures
1150 if (user_data
->dlg
.dialog_graph
.last_interval
== 0xffffffff) {
1151 last_interval
= user_data
->dlg
.dialog_graph
.max_interval
;
1153 last_interval
= user_data
->dlg
.dialog_graph
.last_interval
;
1157 /* plot the x-scale */
1158 #if GTK_CHECK_VERSION(2,22,0)
1159 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1161 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1163 cairo_set_line_width (cr
, 1.0);
1166 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+1.5);
1168 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+1.5,
1169 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+1.5);
1173 if ((last_interval
/user_data
->dlg
.dialog_graph
.interval
) > draw_width
/user_data
->dlg
.dialog_graph
.pixels_per_tick
+1) {
1174 first_interval
= (last_interval
/user_data
->dlg
.dialog_graph
.interval
)
1175 - draw_width
/user_data
->dlg
.dialog_graph
.pixels_per_tick
+1;
1176 first_interval
*= user_data
->dlg
.dialog_graph
.interval
;
1182 delta_multiplier
= 5;
1183 while (interval_delta
< ((last_interval
- first_interval
)/10)) {
1184 interval_delta
*= delta_multiplier
;
1185 if (delta_multiplier
== 5) {
1186 delta_multiplier
= 2;
1188 delta_multiplier
= 5;
1192 for (current_interval
= last_interval
;
1193 current_interval
> (gint32
)first_interval
;
1194 current_interval
= current_interval
- user_data
->dlg
.dialog_graph
.interval
) {
1197 /* if pixels_per_tick is <5, only draw every 10 ticks */
1198 if ((user_data
->dlg
.dialog_graph
.pixels_per_tick
< 10)
1199 && (current_interval
% (10 * user_data
->dlg
.dialog_graph
.interval
))) {
1203 if (current_interval
%interval_delta
) {
1209 x
= draw_width
+ left_x_border
1210 - (((last_interval
- current_interval
)/user_data
->dlg
.dialog_graph
.interval
)
1211 * user_data
->dlg
.dialog_graph
.pixels_per_tick
);
1212 #if GTK_CHECK_VERSION(2,22,0)
1213 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1215 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1217 cairo_set_line_width (cr
, 1.0);
1219 x
- 1 - user_data
->dlg
.dialog_graph
.pixels_per_tick
/2 + 0.5,
1220 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+ 1.5);
1222 x
- 1 - user_data
->dlg
.dialog_graph
.pixels_per_tick
/2 + 0.5,
1223 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+ xlen
+ 1.5);
1228 if (user_data
->dlg
.dialog_graph
.interval
>= 1000) {
1229 g_snprintf(label_string
, sizeof(label_string
), "%ds", current_interval
/1000);
1230 } else if (user_data
->dlg
.dialog_graph
.interval
>= 100) {
1231 g_snprintf(label_string
, sizeof(label_string
),
1232 "%d.%1ds", current_interval
/1000,(current_interval
/100)%10);
1233 } else if (user_data
->dlg
.dialog_graph
.interval
>= 10) {
1234 g_snprintf(label_string
, sizeof(label_string
),
1235 "%d.%2ds", current_interval
/1000,(current_interval
/10)%100);
1237 g_snprintf(label_string
, sizeof(label_string
),
1238 "%d.%3ds", current_interval
/1000,current_interval
%1000);
1240 pango_layout_set_text(layout
, label_string
, -1);
1241 pango_layout_get_pixel_size(layout
, &lwidth
, NULL
);
1242 #if GTK_CHECK_VERSION(2,22,0)
1243 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1245 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1248 x
- 1 - user_data
->dlg
.dialog_graph
.pixels_per_tick
/2 - lwidth
/2,
1249 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+ 20);
1250 pango_cairo_show_layout (cr
, layout
);
1258 * Draw "x" for Sequence Errors and "m" for Marks
1260 /* Draw the labels Fwd and Rev */
1261 g_strlcpy(label_string
, UTF8_LEFTWARDS_ARROW
"Fwd",sizeof(label_string
));
1262 pango_layout_set_text(layout
, label_string
, -1);
1263 pango_layout_get_pixel_size(layout
, &lwidth
, NULL
);
1264 #if GTK_CHECK_VERSION(2,22,0)
1265 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1267 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1270 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+33 - lwidth
,
1271 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+3);
1272 pango_cairo_show_layout (cr
, layout
);
1276 g_strlcpy(label_string
, UTF8_LEFTWARDS_ARROW
"Rev",sizeof(label_string
));
1277 pango_layout_set_text(layout
, label_string
, -1);
1278 pango_layout_get_pixel_size(layout
, &lwidth
, NULL
);
1279 #if GTK_CHECK_VERSION(2,22,0)
1280 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1282 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1285 user_data
->dlg
.dialog_graph
.surface_width
- right_x_border
+33 - lwidth
,
1286 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+3+9);
1287 pango_cairo_show_layout (cr
, layout
);
1291 /* Draw the marks */
1292 for (i
= MAX_GRAPHS
-1; i
>= 0; i
--) {
1294 guint32 x_pos
/*, prev_x_pos*/;
1296 /* XXX for fwd or rev, the flag info for jitter and diff is the same, and here I loop twice */
1297 if (!user_data
->dlg
.dialog_graph
.graph
[i
].display
) {
1300 /* initialize prev x/y to the low left corner of the graph */
1301 /* prev_x_pos=draw_width-1-user_data->dlg.dialog_graph.pixels_per_tick*((last_interval-first_interval)/user_data->dlg.dialog_graph.interval+1)+left_x_border; */
1303 for (interval
= first_interval
+ user_data
->dlg
.dialog_graph
.interval
;
1304 interval
<= last_interval
;
1305 interval
+= user_data
->dlg
.dialog_graph
.interval
) {
1306 x_pos
= draw_width
- 1
1307 - (user_data
->dlg
.dialog_graph
.pixels_per_tick
1308 * ((last_interval
- interval
)/user_data
->dlg
.dialog_graph
.interval
+1))
1311 if (user_data
->dlg
.dialog_graph
.graph
[i
].items
[interval
/user_data
->dlg
.dialog_graph
.interval
].flags
1312 & (STAT_FLAG_WRONG_SEQ
|STAT_FLAG_MARKER
)) {
1313 if (user_data
->dlg
.dialog_graph
.graph
[i
].items
[interval
/user_data
->dlg
.dialog_graph
.interval
].flags
1314 & STAT_FLAG_WRONG_SEQ
) {
1315 g_strlcpy(label_string
, "x", sizeof(label_string
));
1317 g_strlcpy(label_string
, "m", sizeof(label_string
));
1320 pango_layout_set_text(layout
, label_string
, -1);
1321 pango_layout_get_pixel_size(layout
, &lwidth
, NULL
);
1322 #if GTK_CHECK_VERSION(2,22,0)
1323 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1325 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1328 x_pos
- 1 - lwidth
/2,
1329 user_data
->dlg
.dialog_graph
.surface_height
- bottom_y_border
+3+7*(i
/2));
1330 pango_cairo_show_layout (cr
, layout
);
1335 /* prev_x_pos = x_pos; */
1339 g_object_unref(G_OBJECT(layout
));
1342 * Loop over all graphs and draw them
1344 for(i
= MAX_GRAPHS
-1; i
>= 0; i
--) {
1346 guint32 x_pos
, y_pos
, /*prev_x_pos,*/ prev_y_pos
;
1347 if (!user_data
->dlg
.dialog_graph
.graph
[i
].display
) {
1350 /* initialize prev x/y to the low left corner of the graph */
1351 /* prev_x_pos=draw_width-1-user_data->dlg.dialog_graph.pixels_per_tick*((last_interval-first_interval)/user_data->dlg.dialog_graph.interval+1)+left_x_border; */
1352 prev_y_pos
= draw_height
-1 + top_y_border
;
1354 for (interval
= first_interval
+ user_data
->dlg
.dialog_graph
.interval
;
1355 interval
<= last_interval
;
1356 interval
+= user_data
->dlg
.dialog_graph
.interval
) {
1358 x_pos
= draw_width
- 1
1359 - (user_data
->dlg
.dialog_graph
.pixels_per_tick
1360 * ((last_interval
- interval
)/user_data
->dlg
.dialog_graph
.interval
+1))
1362 val
= get_it_value(&user_data
->dlg
.dialog_graph
.graph
[i
],
1363 interval
/user_data
->dlg
.dialog_graph
.interval
);
1367 y_pos
= draw_height
-1 - (val
*draw_height
)/max_y
+ top_y_border
;
1370 /* dont need to draw anything if the segment
1371 * is entirely above the top of the graph
1373 if ( (prev_y_pos
== 0) && (y_pos
== 0) ) {
1375 /* prev_x_pos = x_pos; */
1380 #if GTK_CHECK_VERSION(2,22,0)
1381 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1383 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1385 gdk_cairo_set_source_rgba (cr
, &user_data
->dlg
.dialog_graph
.graph
[i
].rgba_color
);
1386 cairo_set_line_width (cr
, 1.0);
1387 cairo_move_to(cr
, x_pos
+0.5, draw_height
-1 + top_y_border
+0.5);
1388 cairo_line_to(cr
, x_pos
+0.5, y_pos
+0.5);
1394 /* prev_x_pos = x_pos; */
1399 cr
= gdk_cairo_create (gtk_widget_get_window(user_data
->dlg
.dialog_graph
.draw_area
));
1401 #if GTK_CHECK_VERSION(2,22,0)
1402 cairo_set_source_surface (cr
, user_data
->dlg
.dialog_graph
.surface
, 0, 0);
1404 gdk_cairo_set_source_pixmap (cr
, user_data
->dlg
.dialog_graph
.pixmap
, 0, 0);
1406 cairo_rectangle (cr
, 0, 0, user_data
->dlg
.dialog_graph
.surface_width
, user_data
->dlg
.dialog_graph
.surface_height
);
1412 /* update the scrollbar */
1413 gtk_adjustment_set_upper(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
,
1414 (gfloat
) user_data
->dlg
.dialog_graph
.max_interval
);
1415 gtk_adjustment_set_step_increment(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
,
1416 (gfloat
) ((last_interval
- first_interval
)/10));
1417 gtk_adjustment_set_page_increment(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
,
1418 (gfloat
) (last_interval
- first_interval
));
1419 if ((last_interval
- first_interval
)*100 < user_data
->dlg
.dialog_graph
.max_interval
) {
1420 gtk_adjustment_set_page_size(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
,
1421 (gfloat
) (user_data
->dlg
.dialog_graph
.max_interval
/100));
1423 gtk_adjustment_set_page_size(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
,
1424 (gfloat
) (last_interval
- first_interval
));
1426 gtk_adjustment_set_value(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
,
1428 - gtk_adjustment_get_page_size(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
));
1429 gtk_adjustment_changed(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
);
1430 gtk_adjustment_value_changed(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
);
1434 /****************************************************************************/
1436 dialog_graph_redraw(user_data_t
* user_data
)
1438 user_data
->dlg
.dialog_graph
.needs_redraw
= TRUE
;
1439 dialog_graph_draw(user_data
);
1442 /****************************************************************************/
1445 draw_area_destroy_cb(GtkWidget
*widget _U_
, gpointer data
)
1447 user_data_t
*user_data
= (user_data_t
*)data
;
1449 user_data
->dlg
.dialog_graph
.window
= NULL
;
1452 /****************************************************************************/
1453 #if GTK_CHECK_VERSION(3,0,0)
1455 gboolean
draw_area_draw(GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
1457 user_data_t
*user_data
= (user_data_t
*)data
;
1458 GtkAllocation allocation
;
1460 gtk_widget_get_allocation (widget
, &allocation
);
1462 cairo_set_source_surface (cr
, user_data
->dlg
.dialog_graph
.surface
, 0, 0);
1463 cairo_rectangle (cr
, 0, 0, allocation
.width
, allocation
.height
);
1470 draw_area_expose_event(GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
1472 user_data_t
*user_data
= (user_data_t
*)data
;
1473 cairo_t
*cr
= gdk_cairo_create (gtk_widget_get_window(widget
));
1475 #if GTK_CHECK_VERSION(2,22,0)
1476 cairo_set_source_surface (cr
, user_data
->dlg
.dialog_graph
.surface
, 0, 0);
1478 gdk_cairo_set_source_pixmap (cr
, user_data
->dlg
.dialog_graph
.pixmap
, 0, 0);
1480 cairo_rectangle (cr
, event
->area
.x
, event
->area
.y
, event
->area
.width
, event
->area
.height
);
1488 /****************************************************************************/
1490 draw_area_configure_event(GtkWidget
*widget
, GdkEventConfigure
*event _U_
, gpointer data
)
1492 user_data_t
*user_data
= (user_data_t
*)data
;
1493 GtkAllocation widget_alloc
;
1496 #if GTK_CHECK_VERSION(2,22,0)
1497 if (user_data
->dlg
.dialog_graph
.surface
) {
1498 g_object_unref(user_data
->dlg
.dialog_graph
.surface
);
1499 user_data
->dlg
.dialog_graph
.surface
= NULL
;
1501 gtk_widget_get_allocation(widget
, &widget_alloc
);
1502 user_data
->dlg
.dialog_graph
.surface
= gdk_window_create_similar_surface (gtk_widget_get_window(widget
),
1503 CAIRO_CONTENT_COLOR
,
1505 widget_alloc
.height
);
1507 if (user_data
->dlg
.dialog_graph
.pixmap
) {
1508 g_object_unref(user_data
->dlg
.dialog_graph
.pixmap
);
1509 user_data
->dlg
.dialog_graph
.pixmap
= NULL
;
1512 gtk_widget_get_allocation(widget
, &widget_alloc
);
1513 user_data
->dlg
.dialog_graph
.pixmap
= gdk_pixmap_new(gtk_widget_get_window(widget
),
1515 widget_alloc
.height
,
1518 user_data
->dlg
.dialog_graph
.surface_width
= widget_alloc
.width
;
1519 user_data
->dlg
.dialog_graph
.surface_height
= widget_alloc
.height
;
1521 #if GTK_CHECK_VERSION(2,22,0)
1522 cr
= cairo_create (user_data
->dlg
.dialog_graph
.surface
);
1524 cr
= gdk_cairo_create (user_data
->dlg
.dialog_graph
.pixmap
);
1526 cairo_rectangle (cr
, 0, 0, widget_alloc
.width
, widget_alloc
.height
);
1527 cairo_set_source_rgb (cr
, 1, 1, 1);
1531 dialog_graph_redraw(user_data
);
1535 /****************************************************************************/
1537 scrollbar_changed(GtkWidget
*widget _U_
, gpointer data
)
1539 user_data_t
*user_data
= (user_data_t
*)data
;
1542 mi
= (guint32
) (gtk_adjustment_get_value(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
)
1543 + gtk_adjustment_get_page_size(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
));
1544 if (user_data
->dlg
.dialog_graph
.last_interval
== mi
) {
1547 if ( (user_data
->dlg
.dialog_graph
.last_interval
== 0xffffffff)
1548 && (mi
== user_data
->dlg
.dialog_graph
.max_interval
) ) {
1552 user_data
->dlg
.dialog_graph
.last_interval
= (mi
/user_data
->dlg
.dialog_graph
.interval
)*user_data
->dlg
.dialog_graph
.interval
;
1554 dialog_graph_redraw(user_data
);
1558 /****************************************************************************/
1560 create_draw_area(user_data_t
* user_data
, GtkWidget
*box
)
1562 user_data
->dlg
.dialog_graph
.draw_area
= gtk_drawing_area_new();
1563 g_signal_connect(user_data
->dlg
.dialog_graph
.draw_area
, "destroy", G_CALLBACK(draw_area_destroy_cb
), user_data
);
1565 gtk_widget_set_size_request(user_data
->dlg
.dialog_graph
.draw_area
, user_data
->dlg
.dialog_graph
.surface_width
, user_data
->dlg
.dialog_graph
.surface_height
);
1567 /* signals needed to handle backing pixmap */
1568 #if GTK_CHECK_VERSION(3,0,0)
1569 g_signal_connect(user_data
->dlg
.dialog_graph
.draw_area
, "draw", G_CALLBACK(draw_area_draw
), user_data
);
1571 g_signal_connect(user_data
->dlg
.dialog_graph
.draw_area
, "expose_event", G_CALLBACK(draw_area_expose_event
), user_data
);
1573 g_signal_connect(user_data
->dlg
.dialog_graph
.draw_area
, "configure_event", G_CALLBACK(draw_area_configure_event
), user_data
);
1575 gtk_widget_show(user_data
->dlg
.dialog_graph
.draw_area
);
1576 gtk_box_pack_start(GTK_BOX(box
), user_data
->dlg
.dialog_graph
.draw_area
, TRUE
, TRUE
, 0);
1578 /* create the associated scrollbar */
1579 user_data
->dlg
.dialog_graph
.scrollbar_adjustment
= (GtkAdjustment
*)gtk_adjustment_new(0,0,0,0,0,0);
1580 user_data
->dlg
.dialog_graph
.scrollbar
= gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL
,user_data
->dlg
.dialog_graph
.scrollbar_adjustment
);
1581 gtk_widget_show(user_data
->dlg
.dialog_graph
.scrollbar
);
1582 gtk_box_pack_start(GTK_BOX(box
), user_data
->dlg
.dialog_graph
.scrollbar
, FALSE
, FALSE
, 0);
1583 g_signal_connect(user_data
->dlg
.dialog_graph
.scrollbar_adjustment
, "value_changed", G_CALLBACK(scrollbar_changed
), user_data
);
1586 /****************************************************************************/
1588 disable_graph(dialog_graph_graph_t
*dgg
)
1591 dgg
->display
= FALSE
;
1592 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dgg
->display_button
),
1597 /****************************************************************************/
1599 filter_box_display_button_cb(GtkWidget
*widget _U_
, gpointer data
)
1601 dialog_graph_graph_t
*dgg
= (dialog_graph_graph_t
*)data
;
1603 /* this graph is not active, just update display and redraw */
1604 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(dgg
->display_button
))) {
1606 dialog_graph_redraw(dgg
->ud
);
1611 cf_retap_packets(&cfile
);
1612 dialog_graph_redraw(dgg
->ud
);
1617 /****************************************************************************/
1619 create_filter_box(dialog_graph_graph_t
*dgg
, GtkWidget
*box
, int num
)
1625 hbox
= ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 3, FALSE
);
1626 gtk_box_pack_start(GTK_BOX(box
), hbox
, FALSE
, FALSE
, 0);
1628 gtk_widget_show(hbox
);
1630 g_snprintf(str
, sizeof(str
), "Graph %d", num
);
1631 dgg
->display_button
= gtk_toggle_button_new_with_label(str
);
1632 gtk_box_pack_start(GTK_BOX(hbox
), dgg
->display_button
, FALSE
, FALSE
, 0);
1633 gtk_widget_show(dgg
->display_button
);
1634 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dgg
->display_button
), dgg
->display
);
1635 g_signal_connect(dgg
->display_button
, "toggled", G_CALLBACK(filter_box_display_button_cb
), dgg
);
1637 label
= gtk_label_new(dgg
->title
);
1638 gtk_widget_show(label
);
1639 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1640 #if GTK_CHECK_VERSION(3,0,0)
1641 gtk_widget_override_color(label
, (GtkStateFlags
)GTK_STATE_FLAG_NORMAL
, &dgg
->rgba_color
);
1642 /* XXX gtk_widget_override_color() takes flags not state */
1643 gtk_widget_override_color(label
, (GtkStateFlags
)GTK_STATE_ACTIVE
, &dgg
->rgba_color
);
1644 gtk_widget_override_color(label
, (GtkStateFlags
)GTK_STATE_PRELIGHT
, &dgg
->rgba_color
);
1645 gtk_widget_override_color(label
, (GtkStateFlags
)GTK_STATE_SELECTED
, &dgg
->rgba_color
);
1646 gtk_widget_override_color(label
, (GtkStateFlags
)GTK_STATE_INSENSITIVE
, &dgg
->rgba_color
);
1648 gtk_widget_modify_fg(label
, GTK_STATE_NORMAL
, &dgg
->color
);
1649 gtk_widget_modify_fg(label
, GTK_STATE_ACTIVE
, &dgg
->color
);
1650 gtk_widget_modify_fg(label
, GTK_STATE_PRELIGHT
, &dgg
->color
);
1651 gtk_widget_modify_fg(label
, GTK_STATE_SELECTED
, &dgg
->color
);
1652 gtk_widget_modify_fg(label
, GTK_STATE_INSENSITIVE
, &dgg
->color
);
1657 /****************************************************************************/
1659 create_filter_area(user_data_t
* user_data
, GtkWidget
*box
)
1666 frame
= gtk_frame_new("Graphs");
1667 gtk_box_pack_start(GTK_BOX(box
), frame
, TRUE
, TRUE
, 0);
1668 gtk_widget_show(frame
);
1670 vbox
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 1, FALSE
);
1671 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
1672 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 3);
1674 gtk_widget_show(vbox
);
1676 for (i
= 0; i
< MAX_GRAPHS
; i
++) {
1677 create_filter_box(&user_data
->dlg
.dialog_graph
.graph
[i
], vbox
, i
+1);
1680 label
= gtk_label_new("Label: x = Wrong Seq. number m = Mark set");
1681 gtk_widget_show(label
);
1682 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, FALSE
, 0);
1687 /****************************************************************************/
1689 yscale_select(GtkWidget
*item
, gpointer data
)
1692 user_data_t
*user_data
= (user_data_t
*)data
;
1694 i
= gtk_combo_box_get_active (GTK_COMBO_BOX(item
));
1696 user_data
->dlg
.dialog_graph
.max_y_units
= yscale_max
[i
];
1697 dialog_graph_redraw(user_data
);
1700 /****************************************************************************/
1702 pixels_per_tick_select(GtkWidget
*item
, gpointer data
)
1705 user_data_t
*user_data
= (user_data_t
*)data
;
1707 i
= gtk_combo_box_get_active (GTK_COMBO_BOX(item
));
1709 user_data
->dlg
.dialog_graph
.pixels_per_tick
= pixels_per_tick
[i
];
1710 dialog_graph_redraw(user_data
);
1713 /****************************************************************************/
1715 tick_interval_select(GtkWidget
*item
, gpointer data
)
1717 user_data_t
*user_data
= (user_data_t
*)data
;
1720 i
= gtk_combo_box_get_active (GTK_COMBO_BOX(item
));
1722 user_data
->dlg
.dialog_graph
.interval
= tick_interval_values
[i
];
1723 cf_retap_packets(&cfile
);
1724 dialog_graph_redraw(user_data
);
1727 /****************************************************************************/
1729 create_yscale_max_menu_items(user_data_t
* user_data
)
1732 GtkWidget
*combo_box
;
1735 combo_box
= gtk_combo_box_text_new();
1737 for (i
= 0; i
< MAX_YSCALE
; i
++) {
1738 if (yscale_max
[i
] == AUTO_MAX_YSCALE
) {
1739 g_strlcpy(str
,"Auto",sizeof(str
));
1740 } else if (yscale_max
[i
] < 1000000) {
1741 g_snprintf(str
, sizeof(str
), "%u ms", yscale_max
[i
]/1000);
1743 g_snprintf(str
, sizeof(str
), "%u s", yscale_max
[i
]/1000000);
1745 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box
), str
);
1747 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box
), DEFAULT_YSCALE_INDEX
);
1748 g_signal_connect(combo_box
, "changed", G_CALLBACK(yscale_select
), user_data
);
1753 /****************************************************************************/
1755 create_pixels_per_tick_menu_items(user_data_t
*user_data
)
1758 GtkWidget
*combo_box
;
1761 combo_box
= gtk_combo_box_text_new();
1763 for(i
= 0; i
< MAX_PIXELS_PER_TICK
; i
++) {
1764 g_snprintf(str
, sizeof(str
), "%u", pixels_per_tick
[i
]);
1765 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box
), str
);
1767 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box
), DEFAULT_PIXELS_PER_TICK_INDEX
);
1769 g_signal_connect(combo_box
, "changed", G_CALLBACK(pixels_per_tick_select
), user_data
);
1774 /****************************************************************************/
1776 create_tick_interval_menu_items(user_data_t
*user_data
)
1778 GtkWidget
*combo_box
;
1782 combo_box
= gtk_combo_box_text_new();
1784 for(i
= 0; i
< MAX_TICK_VALUES
; i
++) {
1785 if (tick_interval_values
[i
] >= 1000) {
1786 g_snprintf(str
, sizeof(str
), "%u sec", tick_interval_values
[i
]/1000);
1787 } else if (tick_interval_values
[i
] >= 100) {
1788 g_snprintf(str
, sizeof(str
), "0.%1u sec", (tick_interval_values
[i
]/100)%10);
1789 } else if (tick_interval_values
[i
] >= 10) {
1790 g_snprintf(str
, sizeof(str
), "0.%02u sec", (tick_interval_values
[i
]/10)%10);
1792 g_snprintf(str
, sizeof(str
), "0.%03u sec", (tick_interval_values
[i
])%10);
1794 gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (combo_box
), str
);
1796 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box
), DEFAULT_TICK_VALUE_INDEX
);
1797 g_signal_connect(combo_box
, "changed", G_CALLBACK(tick_interval_select
), user_data
);
1802 /****************************************************************************/
1804 create_ctrl_menu(user_data_t
* user_data
, GtkWidget
*box
, const char *name
, GtkWidget
*(*func
)(user_data_t
* user_data
))
1808 GtkWidget
*combo_box
;
1810 hbox
= ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0, FALSE
);
1811 gtk_box_pack_start(GTK_BOX(box
), hbox
, FALSE
, FALSE
, 0);
1812 gtk_widget_show(hbox
);
1814 label
= gtk_label_new(name
);
1815 gtk_widget_show(label
);
1816 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
1818 combo_box
= (*func
)(user_data
);
1819 gtk_box_pack_end(GTK_BOX(hbox
), combo_box
, FALSE
, FALSE
, 0);
1820 gtk_widget_show(combo_box
);
1823 /****************************************************************************/
1825 create_ctrl_area(user_data_t
* user_data
, GtkWidget
*box
)
1827 GtkWidget
*frame_vbox
;
1831 frame_vbox
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0, FALSE
);
1832 gtk_box_pack_start(GTK_BOX(box
), frame_vbox
, TRUE
, TRUE
, 0);
1833 gtk_widget_show(frame_vbox
);
1835 frame
= gtk_frame_new("X Axis");
1836 gtk_container_add(GTK_CONTAINER(frame_vbox
), frame
);
1837 gtk_widget_show(frame
);
1839 vbox
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0, FALSE
);
1840 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
1841 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 3);
1843 gtk_widget_show(vbox
);
1845 create_ctrl_menu(user_data
, vbox
, "Tick interval:", create_tick_interval_menu_items
);
1846 create_ctrl_menu(user_data
, vbox
, "Pixels per tick:", create_pixels_per_tick_menu_items
);
1848 frame
= gtk_frame_new("Y Axis");
1849 gtk_container_add(GTK_CONTAINER(frame_vbox
), frame
);
1850 gtk_widget_show(frame
);
1852 vbox
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0, FALSE
);
1853 gtk_container_add(GTK_CONTAINER(frame
), vbox
);
1854 gtk_container_set_border_width(GTK_CONTAINER(vbox
), 3);
1856 gtk_widget_show(vbox
);
1858 create_ctrl_menu(user_data
, vbox
, "Scale:", create_yscale_max_menu_items
);
1863 /****************************************************************************/
1865 dialog_graph_init_window(user_data_t
* user_data
)
1869 GtkWidget
*bt_close
;
1871 /* create the main window */
1872 user_data
->dlg
.dialog_graph
.window
= dlg_window_new("I/O Graphs"); /* transient_for top_level */
1874 vbox
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0, FALSE
);
1875 gtk_container_add(GTK_CONTAINER(user_data
->dlg
.dialog_graph
.window
), vbox
);
1876 gtk_widget_show(vbox
);
1878 create_draw_area(user_data
, vbox
);
1880 hbox
= ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 3, FALSE
);
1881 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 5);
1882 gtk_container_set_border_width(GTK_CONTAINER(hbox
), 3);
1884 gtk_widget_show(hbox
);
1886 create_filter_area(user_data
, hbox
);
1887 create_ctrl_area(user_data
, hbox
);
1889 dialog_graph_set_title(user_data
);
1891 hbox
= dlg_button_row_new(GTK_STOCK_CLOSE
, NULL
);
1892 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
1893 gtk_widget_show(hbox
);
1895 bt_close
= (GtkWidget
*)g_object_get_data(G_OBJECT(hbox
), GTK_STOCK_CLOSE
);
1896 window_set_cancel_button(user_data
->dlg
.dialog_graph
.window
, bt_close
, window_cancel_button_cb
);
1898 g_signal_connect(user_data
->dlg
.dialog_graph
.window
, "delete_event", G_CALLBACK(window_delete_event_cb
), NULL
);
1900 gtk_widget_show(user_data
->dlg
.dialog_graph
.window
);
1901 window_present(user_data
->dlg
.dialog_graph
.window
);
1906 /****************************************************************************/
1908 on_graph_bt_clicked(GtkWidget
*bt _U_
, gpointer data
)
1910 user_data_t
*user_data
= (user_data_t
*)data
;
1912 if (user_data
->dlg
.dialog_graph
.window
!= NULL
) {
1913 /* There's already a graph window; reactivate it. */
1914 reactivate_window(user_data
->dlg
.dialog_graph
.window
);
1918 dialog_graph_init_window(user_data
);
1922 /****************************************************************************/
1924 on_goto_bt_clicked(GtkWidget
*bt _U_
, gpointer data
)
1926 user_data_t
*user_data
= (user_data_t
*)data
;
1928 GtkTreeModel
*model
;
1929 GtkTreeSelection
*selection
;
1932 selection
= user_data
->dlg
.selected_list_sel
;
1934 if (selection
== NULL
)
1937 if (gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
1938 gtk_tree_model_get (model
, &iter
, PACKET_COLUMN
, &fnumber
, -1);
1939 cf_goto_frame(&cfile
, fnumber
);
1944 static void draw_stat(user_data_t
*user_data
);
1946 /****************************************************************************/
1947 /* re-dissects all packets */
1949 on_refresh_bt_clicked(GtkWidget
*bt _U_
, gpointer data
)
1951 user_data_t
*user_data
= (user_data_t
*)data
;
1952 GString
*error_string
;
1954 /* remove tap listener */
1955 remove_tap_listener(user_data
);
1957 /* register tap listener */
1958 error_string
= register_tap_listener("IAX2", user_data
, NULL
, 0,
1959 iax2_reset
, iax2_packet
, iax2_draw
);
1960 if (error_string
!= NULL
) {
1961 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
, "%s", error_string
->str
);
1962 g_string_free(error_string
, TRUE
);
1966 /* retap all packets */
1967 cf_retap_packets(&cfile
);
1969 /* draw statistics info */
1970 draw_stat(user_data
);
1974 /****************************************************************************/
1976 on_next_bt_clicked(GtkWidget
*bt _U_
, gpointer data
)
1978 user_data_t
*user_data
= (user_data_t
*)data
;
1980 GtkTreeModel
*model
;
1982 GtkTreeSelection
*selection
;
1985 selection
= user_data
->dlg
.selected_list_sel
;
1987 if (selection
== NULL
)
1991 if (gtk_tree_selection_get_selected (selection
, &model
, &iter
)) {
1992 while (gtk_tree_model_iter_next (model
,&iter
)) {
1993 gtk_tree_model_get (model
, &iter
, STATUS_COLUMN
, &text
, -1);
1994 if (strcmp(text
, OK_TEXT
) != 0) {
1995 gtk_tree_selection_select_iter (selection
, &iter
);
1996 path
= gtk_tree_model_get_path(model
, &iter
);
1997 gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW( user_data
->dlg
.selected_list
),
2000 gtk_tree_path_free(path
);
2007 if (user_data
->dlg
.number_of_nok
> 1) {
2008 /* Get the first iter and select it before starting over */
2009 gtk_tree_model_get_iter_first(model
, &iter
);
2010 gtk_tree_selection_select_iter (selection
, &iter
);
2016 /****************************************************************************/
2017 /* when we want to save the information */
2019 save_csv_as_ok_cb(GtkWidget
*w _U_
, gpointer fc
/*user_data_t *user_data*/)
2022 GtkWidget
*rev
, *forw
, *both
;
2023 user_data_t
*user_data
;
2025 GtkListStore
*store
;
2027 GtkTreeModel
*model
;
2028 gboolean more_items
= TRUE
;
2030 /* To Hold data from the list row */
2031 guint packet
; /* Packet */
2032 gfloat delta
; /* Delta(ms) */
2033 gfloat jitter
; /* Jitter(ms) */
2034 gfloat ipbw
; /* IP BW(kbps) */
2035 char *status_str
; /* Status */
2036 char *date_str
; /* Date */
2037 guint length
; /* Length */
2042 g_dest
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc
));
2044 /* Perhaps the user specified a directory instead of a file.
2045 * Check whether they did.
2047 if (test_for_directory(g_dest
) == EISDIR
) {
2048 /* It's a directory - set the file selection box to display it. */
2049 set_last_open_dir(g_dest
);
2051 file_selection_set_current_folder((GtkWidget
*)fc
, get_last_open_dir());
2052 gtk_file_chooser_set_current_name((GtkFileChooser
*)fc
, "");
2053 return FALSE
; /* run the dialog again */
2055 rev
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "reversed_rb");
2056 forw
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "forward_rb");
2057 both
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "both_rb");
2058 user_data
= (user_data_t
*)g_object_get_data(G_OBJECT(fc
), "user_data");
2060 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(forw
))
2061 || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(both
))) {
2062 fp
= ws_fopen(g_dest
, "w");
2064 open_failure_alert_box(g_dest
, errno
, TRUE
);
2066 return TRUE
; /* we're done */
2069 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(both
))) {
2070 fprintf(fp
, "Forward\n");
2072 write_failure_alert_box(g_dest
, errno
);
2075 return TRUE
; /* we're done */
2079 for(j
= 0; j
< NUM_COLS
; j
++) {
2081 fprintf(fp
,"\"%s\"",titles
[j
]);
2083 fprintf(fp
,",\"%s\"",titles
[j
]);
2088 write_failure_alert_box(g_dest
, errno
);
2091 return TRUE
; /* we're done */
2093 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(user_data
->dlg
.list_fwd
));
2094 store
= GTK_LIST_STORE(model
);
2095 if ( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store
), &iter
) ) {
2097 while (more_items
) {
2098 gtk_tree_model_get(GTK_TREE_MODEL(store
), &iter
,
2107 fprintf(fp
, "\"%u\"",packet
);
2108 fprintf(fp
, ",\"%.2f\"", delta
);
2109 fprintf(fp
, ",\"%.2f\"", jitter
);
2110 fprintf(fp
, ",\"%.2f\"", ipbw
);
2111 fprintf(fp
, ",\"%s\"", status_str
);
2112 fprintf(fp
, ",\"%s\"", date_str
);
2113 fprintf(fp
, ",\"%u\"", length
);
2118 write_failure_alert_box(g_dest
, errno
);
2121 return TRUE
; /* we're done */
2124 more_items
= gtk_tree_model_iter_next (model
,&iter
);
2128 if (fclose(fp
) == EOF
) {
2129 write_failure_alert_box(g_dest
, errno
);
2131 return TRUE
; /* we're done */
2135 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rev
)) || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(both
))) {
2137 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(both
))) {
2138 fp
= ws_fopen(g_dest
, "a");
2140 open_failure_alert_box(g_dest
, errno
, TRUE
);
2142 return TRUE
; /* we're done */
2144 fprintf(fp
, "\nReverse\n");
2146 write_failure_alert_box(g_dest
, errno
);
2149 return TRUE
; /* we're done */
2152 fp
= ws_fopen(g_dest
, "w");
2154 open_failure_alert_box(g_dest
, errno
, TRUE
);
2156 return TRUE
; /* we're done */
2159 for(j
= 0; j
< NUM_COLS
; j
++) {
2161 fprintf(fp
,"\"%s\"",titles
[j
]);
2163 fprintf(fp
,",\"%s\"",titles
[j
]);
2168 write_failure_alert_box(g_dest
, errno
);
2171 return TRUE
; /* we're done */
2173 model
= gtk_tree_view_get_model(GTK_TREE_VIEW(user_data
->dlg
.list_rev
));
2174 store
= GTK_LIST_STORE(model
);
2175 if ( gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store
), &iter
) ) {
2179 while (more_items
) {
2180 gtk_tree_model_get(GTK_TREE_MODEL(store
), &iter
,
2189 fprintf(fp
, "\"%u\"",packet
);
2190 fprintf(fp
, ",\"%.2f\"", delta
);
2191 fprintf(fp
, ",\"%.2f\"", jitter
);
2192 fprintf(fp
, ",\"%.2f\"", ipbw
);
2193 fprintf(fp
, ",\"%s\"", status_str
);
2194 fprintf(fp
, ",\"%s\"", date_str
);
2195 fprintf(fp
, ",\"%u\"", length
);
2200 write_failure_alert_box(g_dest
, errno
);
2203 return TRUE
; /* we're done */
2206 more_items
= gtk_tree_model_iter_next (model
,&iter
);
2209 if (fclose(fp
) == EOF
) {
2210 write_failure_alert_box(g_dest
, errno
);
2212 return TRUE
; /* we're done */
2216 return TRUE
; /* we're done */
2219 static void save_csv_as_destroy_cb(GtkWidget
*win _U_
, gpointer data
)
2221 user_data_t
*user_data
= (user_data_t
*)data
;
2223 user_data
->dlg
.save_csv_as_w
= NULL
;
2226 /* when the user wants to save the csv information in a file */
2228 save_csv_as_cb(GtkWidget
*bt _U_
, gpointer data
)
2230 user_data_t
*user_data
= (user_data_t
*)data
;
2233 GtkWidget
*label_format
;
2234 GtkWidget
*channels_label
;
2235 GtkWidget
*forward_rb
;
2236 GtkWidget
*reversed_rb
;
2239 #if 0 /* XXX: GtkFileChooserDialog/gtk_dialog_run currently being used is effectively modal so this is not req'd */
2240 if (user_data
->dlg
.save_csv_as_w
!= NULL
) {
2241 /* There's already a Save CSV info dialog box; reactivate it. */
2242 reactivate_window(user_data
->dlg
.save_csv_as_w
);
2246 user_data
->dlg
.save_csv_as_w
=
2247 gtk_file_chooser_dialog_new("Wireshark: Save Data As CSV",
2248 GTK_WINDOW(user_data
->dlg
.notebook
),
2249 GTK_FILE_CHOOSER_ACTION_SAVE
,
2250 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
,
2251 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
2253 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(user_data
->dlg
.save_csv_as_w
), TRUE
);
2255 /* Build our "extra widget" to be added to the file chooser widget */
2256 /* Container for each row of widgets */
2257 vertb
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0, FALSE
);
2258 gtk_container_set_border_width(GTK_CONTAINER(vertb
), 5);
2259 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(user_data
->dlg
.save_csv_as_w
), vertb
);
2260 gtk_widget_show (vertb
);
2262 grid1
= ws_gtk_grid_new ();
2263 gtk_widget_show (grid1
);
2264 gtk_box_pack_start (GTK_BOX (vertb
), grid1
, FALSE
, FALSE
, 0);
2265 gtk_container_set_border_width (GTK_CONTAINER (grid1
), 10);
2266 ws_gtk_grid_set_row_spacing (GTK_GRID (grid1
), 20);
2268 label_format
= gtk_label_new ("Format: Comma Separated Values");
2269 gtk_widget_show (label_format
);
2270 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), label_format
, 0, 0, 3, 1,
2271 (GtkAttachOptions
) (GTK_FILL
),
2272 (GtkAttachOptions
) (0), 0, 0);
2273 gtk_misc_set_alignment (GTK_MISC (label_format
), 0, 0.5f
);
2275 channels_label
= gtk_label_new ("Channels: ");
2276 gtk_widget_show (channels_label
);
2277 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), channels_label
, 0, 1, 1, 1,
2278 (GtkAttachOptions
) (GTK_FILL
),
2279 (GtkAttachOptions
) (0), 0, 0);
2280 gtk_misc_set_alignment (GTK_MISC (channels_label
), 0, 0.5f
);
2282 forward_rb
= gtk_radio_button_new_with_label (NULL
, "forward ");
2283 gtk_widget_show (forward_rb
);
2284 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), forward_rb
, 1, 1, 1, 1,
2285 (GtkAttachOptions
) (GTK_FILL
),
2286 (GtkAttachOptions
) (0), 0, 0);
2288 reversed_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(forward_rb
), "reversed ");
2289 gtk_widget_show (reversed_rb
);
2290 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), reversed_rb
, 2, 1, 1, 1,
2291 (GtkAttachOptions
) (GTK_FILL
),
2292 (GtkAttachOptions
) (0), 0, 0);
2294 both_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(forward_rb
), "both");
2295 gtk_widget_show (both_rb
);
2296 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), both_rb
, 3, 1, 1, 1,
2297 (GtkAttachOptions
) (GTK_FILL
),
2298 (GtkAttachOptions
) (0), 0, 0);
2300 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb
), TRUE
);
2302 g_object_set_data(G_OBJECT(user_data
->dlg
.save_csv_as_w
), "forward_rb", forward_rb
);
2303 g_object_set_data(G_OBJECT(user_data
->dlg
.save_csv_as_w
), "reversed_rb", reversed_rb
);
2304 g_object_set_data(G_OBJECT(user_data
->dlg
.save_csv_as_w
), "both_rb", both_rb
);
2305 g_object_set_data(G_OBJECT(user_data
->dlg
.save_csv_as_w
), "user_data", user_data
);
2307 g_signal_connect(user_data
->dlg
.save_csv_as_w
, "delete_event",
2308 G_CALLBACK(window_delete_event_cb
), NULL
);
2309 g_signal_connect(user_data
->dlg
.save_csv_as_w
, "destroy",
2310 G_CALLBACK(save_csv_as_destroy_cb
), user_data
);
2312 gtk_widget_show(user_data
->dlg
.save_csv_as_w
);
2313 window_present(user_data
->dlg
.save_csv_as_w
);
2315 /* "Run" the GtkFileChooserDialog. */
2316 /* Upon exit: If "Accept" run the OK callback. */
2317 /* If the OK callback returns with a FALSE status, re-run the dialog.*/
2318 /* Destroy the window. */
2319 /* XXX: If the OK callback pops up an alert box (eg: for an error) it *must* */
2320 /* return with a TRUE status so that the dialog window will be destroyed. */
2321 /* Trying to re-run the dialog after popping up an alert box will not work */
2322 /* since the user will not be able to dismiss the alert box. */
2323 /* The (somewhat unfriendly) effect: the user must re-invoke the */
2324 /* GtkFileChooserDialog whenever the OK callback pops up an alert box. */
2326 /* ToDo: use GtkFileChooserWidget in a dialog window instead of */
2327 /* GtkFileChooserDialog. */
2328 while (gtk_dialog_run(GTK_DIALOG(user_data
->dlg
.save_csv_as_w
)) == GTK_RESPONSE_ACCEPT
) {
2329 if (save_csv_as_ok_cb(NULL
, user_data
->dlg
.save_csv_as_w
)) {
2330 break; /* we're done */
2333 window_destroy(user_data
->dlg
.save_csv_as_w
);
2336 /****************************************************************************/
2337 static void save_voice_as_destroy_cb(GtkWidget
*win _U_
, gpointer data
)
2339 user_data_t
*user_data
= (user_data_t
*)data
;
2341 /* Note that we no longer have a Save voice info dialog box. */
2342 user_data
->dlg
.save_voice_as_w
= NULL
;
2345 /****************************************************************************/
2346 /* here we save it into a file that user specified */
2347 /* XXX what about endians here? could go something wrong? */
2348 static gboolean
copy_file(gchar
*dest
, gint channels
, gint format
, user_data_t
*user_data
)
2350 int to_fd
, forw_fd
, rev_fd
;
2351 size_t fread_cnt
= 0, rread
= 0, fwritten
, rwritten
;
2352 gchar f_pd
[1] = {0};
2353 gchar r_pd
[1] = {0};
2356 guint32 f_write_silence
= 0;
2357 guint32 r_write_silence
= 0;
2359 guint32 progbar_count
, progbar_quantum
, progbar_nextstep
= 0, count
= 0;
2360 gboolean stop_flag
= FALSE
;
2363 forw_fd
= ws_open(user_data
->f_tempname
, O_RDONLY
| O_BINARY
, 0000 /* no creation so don't matter */);
2366 rev_fd
= ws_open(user_data
->r_tempname
, O_RDONLY
| O_BINARY
, 0000 /* no creation so don't matter */);
2372 /* open file for saving */
2373 to_fd
= ws_open(dest
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, 0644);
2380 progbar
= create_progress_dlg(top_level
, "Saving voice in a file", dest
, TRUE
, &stop_flag
);
2382 if (format
== SAVE_AU_FORMAT
) /* au format */
2384 /* First we write the .au header. XXX Hope this is endian independent */
2385 /* the magic word 0x2e736e64 == .snd */
2386 /* XXX: Should we be checking for write errors below ? */
2387 phtonl(pd
, 0x2e736e64);
2388 fwritten
= ws_write(to_fd
, pd
, 4);
2389 if ((fwritten
< 4) || (fread_cnt
== (size_t)-1)) {
2393 destroy_progress_dlg(progbar
);
2396 /* header offset == 24 bytes */
2398 fwritten
= ws_write(to_fd
, pd
, 4);
2399 if ((fwritten
< 4) || (fread_cnt
== (size_t)-1)) {
2403 destroy_progress_dlg(progbar
);
2406 /* total length, it is permited to set this to 0xffffffff */
2408 fwritten
= ws_write(to_fd
, pd
, 4);
2409 if ((fwritten
< 4) || (fread_cnt
== (size_t)-1)) {
2413 destroy_progress_dlg(progbar
);
2416 /* encoding format == 16-bit linear PCM */
2418 fwritten
= ws_write(to_fd
, pd
, 4);
2419 if ((fwritten
< 4) || (fread_cnt
== (size_t)-1)) {
2423 destroy_progress_dlg(progbar
);
2426 /* sample rate == 8000 Hz */
2428 fwritten
= ws_write(to_fd
, pd
, 4);
2429 if ((fwritten
< 4) || (fread_cnt
== (size_t)-1)) {
2433 destroy_progress_dlg(progbar
);
2438 fwritten
= ws_write(to_fd
, pd
, 4);
2439 if ((fwritten
< 4) || (fread_cnt
== (size_t)-1)) {
2443 destroy_progress_dlg(progbar
);
2448 /* only forward direction */
2449 case SAVE_FORWARD_DIRECTION_MASK
: {
2450 progbar_count
= user_data
->forward
.saveinfo
.count
;
2451 progbar_quantum
= user_data
->forward
.saveinfo
.count
/100;
2452 while ((fread_cnt
= read(forw_fd
, f_pd
, 1)) > 0) {
2455 if ((count
> progbar_nextstep
) && (count
<= progbar_count
)) {
2456 update_progress_dlg(progbar
,
2457 (gfloat
) count
/progbar_count
, "Saving");
2458 progbar_nextstep
= progbar_nextstep
+ progbar_quantum
;
2462 if (user_data
->forward
.statinfo
.pt
== AST_FORMAT_ULAW
) {
2463 sample
= ulaw2linear(*f_pd
);
2466 else if (user_data
->forward
.statinfo
.pt
== AST_FORMAT_ALAW
) {
2467 sample
= alaw2linear(*f_pd
);
2474 destroy_progress_dlg(progbar
);
2478 fwritten
= ws_write(to_fd
, pd
, 2);
2479 if ((fwritten
< 2) || (fread_cnt
== (size_t)-1)) {
2483 destroy_progress_dlg(progbar
);
2489 /* only reversed direction */
2490 case SAVE_REVERSE_DIRECTION_MASK
: {
2491 progbar_count
= user_data
->reversed
.saveinfo
.count
;
2492 progbar_quantum
= user_data
->reversed
.saveinfo
.count
/100;
2493 while ((rread
= read(rev_fd
, r_pd
, 1)) > 0) {
2496 if ((count
> progbar_nextstep
) && (count
<= progbar_count
)) {
2497 update_progress_dlg(progbar
,
2498 (gfloat
) count
/progbar_count
, "Saving");
2499 progbar_nextstep
= progbar_nextstep
+ progbar_quantum
;
2503 if (user_data
->reversed
.statinfo
.pt
== AST_FORMAT_ULAW
) {
2504 sample
= ulaw2linear(*r_pd
);
2507 else if (user_data
->reversed
.statinfo
.pt
== AST_FORMAT_ALAW
) {
2508 sample
= alaw2linear(*r_pd
);
2515 destroy_progress_dlg(progbar
);
2519 rwritten
= ws_write(to_fd
, pd
, 2);
2520 if ((rwritten
< 2) || (rread
== (size_t)-1)) {
2524 destroy_progress_dlg(progbar
);
2530 /* both directions */
2531 case SAVE_BOTH_DIRECTION_MASK
: {
2532 (user_data
->forward
.saveinfo
.count
> user_data
->reversed
.saveinfo
.count
) ?
2533 (progbar_count
= user_data
->forward
.saveinfo
.count
) :
2534 (progbar_count
= user_data
->reversed
.saveinfo
.count
);
2535 progbar_quantum
= progbar_count
/100;
2536 /* since conversation in one way can start later than in the other one,
2537 * we have to write some silence information for one channel */
2538 if (user_data
->forward
.statinfo
.start_time
> user_data
->reversed
.statinfo
.start_time
) {
2539 f_write_silence
= (guint32
)
2540 ((user_data
->forward
.statinfo
.start_time
- user_data
->reversed
.statinfo
.start_time
)*8000);
2542 else if (user_data
->forward
.statinfo
.start_time
< user_data
->reversed
.statinfo
.start_time
) {
2543 r_write_silence
= (guint32
)
2544 ((user_data
->reversed
.statinfo
.start_time
- user_data
->forward
.statinfo
.start_time
)*8000);
2549 if ((count
> progbar_nextstep
) && (count
<= progbar_count
)) {
2550 update_progress_dlg(progbar
,
2551 (gfloat
) count
/progbar_count
, "Saving");
2552 progbar_nextstep
= progbar_nextstep
+ progbar_quantum
;
2555 if (f_write_silence
> 0) {
2556 rread
= read(rev_fd
, r_pd
, 1);
2557 switch (user_data
->forward
.statinfo
.reg_pt
) {
2558 case AST_FORMAT_ULAW
:
2559 *f_pd
= SILENCE_PCMU
;
2561 case AST_FORMAT_ALAW
:
2562 *f_pd
= SILENCE_PCMA
;
2568 else if (r_write_silence
> 0) {
2569 fread_cnt
= read(forw_fd
, f_pd
, 1);
2570 switch (user_data
->reversed
.statinfo
.reg_pt
) {
2571 case AST_FORMAT_ULAW
:
2572 *r_pd
= SILENCE_PCMU
;
2574 case AST_FORMAT_ALAW
:
2575 *r_pd
= SILENCE_PCMA
;
2582 fread_cnt
= read(forw_fd
, f_pd
, 1);
2583 rread
= read(rev_fd
, r_pd
, 1);
2585 if ((rread
== 0) && (fread_cnt
== 0))
2587 if ((user_data
->forward
.statinfo
.pt
== AST_FORMAT_ULAW
)
2588 && (user_data
->reversed
.statinfo
.pt
== AST_FORMAT_ULAW
)) {
2589 sample
= (ulaw2linear(*r_pd
) + ulaw2linear(*f_pd
)) / 2;
2592 else if ((user_data
->forward
.statinfo
.pt
== AST_FORMAT_ALAW
)
2593 && (user_data
->reversed
.statinfo
.pt
== AST_FORMAT_ALAW
)) {
2594 sample
= (alaw2linear(*r_pd
) + alaw2linear(*f_pd
)) / 2;
2602 destroy_progress_dlg(progbar
);
2607 rwritten
= ws_write(to_fd
, pd
, 2);
2608 if ((rwritten
< 2) || (rread
== (size_t)-1) || (fread_cnt
== (size_t)-1)) {
2612 destroy_progress_dlg(progbar
);
2619 else if (format
== SAVE_RAW_FORMAT
) /* raw format */
2623 /* only forward direction */
2624 case SAVE_FORWARD_DIRECTION_MASK
: {
2625 progbar_count
= user_data
->forward
.saveinfo
.count
;
2626 progbar_quantum
= user_data
->forward
.saveinfo
.count
/100;
2630 /* only reversed direction */
2631 case SAVE_REVERSE_DIRECTION_MASK
: {
2632 progbar_count
= user_data
->reversed
.saveinfo
.count
;
2633 progbar_quantum
= user_data
->reversed
.saveinfo
.count
/100;
2641 destroy_progress_dlg(progbar
);
2648 /* XXX how do you just copy the file? */
2649 while ((rread
= read(fd
, pd
, 1)) > 0) {
2652 if ((count
> progbar_nextstep
) && (count
<= progbar_count
)) {
2653 update_progress_dlg(progbar
,
2654 (gfloat
) count
/progbar_count
, "Saving");
2655 progbar_nextstep
= progbar_nextstep
+ progbar_quantum
;
2659 rwritten
= ws_write(to_fd
, pd
, 1);
2661 if ((rwritten
< rread
) || (rwritten
== (size_t)-1) || (rread
== (size_t)-1)) {
2665 destroy_progress_dlg(progbar
);
2671 destroy_progress_dlg(progbar
);
2679 /****************************************************************************/
2680 /* the user wants to save in a file */
2681 /* XXX support for different formats is currently commented out */
2682 static gboolean
save_voice_as_ok_cb(GtkWidget
*w _U_
, gpointer fc
)
2685 /*GtkWidget *wav, *sw;*/
2686 GtkWidget
*au
, *raw
;
2687 GtkWidget
*rev
, *forw
, *both
;
2688 user_data_t
*user_data
;
2689 gint channels
, format
;
2691 g_dest
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fc
));
2693 /* Perhaps the user specified a directory instead of a file.
2694 Check whether they did. */
2695 if (test_for_directory(g_dest
) == EISDIR
) {
2696 /* It's a directory - set the file selection box to display it. */
2697 set_last_open_dir(g_dest
);
2698 file_selection_set_current_folder((GtkWidget
*)fc
, get_last_open_dir());
2699 gtk_file_chooser_set_current_name((GtkFileChooser
*)fc
, "");
2701 return FALSE
; /* run the dialog again */
2705 wav
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "wav_rb");
2706 sw
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "sw_rb");
2708 au
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "au_rb");
2709 raw
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "raw_rb");
2710 rev
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "reversed_rb");
2711 forw
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "forward_rb");
2712 both
= (GtkWidget
*)g_object_get_data(G_OBJECT(fc
), "both_rb");
2713 user_data
= (user_data_t
*)g_object_get_data(G_OBJECT(fc
), "user_data");
2715 /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.
2716 * we don't support that codec. So we pop up a warning. Maybe it would be better to
2717 * disable the ok button or disable the buttons for direction if only one is not ok. The
2718 * problem is if we open the save voice dialog and then click the refresh button and maybe
2719 * the state changes, so we can't save anymore. In this case we should be able to update
2720 * the buttons. For now it is easier if we put the warning when the ok button is pressed.
2723 /* we can not save in both directions */
2724 if ((user_data
->forward
.saveinfo
.saved
== FALSE
)
2725 && (user_data
->reversed
.saveinfo
.saved
== FALSE
)
2726 && (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (both
)))) {
2727 /* there are many combinations here, we just exit when first matches */
2728 if ((user_data
->forward
.saveinfo
.error_type
== TAP_RTP_WRONG_CODEC
) ||
2729 (user_data
->reversed
.saveinfo
.error_type
== TAP_RTP_WRONG_CODEC
))
2730 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2731 "Can't save in a file: Unsupported codec.");
2732 else if ((user_data
->forward
.saveinfo
.error_type
== TAP_RTP_WRONG_LENGTH
) ||
2733 (user_data
->reversed
.saveinfo
.error_type
== TAP_RTP_WRONG_LENGTH
))
2734 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2735 "Can't save in a file: Wrong length of captured packets.");
2736 else if ((user_data
->forward
.saveinfo
.error_type
== TAP_RTP_SHORT_FRAME
) ||
2737 (user_data
->reversed
.saveinfo
.error_type
== TAP_RTP_SHORT_FRAME
))
2738 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2739 "Can't save in a file: Not all data in all packets was captured.");
2741 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2742 "Can't save in a file: File I/O problem.");
2744 return TRUE
; /* we're done */
2746 /* we can not save forward direction */
2747 else if ((user_data
->forward
.saveinfo
.saved
== FALSE
) && ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (forw
))) ||
2748 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (both
))))) {
2749 if (user_data
->forward
.saveinfo
.error_type
== TAP_RTP_WRONG_CODEC
)
2750 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2751 "Can't save forward direction in a file: Unsupported codec.");
2752 else if (user_data
->forward
.saveinfo
.error_type
== TAP_RTP_WRONG_LENGTH
)
2753 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2754 "Can't save forward direction in a file: Wrong length of captured packets.");
2755 else if (user_data
->forward
.saveinfo
.error_type
== TAP_RTP_SHORT_FRAME
)
2756 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2757 "Can't save forward direction in a file: Not all data in all packets was captured.");
2759 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2760 "Can't save forward direction in a file: File I/O problem.");
2762 return TRUE
; /* we're done */
2764 /* we can not save reversed direction */
2765 else if ((user_data
->reversed
.saveinfo
.saved
== FALSE
) && ((gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rev
))) ||
2766 (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (both
))))) {
2767 if (user_data
->reversed
.saveinfo
.error_type
== TAP_RTP_WRONG_CODEC
)
2768 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2769 "Can't save reversed direction in a file: Unsupported codec.");
2770 else if (user_data
->reversed
.saveinfo
.error_type
== TAP_RTP_WRONG_LENGTH
)
2771 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2772 "Can't save reversed direction in a file: Wrong length of captured packets.");
2773 else if (user_data
->reversed
.saveinfo
.error_type
== TAP_RTP_SHORT_FRAME
)
2774 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2775 "Can't save reversed direction in a file: Not all data in all packets was captured.");
2776 else if (user_data
->reversed
.saveinfo
.error_type
== TAP_RTP_NO_DATA
)
2777 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2778 "Can't save reversed direction in a file: No IAX2 data.");
2780 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2781 "Can't save reversed direction in a file: File I/O problem.");
2783 return TRUE
; /* we're done */
2787 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (wav
)))
2788 format
= SAVE_WAV_FORMAT
;
2791 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (au
)))
2792 format
= SAVE_AU_FORMAT
;
2794 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (sw
)))
2795 format
= SAVE_SW_FORMAT
;
2797 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (raw
)))
2798 format
= SAVE_RAW_FORMAT
;
2800 format
= SAVE_NONE_FORMAT
;
2802 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (rev
)))
2803 channels
= SAVE_REVERSE_DIRECTION_MASK
;
2804 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON (both
)))
2805 channels
= SAVE_BOTH_DIRECTION_MASK
;
2807 channels
= SAVE_FORWARD_DIRECTION_MASK
;
2809 /* direction/format validity*/
2810 if (format
== SAVE_AU_FORMAT
)
2812 /* make sure streams are alaw/ulaw */
2813 if ((channels
& SAVE_FORWARD_DIRECTION_MASK
)
2814 && (user_data
->forward
.statinfo
.pt
!= AST_FORMAT_ALAW
)
2815 && (user_data
->forward
.statinfo
.pt
!= AST_FORMAT_ULAW
)) {
2816 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2817 "Can't save in a file: saving in au format supported only for alaw/ulaw streams");
2819 return TRUE
; /* we're done */
2821 if ((channels
& SAVE_REVERSE_DIRECTION_MASK
)
2822 && (user_data
->reversed
.statinfo
.pt
!= AST_FORMAT_ALAW
)
2823 && (user_data
->reversed
.statinfo
.pt
!= AST_FORMAT_ULAW
)) {
2824 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2825 "Can't save in a file: saving in au format supported only for alaw/ulaw streams");
2827 return TRUE
; /* we're done */
2829 /* make sure pt's don't differ */
2830 if ((channels
== SAVE_BOTH_DIRECTION_MASK
) && (user_data
->forward
.statinfo
.pt
!= user_data
->reversed
.statinfo
.pt
)) {
2831 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2832 "Can't save in a file: Forward and reverse direction differ in type");
2834 return TRUE
; /* we're done */
2837 else if (format
== SAVE_RAW_FORMAT
)
2839 /* can't save raw in both directions */
2840 if (channels
== SAVE_BOTH_DIRECTION_MASK
) {
2841 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2842 "Can't save in a file: Unable to save raw data in both directions");
2844 return TRUE
; /* we're done */
2849 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2850 "Can't save in a file: Invalid save format");
2852 return TRUE
; /* we're done */
2855 if (!copy_file(g_dest
, channels
, format
, user_data
)) {
2856 /* XXX - report the error type! */
2857 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
2858 "An error occurred while saving voice in a file.");
2860 return TRUE
; /* we're done */
2863 return TRUE
; /* we're done */
2866 /****************************************************************************/
2867 /* when the user wants to save the voice information in a file */
2868 /* XXX support for different formats is currently commented out */
2869 static void save_voice_as_cb(GtkWidget
*bt _U_
, gpointer data
)
2871 user_data_t
*user_data
= (user_data_t
*)data
;
2874 GtkWidget
*label_format
;
2875 GtkWidget
*channels_label
;
2876 GtkWidget
*forward_rb
;
2877 GtkWidget
*reversed_rb
;
2879 /*GtkWidget *wav_rb; GtkWidget *sw_rb;*/
2883 /* if we can't save in a file: wrong codec, cut packets or other errors */
2884 /* should the error arise here or later when you click ok button ?
2885 * if we do it here, then we must disable the refresh button, so we don't do it here */
2887 #if 0 /* XXX: GtkFileChooserDialog/gtk_dialog_run currently being used is effectively modal so this is not req'd */
2888 if (user_data
->dlg
.save_voice_as_w
!= NULL
) {
2889 /* There's already a Save voice info dialog box; reactivate it. */
2890 reactivate_window(user_data
->dlg
.save_voice_as_w
);
2894 /* XXX - use file_selection from dlg_utils instead! */
2895 user_data
->dlg
.save_voice_as_w
=
2896 gtk_file_chooser_dialog_new("Wireshark: Save Payload As ...",
2897 GTK_WINDOW(user_data
->dlg
.notebook
),
2898 GTK_FILE_CHOOSER_ACTION_SAVE
,
2899 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
,
2900 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
2902 gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(user_data
->dlg
.save_voice_as_w
), TRUE
);
2904 /* Container for each row of widgets */
2905 vertb
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0, FALSE
);
2906 gtk_container_set_border_width(GTK_CONTAINER(vertb
), 5);
2907 gtk_file_chooser_set_extra_widget(GTK_FILE_CHOOSER(user_data
->dlg
.save_voice_as_w
), vertb
);
2908 gtk_widget_show (vertb
);
2910 grid1
= ws_gtk_grid_new ();
2911 gtk_widget_show (grid1
);
2912 gtk_box_pack_start (GTK_BOX (vertb
), grid1
, FALSE
, FALSE
, 0);
2913 gtk_container_set_border_width (GTK_CONTAINER (grid1
), 10);
2914 ws_gtk_grid_set_row_spacing (GTK_GRID (grid1
), 20);
2917 label_format
= gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");
2918 gtk_widget_show (label_format
);
2919 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), label_format
, 0, 0, 3, 1,
2920 (GtkAttachOptions
) (GTK_FILL
),
2921 (GtkAttachOptions
) (0), 0, 0);
2924 label_format
= gtk_label_new ("Format: ");
2925 gtk_widget_show (label_format
);
2926 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), label_format
, 0, 0, 1, 1,
2927 (GtkAttachOptions
) (GTK_FILL
),
2928 (GtkAttachOptions
) (0), 0, 0);
2930 gtk_misc_set_alignment (GTK_MISC (label_format
), 0, 0.5f
);
2932 raw_rb
= gtk_radio_button_new_with_label (NULL
, ".raw");
2933 gtk_widget_show (raw_rb
);
2934 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), raw_rb
, 1, 0, 1, 1,
2935 (GtkAttachOptions
) (GTK_FILL
),
2936 (GtkAttachOptions
) (0), 0, 0);
2939 au_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(raw_rb
), ".au");
2940 gtk_widget_show (au_rb
);
2941 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), au_rb
, 3, 0, 1, 1,
2942 (GtkAttachOptions
) (GTK_FILL
),
2943 (GtkAttachOptions
) (0), 0, 0);
2946 /* we support .au - ulaw*/
2947 wav_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(raw_rb
), ".wav");
2948 gtk_widget_show (wav_rb
);
2949 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), wav_rb
, 1, 0, 1, 1,
2950 (GtkAttachOptions
) (GTK_FILL
),
2951 (GtkAttachOptions
) (0), 0, 0);
2953 sw_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(raw_rb
), "8 kHz, 16 bit ");
2954 gtk_widget_show (sw_rb
);
2955 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), sw_rb
, 2, 0, 1, 1,
2956 (GtkAttachOptions
) (GTK_FILL
),
2957 (GtkAttachOptions
) (0), 0, 0);
2958 au_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(raw_rb
), ".au");
2959 gtk_widget_show (au_rb
);
2960 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), au_rb
, 3, 0, 1, 1,
2961 (GtkAttachOptions
) (GTK_FILL
),
2962 (GtkAttachOptions
) (0), 0, 0);
2965 channels_label
= gtk_label_new ("Channels: ");
2966 gtk_widget_show (channels_label
);
2967 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), channels_label
, 0, 1, 1, 1,
2968 (GtkAttachOptions
) (GTK_FILL
),
2969 (GtkAttachOptions
) (0), 0, 0);
2970 gtk_misc_set_alignment (GTK_MISC (channels_label
), 0, 0.5f
);
2972 forward_rb
= gtk_radio_button_new_with_label (NULL
, "forward ");
2973 gtk_widget_show (forward_rb
);
2974 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), forward_rb
, 1, 1, 1, 1,
2975 (GtkAttachOptions
) (GTK_FILL
),
2976 (GtkAttachOptions
) (0), 0, 0);
2978 reversed_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(forward_rb
), "reversed ");
2979 gtk_widget_show (reversed_rb
);
2980 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), reversed_rb
, 2, 1, 1, 1,
2981 (GtkAttachOptions
) (GTK_FILL
),
2982 (GtkAttachOptions
) (0), 0, 0);
2984 both_rb
= gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON(forward_rb
), "both");
2985 gtk_widget_show (both_rb
);
2986 ws_gtk_grid_attach_extended (GTK_GRID (grid1
), both_rb
, 3, 1, 1, 1,
2987 (GtkAttachOptions
) (GTK_FILL
),
2988 (GtkAttachOptions
) (0), 0, 0);
2990 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(forward_rb
), TRUE
);
2993 /* if one direction is nok we don't allow saving
2994 XXX this is not ok since the user can click the refresh button and cause changes
2995 but we can not update this window. So we move all the decision on the time the ok
2996 button is clicked */
2997 if (user_data
->forward
.saved
== FALSE
) {
2998 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb
), TRUE
);
2999 gtk_widget_set_sensitive(forward_rb
, FALSE
);
3000 gtk_widget_set_sensitive(both_rb
, FALSE
);
3002 else if (user_data
->reversed
.saved
== FALSE
) {
3003 gtk_widget_set_sensitive(reversed_rb
, FALSE
);
3004 gtk_widget_set_sensitive(both_rb
, FALSE
);
3008 /*g_object_set_data(G_OBJECT(user_data->dlg.save_voice_as_w), "wav_rb", wav_rb);*/
3009 g_object_set_data(G_OBJECT(user_data
->dlg
.save_voice_as_w
), "au_rb", au_rb
);
3010 /*g_object_set_data(G_OBJECT(user_data->dlg.save_voice_as_w), "sw_rb", sw_rb);*/
3011 g_object_set_data(G_OBJECT(user_data
->dlg
.save_voice_as_w
), "raw_rb", raw_rb
);
3012 g_object_set_data(G_OBJECT(user_data
->dlg
.save_voice_as_w
), "forward_rb", forward_rb
);
3013 g_object_set_data(G_OBJECT(user_data
->dlg
.save_voice_as_w
), "reversed_rb", reversed_rb
);
3014 g_object_set_data(G_OBJECT(user_data
->dlg
.save_voice_as_w
), "both_rb", both_rb
);
3015 g_object_set_data(G_OBJECT(user_data
->dlg
.save_voice_as_w
), "user_data", user_data
);
3017 g_signal_connect(user_data
->dlg
.save_voice_as_w
, "delete_event",
3018 G_CALLBACK(window_delete_event_cb
), NULL
);
3019 g_signal_connect(user_data
->dlg
.save_voice_as_w
, "destroy",
3020 G_CALLBACK(save_voice_as_destroy_cb
), user_data
);
3022 gtk_widget_show(user_data
->dlg
.save_voice_as_w
);
3023 window_present(user_data
->dlg
.save_voice_as_w
);
3025 /* "Run" the GtkFileChooserDialog. */
3026 /* Upon exit: If "Accept" run the OK callback. */
3027 /* If the OK callback returns with a FALSE status, re-run the dialog.*/
3028 /* Destroy the window. */
3029 /* XXX: If the OK callback pops up an alert box (eg: for an error) it *must* */
3030 /* return with a TRUE status so that the dialog window will be destroyed. */
3031 /* Trying to re-run the dialog after popping up an alert box will not work */
3032 /* since the user will not be able to dismiss the alert box. */
3033 /* The (somewhat unfriendly) effect: the user must re-invoke the */
3034 /* GtkFileChooserDialog whenever the OK callback pops up an alert box. */
3036 /* ToDo: use GtkFileChooserWidget in a dialog window instead of */
3037 /* GtkFileChooserDialog. */
3038 while (gtk_dialog_run(GTK_DIALOG(user_data
->dlg
.save_voice_as_w
)) == GTK_RESPONSE_ACCEPT
) {
3039 if (save_voice_as_ok_cb(NULL
, user_data
->dlg
.save_voice_as_w
)) {
3040 break; /* we're done */
3043 window_destroy(user_data
->dlg
.save_voice_as_w
);
3047 /****************************************************************************/
3048 /* when we are finished with redisection, we add the label for the statistic */
3050 draw_stat(user_data_t
*user_data
)
3052 gchar label_max
[200];
3054 g_snprintf(label_max
, sizeof(label_max
), "Total IAX2 packets = %u Max delta = %f sec at packet no. %u",
3055 user_data
->forward
.statinfo
.total_nr
,
3056 user_data
->forward
.statinfo
.max_delta
, user_data
->forward
.statinfo
.max_nr
);
3058 gtk_label_set_text(GTK_LABEL(user_data
->dlg
.label_stats_fwd
), label_max
);
3060 g_snprintf(label_max
, sizeof(label_max
), "Total IAX2 packets = %u Max delta = %f sec at packet no. %u",
3061 user_data
->reversed
.statinfo
.total_nr
,
3062 user_data
->reversed
.statinfo
.max_delta
, user_data
->reversed
.statinfo
.max_nr
);
3064 gtk_label_set_text(GTK_LABEL(user_data
->dlg
.label_stats_rev
), label_max
);
3065 gtk_label_set_selectable (GTK_LABEL(user_data
->dlg
.label_stats_rev
),TRUE
);
3072 /****************************************************************************/
3073 /* append a line to list */
3075 add_to_list(GtkWidget
*list
, user_data_t
* user_data
, guint32 number
,
3076 double delta
, double jitter
, double bandwidth
, gchar
*status
,
3077 gchar
*timeStr
, guint32 pkt_len
, gchar
*color_str
, guint32 flags
)
3079 GtkListStore
*list_store
;
3081 if (strcmp(status
, OK_TEXT
) != 0) {
3082 user_data
->dlg
.number_of_nok
++;
3085 list_store
= GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW (list
))); /* Get store */
3087 /* Creates a new row at position. iter will be changed to point to this new row.
3088 * If position is larger than the number of rows on the list, then the new row will be appended to the list.
3089 * The row will be filled with the values given to this function.
3091 * should generally be preferred when inserting rows in a sorted list store.
3093 gtk_list_store_insert_with_values( list_store
, &user_data
->dlg
.iter
, G_MAXINT
,
3094 PACKET_COLUMN
, number
,
3095 DELTA_COLUMN
, delta
,
3096 JITTER_COLUMN
, jitter
,
3097 IPBW_COLUMN
, bandwidth
,
3098 STATUS_COLUMN
, (char *)status
,
3099 DATE_COLUMN
, (char *)timeStr
,
3100 LENGTH_COLUMN
, pkt_len
,
3101 FOREGROUND_COLOR_COL
, NULL
,
3102 BACKGROUND_COLOR_COL
, (char *)color_str
,
3105 if (flags
& STAT_FLAG_FIRST
) {
3106 /* Set first row as active */
3107 gtk_tree_selection_select_iter(gtk_tree_view_get_selection(GTK_TREE_VIEW(list
)), &user_data
->dlg
.iter
);
3111 /****************************************************************************
3112 * Functions needed to present values from the list
3115 /* Present floats with two decimals */
3117 iax2_float_data_func (GtkTreeViewColumn
*column _U_
,
3118 GtkCellRenderer
*renderer
,
3119 GtkTreeModel
*model
,
3127 /* the col to get data from is in userdata */
3128 gint float_col
= GPOINTER_TO_INT(user_data
);
3130 gtk_tree_model_get(model
, iter
, float_col
, &float_val
, -1);
3132 /* save the current locale */
3133 savelocale
= setlocale(LC_NUMERIC
, NULL
);
3134 /* switch to "C" locale to avoid problems with localized decimal separators
3135 * in g_snprintf("%f") functions
3137 setlocale(LC_NUMERIC
, "C");
3139 g_snprintf(buf
, sizeof(buf
), "%.2f", float_val
);
3140 /* restore previous locale setting */
3141 setlocale(LC_NUMERIC
, savelocale
);
3143 g_object_set(renderer
, "text", buf
, NULL
);
3150 create_list(user_data_t
* user_data
)
3153 GtkListStore
*list_store
;
3155 GtkTreeViewColumn
*column
;
3156 GtkCellRenderer
*renderer
;
3157 GtkTreeSortable
*sortable
;
3158 GtkTreeView
*list_view
;
3159 GtkTreeSelection
*selection
;
3161 /* Create the store */
3162 list_store
= gtk_list_store_new(N_COLUMN
, /* Total number of columns XXX */
3163 G_TYPE_UINT
, /* Packet */
3164 G_TYPE_FLOAT
, /* Delta(ms) */
3165 G_TYPE_FLOAT
, /* Jitter(ms) */
3166 G_TYPE_FLOAT
, /* IP BW(kbps) */
3167 G_TYPE_STRING
, /* Status */
3168 G_TYPE_STRING
, /* Date */
3169 G_TYPE_UINT
, /* Length */
3170 G_TYPE_STRING
, /* Foreground color */
3171 G_TYPE_STRING
); /* Background color */
3174 list
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (list_store
));
3176 list_view
= GTK_TREE_VIEW(list
);
3177 sortable
= GTK_TREE_SORTABLE(list_store
);
3179 /* Speed up the list display */
3180 gtk_tree_view_set_fixed_height_mode(list_view
, TRUE
);
3182 /* Setup the sortable columns */
3183 gtk_tree_sortable_set_sort_column_id(sortable
, PACKET_COLUMN
, GTK_SORT_ASCENDING
);
3184 gtk_tree_view_set_headers_clickable(list_view
, FALSE
);
3186 /* The view now holds a reference. We can get rid of our own reference */
3187 g_object_unref (G_OBJECT (list_store
));
3190 * Create the first column packet, associating the "text" attribute of the
3191 * cell_renderer to the first column of the model
3193 renderer
= gtk_cell_renderer_text_new ();
3194 column
= gtk_tree_view_column_new_with_attributes ("Packet", renderer
,
3195 "text", PACKET_COLUMN
,
3196 "foreground", FOREGROUND_COLOR_COL
,
3197 "background", BACKGROUND_COLOR_COL
,
3199 gtk_tree_view_column_set_sort_column_id(column
, PACKET_COLUMN
);
3200 gtk_tree_view_column_set_resizable(column
, TRUE
);
3201 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_FIXED
);
3202 gtk_tree_view_column_set_min_width(column
, 100);
3204 /* Add the column to the view. */
3205 gtk_tree_view_append_column (list_view
, column
);
3207 /* Second column.. Delta(ms). */
3208 renderer
= gtk_cell_renderer_text_new ();
3209 column
= gtk_tree_view_column_new_with_attributes ("Delta(ms)", renderer
,
3210 "text", DELTA_COLUMN
,
3211 "foreground", FOREGROUND_COLOR_COL
,
3212 "background", BACKGROUND_COLOR_COL
,
3215 gtk_tree_view_column_set_cell_data_func(column
, renderer
, iax2_float_data_func
,
3216 GINT_TO_POINTER(DELTA_COLUMN
), NULL
);
3218 gtk_tree_view_column_set_sort_column_id(column
, DELTA_COLUMN
);
3219 gtk_tree_view_column_set_resizable(column
, TRUE
);
3220 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_FIXED
);
3221 gtk_tree_view_column_set_min_width(column
, 100);
3222 gtk_tree_view_append_column (list_view
, column
);
3224 /* Third column.. Jitter(ms). */
3225 renderer
= gtk_cell_renderer_text_new ();
3226 column
= gtk_tree_view_column_new_with_attributes ("Jitter(ms)", renderer
,
3227 "text", JITTER_COLUMN
,
3228 "foreground", FOREGROUND_COLOR_COL
,
3229 "background", BACKGROUND_COLOR_COL
,
3232 gtk_tree_view_column_set_cell_data_func(column
, renderer
, iax2_float_data_func
,
3233 GINT_TO_POINTER(JITTER_COLUMN
), NULL
);
3235 gtk_tree_view_column_set_sort_column_id(column
, JITTER_COLUMN
);
3236 gtk_tree_view_column_set_resizable(column
, TRUE
);
3237 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_FIXED
);
3238 gtk_tree_view_column_set_min_width(column
, 100);
3239 gtk_tree_view_append_column (list_view
, column
);
3241 /* Fourth column.. IP BW(kbps). */
3242 renderer
= gtk_cell_renderer_text_new ();
3243 column
= gtk_tree_view_column_new_with_attributes ("IP BW(kbps)", renderer
,
3244 "text", IPBW_COLUMN
,
3245 "foreground", FOREGROUND_COLOR_COL
,
3246 "background", BACKGROUND_COLOR_COL
,
3249 gtk_tree_view_column_set_cell_data_func(column
, renderer
, iax2_float_data_func
,
3250 GINT_TO_POINTER(IPBW_COLUMN
), NULL
);
3252 gtk_tree_view_column_set_sort_column_id(column
, IPBW_COLUMN
);
3253 gtk_tree_view_column_set_resizable(column
, TRUE
);
3254 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_FIXED
);
3255 gtk_tree_view_column_set_min_width(column
, 100);
3256 gtk_tree_view_append_column (list_view
, column
);
3258 /* Fifth column.. Status. */
3259 renderer
= gtk_cell_renderer_text_new ();
3260 column
= gtk_tree_view_column_new_with_attributes ( "Status", renderer
,
3261 "text", STATUS_COLUMN
,
3262 "foreground", FOREGROUND_COLOR_COL
,
3263 "background", BACKGROUND_COLOR_COL
,
3265 gtk_tree_view_column_set_sort_column_id(column
, STATUS_COLUMN
);
3266 gtk_tree_view_column_set_resizable(column
, TRUE
);
3267 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_FIXED
);
3268 gtk_tree_view_column_set_min_width(column
, 100);
3269 gtk_tree_view_append_column (list_view
, column
);
3271 /* Sixth column.. Length. */
3272 renderer
= gtk_cell_renderer_text_new ();
3273 column
= gtk_tree_view_column_new_with_attributes ("Length", renderer
,
3274 "text", LENGTH_COLUMN
,
3275 "foreground", FOREGROUND_COLOR_COL
,
3276 "background", BACKGROUND_COLOR_COL
,
3280 gtk_tree_view_column_set_sort_column_id(column
, LENGTH_COLUMN
);
3281 gtk_tree_view_column_set_resizable(column
, TRUE
);
3282 gtk_tree_view_column_set_sizing(column
, GTK_TREE_VIEW_COLUMN_FIXED
);
3283 gtk_tree_view_column_set_min_width(column
, 100);
3284 gtk_tree_view_append_column (list_view
, column
);
3286 /* Now enable the sorting of each column */
3287 gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(list_view
), TRUE
);
3288 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(list_view
), TRUE
);
3290 /* Setup the selection handler */
3291 selection
= gtk_tree_view_get_selection(GTK_TREE_VIEW(list
));
3292 gtk_tree_selection_set_mode(selection
, GTK_SELECTION_SINGLE
);
3294 g_signal_connect (G_OBJECT (selection
), "changed", /* select_row */
3295 G_CALLBACK (on_list_select_row
),
3302 /****************************************************************************/
3303 /* Create the dialog box with all widgets */
3305 create_iax2_dialog(user_data_t
* user_data
)
3307 GtkWidget
*window
= NULL
;
3308 GtkWidget
*list_fwd
;
3309 GtkWidget
*list_rev
;
3310 GtkWidget
*label_stats_fwd
;
3311 GtkWidget
*label_stats_rev
;
3312 GtkWidget
*notebook
;
3314 GtkWidget
*main_vb
, *page
, *page_r
;
3316 GtkWidget
*scrolled_window
, *scrolled_window_r
/*, *frame, *text, *label4, *page_help*/;
3317 GtkWidget
*box4
, *voice_bt
, *refresh_bt
, *goto_bt
, *close_bt
, *csv_bt
, *next_bt
;
3318 GtkWidget
*graph_bt
;
3319 gchar label_forward
[150];
3320 gchar label_reverse
[150];
3322 gchar str_ip_src
[16];
3323 gchar str_ip_dst
[16];
3325 window
= dlg_window_new("Wireshark: IAX2 Stream Analysis"); /* transient_for top_level */
3326 gtk_window_set_default_size(GTK_WINDOW(window
), 700, 400);
3328 /* Container for each row of widgets */
3329 main_vb
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 2, FALSE
);
3330 gtk_container_set_border_width(GTK_CONTAINER(main_vb
), 2);
3331 gtk_container_add(GTK_CONTAINER(window
), main_vb
);
3332 gtk_widget_show(main_vb
);
3335 g_strlcpy(str_ip_src
, get_addr_name(&(user_data
->ip_src_fwd
)), 16);
3336 g_strlcpy(str_ip_dst
, get_addr_name(&(user_data
->ip_dst_fwd
)), 16);
3338 g_snprintf(label_forward
, sizeof(label_forward
),
3339 "Analysing stream from %s port %u to %s port %u ",
3340 str_ip_src
, user_data
->port_src_fwd
, str_ip_dst
, user_data
->port_dst_fwd
);
3343 g_strlcpy(str_ip_src
, get_addr_name(&(user_data
->ip_src_rev
)), 16);
3344 g_strlcpy(str_ip_dst
, get_addr_name(&(user_data
->ip_dst_rev
)), 16);
3346 g_snprintf(label_reverse
, sizeof(label_reverse
),
3347 "Analysing stream from %s port %u to %s port %u ",
3348 str_ip_src
, user_data
->port_src_rev
, str_ip_dst
, user_data
->port_dst_rev
);
3350 /* Start a notebook for flipping between sets of changes */
3351 notebook
= gtk_notebook_new();
3352 gtk_box_pack_start(GTK_BOX(main_vb
), notebook
, TRUE
, TRUE
, 0);
3353 g_object_set_data(G_OBJECT(window
), "notebook", notebook
);
3355 user_data
->dlg
.notebook_signal_id
=
3356 g_signal_connect(notebook
, "switch_page", G_CALLBACK(on_notebook_switch_page
), user_data
);
3358 /* page for forward connection */
3359 page
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 8, FALSE
);
3360 gtk_container_set_border_width(GTK_CONTAINER(page
), 8);
3362 /* direction label */
3363 label
= gtk_label_new(label_forward
);
3364 gtk_box_pack_start(GTK_BOX(page
), label
, FALSE
, FALSE
, 0);
3366 /* place for some statistics */
3367 label_stats_fwd
= gtk_label_new("\n");
3368 gtk_box_pack_end(GTK_BOX(page
), label_stats_fwd
, FALSE
, FALSE
, 0);
3370 /* scrolled window */
3371 scrolled_window
= scrolled_window_new(NULL
, NULL
);
3374 list_fwd
= create_list(user_data
);
3375 gtk_widget_show(list_fwd
);
3376 gtk_container_add(GTK_CONTAINER(scrolled_window
), list_fwd
);
3377 gtk_box_pack_start(GTK_BOX(page
), scrolled_window
, TRUE
, TRUE
, 0);
3378 gtk_widget_show(scrolled_window
);
3381 label
= gtk_label_new(" Forward Direction ");
3382 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), page
, label
);
3384 /* same page for reversed connection */
3385 page_r
= ws_gtk_box_new(GTK_ORIENTATION_VERTICAL
, 8, FALSE
);
3386 gtk_container_set_border_width(GTK_CONTAINER(page_r
), 8);
3387 label
= gtk_label_new(label_reverse
);
3388 gtk_box_pack_start(GTK_BOX(page_r
), label
, FALSE
, FALSE
, 0);
3389 label_stats_rev
= gtk_label_new("\n");
3390 gtk_box_pack_end(GTK_BOX(page_r
), label_stats_rev
, FALSE
, FALSE
, 0);
3392 scrolled_window_r
= scrolled_window_new(NULL
, NULL
);
3394 list_rev
= create_list(user_data
);
3395 gtk_widget_show(list_rev
);
3396 gtk_container_add(GTK_CONTAINER(scrolled_window_r
), list_rev
);
3397 gtk_box_pack_start(GTK_BOX(page_r
), scrolled_window_r
, TRUE
, TRUE
, 0);
3398 gtk_widget_show(scrolled_window_r
);
3400 label
= gtk_label_new(" Reversed Direction ");
3401 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), page_r
, label
);
3404 /* page for help&about or future */
3405 page_help
= ws_gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 5, FALSE
);
3406 label
= gtk_label_new(" Future ");
3407 gtk_notebook_append_page(GTK_NOTEBOOK(notebook
), page_help
, label
);
3408 frame
= gtk_frame_new("");
3409 text
= gtk_label_new("\n\nMaybe some more statistics: delta and jitter distribution,...");
3410 gtk_label_set_justify(GTK_LABEL(text
), GTK_JUSTIFY_LEFT
);
3411 gtk_container_add(GTK_CONTAINER(frame
), text
);
3412 gtk_container_set_border_width(GTK_CONTAINER(frame
), 20);
3413 gtk_box_pack_start(GTK_BOX(page_help
), frame
, TRUE
, TRUE
, 0);
3416 /* show all notebooks */
3417 gtk_widget_show_all(notebook
);
3420 box4
= gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL
);
3421 gtk_box_pack_start(GTK_BOX(main_vb
), box4
, FALSE
, FALSE
, 0);
3422 gtk_container_set_border_width(GTK_CONTAINER(box4
), 10);
3423 gtk_button_box_set_layout(GTK_BUTTON_BOX (box4
), GTK_BUTTONBOX_EDGE
);
3424 gtk_box_set_spacing(GTK_BOX (box4
), 0);
3425 gtk_widget_show(box4
);
3427 voice_bt
= gtk_button_new_with_label("Save payload...");
3428 gtk_container_add(GTK_CONTAINER(box4
), voice_bt
);
3429 gtk_widget_show(voice_bt
);
3430 g_signal_connect(voice_bt
, "clicked", G_CALLBACK(save_voice_as_cb
), user_data
);
3432 csv_bt
= gtk_button_new_with_label("Save as CSV...");
3433 gtk_container_add(GTK_CONTAINER(box4
), csv_bt
);
3434 gtk_widget_show(csv_bt
);
3435 g_signal_connect(csv_bt
, "clicked", G_CALLBACK(save_csv_as_cb
), user_data
);
3437 refresh_bt
= gtk_button_new_from_stock(GTK_STOCK_REFRESH
);
3438 gtk_container_add(GTK_CONTAINER(box4
), refresh_bt
);
3439 gtk_widget_show(refresh_bt
);
3440 g_signal_connect(refresh_bt
, "clicked", G_CALLBACK(on_refresh_bt_clicked
), user_data
);
3442 goto_bt
= gtk_button_new_from_stock(GTK_STOCK_JUMP_TO
);
3443 gtk_container_add(GTK_CONTAINER(box4
), goto_bt
);
3444 gtk_widget_show(goto_bt
);
3445 g_signal_connect(goto_bt
, "clicked", G_CALLBACK(on_goto_bt_clicked
), user_data
);
3447 graph_bt
= gtk_button_new_with_label("Graph");
3448 gtk_container_add(GTK_CONTAINER(box4
), graph_bt
);
3449 gtk_widget_show(graph_bt
);
3450 g_signal_connect(graph_bt
, "clicked", G_CALLBACK(on_graph_bt_clicked
), user_data
);
3452 next_bt
= gtk_button_new_with_label("Next non-Ok");
3453 gtk_container_add(GTK_CONTAINER(box4
), next_bt
);
3454 gtk_widget_show(next_bt
);
3455 g_signal_connect(next_bt
, "clicked", G_CALLBACK(on_next_bt_clicked
), user_data
);
3457 close_bt
= gtk_button_new_from_stock(GTK_STOCK_CLOSE
);
3458 gtk_container_add(GTK_CONTAINER(box4
), close_bt
);
3459 gtk_widget_set_can_default(close_bt
, TRUE
);
3460 gtk_widget_show(close_bt
);
3461 window_set_cancel_button(window
, close_bt
, window_cancel_button_cb
);
3463 g_signal_connect(window
, "delete_event", G_CALLBACK(window_delete_event_cb
), NULL
);
3464 g_signal_connect(window
, "destroy", G_CALLBACK(on_iax2_window_destroy
), user_data
);
3466 gtk_widget_show(window
);
3467 window_present(window
);
3469 /* some widget references need to be saved for outside use */
3470 user_data
->dlg
.window
= window
;
3471 user_data
->dlg
.list_fwd
= list_fwd
;
3472 user_data
->dlg
.list_rev
= list_rev
;
3473 user_data
->dlg
.label_stats_fwd
= label_stats_fwd
;
3474 user_data
->dlg
.label_stats_rev
= label_stats_rev
;
3475 user_data
->dlg
.notebook
= notebook
;
3476 user_data
->dlg
.selected_list
= list_fwd
;
3477 user_data
->dlg
.number_of_nok
= 0;
3480 * select the initial row
3482 gtk_widget_grab_focus(list_fwd
);
3486 /****************************************************************************/
3488 process_node(proto_node
*ptree_node
, header_field_info
*hfinformation
,
3489 const gchar
* proto_field
, guint32
* p_result
)
3492 proto_node
*proto_sibling_node
;
3493 header_field_info
*hfssrc
;
3496 finfo
= PNODE_FINFO(ptree_node
);
3498 if (hfinformation
== (finfo
->hfinfo
)) {
3499 hfssrc
= proto_registrar_get_byname(proto_field
);
3500 if (hfssrc
== NULL
) {
3501 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3505 for (ptree_node
= ptree_node
->first_child
;
3507 ptree_node
= ptree_node
->next
) {
3508 finfo
= PNODE_FINFO(ptree_node
);
3509 if (hfssrc
== finfo
->hfinfo
) {
3510 if (hfinformation
->type
== FT_IPv4
) {
3511 ipv4
= fvalue_get(&finfo
->value
);
3512 *p_result
= ipv4_get_net_order_addr(ipv4
);
3515 *p_result
= fvalue_get_uinteger(&finfo
->value
);
3524 proto_sibling_node
= ptree_node
->next
;
3526 if (proto_sibling_node
) {
3527 return process_node(proto_sibling_node
, hfinformation
, proto_field
, p_result
);
3533 /****************************************************************************/
3535 get_int_value_from_proto_tree(proto_tree
*protocol_tree
,
3536 const gchar
* proto_name
,
3537 const gchar
* proto_field
,
3540 proto_node
*ptree_node
;
3541 header_field_info
*hfinformation
;
3543 hfinformation
= proto_registrar_get_byname(proto_name
);
3544 if (hfinformation
== NULL
) {
3545 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3550 ptree_node
= ((proto_node
*)protocol_tree
)->first_child
;
3552 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3556 return process_node(ptree_node
, hfinformation
, proto_field
, p_result
);
3560 /****************************************************************************/
3563 address
*ip_src_fwd
,
3564 guint16 port_src_fwd
,
3565 address
*ip_dst_fwd
,
3566 guint16 port_dst_fwd
,
3567 address
*ip_src_rev
,
3568 guint16 port_src_rev
,
3569 address
*ip_dst_rev
,
3570 guint16 port_dst_rev
3573 user_data_t
*user_data
;
3576 static GdkColor col
[MAX_GRAPHS
] = {
3577 {0, 0x0000, 0x0000, 0x0000},
3578 {0, 0xffff, 0x0000, 0x0000},
3579 {0, 0x0000, 0xffff, 0x0000},
3580 {0, 0x0000, 0x0000, 0xffff}
3582 static GdkRGBA rgba_col
[MAX_GRAPHS
] = {
3583 {0.0, 0.0, 0.0, 1.0}, /* Black */
3584 {1.0, 0.0, 0.1, 1.0}, /* Red */
3585 {0.0, 1.0, 0.0, 1.0}, /* Green */
3586 {0.0, 0.0, 1.0, 1.0}, /* Blue */
3592 user_data
= (user_data_t
*)g_malloc(sizeof(user_data_t
));
3594 COPY_ADDRESS(&(user_data
->ip_src_fwd
), ip_src_fwd
);
3595 user_data
->port_src_fwd
= port_src_fwd
;
3596 COPY_ADDRESS(&(user_data
->ip_dst_fwd
), ip_dst_fwd
);
3597 user_data
->port_dst_fwd
= port_dst_fwd
;
3598 COPY_ADDRESS(&(user_data
->ip_src_rev
), ip_src_rev
);
3599 user_data
->port_src_rev
= port_src_rev
;
3600 COPY_ADDRESS(&(user_data
->ip_dst_rev
), ip_dst_rev
);
3601 user_data
->port_dst_rev
= port_dst_rev
;
3604 /* file names for storing sound data */
3605 fd
= create_tempfile(&tempname
, "wireshark_iax2_f");
3607 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3608 "Can't create temporary file for IAX2 analysis:\n%s.",
3613 user_data
->f_tempname
= g_strdup(tempname
);
3615 fd
= create_tempfile(&tempname
, "wireshark_iax2_r");
3617 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3618 "Can't create temporary file for IAX2 analysis:\n%s.",
3620 g_free(user_data
->f_tempname
);
3624 user_data
->r_tempname
= g_strdup(tempname
);
3626 user_data
->forward
.saveinfo
.fp
= NULL
;
3627 user_data
->reversed
.saveinfo
.fp
= NULL
;
3628 user_data
->dlg
.save_voice_as_w
= NULL
;
3629 user_data
->dlg
.save_csv_as_w
= NULL
;
3630 user_data
->dlg
.dialog_graph
.window
= NULL
;
3632 /* init dialog_graph */
3633 user_data
->dlg
.dialog_graph
.needs_redraw
= TRUE
;
3634 user_data
->dlg
.dialog_graph
.interval
= tick_interval_values
[DEFAULT_TICK_VALUE_INDEX
];
3635 user_data
->dlg
.dialog_graph
.draw_area
= NULL
;
3636 #if GTK_CHECK_VERSION(2,22,0)
3637 user_data
->dlg
.dialog_graph
.surface
= NULL
;
3639 user_data
->dlg
.dialog_graph
.pixmap
= NULL
;
3641 user_data
->dlg
.dialog_graph
.scrollbar
= NULL
;
3642 user_data
->dlg
.dialog_graph
.scrollbar_adjustment
= NULL
;
3643 user_data
->dlg
.dialog_graph
.surface_width
= 500;
3644 user_data
->dlg
.dialog_graph
.surface_height
= 200;
3645 user_data
->dlg
.dialog_graph
.pixels_per_tick
= pixels_per_tick
[DEFAULT_PIXELS_PER_TICK_INDEX
];
3646 user_data
->dlg
.dialog_graph
.max_y_units
= AUTO_MAX_YSCALE
;
3647 user_data
->dlg
.dialog_graph
.last_interval
= 0xffffffff;
3648 user_data
->dlg
.dialog_graph
.max_interval
= 0;
3649 user_data
->dlg
.dialog_graph
.num_items
= 0;
3650 user_data
->dlg
.dialog_graph
.start_time
= -1;
3652 for(i
= 0; i
< MAX_GRAPHS
; i
++) {
3653 user_data
->dlg
.dialog_graph
.graph
[i
].color
.pixel
= 0;
3654 user_data
->dlg
.dialog_graph
.graph
[i
].color
.red
= col
[i
].red
;
3655 user_data
->dlg
.dialog_graph
.graph
[i
].color
.green
= col
[i
].green
;
3656 user_data
->dlg
.dialog_graph
.graph
[i
].color
.blue
= col
[i
].blue
;
3657 user_data
->dlg
.dialog_graph
.graph
[i
].rgba_color
.red
= rgba_col
[i
].red
;
3658 user_data
->dlg
.dialog_graph
.graph
[i
].rgba_color
.green
= rgba_col
[i
].green
;
3659 user_data
->dlg
.dialog_graph
.graph
[i
].rgba_color
.blue
= rgba_col
[i
].blue
;
3660 user_data
->dlg
.dialog_graph
.graph
[i
].rgba_color
.alpha
= rgba_col
[i
].alpha
;
3661 user_data
->dlg
.dialog_graph
.graph
[i
].display
= TRUE
;
3662 user_data
->dlg
.dialog_graph
.graph
[i
].display_button
= NULL
;
3663 user_data
->dlg
.dialog_graph
.graph
[i
].ud
= user_data
;
3666 /* create the dialog box */
3667 create_iax2_dialog(user_data
);
3669 /* proceed as if the Refresh button would have been pressed */
3670 on_refresh_bt_clicked(NULL
, user_data
);
3673 /****************************************************************************/
3674 /* entry point from main menu */
3675 void iax2_analysis_cb(GtkAction
*action _U_
, gpointer user_data _U_
)
3678 guint16 port_src_fwd
;
3680 guint16 port_dst_fwd
;
3682 guint16 port_src_rev
;
3684 guint16 port_dst_rev
;
3685 /* unsigned int ptype; */
3687 gchar filter_text
[256];
3690 gboolean frame_matched
;
3692 GList
*strinfo_list
;
3693 GList
*filtered_list
= NULL
;
3696 rtp_stream_info_t
*strinfo
;
3698 /* Try to compile the filter. */
3699 g_strlcpy(filter_text
,"iax2 && (ip || ipv6)",256);
3700 if (!dfilter_compile(filter_text
, &sfcode
)) {
3701 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
, "%s", dfilter_error_msg
);
3704 /* we load the current file into cf variable */
3706 fdata
= cf
->current_frame
;
3708 /* we are on the selected frame now */
3710 return; /* if we exit here it's an error */
3712 /* dissect the current frame */
3713 if (!cf_read_frame(cf
, fdata
))
3714 return; /* error reading the frame */
3715 epan_dissect_init(&edt
, cf
->epan
, TRUE
, FALSE
);
3716 epan_dissect_prime_dfilter(&edt
, sfcode
);
3717 epan_dissect_run(&edt
, &cf
->phdr
, frame_tvbuff_new_buffer(fdata
, &cf
->buf
),
3720 /* if it is not an iax2 frame, show an error dialog */
3721 frame_matched
= dfilter_apply_edt(sfcode
, &edt
);
3722 if (frame_matched
!= 1) {
3723 epan_dissect_cleanup(&edt
);
3724 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3725 "Please select an IAX2 packet.");
3729 /* check if it is Voice or MiniPacket */
3730 if (!get_int_value_from_proto_tree(edt
->tree
, "iax2", "iax2.call", &ptype
)) {
3731 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3732 "Please select a Voice packet.");
3737 /* check if it is part of a Call */
3738 if (edt
.pi
.circuit_id
== 0) {
3739 simple_dialog(ESD_TYPE_ERROR
, ESD_BTN_OK
,
3740 "Please select a Call packet.");
3744 /* ok, it is a IAX2 frame, so let's get the ip and port values */
3745 COPY_ADDRESS(&(ip_src_fwd
), &(edt
.pi
.src
));
3746 COPY_ADDRESS(&(ip_dst_fwd
), &(edt
.pi
.dst
));
3747 port_src_fwd
= edt
.pi
.srcport
;
3748 port_dst_fwd
= edt
.pi
.destport
;
3750 /* assume the inverse ip/port combination for the reverse direction */
3751 COPY_ADDRESS(&(ip_src_rev
), &(edt
.pi
.dst
));
3752 COPY_ADDRESS(&(ip_dst_rev
), &(edt
.pi
.src
));
3753 port_src_rev
= edt
.pi
.destport
;
3754 port_dst_rev
= edt
.pi
.srcport
;
3756 /* Scan for rtpstream */
3758 /* search for reversed direction in the global rtp streams list */
3760 strinfo_list
= g_list_first(rtpstream_get_info()->strinfo_list
);
3761 while (strinfo_list
)
3763 strinfo
= (rtp_stream_info_t
*)(strinfo_list
->data
);
3764 if (ADDRESSES_EQUAL(&(strinfo
->src_addr
),&(ip_src_fwd
))
3765 && strinfo
->src_port
== port_src_fwd
3766 && ADDRESSES_EQUAL(&(strinfo
->dest_addr
),&(ip_dst_fwd
))
3767 && strinfo
->dest_port
== port_dst_fwd
)
3769 filtered_list
= g_list_prepend(filtered_list
, strinfo
);
3772 if (ADDRESSES_EQUAL(&(strinfo
->src_addr
),&(ip_src_rev
))
3773 && strinfo
->src_port
== port_src_rev
3774 && ADDRESSES_EQUAL(&(strinfo
->dest_addr
),&(ip_dst_rev
))
3775 && strinfo
->dest_port
== port_dst_rev
)
3778 filtered_list
= g_list_append(filtered_list
, strinfo
);
3781 strinfo_list
= g_list_next(strinfo_list
);
3784 /* if more than one reverse streams found, we let the user choose the right one */
3786 rtpstream_dlg_show(filtered_list
);
3803 /****************************************************************************/
3805 iax2_analysis_init(const char *dummy _U_
,void* userdata _U_
)
3807 iax2_analysis_cb(NULL
, NULL
);
3810 /****************************************************************************/
3812 register_tap_listener_iax2_analysis(void)
3814 register_stat_cmd_arg("IAX2", iax2_analysis_init
,NULL
);
3824 * indent-tabs-mode: t
3827 * ex: set shiftwidth=8 tabstop=8 noexpandtab:
3828 * :indentSize=8:tabSize=8:noTabs=false: