actions.c 41.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
#include <gdk/gdkkeysyms.h>
34
35
#include <glib/gprintf.h>
#include <stdlib.h>
36
#include <string.h>
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
37
38
#include <sys/types.h>
#include <unistd.h>
39
#include <assert.h>
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
40

41
#include <arpa/nameser.h>
42
#include <netinet/in.h>
43
44
#include <resolv.h>

45
#include <linux/if.h>
46
47
48
49
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>

50
51
52
53
54
55
56
57
58
#include "actions.h"
#include "dbus/dbus.h"
#include "contacts/searchbar.h"
#include "contacts/addrbookfactory.h"
#include "icons/icon_factory.h"
#include "imwindow.h"
#include "statusicon.h"
#include "widget/imwidget.h"

59

60
static GHashTable * ip2ip_profile=NULL;
61

62
static gchar ** sflphone_order_history_hash_table(GHashTable *result)
63
64
{
    GHashTableIter iter;
65
66
    gint size = 0;
    gchar **ordered_list = NULL;
67

68
    assert(result);
69
    while (g_hash_table_size (result)) {
70
        gpointer key, key_to_min, value;
71
72
73
74

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

75
        gint min_timestamp = G_MAXINT;
76
        while (g_hash_table_iter_next (&iter, &key, &value))  {
77
78
            gint timestamp = atoi ( (gchar*) key);
            if (timestamp < min_timestamp) {
79
80
81
82
83
                min_timestamp = timestamp;
                key_to_min = key;
            }
        }

Tristan Matthews's avatar
Tristan Matthews committed
84
85
86
87
88
89
90
91
92
        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);
93
94
95
        }
    }

96
97
    ordered_list = (void *) g_realloc(ordered_list, (size + 1) * sizeof(void *));
    *(ordered_list + size) = NULL;
98

99
    return ordered_list;
100
101
}

102
void
103
sflphone_notify_voice_mail (const gchar* accountID , guint count)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
104
{
105
    // We want to notify only the current account; ie the first in the list
106
107
    gchar *id = g_strdup (accountID);
    const gchar * const current_id = account_list_get_current_id ();
108

Julien Bonjean's avatar
Julien Bonjean committed
109
    DEBUG ("sflphone_notify_voice_mail begin");
110

111
    if (g_ascii_strcasecmp (id, current_id) != 0 || account_list_get_size() == 0)
112
113
        return;

114
115
    // Set the number of voice messages for the current account
    current_account_set_message_number (count);
116
    account_t *current = account_list_get_current ();
117

118
119
    // Update the voicemail tool button
    update_voicemail_status ();
Emmanuel Milou's avatar
Emmanuel Milou committed
120

121
122
    if (current)
        notify_voice_mails (count, current);
Emmanuel Milou's avatar
Emmanuel Milou committed
123

Julien Bonjean's avatar
Julien Bonjean committed
124
    DEBUG ("sflphone_notify_voice_mail end");
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
125
126
}

127
128
129
130
131
132
133
/*
 * 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
 */

134
135
136
137
138
139
static gboolean _is_direct_call (callable_obj_t * c)
{
    if (g_strcasecmp (c->_accountID, EMPTY_ENTRY) == 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);
140
141
            c->_peer_number = new_number;
        }
142

143
        return TRUE;
Alexandre Savard's avatar
Alexandre Savard committed
144
145
    }

146
147
    return g_str_has_prefix (c->_peer_number, "sip:") ||
           g_str_has_prefix (c->_peer_number, "sips:");
148
149
150
}


151
void
152
status_bar_display_account ()
153
{
154
    gchar* msg;
155

156
    statusbar_pop_message (__MSG_ACCOUNT_DEFAULT);
157

158
159
    account_t *acc = account_list_get_current ();
    status_tray_icon_online (acc != NULL);
160
161
162
163
164
165
166
167

    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"));
168
    }
169

