calltree.c 49.4 KB
Newer Older
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
1 2
/*
 *  Copyright (C) 2007 Savoir-Faire Linux inc.
3
 *  Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com>
4
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
5
 *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
Emmanuel Milou's avatar
Emmanuel Milou committed
6
 *
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
7 8
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 3 of the License, or
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
10
 *  (at your option) any later version.
Emmanuel Milou's avatar
Emmanuel Milou committed
11
 *
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
12 13 14 15
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
Emmanuel Milou's avatar
Emmanuel Milou committed
16
 *
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
17 18 19 20 21
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

Julien Bonjean's avatar
Julien Bonjean committed
22
#include <calltree.h>
23
#include <stdlib.h>
24
#include <glib/gprintf.h>
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
25
#include <calllist.h>
26
#include <conferencelist.h>
27
#include <mainwindow.h>
Alexandre Savard's avatar
Alexandre Savard committed
28
#include <history.h>
29 30 31 32 33 34

GtkWidget *sw;
GtkCellRenderer *rend;
GtkTreeViewColumn *col;
GtkTreeSelection *sel;

35 36 37 38 39
gint dragged_type;
gint selected_type;

gchar *dragged_call_id;
gchar *selected_call_id;
40

41 42
gchar *dragged_path;
gchar *selected_path;
43

44 45
gint dragged_path_depth;
gint selected_path_depth;
46

47
callable_obj_t *dragged_call;
48
callable_obj_t *selected_call;
49

50 51 52
conference_obj_t *dragged_conf;
conference_obj_t *selected_conf;

53 54

static void drag_begin_cb(GtkWidget *widget, GdkDragContext *dc, gpointer data);
55
static void drag_end_cb(GtkWidget * mblist, GdkDragContext * context, gpointer data);
56 57 58
void drag_data_received_cb(GtkWidget *widget, GdkDragContext *dc, gint x, gint y, GtkSelectionData *selection_data, guint info, guint t, gpointer data);


59
enum {
60 61 62 63
	COLUMN_ACCOUNT_STATE = 0,
	COLUMN_ACCOUNT_DESC,
	COLUMN_ACCOUNT_SECURITY,
	COLUMN_ACCOUNT_PTR,
64
};
65

66

67 68 69
/**
 * Show popup menu
 */
70
	static gboolean
71
popup_menu (GtkWidget *widget,
72
		gpointer   user_data UNUSED)
73
{
74 75
	show_popup_menu(widget, NULL);
	return TRUE;
Emmanuel Milou's avatar
Emmanuel Milou committed
76
}
Emmanuel Milou's avatar
Emmanuel Milou committed
77

78
/* Call back when the user click on a call in the list */
79
	static void
80
call_selected_cb(GtkTreeSelection *sel, void* data UNUSED )
81
{
82

83
    DEBUG("CallTree: Selection callback");
84

Alexandre Savard's avatar
Alexandre Savard committed
85 86 87 88 89 90
    GtkTreeIter iter;
    GValue val;
    GtkTreeModel *model = (GtkTreeModel*)active_calltree->store;
    
    GtkTreePath* path;
    gchar* string_path;
91

92

93
    if (! gtk_tree_selection_get_selected (sel, &model, &iter)) {
Alexandre Savard's avatar
Alexandre Savard committed
94
        return;
95
    }
96

Alexandre Savard's avatar
Alexandre Savard committed
97 98 99 100
    // store info for dragndrop
    path = gtk_tree_model_get_path(model, &iter);
    string_path = gtk_tree_path_to_string(path);
    selected_path_depth = gtk_tree_path_get_depth(path);
101

Alexandre Savard's avatar
Alexandre Savard committed
102
    if(gtk_tree_model_iter_has_child(GTK_TREE_MODEL(model), &iter)) {
103

104
        DEBUG("CallTree: Selected a conference");
Alexandre Savard's avatar
Alexandre Savard committed
105
	selected_type = A_CONFERENCE;
Alexandre Savard's avatar
Alexandre Savard committed
106

Alexandre Savard's avatar
Alexandre Savard committed
107 108
	val.g_type = 0;
	gtk_tree_model_get_value (model, &iter, COLUMN_ACCOUNT_PTR, &val);
109

Alexandre Savard's avatar
Alexandre Savard committed
110
	calltab_select_conf((conference_obj_t*) g_value_get_pointer(&val));
111

Alexandre Savard's avatar
Alexandre Savard committed
112
	selected_conf = (conference_obj_t*)g_value_get_pointer(&val);
113

Alexandre Savard's avatar
Alexandre Savard committed
114
	if(selected_conf) {
115

Alexandre Savard's avatar
Alexandre Savard committed
116 117 118
	    selected_call_id = selected_conf->_confID;
	    selected_path = string_path;
	    selected_call = NULL;
119

120
	}
121

122 123
	DEBUG("CallTree: selected_path %s, selected_call_id %s, selected_path_depth %d", 
	                          selected_path, selected_call_id, selected_path_depth);
124

Alexandre Savard's avatar
Alexandre Savard committed
125 126 127
    }
    else {
      
128
        DEBUG("CallTree: Selected a call");
Alexandre Savard's avatar
Alexandre Savard committed
129
	selected_type = A_CALL;
130

Alexandre Savard's avatar
Alexandre Savard committed
131 132 133 134 135 136
	val.g_type = 0;
	gtk_tree_model_get_value (model, &iter, COLUMN_ACCOUNT_PTR, &val);
	
	calltab_select_call(active_calltree, (callable_obj_t*) g_value_get_pointer(&val));
	
	selected_call = (callable_obj_t*)g_value_get_pointer(&val);
137

Alexandre Savard's avatar
Alexandre Savard committed
138
	if(selected_call) {
139

Alexandre Savard's avatar
Alexandre Savard committed
140 141 142
	    selected_call_id = selected_call->_callID;
	    selected_path = string_path;
	    selected_conf = NULL;
143
	}
144

145 146
	DEBUG("CallTree: selected_path %s, selected_call_id %s, selected_path_depth %d", 
	                            selected_path, selected_call_id, selected_path_depth);
Alexandre Savard's avatar
Alexandre Savard committed
147
    }
148

Alexandre Savard's avatar
Alexandre Savard committed
149 150
    g_value_unset(&val);
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
151 152
}

