actions.c 38.3 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
77

    while (g_hash_table_size(result)) {
78
        gpointer key, key_to_min, value;
79
80

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

83
        gint min_timestamp = G_MAXINT;
84
85
86
87

        while (g_hash_table_iter_next(&iter, &key, &value))  {
            gint timestamp = atoi((gchar*) key);

88
            if (timestamp < min_timestamp) {
89
90
91
92
93
                min_timestamp = timestamp;
                key_to_min = key;
            }
        }

Tristan Matthews's avatar
Tristan Matthews committed
94
95
        if (g_hash_table_lookup_extended(result, key_to_min, &key, &value)) {
            GSList *llist = (GSList *)value;
96

Tristan Matthews's avatar
Tristan Matthews committed
97
            while (llist) {
98
                ordered_list = (gchar **) g_realloc(ordered_list, (size + 1) * sizeof(gchar *));
Tristan Matthews's avatar
Tristan Matthews committed
99
100
101
102
                *(ordered_list + size) = g_strdup((gchar *)llist->data);
                size++;
                llist = g_slist_next(llist);
            }
103

Tristan Matthews's avatar
Tristan Matthews committed
104
            g_hash_table_remove(result, key_to_min);
105
106
107
        }
    }

108
109
    ordered_list = (gchar **) g_realloc(ordered_list, (size + 1) * sizeof(gchar *));
    ordered_list[size] = NULL;
110

111
    return ordered_list;
112
113
}

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

121
    DEBUG("sflphone_notify_voice_mail begin");
122

123
    if (g_ascii_strcasecmp(id, current_id) != 0 || account_list_get_size() == 0)
124
125
        return;

126
    // Set the number of voice messages for the current account
127
128
    current_account_set_message_number(count);
    account_t *current = account_list_get_current();
129

130
    // Update the voicemail tool button
131
    update_voicemail_status();
Emmanuel Milou's avatar
Emmanuel Milou committed
132

133
    if (current)
134
        notify_voice_mails(count, current);
Emmanuel Milou's avatar
Emmanuel Milou committed
135

136
    DEBUG("sflphone_notify_voice_mail end");
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
137
138
}

139
140
141
142
143
144
145
/*
 * 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
 */

146
static gboolean _is_direct_call(callable_obj_t * c)
147
{
148
149
150
151
    if (g_strcasecmp(c->_accountID, "empty") == 0) {
        if (!g_str_has_prefix(c->_peer_number, "sip:")) {
            gchar * new_number = g_strconcat("sip:", c->_peer_number, NULL);
            g_free(c->_peer_number);
152
153
            c->_peer_number = new_number;
        }
154

155
        return TRUE;
Alexandre Savard's avatar
Alexandre Savard committed
156
157
    }

158
159
    return g_str_has_prefix(c->_peer_number, "sip:") ||
           g_str_has_prefix(c->_peer_number, "sips:");
160
161
162
}


163
void
164
status_bar_display_account()
165
{
166
    gchar* msg;
167

168
    statusbar_pop_message(__MSG_ACCOUNT_DEFAULT);
169

170
171
    account_t *acc = account_list_get_current();
    status_tray_icon_online(acc != NULL);
172
173

    if (acc) {
174
175
176
177
        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));
178
    } else {
179
        msg = g_markup_printf_escaped(_("No registered accounts"));
180
    }
181

182
183
    statusbar_push_message(msg, NULL,  __MSG_ACCOUNT_DEFAULT);
    g_free(msg);
184
185
}

Emmanuel Milou's avatar
Emmanuel Milou committed
186

