actions.c 38.4 KB
Newer Older
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
1
/*
2
 *  Copyright (C) 2004, 2005, 2006, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc.
3
 *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
4
 *  Author: Pierre-Luc Beaudoin <pierre-luc.beaudoin@savoirfairelinux.com>
Emmanuel Milou's avatar
Emmanuel Milou committed
5
 *
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
6 7
 *  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
8
 *  the Free Software Foundation; either version 3 of the License, or
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
9
 *  (at your option) any later version.
Emmanuel Milou's avatar
Emmanuel Milou committed
10
 *
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
11 12 13 14
 *  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
15
 *
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
16 17 18
 *  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.
19 20 21 22 23 24 25 26 27 28 29
 *
 *  Additional permission under GNU GPL version 3 section 7:
 *
 *  If you modify this program, or any covered work, by linking or
 *  combining it with the OpenSSL project's OpenSSL library (or a
 *  modified version of that library), containing parts covered by the
 *  terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
 *  grants you additional permission to convey the resulting work.
 *  Corresponding Source for a non-source form of such a combination
 *  shall include the source code for the parts of OpenSSL used as well
 *  as that of the covered work.
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
30
 */
31

32
#include <gtk/gtk.h>
33 34 35 36
/* Backward compatibility for gtk < 2.22.0 */
#if GTK_CHECK_VERSION(2,22,0)
#include <gdk/gdkkeysyms-compat.h>
#else
37
#include <gdk/gdkkeysyms.h>
38
#endif
39 40
#include <glib/gprintf.h>
#include <stdlib.h>
41
#include <string.h>
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
42 43
#include <sys/types.h>
#include <unistd.h>
44
#include <assert.h>
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
45

46
#include <arpa/nameser.h>
47
#include <netinet/in.h>
48 49
#include <resolv.h>

50
#include <linux/if.h>
51 52 53 54
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

55 56
#include "actions.h"
#include "dbus/dbus.h"
57
#include "logger.h"
58
#include "contacts/calltab.h"
59 60 61 62 63 64 65
#include "contacts/searchbar.h"
#include "contacts/addrbookfactory.h"
#include "icons/icon_factory.h"
#include "imwindow.h"
#include "statusicon.h"
#include "widget/imwidget.h"

66

67
static GHashTable * ip2ip_profile;
68

69
static gchar ** sflphone_order_history_hash_table(GHashTable *result)
70 71
{
    GHashTableIter iter;
72 73
    gint size = 0;
    gchar **ordered_list = NULL;
74

75
    assert(result);
76
    while (g_hash_table_size (result)) {
77
        gpointer key, key_to_min, value;
78 79 80 81

        // find lowest timestamp in map
        g_hash_table_iter_init (&iter, result);

82
        gint min_timestamp = G_MAXINT;
83
        while (g_hash_table_iter_next (&iter, &key, &value))  {
84 85
            gint timestamp = atoi ( (gchar*) key);
            if (timestamp < min_timestamp) {
86 87 88 89 90
                min_timestamp = timestamp;
                key_to_min = key;
            }
        }

Tristan Matthews's avatar
Tristan Matthews committed
91 92 93 94 95 96 97 98 99
        if (g_hash_table_lookup_extended(result, key_to_min, &key, &value)) {
            GSList *llist = (GSList *)value;
            while (llist) {
                ordered_list = (void *) g_realloc(ordered_list, (size + 1) * sizeof (void *));
                *(ordered_list + size) = g_strdup((gchar *)llist->data);
                size++;
                llist = g_slist_next(llist);
            }
            g_hash_table_remove(result, key_to_min);
100 101 102
        }
    }

103 104
    ordered_list = (void *) g_realloc(ordered_list, (size + 1) * sizeof(void *));
    *(ordered_list + size) = NULL;
105

106
    return ordered_list;
107 108
}