Julien Bonjean's avatar
Julien Bonjean committed
170
    statusbar_push_message (msg, NULL,  __MSG_ACCOUNT_DEFAULT);
171
    g_free (msg);
172
173
}

Emmanuel Milou's avatar
Emmanuel Milou committed
174

175
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
176
177
sflphone_quit ()
{
178
    if (calllist_get_size(current_calls) == 0 || main_window_ask_quit()) {
179
        // Save the history
180
181
        sflphone_save_history ();

182
        dbus_unregister (getpid());
Emmanuel Milou's avatar
Emmanuel Milou committed
183
        dbus_clean ();
Vivien Didelot's avatar
Vivien Didelot committed
184
185
186
        calllist_clean (current_calls);
        calllist_clean (contacts);
        calllist_clean (history);
Emmanuel Milou's avatar
Emmanuel Milou committed
187
188
        gtk_main_quit ();
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
189
190
}

191
192
void
sflphone_hold (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
193
{
194
    c->_state = CALL_STATE_HOLD;
195
    calltree_update_call (current_calls, c, NULL);
196
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
197
198
}

199
200
void
sflphone_ringing (callable_obj_t * c)
201
{
202
    c->_state = CALL_STATE_RINGING;
203
    calltree_update_call (current_calls, c, NULL);
204
    update_actions();
205
}
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
206

207
208
void
sflphone_hung_up (callable_obj_t * c)
Emmanuel Milou's avatar
Emmanuel Milou committed
209
{
Julien Bonjean's avatar
Julien Bonjean committed
210
    DEBUG ("SFLphone: Hung up");
211

212
    calllist_remove_call (current_calls, c->_callID);
213
    calltree_remove_call (current_calls, c, NULL);
214
    c->_state = CALL_STATE_DIALING;
215
    call_remove_all_errors (c);
216
    update_actions();
217

218
219
220
221
222
    if(c->_confID) {
	g_free(c->_confID);
	c->_confID = NULL;
    }

223
224
225
226
227
    // 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);
228

229
#if GTK_CHECK_VERSION(2,10,0)
230
    status_tray_icon_blink (FALSE);
231
#endif
232

233
    statusbar_update_clock("");
234
235
}

Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
236
/** Internal to actions: Fill account list */
237
238
void sflphone_fill_account_list (void)
{
239
240
241
242

    gchar** array;
    gchar** accountID;
    unsigned int i;
243
    int count;
244

245
    DEBUG ("SFLphone: Fill account list");
246

247
    count = current_account_get_message_number ();
248

Emmanuel Milou's avatar
Emmanuel Milou committed
249
    account_list_clear ();
250

251
252
253
    array = (gchar **) dbus_account_list();

    if (array) {
Julien Bonjean's avatar
Julien Bonjean committed
254

255
256
257
        for (accountID = array; *accountID; accountID++) {
            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 (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
        gchar * code = NULL;
310
311
        code = g_hash_table_lookup (details, REGISTRATION_STATE_CODE);

312
        if (code != NULL) {
313
            a->protocol_state_code = atoi (code);
314
        }
315
316
317

        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
318
319
    }

320
321
    // Set the current account message number
    current_account_set_message_number (count);
322

323
    sflphone_fill_codec_list ();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
324
325
}

326
gboolean sflphone_init (GError **error)
327
{
328
    if (!dbus_connect (error) || !dbus_register (getpid (), "Gtk+ Client", error))
329
        return FALSE;
330
331

    abookfactory_init_factory();
332

333
334
    // Init icons factory
    init_icon_factory ();
335

336
337
338
    current_calls = calltab_init (FALSE, CURRENT_CALLS);
    contacts = calltab_init (TRUE, CONTACTS);
    history = calltab_init (TRUE, HISTORY);
339

340
341
    account_list_init ();
    codec_capabilities_load ();
342
343
    conferencelist_init (current_calls);
    conferencelist_init (history);
344

345
346
    // Fetch the configured accounts
    sflphone_fill_account_list ();
347

348
349
    // Fetch the ip2ip profile
    sflphone_fill_ip2ip_profile();
350

351
352
    // Fetch the conference list
    // sflphone_fill_conference_list();
353

354
    return TRUE;
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
355
356
}

357
void sflphone_fill_ip2ip_profile (void)
358
359
360
361
{
    ip2ip_profile = (GHashTable *) dbus_get_ip2_ip_details();
}

362
GHashTable *sflphone_get_ip2ip_properties(void)
363
{
364
    return ip2ip_profile;
365
366
}

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

Julien Bonjean's avatar
Julien Bonjean committed
373
    DEBUG ("SFLphone: Hang up");
374

375
376
    if (selectedCall) {
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
377
378
379
380
381
            case CALL_STATE_DIALING:
                dbus_hang_up (selectedCall);
                break;
            case CALL_STATE_RINGING:
                dbus_hang_up (selectedCall);
382
                call_remove_all_errors (selectedCall);
383
384
                selectedCall->_state = CALL_STATE_DIALING;
                //selectedCall->_stop = 0;
Emmanuel Milou's avatar
Emmanuel Milou committed
385
386
387
388
                break;
            case CALL_STATE_CURRENT:
            case CALL_STATE_HOLD:
            case CALL_STATE_BUSY:
389
            case CALL_STATE_RECORD:
Emmanuel Milou's avatar
Emmanuel Milou committed
390
                dbus_hang_up (selectedCall);
391
                call_remove_all_errors (selectedCall);
392
                selectedCall->_state = CALL_STATE_DIALING;
393
                time (&selectedCall->_time_stop);
394
395
396
397
398

                //if ( (im_window_get_nb_tabs() > 1) && selectedCall->_im_widget &&
                //        ! (IM_WIDGET (selectedCall->_im_widget)->containText))
                //    im_window_remove_tab (selectedCall->_im_widget);
                //else
399
                im_widget_update_state (IM_WIDGET (selectedCall->_im_widget), FALSE);
400

Emmanuel Milou's avatar
Emmanuel Milou committed
401
402
403
                break;
            case CALL_STATE_FAILURE:
                dbus_hang_up (selectedCall);
404
                call_remove_all_errors (selectedCall);
405
                selectedCall->_state = CALL_STATE_DIALING;
Emmanuel Milou's avatar
Emmanuel Milou committed
406
407
408
                break;
            case CALL_STATE_INCOMING:
                dbus_refuse (selectedCall);
409
                call_remove_all_errors (selectedCall);
410
                selectedCall->_state = CALL_STATE_DIALING;
411
412
                DEBUG ("from sflphone_hang_up : ");
                stop_notification();
Emmanuel Milou's avatar
Emmanuel Milou committed
413
414
415
                break;
            case CALL_STATE_TRANSFERT:
                dbus_hang_up (selectedCall);
416
                call_remove_all_errors (selectedCall);
417
                time (&selectedCall->_time_stop);
Emmanuel Milou's avatar
Emmanuel Milou committed
418
419
                break;
            default:
420
                WARN ("Should not happen in sflphone_hang_up()!");
Emmanuel Milou's avatar
Emmanuel Milou committed
421
422
                break;
        }
423
    } else if (selectedConf) {
424
        im_widget_update_state (IM_WIDGET (selectedConf->_im_widget), FALSE);
425
        dbus_hang_up_conference (selectedConf);
426
427
    }

428
    calltree_update_call (history, selectedCall, NULL);
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()
{
436
    callable_obj_t *selectedCall = calltab_get_selected_call (active_calltree);
437

438
439
    DEBUG("SFLphone: Pick up");

440
441
442
443
444
445
446
    if (!selectedCall) {
        sflphone_new_call();
        return;
    }
    switch (selectedCall->_state) {
        case CALL_STATE_DIALING:
            sflphone_place_call (selectedCall);
447

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

452
453
454
455
            break;
        case CALL_STATE_INCOMING:
            selectedCall->_history_state = INCOMING;
            calltree_update_call (history, selectedCall, NULL);
456

457
458
459
460
            // if instant messaging window is visible, create new tab (deleted automatically if not used)
            if (selectedCall->_im_widget && im_window_is_visible()) {
                im_widget_display ( (IMWidget **) (&selectedCall->_im_widget), NULL, selectedCall->_callID, NULL);
            }
461

462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
            dbus_accept (selectedCall);
            stop_notification();
            break;
        case CALL_STATE_TRANSFERT:
            dbus_transfert (selectedCall);
            time (&selectedCall->_time_stop);
            calltree_remove_call(current_calls, selectedCall, NULL);
            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;
480
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
481
482
}

483
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
484
485
sflphone_on_hold ()
{
486
487
    callable_obj_t * selectedCall = calltab_get_selected_call (current_calls);
    conference_obj_t * selectedConf = calltab_get_selected_conf (active_calltree);
488

489
490
491
492
    DEBUG ("sflphone_on_hold");

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

508
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
509
510
sflphone_off_hold ()
{
511
512
513
    DEBUG ("sflphone_off_hold");
    callable_obj_t * selectedCall = calltab_get_selected_call (current_calls);
    conference_obj_t * selectedConf = calltab_get_selected_conf (active_calltree);
514

515
516
    if (selectedCall) {
        switch (selectedCall->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
517
518
519
520
            case CALL_STATE_HOLD:
                dbus_unhold (selectedCall);
                break;
            default:
521
                WARN ("Should not happen in sflphone_off_hold ()!");
Emmanuel Milou's avatar
Emmanuel Milou committed
522
523
                break;
        }
524
525
    } else if (selectedConf) {

Julien Bonjean's avatar
Julien Bonjean committed
526

527
        dbus_unhold_conference (selectedConf);
528
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
529
530
531
}


532
533
void
sflphone_fail (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
534
{
535
    c->_state = CALL_STATE_FAILURE;
536
    calltree_update_call (current_calls, c, NULL);
537
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
538
539
}

540
541
void
sflphone_busy (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
542
{
543
    c->_state = CALL_STATE_BUSY;
544
    calltree_update_call (current_calls, c, NULL);
545
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
546
547
}

548
549
void
sflphone_current (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
550
{
551

552
    if (c->_state != CALL_STATE_HOLD)
553
        time (&c->_time_start);
554

555
    c->_state = CALL_STATE_CURRENT;
556
    calltree_update_call (current_calls, c, NULL);
557
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
558
559
}

560
561
void
sflphone_record (callable_obj_t * c)
alexandresavard's avatar
alexandresavard committed
562
{
563
    if (c->_state != CALL_STATE_HOLD)
564
        time (&c->_time_start);
565

566
    c->_state = CALL_STATE_RECORD;
567
    calltree_update_call (current_calls, c, NULL);
568
    update_actions();
alexandresavard's avatar
alexandresavard committed
569
570
}

571
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
572
sflphone_set_transfert()
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_TRANSFERT;
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
585
}

586
void
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
587
588
sflphone_unset_transfert()
{
589
590
591
    callable_obj_t * c = calltab_get_selected_call (current_calls);

    if (c) {
592
        c->_state = CALL_STATE_CURRENT;
Tristan Matthews's avatar
Tristan Matthews committed
593
        g_free(c->_trsft_to);
594
595
        c->_trsft_to = g_strdup ("");
        calltree_update_call (current_calls, c, NULL);
Emmanuel Milou's avatar
Emmanuel Milou committed
596
    }
597

598
    update_actions();
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
599
}
Emmanuel Milou's avatar
Emmanuel Milou committed
600

601
602
void
sflphone_display_transfer_status (const gchar* message)
603
{
Julien Bonjean's avatar
Julien Bonjean committed
604
    statusbar_push_message (message , NULL, __MSG_ACCOUNT_DEFAULT);
605
606
}

607
void
608
sflphone_incoming_call (callable_obj_t * c)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
609
{
610
    c->_history_state = MISSED;
611
    calllist_add_call (current_calls, c);
612
    calltree_add_call (current_calls, c, NULL);
613

614
    update_actions();
Julien Bonjean's avatar
Julien Bonjean committed
615
    calltree_display (current_calls);
616
617
618

    // Change the status bar if we are dealing with a direct SIP call
    if (_is_direct_call (c)) {
619
        gchar *msg = g_markup_printf_escaped (_ ("Direct SIP call"));
620
        statusbar_pop_message (__MSG_ACCOUNT_DEFAULT);
Julien Bonjean's avatar
Julien Bonjean committed
621
        statusbar_push_message (msg , NULL, __MSG_ACCOUNT_DEFAULT);
622
623
        g_free (msg);
    }
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
624
}
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
625

626
void
627
process_dialing (callable_obj_t *c, guint keyval, gchar *key)
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
628
{
Emmanuel Milou's avatar
Emmanuel Milou committed
629
    // We stop the tone
630
    if (!*c->_peer_number && c->_state != CALL_STATE_TRANSFERT)
631
        dbus_start_tone (FALSE , 0);
632

633
    switch (keyval) {
634
635
        case GDK_KEY_Return:
        case GDK_KEY_KP_Enter:
636
            sflphone_place_call (c);
Emmanuel Milou's avatar
Emmanuel Milou committed
637
            break;
638
        case GDK_KEY_Escape:
Rafaël Carré's avatar
Rafaël Carré committed
639
            sflphone_hang_up ();
Emmanuel Milou's avatar
Emmanuel Milou committed
640
            break;
641
642
643
644
        case GDK_KEY_BackSpace:
            if (c->_state == CALL_STATE_TRANSFERT) {
                if (*c->_trsft_to)
                    c->_trsft_to[strlen (c->_trsft_to) - 1] = '\0';
645
                calltree_update_call (current_calls, c, NULL);
646
647
648
649
650
651
652
            } else {
                if (*c->_peer_number) {
                  c->_peer_number[strlen (c->_peer_number) -1] = '\0';
                  calltree_update_call (current_calls, c, NULL);
                }
                else
                  dbus_hang_up(c);
Emmanuel Milou's avatar
Emmanuel Milou committed
653
            }
654
655
656
657
658
659
660

            break;
        case GDK_KEY_Tab:
        case GDK_KEY_Alt_L:
        case GDK_KEY_Control_L:
        case GDK_KEY_Super_L:
        case GDK_KEY_Caps_Lock:
Emmanuel Milou's avatar
Emmanuel Milou committed
661
662
            break;
        default:
663

664
665
            if (keyval < 127 /* ascii */ ||
               (keyval >= GDK_KEY_Mode_switch && keyval <= GDK_KEY_KP_9) /* num keypad */) {
Emmanuel Milou's avatar
Emmanuel Milou committed
666

667
                if (c->_state == CALL_STATE_TRANSFERT) {
Tristan Matthews's avatar
Tristan Matthews committed
668
669
670
                    gchar *new_trsft = g_strconcat (c->_trsft_to, key, NULL);
                    g_free (c->_trsft_to);
                    c->_trsft_to = new_trsft;
671
672
                } else {
                    dbus_play_dtmf (key);
Tristan Matthews's avatar
Tristan Matthews committed
673
674
675
                    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
676
                }
677
678

                calltree_update_call (current_calls, c, NULL);
Emmanuel Milou's avatar
Emmanuel Milou committed
679
            }
680

Emmanuel Milou's avatar
Emmanuel Milou committed
681
682
            break;
    }
683
684
}

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

686
callable_obj_t *
areversat's avatar
areversat committed
687
sflphone_new_call()
Pierre-Luc Beaudoin's avatar
Pierre-Luc Beaudoin committed
688
{
Tristan Matthews's avatar
Tristan Matthews committed
689
    callable_obj_t *current_selected_call = calltab_get_selected_call (current_calls);
690

691
692
    if ( (current_selected_call != NULL) && (current_selected_call->_confID == NULL))
        sflphone_on_hold();
693

Emmanuel Milou's avatar
Emmanuel Milou committed
694
    // Play a tone when creating a new call
695
696
    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
697

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

700
701
    c->_history_state = OUTGOING;

Alexandre Savard's avatar
Alexandre Savard committed
702
    calllist_add_call (current_calls, c);
703
    calltree_add_call (current_calls, c, NULL);
704
    update_actions();
705

Emmanuel Milou's avatar
Emmanuel Milou committed
706
    return c;
707
708
}

areversat's avatar
areversat committed
709

710
711
void
sflphone_keypad (guint keyval, gchar * key)
areversat's avatar
areversat committed
712
{
713
714
715
716
    callable_obj_t * c = calltab_get_selected_call (current_calls);

    if ( (active_calltree != current_calls) || (active_calltree == current_calls && !c)) {
        switch (keyval) {
717
718
719
            case GDK_KEY_Return:
            case GDK_KEY_KP_Enter:
            case GDK_KEY_Escape:
Emmanuel Milou's avatar
Emmanuel Milou committed
720
721
                break;
            default:
Julien Bonjean's avatar
Julien Bonjean committed
722
                calltree_display (current_calls);
723
                process_dialing (sflphone_new_call(), keyval, key);
Emmanuel Milou's avatar
Emmanuel Milou committed
724
725
                break;
        }
726
727
    } else if (c) {
        switch (c->_state) {
Emmanuel Milou's avatar
Emmanuel Milou committed
728
            case CALL_STATE_DIALING: // Currently dialing => edit number
729
                process_dialing (c, keyval, key);
Emmanuel Milou's avatar
Emmanuel Milou committed
730
731
732
                break;
            case CALL_STATE_RECORD:
            case CALL_STATE_CURRENT:
733
734

                switch (keyval) {
735
                    case GDK_KEY_Escape:
736
                        dbus_hang_up (c);
737
                        time (&c->_time_stop);
738
                        calltree_update_call (history, c, NULL);
Emmanuel Milou's avatar
Emmanuel Milou committed
739
740
741
                        break;
                    default:
                        // To play the dtmf when calling mail box for instance
742
                        dbus_play_dtmf (key);
Emmanuel Milou's avatar
Emmanuel Milou committed
743
744
                        break;
                }
745

Emmanuel Milou's avatar
Emmanuel Milou committed
746
747
                break;
            case CALL_STATE_INCOMING:
748
749

                switch (keyval) {
750
751
                    case GDK_KEY_Return:
                    case GDK_KEY_KP_Enter:
752
                        c->_history_state = INCOMING;
753
754
755
                        calltree_update_call (history, c, NULL);
                        dbus_accept (c);
                        stop_notification();
Emmanuel Milou's avatar
Emmanuel Milou committed
756
                        break;
757
                    case GDK_KEY_Escape:
758
759
                        dbus_refuse (c);
                        stop_notification();
Emmanuel Milou's avatar
Emmanuel Milou committed
760
761
                        break;
                }
762

Emmanuel Milou's avatar
Emmanuel Milou committed
763
764
                break;
            case CALL_STATE_TRANSFERT:
765
766

                switch (keyval) {
767
768
                    case GDK_KEY_Return:
                    case GDK_KEY_KP_Enter:
769
                        dbus_transfert (c);
770
                        time (&c->_time_stop);
771
                        calltree_remove_call(current_calls, c, NULL);
Emmanuel Milou's avatar
Emmanuel Milou committed
772
                        break;
773
                    case GDK_KEY_Escape:
Rafaël Carré's avatar
Rafaël Carré committed
774
                        sflphone_unset_transfert ();