153
/* A row is activated when it is double clicked */
154
	void 
155
row_activated(GtkTreeView       *tree_view UNUSED,
156 157
		GtkTreePath       *path UNUSED,
		GtkTreeViewColumn *column UNUSED,
Alexandre Savard's avatar
Alexandre Savard committed
158 159 160 161 162 163
		void * data UNUSED) {
    callable_obj_t* selectedCall = NULL;
    callable_obj_t* new_call;
    conference_obj_t* selectedConf = NULL;
    gchar *account_id;
	
164
    DEBUG("CallTree: Double click action");
Alexandre Savard's avatar
Alexandre Savard committed
165 166 167 168
    
    if(calltab_get_selected_type(active_calltree) == A_CALL) {
      
	selectedCall = calltab_get_selected_call(active_calltree);
169

Alexandre Savard's avatar
Alexandre Savard committed
170
	if (selectedCall) {
171 172
	    DEBUG("CallTree: Selected a call");
	    
Alexandre Savard's avatar
Alexandre Savard committed
173 174
	    // Get the right event from the right calltree
	    if( active_calltree == current_calls ) {
175

176
	      DEBUG("CallTree: Active tree is current calls");
Alexandre Savard's avatar
Alexandre Savard committed
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
	      
	      switch(selectedCall->_state) {
	      case CALL_STATE_INCOMING:
		  dbus_accept(selectedCall);
		  stop_notification();
		  break;
	      case CALL_STATE_HOLD:
		  dbus_unhold(selectedCall);
		  break;
	      case CALL_STATE_RINGING:
	      case CALL_STATE_CURRENT:
	      case CALL_STATE_BUSY:
	      case CALL_STATE_FAILURE:
		  break;
	      case CALL_STATE_DIALING:
		  sflphone_place_call (selectedCall);
		  break;
	      default:
		  WARN("Row activated - Should not happen!");
		  break;
	      }
	    }
199
		
Alexandre Savard's avatar
Alexandre Savard committed
200 201 202
	    // If history or contact: double click action places a new call
	    else {

203
	        DEBUG("CallTree: Active tree is history or contact");
204

Alexandre Savard's avatar
Alexandre Savard committed
205
		account_id = g_strdup (selectedCall->_accountID);
206
		      
Alexandre Savard's avatar
Alexandre Savard committed
207 208
		// Create a new call
		create_new_call (CALL, CALL_STATE_DIALING, "", account_id, selectedCall->_peer_name, selectedCall->_peer_number, &new_call);
209

Alexandre Savard's avatar
Alexandre Savard committed
210 211 212 213
		calllist_add(current_calls, new_call);
		calltree_add_call(current_calls, new_call, NULL);
		sflphone_place_call(new_call);
		calltree_display(current_calls);
214
	    }
215
	}
Alexandre Savard's avatar
Alexandre Savard committed
216 217
    }
    else if(calltab_get_selected_type(current_calls) == A_CONFERENCE) {
218

219
        DEBUG("CallTree: Selected a conference");
Alexandre Savard's avatar
Alexandre Savard committed
220 221
	    
	if( active_calltree == current_calls ) {
222

Alexandre Savard's avatar
Alexandre Savard committed
223
	    selectedConf = calltab_get_selected_conf(current_calls);
224

Alexandre Savard's avatar
Alexandre Savard committed
225 226 227 228 229 230 231 232 233 234 235 236
	    if(selectedConf) {

	        switch(selectedConf->_state) {
		case CONFERENCE_STATE_ACTIVE_ATACHED:
		    // sflphone_add_main_participant(selectedConf);
		    break;
		case CONFERENCE_STATE_ACTIVE_DETACHED:
		    sflphone_add_main_participant(selectedConf);
		    break;
		case CONFERENCE_STATE_HOLD:
		    sflphone_conference_off_hold(selectedConf);
		    break;
237
		}
Alexandre Savard's avatar
Alexandre Savard committed
238
	    }
239
	}
Alexandre Savard's avatar
Alexandre Savard committed
240
    }
241
}
242

