~ubuntu-branches/ubuntu/trusty/bluez/trusty

« back to all changes in this revision

Viewing changes to .pc/telephony_ofono_add_watch.patch/audio/telephony-ofono.c

  • Committer: Package Import Robot
  • Author(s): Mathieu Trudel-Lapierre
  • Date: 2013-12-19 21:36:00 UTC
  • Revision ID: package-import@ubuntu.com-20131219213600-4g6ut812p970tp2u
Tags: 4.101-0ubuntu10
* debian/patches/telephony_ofono_add_watch.patch: fix telephony-ofono code
  to have the add_watch function not be conditioned out, since it's used.
* debian/rules: explicitly specify to use ofono a the telephony service. 
* debian/bluez.dirs: add /var/lib/bluetooth, we need to have it created
  on Ubuntu Touch so that discovery writes cache data for classes, seen
  addresses, etc. (LP: #1234361)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *
 
3
 *  BlueZ - Bluetooth protocol stack for Linux
 
4
 *
 
5
 *  Copyright (C) 2009-2010  Intel Corporation
 
6
 *  Copyright (C) 2006-2009  Nokia Corporation
 
7
 *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
8
 *
 
9
 *
 
10
 *  This program is free software; you can redistribute it and/or modify
 
11
 *  it under the terms of the GNU General Public License as published by
 
12
 *  the Free Software Foundation; either version 2 of the License, or
 
13
 *  (at your option) any later version.
 
14
 *
 
15
 *  This program is distributed in the hope that it will be useful,
 
16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 *  GNU General Public License for more details.
 
19
 *
 
20
 *  You should have received a copy of the GNU General Public License
 
21
 *  along with this program; if not, write to the Free Software
 
22
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
23
 *
 
24
 */
 
25
 
 
26
#ifdef HAVE_CONFIG_H
 
27
#include <config.h>
 
28
#endif
 
29
 
 
30
#include <stdlib.h>
 
31
#include <stdio.h>
 
32
#include <string.h>
 
33
#include <stdint.h>
 
34
#include <glib.h>
 
35
#include <dbus/dbus.h>
 
36
#include <gdbus.h>
 
37
 
 
38
#include <bluetooth/sdp.h>
 
39
 
 
40
#include "log.h"
 
41
#include "telephony.h"
 
42
 
 
43
enum net_registration_status {
 
44
        NETWORK_REG_STATUS_HOME = 0x00,
 
45
        NETWORK_REG_STATUS_ROAM,
 
46
        NETWORK_REG_STATUS_NOSERV
 
47
};
 
48
 
 
49
struct voice_call {
 
50
        char *obj_path;
 
51
        int status;
 
52
        gboolean originating;
 
53
        gboolean conference;
 
54
        char *number;
 
55
        guint watch;
 
56
};
 
57
 
 
58
static DBusConnection *connection = NULL;
 
59
static char *modem_obj_path = NULL;
 
60
static char *last_dialed_number = NULL;
 
61
static GSList *calls = NULL;
 
62
static GSList *watches = NULL;
 
63
static GSList *pending = NULL;
 
64
 
 
65
#define OFONO_BUS_NAME "org.ofono"
 
66
#define OFONO_PATH "/"
 
67
#define OFONO_MODEM_INTERFACE "org.ofono.Modem"
 
68
#define OFONO_MANAGER_INTERFACE "org.ofono.Manager"
 
69
#define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration"
 
70
#define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
 
71
#define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
 
72
 
 
73
/* HAL battery namespace key values */
 
74
static int battchg_cur = -1;    /* "battery.charge_level.current" */
 
75
static int battchg_last = -1;   /* "battery.charge_level.last_full" */
 
76
static int battchg_design = -1; /* "battery.charge_level.design" */
 
77
 
 
78
static struct {
 
79
        uint8_t status;
 
80
        uint32_t signals_bar;
 
81
        char *operator_name;
 
82
} net = {
 
83
        .status = NETWORK_REG_STATUS_NOSERV,
 
84
        .signals_bar = 0,
 
85
        .operator_name = NULL,
 
86
};
 
87
 
 
88
static const char *chld_str = "0,1,1x,2,2x,3,4";
 
89
static char *subscriber_number = NULL;
 
90
 
 
91
static gboolean events_enabled = FALSE;
 
92
 
 
93
static struct indicator ofono_indicators[] =
 
94
{
 
95
        { "battchg",    "0-5",  5,      TRUE },
 
96
        { "signal",     "0-5",  5,      TRUE },
 
97
        { "service",    "0,1",  1,      TRUE },
 
98
        { "call",       "0,1",  0,      TRUE },
 
99
        { "callsetup",  "0-3",  0,      TRUE },
 
100
        { "callheld",   "0-2",  0,      FALSE },
 
101
        { "roam",       "0,1",  0,      TRUE },
 
102
        { NULL }
 
103
};
 
104
 
 
105
static struct voice_call *find_vc(const char *path)
 
106
{
 
107
        GSList *l;
 
108
 
 
109
        for (l = calls; l != NULL; l = l->next) {
 
110
                struct voice_call *vc = l->data;
 
111
 
 
112
                if (g_str_equal(vc->obj_path, path))
 
113
                        return vc;
 
114
        }
 
115
 
 
116
        return NULL;
 
117
}
 
118
 
 
119
static struct voice_call *find_vc_with_status(int status)
 
120
{
 
121
        GSList *l;
 
122
 
 
123
        for (l = calls; l != NULL; l = l->next) {
 
124
                struct voice_call *vc = l->data;
 
125
 
 
126
                if (vc->status == status)
 
127
                        return vc;
 
128
        }
 
129
 
 
130
        return NULL;
 
131
}
 
132
 
 
133
static struct voice_call *find_vc_without_status(int status)
 
134
{
 
135
        GSList *l;
 
136
 
 
137
        for (l = calls; l != NULL; l = l->next) {
 
138
                struct voice_call *call = l->data;
 
139
 
 
140
                if (call->status != status)
 
141
                        return call;
 
142
        }
 
143
 
 
144
        return NULL;
 
145
}
 
146
 
 
147
static int number_type(const char *number)
 
148
{
 
149
        if (number == NULL)
 
150
                return NUMBER_TYPE_TELEPHONY;
 
151
 
 
152
        if (number[0] == '+' || strncmp(number, "00", 2) == 0)
 
153
                return NUMBER_TYPE_INTERNATIONAL;
 
154
 
 
155
        return NUMBER_TYPE_TELEPHONY;
 
156
}
 
157
 
 
158
void telephony_device_connected(void *telephony_device)
 
159
{
 
160
        struct voice_call *coming;
 
161
 
 
162
        DBG("telephony-ofono: device %p connected", telephony_device);
 
163
 
 
164
        coming = find_vc_with_status(CALL_STATUS_ALERTING);
 
165
        if (coming) {
 
166
                if (find_vc_with_status(CALL_STATUS_ACTIVE))
 
167
                        telephony_call_waiting_ind(coming->number,
 
168
                                                number_type(coming->number));
 
169
                else
 
170
                        telephony_incoming_call_ind(coming->number,
 
171
                                                number_type(coming->number));
 
172
        }
 
173
}
 
174
 
 
175
void telephony_device_disconnected(void *telephony_device)
 
176
{
 
177
        DBG("telephony-ofono: device %p disconnected", telephony_device);
 
178
        events_enabled = FALSE;
 
179
}
 
180
 
 
181
void telephony_event_reporting_req(void *telephony_device, int ind)
 
182
{
 
183
        events_enabled = ind == 1 ? TRUE : FALSE;
 
184
 
 
185
        telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
 
186
}
 
187
 
 
188
void telephony_response_and_hold_req(void *telephony_device, int rh)
 
189
{
 
190
        telephony_response_and_hold_rsp(telephony_device,
 
191
                                                CME_ERROR_NOT_SUPPORTED);
 
192
}
 
193
 
 
194
void telephony_last_dialed_number_req(void *telephony_device)
 
195
{
 
196
        DBG("telephony-ofono: last dialed number request");
 
197
 
 
198
        if (last_dialed_number)
 
199
                telephony_dial_number_req(telephony_device, last_dialed_number);
 
200
        else
 
201
                telephony_last_dialed_number_rsp(telephony_device,
 
202
                                CME_ERROR_NOT_ALLOWED);
 
203
}
 
204
 
 
205
static int send_method_call(const char *dest, const char *path,
 
206
                                const char *interface, const char *method,
 
207
                                DBusPendingCallNotifyFunction cb,
 
208
                                void *user_data, int type, ...)
 
209
{
 
210
        DBusMessage *msg;
 
211
        DBusPendingCall *call;
 
212
        va_list args;
 
213
 
 
214
        msg = dbus_message_new_method_call(dest, path, interface, method);
 
215
        if (!msg) {
 
216
                error("Unable to allocate new D-Bus %s message", method);
 
217
                return -ENOMEM;
 
218
        }
 
219
 
 
220
        va_start(args, type);
 
221
 
 
222
        if (!dbus_message_append_args_valist(msg, type, args)) {
 
223
                dbus_message_unref(msg);
 
224
                va_end(args);
 
225
                return -EIO;
 
226
        }
 
227
 
 
228
        va_end(args);
 
229
 
 
230
        if (!cb) {
 
231
                g_dbus_send_message(connection, msg);
 
232
                return 0;
 
233
        }
 
234
 
 
235
        if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
 
236
                error("Sending %s failed", method);
 
237
                dbus_message_unref(msg);
 
238
                return -EIO;
 
239
        }
 
240
 
 
241
        dbus_pending_call_set_notify(call, cb, user_data, NULL);
 
242
        pending = g_slist_prepend(pending, call);
 
243
        dbus_message_unref(msg);
 
244
 
 
245
        return 0;
 
246
}
 