109
void
110
sflphone_notify_voice_mail (const gchar* accountID , guint count)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
111
{
112
    // We want to notify only the current account; ie the first in the list
113 114
    gchar *id = g_strdup (accountID);
    const gchar * const current_id = account_list_get_current_id ();
115

Julien Bonjean's avatar
Julien Bonjean committed
116
    DEBUG ("sflphone_notify_voice_mail begin");
117

118
    if (g_ascii_strcasecmp (id, current_id) != 0 || account_list_get_size() == 0)
119 120
        return;

121 122
    // Set the number of voice messages for the current account
    current_account_set_message_number (count);
123
    account_t *current = account_list_get_current ();
124

125 126
    // Update the voicemail tool button
    update_voicemail_status ();
Emmanuel Milou's avatar
Emmanuel Milou committed
127

128 129
    if (current)
        notify_voice_mails (count, current);
Emmanuel Milou's avatar
Emmanuel Milou committed
130

Julien Bonjean's avatar
Julien Bonjean committed
131
    DEBUG ("sflphone_notify_voice_mail end");
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
132 133
}

134 135 136 137 138 139 140
/*
 * Place a call with the current account.
 * If there is no default account selected, place a call with the first
 * registered account of the account list
 * Else, check if it an IP call. if not, popup an error message
 */

141 142
static gboolean _is_direct_call (callable_obj_t * c)
{
143
    if (g_strcasecmp (c->_accountID, "empty") == 0) {
144 145 146
        if (!g_str_has_prefix (c->_peer_number, "sip:")) {
            gchar * new_number = g_strconcat ("sip:", c->_peer_number, NULL);
            g_free (c->_peer_number);
147 148
            c->_peer_number = new_number;
        }
149

150
        return TRUE;
Alexandre Savard's avatar
Alexandre Savard committed
151 152
    }

153 154
    return g_str_has_prefix (c->_peer_number, "sip:") ||
           g_str_has_prefix (c->_peer_number, "sips:");
155 156 157
}


158
void
159
status_bar_display_account ()
160
{
161
    gchar* msg;
162

163
    statusbar_pop_message (__MSG_ACCOUNT_DEFAULT);
164

165 166
    account_t *acc = account_list_get_current ();
    status_tray_icon_online (acc != NULL);
167 168 169 170 171 172 173 174

    if (acc) {
        msg = g_markup_printf_escaped ("%s %s (%s)" ,
                                       _ ("Using account"),
                                       (gchar*) g_hash_table_lookup (acc->properties , ACCOUNT_ALIAS),
                                       (gchar*) g_hash_table_lookup (acc->properties , ACCOUNT_TYPE));
    } else {
        msg = g_markup_printf_escaped (_ ("No registered accounts"));
175
    }
176

Julien Bonjean's avatar
Julien Bonjean committed
177
    statusbar_push_message (msg, NULL,  __MSG_ACCOUNT_DEFAULT);
178
    g_free (msg);
179 180
}

Emmanuel Milou's avatar
Emmanuel Milou committed
181