243

244
/* Catch cursor-activated signal. That is, when the entry is single clicked */
245
	void  
246
row_single_click(GtkTreeView *tree_view UNUSED, void * data UNUSED)
247
{
248 249
    callable_obj_t * selectedCall = NULL;
    account_t * account_details = NULL;
Alexandre Savard's avatar
Alexandre Savard committed
250
    gchar * displaySasOnce="";
251

252 253
    DEBUG("CallTree: Single click action");

Alexandre Savard's avatar
Alexandre Savard committed
254
    selectedCall = calltab_get_selected_call( active_calltree );
255

256 257 258 259 260 261 262
    /*
    if(!selected_call) {
      selected_call = selectedCall;
    }
    */

    if (selectedCall) {
263

Alexandre Savard's avatar
Alexandre Savard committed
264 265
        account_details = account_list_get_by_id(selectedCall->_accountID);
	DEBUG("AccountID %s", selectedCall->_accountID);
266

Alexandre Savard's avatar
Alexandre Savard committed
267 268 269 270 271 272 273 274 275 276
	if(account_details != NULL) {
	    displaySasOnce = g_hash_table_lookup(account_details->properties, ACCOUNT_DISPLAY_SAS_ONCE);
	    DEBUG("Display SAS once %s", displaySasOnce);
	}
	else {
	    GHashTable * properties = NULL;
	    sflphone_get_ip2ip_properties (&properties);
	    if(properties != NULL)
	      { displaySasOnce = g_hash_table_lookup(properties, ACCOUNT_DISPLAY_SAS_ONCE); DEBUG("IP2IP displaysasonce %s", displaySasOnce); }
	}
277

Alexandre Savard's avatar
Alexandre Savard committed
278 279 280 281
	/*  Make sure that we are not in the history tab since 
	 *  nothing is defined for it yet 
	 */
	if( active_calltree == current_calls ) {
282

Alexandre Savard's avatar
Alexandre Savard committed
283
	    // sflphone_selected_call_codec(selectedCall);
284

Alexandre Savard's avatar
Alexandre Savard committed
285 286 287 288 289
	    // DEBUG("single click action: %s", dbus_get_current_codec_name(selectedCall));
	    // sflphone_display_selected_codec(dbus_get_current_codec_name(selectedCall));

	  switch(selectedCall->_srtp_state) {

290 291
	  case SRTP_STATE_ZRTP_SAS_UNCONFIRMED:
	      selectedCall->_srtp_state = SRTP_STATE_ZRTP_SAS_CONFIRMED;
Alexandre Savard's avatar
Alexandre Savard committed
292 293 294 295 296 297
	      if(g_strcasecmp(displaySasOnce,"true") == 0) {
		  selectedCall->_zrtp_confirmed = TRUE;
	      }
	      dbus_confirm_sas(selectedCall);
	      calltree_update_call(current_calls, selectedCall, NULL);
	      break;
298 299
	  case SRTP_STATE_ZRTP_SAS_CONFIRMED:
	      selectedCall->_srtp_state = SRTP_STATE_ZRTP_SAS_UNCONFIRMED;
Alexandre Savard's avatar
Alexandre Savard committed
300 301 302 303 304 305 306
	      dbus_reset_sas(selectedCall);
	      calltree_update_call(current_calls, selectedCall, NULL);
	      break;
	  default:
	      DEBUG("Single click but no action");
	      break;
	  }
307
	}
Alexandre Savard's avatar
Alexandre Savard committed
308
    }
309 310
}

311
	static gboolean