187
void
188
sflphone_quit()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
189
{
Tristan Matthews's avatar
Tristan Matthews committed
190
    if (calllist_get_size(current_calls_tab) == 0 || main_window_ask_quit()) {
191
        // Save the history
192
        sflphone_save_history();
193

194
195
        dbus_unregister(getpid());
        dbus_clean();
Rafaël Carré's avatar
Cleanup    
Rafaël Carré committed
196
        account_list_free();
Tristan Matthews's avatar
Tristan Matthews committed
197
198
199
200
201
202
        calllist_clean(current_calls_tab);
        calllist_clean(contacts_tab);
        calllist_clean(history_tab);
        gtk_tree_store_clear(history_tab->store);
        gtk_tree_store_clear(current_calls_tab->store);
        gtk_tree_store_clear(contacts_tab->store);
203
        gtk_main_quit();
Emmanuel Milou's avatar
Emmanuel Milou committed
204
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
205
206
}

207
void
208
sflphone_hold(callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
209
{
210
    c->_state = CALL_STATE_HOLD;
Tristan Matthews's avatar
Tristan Matthews committed
211
    calltree_update_call(current_calls_tab, c);
212
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
213
214
}

215
void
216
sflphone_ringing(callable_obj_t * c)
217
{
218
    c->_state = CALL_STATE_RINGING;
Tristan Matthews's avatar
Tristan Matthews committed
219
    calltree_update_call(current_calls_tab, c);
220
    update_actions();
221
}
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
222

223
void
224
sflphone_hung_up(callable_obj_t * c)
Emmanuel Milou's avatar
Emmanuel Milou committed
225
{
226
    DEBUG("SFLphone: Hung up");
227

Tristan Matthews's avatar
Tristan Matthews committed
228
229
    calllist_remove_call(current_calls_tab, c->_callID);
    calltree_remove_call(current_calls_tab, c);
230
    c->_state = CALL_STATE_DIALING;
231
    call_remove_all_errors(c);
232
    update_actions();
233

234
235
236
    if (c->_confID) {
        g_free(c->_confID);
        c->_confID = NULL;
237
238
    }

239
    // test wether the widget contain text, if not remove it
240
241
    if ((im_window_get_nb_tabs() > 1) && c->_im_widget && !(IM_WIDGET(c->_im_widget)->containText))
        im_window_remove_tab(c->_im_widget);
242
    else
243
        im_widget_update_state(IM_WIDGET(c->_im_widget), FALSE);
244

245
    status_tray_icon_blink(FALSE);
246

247
    statusbar_update_clock("");
248
249
}

Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
250
/** Internal to actions: Fill account list */
251
void sflphone_fill_account_list(void)
252
{
253
    int count = current_account_get_message_number();
254

Rafaël Carré's avatar
Cleanup    
Rafaël Carré committed
255
256
    account_list_free();
    account_list_init();
257

258
    gchar **array = dbus_account_list();
259

260
    if (array) {
261
        for (gchar **accountID = array; accountID && *accountID; accountID++) {
262
263
            account_t * a = g_new0(account_t,1);
            a->accountID = g_strdup(*accountID);
264
            a->credential_information = NULL;
265
            account_list_add(a);
Emmanuel Milou's avatar
Emmanuel Milou committed
266
        }
267

268
        g_strfreev(array);
269
    }
270

271
    for (unsigned i = 0; i < account_list_get_size(); i++) {
272
273
274
        account_t  * a = account_list_get_nth(i);

        if (a == NULL) {
275
            ERROR("SFLphone: Error: Could not find account %d in list", i);
276
            break;
277
        }
278

279
280
        GHashTable * details = (GHashTable *) dbus_get_account_details(a->accountID);

281
282
        if (details == NULL) {
            ERROR("SFLphone: Error: Could not fetch detais for account %s", a->accountID);
283
            break;
284
        }
285

286
        a->properties = details;
287
288

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

291
        gchar * status = g_hash_table_lookup(details, REGISTRATION_STATUS);
292

293
        if (g_strcmp0(status, "REGISTERED") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
294
            a->state = ACCOUNT_STATE_REGISTERED;
295
        else if (g_strcmp0(status, "UNREGISTERED") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
296
            a->state = ACCOUNT_STATE_UNREGISTERED;
297
        else if (g_strcmp0(status, "TRYING") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
298
            a->state = ACCOUNT_STATE_TRYING;
299
        else if (g_strcmp0(status, "ERROR") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
300
            a->state = ACCOUNT_STATE_ERROR;
301
        else if (g_strcmp0(status , "ERROR_AUTH") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
302
            a->state = ACCOUNT_STATE_ERROR_AUTH;
303
        else if (g_strcmp0(status , "ERROR_NETWORK") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
304
            a->state = ACCOUNT_STATE_ERROR_NETWORK;
305
        else if (g_strcmp0(status , "ERROR_HOST") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
306
            a->state = ACCOUNT_STATE_ERROR_HOST;
307
        else if (g_strcmp0(status , "ERROR_CONF_STUN") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
308
            a->state = ACCOUNT_STATE_ERROR_CONF_STUN;
309
        else if (g_strcmp0(status , "ERROR_EXIST_STUN") == 0)
Emmanuel Milou's avatar
Emmanuel Milou committed
310
            a->state = ACCOUNT_STATE_ERROR_EXIST_STUN;
311
        else if (g_strcmp0(status, "READY") == 0)
312
            a->state = IP2IP_PROFILE_STATUS;
313
        else
Emmanuel Milou's avatar
Emmanuel Milou committed
314
315
            a->state = ACCOUNT_STATE_INVALID;

316
317
        gchar * code = g_hash_table_lookup(details, REGISTRATION_STATE_CODE);

318
        if (code != NULL)
319
            a->protocol_state_code = atoi(code);
320

321
322
        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
323
324
    }

325
    // Set the current account message number
326
    current_account_set_message_number(count);
327

328
    sflphone_fill_codec_list();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
329
330
}

331
gboolean sflphone_init(GError **error)
332
{
333
    if (!dbus_connect(error) || !dbus_register(getpid(), "Gtk+ Client", error))
334
        return FALSE;
335

Rafaël Carré's avatar
Rafaël Carré committed
336
    abook_init();
337

338
    // Init icons factory
339
    init_icon_factory();
340

Tristan Matthews's avatar
Tristan Matthews committed
341
342
343
    current_calls_tab = calltab_init(FALSE, CURRENT_CALLS);
    contacts_tab = calltab_init(TRUE, CONTACTS);
    history_tab = calltab_init(TRUE, HISTORY);
344

345
346
    account_list_init();
    codec_capabilities_load();
Tristan Matthews's avatar
Tristan Matthews committed
347
348
    conferencelist_init(current_calls_tab);
    conferencelist_init(history_tab);
349

350
    // Fetch the configured accounts
351
    sflphone_fill_account_list();
352

353
354
    // Fetch the ip2ip profile
    sflphone_fill_ip2ip_profile();
355

356
    // Fetch the conference list
357
    sflphone_fill_conference_list();
358

359
    return TRUE;
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
360
361
}

362
void sflphone_fill_ip2ip_profile(void)
363
364
365
366
{
    ip2ip_profile = (GHashTable *) dbus_get_ip2_ip_details();
}

367
GHashTable *sflphone_get_ip2ip_properties(void)
368
{
369
    return ip2ip_profile;
370
371
}

372
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
373
sflphone_hang_up()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
374
{
Tristan Matthews's avatar
Tristan Matthews committed
375
376
    callable_obj_t * selectedCall = calltab_get_selected_call(current_calls_tab);
    conference_obj_t * selectedConf = calltab_get_selected_conf(active_calltree_tab);
377

378
    DEBUG("SFLphone: Hang up");
379

380
    if (selectedConf) {
381
382
383
        im_widget_update_state(IM_WIDGET(selectedConf->_im_widget), FALSE);
        dbus_hang_up_conference(selectedConf);
    } else if (selectedCall) {
384
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
385
            case CALL_STATE_DIALING:
386
                dbus_hang_up(selectedCall);
Emmanuel Milou's avatar
Emmanuel Milou committed
387
388
                break;
            case CALL_STATE_RINGING:
389
390
                dbus_hang_up(selectedCall);
                call_remove_all_errors(selectedCall);
391
392
                selectedCall->_state = CALL_STATE_DIALING;
                //selectedCall->_stop = 0;
Emmanuel Milou's avatar
Emmanuel Milou committed
393
394
395
396
                break;
            case CALL_STATE_CURRENT:
            case CALL_STATE_HOLD:
            case CALL_STATE_BUSY:
397
            case CALL_STATE_RECORD:
398
399
                dbus_hang_up(selectedCall);
                call_remove_all_errors(selectedCall);
400
                selectedCall->_state = CALL_STATE_DIALING;
401
                time(&selectedCall->_time_stop);
402

403
                im_widget_update_state(IM_WIDGET(selectedCall->_im_widget), FALSE);
404

Emmanuel Milou's avatar
Emmanuel Milou committed
405
406
                break;
            case CALL_STATE_FAILURE:
407
408
                dbus_hang_up(selectedCall);
                call_remove_all_errors(selectedCall);
409
                selectedCall->_state = CALL_STATE_DIALING;
Emmanuel Milou's avatar
Emmanuel Milou committed
410
411
                break;
            case CALL_STATE_INCOMING:
412
413
                dbus_refuse(selectedCall);
                call_remove_all_errors(selectedCall);
414
                selectedCall->_state = CALL_STATE_DIALING;
415
                DEBUG("from sflphone_hang_up : ");
Emmanuel Milou's avatar
Emmanuel Milou committed
416
                break;
417
            case CALL_STATE_TRANSFER:
418
419
420
                dbus_hang_up(selectedCall);
                call_remove_all_errors(selectedCall);
                time(&selectedCall->_time_stop);
Emmanuel Milou's avatar
Emmanuel Milou committed
421
422
                break;
            default:
423
                WARN("Should not happen in sflphone_hang_up()!");
Emmanuel Milou's avatar
Emmanuel Milou committed
424
425
                break;
        }
426
427
    }

Tristan Matthews's avatar
Tristan Matthews committed
428
    calltree_update_call(history_tab, selectedCall);
429

430
    statusbar_update_clock("");
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
431
432
}

433
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
434
435
sflphone_pick_up()
{
Tristan Matthews's avatar
Tristan Matthews committed
436
    callable_obj_t *selectedCall = calltab_get_selected_call(active_calltree_tab);
437

438
439
440
441
    if (!selectedCall) {
        sflphone_new_call();
        return;
    }
442

443
444
    switch (selectedCall->_state) {
        case CALL_STATE_DIALING:
445
            sflphone_place_call(selectedCall);
446

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

452
453
454
            break;
        case CALL_STATE_INCOMING:
            selectedCall->_history_state = INCOMING;
Tristan Matthews's avatar
Tristan Matthews committed
455
            calltree_update_call(history_tab, selectedCall);
456

457
            // if instant messaging window is visible, create new tab (deleted automatically if not used)
458
459
460
            if (im_window_is_visible())
                if (!selectedCall->_im_widget)
                    selectedCall->_im_widget = im_widget_display(selectedCall->_callID);
461

462
            dbus_accept(selectedCall);
463
            break;
464
        case CALL_STATE_TRANSFER:
465
466
            dbus_transfer(selectedCall);
            time(&selectedCall->_time_stop);
Tristan Matthews's avatar
Tristan Matthews committed
467
468
            calltree_remove_call(current_calls_tab, selectedCall);
            calllist_remove_call(current_calls_tab, selectedCall->_callID);
469
470
471
472
473
474
475
476
            break;
        case CALL_STATE_CURRENT:
        case CALL_STATE_HOLD:
        case CALL_STATE_RECORD:
        case CALL_STATE_RINGING:
            sflphone_new_call();
            break;
        default:
477
            WARN("Should not happen in sflphone_pick_up()!");
478
            break;
479
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
480
481
}

482
void
483
sflphone_on_hold()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
484
{
Tristan Matthews's avatar
Tristan Matthews committed
485
486
    callable_obj_t * selectedCall = calltab_get_selected_call(current_calls_tab);
    conference_obj_t * selectedConf = calltab_get_selected_conf(active_calltree_tab);
487

488
489
    if (selectedCall) {
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
490
491
            case CALL_STATE_CURRENT:
            case CALL_STATE_RECORD:
492
                dbus_hold(selectedCall);
Emmanuel Milou's avatar
Emmanuel Milou committed
493
494
                break;
            default:
495
                WARN("Should not happen in sflphone_on_hold!");
Emmanuel Milou's avatar
Emmanuel Milou committed
496
497
                break;
        }
498
    } else if (selectedConf)
499
        dbus_hold_conference(selectedConf);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
500
501
}

502
void
503
sflphone_off_hold()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
504
{
505
    DEBUG("sflphone_off_hold");
Tristan Matthews's avatar
Tristan Matthews committed
506
507
    callable_obj_t * selectedCall = calltab_get_selected_call(current_calls_tab);
    conference_obj_t * selectedConf = calltab_get_selected_conf(active_calltree_tab);
508

509
510
    if (selectedCall) {
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
511
            case CALL_STATE_HOLD:
512
                dbus_unhold(selectedCall);
Emmanuel Milou's avatar
Emmanuel Milou committed
513
514
                break;
            default:
515
                WARN("Should not happen in sflphone_off_hold ()!");
Emmanuel Milou's avatar
Emmanuel Milou committed
516
517
                break;
        }
518
    } else if (selectedConf)
519
        dbus_unhold_conference(selectedConf);
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
520
521
522
}


523
void
524
sflphone_fail(callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
525
{
526
    c->_state = CALL_STATE_FAILURE;
Tristan Matthews's avatar
Tristan Matthews committed
527
    calltree_update_call(current_calls_tab, c);
528
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
529
530
}

531
void
532
sflphone_busy(callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
533
{
534
    c->_state = CALL_STATE_BUSY;
Tristan Matthews's avatar
Tristan Matthews committed
535
    calltree_update_call(current_calls_tab, c);
536
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
537
538
}

539
void
540
sflphone_current(callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
541
{
542
    if (c->_state != CALL_STATE_HOLD)
543
        time(&c->_time_start);
544

545
    c->_state = CALL_STATE_CURRENT;
Tristan Matthews's avatar
Tristan Matthews committed
546
    calltree_update_call(current_calls_tab, c);
547
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
548
549
}

550
void
551
sflphone_record(callable_obj_t * c)
alexandresavard's avatar
alexandresavard committed
552
{
553
    if (c->_state != CALL_STATE_HOLD)
554
        time(&c->_time_start);
555

556
    c->_state = CALL_STATE_RECORD;
Tristan Matthews's avatar
Tristan Matthews committed
557
    calltree_update_call(current_calls_tab, c);
558
    update_actions();
alexandresavard's avatar
alexandresavard committed
559
560
}

561
void
562
sflphone_set_transfer()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
563
{
Tristan Matthews's avatar
Tristan Matthews committed
564
    callable_obj_t * c = calltab_get_selected_call(current_calls_tab);
565
566

    if (c) {
567
        c->_state = CALL_STATE_TRANSFER;
Tristan Matthews's avatar
Tristan Matthews committed
568
        g_free(c->_trsft_to);
569
        c->_trsft_to = g_strdup("");
Tristan Matthews's avatar
Tristan Matthews committed
570
        calltree_update_call(current_calls_tab, c);
Emmanuel Milou's avatar
Emmanuel Milou committed
571
    }
572

573
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
574
575
}

576
void
577
sflphone_unset_transfer()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
578
{
Tristan Matthews's avatar
Tristan Matthews committed
579
    callable_obj_t * c = calltab_get_selected_call(current_calls_tab);
580
581

    if (c) {
582
        c->_state = CALL_STATE_CURRENT;
Tristan Matthews's avatar
Tristan Matthews committed
583
        g_free(c->_trsft_to);
584
        c->_trsft_to = g_strdup("");
Tristan Matthews's avatar
Tristan Matthews committed
585
        calltree_update_call(current_calls_tab, c);
Emmanuel Milou's avatar
Emmanuel Milou committed
586
    }
587

588
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
589
}
Emmanuel Milou's avatar
Emmanuel Milou committed
590

591
void
592
sflphone_display_transfer_status(const gchar* message)
593
{
594
    statusbar_push_message(message , NULL, __MSG_ACCOUNT_DEFAULT);
595
596
}

597
void
598
sflphone_incoming_call(callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
599
{
600
    c->_history_state = MISSED;
Tristan Matthews's avatar
Tristan Matthews committed
601
602
    calllist_add_call(current_calls_tab, c);
    calltree_add_call(current_calls_tab, c, NULL);
603

604
    update_actions();
Tristan Matthews's avatar
Tristan Matthews committed
605
    calltree_display(current_calls_tab);
606
607

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

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

623
    switch (keyval) {
624
625
        case GDK_Return:
        case GDK_KP_Enter:
626
            sflphone_place_call(c);
Emmanuel Milou's avatar
Emmanuel Milou committed
627
            break;
628
        case GDK_Escape:
629
            sflphone_hang_up();
Emmanuel Milou's avatar
Emmanuel Milou committed
630
            break;
631
        case GDK_BackSpace: {
632
633
            gchar *num = (c->_state == CALL_STATE_TRANSFER) ? c->_trsft_to : c->_peer_number;
            size_t len = strlen(num);
634

635
636
637
            if (len) {
                len--; // delete one character
                num[len] = '\0';
Tristan Matthews's avatar
Tristan Matthews committed
638
                calltree_update_call(current_calls_tab, c);
639

640
                /* If number is now empty, hang up immediately */
641
                if (c->_state != CALL_STATE_TRANSFER && len == 0)
642
                    dbus_hang_up(c);
Emmanuel Milou's avatar
Emmanuel Milou committed
643
            }
644

645
            break;
646
        }
647
648
649
650
651
        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
652
653
            break;
        default:
654

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

658
                if (c->_state == CALL_STATE_TRANSFER) {
659
660
                    gchar *new_trsft = g_strconcat(c->_trsft_to, key, NULL);
                    g_free(c->_trsft_to);
Tristan Matthews's avatar
Tristan Matthews committed
661
                    c->_trsft_to = new_trsft;
662
                } else {
663
664
665
                    dbus_play_dtmf(key);
                    gchar *new_peer_number = g_strconcat(c->_peer_number, key, NULL);
                    g_free(c->_peer_number);
Tristan Matthews's avatar
Tristan Matthews committed
666
                    c->_peer_number = new_peer_number;
Emmanuel Milou's avatar
Emmanuel Milou committed
667
                }
668

Tristan Matthews's avatar
Tristan Matthews committed
669
                calltree_update_call(current_calls_tab, c);
Emmanuel Milou's avatar
Emmanuel Milou committed
670
            }
671

Emmanuel Milou's avatar
Emmanuel Milou committed
672
673
            break;
    }
674
675
}

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

677
callable_obj_t *
areversat's avatar
areversat committed
678
sflphone_new_call()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
679
{
Tristan Matthews's avatar
Tristan Matthews committed
680
    callable_obj_t *current_selected_call = calltab_get_selected_call(current_calls_tab);
681

682
    if ((current_selected_call != NULL) && (current_selected_call->_confID == NULL))
683
        sflphone_on_hold();
684

Emmanuel Milou's avatar
Emmanuel Milou committed
685
    // Play a tone when creating a new call
Tristan Matthews's avatar
Tristan Matthews committed
686
    if (calllist_get_size(current_calls_tab) == 0)
687
        dbus_start_tone(TRUE , (current_account_has_new_message()  > 0) ? TONE_WITH_MESSAGE : TONE_WITHOUT_MESSAGE) ;