247
 
 
248
static int answer_call(struct voice_call *vc)
 
249
{
 
250
        DBG("%s", vc->number);
 
251
        return send_method_call(OFONO_BUS_NAME, vc->obj_path,
 
252
                                                OFONO_VC_INTERFACE, "Answer",
 
253
                                                NULL, NULL, DBUS_TYPE_INVALID);
 
254
}
 
255
 
 
256
static int release_call(struct voice_call *vc)
 
257
{
 
258
        DBG("%s", vc->number);
 
259
        return send_method_call(OFONO_BUS_NAME, vc->obj_path,
 
260
                                                OFONO_VC_INTERFACE, "Hangup",
 
261
                                                NULL, NULL, DBUS_TYPE_INVALID);
 
262
}
 
263
 
 
264
static int release_answer_calls(void)
 
265
{
 
266
        DBG("");
 
267
        return send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
268
                                                OFONO_VCMANAGER_INTERFACE,
 
269
                                                "ReleaseAndAnswer",
 
270
                                                NULL, NULL, DBUS_TYPE_INVALID);
 
271
}
 
272
 
 
273
static int split_call(struct voice_call *call)
 
274
{
 
275
        DBG("%s", call->number);
 
276
        return send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
277
                                                OFONO_VCMANAGER_INTERFACE,
 
278
                                                "PrivateChat",
 
279
                                                NULL, NULL,
 
280
                                                DBUS_TYPE_OBJECT_PATH,
 
281
                                                call->obj_path,
 
282
                                                DBUS_TYPE_INVALID);
 
283
        return -1;
 
284
}
 
285
 
 
286
static int swap_calls(void)
 
287
{
 
288
        DBG("");
 
289
        return send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
290
                                                OFONO_VCMANAGER_INTERFACE,
 
291
                                                "SwapCalls",
 
292
                                                NULL, NULL, DBUS_TYPE_INVALID);
 
293
}
 
294
 
 
295
static int create_conference(void)
 
296
{
 
297
        DBG("");
 
298
        return send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
299
                                                OFONO_VCMANAGER_INTERFACE,
 
300
                                                "CreateMultiparty",
 
301
                                                NULL, NULL, DBUS_TYPE_INVALID);
 
302
}
 
303
 
 
304
static int release_conference(void)
 
305
{
 
306
        DBG("");
 
307
        return send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
308
                                                OFONO_VCMANAGER_INTERFACE,
 
309
                                                "HangupMultiparty",
 
310
                                                NULL, NULL, DBUS_TYPE_INVALID);
 
311
}
 
312
 
 
313
static int call_transfer(void)
 
314
{
 
315
        DBG("");
 
316
        return send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
317
                                                OFONO_VCMANAGER_INTERFACE,
 
318
                                                "Transfer",
 
319
                                                NULL, NULL, DBUS_TYPE_INVALID);
 
320
}
 
321
 
 
322
void telephony_terminate_call_req(void *telephony_device)
 
323
{
 
324
        struct voice_call *call;
 
325
        struct voice_call *alerting;
 
326
        int err;
 
327
 
 
328
        call = find_vc_with_status(CALL_STATUS_ACTIVE);
 
329
        if (!call)
 
330
                call = calls->data;
 
331
 
 
332
        if (!call) {
 
333
                error("No active call");
 
334
                telephony_terminate_call_rsp(telephony_device,
 
335
                                                CME_ERROR_NOT_ALLOWED);
 
336
                return;
 
337
        }
 
338
 
 
339
        alerting = find_vc_with_status(CALL_STATUS_ALERTING);
 
340
        if (call->status == CALL_STATUS_HELD && alerting)
 
341
                err = release_call(alerting);
 
342
        else if (call->conference)
 
343
                err = release_conference();
 
344
        else
 
345
                err = release_call(call);
 
346
 
 
347
        if (err < 0)
 
348
                telephony_terminate_call_rsp(telephony_device,
 
349
                                                CME_ERROR_AG_FAILURE);
 
350
        else
 
351
                telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
 
352
}
 
353
 
 
354
void telephony_answer_call_req(void *telephony_device)
 
355
{
 
356
        struct voice_call *vc;
 
357
        int ret;
 
358
 
 
359
        vc = find_vc_with_status(CALL_STATUS_INCOMING);
 
360
        if (!vc)
 
361
                vc = find_vc_with_status(CALL_STATUS_ALERTING);
 
362
 
 
363
        if (!vc)
 
364
                vc = find_vc_with_status(CALL_STATUS_WAITING);
 
365
 
 
366
        if (!vc) {
 
367
                telephony_answer_call_rsp(telephony_device,
 
368
                                        CME_ERROR_NOT_ALLOWED);
 
369
                return;
 
370
        }
 
371
 
 
372
        ret = answer_call(vc);
 
373
        if (ret < 0) {
 
374
                telephony_answer_call_rsp(telephony_device,
 
375
                                        CME_ERROR_AG_FAILURE);
 
376
                return;
 
377
        }
 
378
 
 
379
        telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
 
380
}
 
381
 
 
382
void telephony_dial_number_req(void *telephony_device, const char *number)
 
383
{
 
384
        const char *clir;
 
385
        int ret;
 
386
 
 
387
        DBG("telephony-ofono: dial request to %s", number);
 
388
 
 
389
        if (!modem_obj_path) {
 
390
                telephony_dial_number_rsp(telephony_device,
 
391
                                        CME_ERROR_AG_FAILURE);
 
392
                return;
 
393
        }
 
394
 
 
395
        if (!strncmp(number, "*31#", 4)) {
 
396
                number += 4;
 
397
                clir = "enabled";
 
398
        } else if (!strncmp(number, "#31#", 4)) {
 
399
                number += 4;
 
400
                clir =  "disabled";
 
401
        } else
 
402
                clir = "default";
 
403
 
 
404
        ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
405
                        OFONO_VCMANAGER_INTERFACE,
 
406
                        "Dial", NULL, NULL,
 
407
                        DBUS_TYPE_STRING, &number,
 
408
                        DBUS_TYPE_STRING, &clir,
 
409
                        DBUS_TYPE_INVALID);
 
410
 
 
411
        if (ret < 0)
 
412
                telephony_dial_number_rsp(telephony_device,
 
413
                        CME_ERROR_AG_FAILURE);
 
414
        else
 
415
                telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
 
416
}
 
417
 
 
418
void telephony_transmit_dtmf_req(void *telephony_device, char tone)
 