Julien Bonjean's avatar
Julien Bonjean committed
312 313
button_pressed(GtkWidget* widget, GdkEventButton *event, gpointer user_data UNUSED)
{
Alexandre Savard's avatar
Alexandre Savard committed
314 315 316 317
    if (event->button == 3 && event->type == GDK_BUTTON_PRESS){
        if( active_calltree == current_calls ) {
	    show_popup_menu(widget,  event);
	    return TRUE;
318
	}
Alexandre Savard's avatar
Alexandre Savard committed
319 320 321 322 323 324 325 326 327 328
	else if (active_calltree == history) {
	    show_popup_menu_history (widget,  event);
	    return TRUE;
	}
	else {
	    show_popup_menu_contacts (widget, event);
	    return TRUE;
	}
    }
    return FALSE;
Julien Bonjean's avatar
Julien Bonjean committed
329 330
}

331 332

gchar* 
333
calltree_display_call_info(callable_obj_t * c, CallDisplayType display_type, gchar *audio_codec, gchar** display_info)
334 335 336
{

    gchar * description;
337
    gchar * tmp_info;
338

339 340 341
    gchar * peer_number = c->_peer_number;
    gchar * hostname = NULL;
    gchar * display_number = "";  
342

343
    DEBUG("CallTree: Display call info");
344

345 346
    // If call is outgoing, keep the hostname, strip it elsewhere
    if(c->_type == CALL && c->_history_state == OUTGOING) {
347

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
        display_number = peer_number; 
    }
    else {

        // Get the hostname for this call (NULL if not existent)
        hostname = g_strrstr(peer_number, "@");

	// Test if we are dialing a new number
	if(g_strcmp0("", c->_peer_number) != 0) {

	    // Strip the hostname if existent
	    if(hostname) {
	        display_number = g_strndup(peer_number, hostname - peer_number);
	    }
	    else {
	        display_number = peer_number;
	    }
365 366
	}
	else {
367

368 369 370 371
	    display_number = peer_number;
	}
    }
    // Different display depending on type
372 373
    switch(display_type) {

374
    case DISPLAY_TYPE_CALL:
375

376
        DEBUG("CallTree: Display a normal call");
377 378 379
        if(c->_state_code == 0) {

	    if(g_strcmp0("", c->_peer_name) == 0) {
380
	        description = g_markup_printf_escaped("<b>%s</b><i>%s</i>",
381
						      display_number, c->_peer_name);
382 383 384
	    }
	    else {
	        description = g_markup_printf_escaped("<b>%s</b>   <i>%s</i>",
385
						      c->_peer_name, display_number);
386
	    }
387 388 389

	}
	else {
390
	    if(g_strcmp0("", c->_peer_name) == 0) {
391
	        description = g_markup_printf_escaped("<b>%s</b><i>%s</i>\n<i>%s (%d)</i>",
392 393
						      display_number, c->_peer_name,
						      c->_state_code_description, c->_state_code);
394 395 396
	    }
	    else {
	        description = g_markup_printf_escaped("<b>%s</b>   <i>%s</i>\n<i>%s (%d)</i>",
397 398
						      c->_peer_name, display_number,
						      c->_state_code_description, c->_state_code);
399
	    }
400
	}
401 402 403 404 405
	break;


    case DISPLAY_TYPE_CALL_TRANSFER: 

406
        DEBUG("CallTree: Display a call transfer")
407 408

        if(g_strcmp0("",c->_peer_name) == 0){
409
	    description = g_markup_printf_escaped("<b>%s</b><i>%s</i>\n<i>Transfert to:%s</i> ",
410
						  display_number, c->_peer_name, c->_trsft_to);
411 412
	}
	else {
413
	    description = g_markup_printf_escaped("<b>%s</b>   <i>%s</i>\n<i>Transfert to:%s</i> ",
414 415
						  c->_peer_name, display_number, c->_trsft_to);
	}	
416 417 418 419 420
	break;


    case DISPLAY_TYPE_STATE_CODE : 

421
        DEBUG("CallTree: Display a state code");
422 423 424 425

        if(g_strcmp0("",c->_peer_name) == 0){

	    if (c->_state_code) {
426

427
	        description = g_markup_printf_escaped("<b>%s</b><i>%s</i>\n<i>%s (%d)</i>  <i>%s</i>",
428 429
						      display_number, c->_peer_name,
						      c->_state_code_description, c->_state_code,
430 431 432
						      audio_codec);
	    } else {
	        description = g_markup_printf_escaped("<b>%s</b><i>%s</i>\n<i>%s</i>",
433
						      display_number, c->_peer_name, audio_codec);
434 435 436 437 438
	    }
	}
	else {
	    if (c->_state_code) {
	        description = g_markup_printf_escaped("<b>%s</b>   <i>%s</i>\n<i>%s (%d)</i>  <i>%s</i>",
439 440
						      c->_peer_name, display_number, 
						      c->_state_code_description, c->_state_code,
441 442 443
						      audio_codec);
	    } else {
	        description = g_markup_printf_escaped("<b>%s</b>   <i>%s</i>\n<i>%s</i>",
444
						      c->_peer_name, display_number, audio_codec);
445 446
	    }
	}
447 448
	break;

449 450
    case DISPLAY_TYPE_SAS:

451
        DEBUG("CallTree: Display a call with sas");
452

453
        if(g_strcmp0("", c->_peer_name) == 0){
454
	    description = g_markup_printf_escaped("<b>%s</b><i>%s</i>\n<i>Confirm SAS <b>%s</b> ?</i> ",
455
						  display_number, c->_peer_name, c->_sas);
456 457 458
	}
	else {
	  description = g_markup_printf_escaped("<b>%s</b>   <i>%s</i>\n<i>Confirm SAS <b>%s</b> ?</i> ",
459
						c->_peer_name, display_number, c->_sas);
460
	}
461
	break;
462 463 464

    case DISPLAY_TYPE_HISTORY :

465
        DEBUG("CallTree: Display history entry");
466 467 468

        if(g_strcmp0("", c->_peer_name) == 0) {
	    description = g_markup_printf_escaped("<b>%s</b><i>%s</i>",
469
						  display_number, c->_peer_name);
470 471 472
	}
	else {
	  description = g_markup_printf_escaped("<b>%s</b>   <i>%s</i>",
473
						c->_peer_name, display_number);
474 475
	}
	break;
476 477

    default : 
478
        DEBUG("CallTree: Not an allowable type of display");
479
	break;
480

481
    }
482

483 484 485
    // return description;
    tmp_info = g_strdup(description);
    *display_info = tmp_info;
486 487 488 489
}



Emmanuel Milou's avatar
Emmanuel Milou committed
490 491 492
/**
 * Reset call tree
 */
493
	void
Julien Bonjean's avatar
Julien Bonjean committed
494
calltree_reset (calltab_t* tab)
Emmanuel Milou's avatar
Emmanuel Milou committed
495
{
496
	gtk_tree_store_clear (tab->store);
Emmanuel Milou's avatar
Emmanuel Milou committed
497 498
}

499 500
void
focus_on_calltree_out(){
501 502 503
	//DEBUG("set_focus_on_calltree_out");
	// gtk_widget_grab_focus(GTK_WIDGET(sw));
	focus_is_on_calltree = FALSE;
504 505 506 507
}

void
focus_on_calltree_in(){
508 509 510
	//DEBUG("set_focus_on_calltree_in");
	// gtk_widget_grab_focus(GTK_WIDGET(sw));
	focus_is_on_calltree = TRUE;
511 512
}

513
	void
514
calltree_create (calltab_t* tab, gboolean searchbar_type)
areversat's avatar
areversat committed
515
{
Julien Bonjean's avatar
Julien Bonjean committed
516

517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
	tab->tree = gtk_vbox_new(FALSE, 10);

	// Fix bug #708 (resize)
	gtk_widget_set_size_request(tab->tree,100,80);

	gtk_container_set_border_width (GTK_CONTAINER (tab->tree), 0);

	sw = gtk_scrolled_window_new( NULL, NULL);
	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
	gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_IN);


	tab->store = gtk_tree_store_new (4,
			GDK_TYPE_PIXBUF,// Icon
			G_TYPE_STRING,  // Description
			GDK_TYPE_PIXBUF, // Security Icon
			G_TYPE_POINTER  // Pointer to the Object
			);

	tab->view = gtk_tree_view_new_with_model (GTK_TREE_MODEL(tab->store));
	gtk_tree_view_set_enable_search( GTK_TREE_VIEW(tab->view), FALSE);
	gtk_tree_view_set_headers_visible (GTK_TREE_VIEW(tab->view), FALSE);
	g_signal_connect (G_OBJECT (tab->view), "row-activated",
			G_CALLBACK (row_activated),
			NULL);

	GTK_WIDGET_SET_FLAGS (GTK_WIDGET(sw),GTK_CAN_FOCUS);
	gtk_widget_grab_focus (GTK_WIDGET(sw));

	g_signal_connect (G_OBJECT (tab->view), "cursor-changed",
			G_CALLBACK (row_single_click),
			NULL);

	// Connect the popup menu
	g_signal_connect (G_OBJECT (tab->view), "popup-menu",
			G_CALLBACK (popup_menu),
			NULL);
	g_signal_connect (G_OBJECT (tab->view), "button-press-event",
			G_CALLBACK (button_pressed),
			NULL);

	// g_signal_connect (G_OBJECT (sw), "key-release-event",
	//                   G_CALLBACK (on_key_released), NULL);

	g_signal_connect_after (G_OBJECT (tab->view), "focus-in-event",
			G_CALLBACK (focus_on_calltree_in), NULL);
	g_signal_connect_after (G_OBJECT (tab->view), "focus-out-event",
			G_CALLBACK (focus_on_calltree_out), NULL);


