add packet-sdp.h
[obnox/wireshark/wip.git] / gtk / graph_analysis.c
1 /* graph_analysis.c
2  * Graphic Analysis addition for ethereal
3  *
4  * $Id$
5  *
6  * Copyright 2004, Verso Technologies Inc.
7  * By Alejandro Vaquero <alejandrovaquero@yahoo.com>
8  *
9  * based on rtp_analysis.c and io_stat
10  *
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@ethereal.com>
14  * Copyright 1998 Gerald Combs
15  *
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include "graph_analysis.h"
36
37 #include <epan/epan_dissect.h>
38 #include <epan/filesystem.h>
39
40 #include "util.h"
41 #include <epan/tap.h>
42 #include "register.h"
43 #include <epan/dissectors/packet-rtp.h>
44
45 /* in /gtk ... */
46 #include <gtk/gtk.h>
47 #include "gtkglobals.h"
48
49 #include "dlg_utils.h"
50 #include "ui_util.h"
51 #include "alert_box.h"
52 #include "simple_dialog.h"
53 #include "tap_menu.h"
54 #include "main.h"
55 #include "progress_dlg.h"
56 #include "compat_macros.h"
57 #include "../color.h"
58
59 #include "image/clist_ascend.xpm"
60 #include "image/clist_descend.xpm"
61
62 #include <math.h>
63 #include <fcntl.h>
64 #include <string.h>
65
66 #ifdef HAVE_UNISTD_H
67 #include <unistd.h>
68 #endif
69
70 #ifdef HAVE_FCNTL_H
71 #include <fcntl.h>
72 #endif
73
74 #ifdef HAVE_IO_H
75 #include <io.h> /* open/close on win32 */
76 #endif
77
78 /* Win32 needs the O_BINARY flag for open() */
79 #ifndef O_BINARY
80 #define O_BINARY 0
81 #endif
82
83 /****************************************************************************/
84
85
86 #define OK_TEXT "[ Ok ]"
87 #define PT_UNDEFINED -1
88
89
90 #if GTK_MAJOR_VERSION < 2
91 GtkRcStyle *rc_style;
92 GdkColormap *colormap;
93 #endif
94
95 typedef const guint8 * ip_addr_p;
96
97
98 /****************************************************************************/
99 /* Reset the user_data structure */
100 static void graph_analysis_reset(graph_analysis_data_t* user_data)
101 {
102         int i;
103
104         user_data->num_nodes = 0;
105         user_data->num_items = 0;
106         for (i=0; i<MAX_NUM_NODES; i++){
107                 user_data->nodes[i] = 0;
108         }
109         
110         user_data->dlg.first_node=0;
111         user_data->dlg.first_item=0;
112         user_data->dlg.left_x_border=0;
113         user_data->dlg.selected_item=0xFFFFFFFF;    /*not item selected */
114 }
115
116 /****************************************************************************/
117 /* Reset the user_data structure */
118 static void graph_analysis_init_dlg(graph_analysis_data_t* user_data)
119 {
120     /* init dialog_graph */
121     user_data->dlg.needs_redraw=TRUE;
122     user_data->dlg.draw_area=NULL;
123     user_data->dlg.pixmap=NULL;
124     user_data->dlg.h_scrollbar=NULL;
125     user_data->dlg.h_scrollbar_adjustment=NULL;
126     user_data->dlg.v_scrollbar=NULL;
127     user_data->dlg.v_scrollbar_adjustment=NULL;
128     user_data->dlg.pixmap_width=600;
129     user_data->dlg.pixmap_height=400;
130         user_data->dlg.first_node=0;
131         user_data->dlg.first_item=0;
132         user_data->dlg.left_x_border=0;
133         user_data->dlg.selected_item=0xFFFFFFFF;    /*not item selected */
134         user_data->dlg.window=NULL;
135 }
136
137 /****************************************************************************/
138 /* CALLBACKS */
139
140
141 /****************************************************************************/
142 /* close the dialog window and remove the tap listener */
143 static void on_destroy(GtkWidget *win _U_, graph_analysis_data_t *user_data _U_)
144 {
145
146         g_free(user_data);
147 }
148
149
150 /****************************************************************************/
151 static void dialog_graph_set_title(graph_analysis_data_t* user_data)
152 {
153         char            *title;
154         if (!user_data->dlg.window){
155                 return;
156         }
157         title = g_strdup_printf("Ale");
158
159         gtk_window_set_title(GTK_WINDOW(user_data->dlg.window), title);
160         g_free(title);  
161 }
162
163 #define RIGHT_ARROW 1
164 #define LEFT_ARROW 0
165 #define WIDTH_ARROW 8
166 #define HEIGHT_ARROW 6
167
168 /****************************************************************************/
169 static void draw_arrow(GdkDrawable *pixmap, GdkGC *gc, gint x, gint y, gboolean direction)
170 {
171         GdkPoint arrow_point[3];
172
173         arrow_point[0].x = x;
174         arrow_point[0].y = y-HEIGHT_ARROW/2;
175         if (direction == RIGHT_ARROW)
176                 arrow_point[1].x = x+WIDTH_ARROW;
177         else
178                 arrow_point[1].x = x-WIDTH_ARROW;
179         arrow_point[1].y = y;
180         arrow_point[2].x = x;
181         arrow_point[2].y = y+HEIGHT_ARROW/2;;
182
183         gdk_draw_polygon(pixmap, gc, TRUE, 
184                 arrow_point, 3);
185 }
186
187 #define MAX_LABEL 50
188 #define MAX_COMMENT 60
189 #define ITEM_HEIGHT 20
190 #define NODE_WIDTH 100
191 #define TOP_Y_BORDER 40
192 #define BOTTOM_Y_BORDER 0
193 #define COMMENT_WIDTH 250
194
195 /****************************************************************************/
196 static void dialog_graph_draw(graph_analysis_data_t* user_data)
197 {
198         guint32 i, last_item, first_item, last_node, first_node, display_items, display_nodes;
199                 guint32 start_arrow, end_arrow, label_x, src_port_x, dst_port_x, arrow_width;
200         guint32 current_item;
201         guint32 left_x_border;
202         guint32 right_x_border;
203         guint32 top_y_border;
204         guint32 bottom_y_border;
205                 graph_analysis_item_t *gai;
206                 gboolean display_label;
207
208 #if GTK_MAJOR_VERSION < 2
209         GdkFont *font;
210                 FONT_TYPE *big_font;
211                 FONT_TYPE *small_font;
212 #else
213         PangoLayout  *layout;
214         PangoLayout  *big_layout;
215         PangoLayout  *small_layout;
216 #endif
217         guint32 label_width, label_height;
218         guint32 draw_width, draw_height;
219         char label_string[MAX_COMMENT];
220                 GList* list;
221
222         /* new variables */
223
224 #if GTK_MAJOR_VERSION <2
225         font = user_data->dlg.draw_area->style->font;
226                 big_font = gdk_font_load("-adobe-helvetica-bold-r-normal--12-120-75-75-p-70-iso8859-1");
227                 small_font = gdk_font_load("-adobe-helvetica-bold-r-normal--10-120-75-75-p-70-iso8859-1");
228 #endif
229         if(!user_data->dlg.needs_redraw){
230                 return;
231         }
232         user_data->dlg.needs_redraw=FALSE;
233
234         /*
235          * Clear out old plot
236          */
237         gdk_draw_rectangle(user_data->dlg.pixmap,
238                            user_data->dlg.draw_area->style->white_gc,
239                            TRUE,
240                            0, 0,
241                            user_data->dlg.draw_area->allocation.width,
242                            user_data->dlg.draw_area->allocation.height);
243
244                 /* Calculate the y border */
245         top_y_border=TOP_Y_BORDER;      /* to display the node IP address */
246         bottom_y_border=BOTTOM_Y_BORDER;
247
248         draw_height=user_data->dlg.pixmap_height-top_y_border-bottom_y_border;
249
250                 first_item = user_data->dlg.first_item;
251                 display_items = draw_height/ITEM_HEIGHT;
252                 last_item = first_item+display_items-1;
253
254                 /* get the items to display and fill the matrix array */
255                 list = g_list_first(user_data->graph_info->list);
256                 current_item = 0;
257                 i = 0;
258                 while (list)
259                 {
260                         gai = list->data;
261                         if (gai->display){
262                                 if (current_item>=display_items) break;         /* the item is outside the display */
263                                 if (i>=first_item){
264                                         user_data->dlg.items[current_item].frame_num = gai->frame_num;
265                                         user_data->dlg.items[current_item].time = gai->time;
266                                         user_data->dlg.items[current_item].port_src = gai->port_src;
267                                         user_data->dlg.items[current_item].port_dst = gai->port_dst;
268                                         /* Add "..." if the length is 50 characters */
269                                         if (strlen(gai->frame_label) > 48) {
270                                                 gai->frame_label[48] = '.';
271                                                 gai->frame_label[47] = '.';
272                                                 gai->frame_label[46] = '.';
273                                         }
274                                         user_data->dlg.items[current_item].frame_label = gai->frame_label;
275                                         user_data->dlg.items[current_item].comment = gai->comment;
276                                         user_data->dlg.items[current_item].conv_num = gai->conv_num;
277                                         user_data->dlg.items[current_item].src_node = gai->src_node;
278                                         user_data->dlg.items[current_item].dst_node = gai->dst_node;
279                                         user_data->dlg.items[current_item].line_style = gai->line_style;
280                                         current_item++;
281                                 }
282                                 i++;
283                         }
284
285                         list = g_list_next(list);
286                 }
287                 /* in case the windows is resized so we have to move the top item */
288                 if ((first_item + display_items) > user_data->num_items){
289                         if (display_items>user_data->num_items)
290                                 first_item=0;
291                         else
292                                 first_item = user_data->num_items - display_items;
293                 }
294                 
295                 /* in case there are less items than possible displayed */
296                 display_items = current_item;
297                 last_item = first_item+display_items-1;
298
299                 /* if not items to display */
300                 if (display_items == 0) return;                         
301
302
303                 /* Calculate the x borders */
304                 /* We use time from the last display item to calcultate the x left border */
305                 g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[display_items-1].time);
306 #if GTK_MAJOR_VERSION < 2
307         label_width=gdk_string_width(font, label_string);
308         label_height=gdk_string_height(font, label_string);
309 #else
310         layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area, label_string);
311         big_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area, label_string);
312         small_layout = gtk_widget_create_pango_layout(user_data->dlg.draw_area, label_string);
313
314                 pango_layout_set_font_description(big_layout, pango_font_description_from_string("Helvetica-Bold 8"));
315                 pango_layout_set_font_description(small_layout, pango_font_description_from_string("Helvetica-Bold 7"));
316
317         pango_layout_get_pixel_size(layout, &label_width, &label_height);
318 #endif
319         left_x_border=label_width+10;
320                 user_data->dlg.left_x_border = left_x_border;
321
322         right_x_border=COMMENT_WIDTH;
323
324                 /* Calculate the number of nodes to display */
325         draw_width=user_data->dlg.pixmap_width-right_x_border-left_x_border;
326                 display_nodes = draw_width/NODE_WIDTH;
327                 first_node = user_data->dlg.first_node;
328
329                 /* in case the windows is resized so we have to move the left node */
330                 if ((first_node + display_nodes) > user_data->num_nodes){
331                         if (display_nodes>user_data->num_nodes) 
332                                 first_node=0;
333                         else
334                                 first_node=user_data->num_nodes - display_nodes;
335                 }
336
337                 /* in case there are less nodes than possible displayed */
338                 if (display_nodes>user_data->num_nodes) display_nodes=user_data->num_nodes;
339
340                 last_node = first_node + display_nodes-1;
341
342                 /* Paint the background items */ 
343                 for (current_item=0; current_item<display_items; current_item++){
344                         /* Paint background */
345                 gdk_draw_rectangle(user_data->dlg.pixmap,
346                            user_data->dlg.bg_gc[user_data->dlg.items[current_item].conv_num%MAX_NUM_COL_CONV],
347                            TRUE,
348                            left_x_border, 
349                                                    top_y_border+current_item*ITEM_HEIGHT,
350                            draw_width,
351                            ITEM_HEIGHT);
352                 }
353
354
355                 /* Draw the node names on top and the division lines */
356                 for (i=0; i<display_nodes; i++){
357                         /* draw the node IPs */
358                         g_snprintf(label_string, MAX_LABEL, "%s",
359                                 ip_to_str((guint8 *)&(user_data->nodes[i+first_node])));
360 #if GTK_MAJOR_VERSION < 2
361                 label_width=gdk_string_width(font, label_string);
362                 label_height=gdk_string_height(font, label_string);
363                         gdk_draw_string(user_data->dlg.pixmap,
364                 font,
365                 user_data->dlg.draw_area->style->black_gc,
366                 left_x_border+NODE_WIDTH/2-label_width/2+NODE_WIDTH*i,
367                 top_y_border/2-label_height/2,
368                 label_string);
369 #else
370                         pango_layout_set_text(layout, label_string, -1);
371                 pango_layout_get_pixel_size(layout, &label_width, &label_height);
372                 gdk_draw_layout(user_data->dlg.pixmap,
373                 user_data->dlg.draw_area->style->black_gc,
374                 left_x_border+NODE_WIDTH/2-label_width/2+NODE_WIDTH*i,
375                 top_y_border/2-label_height/2,
376                 layout);
377 #endif          
378
379                         /* draw the node division lines */
380                         gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.div_line_gc,
381                                 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
382                                 top_y_border,
383                                 left_x_border+NODE_WIDTH/2+NODE_WIDTH*i,
384                                 user_data->dlg.pixmap_height-bottom_y_border);
385
386                 }
387
388                 /*
389                  * Draw the items 
390                  */
391
392
393                 for (current_item=0; current_item<display_items; current_item++){
394                         /* draw the time */
395                         g_snprintf(label_string, MAX_LABEL, "%.3f", user_data->dlg.items[current_item].time);
396 #if GTK_MAJOR_VERSION < 2
397                 label_width=gdk_string_width(font, label_string);
398                 label_height=gdk_string_height(font, label_string);
399                         gdk_draw_string(user_data->dlg.pixmap,
400                 font,
401                 user_data->dlg.draw_area->style->black_gc,
402                 left_x_border-label_width-4,
403                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4,
404                 label_string);
405 #else
406                         pango_layout_set_text(layout, label_string, -1);
407                 pango_layout_get_pixel_size(layout, &label_width, &label_height);
408                 gdk_draw_layout(user_data->dlg.pixmap,
409                 user_data->dlg.draw_area->style->black_gc,
410                 left_x_border-label_width-4,
411                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
412                 layout);
413 #endif
414
415                         /*draw the comments */
416                         g_snprintf(label_string, MAX_COMMENT, "%s", user_data->dlg.items[current_item].comment);
417 #if GTK_MAJOR_VERSION < 2
418                         label_width=gdk_string_width(small_font, label_string);
419                         label_height=gdk_string_height(small_font, label_string);
420                         gdk_draw_string(user_data->dlg.pixmap,
421                 small_font,
422                 user_data->dlg.draw_area->style->black_gc,
423                 user_data->dlg.pixmap_width-right_x_border+3,
424                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4,
425                 label_string);
426 #else
427                         pango_layout_set_text(small_layout, label_string, -1);
428                         pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
429                 gdk_draw_layout(user_data->dlg.pixmap,
430                 user_data->dlg.draw_area->style->black_gc,
431                 user_data->dlg.pixmap_width-right_x_border+3,
432                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2,
433                 small_layout);
434 #endif
435                         
436                         /* draw the arrow an frame label*/
437                         display_label = FALSE;
438                         if (user_data->dlg.items[current_item].src_node>=first_node){
439                                 if (user_data->dlg.items[current_item].src_node<=last_node){
440                                         start_arrow = left_x_border+(user_data->dlg.items[current_item].src_node-first_node)*NODE_WIDTH+NODE_WIDTH/2;
441                                         display_label = TRUE;
442                                 } else {
443                                         start_arrow = user_data->dlg.pixmap_width - right_x_border;
444                                 }
445                         } else {
446                                 start_arrow = left_x_border;
447                         }
448
449                         if (user_data->dlg.items[current_item].dst_node>=first_node){
450                                 if (user_data->dlg.items[current_item].dst_node<=last_node){
451                                         end_arrow = left_x_border+(user_data->dlg.items[current_item].dst_node-first_node)*NODE_WIDTH+NODE_WIDTH/2;
452                                         display_label = TRUE;
453                                 } else {
454                                         end_arrow = user_data->dlg.pixmap_width - right_x_border;
455                                 }
456                         } else {
457                                 end_arrow = left_x_border;
458                         }
459
460                         if (start_arrow != end_arrow){
461                                 /* draw the arrow line */
462                                 gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc,
463                                         start_arrow,
464                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7,
465                                         end_arrow,
466                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7);
467
468                                 /* draw the additional line when line style is 2 pixels width */
469                                 if (user_data->dlg.items[current_item].line_style == 2){
470                                         gdk_draw_line(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc,
471                                                 start_arrow,
472                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6,
473                                                 end_arrow,
474                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-6);
475                                 }                                       
476
477                                 /* draw the arrow */
478                                 if (start_arrow<end_arrow)
479                                         draw_arrow(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc, end_arrow-WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, RIGHT_ARROW);
480                                 else
481                                         draw_arrow(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc, end_arrow+WIDTH_ARROW,top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-7, LEFT_ARROW);
482                         }
483
484                         /* draw the frame comment */
485                         if (display_label){
486                                 g_snprintf(label_string, MAX_LABEL, "%s", user_data->dlg.items[current_item].frame_label);
487 #if GTK_MAJOR_VERSION < 2
488                                 label_width=gdk_string_width(big_font, label_string);
489                                 label_height=gdk_string_height(big_font, label_string);
490 #else
491                                 pango_layout_set_text(big_layout, label_string, -1);
492                                 pango_layout_get_pixel_size(big_layout, &label_width, &label_height);
493 #endif
494
495                                 if (start_arrow<end_arrow){
496                                         arrow_width = end_arrow-start_arrow;
497                                         label_x = arrow_width/2+start_arrow;
498                                 }
499                                 else {
500                                         arrow_width = start_arrow-end_arrow;
501                                         label_x = arrow_width/2+end_arrow;
502                                 }
503
504                                 if (label_width>arrow_width) arrow_width = label_width;
505
506                                 if (left_x_border > (label_x-label_width/2)) label_x = left_x_border + label_width/2;
507
508                                 if ((user_data->dlg.pixmap_width - right_x_border) < (label_x+label_width/2)) label_x = user_data->dlg.pixmap_width - right_x_border - label_width/2;
509
510 #if GTK_MAJOR_VERSION < 2
511                                 gdk_draw_string(user_data->dlg.pixmap,
512                                         big_font,
513                                         user_data->dlg.draw_area->style->black_gc,
514                                         label_x - label_width/2,
515                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2+label_height/4-3,
516                                         label_string);
517 #else
518                                 gdk_draw_layout(user_data->dlg.pixmap,
519                                         user_data->dlg.draw_area->style->black_gc,
520                                         label_x - label_width/2,
521                                         top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT/2-label_height/2-3,
522                                         big_layout);
523 #endif
524
525                                 /* draw the source port number */
526                                 if ((start_arrow != left_x_border) && (start_arrow != (user_data->dlg.pixmap_width - right_x_border))){ 
527                                         g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_src);
528 #if GTK_MAJOR_VERSION < 2
529                                         label_width=gdk_string_width(small_font, label_string);
530                                         label_height=gdk_string_height(small_font, label_string);
531 #else
532                                         pango_layout_set_text(small_layout, label_string, -1);
533                                         pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
534 #endif
535                                         if (start_arrow<end_arrow){
536                                                 src_port_x = start_arrow - label_width - 2;
537                                         }
538                                         else {
539                                                 src_port_x = start_arrow + 2;
540                                         }
541 #if GTK_MAJOR_VERSION < 2
542                                         gdk_draw_string(user_data->dlg.pixmap,
543                                                 small_font,
544                                                 user_data->dlg.div_line_gc,
545                                                 src_port_x,
546                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2+label_height/4-2,
547                                                 label_string);
548 #else
549                                         gdk_draw_layout(user_data->dlg.pixmap,
550                                                 user_data->dlg.div_line_gc,
551                                                 src_port_x,
552                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
553                                                 small_layout);
554 #endif
555                                 }
556
557                                 /* draw the destination port number */
558                                 if ((end_arrow != left_x_border) && (end_arrow != (user_data->dlg.pixmap_width - right_x_border))){ 
559                                         g_snprintf(label_string, MAX_LABEL, "(%i)", user_data->dlg.items[current_item].port_dst);
560 #if GTK_MAJOR_VERSION < 2
561                                         label_width=gdk_string_width(small_font, label_string);
562                                         label_height=gdk_string_height(small_font, label_string);
563 #else
564                                         pango_layout_set_text(small_layout, label_string, -1);
565                                         pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
566 #endif
567                                         if (start_arrow<end_arrow){
568                                                 dst_port_x = end_arrow + 2;
569                                         }
570                                         else {
571                                                 dst_port_x = end_arrow - label_width - 2;
572                                         }
573 #if GTK_MAJOR_VERSION < 2
574                                         gdk_draw_string(user_data->dlg.pixmap,
575                                                 small_font,
576                                                 user_data->dlg.div_line_gc,
577                                                 dst_port_x,
578                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2+label_height/4-2,
579                                                 label_string);
580 #else
581                                         gdk_draw_layout(user_data->dlg.pixmap,
582                                                 user_data->dlg.div_line_gc,
583                                                 dst_port_x,
584                                                 top_y_border+current_item*ITEM_HEIGHT+ITEM_HEIGHT-2-label_height/2-2,
585                                                 small_layout);
586 #endif
587                                 }
588
589                         }
590                 }
591
592 #if GTK_MAJOR_VERSION >= 2
593         g_object_unref(G_OBJECT(layout));
594 #endif
595
596                 /* draw the border on the selected item */
597                 if ( (user_data->dlg.selected_item != 0xFFFFFFFF) && ( (user_data->dlg.selected_item>=first_item) && (user_data->dlg.selected_item<=last_item) )){
598                         gdk_draw_rectangle(user_data->dlg.pixmap, user_data->dlg.draw_area->style->black_gc,
599                                 FALSE,
600                                 left_x_border-1,
601                                 (user_data->dlg.selected_item-first_item)*ITEM_HEIGHT+TOP_Y_BORDER,
602                                 user_data->dlg.pixmap_width-COMMENT_WIDTH-left_x_border+1,
603                                 ITEM_HEIGHT);
604                 }
605
606
607
608         gdk_draw_pixmap(user_data->dlg.draw_area->window,
609                         user_data->dlg.draw_area->style->fg_gc[GTK_WIDGET_STATE(user_data->dlg.draw_area)],
610                         user_data->dlg.pixmap,
611                         0, 0,
612                         0, 0,
613                         user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
614
615
616         /* update the h_scrollbar */
617         user_data->dlg.h_scrollbar_adjustment->upper=(gfloat) user_data->num_nodes-1;
618         user_data->dlg.h_scrollbar_adjustment->step_increment=1;
619         user_data->dlg.h_scrollbar_adjustment->page_increment=(gfloat) (last_node-first_node);
620         user_data->dlg.h_scrollbar_adjustment->page_size=(gfloat) (last_node-first_node);
621         user_data->dlg.h_scrollbar_adjustment->value=(gfloat) first_node;
622
623                 gtk_adjustment_changed(user_data->dlg.h_scrollbar_adjustment);
624         gtk_adjustment_value_changed(user_data->dlg.h_scrollbar_adjustment);
625
626         /* update the v_scrollbar */
627         user_data->dlg.v_scrollbar_adjustment->upper=(gfloat) user_data->num_items-1;
628         user_data->dlg.v_scrollbar_adjustment->step_increment=1;
629         user_data->dlg.v_scrollbar_adjustment->page_increment=(gfloat) (last_item-first_item);
630         user_data->dlg.v_scrollbar_adjustment->page_size=(gfloat) (last_item-first_item);
631         user_data->dlg.v_scrollbar_adjustment->value=(gfloat) first_item;
632
633                 gtk_adjustment_changed(user_data->dlg.v_scrollbar_adjustment);
634         gtk_adjustment_value_changed(user_data->dlg.v_scrollbar_adjustment);
635
636 }
637
638 /****************************************************************************/
639 static void dialog_graph_redraw(graph_analysis_data_t* user_data)
640 {
641         user_data->dlg.needs_redraw=TRUE;
642         dialog_graph_draw(user_data); 
643 }
644
645 /****************************************************************************/
646 static gint quit(GtkWidget *widget, GdkEventExpose *event _U_)
647 {
648         graph_analysis_data_t *user_data;
649
650         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
651
652                 user_data->dlg.window = NULL;
653
654                 user_data = NULL;
655         return TRUE;
656 }
657
658 /****************************************************************************/
659 static gint button_press_event(GtkWidget *widget, GdkEventButton *event _U_)
660 {
661         graph_analysis_data_t *user_data;
662                 guint32 item;
663
664         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
665
666                 if (event->type != GDK_BUTTON_PRESS) return TRUE;
667
668                 if (event->y<TOP_Y_BORDER) return TRUE;
669
670                 /* get the item clicked */
671                 item = ((guint32)event->y - TOP_Y_BORDER) / ITEM_HEIGHT;
672                 user_data->dlg.selected_item = item + user_data->dlg.first_item;
673
674                 user_data->dlg.needs_redraw=TRUE;
675                 dialog_graph_draw(user_data);
676
677                 goto_frame(&cfile, user_data->dlg.items[item].frame_num);
678
679         return TRUE;
680 }
681
682 /****************************************************************************/
683 static gint expose_event(GtkWidget *widget, GdkEventExpose *event)
684 {
685         graph_analysis_data_t *user_data;
686
687         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
688         if(!user_data){
689                 exit(10);
690         }
691
692
693         gdk_draw_pixmap(widget->window,
694                         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
695                         user_data->dlg.pixmap,
696                         event->area.x, event->area.y,
697                         event->area.x, event->area.y,
698                         event->area.width, event->area.height);
699
700         return FALSE;
701 }
702
703 static const GdkColor COLOR_GRAY = {0, 0x7fff, 0x7fff, 0x7fff};
704
705 /****************************************************************************/
706 static gint configure_event(GtkWidget *widget, GdkEventConfigure *event _U_)
707 {
708         graph_analysis_data_t *user_data;
709                 int i;
710                 GdkColor color_div_line = COLOR_GRAY;
711
712                 static GdkColor col[MAX_NUM_COL_CONV] = {
713                 {0,     0x00FF, 0xFFFF, 0x00FF},
714                 {0,     0xFFFF, 0xFFFF, 0x00FF},
715                 {0,     0xFFFF, 0x00FF, 0x00FF},
716                 {0,     0xFFFF, 0x00FF, 0xFFFF},
717                         {0,     0x00FF, 0x00FF, 0xFFFF},
718                         {0,     0x00FF, 0xFFFF, 0xFFFF},
719                         {0,     0xFFFF, 0x80FF, 0x00FF},
720                         {0,     0x80FF, 0x00FF, 0xFFFF},
721                         {0,     0x00FF, 0x80FF, 0xFFFF},
722                         {0,     0xFFFF, 0x00FF, 0x80FF}
723                 };
724
725         user_data=(graph_analysis_data_t *)OBJECT_GET_DATA(widget, "graph_analysis_data_t");
726
727         if(!user_data){
728                 exit(10);
729         }
730
731         if(user_data->dlg.pixmap){
732                 gdk_pixmap_unref(user_data->dlg.pixmap);
733                 user_data->dlg.pixmap=NULL;
734         }
735
736         user_data->dlg.pixmap=gdk_pixmap_new(widget->window,
737                         widget->allocation.width,
738                         widget->allocation.height,
739                         -1);
740         user_data->dlg.pixmap_width=widget->allocation.width;
741         user_data->dlg.pixmap_height=widget->allocation.height;
742
743         gdk_draw_rectangle(user_data->dlg.pixmap,
744                         widget->style->white_gc,
745                         TRUE,
746                         0, 0,
747                         widget->allocation.width,
748                         widget->allocation.height);
749
750                 /* create gc for division lines and set the line stype to dash*/
751                 user_data->dlg.div_line_gc=gdk_gc_new(user_data->dlg.pixmap);
752                 gdk_gc_set_line_attributes(user_data->dlg.div_line_gc, 1, GDK_LINE_ON_OFF_DASH, 0, 0);
753 #if GTK_MAJOR_VERSION < 2
754         colormap = gtk_widget_get_colormap (widget);
755         if (!gdk_color_alloc (colormap, &color_div_line)){
756                      g_warning ("Couldn't allocate color");
757         }
758         gdk_gc_set_foreground(user_data->dlg.div_line_gc, &color_div_line);
759 #else
760         gdk_gc_set_rgb_fg_color(user_data->dlg.div_line_gc, &color_div_line);
761 #endif
762         
763                 /* create gcs for the background items */
764
765                 for (i=0; i<MAX_NUM_COL_CONV; i++){
766                         user_data->dlg.bg_gc[i]=gdk_gc_new(user_data->dlg.pixmap);
767 #if GTK_MAJOR_VERSION < 2
768                         colormap = gtk_widget_get_colormap (widget);
769                         if (!gdk_color_alloc (colormap, &col[i])){
770                                                  g_warning ("Couldn't allocate color");
771                         }
772                         gdk_gc_set_foreground(user_data->dlg.bg_gc[i], &col[i]);
773 #else
774                 gdk_gc_set_rgb_fg_color(user_data->dlg.bg_gc[i], &col[i]);
775 #endif
776                 }
777
778         dialog_graph_redraw(user_data);
779         return TRUE;
780 }
781
782 /****************************************************************************/
783 static gint h_scrollbar_changed(GtkWidget *widget _U_, gpointer data)
784 {
785     graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
786
787         if ((user_data->dlg.first_node+user_data->dlg.h_scrollbar_adjustment->page_size+1 == user_data->num_nodes) 
788                 && (user_data->dlg.h_scrollbar_adjustment->value >= user_data->dlg.first_node ))
789                 return TRUE;
790
791         if (user_data->dlg.first_node == (guint16) user_data->dlg.h_scrollbar_adjustment->value)
792                 return TRUE;
793
794     user_data->dlg.first_node = (guint16) user_data->dlg.h_scrollbar_adjustment->value;
795
796         dialog_graph_redraw(user_data);
797     return TRUE;
798 }
799
800 /****************************************************************************/
801 static gint v_scrollbar_changed(GtkWidget *widget _U_, gpointer data)
802 {
803     graph_analysis_data_t *user_data=(graph_analysis_data_t *)data;
804         if ((user_data->dlg.first_item+user_data->dlg.v_scrollbar_adjustment->page_size+1 == user_data->num_items) 
805                 && (user_data->dlg.v_scrollbar_adjustment->value >= user_data->dlg.first_item ))
806                 return TRUE;
807
808         if (user_data->dlg.first_item == user_data->dlg.v_scrollbar_adjustment->value)
809                 return TRUE;
810                 
811     user_data->dlg.first_item = (guint32) user_data->dlg.v_scrollbar_adjustment->value;
812
813         dialog_graph_redraw(user_data);
814     return TRUE;
815 }
816
817 /****************************************************************************/
818 static void create_draw_area(graph_analysis_data_t* user_data, GtkWidget *box)
819 {
820             GtkWidget *vbox;
821         GtkWidget *hbox;
822
823         hbox=gtk_hbox_new(FALSE, 0);
824         gtk_widget_show(hbox);
825
826         vbox=gtk_vbox_new(FALSE, 0);
827         gtk_widget_show(vbox);
828
829
830         user_data->dlg.draw_area=gtk_drawing_area_new();
831         SIGNAL_CONNECT(user_data->dlg.draw_area, "destroy", quit, user_data);
832         OBJECT_SET_DATA(user_data->dlg.draw_area, "graph_analysis_data_t", user_data);
833
834         WIDGET_SET_SIZE(user_data->dlg.draw_area, user_data->dlg.pixmap_width, user_data->dlg.pixmap_height);
835
836         /* signals needed to handle backing pixmap */
837         SIGNAL_CONNECT(user_data->dlg.draw_area, "expose_event", expose_event, NULL);
838         SIGNAL_CONNECT(user_data->dlg.draw_area, "configure_event", configure_event, user_data);
839
840                 gtk_widget_add_events (user_data->dlg.draw_area,
841                          GDK_BUTTON_PRESS_MASK);
842                 SIGNAL_CONNECT(user_data->dlg.draw_area, "button_press_event", button_press_event, user_data);
843
844         gtk_widget_show(user_data->dlg.draw_area);
845         gtk_box_pack_start(GTK_BOX(vbox), user_data->dlg.draw_area, TRUE, TRUE, 0);
846
847         /* create the associated h_scrollbar */
848         user_data->dlg.h_scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
849         user_data->dlg.h_scrollbar=gtk_hscrollbar_new(user_data->dlg.h_scrollbar_adjustment);
850         gtk_widget_show(user_data->dlg.h_scrollbar);
851         gtk_box_pack_end(GTK_BOX(vbox), user_data->dlg.h_scrollbar, FALSE, FALSE, 0);
852         SIGNAL_CONNECT(user_data->dlg.h_scrollbar_adjustment, "value_changed", h_scrollbar_changed, user_data);
853
854         gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
855
856        /* create the associated v_scrollbar */
857         user_data->dlg.v_scrollbar_adjustment=(GtkAdjustment *)gtk_adjustment_new(0,0,0,0,0,0);
858         user_data->dlg.v_scrollbar=gtk_vscrollbar_new(user_data->dlg.v_scrollbar_adjustment);
859         gtk_widget_show(user_data->dlg.v_scrollbar);
860         gtk_box_pack_end(GTK_BOX(hbox), user_data->dlg.v_scrollbar, FALSE, FALSE, 0);
861                 SIGNAL_CONNECT(user_data->dlg.v_scrollbar_adjustment, "value_changed", v_scrollbar_changed, user_data);
862
863         gtk_box_pack_start(GTK_BOX(box), hbox, TRUE, TRUE, 0);
864 }
865
866
867 /****************************************************************************/
868 static void dialog_graph_create_window(graph_analysis_data_t* user_data)
869 {
870         GtkWidget *vbox;
871         GtkWidget *hbox;
872         GtkWidget *bt_close;
873                 GtkWidget *label = NULL;
874
875         /* create the main window */
876         user_data->dlg.window=window_new(GTK_WINDOW_TOPLEVEL, "Graph Analysis");
877
878
879         vbox=gtk_vbox_new(FALSE, 0);
880         gtk_container_add(GTK_CONTAINER(user_data->dlg.window), vbox);
881         gtk_widget_show(vbox);
882
883         create_draw_area(user_data, vbox);
884
885             hbox = dlg_button_row_new(GTK_STOCK_CLOSE, NULL);
886         gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
887                 gtk_widget_show(hbox);
888
889                 bt_close = OBJECT_GET_DATA(hbox, GTK_STOCK_CLOSE);
890                 window_set_cancel_button(user_data->dlg.window, bt_close, window_cancel_button_cb);
891
892                 SIGNAL_CONNECT(user_data->dlg.window, "delete_event", window_delete_event_cb, NULL);
893
894             gtk_widget_show(user_data->dlg.window);
895             window_present(user_data->dlg.window);
896 }
897
898 /* Return the index array if the node is in the array. Return -1 if there is room in the array
899  * and Return -2 if the array is full
900  */
901 /****************************************************************************/
902 gint is_node_array(graph_analysis_data_t* user_data, guint32 node)
903 {
904         int i;
905         for (i=0; i<MAX_NUM_NODES; i++){
906                 if (user_data->nodes[i] == 0)   return -1;      /* it is not in the array */
907                 if (user_data->nodes[i] == node) return i;      /* it is in the array */
908         }
909         return -2;              /* array full */
910 }
911
912
913 /* Get the nodes (IPs) from the list */
914 /****************************************************************************/
915 void get_nodes(graph_analysis_data_t* user_data)
916 {
917         GList* list;
918         graph_analysis_item_t *gai;
919         gint index;
920
921         /* fill the node array */
922         list = g_list_first(user_data->graph_info->list);
923         while (list)
924         {
925                 gai = list->data;
926                 if (gai->display){
927                         user_data->num_items++;
928                         /* check source IP node */
929                         index = is_node_array(user_data, gai->ip_src);
930                         switch(index){
931                                 case -2: /* array full */
932                                         gai->src_node = NODE_OVERFLOW;
933                                         break;
934                                 case -1: /* not in array */
935                                         user_data->nodes[user_data->num_nodes] = gai->ip_src;
936                                         gai->src_node = user_data->num_nodes;
937                                         user_data->num_nodes++;
938                                         break;
939                                 default: /* it is in the array, just update the src_node */
940                                         gai->src_node = (guint16)index;
941                         }
942
943                         /* check destination  IP node */
944                         index = is_node_array(user_data, gai->ip_dst);
945                         switch(index){
946                                 case -2: /* array full */
947                                         gai->dst_node = NODE_OVERFLOW;
948                                         break;
949                                 case -1: /* not in array */
950                                         user_data->nodes[user_data->num_nodes] = gai->ip_dst;
951                                         gai->dst_node = user_data->num_nodes;
952                                         user_data->num_nodes++;
953                                         break;
954                                 default: /* it is in the array, just update the dst_node */
955                                         gai->dst_node = (guint16)index;
956                         }
957                 }
958
959                 list = g_list_next(list);
960         }
961 }
962
963 /****************************************************************************/
964 /* XXX only handles IPv4, should add IPv6 support */
965 graph_analysis_data_t* graph_analysis_init()
966 {
967         graph_analysis_data_t* user_data;
968         /* init */
969         user_data = g_malloc(sizeof(graph_analysis_data_t));
970
971         /* init user_data */
972         graph_analysis_init_dlg(user_data);
973
974         return user_data;
975 }
976
977 /****************************************************************************/
978 void graph_analysis_create(graph_analysis_data_t* user_data)
979 {
980         /* reset the data */
981         graph_analysis_reset(user_data);
982
983         /* get nodes (each node is an IP address) */
984         get_nodes(user_data);
985
986         /* create the graph windows */
987         dialog_graph_create_window(user_data);
988
989         /* redraw the graph */
990         dialog_graph_redraw(user_data); 
991
992         return;
993 }
994
995 /****************************************************************************/
996 void graph_analysis_update(graph_analysis_data_t* user_data)
997 {
998         /* reset the data */
999         graph_analysis_reset(user_data);
1000
1001         /* get nodes (each node is an IP address) */
1002         get_nodes(user_data);
1003
1004         /* redraw the graph */
1005         dialog_graph_redraw(user_data); 
1006
1007     window_present(user_data->dlg.window);
1008         return;
1009 }