182
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
183 184
sflphone_quit ()
{
185
    if (calllist_get_size(current_calls) == 0 || main_window_ask_quit()) {
186
        // Save the history
187 188
        sflphone_save_history ();

189
        dbus_unregister (getpid());
Emmanuel Milou's avatar
Emmanuel Milou committed
190
        dbus_clean ();
Rafaël Carré's avatar
Cleanup  
Rafaël Carré committed
191
        account_list_free();
Vivien Didelot's avatar
Vivien Didelot committed
192 193 194
        calllist_clean (current_calls);
        calllist_clean (contacts);
        calllist_clean (history);
Rafaël Carré's avatar
Cleanup  
Rafaël Carré committed
195 196 197
        gtk_tree_store_clear(history->store);
        gtk_tree_store_clear(current_calls->store);
        gtk_tree_store_clear(contacts->store);
Emmanuel Milou's avatar
Emmanuel Milou committed
198 199
        gtk_main_quit ();
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
200 201
}

202 203
void
sflphone_hold (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
204
{
205
    c->_state = CALL_STATE_HOLD;
206
    calltree_update_call (current_calls, c, NULL);
207
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
208 209
}

210 211
void
sflphone_ringing (callable_obj_t * c)
212
{
213
    c->_state = CALL_STATE_RINGING;
214
    calltree_update_call (current_calls, c, NULL);
215
    update_actions();
216
}
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
217

218 219
void
sflphone_hung_up (callable_obj_t * c)
Emmanuel Milou's avatar
Emmanuel Milou committed
220
{
Julien Bonjean's avatar
Julien Bonjean committed
221
    DEBUG ("SFLphone: Hung up");
222

223
    calllist_remove_call (current_calls, c->_callID);
224
    calltree_remove_call (current_calls, c);
225
    c->_state = CALL_STATE_DIALING;
226
    call_remove_all_errors (c);
227
    update_actions();
228

229 230 231 232 233
    if(c->_confID) {
	g_free(c->_confID);
	c->_confID = NULL;
    }

234 235 236 237 238
    // test wether the widget contain text, if not remove it
    if ( (im_window_get_nb_tabs() > 1) && c->_im_widget && ! (IM_WIDGET (c->_im_widget)->containText))
        im_window_remove_tab (c->_im_widget);
    else
        im_widget_update_state (IM_WIDGET (c->_im_widget), FALSE);
239

240
    status_tray_icon_blink (FALSE);
241

242
    statusbar_update_clock("");
243 244
}

Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
245
/** Internal to actions: Fill account list */
246 247
void sflphone_fill_account_list (void)
{
248
    int count = current_account_get_message_number ();
249

Rafaël Carré's avatar
Cleanup  
Rafaël Carré committed
250 251
    account_list_free();
    account_list_init();
252

253
    gchar **array = dbus_account_list();
254
    if (array) {
255
        for (gchar **accountID = array; *accountID; accountID++) {
256 257
            account_t * a = g_new0 (account_t,1);
            a->accountID = g_strdup (*accountID);
258
            a->credential_information = NULL;
259
            account_list_add (a);
Emmanuel Milou's avatar
Emmanuel Milou committed
260
        }
261

Emmanuel Milou's avatar
Emmanuel Milou committed
262
        g_strfreev (array);
263
    }
264

265
    for (unsigned i = 0; i < account_list_get_size(); i++) {
Emmanuel Milou's avatar
Emmanuel Milou committed
266
        account_t  * a = account_list_get_nth (i);
267 268
        if(a == NULL) {
            ERROR("SFLphone: Error: Could not find account %d in list", i);
269
            break;
270
        }
271

272 273 274 275 276
        GHashTable * details = (GHashTable *) dbus_get_account_details (a->accountID);
        if (details == NULL) {
            ERROR("SFLphone: Error: Could not fetch detais for account %s", a->accountID);
	    break;
        }
277

278
        a->properties = details;
279 280

        /* Fill the actual array of credentials */
281
        dbus_get_credentials (a);
Emmanuel Milou's avatar
Emmanuel Milou committed
282

283 284
        gchar * status = g_hash_table_lookup (details, REGISTRATION_STATUS);

285
        if (g_strcmp0 (status, "REGISTERED") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
286
            a->state = ACCOUNT_STATE_REGISTERED;
287
        } else if (g_strcmp0 (status, "UNREGISTERED") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
288
            a->state = ACCOUNT_STATE_UNREGISTERED;
289
        } else if (g_strcmp0 (status, "TRYING") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
290
            a->state = ACCOUNT_STATE_TRYING;
291
        } else if (g_strcmp0 (status, "ERROR") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
292
            a->state = ACCOUNT_STATE_ERROR;
293
        } else if (g_strcmp0 (status , "ERROR_AUTH") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
294
            a->state = ACCOUNT_STATE_ERROR_AUTH;
295
        } else if (g_strcmp0 (status , "ERROR_NETWORK") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
296
            a->state = ACCOUNT_STATE_ERROR_NETWORK;
297
        } else if (g_strcmp0 (status , "ERROR_HOST") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
298
            a->state = ACCOUNT_STATE_ERROR_HOST;
299
        } else if (g_strcmp0 (status , "ERROR_CONF_STUN") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
300
            a->state = ACCOUNT_STATE_ERROR_CONF_STUN;
301
        } else if (g_strcmp0 (status , "ERROR_EXIST_STUN") == 0) {
Emmanuel Milou's avatar
Emmanuel Milou committed
302
            a->state = ACCOUNT_STATE_ERROR_EXIST_STUN;
303
        } else if (g_strcmp0 (status, "READY") == 0) {
304 305
            a->state = IP2IP_PROFILE_STATUS;
        } else {
Emmanuel Milou's avatar
Emmanuel Milou committed
306 307 308
            a->state = ACCOUNT_STATE_INVALID;
        }

309 310
        gchar * code = g_hash_table_lookup (details, REGISTRATION_STATE_CODE);
        if (code != NULL)
311 312 313 314
            a->protocol_state_code = atoi (code);

        g_free (a->protocol_state_description);
        a->protocol_state_description = g_hash_table_lookup (details, REGISTRATION_STATE_DESCRIPTION);
Emmanuel Milou's avatar
Emmanuel Milou committed
315 316
    }

317 318
    // Set the current account message number
    current_account_set_message_number (count);
319

320
    sflphone_fill_codec_list ();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
321 322
}

323
gboolean sflphone_init (GError **error)
324
{
325
    if (!dbus_connect (error) || !dbus_register (getpid (), "Gtk+ Client", error))
326
        return FALSE;
327

Rafaël Carré's avatar
Rafaël Carré committed
328
    abook_init();
329

330 331
    // Init icons factory
    init_icon_factory ();
332

333 334 335
    current_calls = calltab_init (FALSE, CURRENT_CALLS);
    contacts = calltab_init (TRUE, CONTACTS);
    history = calltab_init (TRUE, HISTORY);
336

337 338
    account_list_init ();
    codec_capabilities_load ();
339 340
    conferencelist_init (current_calls);
    conferencelist_init (history);
341

342 343
    // Fetch the configured accounts
    sflphone_fill_account_list ();
344

345 346
    // Fetch the ip2ip profile
    sflphone_fill_ip2ip_profile();
347

348 349
    // Fetch the conference list
    // sflphone_fill_conference_list();
350

351
    return TRUE;
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
352 353
}

354
void sflphone_fill_ip2ip_profile (void)
355 356 357 358
{
    ip2ip_profile = (GHashTable *) dbus_get_ip2_ip_details();
}

359
GHashTable *sflphone_get_ip2ip_properties(void)
360
{
361
    return ip2ip_profile;
362 363
}

364
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
365
sflphone_hang_up()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
366
{
367 368
    callable_obj_t * selectedCall = calltab_get_selected_call (current_calls);
    conference_obj_t * selectedConf = calltab_get_selected_conf (active_calltree);
369

Julien Bonjean's avatar
Julien Bonjean committed
370
    DEBUG ("SFLphone: Hang up");
371

372 373 374 375 376
    if (selectedConf) {
        im_widget_update_state (IM_WIDGET (selectedConf->_im_widget), FALSE);
        dbus_hang_up_conference (selectedConf);
    }
    else if (selectedCall) {
377
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
378 379 380 381 382
            case CALL_STATE_DIALING:
                dbus_hang_up (selectedCall);
                break;
            case CALL_STATE_RINGING:
                dbus_hang_up (selectedCall);
383
                call_remove_all_errors (selectedCall);
384 385
                selectedCall->_state = CALL_STATE_DIALING;
                //selectedCall->_stop = 0;
Emmanuel Milou's avatar
Emmanuel Milou committed
386 387 388 389
                break;
            case CALL_STATE_CURRENT:
            case CALL_STATE_HOLD:
            case CALL_STATE_BUSY:
390
            case CALL_STATE_RECORD:
Emmanuel Milou's avatar
Emmanuel Milou committed
391
                dbus_hang_up (selectedCall);
392
                call_remove_all_errors (selectedCall);
393
                selectedCall->_state = CALL_STATE_DIALING;
394
                time (&selectedCall->_time_stop);
395

396
                im_widget_update_state (IM_WIDGET (selectedCall->_im_widget), FALSE);
397

Emmanuel Milou's avatar
Emmanuel Milou committed
398 399 400
                break;
            case CALL_STATE_FAILURE:
                dbus_hang_up (selectedCall);
401
                call_remove_all_errors (selectedCall);
402
                selectedCall->_state = CALL_STATE_DIALING;
Emmanuel Milou's avatar
Emmanuel Milou committed
403 404 405
                break;
            case CALL_STATE_INCOMING:
                dbus_refuse (selectedCall);
406
                call_remove_all_errors (selectedCall);
407
                selectedCall->_state = CALL_STATE_DIALING;
408
                DEBUG ("from sflphone_hang_up : ");
Emmanuel Milou's avatar
Emmanuel Milou committed
409
                break;
410
            case CALL_STATE_TRANSFER:
Emmanuel Milou's avatar
Emmanuel Milou committed
411
                dbus_hang_up (selectedCall);
412
                call_remove_all_errors (selectedCall);
413
                time (&selectedCall->_time_stop);
Emmanuel Milou's avatar
Emmanuel Milou committed
414 415
                break;
            default:
416
                WARN ("Should not happen in sflphone_hang_up()!");
Emmanuel Milou's avatar
Emmanuel Milou committed
417 418
                break;
        }
419 420
    }

421
    calltree_update_call (history, selectedCall, NULL);
422

423
    statusbar_update_clock("");
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
424 425
}

426
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
427 428
sflphone_pick_up()
{
429 430 431 432 433
    callable_obj_t *selectedCall = calltab_get_selected_call (active_calltree);
    if (!selectedCall) {
        sflphone_new_call();
        return;
    }
434

435 436 437
    switch (selectedCall->_state) {
        case CALL_STATE_DIALING:
            sflphone_place_call (selectedCall);
438

439 440
            // if instant messaging window is visible, create new tab (deleted automatically if not used)
            if (im_window_is_visible())
441 442
                if (!selectedCall->_im_widget)
                    selectedCall->_im_widget = im_widget_display(selectedCall->_callID);
443

444 445 446 447
            break;
        case CALL_STATE_INCOMING:
            selectedCall->_history_state = INCOMING;
            calltree_update_call (history, selectedCall, NULL);
448

449
            // if instant messaging window is visible, create new tab (deleted automatically if not used)
450 451 452
            if (im_window_is_visible())
                if (!selectedCall->_im_widget)
                    selectedCall->_im_widget = im_widget_display(selectedCall->_callID);
453

454 455
            dbus_accept (selectedCall);
            break;
456 457
        case CALL_STATE_TRANSFER:
            dbus_transfer (selectedCall);
458
            time (&selectedCall->_time_stop);
459
            calltree_remove_call(current_calls, selectedCall);
460 461 462 463 464 465 466 467 468 469 470
            calllist_remove_call(current_calls, selectedCall->_callID);
            break;
        case CALL_STATE_CURRENT:
        case CALL_STATE_HOLD:
        case CALL_STATE_RECORD:
        case CALL_STATE_RINGING:
            sflphone_new_call();
            break;
        default:
            WARN ("Should not happen in sflphone_pick_up()!");
            break;
471
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
472 473
}

474
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
475 476
sflphone_on_hold ()
{
477 478
    callable_obj_t * selectedCall = calltab_get_selected_call (current_calls);
    conference_obj_t * selectedConf = calltab_get_selected_conf (active_calltree);
479

480 481
    if (selectedCall) {
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
482 483 484 485 486
            case CALL_STATE_CURRENT:
            case CALL_STATE_RECORD:
                dbus_hold (selectedCall);
                break;
            default:
487
                WARN ("Should not happen in sflphone_on_hold!");
Emmanuel Milou's avatar
Emmanuel Milou committed
488 489
                break;
        }
490 491
    } else if (selectedConf) {
        dbus_hold_conference (selectedConf);
492
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
493 494
}

495
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
496 497
sflphone_off_hold ()
{
498 499 500
    DEBUG ("sflphone_off_hold");
    callable_obj_t * selectedCall = calltab_get_selected_call (current_calls);
    conference_obj_t * selectedConf = calltab_get_selected_conf (active_calltree);
501

502 503
    if (selectedCall) {
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
504 505 506 507
            case CALL_STATE_HOLD:
                dbus_unhold (selectedCall);
                break;
            default:
508
                WARN ("Should not happen in sflphone_off_hold ()!");
Emmanuel Milou's avatar
Emmanuel Milou committed
509 510
                break;
        }
511 512
    } else if (selectedConf) {
        dbus_unhold_conference (selectedConf);
513
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
514 515 516
}


517 518
void
sflphone_fail (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
519
{
520
    c->_state = CALL_STATE_FAILURE;
521
    calltree_update_call (current_calls, c, NULL);
522
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
523 524
}

525 526
void
sflphone_busy (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
527
{
528
    c->_state = CALL_STATE_BUSY;
529
    calltree_update_call (current_calls, c, NULL);
530
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
531 532
}

533 534
void
sflphone_current (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
535
{
536

537
    if (c->_state != CALL_STATE_HOLD)
538
        time (&c->_time_start);
539

540
    c->_state = CALL_STATE_CURRENT;
541
    calltree_update_call (current_calls, c, NULL);
542
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
543 544
}

545 546
void
sflphone_record (callable_obj_t * c)
alexandresavard's avatar
alexandresavard committed
547
{
548
    if (c->_state != CALL_STATE_HOLD)
549
        time (&c->_time_start);
550

551
    c->_state = CALL_STATE_RECORD;
552
    calltree_update_call (current_calls, c, NULL);
553
    update_actions();
alexandresavard's avatar
alexandresavard committed
554 555
}

556
void
557
sflphone_set_transfer()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
558
{
559 560 561
    callable_obj_t * c = calltab_get_selected_call (current_calls);

    if (c) {
562
        c->_state = CALL_STATE_TRANSFER;
Tristan Matthews's avatar
Tristan Matthews committed
563
        g_free(c->_trsft_to);
564 565
        c->_trsft_to = g_strdup ("");
        calltree_update_call (current_calls, c, NULL);
Emmanuel Milou's avatar
Emmanuel Milou committed
566
    }
567

568
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
569 570
}

571
void
572
sflphone_unset_transfer()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
573
{
574 575 576
    callable_obj_t * c = calltab_get_selected_call (current_calls);

    if (c) {
577
        c->_state = CALL_STATE_CURRENT;
Tristan Matthews's avatar
Tristan Matthews committed
578
        g_free(c->_trsft_to);
579 580
        c->_trsft_to = g_strdup ("");
        calltree_update_call (current_calls, c, NULL);
Emmanuel Milou's avatar
Emmanuel Milou committed
581
    }
582

583
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
584
}
Emmanuel Milou's avatar
Emmanuel Milou committed
585

586 587
void
sflphone_display_transfer_status (const gchar* message)
588
{
Julien Bonjean's avatar
Julien Bonjean committed
589
    statusbar_push_message (message , NULL, __MSG_ACCOUNT_DEFAULT);
590 591
}

592
void
593
sflphone_incoming_call (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
594
{
595
    c->_history_state = MISSED;
596
    calllist_add_call (current_calls, c);
597
    calltree_add_call (current_calls, c, NULL);
598

599
    update_actions();
Julien Bonjean's avatar
Julien Bonjean committed
600
    calltree_display (current_calls);
601 602 603

    // Change the status bar if we are dealing with a direct SIP call
    if (_is_direct_call (c)) {
604
        gchar *msg = g_markup_printf_escaped (_ ("Direct SIP call"));
605
        statusbar_pop_message (__MSG_ACCOUNT_DEFAULT);
Julien Bonjean's avatar
Julien Bonjean committed
606
        statusbar_push_message (msg , NULL, __MSG_ACCOUNT_DEFAULT);
607 608
        g_free (msg);
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
609
}
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
610

611
static void
612
process_dialing (callable_obj_t *c, guint keyval, gchar *key)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
613
{
Emmanuel Milou's avatar
Emmanuel Milou committed
614
    // We stop the tone
615
    if (!*c->_peer_number && c->_state != CALL_STATE_TRANSFER)
616
        dbus_start_tone (FALSE, 0);
617

618
    switch (keyval) {
619 620
        case GDK_Return:
        case GDK_KP_Enter:
621
            sflphone_place_call (c);
Emmanuel Milou's avatar
Emmanuel Milou committed
622
            break;
623
        case GDK_Escape:
Rafaël Carré's avatar
Rafaël Carré committed
624
            sflphone_hang_up ();
Emmanuel Milou's avatar
Emmanuel Milou committed
625
            break;
626
        case GDK_BackSpace:
627 628 629 630 631 632
        {
            gchar *num = (c->_state == CALL_STATE_TRANSFER) ? c->_trsft_to : c->_peer_number;
            size_t len = strlen(num);
            if (len) {
                len--; // delete one character
                num[len] = '\0';
633
                calltree_update_call (current_calls, c, NULL);
634

635
                /* If number is now empty, hang up immediately */
636
                if (c->_state != CALL_STATE_TRANSFER && len == 0)
637
                    dbus_hang_up(c);
Emmanuel Milou's avatar
Emmanuel Milou committed
638
            }
639
            break;
640
        }
641 642 643 644 645
        case GDK_Tab:
        case GDK_Alt_L:
        case GDK_Control_L:
        case GDK_Super_L:
        case GDK_Caps_Lock:
Emmanuel Milou's avatar
Emmanuel Milou committed
646 647
            break;
        default:
648

649
            if (keyval < 127 /* ascii */ ||
650
               (keyval >= GDK_Mode_switch && keyval <= GDK_KP_9) /* num keypad */) {
Emmanuel Milou's avatar
Emmanuel Milou committed
651

652
                if (c->_state == CALL_STATE_TRANSFER) {
Tristan Matthews's avatar
Tristan Matthews committed
653 654 655
                    gchar *new_trsft = g_strconcat (c->_trsft_to, key, NULL);
                    g_free (c->_trsft_to);
                    c->_trsft_to = new_trsft;
656 657
                } else {
                    dbus_play_dtmf (key);
Tristan Matthews's avatar
Tristan Matthews committed
658 659 660
                    gchar *new_peer_number = g_strconcat (c->_peer_number, key, NULL);
                    g_free (c->_peer_number);
                    c->_peer_number = new_peer_number;
Emmanuel Milou's avatar
Emmanuel Milou committed
661
                }
662 663

                calltree_update_call (current_calls, c, NULL);
Emmanuel Milou's avatar
Emmanuel Milou committed
664
            }
665

Emmanuel Milou's avatar
Emmanuel Milou committed
666 667
            break;
    }
668 669
}

Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
670

671
callable_obj_t *
areversat's avatar
areversat committed
672
sflphone_new_call()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
673
{
Tristan Matthews's avatar
Tristan Matthews committed
674
    callable_obj_t *current_selected_call = calltab_get_selected_call (current_calls);
675

676 677
    if ( (current_selected_call != NULL) && (current_selected_call->_confID == NULL))
        sflphone_on_hold();
678

Emmanuel Milou's avatar
Emmanuel Milou committed
679
    // Play a tone when creating a new call
680 681
    if (calllist_get_size (current_calls) == 0)
        dbus_start_tone (TRUE , (current_account_has_new_message ()  > 0) ? TONE_WITH_MESSAGE : TONE_WITHOUT_MESSAGE) ;
Emmanuel Milou's avatar
Emmanuel Milou committed
682

683
    callable_obj_t *c = create_new_call (CALL, CALL_STATE_DIALING, "", "", "", "");
Emmanuel Milou's avatar
Emmanuel Milou committed
684

685 686
    c->_history_state = OUTGOING;

Alexandre Savard's avatar
Alexandre Savard committed
687
    calllist_add_call (current_calls, c);
688
    calltree_add_call (current_calls, c, NULL);
689
    update_actions();
690

Emmanuel Milou's avatar
Emmanuel Milou committed
691
    return c;
692 693
}

areversat's avatar
areversat committed
694

695 696
void
sflphone_keypad (guint keyval, gchar * key)
areversat's avatar
areversat committed
697
{
698 699 700 701
    callable_obj_t * c = calltab_get_selected_call (current_calls);

    if ( (active_calltree != current_calls) || (active_calltree == current_calls && !c)) {
        switch (keyval) {
702 703 704
            case GDK_Return:
            case GDK_KP_Enter:
            case GDK_Escape: