Add the sccp tap to the "VoIP Calls" Tap (which by now should be renamed to just...
[obnox/wireshark/wip.git] / gtk / voip_calls_dlg.c
1 /* voip_calls_dlg.c
2  * VoIP calls summary addition for Wireshark
3  *
4  * $Id$
5  *
6  * Copyright 2004, Ericsson , Spain
7  * By Francisco Alcoba <francisco.alcoba@ericsson.com>
8  *
9  * based on h323_calls_dlg.c
10  * Copyright 2004, Iskratel, Ltd, Kranj
11  * By Miha Jemec <m.jemec@iskratel.si>
12  *
13  * H323, RTP and Graph Support
14  * By Alejandro Vaquero, alejandro.vaquero@verso.com
15  * Copyright 2005, Verso Technologies Inc.
16  *
17  * Wireshark - Network traffic analyzer
18  * By Gerald Combs <gerald@wireshark.org>
19  * Copyright 1998 Gerald Combs
20  *
21  * This program is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU General Public License
23  * as published by the Free Software Foundation; either version 2
24  * of the License, or (at your option) any later version.
25  *
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  * GNU General Public License for more details.
30  *
31  * You should have received a copy of the GNU General Public License
32  * along with this program; if not, write to the Free Software
33  * Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
34  */
35
36 #ifdef HAVE_CONFIG_H
37 #  include <config.h>
38 #endif
39
40 #include <string.h>
41 #include <ctype.h>
42
43 #include "register.h"
44
45 #include "graph_analysis.h"
46 #include "voip_calls_dlg.h"
47 #include "voip_calls.h"
48
49 #include "globals.h"
50 #include "epan/filesystem.h"
51
52 #include <epan/tap.h>
53 #include <epan/stat_cmd_args.h>
54 #include "../stat_menu.h"
55 #include "gui_stat_menu.h"
56 #include "dlg_utils.h"
57 #include "gui_utils.h"
58 #include "compat_macros.h"
59 #include "gtkglobals.h"
60
61 #include "image/clist_ascend.xpm"
62 #include "image/clist_descend.xpm"
63 #include "simple_dialog.h"
64
65 #include <epan/to_str.h>
66
67 #include <epan/address.h>
68 #include <epan/addr_resolv.h>
69 #include <epan/dissectors/packet-h248.h>
70
71 #ifdef HAVE_LIBPORTAUDIO
72 #if GTK_MAJOR_VERSION >= 2
73 #include "rtp_analysis.h"
74 #include "rtp_player.h"
75 #endif
76 #endif /* HAVE_LIBPORTAUDIO */
77
78 static const gchar FWD_LABEL_TEXT[] = "Select one call.";
79
80 /****************************************************************************/
81 /* pointer to the one and only dialog window */
82 static GtkWidget *voip_calls_dlg = NULL;
83
84 static GtkWidget *clist = NULL;
85 static GtkWidget *top_label = NULL;
86 static GtkWidget *status_label = NULL;
87 static GtkWidget *label_fwd = NULL;
88
89 /*static GtkWidet *bt_unselect = NULL;*/
90 static GtkWidget *bt_filter = NULL;
91 static GtkWidget *bt_graph = NULL;
92 #ifdef HAVE_LIBPORTAUDIO
93 #if GTK_MAJOR_VERSION >= 2
94 static GtkWidget *bt_player = NULL;
95 #endif
96 #endif /* HAVE_LIBPORTAUDIO */
97
98 static voip_calls_info_t* selected_call_fwd = NULL;  /* current selection */
99 static GList *last_list = NULL;
100
101 static guint32 calls_nb = 0;     /* number of displayed calls */
102 static guint32 calls_ns = 0;     /* number of selected calls */
103
104 static graph_analysis_data_t *graph_analysis_data = NULL;
105
106 #define NUM_COLS 9
107 #define CALL_COL_START_TIME             0
108 #define CALL_COL_STOP_TIME              1
109 #define CALL_COL_INITIAL_SPEAKER        2
110 #define CALL_COL_FROM                   3
111 #define CALL_COL_TO                     4
112 #define CALL_COL_PROTOCOL               5
113 #define CALL_COL_PACKETS                6
114 #define CALL_COL_STATE                  7
115 #define CALL_COL_COMMENTS               8
116 static const GdkColor COLOR_SELECT = {0, 0x00ff, 0x80ff, 0x80ff};
117 static const GdkColor COLOR_DEFAULT = {0, 0xffff, 0xffff, 0xffff};
118
119 /****************************************************************************/
120 /* append a line to clist */
121 static void add_to_clist(voip_calls_info_t* strinfo)
122 {
123         gchar label_text[256];
124         gint added_row;
125         gchar *data[NUM_COLS];
126         gchar field[NUM_COLS][50];
127         gint c;
128         isup_calls_info_t *tmp_isupinfo;
129         h323_calls_info_t *tmp_h323info;
130         gboolean tmp_bool = FALSE;
131         GdkColor color = COLOR_SELECT;
132         for (c=0;c<NUM_COLS;c++){
133                 data[c]=&field[c][0];
134         }
135
136 /*      strinfo->selected = FALSE;*/
137
138         g_snprintf(field[CALL_COL_START_TIME], 15, "%i.%2i", strinfo->start_sec, strinfo->start_usec/10000);
139         g_snprintf(field[CALL_COL_STOP_TIME], 15, "%i.%2i", strinfo->stop_sec, strinfo->stop_usec/10000);
140 /*      xxx display_signed_time(data[0], sizeof(field[CALL_COL_START_TIME]), strinfo->start_sec, strinfo->start_usec, USECS); */
141 /*      display_signed_time(data[1], sizeof(field[CALL_COL_STOP_TIME]), strinfo->stop_sec, strinfo->stop_usec, USECS); */
142         g_snprintf(field[CALL_COL_INITIAL_SPEAKER], 30, "%s", get_addr_name(&(strinfo->initial_speaker)));
143         g_snprintf(field[CALL_COL_FROM], 50, "%s", strinfo->from_identity);
144         g_snprintf(field[CALL_COL_TO], 50, "%s", strinfo->to_identity);
145         g_snprintf(field[CALL_COL_PROTOCOL], 15, "%s", voip_protocol_name[strinfo->protocol]);
146         g_snprintf(field[CALL_COL_PACKETS], 15, "%u", strinfo->npackets);
147         g_snprintf(field[CALL_COL_STATE], 15, "%s", voip_call_state_name[strinfo->call_state]);
148
149         /* Add comments based on the protocol */
150         switch(strinfo->protocol){
151                 case VOIP_ISUP:
152                         tmp_isupinfo = strinfo->prot_info;
153                         g_snprintf(field[CALL_COL_COMMENTS],30, "%i-%i -> %i-%i", tmp_isupinfo->ni, tmp_isupinfo->opc,
154                                 tmp_isupinfo->ni, tmp_isupinfo->dpc);
155                         break;
156                 case VOIP_H323:
157                         tmp_h323info = strinfo->prot_info;
158                         if (strinfo->call_state == VOIP_CALL_SETUP) 
159                                 tmp_bool = tmp_h323info->is_faststart_Setup;
160                         else
161                                 if ((tmp_h323info->is_faststart_Setup == TRUE) && (tmp_h323info->is_faststart_Proc == TRUE)) tmp_bool = TRUE; 
162                         g_snprintf(field[CALL_COL_COMMENTS],35, "Tunneling: %s  Fast Start: %s", (tmp_h323info->is_h245Tunneling==TRUE?"ON":"OFF"), 
163                                 (tmp_bool==TRUE?"ON":"OFF"));
164                         break;
165                 default:
166                         field[CALL_COL_COMMENTS][0]='\0';
167         }
168
169         
170         added_row = gtk_clist_append(GTK_CLIST(clist), data);
171
172         /* set the background color if selected */
173         if (strinfo->selected) { 
174                 calls_ns++;
175                 gtk_clist_set_background(GTK_CLIST(clist), added_row, &color);
176         }
177
178         /* set data pointer of last row to point to user data for that row */
179         gtk_clist_set_row_data(GTK_CLIST(clist), added_row, strinfo);
180
181         /* Update the top label with the number of detected calls */
182         calls_nb++;
183         g_snprintf(label_text, 256,
184                 "Detected %d VoIP %s. Selected %d %s.",
185                 calls_nb, 
186                 plurality(calls_nb, "Call", "Calls"),
187                 calls_ns,
188                 plurality(calls_ns, "Call", "Calls"));
189         gtk_label_set(GTK_LABEL(top_label), label_text);
190
191         /* Update the status label with the number of total messages */
192         g_snprintf(label_text, 256,
193                 "Total: Calls: %d   Start packets: %d   Completed calls: %d   Rejected calls: %d",
194                         g_list_length(voip_calls_get_info()->strinfo_list),
195                         voip_calls_get_info()->start_packets, 
196                         voip_calls_get_info()->completed_calls,
197                         voip_calls_get_info()->rejected_calls);
198         gtk_label_set(GTK_LABEL(status_label), label_text);
199 }
200
201
202 static void voip_calls_remove_tap_listener(void)
203 {
204         /* Remove the calls tap listener */
205         remove_tap_listener_sip_calls();
206         remove_tap_listener_isup_calls();
207         remove_tap_listener_mtp3_calls();
208         remove_tap_listener_h225_calls();
209         remove_tap_listener_h245dg_calls();
210         remove_tap_listener_q931_calls();
211         remove_tap_listener_h248_calls();
212         remove_tap_listener_sccp_calls();
213         remove_tap_listener_sdp_calls();
214         remove_tap_listener_rtp();
215         remove_tap_listener_rtp_event();
216         if (find_tap_id("mgcp")) {
217                 remove_tap_listener_mgcp_calls();
218         }
219         remove_tap_listener_actrace_calls();
220         remove_tap_listener_t38();
221 }
222
223 /****************************************************************************/
224 /* CALLBACKS                                                                */
225 /****************************************************************************/
226 static void
227 voip_calls_on_destroy                      (GtkObject       *object _U_,
228                                         gpointer         user_data _U_)
229 {
230         /* remove_tap_listeners */
231         voip_calls_remove_tap_listener();
232
233         /* Clean up memory used by calls tap */
234         voip_calls_dlg_reset(NULL);
235
236         /* Note that we no longer have a "VoIP Calls" dialog box. */
237         voip_calls_dlg = NULL;
238
239         graph_analysis_data = NULL;
240 }
241
242
243 /****************************************************************************/
244 static void
245 voip_calls_on_unselect                  (GtkButton       *button _U_,
246                                         gpointer         user_data _U_)
247 {
248         selected_call_fwd = NULL;
249         gtk_clist_unselect_all(GTK_CLIST(clist));
250         gtk_label_set_text(GTK_LABEL(label_fwd), FWD_LABEL_TEXT);
251
252         /*gtk_widget_set_sensitive(bt_unselect, FALSE);*/
253         gtk_widget_set_sensitive(bt_filter, FALSE);
254         gtk_widget_set_sensitive(bt_graph, FALSE);
255 #ifdef HAVE_LIBPORTAUDIO
256 #if GTK_MAJOR_VERSION >= 2
257         gtk_widget_set_sensitive(bt_player, FALSE);
258 #endif
259 #endif /* HAVE_LIBPORTAUDIO */
260 }
261
262
263 /****************************************************************************/
264 static void
265 voip_calls_on_filter                    (GtkButton       *button _U_,
266                                         gpointer         user_data _U_)
267 {
268         const gchar *filter_string;
269         gchar c;
270         GString *filter_string_fwd;
271         const gchar *filter_prepend;
272         gboolean isFirst = TRUE;
273         GList* list;
274         guint filter_length = 0;
275         guint max_filter_length = 2048;
276         sip_calls_info_t *tmp_sipinfo;
277         isup_calls_info_t *tmp_isupinfo;
278         h323_calls_info_t *tmp_h323info;
279         h245_address_t *h245_add = NULL;
280
281         graph_analysis_item_t *gai;
282
283         if (selected_call_fwd==NULL)
284                 return;
285
286         filter_string=gtk_entry_get_text(GTK_ENTRY(main_display_filter_widget));
287         filter_length = strlen(filter_string);
288         filter_prepend = "";
289         while ((c = *filter_string++) != '\0') {
290                 if (!isspace((guchar)c)) {
291                         /* The filter string isn't blank, so there's already
292                            an expression; we OR in the new expression */
293                         filter_prepend = " or ";
294                         break;
295                 }
296         }
297                 
298         filter_string_fwd = g_string_new(filter_prepend);
299         
300         /* look in the Graph and get all the frame_num for this call */
301         g_string_sprintfa(filter_string_fwd, " (");
302         list = g_list_first(voip_calls_get_info()->graph_analysis->list);
303         while (list)
304         {
305                 gai = list->data;
306                 if (gai->conv_num == selected_call_fwd->call_num){
307                         g_string_sprintfa(filter_string_fwd,"%sframe.number == %d", isFirst?"":" or ", gai->frame_num );
308                         isFirst = FALSE;
309                 }               
310                 list = g_list_next (list);
311         }
312         g_string_sprintfa(filter_string_fwd, ") ");
313         filter_length = filter_length + filter_string_fwd->len;
314
315         if (filter_length < max_filter_length){
316                 gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str);
317         } else {
318                 g_string_free(filter_string_fwd, TRUE);
319                 filter_string_fwd = g_string_new(filter_prepend);
320
321                 switch(selected_call_fwd->protocol){
322                         case VOIP_SIP:
323                                 tmp_sipinfo = selected_call_fwd->prot_info;
324                                 g_string_sprintfa(filter_string_fwd,
325                                    "(sip.Call-ID == \"%s\") ",
326                                    tmp_sipinfo->call_identifier 
327                                    );
328                                 gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str);
329                                 break;
330                         case VOIP_ISUP:
331                                 tmp_isupinfo = selected_call_fwd->prot_info;
332                                 g_string_sprintfa(filter_string_fwd,
333                                    "(isup.cic == %i and frame.number >=%i and frame.number<=%i and mtp3.network_indicator == %i and ((mtp3.dpc == %i) and (mtp3.opc == %i)) or((mtp3.dpc == %i) and (mtp3.opc == %i))) ",
334                                    tmp_isupinfo->cic,selected_call_fwd->first_frame_num,
335                                    selected_call_fwd->last_frame_num, 
336                                    tmp_isupinfo->ni, tmp_isupinfo->dpc, tmp_isupinfo->opc, 
337                                    tmp_isupinfo->opc, tmp_isupinfo->dpc
338                                    );
339                                 gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str);
340                                 break;
341                         case VOIP_H323:
342                                 tmp_h323info = selected_call_fwd->prot_info;
343                                 g_string_sprintfa(filter_string_fwd,
344                                    "((h225.guid == %s || q931.call_ref == %x:%x || q931.call_ref == %x:%x) ",
345                                    guid_to_str(&tmp_h323info->guid[0]),
346                                    (guint8)(tmp_h323info->q931_crv & 0xff),
347                                    (guint8)((tmp_h323info->q931_crv & 0xff00)>>8),
348                                    (guint8)(tmp_h323info->q931_crv2 & 0xff),
349                                    (guint8)((tmp_h323info->q931_crv2 & 0xff00)>>8));
350                                 list = g_list_first(tmp_h323info->h245_list);
351                                 while (list)
352                                 {
353                                         h245_add=list->data;
354                                         g_string_sprintfa(filter_string_fwd,
355                                                 " || (ip.addr == %s && tcp.port == %d && h245) ", 
356                                                 ip_to_str((guint8 *)&(h245_add->h245_address)), h245_add->h245_port);
357                                 list = g_list_next(list);
358                                 }
359                                 g_string_sprintfa(filter_string_fwd, ") ");
360                                 gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), filter_string_fwd->str);
361                                 break;
362                         case TEL_H248: {
363                                 const h248_ctx_t* ctx = selected_call_fwd->prot_info;
364                                 gtk_entry_append_text(GTK_ENTRY(main_display_filter_widget), ep_strdup_printf("h248.ctx == 0x%x", ctx->id ));
365                                 break;
366                         }
367                         case TEL_SCCP:
368                         case VOIP_MGCP:
369                         case VOIP_AC_ISDN:
370                         case VOIP_AC_CAS:
371                         case MEDIA_T38:
372                                 /* XXX - not supported */
373                                 break;
374                 }
375                 
376         }
377         
378         g_string_free(filter_string_fwd, TRUE);
379 }
380
381
382
383
384 /****************************************************************************/
385 static void
386 on_graph_bt_clicked                    (GtkButton       *button _U_,
387                                         gpointer         user_data _U_)
388 {
389         graph_analysis_item_t *gai;
390         GList* list;
391         GList* list2;
392         voip_calls_info_t *tmp_listinfo;
393
394         /* reset the "display" parameter in graph analysis */
395         list2 = g_list_first(voip_calls_get_info()->graph_analysis->list);
396         while (list2){
397                 gai = list2->data;
398                 gai->display = FALSE;
399                 list2 = g_list_next(list2);
400         }
401
402
403         /* set the display for selected calls */
404         list = g_list_first(voip_calls_get_info()->strinfo_list);
405         while (list){
406                 tmp_listinfo=list->data;
407                 if (tmp_listinfo->selected){
408                         list2 = g_list_first(voip_calls_get_info()->graph_analysis->list);
409                         while (list2){
410                                 gai = list2->data;
411                                 if (gai->conv_num == tmp_listinfo->call_num){
412                                         gai->display = TRUE;
413                                 }
414                                 list2 = g_list_next(list2);
415                         }
416                 }
417                 list = g_list_next(list);
418         }
419
420         /* create or refresh the graph windows */
421         if (graph_analysis_data->dlg.window == NULL)    /* create the window */
422                 graph_analysis_create(graph_analysis_data);
423         else
424                 graph_analysis_update(graph_analysis_data);             /* refresh it */
425 }
426
427 #ifdef HAVE_LIBPORTAUDIO
428 #if GTK_MAJOR_VERSION >= 2
429 /****************************************************************************/
430 static void
431 on_player_bt_clicked                    (GtkButton       *button _U_,
432                                         gpointer         user_data _U_)
433 {
434         rtp_player_init(voip_calls_get_info());
435 }
436 #endif
437 #endif /* HAVE_LIBPORTAUDIO */
438
439 /****************************************************************************/
440 /* when the user selects a row in the calls list */
441 static void
442 voip_calls_on_select_row(GtkCList *clist,
443                                             gint row _U_,
444                                             gint column _U_,
445                                             GdkEventButton *event _U_,
446                                             gpointer user_data _U_)
447 {
448         GdkColor color = COLOR_DEFAULT;
449         gchar label_text[80];
450         
451         selected_call_fwd = gtk_clist_get_row_data(GTK_CLIST(clist), row);
452
453         if (selected_call_fwd==NULL)
454                 return;
455
456         if (!selected_call_fwd->selected)
457                 calls_ns++;
458         else
459                 calls_ns--;
460
461         g_snprintf(label_text, 80,
462                 "Detected %d VoIP %s. Selected %d %s.",
463                 calls_nb, 
464             plurality(calls_nb, "Call", "Calls"),
465                         calls_ns,
466                         plurality(calls_ns, "Call", "Calls"));
467         gtk_label_set(GTK_LABEL(top_label), label_text);
468
469         g_snprintf(label_text, 80, "Selected Call: From  %s  To %s, starting time %i.%i",
470                 selected_call_fwd->from_identity,
471                 selected_call_fwd->to_identity,
472                 selected_call_fwd->start_sec, 
473                 selected_call_fwd->start_usec
474         );
475         gtk_label_set_text(GTK_LABEL(label_fwd), label_text);
476
477         selected_call_fwd->selected=!selected_call_fwd->selected;
478         if (selected_call_fwd->selected)
479                 color = COLOR_SELECT;
480         else
481                 color = COLOR_DEFAULT;
482
483         gtk_clist_set_background(GTK_CLIST(clist), row, &color);
484
485         if      (calls_ns > 0) {
486                 gtk_widget_set_sensitive(bt_filter, TRUE);
487                 gtk_widget_set_sensitive(bt_graph, TRUE);
488 #ifdef HAVE_LIBPORTAUDIO
489 #if GTK_MAJOR_VERSION >= 2
490                 gtk_widget_set_sensitive(bt_player, TRUE);
491 #endif
492 #endif /* HAVE_LIBPORTAUDIO */
493         } else {
494                 gtk_widget_set_sensitive(bt_filter, FALSE);
495                 gtk_widget_set_sensitive(bt_graph, FALSE);
496 #ifdef HAVE_LIBPORTAUDIO
497 #if GTK_MAJOR_VERSION >= 2
498                 gtk_widget_set_sensitive(bt_player, FALSE);
499 #endif
500 #endif /* HAVE_LIBPORTAUDIO */
501         }
502
503         /* TODO: activate other buttons when implemented */
504 }
505
506
507 /****************************************************************************/
508
509 typedef struct column_arrows {
510         GtkWidget *table;
511         GtkWidget *ascend_pm;
512         GtkWidget *descend_pm;
513 } column_arrows;
514
515
516 /****************************************************************************/
517 static void
518 voip_calls_click_column_cb(GtkCList *clist, gint column, gpointer data)
519 {
520         column_arrows *col_arrows = (column_arrows *) data;
521         int i;
522
523         gtk_clist_freeze(clist);
524
525         for (i=0; i<NUM_COLS; i++) {
526                 gtk_widget_hide(col_arrows[i].ascend_pm);
527                 gtk_widget_hide(col_arrows[i].descend_pm);
528         }
529
530         if (column == clist->sort_column) {
531                 if (clist->sort_type == GTK_SORT_ASCENDING) {
532                         clist->sort_type = GTK_SORT_DESCENDING;
533                         gtk_widget_show(col_arrows[column].descend_pm);
534                 } else {
535                         clist->sort_type = GTK_SORT_ASCENDING;
536                         gtk_widget_show(col_arrows[column].ascend_pm);
537                 }
538         } else {
539                 clist->sort_type = GTK_SORT_ASCENDING;
540                 gtk_widget_show(col_arrows[column].ascend_pm);
541                 gtk_clist_set_sort_column(clist, column);
542         }
543         gtk_clist_thaw(clist);
544
545         gtk_clist_sort(clist);
546 }
547
548
549 /****************************************************************************/
550 static gint
551 voip_calls_sort_column(GtkCList *clist, gconstpointer ptr1, gconstpointer ptr2)
552 {
553         char *text1 = NULL;
554         char *text2 = NULL;
555         guint i1, i2, i3, i4;
556
557         const GtkCListRow *row1 = (const GtkCListRow *) ptr1;
558         const GtkCListRow *row2 = (const GtkCListRow *) ptr2;
559
560         text1 = GTK_CELL_TEXT (row1->cell[clist->sort_column])->text;
561         text2 = GTK_CELL_TEXT (row2->cell[clist->sort_column])->text;
562
563         switch(clist->sort_column){
564         case CALL_COL_START_TIME:
565         case CALL_COL_STOP_TIME:
566                 if ((sscanf(text1, "%u.%u", &i1, &i2) != 2) ||
567                         (sscanf(text2, "%u.%u", &i3, &i4) != 2) ){
568                                 return 0;
569                         }
570                 if (i1>i3)
571                         return 1;
572                 if (i1<i3)
573                         return -1;
574                 return (i3-i4);
575         case CALL_COL_INITIAL_SPEAKER:
576         case CALL_COL_FROM:
577         case CALL_COL_TO:
578         case CALL_COL_PROTOCOL:
579         case CALL_COL_STATE:
580         case CALL_COL_COMMENTS:
581                 return strcmp (text1, text2);
582         case CALL_COL_PACKETS:
583                 i1=atoi(text1);
584                 i2=atoi(text2);
585                 return i1-i2;
586         }
587         g_assert_not_reached();
588         return 0;
589 }
590
591
592 /****************************************************************************/
593 /* INTERFACE                                                                */
594 /****************************************************************************/
595
596 static void voip_calls_dlg_create (void)
597 {
598         GtkWidget *voip_calls_dlg_w;
599         GtkWidget *main_vb;
600         GtkWidget *scrolledwindow;
601         GtkWidget *hbuttonbox;
602         GtkWidget *bt_close;
603         GtkTooltips *tooltips = gtk_tooltips_new();
604
605         const gchar *titles[NUM_COLS] =  {"Start Time", "Stop Time", "Initial Speaker", "From",  "To", "Protocol", "Packets", "State", "Comments"};
606         column_arrows *col_arrows;
607         GtkWidget *column_lb;
608         int i;
609
610         voip_calls_dlg_w=window_new(GTK_WINDOW_TOPLEVEL, "Wireshark: VoIP Calls");
611
612         gtk_window_set_default_size(GTK_WINDOW(voip_calls_dlg_w), 840, 350);
613
614         main_vb = gtk_vbox_new (FALSE, 0);
615         gtk_container_add(GTK_CONTAINER(voip_calls_dlg_w), main_vb);
616         gtk_container_set_border_width (GTK_CONTAINER (main_vb), 12);
617
618         top_label = gtk_label_new ("Detected 0 VoIP Calls. Selected 0 Calls.");
619         gtk_box_pack_start (GTK_BOX (main_vb), top_label, FALSE, FALSE, 8);
620
621         scrolledwindow = scrolled_window_new (NULL, NULL);
622         gtk_box_pack_start (GTK_BOX (main_vb), scrolledwindow, TRUE, TRUE, 0);
623
624         clist = gtk_clist_new (NUM_COLS);
625         gtk_container_add (GTK_CONTAINER (scrolledwindow), clist);
626
627         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_START_TIME, 60);
628         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_STOP_TIME, 60);
629         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_INITIAL_SPEAKER, 80);
630         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_FROM, 130);
631         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_TO, 130);
632         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_PROTOCOL, 50);
633         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_PACKETS, 45);
634         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_STATE, 60);
635         gtk_clist_set_column_width (GTK_CLIST (clist), CALL_COL_COMMENTS, 100);
636
637         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_START_TIME, GTK_JUSTIFY_LEFT);
638         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_STOP_TIME, GTK_JUSTIFY_LEFT);
639         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_INITIAL_SPEAKER, GTK_JUSTIFY_LEFT);
640         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_FROM, GTK_JUSTIFY_LEFT);
641         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_TO, GTK_JUSTIFY_LEFT);
642         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_PROTOCOL, GTK_JUSTIFY_CENTER);
643         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_PACKETS, GTK_JUSTIFY_CENTER);
644         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_STATE, GTK_JUSTIFY_LEFT);
645         gtk_clist_set_column_justification(GTK_CLIST(clist), CALL_COL_COMMENTS, GTK_JUSTIFY_LEFT);
646
647         gtk_clist_column_titles_show (GTK_CLIST (clist));
648
649         gtk_clist_set_compare_func(GTK_CLIST(clist), voip_calls_sort_column);
650         gtk_clist_set_sort_column(GTK_CLIST(clist), 0);
651         gtk_clist_set_sort_type(GTK_CLIST(clist), GTK_SORT_ASCENDING);
652
653         gtk_widget_show(voip_calls_dlg_w);
654
655         /* sort by column feature */
656         col_arrows = (column_arrows *) g_malloc(sizeof(column_arrows) * NUM_COLS);
657
658         for (i=0; i<NUM_COLS; i++) {
659                 col_arrows[i].table = gtk_table_new(2, 2, FALSE);
660                 gtk_table_set_col_spacings(GTK_TABLE(col_arrows[i].table), 5);
661                 column_lb = gtk_label_new(titles[i]);
662                 gtk_table_attach(GTK_TABLE(col_arrows[i].table), column_lb, 0, 1, 0, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
663                 gtk_widget_show(column_lb);
664
665                 col_arrows[i].ascend_pm = xpm_to_widget(clist_ascend_xpm);
666                 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].ascend_pm, 1, 2, 1, 2, GTK_SHRINK, GTK_SHRINK, 0, 0);
667                 col_arrows[i].descend_pm = xpm_to_widget(clist_descend_xpm);
668                 gtk_table_attach(GTK_TABLE(col_arrows[i].table), col_arrows[i].descend_pm, 1, 2, 0, 1, GTK_SHRINK, GTK_SHRINK, 0, 0);
669                 /* make start time be the default sort order */
670                 if (i == 0) {
671                         gtk_widget_show(col_arrows[i].ascend_pm);
672                 }
673                 gtk_clist_set_column_widget(GTK_CLIST(clist), i, col_arrows[i].table);
674                 gtk_widget_show(col_arrows[i].table);
675         }
676
677         SIGNAL_CONNECT(clist, "click-column", voip_calls_click_column_cb, col_arrows);
678
679         label_fwd = gtk_label_new (FWD_LABEL_TEXT);
680         gtk_box_pack_start (GTK_BOX (main_vb), label_fwd, FALSE, FALSE, 0);
681
682         status_label = gtk_label_new ("Total: Calls: 0   Start packets: 0   Completed calls: 0   Rejected calls: 0");
683         gtk_box_pack_start (GTK_BOX (main_vb), status_label, FALSE, FALSE, 8);
684
685         /* button row */
686         hbuttonbox = gtk_hbutton_box_new ();
687         gtk_box_pack_start (GTK_BOX (main_vb), hbuttonbox, FALSE, FALSE, 0);
688         gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD);
689         gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 30);
690
691         /*bt_unselect = gtk_button_new_with_label ("Unselect");
692         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_unselect);
693         gtk_tooltips_set_tip (tooltips, bt_unselect, "Unselect this conversation", NULL);*/
694
695         bt_filter = gtk_button_new_with_label ("Prepare Filter");
696         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_filter);
697         gtk_tooltips_set_tip (tooltips, bt_filter, "Prepare a display filter of the selected conversation", NULL);
698
699         bt_graph = gtk_button_new_with_label("Graph");
700         gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_graph);
701         gtk_widget_show(bt_graph);
702         SIGNAL_CONNECT(bt_graph, "clicked", on_graph_bt_clicked, NULL);
703         gtk_tooltips_set_tip (tooltips, bt_graph, "Show a flow graph of the selected calls.", NULL);
704
705 #ifdef HAVE_LIBPORTAUDIO
706 #if GTK_MAJOR_VERSION >= 2
707         bt_player = gtk_button_new_with_label("Player");
708         gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_player);
709         gtk_widget_show(bt_player);
710         SIGNAL_CONNECT(bt_player, "clicked", on_player_bt_clicked, NULL);
711         gtk_tooltips_set_tip (tooltips, bt_player, "Launch the RTP player to listen the selected calls.", NULL);
712 #endif
713 #endif /* HAVE_LIBPORTAUDIO */
714
715         bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
716         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
717         GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
718         gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
719
720         SIGNAL_CONNECT(clist, "select_row", voip_calls_on_select_row, NULL);
721         /*SIGNAL_CONNECT(bt_unselect, "clicked", voip_calls_on_unselect, NULL);*/
722         SIGNAL_CONNECT(bt_filter, "clicked", voip_calls_on_filter, NULL);
723
724         window_set_cancel_button(voip_calls_dlg_w, bt_close, window_cancel_button_cb);
725
726         SIGNAL_CONNECT(voip_calls_dlg_w, "delete_event", window_delete_event_cb, NULL);
727         SIGNAL_CONNECT(voip_calls_dlg_w, "destroy", voip_calls_on_destroy, NULL);
728
729         gtk_widget_show_all(voip_calls_dlg_w);
730         window_present(voip_calls_dlg_w);
731
732         voip_calls_on_unselect(NULL, NULL);
733
734         voip_calls_dlg = voip_calls_dlg_w;
735 }
736
737
738 /****************************************************************************/
739 /* PUBLIC                                                                   */
740 /****************************************************************************/
741
742 /****************************************************************************/
743 /* update the contents of the dialog box clist */
744 /* list: pointer to list of voip_calls_info_t* */
745
746 void voip_calls_dlg_update(GList *list)
747 {
748         gchar label_text[256];
749         if (voip_calls_dlg != NULL) {
750                 calls_nb = 0;
751                 calls_ns = 0;
752
753                 g_snprintf(label_text, 256,
754                         "Total: Calls: %d   Start packets: %d   Completed calls: %d   Rejected calls: %d",
755                         g_list_length(voip_calls_get_info()->strinfo_list),
756                         voip_calls_get_info()->start_packets, 
757                         voip_calls_get_info()->completed_calls,
758                         voip_calls_get_info()->rejected_calls);
759                 gtk_label_set(GTK_LABEL(status_label), label_text);
760
761                 gtk_clist_freeze(GTK_CLIST(clist));
762                 gtk_clist_clear(GTK_CLIST(clist));
763                 list = g_list_first(list);
764                 while (list)
765                 {
766                         add_to_clist((voip_calls_info_t*)(list->data));
767                         list = g_list_next(list);
768                 }
769                 gtk_clist_thaw(GTK_CLIST(clist));
770
771                 g_snprintf(label_text, 256,
772                         "Detected %d VoIP %s. Selected %d %s.",
773                         calls_nb, 
774                         plurality(calls_nb, "Call", "Calls"),
775                         calls_ns,
776                         plurality(calls_ns, "Call", "Calls"));
777                 gtk_label_set(GTK_LABEL(top_label), label_text);
778         }
779
780         last_list = list;
781 }
782
783
784 /****************************************************************************/
785 /* draw function for tap listeners to keep the window up to date */
786 void voip_calls_dlg_draw(void *ptr _U_)
787 {
788         if (voip_calls_get_info()->redraw) {
789                 voip_calls_dlg_update(voip_calls_get_info()->strinfo_list);
790                 voip_calls_get_info()->redraw = FALSE;
791         }
792 }
793
794 /* reset function for tap listeners to clear window, if necessary */
795 void voip_calls_dlg_reset(void *ptr _U_)
796 {
797         /* Clean up memory used by calls tap */
798         voip_calls_reset((voip_calls_tapinfo_t*) voip_calls_get_info());
799
800         /* close the graph window if open */
801         if (graph_analysis_data && graph_analysis_data->dlg.window != NULL) {
802                 window_cancel_button_cb(NULL, graph_analysis_data->dlg.window);
803                 graph_analysis_data->dlg.window = NULL;
804         }
805 }
806
807 /* init function for tap */
808 /* Made extern only for "Fax T38 Analysis..." */
809 void
810 voip_calls_init_tap(const char *dummy _U_, void* userdata _U_)
811 {
812         gint c;
813         gchar *data[NUM_COLS];
814         gchar field[NUM_COLS][50];
815
816         if (graph_analysis_data == NULL) {
817                 graph_analysis_data_init();
818                 /* init the Graph Analysys */
819                 graph_analysis_data = graph_analysis_init();
820                 graph_analysis_data->graph_info = voip_calls_get_info()->graph_analysis;
821         }
822
823         /* Clean up memory used by calls tap */
824         voip_calls_reset((voip_calls_tapinfo_t*) voip_calls_get_info());
825
826         /* Register the tap listener */
827         sip_calls_init_tap();
828         mtp3_calls_init_tap();
829         isup_calls_init_tap();
830         h225_calls_init_tap();
831         h245dg_calls_init_tap();
832         q931_calls_init_tap();
833         h248_calls_init_tap();
834         sccp_calls_init_tap();
835         sdp_calls_init_tap();
836         rtp_init_tap();
837         rtp_event_init_tap();
838         /* We don't register this tap, if we don't have the mgcp plugin loaded.*/
839         if (find_tap_id("mgcp")) {
840                 mgcp_calls_init_tap();
841         }
842         actrace_calls_init_tap();
843         t38_init_tap();
844
845         /* create dialog box if necessary */
846         if (voip_calls_dlg == NULL) {
847                 voip_calls_dlg_create();
848         } else {
849                 /* There's already a dialog box; reactivate it. */
850                 reactivate_window(voip_calls_dlg);
851         }
852
853         voip_calls_get_info()->redraw = TRUE;
854         voip_calls_dlg_draw(NULL);
855         voip_calls_get_info()->redraw = TRUE;
856         for (c=0;c<NUM_COLS;c++){
857                 data[c]=&field[c][0];
858                 field[c][0] = '\0';
859         }
860         g_snprintf(field[3], 50, "Please wait...");
861         gtk_clist_append(GTK_CLIST(clist), data);
862         
863         /* Scan for VoIP calls calls (redissect all packets) */
864         cf_retap_packets(&cfile, FALSE);
865
866         /* Tap listener will be removed and cleaned up in voip_calls_on_destroy */
867 }
868
869
870 /****************************************************************************/
871 /* entry point when called via the GTK menu */
872 static void voip_calls_launch(GtkWidget *w _U_, gpointer data _U_)
873 {
874         voip_calls_init_tap("",NULL);
875 }
876
877 /****************************************************************************/
878 void
879 register_tap_listener_voip_calls_dlg(void)
880 {
881         register_stat_cmd_arg("voip,calls",voip_calls_init_tap,NULL);
882         register_stat_menu_item("VoIP Calls", REGISTER_STAT_GROUP_TELEPHONY,
883             voip_calls_launch, NULL, NULL, NULL);    
884 }