567
	if(tab != history && tab!=contacts) {
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628

		DEBUG("SET TREE VIEW REORDABLE");
		// Make calltree reordable for drag n drop
		gtk_tree_view_set_reorderable(GTK_TREE_VIEW(tab->view), TRUE); 

		// source widget drag n drop signals
		g_signal_connect (G_OBJECT (tab->view), "drag_begin", G_CALLBACK (drag_begin_cb), NULL);
		g_signal_connect (G_OBJECT (tab->view), "drag_end", G_CALLBACK (drag_end_cb), NULL);

		// destination widget drag n drop signals
		g_signal_connect (G_OBJECT (tab->view), "drag_data_received", G_CALLBACK (drag_data_received_cb), NULL);

	}


	gtk_widget_grab_focus(GTK_WIDGET(tab->view));

	rend = gtk_cell_renderer_pixbuf_new();
	col = gtk_tree_view_column_new_with_attributes ("Icon",
			rend,
			"pixbuf", 0,
			NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW(tab->view), col);

	rend = gtk_cell_renderer_text_new();
	col = gtk_tree_view_column_new_with_attributes ("Description",
			rend,
			"markup", COLUMN_ACCOUNT_DESC,
			NULL);
	g_object_set(rend, "wrap-mode", (PangoWrapMode) PANGO_WRAP_WORD_CHAR, NULL);
	g_object_set(rend, "wrap-width", (gint) CALLTREE_TEXT_WIDTH, NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW(tab->view), col);

	/* Security icon */
	rend = gtk_cell_renderer_pixbuf_new();
	col = gtk_tree_view_column_new_with_attributes ("Icon",
			rend,
			"pixbuf", COLUMN_ACCOUNT_SECURITY,
			NULL);
	g_object_set(rend, "xalign", (gfloat) 1.0, NULL);
	g_object_set(rend, "yalign", (gfloat) 0.0, NULL);
	gtk_tree_view_append_column (GTK_TREE_VIEW(tab->view), col);


	g_object_unref(G_OBJECT(tab->store));
	gtk_container_add(GTK_CONTAINER(sw), tab->view);

	sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tab->view));
	g_signal_connect (G_OBJECT (sel), "changed",
			G_CALLBACK (call_selected_cb),
			NULL);

	gtk_box_pack_start(GTK_BOX(tab->tree), sw, TRUE, TRUE, 0);

	// search bar if tab is either "history" or "addressbook"
	if(searchbar_type){
		calltab_create_searchbar (tab);
		gtk_box_pack_start(GTK_BOX(tab->tree), tab->searchbar, FALSE, TRUE, 0);
	}

	gtk_widget_show(tab->tree);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
629
}
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
630

631

632
	void
633
calltree_remove_call (calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
634
{
635

636 637 638 639 640
	GtkTreeIter iter;
	GValue val;
	callable_obj_t * iterCall;
	GtkTreeStore* store = tab->store;

641 642 643 644 645
	if(!c)
	  ERROR("CallTree: Error: Not a valid call");

	DEBUG("CallTree: Remove call %s", c->_callID);

646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672
	int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), parent);
	int i;
	for( i = 0; i < nbChild; i++)
	{
		if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, parent, i))
		{
			if(gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter))
			{
				calltree_remove_call (tab, c, &iter);
			}

			val.g_type = 0;
			gtk_tree_model_get_value (GTK_TREE_MODEL(store), &iter, COLUMN_ACCOUNT_PTR, &val);

			iterCall = (callable_obj_t*) g_value_get_pointer(&val);
			g_value_unset(&val);

			if(iterCall == c)
			{
				gtk_tree_store_remove(store, &iter);
			}
		}
	}
	callable_obj_t * selectedCall = calltab_get_selected_call(tab);
	if(selectedCall == c)
		calltab_select_call(tab, NULL);
	update_actions();
673 674

	DEBUG("Calltre remove call ended");
675
}
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
676

677
	void