419
{
 
420
        char *tone_string;
 
421
        int ret;
 
422
 
 
423
        DBG("telephony-ofono: transmit dtmf: %c", tone);
 
424
 
 
425
        if (!modem_obj_path) {
 
426
                telephony_transmit_dtmf_rsp(telephony_device,
 
427
                                        CME_ERROR_AG_FAILURE);
 
428
                return;
 
429
        }
 
430
 
 
431
        tone_string = g_strdup_printf("%c", tone);
 
432
        ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
433
                        OFONO_VCMANAGER_INTERFACE,
 
434
                        "SendTones", NULL, NULL,
 
435
                        DBUS_TYPE_STRING, &tone_string,
 
436
                        DBUS_TYPE_INVALID);
 
437
        g_free(tone_string);
 
438
 
 
439
        if (ret < 0)
 
440
                telephony_transmit_dtmf_rsp(telephony_device,
 
441
                        CME_ERROR_AG_FAILURE);
 
442
        else
 
443
                telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
 
444
}
 
445
 
 
446
void telephony_subscriber_number_req(void *telephony_device)
 
447
{
 
448
        DBG("telephony-ofono: subscriber number request");
 
449
 
 
450
        if (subscriber_number)
 
451
                telephony_subscriber_number_ind(subscriber_number,
 
452
                                                NUMBER_TYPE_TELEPHONY,
 
453
                                                SUBSCRIBER_SERVICE_VOICE);
 
454
        telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
 
455
}
 
456
 
 
457
void telephony_list_current_calls_req(void *telephony_device)
 
458
{
 
459
        GSList *l;
 
460
        int i;
 
461
 
 
462
        DBG("telephony-ofono: list current calls request");
 
463
 
 
464
        for (l = calls, i = 1; l != NULL; l = l->next, i++) {
 
465
                struct voice_call *vc = l->data;
 
466
                int direction, multiparty;
 
467
 
 
468
                direction = vc->originating ?
 
469
                                CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
 
470
 
 
471
                multiparty = vc->conference ?
 
472
                                CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
 
473
 
 
474
                DBG("call %s direction %d multiparty %d", vc->number,
 
475
                                                        direction, multiparty);
 
476
 
 
477
                telephony_list_current_call_ind(i, direction, vc->status,
 
478
                                        CALL_MODE_VOICE, multiparty,
 
479
                                        vc->number, number_type(vc->number));
 
480
        }
 
481
 
 
482
        telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
 
483
}
 
484
 
 
485
void telephony_operator_selection_req(void *telephony_device)
 
486
{
 
487
        DBG("telephony-ofono: operator selection request");
 
488
 
 
489
        telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
 
490
                                net.operator_name ? net.operator_name : "");
 
491
        telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
 
492
}
 
493
 
 
494
static void foreach_vc_with_status(int status,
 
495
                                        int (*func)(struct voice_call *vc))
 
496
{
 
497
        GSList *l;
 
498
 
 
499
        for (l = calls; l != NULL; l = l->next) {
 
500
                struct voice_call *call = l->data;
 
501
 
 
502
                if (call->status == status)
 
503
                        func(call);
 
504
        }
 
505
}
 
506
 
 
507
void telephony_call_hold_req(void *telephony_device, const char *cmd)
 
508
{
 
509
        const char *idx;
 
510
        struct voice_call *call;
 
511
        int err = 0;
 
512
 
 
513
        DBG("telephony-ofono: got call hold request %s", cmd);
 
514
 
 
515
        if (strlen(cmd) > 1)
 
516
                idx = &cmd[1];
 
517
        else
 
518
                idx = NULL;
 
519
 
 
520
        if (idx)
 
521
                call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
 
522
        else
 
523
                call = NULL;
 
524
 
 
525
        switch (cmd[0]) {
 
526
        case '0':
 
527
                if (find_vc_with_status(CALL_STATUS_WAITING))
 
528
                        foreach_vc_with_status(CALL_STATUS_WAITING,
 
529
                                                                release_call);
 
530
                else
 
531
                        foreach_vc_with_status(CALL_STATUS_HELD, release_call);
 
532
                break;
 
533
        case '1':
 
534
                if (idx) {
 
535
                        if (call)
 
536
                                err = release_call(call);
 
537
                        break;
 
538
                }
 
539
                err = release_answer_calls();
 
540
                break;
 
541
        case '2':
 
542
                if (idx) {
 
543
                        if (call)
 
544
                                err = split_call(call);
 
545
                } else {
 
546
                        call = find_vc_with_status(CALL_STATUS_WAITING);
 
547
 
 
548
                        if (call)
 
549
                                err = answer_call(call);
 
550
                        else
 
551
                                err = swap_calls();
 
552
                }
 
553
                break;
 
554
        case '3':
 
555
                if (find_vc_with_status(CALL_STATUS_HELD) ||
 
556
                                find_vc_with_status(CALL_STATUS_WAITING))
 
557
                        err = create_conference();
 
558
                break;
 
559
        case '4':
 
560
                err = call_transfer();
 
561
                break;
 
562
        default:
 
563
                DBG("Unknown call hold request");
 
564
                break;
 
565
        }
 
566
 
 
567
        if (err)
 
568
                telephony_call_hold_rsp(telephony_device,
 
569
                                        CME_ERROR_AG_FAILURE);
 
570
        else
 
571
                telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
 
572
}
 
573
 
 
574
void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
 
575
{
 
576
        DBG("telephony-ofono: got %s NR and EC request",
 
577
                        enable ? "enable" : "disable");
 
578
 
 
579
        telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
 
580
}
 
581
 
 
582
void telephony_key_press_req(void *telephony_device, const char *keys)
 
583
{
 
584
        struct voice_call *active, *incoming;
 
585
        int err;
 
586
 
 
587
        DBG("telephony-ofono: got key press request for %s", keys);
 
588
 
 
589
        incoming = find_vc_with_status(CALL_STATUS_INCOMING);
 
590
 
 
591
        active = find_vc_with_status(CALL_STATUS_ACTIVE);
 
592
 
 
593
        if (incoming)
 
594
                err = answer_call(incoming);
 
595
        else if (active)
 
596
                err = release_call(active);
 
597
        else
 
598
                err = 0;
 
599
 
 
600
        if (err < 0)
 
601
                telephony_key_press_rsp(telephony_device,
 
602
                                                        CME_ERROR_AG_FAILURE);
 
603
        else
 
604
                telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
 
605
}
 
606
 
 
607
void telephony_voice_dial_req(void *telephony_device, gboolean enable)
 
608
{
 
609
        DBG("telephony-ofono: got %s voice dial request",
 
610
                        enable ? "enable" : "disable");
 
611
 
 
612
        telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
 
613
}
 
614
 
 
615
static gboolean iter_get_basic_args(DBusMessageIter *iter,
 
616
                                        int first_arg_type, ...)
 
617
{
 
618
        int type;
 
619
        va_list ap;
 
620
 
 
621
        va_start(ap, first_arg_type);
 
622
 
 
623
        for (type = first_arg_type; type != DBUS_TYPE_INVALID;
 
624
                type = va_arg(ap, int)) {
 
625
                void *value = va_arg(ap, void *);
 
626
                int real_type = dbus_message_iter_get_arg_type(iter);
 
627
 
 
628
                if (real_type != type) {
 
629
                        error("iter_get_basic_args: expected %c but got %c",
 
630
                                (char) type, (char) real_type);
 
631
                        break;
 
632
                }
 
633
 
 
634
                dbus_message_iter_get_basic(iter, value);
 
635
                dbus_message_iter_next(iter);
 
636
        }
 
637
 
 
638
        va_end(ap);
 
639
 
 
640
        return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
 
641
}
 
642
 
 
643
static void call_free(void *data)
 