678
calltree_update_call (calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent)
679
{
680 681 682 683 684 685 686 687 688
    GdkPixbuf *pixbuf=NULL;
    GdkPixbuf *pixbuf_security=NULL;
    GtkTreeIter iter;
    GValue val;
    callable_obj_t * iterCall;
    GtkTreeStore* store = tab->store;

    gchar* srtp_enabled = "";
    gboolean display_sas = TRUE;
689
    gboolean sdes_success = TRUE;
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705
    account_t* account_details=NULL;
    gchar *audio_codec = "";

    int nbChild = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), parent);
    int i;

    if(c != NULL) {
        account_details = account_list_get_by_id(c->_accountID);
	if(account_details != NULL) {
	    srtp_enabled = g_hash_table_lookup(account_details->properties, ACCOUNT_SRTP_ENABLED);
	    if(g_strcasecmp(g_hash_table_lookup(account_details->properties, ACCOUNT_ZRTP_DISPLAY_SAS),"false") == 0) 
	      { display_sas = FALSE; }
	} else {
	    GHashTable * properties = NULL;
	    sflphone_get_ip2ip_properties (&properties);
	    if(properties != NULL) {
706
	        srtp_enabled = g_hash_table_lookup(properties, ACCOUNT_SRTP_ENABLED);
707 708 709 710 711
	        if(g_strcasecmp(g_hash_table_lookup(properties, ACCOUNT_ZRTP_DISPLAY_SAS),"false") == 0) 
		  { display_sas = FALSE; }
	    }
	}
    } 
712

713
    for( i = 0; i < nbChild; i++) {
714

715
        if(gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, parent, i)) {
716

717 718 719
	    if(gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) {
	      calltree_update_call (tab, c, &iter);
	    }
720

721 722
	    val.g_type = 0;
	    gtk_tree_model_get_value (GTK_TREE_MODEL(store), &iter, COLUMN_ACCOUNT_PTR, &val);
723

724
	
725 726
	    iterCall = (callable_obj_t*) g_value_get_pointer(&val);
	    g_value_unset(&val);
727
	
728 729 730
	    if(iterCall != c) {
	        continue;
	    }
731

732 733 734 735 736
	    /* Update text */
	    gchar * description;
	    gchar * date="";
	    gchar * duration="";
	    audio_codec = call_get_audio_codec (c);
737
	
738
	    if(c->_state == CALL_STATE_TRANSFERT) {
739

740
	        calltree_display_call_info(c, DISPLAY_TYPE_CALL_TRANSFER, NULL, &description);
741
			    
742 743
	    }
	    else {
744

745
	        if((c->_sas != NULL) && (display_sas == TRUE) && (c->_srtp_state == SRTP_STATE_ZRTP_SAS_UNCONFIRMED) && (c->_zrtp_confirmed == FALSE)) {
746 747 748 749
		    calltree_display_call_info(c, DISPLAY_TYPE_SAS, NULL, &description);
		} else {
		    calltree_display_call_info(c, DISPLAY_TYPE_STATE_CODE, audio_codec, &description);		    
		}
750
	    }
751

752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
	    /* Update icons */
	    if( tab == current_calls ) {
	        DEBUG("Receiving in state %d", c->_state);
		switch(c->_state) {
		case CALL_STATE_HOLD:
		    pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/hold.svg", NULL);
		    break;
		case CALL_STATE_INCOMING:
		case CALL_STATE_RINGING:
		    pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/ring.svg", NULL);
		    break;
		case CALL_STATE_CURRENT:
		    pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL);
		    break;
		case CALL_STATE_DIALING:
767
      	            pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/dial.svg", NULL);
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
		    break;
		case CALL_STATE_FAILURE:
		    pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/fail.svg", NULL);
		    break;
		case CALL_STATE_BUSY:
	            pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/busy.svg", NULL);
		    break;
		case CALL_STATE_TRANSFERT:
	            pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/transfert.svg", NULL);
		    break;
		case CALL_STATE_RECORD:
	            pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/icon_rec.svg", NULL);
		    break;
		default:
		    WARN("Update calltree - Should not happen!");
		}        

		switch(c->_srtp_state) {
786 787 788 789
		case SRTP_STATE_SDES_SUCCESS:
		    DEBUG("SDES negotiation succes");
		    pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL); 
		    break;
790
		case SRTP_STATE_ZRTP_SAS_UNCONFIRMED:
791 792 793 794
	            DEBUG("Secure is ON");
		    pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_unconfirmed.svg", NULL);
		    if(c->_sas != NULL) { DEBUG("SAS is ready with value %s", c->_sas); }
		    break;
795
		case SRTP_STATE_ZRTP_SAS_CONFIRMED:
796 797 798
		    DEBUG("SAS is confirmed");
		    pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_confirmed.svg", NULL);   
		    break;
799
		case SRTP_STATE_ZRTP_SAS_SIGNED:   
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
		    DEBUG("Secure is ON with SAS signed and verified");
		    pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_certified.svg", NULL);
		    break;
		case SRTP_STATE_UNLOCKED:  
		    DEBUG("Secure is off calltree %d", c->_state);
		    if(g_strcasecmp(srtp_enabled,"true") == 0) {
		        pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL); 
		    }
		    break;
		default:
		    WARN("Update calltree srtp state #%d- Should not happen!", c->_srtp_state); 
		    if(g_strcasecmp(srtp_enabled,"true") == 0) {
		        pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/lock_off.svg", NULL);    
		    }