644
{
 
645
        struct voice_call *vc = data;
 
646
 
 
647
        DBG("%s", vc->obj_path);
 
648
 
 
649
        if (vc->status == CALL_STATUS_ACTIVE)
 
650
                telephony_update_indicator(ofono_indicators, "call",
 
651
                                                        EV_CALL_INACTIVE);
 
652
        else
 
653
                telephony_update_indicator(ofono_indicators, "callsetup",
 
654
                                                        EV_CALLSETUP_INACTIVE);
 
655
 
 
656
        if (vc->status == CALL_STATUS_INCOMING)
 
657
                telephony_calling_stopped_ind();
 
658
 
 
659
        g_dbus_remove_watch(connection, vc->watch);
 
660
        g_free(vc->obj_path);
 
661
        g_free(vc->number);
 
662
        g_free(vc);
 
663
}
 
664
 
 
665
static gboolean handle_vc_property_changed(DBusConnection *conn,
 
666
                                        DBusMessage *msg, void *data)
 
667
{
 
668
        struct voice_call *vc = data;
 
669
        const char *obj_path = dbus_message_get_path(msg);
 
670
        DBusMessageIter iter, sub;
 
671
        const char *property, *state;
 
672
 
 
673
        DBG("path %s", obj_path);
 
674
 
 
675
        dbus_message_iter_init(msg, &iter);
 
676
 
 
677
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
 
678
                error("Unexpected signature in vc PropertyChanged signal");
 
679
                return TRUE;
 
680
        }
 
681
 
 
682
        dbus_message_iter_get_basic(&iter, &property);
 
683
        DBG("property %s", property);
 
684
 
 
685
        dbus_message_iter_next(&iter);
 
686
        dbus_message_iter_recurse(&iter, &sub);
 
687
        if (g_str_equal(property, "State")) {
 
688
                dbus_message_iter_get_basic(&sub, &state);
 
689
                DBG("State %s", state);
 
690
                if (g_str_equal(state, "disconnected")) {
 
691
                        calls = g_slist_remove(calls, vc);
 
692
                        call_free(vc);
 
693
                } else if (g_str_equal(state, "active")) {
 
694
                        telephony_update_indicator(ofono_indicators,
 
695
                                                        "call", EV_CALL_ACTIVE);
 
696
                        telephony_update_indicator(ofono_indicators,
 
697
                                                        "callsetup",
 
698
                                                        EV_CALLSETUP_INACTIVE);
 
699
                        if (vc->status == CALL_STATUS_INCOMING)
 
700
                                telephony_calling_stopped_ind();
 
701
                        vc->status = CALL_STATUS_ACTIVE;
 
702
                } else if (g_str_equal(state, "alerting")) {
 
703
                        telephony_update_indicator(ofono_indicators,
 
704
                                        "callsetup", EV_CALLSETUP_ALERTING);
 
705
                        vc->status = CALL_STATUS_ALERTING;
 
706
                        vc->originating = TRUE;
 
707
                } else if (g_str_equal(state, "incoming")) {
 
708
                        /* state change from waiting to incoming */
 
709
                        telephony_update_indicator(ofono_indicators,
 
710
                                        "callsetup", EV_CALLSETUP_INCOMING);
 
711
                        telephony_incoming_call_ind(vc->number,
 
712
                                                NUMBER_TYPE_TELEPHONY);
 
713
                        vc->status = CALL_STATUS_INCOMING;
 
714
                        vc->originating = FALSE;
 
715
                } else if (g_str_equal(state, "held")) {
 
716
                        vc->status = CALL_STATUS_HELD;
 
717
                        if (find_vc_without_status(CALL_STATUS_HELD))
 
718
                                telephony_update_indicator(ofono_indicators,
 
719
                                                        "callheld",
 
720
                                                        EV_CALLHELD_MULTIPLE);
 
721
                        else
 
722
                                telephony_update_indicator(ofono_indicators,
 
723
                                                        "callheld",
 
724
                                                        EV_CALLHELD_ON_HOLD);
 
725
                }
 
726
        } else if (g_str_equal(property, "Multiparty")) {
 
727
                dbus_bool_t multiparty;
 
728
 
 
729
                dbus_message_iter_get_basic(&sub, &multiparty);
 
730
                DBG("Multiparty %s", multiparty ? "True" : "False");
 
731
                vc->conference = multiparty;
 
732
        }
 
733
 
 
734
        return TRUE;
 
735
}
 
736
 
 
737
static struct voice_call *call_new(const char *path, DBusMessageIter *properties)
 
738
{
 
739
        struct voice_call *vc;
 
740
 
 
741
        DBG("%s", path);
 
742
 
 
743
        vc = g_new0(struct voice_call, 1);
 
744
        vc->obj_path = g_strdup(path);
 
745
        vc->watch = g_dbus_add_signal_watch(connection, NULL, path,
 
746
                                        OFONO_VC_INTERFACE, "PropertyChanged",
 
747
                                        handle_vc_property_changed, vc, NULL);
 
748
 
 
749
        while (dbus_message_iter_get_arg_type(properties)
 
750
                                                == DBUS_TYPE_DICT_ENTRY) {
 
751
                DBusMessageIter entry, value;
 
752
                const char *property, *cli, *state;
 
753
                dbus_bool_t multiparty;
 
754
 
 
755
                dbus_message_iter_recurse(properties, &entry);
 
756
                dbus_message_iter_get_basic(&entry, &property);
 
757
 
 
758
                dbus_message_iter_next(&entry);
 
759
                dbus_message_iter_recurse(&entry, &value);
 
760
 
 
761
                if (g_str_equal(property, "LineIdentification")) {
 
762
                        dbus_message_iter_get_basic(&value, &cli);
 
763
                        DBG("cli %s", cli);
 
764
                        vc->number = g_strdup(cli);
 
765
                } else if (g_str_equal(property, "State")) {
 
766
                        dbus_message_iter_get_basic(&value, &state);
 
767
                        DBG("state %s", state);
 
768
                        if (g_str_equal(state, "incoming"))
 
769
                                vc->status = CALL_STATUS_INCOMING;
 
770
                        else if (g_str_equal(state, "dialing"))
 
771
                                vc->status = CALL_STATUS_DIALING;
 
772
                        else if (g_str_equal(state, "alerting"))
 
773
                                vc->status = CALL_STATUS_ALERTING;
 
774
                        else if (g_str_equal(state, "waiting"))
 
775
                                vc->status = CALL_STATUS_WAITING;
 
776
                        else if (g_str_equal(state, "held"))
 
777
                                vc->status = CALL_STATUS_HELD;
 
778
                } else if (g_str_equal(property, "Multiparty")) {
 
779
                        dbus_message_iter_get_basic(&value, &multiparty);
 
780
                        DBG("Multipary %s", multiparty ? "True" : "False");
 
781
                        vc->conference = multiparty;
 
782
                }
 
783
 
 
784
                dbus_message_iter_next(properties);
 
785
        }
 
786
 
 
787
        switch (vc->status) {
 
788
        case CALL_STATUS_INCOMING:
 
789
                DBG("CALL_STATUS_INCOMING");
 
790
                vc->originating = FALSE;
 
791
                telephony_update_indicator(ofono_indicators, "callsetup",
 
792
                                        EV_CALLSETUP_INCOMING);
 
793
                telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
 
794
                break;
 
795
        case CALL_STATUS_DIALING:
 
796
                DBG("CALL_STATUS_DIALING");
 
797
                vc->originating = TRUE;
 
798
                g_free(last_dialed_number);
 
799
                last_dialed_number = g_strdup(vc->number);
 
800
                telephony_update_indicator(ofono_indicators, "callsetup",
 
801
                                        EV_CALLSETUP_OUTGOING);
 
802
                break;
 
803
        case CALL_STATUS_ALERTING:
 
804
                DBG("CALL_STATUS_ALERTING");
 
805
                vc->originating = TRUE;
 
806
                g_free(last_dialed_number);
 
807
                last_dialed_number = g_strdup(vc->number);
 
808
                telephony_update_indicator(ofono_indicators, "callsetup",
 
809
                                        EV_CALLSETUP_ALERTING);
 
810
                break;
 
811
        case CALL_STATUS_WAITING:
 
812
                DBG("CALL_STATUS_WAITING");
 
813
                vc->originating = FALSE;
 
814
                telephony_update_indicator(ofono_indicators, "callsetup",
 
815
                                        EV_CALLSETUP_INCOMING);
 
816
                telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
 
817
                break;
 
818
        }
 
819
 
 
820
        return vc;
 
821
}
 
822
 
 
823
static void remove_pending(DBusPendingCall *call)
 
824
{
 
825
        pending = g_slist_remove(pending, call);
 
826
        dbus_pending_call_unref(call);
 
827
}
 
828
 
 
829
static void call_added(const char *path, DBusMessageIter *properties)
 
830
{
 
831
        struct voice_call *vc;
 
832
 
 
833
        DBG("%s", path);
 
834
 
 
835
        vc = find_vc(path);
 
836
        if (vc)
 
837
                return;
 
838
 
 
839
        vc = call_new(path, properties);
 
840
        calls = g_slist_prepend(calls, vc);
 
841
}
 
842
 
 
843
static void get_calls_reply(DBusPendingCall *call, void *user_data)
 
844
{
 
845
        DBusError err;
 
846
        DBusMessage *reply;
 
847
        DBusMessageIter iter, entry;
 
848
 
 
849
        DBG("");
 
850
        reply = dbus_pending_call_steal_reply(call);
 
851
 
 
852
        dbus_error_init(&err);
 
853
        if (dbus_set_error_from_message(&err, reply)) {
 
854
                error("ofono replied with an error: %s, %s",
 
855
                                err.name, err.message);
 
856
                dbus_error_free(&err);
 
857
                goto done;
 
858
        }
 
859
 
 
860
        dbus_message_iter_init(reply, &iter);
 
861
 
 
862
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
863
                error("Unexpected signature");
 
864
                goto done;
 
865
        }
 
866
 
 
867
        dbus_message_iter_recurse(&iter, &entry);
 
868
 
 
869
        while (dbus_message_iter_get_arg_type(&entry)
 
870
                                                == DBUS_TYPE_STRUCT) {
 
871
                const char *path;
 
872
                DBusMessageIter value, properties;
 
873
 
 
874
                dbus_message_iter_recurse(&entry, &value);
 
875
                dbus_message_iter_get_basic(&value, &path);
 
876
 
 
877
                dbus_message_iter_next(&value);
 
878
                dbus_message_iter_recurse(&value, &properties);
 
879
 
 
880
                call_added(path, &properties);
 
881
 
 
882
                dbus_message_iter_next(&entry);
 
883
        }
 
884
 
 
885
done:
 
886
        dbus_message_unref(reply);
 
887
        remove_pending(call);
 
888
}
 
889
 
 
890
static void handle_network_property(const char *property, DBusMessageIter *variant)
 
891
{
 
892
        const char *status, *operator;
 
893
        unsigned int signals_bar;
 
894
 
 
895
        if (g_str_equal(property, "Status")) {
 
896
                dbus_message_iter_get_basic(variant, &status);
 
897
                DBG("Status is %s", status);
 
898
                if (g_str_equal(status, "registered")) {
 
899
                        net.status = NETWORK_REG_STATUS_HOME;
 
900
                        telephony_update_indicator(ofono_indicators,
 
901
                                                "roam", EV_ROAM_INACTIVE);
 
902
                        telephony_update_indicator(ofono_indicators,
 
903
                                                "service", EV_SERVICE_PRESENT);
 
904
                } else if (g_str_equal(status, "roaming")) {
 
905
                        net.status = NETWORK_REG_STATUS_ROAM;
 
906
                        telephony_update_indicator(ofono_indicators,
 
907
                                                "roam", EV_ROAM_ACTIVE);
 
908
                        telephony_update_indicator(ofono_indicators,
 
909
                                                "service", EV_SERVICE_PRESENT);
 
910
                } else {
 
911
                        net.status = NETWORK_REG_STATUS_NOSERV;
 
912
                        telephony_update_indicator(ofono_indicators,
 
913
                                                "roam", EV_ROAM_INACTIVE);
 
914
                        telephony_update_indicator(ofono_indicators,
 
915
                                                "service", EV_SERVICE_NONE);
 
916
                }
 
917
        } else if (g_str_equal(property, "Name")) {
 
918
                dbus_message_iter_get_basic(variant, &operator);
 
919
                DBG("Operator is %s", operator);
 
920
                g_free(net.operator_name);
 
921
                net.operator_name = g_strdup(operator);
 
922
        } else if (g_str_equal(property, "SignalStrength")) {
 
923
                dbus_message_iter_get_basic(variant, &signals_bar);
 
924
                DBG("SignalStrength is %d", signals_bar);
 
925
                net.signals_bar = signals_bar;
 
926
                telephony_update_indicator(ofono_indicators, "signal",
 
927
                                                (signals_bar + 20) / 21);
 
928
        }
 
929
}
 
930
 
 
931
static int parse_network_properties(DBusMessageIter *properties)
 
932
{
 
933
        int i;
 
934
 
 
935
        /* Reset indicators */
 
936
        for (i = 0; ofono_indicators[i].desc != NULL; i++) {
 
937
                if (g_str_equal(ofono_indicators[i].desc, "battchg"))
 
938
                        ofono_indicators[i].val = 5;
 
939
                else
 
940
                        ofono_indicators[i].val = 0;
 
941
        }
 
942
 
 
943
        while (dbus_message_iter_get_arg_type(properties)
 
944
                                                == DBUS_TYPE_DICT_ENTRY) {
 
945
                const char *key;
 
946
                DBusMessageIter value, entry;
 
947
 
 
948
                dbus_message_iter_recurse(properties, &entry);
 
949
                dbus_message_iter_get_basic(&entry, &key);
 
950
 
 
951
                dbus_message_iter_next(&entry);
 
952
                dbus_message_iter_recurse(&entry, &value);
 
953
 
 
954
                handle_network_property(key, &value);
 
955
 
 
956
                dbus_message_iter_next(properties);
 
957
        }
 
958
 
 
959
        return 0;
 
960
}
 
961
 
 
962
static void get_properties_reply(DBusPendingCall *call, void *user_data)
 
963
{
 
964
        DBusError err;
 
965
        DBusMessage *reply;
 
966
        DBusMessageIter iter, properties;
 
967
        int ret = 0;
 
968
 
 
969
        DBG("");
 
970
        reply = dbus_pending_call_steal_reply(call);
 
971
 
 
972
        dbus_error_init(&err);
 
973
        if (dbus_set_error_from_message(&err, reply)) {
 
974
                error("ofono replied with an error: %s, %s",
 
975
                                err.name, err.message);
 
976
                dbus_error_free(&err);
 
977
                goto done;
 
978
        }
 
979
 
 
980
        dbus_message_iter_init(reply, &iter);
 
981
 
 
982
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
983
                error("Unexpected signature");
 
984
                goto done;
 
985
        }
 
986
 
 
987
        dbus_message_iter_recurse(&iter, &properties);
 
988
 
 
989
        ret = parse_network_properties(&properties);
 
990
        if (ret < 0) {
 
991
                error("Unable to parse %s.GetProperty reply",
 
992
                                                OFONO_NETWORKREG_INTERFACE);
 
993
                goto done;
 
994
        }
 
995
 
 
996
        ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
 
997
                                OFONO_VCMANAGER_INTERFACE, "GetCalls",
 
998
                                get_calls_reply, NULL, DBUS_TYPE_INVALID);
 
999
        if (ret < 0)
 
1000
                error("Unable to send %s.GetCalls",
 
1001
                                                OFONO_VCMANAGER_INTERFACE);
 
1002
 
 
1003
done:
 
1004
        dbus_message_unref(reply);
 
1005
        remove_pending(call);
 
1006
}
 
1007
 
 
1008
static void network_found(const char *path)
 
1009
{
 
1010
        int ret;
 
1011
 
 
1012
        DBG("%s", path);
 
1013
 
 
1014
        modem_obj_path = g_strdup(path);
 
1015
 
 
1016
        ret = send_method_call(OFONO_BUS_NAME, path,
 
1017
                                OFONO_NETWORKREG_INTERFACE, "GetProperties",
 
1018
                                get_properties_reply, NULL, DBUS_TYPE_INVALID);
 
1019
        if (ret < 0)
 
1020
                error("Unable to send %s.GetProperties",
 
1021
                                                OFONO_NETWORKREG_INTERFACE);
 
1022
}
 