815
		}
816 817
	
	    }
818
	    else if(tab == history) {
819 820 821 822 823 824 825 826 827 828 829 830
	        switch(c->_history_state) {
		case INCOMING:
		    pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/incoming.svg", NULL);
		    break;
		case OUTGOING:
		    pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/outgoing.svg", NULL);
		    break;
		case MISSED:
		    pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/missed.svg", NULL);
		    break;
		default:
		    WARN("History - Should not happen!");
831
		}
Emmanuel Milou's avatar
Emmanuel Milou committed
832

833 834 835 836 837 838
		calltree_display_call_info(c, DISPLAY_TYPE_HISTORY, NULL, &description);

		date = get_formatted_start_timestamp (c);
		duration = get_call_duration (c);
		duration = g_strconcat( date , duration , NULL);
		description = g_strconcat( description , duration, NULL);
839
	    }
840

841
	    gtk_tree_store_set(store, &iter,
842 843 844 845 846
			   0, pixbuf, // Icon
			   1, description, // Description
			   2, pixbuf_security,
			   3, c,
			   -1);
847 848

	    if (pixbuf != NULL)
849
	        g_object_unref(G_OBJECT(pixbuf));
850
	}
851 852
      
    }
853

854
    update_actions();
Emmanuel Milou's avatar
Emmanuel Milou committed
855 856
}

857

858
void calltree_add_call (calltab_t* tab, callable_obj_t * c, GtkTreeIter *parent)
859 860
{

861
        DEBUG("CallTree: Add call to calltree id: %s, peer name: %s", c->_callID, c->_peer_name);
862

863 864 865 866 867
	if (tab == history)
	{
		calltree_add_history_entry (c);
		return;
	}
868

869
	account_t* account_details=NULL;
870

871 872 873 874 875
	GdkPixbuf *pixbuf=NULL;
	GdkPixbuf *pixbuf_security=NULL;
	GtkTreeIter iter;
	gchar* key_exchange="";
	gchar* srtp_enabled="";
876

877 878 879 880
	// New call in the list
	gchar * description;
	gchar * date="";
	gchar *duration="";
881

882
	calltree_display_call_info(c, DISPLAY_TYPE_CALL, NULL, &description);
883

884
	gtk_tree_store_prepend (tab->store, &iter, parent);
885

886 887 888 889 890 891 892
	if(c != NULL) {
		account_details = account_list_get_by_id(c->_callID);
		if(account_details != NULL) {
			srtp_enabled = g_hash_table_lookup(account_details->properties, ACCOUNT_SRTP_ENABLED);
			key_exchange = g_hash_table_lookup(account_details->properties, ACCOUNT_KEY_EXCHANGE);
		}
	} 
893

894 895
	DEBUG("Added call key exchange is %s", key_exchange)

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
	if( tab == current_calls )
	{
		switch(c->_state)
		{
			case CALL_STATE_INCOMING:
				pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/ring.svg", NULL);
				break;
			case CALL_STATE_DIALING:
				pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/dial.svg", NULL);
				break;
			case CALL_STATE_RINGING:
				pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/ring.svg", NULL);
				break;
			case CALL_STATE_CURRENT:
				// If the call has been initiated by a another client and, when we start, it is already current
				pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/current.svg", NULL);
				break;
			case CALL_STATE_HOLD:
				// If the call has been initiated by a another client and, when we start, it is already current
				pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/hold.svg", NULL);
				break;
			case CALL_STATE_FAILURE:
				// If the call has been initiated by a another client and, when we start, it is already current
				pixbuf = gdk_pixbuf_new_from_file(ICONS_DIR "/fail.svg", NULL);
				break;
			default:
				WARN("Update calltree add - Should not happen!");
		}
924

925 926 927 928
		if(g_strcasecmp(srtp_enabled,"true") == 0) {
			pixbuf_security = gdk_pixbuf_new_from_file(ICONS_DIR "/secure_off.svg", NULL);
		}
	}
929

930 931 932 933
	else if (tab == contacts) {
		pixbuf = c->_contact_thumbnail;
		description = g_strconcat( description , NULL);
	}
934

935 936 937
	else {
		WARN ("This widget doesn't exist - This is a bug in the application.");
	}
938

Alexandre Savard's avatar