1023
 
 
1024
static void modem_removed(const char *path)
 
1025
{
 
1026
        if (g_strcmp0(modem_obj_path, path) != 0)
 
1027
                return;
 
1028
 
 
1029
        DBG("%s", path);
 
1030
 
 
1031
        g_slist_free_full(calls, call_free);
 
1032
        calls = NULL;
 
1033
 
 
1034
        g_free(net.operator_name);
 
1035
        net.operator_name = NULL;
 
1036
        net.status = NETWORK_REG_STATUS_NOSERV;
 
1037
        net.signals_bar = 0;
 
1038
 
 
1039
        g_free(modem_obj_path);
 
1040
        modem_obj_path = NULL;
 
1041
}
 
1042
 
 
1043
static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces)
 
1044
{
 
1045
        DBG("%s", path);
 
1046
 
 
1047
        while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) {
 
1048
                const char *iface;
 
1049
 
 
1050
                dbus_message_iter_get_basic(ifaces, &iface);
 
1051
 
 
1052
                if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) {
 
1053
                        network_found(path);
 
1054
                        return;
 
1055
                }
 
1056
 
 
1057
                dbus_message_iter_next(ifaces);
 
1058
        }
 
1059
 
 
1060
        modem_removed(path);
 
1061
}
 
1062
 
 
1063
static void modem_added(const char *path, DBusMessageIter *properties)
 
1064
{
 
1065
        if (modem_obj_path != NULL) {
 
1066
                DBG("Ignoring, modem already exist");
 
1067
                return;
 
1068
        }
 
1069
 
 
1070
        DBG("%s", path);
 
1071
 
 
1072
        while (dbus_message_iter_get_arg_type(properties)
 
1073
                                                == DBUS_TYPE_DICT_ENTRY) {
 
1074
                const char *key;
 
1075
                DBusMessageIter interfaces, value, entry;
 
1076
 
 
1077
                dbus_message_iter_recurse(properties, &entry);
 
1078
                dbus_message_iter_get_basic(&entry, &key);
 
1079
 
 
1080
                dbus_message_iter_next(&entry);
 
1081
                dbus_message_iter_recurse(&entry, &value);
 
1082
 
 
1083
                if (strcasecmp(key, "Interfaces") != 0)
 
1084
                        goto next;
 
1085
 
 
1086
                if (dbus_message_iter_get_arg_type(&value)
 
1087
                                                        != DBUS_TYPE_ARRAY) {
 
1088
                        error("Invalid Signature");
 
1089
                        return;
 
1090
                }
 
1091
 
 
1092
                dbus_message_iter_recurse(&value, &interfaces);
 
1093
 
 
1094
                parse_modem_interfaces(path, &interfaces);
 
1095
 
 
1096
                if (modem_obj_path != NULL)
 
1097
                        return;
 
1098
 
 
1099
        next:
 
1100
                dbus_message_iter_next(properties);
 
1101
        }
 
1102
}
 
1103
 
 
1104
static void get_modems_reply(DBusPendingCall *call, void *user_data)
 
1105
{
 
1106
        DBusError err;
 
1107
        DBusMessage *reply;
 
1108
        DBusMessageIter iter, entry;
 
1109
 
 
1110
        DBG("");
 
1111
        reply = dbus_pending_call_steal_reply(call);
 
1112
 
 
1113
        dbus_error_init(&err);
 
1114
        if (dbus_set_error_from_message(&err, reply)) {
 
1115
                error("ofono replied with an error: %s, %s",
 
1116
                                err.name, err.message);
 
1117
                dbus_error_free(&err);
 
1118
                goto done;
 
1119
        }
 
1120
 
 
1121
        /* Skip modem selection if a modem already exist */
 
1122
        if (modem_obj_path != NULL)
 
1123
                goto done;
 
1124
 
 
1125
        dbus_message_iter_init(reply, &iter);
 
1126
 
 
1127
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
1128
                error("Unexpected signature");
 
1129
                goto done;
 
1130
        }
 
1131
 
 
1132
        dbus_message_iter_recurse(&iter, &entry);
 
1133
 
 
1134
        while (dbus_message_iter_get_arg_type(&entry)
 
1135
                                                == DBUS_TYPE_STRUCT) {
 
1136
                const char *path;
 
1137
                DBusMessageIter item, properties;
 
1138
 
 
1139
                dbus_message_iter_recurse(&entry, &item);
 
1140
                dbus_message_iter_get_basic(&item, &path);
 
1141
 
 
1142
                dbus_message_iter_next(&item);
 
1143
                dbus_message_iter_recurse(&item, &properties);
 
1144
 
 
1145
                modem_added(path, &properties);
 
1146
                if (modem_obj_path != NULL)
 
1147
                        break;
 
1148
 
 
1149
                dbus_message_iter_next(&entry);
 
1150
        }
 
1151
 
 
1152
done:
 
1153
        dbus_message_unref(reply);
 
1154
        remove_pending(call);
 
1155
}
 
1156
 
 
1157
static gboolean handle_network_property_changed(DBusConnection *conn,
 
1158
                                                DBusMessage *msg, void *data)
 
1159
{
 
1160
        DBusMessageIter iter, variant;
 
1161
        const char *property;
 
1162
 
 
1163
        dbus_message_iter_init(msg, &iter);
 
1164
 
 
1165
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
 
1166
                error("Unexpected signature in networkregistration"
 
1167
                                        " PropertyChanged signal");
 
1168
                return TRUE;
 
1169
        }
 
1170
        dbus_message_iter_get_basic(&iter, &property);
 
1171
        DBG("in handle_registration_property_changed(),"
 
1172
                                        " the property is %s", property);
 
1173
 
 
1174
        dbus_message_iter_next(&iter);
 
1175
        dbus_message_iter_recurse(&iter, &variant);
 
1176
 
 
1177
        handle_network_property(property, &variant);
 
1178
 
 
1179
        return TRUE;
 
1180
}
 
1181
 
 
1182
static void handle_modem_property(const char *path, const char *property,
 
1183
                                                DBusMessageIter *variant)
 
1184
{
 
1185
        DBG("%s", property);
 
1186
 
 
1187
        if (g_str_equal(property, "Interfaces")) {
 
1188
                DBusMessageIter interfaces;
 
1189
 
 
1190
                if (dbus_message_iter_get_arg_type(variant)
 
1191
                                                        != DBUS_TYPE_ARRAY) {
 
1192
                        error("Invalid signature");
 
1193
                        return;
 
1194
                }
 
1195
 
 
1196
                dbus_message_iter_recurse(variant, &interfaces);
 
1197
                parse_modem_interfaces(path, &interfaces);
 
1198
        }
 
1199
}
 
1200
 
 
1201
static gboolean handle_modem_property_changed(DBusConnection *conn,
 
1202
                                                DBusMessage *msg, void *data)
 
1203
{
 
1204
        DBusMessageIter iter, variant;
 
1205
        const char *property, *path;
 
1206
 
 
1207
        path = dbus_message_get_path(msg);
 
1208
 
 
1209
        /* Ignore if modem already exist and paths doesn't match */
 
1210
        if (modem_obj_path != NULL &&
 
1211
                                g_str_equal(path, modem_obj_path) == FALSE)
 
1212
                return TRUE;
 
1213
 
 
1214
        dbus_message_iter_init(msg, &iter);
 
1215
 
 
1216
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
 
1217
                error("Unexpected signature in %s.%s PropertyChanged signal",
 
1218
                                        dbus_message_get_interface(msg),
 
1219
                                        dbus_message_get_member(msg));
 
1220
                return TRUE;
 
1221
        }
 
1222
 
 
1223
        dbus_message_iter_get_basic(&iter, &property);
 
1224
 
 
1225
        dbus_message_iter_next(&iter);
 
1226
        dbus_message_iter_recurse(&iter, &variant);
 
1227
 
 
1228
        handle_modem_property(path, property, &variant);
 
1229
 
 
1230
        return TRUE;
 
1231
}
 
1232
 
 
1233
static gboolean handle_vcmanager_call_added(DBusConnection *conn,
 
1234
                                                DBusMessage *msg, void *data)
 
1235
{
 
1236
        DBusMessageIter iter, properties;
 
1237
        const char *path = dbus_message_get_path(msg);
 
1238
 
 
1239
        /* Ignore call if modem path doesn't math */
 
1240
        if (g_strcmp0(modem_obj_path, path) != 0)
 
1241
                return TRUE;
 
1242
 
 
1243
        dbus_message_iter_init(msg, &iter);
 
1244
 
 
1245
        if (dbus_message_iter_get_arg_type(&iter)
 
1246
                                                != DBUS_TYPE_OBJECT_PATH) {
 
1247
                error("Unexpected signature in %s.%s signal",
 
1248
                                        dbus_message_get_interface(msg),
 
1249
                                        dbus_message_get_member(msg));
 
1250
                return TRUE;
 
1251
        }
 
1252
 
 
1253
        dbus_message_iter_get_basic(&iter, &path);
 
1254
        dbus_message_iter_next(&iter);
 
1255
        dbus_message_iter_recurse(&iter, &properties);
 
1256
 
 
1257
        call_added(path, &properties);
 
1258
 
 
1259
        return TRUE;
 
1260
}
 
1261
 
 
1262
static void call_removed(const char *path)
 
1263
{
 
1264
        struct voice_call *vc;
 
1265
 
 
1266
        DBG("%s", path);
 
1267
 
 
1268
        vc = find_vc(path);
 
1269
        if (vc == NULL)
 
1270
                return;
 
1271
 
 
1272
        calls = g_slist_remove(calls, vc);
 
1273
        call_free(vc);
 
1274
}
 
1275
 
 
1276
static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
 
1277
                                                DBusMessage *msg, void *data)
 
1278
{
 
1279
        const char *path = dbus_message_get_path(msg);
 
1280
 
 
1281
        /* Ignore call if modem path doesn't math */
 
1282
        if (g_strcmp0(modem_obj_path, path) != 0)
 
1283
                return TRUE;
 
1284
 
 
1285
        if (!dbus_message_get_args(msg, NULL,
 
1286
                                DBUS_TYPE_OBJECT_PATH, &path,
 
1287
                                DBUS_TYPE_INVALID)) {
 
1288
                error("Unexpected signature in %s.%s signal",
 
1289
                                        dbus_message_get_interface(msg),
 
1290
                                        dbus_message_get_member(msg));
 
1291
                return TRUE;
 
1292
        }
 
1293
 
 
1294
        call_removed(path);
 
1295
 
 
1296
        return TRUE;
 
1297
}
 
1298
 
 
1299
static gboolean handle_manager_modem_added(DBusConnection *conn,
 
1300
                                                DBusMessage *msg, void *data)
 
1301
{
 
1302
        DBusMessageIter iter, properties;
 
1303
        const char *path;
 
1304
 
 
1305
        if (modem_obj_path != NULL)
 
1306
                return TRUE;
 
1307
 
 
1308
        dbus_message_iter_init(msg, &iter);
 
1309
 
 
1310
        if (dbus_message_iter_get_arg_type(&iter)
 
1311
                                                != DBUS_TYPE_OBJECT_PATH) {
 
1312
                error("Unexpected signature in %s.%s signal",
 
1313
                                        dbus_message_get_interface(msg),
 
1314
                                        dbus_message_get_member(msg));
 
1315
                return TRUE;
 
1316
        }
 
1317
 
 
1318
        dbus_message_iter_get_basic(&iter, &path);
 
1319
        dbus_message_iter_next(&iter);
 
1320
        dbus_message_iter_recurse(&iter, &properties);
 
1321
 
 
1322
        modem_added(path, &properties);
 
1323
 
 
1324
        return TRUE;
 
1325
}
 
1326
 
 
1327
static gboolean handle_manager_modem_removed(DBusConnection *conn,
 
1328
                                                DBusMessage *msg, void *data)
 
1329
{
 
1330
        const char *path;
 
1331
 
 
1332
        if (!dbus_message_get_args(msg, NULL,
 
1333
                                DBUS_TYPE_OBJECT_PATH, &path,
 
1334
                                DBUS_TYPE_INVALID)) {
 
1335
                error("Unexpected signature in %s.%s signal",
 
1336
                                        dbus_message_get_interface(msg),
 
1337
                                        dbus_message_get_member(msg));
 
1338
                return TRUE;
 
1339
        }
 
1340
 
 
1341
        modem_removed(path);
 
1342
 
 
1343
        return TRUE;
 
1344
}
 
1345
 
 
1346
#if 0 /* Disable hal */
 
1347
static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
 
1348
{
 
1349
        DBusMessage *reply;
 
1350
        DBusError err;
 
1351
        dbus_int32_t level;
 
1352
        int *value = user_data;
 
1353
 
 
1354
        reply = dbus_pending_call_steal_reply(call);
 
1355
 
 
1356
        dbus_error_init(&err);
 
1357
        if (dbus_set_error_from_message(&err, reply)) {
 
1358
                error("hald replied with an error: %s, %s",
 
1359
                                err.name, err.message);
 
1360
                dbus_error_free(&err);
 
1361
                goto done;
 
1362
        }
 
1363
 
 
1364
        dbus_error_init(&err);
 
1365
        if (dbus_message_get_args(reply, &err,
 
1366
                                DBUS_TYPE_INT32, &level,
 
1367
                                DBUS_TYPE_INVALID) == FALSE) {
 
1368
                error("Unable to parse GetPropertyInteger reply: %s, %s",
 
1369
                                                        err.name, err.message);
 
1370
                dbus_error_free(&err);
 
1371
                goto done;
 
1372
        }
 
1373
 
 
1374
        *value = (int) level;
 
1375
 
 
1376
        if (value == &battchg_last)
 
1377
                DBG("telephony-ofono: battery.charge_level.last_full"
 
1378
                                        " is %d", *value);
 
1379
        else if (value == &battchg_design)
 
1380
                DBG("telephony-ofono: battery.charge_level.design"
 
1381
                                        " is %d", *value);
 
1382
        else
 
1383
                DBG("telephony-ofono: battery.charge_level.current"
 
1384
                                        " is %d", *value);
 
1385
 
 
1386
        if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
 
1387
                int new, max;
 
1388
 
 
1389
                if (battchg_last > 0)
 
1390
                        max = battchg_last;
 
1391
                else
 
1392
                        max = battchg_design;
 
1393
 
 
1394
                new = battchg_cur * 5 / max;
 
1395
 
 
1396
                telephony_update_indicator(ofono_indicators, "battchg", new);
 
1397
        }
 
1398
done:
 
1399
        dbus_message_unref(reply);
 
1400
        remove_pending(call);
 
1401
}
 
1402
 
 
1403
static void hal_get_integer(const char *path, const char *key, void *user_data)
 
1404
{
 
1405
        send_method_call("org.freedesktop.Hal", path,
 
1406
                        "org.freedesktop.Hal.Device",
 
1407
                        "GetPropertyInteger",
 
1408
                        hal_battery_level_reply, user_data,
 
1409
                        DBUS_TYPE_STRING, &key,
 
1410
                        DBUS_TYPE_INVALID);
 
1411
}
 
1412
 
 
1413
static gboolean handle_hal_property_modified(DBusConnection *conn,
 
1414
                                                DBusMessage *msg, void *data)
 
1415
{
 
1416
        const char *path;
 
1417
        DBusMessageIter iter, array;
 
1418
        dbus_int32_t num_changes;
 
1419
 
 
1420
        path = dbus_message_get_path(msg);
 
1421
 
 
1422
        dbus_message_iter_init(msg, &iter);
 
1423
 
 
1424
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
 
1425
                error("Unexpected signature in hal PropertyModified signal");
 
1426
                return TRUE;
 
1427
        }
 
1428
 
 
1429
        dbus_message_iter_get_basic(&iter, &num_changes);
 
1430
        dbus_message_iter_next(&iter);
 
1431
 
 
1432
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
1433
                error("Unexpected signature in hal PropertyModified signal");
 
1434
                return TRUE;
 
1435
        }
 
1436
 
 
1437
        dbus_message_iter_recurse(&iter, &array);
 
1438
 
 
1439
        while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
 
1440
                DBusMessageIter prop;
 
1441
                const char *name;
 
1442
                dbus_bool_t added, removed;
 
1443
 
 
1444
                dbus_message_iter_recurse(&array, &prop);
 
1445
 
 
1446
                if (!iter_get_basic_args(&prop,
 
1447
                                        DBUS_TYPE_STRING, &name,
 
1448
                                        DBUS_TYPE_BOOLEAN, &added,
 
1449
                                        DBUS_TYPE_BOOLEAN, &removed,
 
1450
                                        DBUS_TYPE_INVALID)) {
 
1451
                        error("Invalid hal PropertyModified parameters");
 
1452
                        break;
 
1453
                }
 
1454
 
 
1455
                if (g_str_equal(name, "battery.charge_level.last_full"))
 
1456
                        hal_get_integer(path, name, &battchg_last);
 
1457
                else if (g_str_equal(name, "battery.charge_level.current"))
 
1458
                        hal_get_integer(path, name, &battchg_cur);
 
1459
                else if (g_str_equal(name, "battery.charge_level.design"))
 
1460
                        hal_get_integer(path, name, &battchg_design);
 
1461
 
 
1462
                dbus_message_iter_next(&array);
 
1463
        }
 
1464
 
 
1465
        return TRUE;
 
1466
}
 
1467
 
 
1468
static void add_watch(const char *sender, const char *path,
 
1469
                                const char *interface, const char *member,
 
1470
                                GDBusSignalFunction function)
 
1471
{
 
1472
        guint watch;
 
1473
 
 
1474
        watch = g_dbus_add_signal_watch(connection, sender, path, interface,
 
1475
                                        member, function, NULL, NULL);
 
1476
 
 
1477
        watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
 
1478
}
 
1479
 
 
1480
static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
 
1481
{
 
1482
        DBusMessage *reply;
 
1483
        DBusError err;
 
1484
        DBusMessageIter iter, sub;
 
1485
        int type;
 
1486
        const char *path;
 
1487
 
 
1488
        DBG("begin of hal_find_device_reply()");
 
1489
        reply = dbus_pending_call_steal_reply(call);
 
1490
 
 
1491
        dbus_error_init(&err);
 
1492
 
 
1493
        if (dbus_set_error_from_message(&err, reply)) {
 
1494
                error("hald replied with an error: %s, %s",
 
1495
                                err.name, err.message);
 
1496
                dbus_error_free(&err);
 
1497
                goto done;
 
1498
        }
 
1499
 
 
1500
        dbus_message_iter_init(reply, &iter);
 
1501
 
 
1502
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
1503
                error("Unexpected signature in hal_find_device_reply()");
 
1504
                goto done;
 
1505
        }
 
1506
 
 
1507
        dbus_message_iter_recurse(&iter, &sub);
 
1508
 
 
1509
        type = dbus_message_iter_get_arg_type(&sub);
 
1510
 
 
1511
        if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
 
1512
                error("No hal device with battery capability found");
 
1513
                goto done;
 
1514
        }
 
1515
 
 
1516
        dbus_message_iter_get_basic(&sub, &path);
 
1517
 
 
1518
        DBG("telephony-ofono: found battery device at %s", path);
 
1519
 
 
1520
        add_watch(NULL, path, "org.freedesktop.Hal.Device",
 
1521
                        "PropertyModified", handle_hal_property_modified);
 
1522
 
 
1523
        hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
 
1524
        hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
 
1525
        hal_get_integer(path, "battery.charge_level.design", &battchg_design);
 
1526
done:
 
1527
        dbus_message_unref(reply);
 
1528
        remove_pending(call);
 
1529
}
 
1530
#endif /* Disable hal */
 
1531
 
 
1532
static void handle_service_connect(DBusConnection *conn, void *user_data)
 
1533
{
 
1534
        DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
 
1535
 
 
1536
        send_method_call(OFONO_BUS_NAME, OFONO_PATH,
 
1537
                                OFONO_MANAGER_INTERFACE, "GetModems",
 
1538
                                get_modems_reply, NULL, DBUS_TYPE_INVALID);
 
1539
}
 
1540
 
 
1541
static void handle_service_disconnect(DBusConnection *conn, void *user_data)
 
1542
{
 
1543
        DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
 
1544
 
 
1545
        if (modem_obj_path)
 
1546
                modem_removed(modem_obj_path);
 
1547
}
 
1548
 
 
1549
int telephony_init(void)
 
1550
{
 
1551
        uint32_t features = AG_FEATURE_EC_ANDOR_NR |
 
1552
                                AG_FEATURE_INBAND_RINGTONE |
 
1553
                                AG_FEATURE_REJECT_A_CALL |
 
1554
                                AG_FEATURE_ENHANCED_CALL_STATUS |
 
1555
                                AG_FEATURE_ENHANCED_CALL_CONTROL |
 
1556
                                AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
 
1557
                                AG_FEATURE_THREE_WAY_CALLING;
 
1558
        const char *battery_cap = "battery";
 
1559
        int ret;
 
1560
        guint watch;
 
1561
 
 
1562
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
1563
 
 
1564
        add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE,
 
1565
                        "PropertyChanged", handle_modem_property_changed);
 
1566
        add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
 
1567
                        "PropertyChanged", handle_network_property_changed);
 
1568
        add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
 
1569
                        "ModemAdded", handle_manager_modem_added);
 
1570
        add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
 
1571
                        "ModemRemoved", handle_manager_modem_removed);
 
1572
        add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
 
1573
                        "CallAdded", handle_vcmanager_call_added);
 
1574
        add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
 
1575
                        "CallRemoved", handle_vcmanager_call_removed);
 
1576
 
 
1577
        watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
 
1578
                                                handle_service_connect,
 
1579
                                                handle_service_disconnect,
 
1580
                                                NULL, NULL);
 
1581
        if (watch == 0)
 
1582
                return -ENOMEM;
 
1583
 
 
1584
        watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
 
1585
 
 
1586
#if 0 /* Disable hal */
 
1587
        ret = send_method_call("org.freedesktop.Hal",
 
1588
                                "/org/freedesktop/Hal/Manager",
 
1589
                                "org.freedesktop.Hal.Manager",
 
1590
                                "FindDeviceByCapability",
 
1591
                                hal_find_device_reply, NULL,
 
1592
                                DBUS_TYPE_STRING, &battery_cap,
 
1593
                                DBUS_TYPE_INVALID);
 
1594
        if (ret < 0)
 
1595
                return ret;
 
1596
#endif
 
1597
        DBG("telephony_init() successfully");
 
1598
 
 
1599
        telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
 
1600
                                                                chld_str);
 
1601
 
 
1602
        return ret;
 
1603
}
 
1604
 
 
1605
static void remove_watch(gpointer data)
 
1606
{
 
1607
        g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
 
1608
}
 
1609
 
 
1610
static void pending_free(void *data)
 
1611
{
 
1612
        DBusPendingCall *call = data;
 
1613
 
 
1614
        if (!dbus_pending_call_get_completed(call))
 
1615
                dbus_pending_call_cancel(call);
 
1616
 
 
1617
        dbus_pending_call_unref(call);
 
1618
}
 
1619
 
 
1620
void telephony_exit(void)
 
1621
{
 
1622
        DBG("");
 
1623
 
 
1624
        g_free(last_dialed_number);
 
1625
        last_dialed_number = NULL;
 
1626
 
 
1627
        if (modem_obj_path)
 
1628
                modem_removed(modem_obj_path);
 
1629
 
 
1630
        g_slist_free_full(watches, remove_watch);
 
1631
        watches = NULL;
 
1632
 
 
1633
        g_slist_free_full(pending, pending_free);
 
1634
        pending = NULL;
 
1635
 
 
1636
        dbus_connection_unref(connection);
 
1637
        connection = NULL;
 
1638
 
 
1639
        telephony_deinit();
 
1640
}