~ubuntu-branches/ubuntu/wily/bluez/wily

« back to all changes in this revision

Viewing changes to audio/telephony-maemo6.c

ImportĀ upstreamĀ versionĀ 4.81

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) 2008-2010  Nokia Corporation
 
6
 *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
 
7
 *
 
8
 *
 
9
 *  This program is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License as published by
 
11
 *  the Free Software Foundation; either version 2 of the License, or
 
12
 *  (at your option) any later version.
 
13
 *
 
14
 *  This program is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU General Public License
 
20
 *  along with this program; if not, write to the Free Software
 
21
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
22
 *
 
23
 */
 
24
 
 
25
#ifdef HAVE_CONFIG_H
 
26
#include <config.h>
 
27
#endif
 
28
 
 
29
#include <stdlib.h>
 
30
#include <stdio.h>
 
31
#include <unistd.h>
 
32
#include <fcntl.h>
 
33
#include <stdint.h>
 
34
#include <string.h>
 
35
#include <glib.h>
 
36
#include <dbus/dbus.h>
 
37
#include <gdbus.h>
 
38
 
 
39
#include "log.h"
 
40
#include "telephony.h"
 
41
 
 
42
/* SSC D-Bus definitions */
 
43
#define SSC_DBUS_NAME  "com.nokia.phone.SSC"
 
44
#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
 
45
#define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
 
46
 
 
47
/* libcsnet D-Bus definitions */
 
48
#define CSD_CSNET_BUS_NAME      "com.nokia.csd.CSNet"
 
49
#define CSD_CSNET_PATH          "/com/nokia/csd/csnet"
 
50
#define CSD_CSNET_IFACE         "com.nokia.csd.CSNet"
 
51
#define CSD_CSNET_REGISTRATION  "com.nokia.csd.CSNet.NetworkRegistration"
 
52
#define CSD_CSNET_OPERATOR      "com.nokia.csd.CSNet.NetworkOperator"
 
53
#define CSD_CSNET_SIGNAL        "com.nokia.csd.CSNet.SignalStrength"
 
54
 
 
55
enum net_registration_status {
 
56
        NETWORK_REG_STATUS_HOME,
 
57
        NETWORK_REG_STATUS_ROAMING,
 
58
        NETWORK_REG_STATUS_OFFLINE,
 
59
        NETWORK_REG_STATUS_SEARCHING,
 
60
        NETWORK_REG_STATUS_NO_SIM,
 
61
        NETWORK_REG_STATUS_POWEROFF,
 
62
        NETWORK_REG_STATUS_POWERSAFE,
 
63
        NETWORK_REG_STATUS_NO_COVERAGE,
 
64
        NETWORK_REG_STATUS_REJECTED,
 
65
        NETWORK_REG_STATUS_UNKOWN
 
66
};
 
67
 
 
68
/* Driver definitions */
 
69
#define TELEPHONY_MAEMO_PATH            "/com/nokia/MaemoTelephony"
 
70
#define TELEPHONY_MAEMO_INTERFACE       "com.nokia.MaemoTelephony"
 
71
 
 
72
#define CALLERID_BASE           "/var/lib/bluetooth/maemo-callerid-"
 
73
#define ALLOWED_FLAG_FILE       "/var/lib/bluetooth/maemo-callerid-allowed"
 
74
#define RESTRICTED_FLAG_FILE    "/var/lib/bluetooth/maemo-callerid-restricted"
 
75
#define NONE_FLAG_FILE          "/var/lib/bluetooth/maemo-callerid-none"
 
76
 
 
77
static uint32_t callerid = 0;
 
78
 
 
79
/* CSD CALL plugin D-Bus definitions */
 
80
#define CSD_CALL_BUS_NAME       "com.nokia.csd.Call"
 
81
#define CSD_CALL_INTERFACE      "com.nokia.csd.Call"
 
82
#define CSD_CALL_INSTANCE       "com.nokia.csd.Call.Instance"
 
83
#define CSD_CALL_CONFERENCE     "com.nokia.csd.Call.Conference"
 
84
#define CSD_CALL_PATH           "/com/nokia/csd/call"
 
85
#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
 
86
 
 
87
/* Call status values as exported by the CSD CALL plugin */
 
88
#define CSD_CALL_STATUS_IDLE                    0
 
89
#define CSD_CALL_STATUS_CREATE                  1
 
90
#define CSD_CALL_STATUS_COMING                  2
 
91
#define CSD_CALL_STATUS_PROCEEDING              3
 
92
#define CSD_CALL_STATUS_MO_ALERTING             4
 
93
#define CSD_CALL_STATUS_MT_ALERTING             5
 
94
#define CSD_CALL_STATUS_WAITING                 6
 
95
#define CSD_CALL_STATUS_ANSWERED                7
 
96
#define CSD_CALL_STATUS_ACTIVE                  8
 
97
#define CSD_CALL_STATUS_MO_RELEASE              9
 
98
#define CSD_CALL_STATUS_MT_RELEASE              10
 
99
#define CSD_CALL_STATUS_HOLD_INITIATED          11
 
100
#define CSD_CALL_STATUS_HOLD                    12
 
101
#define CSD_CALL_STATUS_RETRIEVE_INITIATED      13
 
102
#define CSD_CALL_STATUS_RECONNECT_PENDING       14
 
103
#define CSD_CALL_STATUS_TERMINATED              15
 
104
#define CSD_CALL_STATUS_SWAP_INITIATED          16
 
105
 
 
106
#define CALL_FLAG_NONE                          0
 
107
#define CALL_FLAG_PRESENTATION_ALLOWED          0x01
 
108
#define CALL_FLAG_PRESENTATION_RESTRICTED       0x02
 
109
 
 
110
/* SIM Phonebook D-Bus definitions */
 
111
#define CSD_SIMPB_BUS_NAME                      "com.nokia.csd.SIM"
 
112
#define CSD_SIMPB_INTERFACE                     "com.nokia.csd.SIM.Phonebook"
 
113
#define CSD_SIMPB_PATH                          "/com/nokia/csd/sim/phonebook"
 
114
 
 
115
#define CSD_SIMPB_TYPE_ADN                      "ADN"
 
116
#define CSD_SIMPB_TYPE_FDN                      "FDN"
 
117
#define CSD_SIMPB_TYPE_SDN                      "SDN"
 
118
#define CSD_SIMPB_TYPE_VMBX                     "VMBX"
 
119
#define CSD_SIMPB_TYPE_MBDN                     "MBDN"
 
120
#define CSD_SIMPB_TYPE_EN                       "EN"
 
121
#define CSD_SIMPB_TYPE_MSISDN                   "MSISDN"
 
122
 
 
123
struct csd_call {
 
124
        char *object_path;
 
125
        int status;
 
126
        gboolean originating;
 
127
        gboolean emergency;
 
128
        gboolean on_hold;
 
129
        gboolean conference;
 
130
        char *number;
 
131
        gboolean setup;
 
132
};
 
133
 
 
134
static struct {
 
135
        char *operator_name;
 
136
        uint8_t status;
 
137
        int32_t signal_bars;
 
138
} net = {
 
139
        .operator_name = NULL,
 
140
        .status = NETWORK_REG_STATUS_UNKOWN,
 
141
        /* Init as 0 meaning inactive mode. In modem power off state
 
142
         * can be be -1, but we treat all values as 0s regardless
 
143
         * inactive or power off. */
 
144
        .signal_bars = 0,
 
145
};
 
146
 
 
147
static int get_property(const char *iface, const char *prop);
 
148
 
 
149
static DBusConnection *connection = NULL;
 
150
 
 
151
static GSList *calls = NULL;
 
152
static GSList *watches = NULL;
 
153
static GSList *pending = NULL;
 
154
 
 
155
/* Reference count for determining the call indicator status */
 
156
static GSList *active_calls = NULL;
 
157
 
 
158
static char *msisdn = NULL;     /* Subscriber number */
 
159
static char *vmbx = NULL;       /* Voice mailbox number */
 
160
 
 
161
/* HAL battery namespace key values */
 
162
static int battchg_cur = -1;    /* "battery.charge_level.current" */
 
163
static int battchg_last = -1;   /* "battery.charge_level.last_full" */
 
164
static int battchg_design = -1; /* "battery.charge_level.design" */
 
165
 
 
166
static gboolean get_calls_active = FALSE;
 
167
 
 
168
static gboolean events_enabled = FALSE;
 
169
 
 
170
/* Supported set of call hold operations */
 
171
static const char *chld_str = "0,1,1x,2,2x,3,4";
 
172
 
 
173
/* Response and hold state
 
174
 * -1 = none
 
175
 *  0 = incoming call is put on hold in the AG
 
176
 *  1 = held incoming call is accepted in the AG
 
177
 *  2 = held incoming call is rejected in the AG
 
178
 */
 
179
static int response_and_hold = -1;
 
180
 
 
181
static char *last_dialed_number = NULL;
 
182
 
 
183
/* Timer for tracking call creation requests */
 
184
static guint create_request_timer = 0;
 
185
 
 
186
static struct indicator maemo_indicators[] =
 
187
{
 
188
        { "battchg",    "0-5",  5,      TRUE },
 
189
        /* signal strength in terms of bars */
 
190
        { "signal",     "0-5",  0,      TRUE },
 
191
        { "service",    "0,1",  0,      TRUE },
 
192
        { "call",       "0,1",  0,      TRUE },
 
193
        { "callsetup",  "0-3",  0,      TRUE },
 
194
        { "callheld",   "0-2",  0,      FALSE },
 
195
        { "roam",       "0,1",  0,      TRUE },
 
196
        { NULL }
 
197
};
 
198
 
 
199
static char *call_status_str[] = {
 
200
        "IDLE",
 
201
        "CREATE",
 
202
        "COMING",
 
203
        "PROCEEDING",
 
204
        "MO_ALERTING",
 
205
        "MT_ALERTING",
 
206
        "WAITING",
 
207
        "ANSWERED",
 
208
        "ACTIVE",
 
209
        "MO_RELEASE",
 
210
        "MT_RELEASE",
 
211
        "HOLD_INITIATED",
 
212
        "HOLD",
 
213
        "RETRIEVE_INITIATED",
 
214
        "RECONNECT_PENDING",
 
215
        "TERMINATED",
 
216
        "SWAP_INITIATED",
 
217
        "???"
 
218
};
 
219
 
 
220
static struct csd_call *find_call(const char *path)
 
221
{
 
222
        GSList *l;
 
223
 
 
224
        for (l = calls; l != NULL; l = l->next) {
 
225
                struct csd_call *call = l->data;
 
226
 
 
227
                if (g_str_equal(call->object_path, path))
 
228
                        return call;
 
229
        }
 
230
 
 
231
        return NULL;
 
232
}
 
233
 
 
234
static struct csd_call *find_non_held_call(void)
 
235
{
 
236
        GSList *l;
 
237
 
 
238
        for (l = calls; l != NULL; l = l->next) {
 
239
                struct csd_call *call = l->data;
 
240
 
 
241
                if (call->status == CSD_CALL_STATUS_IDLE)
 
242
                        continue;
 
243
 
 
244
                if (call->status != CSD_CALL_STATUS_HOLD)
 
245
                        return call;
 
246
        }
 
247
 
 
248
        return NULL;
 
249
}
 
250
 
 
251
static struct csd_call *find_non_idle_call(void)
 
252
{
 
253
        GSList *l;
 
254
 
 
255
        for (l = calls; l != NULL; l = l->next) {
 
256
                struct csd_call *call = l->data;
 
257
 
 
258
                if (call->status != CSD_CALL_STATUS_IDLE)
 
259
                        return call;
 
260
        }
 
261
 
 
262
        return NULL;
 
263
}
 
264
 
 
265
static struct csd_call *find_call_with_status(int status)
 
266
{
 
267
        GSList *l;
 
268
 
 
269
        for (l = calls; l != NULL; l = l->next) {
 
270
                struct csd_call *call = l->data;
 
271
 
 
272
                if (call->status == status)
 
273
                        return call;
 
274
        }
 
275
 
 
276
        return NULL;
 
277
}
 
278
 
 
279
static int release_conference(void)
 
280
{
 
281
        DBusMessage *msg;
 
282
 
 
283
        DBG("telephony-maemo6: releasing conference call");
 
284
 
 
285
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
 
286
                                                CSD_CALL_CONFERENCE_PATH,
 
287
                                                CSD_CALL_INSTANCE,
 
288
                                                "Release");
 
289
        if (!msg) {
 
290
                error("Unable to allocate new D-Bus message");
 
291
                return -ENOMEM;
 
292
        }
 
293
 
 
294
        g_dbus_send_message(connection, msg);
 
295
 
 
296
        return 0;
 
297
}
 
298
 
 
299
static int release_call(struct csd_call *call)
 
300
{
 
301
        DBusMessage *msg;
 
302
 
 
303
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
 
304
                                                call->object_path,
 
305
                                                CSD_CALL_INSTANCE,
 
306
                                                "Release");
 
307
        if (!msg) {
 
308
                error("Unable to allocate new D-Bus message");
 
309
                return -ENOMEM;
 
310
        }
 
311
 
 
312
        g_dbus_send_message(connection, msg);
 
313
 
 
314
        return 0;
 
315
}
 
316
 
 
317
static int answer_call(struct csd_call *call)
 
318
{
 
319
        DBusMessage *msg;
 
320
 
 
321
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
 
322
                                                call->object_path,
 
323
                                                CSD_CALL_INSTANCE,
 
324
                                                "Answer");
 
325
        if (!msg) {
 
326
                error("Unable to allocate new D-Bus message");
 
327
                return -ENOMEM;
 
328
        }
 
329
 
 
330
        g_dbus_send_message(connection, msg);
 
331
 
 
332
        return 0;
 
333
}
 
334
 
 
335
static int split_call(struct csd_call *call)
 
336
{
 
337
        DBusMessage *msg;
 
338
 
 
339
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
 
340
                                                call->object_path,
 
341
                                                CSD_CALL_INSTANCE,
 
342
                                                "Split");
 
343
        if (!msg) {
 
344
                error("Unable to allocate new D-Bus message");
 
345
                return -ENOMEM;
 
346
        }
 
347
 
 
348
        g_dbus_send_message(connection, msg);
 
349
 
 
350
        return 0;
 
351
}
 
352
 
 
353
static int unhold_call(struct csd_call *call)
 
354
{
 
355
        DBusMessage *msg;
 
356
 
 
357
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
358
                                                CSD_CALL_INTERFACE,
 
359
                                                "Unhold");
 
360
        if (!msg) {
 
361
                error("Unable to allocate new D-Bus message");
 
362
                return -ENOMEM;
 
363
        }
 
364
 
 
365
        g_dbus_send_message(connection, msg);
 
366
 
 
367
        return 0;
 
368
}
 
369
 
 
370
static int hold_call(struct csd_call *call)
 
371
{
 
372
        DBusMessage *msg;
 
373
 
 
374
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
375
                                                CSD_CALL_INTERFACE,
 
376
                                                "Hold");
 
377
        if (!msg) {
 
378
                error("Unable to allocate new D-Bus message");
 
379
                return -ENOMEM;
 
380
        }
 
381
 
 
382
        g_dbus_send_message(connection, msg);
 
383
 
 
384
        return 0;
 
385
}
 
386
 
 
387
static int swap_calls(void)
 
388
{
 
389
        DBusMessage *msg;
 
390
 
 
391
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
392
                                                CSD_CALL_INTERFACE,
 
393
                                                "Swap");
 
394
        if (!msg) {
 
395
                error("Unable to allocate new D-Bus message");
 
396
                return -ENOMEM;
 
397
        }
 
398
 
 
399
        g_dbus_send_message(connection, msg);
 
400
 
 
401
        return 0;
 
402
}
 
403
 
 
404
static int create_conference(void)
 
405
{
 
406
        DBusMessage *msg;
 
407
 
 
408
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
409
                                                CSD_CALL_INTERFACE,
 
410
                                                "Conference");
 
411
        if (!msg) {
 
412
                error("Unable to allocate new D-Bus message");
 
413
                return -ENOMEM;
 
414
        }
 
415
 
 
416
        g_dbus_send_message(connection, msg);
 
417
 
 
418
        return 0;
 
419
}
 
420
 
 
421
static int call_transfer(void)
 
422
{
 
423
        DBusMessage *msg;
 
424
 
 
425
        msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
426
                                                CSD_CALL_INTERFACE,
 
427
                                                "Transfer");
 
428
        if (!msg) {
 
429
                error("Unable to allocate new D-Bus message");
 
430
                return -ENOMEM;
 
431
        }
 
432
 
 
433
        g_dbus_send_message(connection, msg);
 
434
 
 
435
        return 0;
 
436
}
 
437
 
 
438
static int number_type(const char *number)
 
439
{
 
440
        if (number == NULL)
 
441
                return NUMBER_TYPE_TELEPHONY;
 
442
 
 
443
        if (number[0] == '+' || strncmp(number, "00", 2) == 0)
 
444
                return NUMBER_TYPE_INTERNATIONAL;
 
445
 
 
446
        return NUMBER_TYPE_TELEPHONY;
 
447
}
 
448
 
 
449
void telephony_device_connected(void *telephony_device)
 
450
{
 
451
        struct csd_call *coming;
 
452
 
 
453
        DBG("telephony-maemo6: device %p connected", telephony_device);
 
454
 
 
455
        coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
 
456
        if (coming) {
 
457
                if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
 
458
                        telephony_call_waiting_ind(coming->number,
 
459
                                                number_type(coming->number));
 
460
                else
 
461
                        telephony_incoming_call_ind(coming->number,
 
462
                                                number_type(coming->number));
 
463
        }
 
464
}
 
465
 
 
466
void telephony_device_disconnected(void *telephony_device)
 
467
{
 
468
        DBG("telephony-maemo6: device %p disconnected", telephony_device);
 
469
        events_enabled = FALSE;
 
470
}
 
471
 
 
472
void telephony_event_reporting_req(void *telephony_device, int ind)
 
473
{
 
474
        events_enabled = ind == 1 ? TRUE : FALSE;
 
475
 
 
476
        telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
 
477
}
 
478
 
 
479
void telephony_response_and_hold_req(void *telephony_device, int rh)
 
480
{
 
481
        response_and_hold = rh;
 
482
 
 
483
        telephony_response_and_hold_ind(response_and_hold);
 
484
 
 
485
        telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NONE);
 
486
}
 
487
 
 
488
void telephony_last_dialed_number_req(void *telephony_device)
 
489
{
 
490
        DBG("telephony-maemo6: last dialed number request");
 
491
 
 
492
        if (last_dialed_number)
 
493
                telephony_dial_number_req(telephony_device,
 
494
                                                last_dialed_number);
 
495
        else
 
496
                telephony_last_dialed_number_rsp(telephony_device,
 
497
                                                CME_ERROR_NOT_ALLOWED);
 
498
}
 
499
 
 
500
void telephony_terminate_call_req(void *telephony_device)
 
501
{
 
502
        struct csd_call *call;
 
503
        struct csd_call *alerting;
 
504
        int err;
 
505
 
 
506
        call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
 
507
        if (!call)
 
508
                call = find_non_idle_call();
 
509
 
 
510
        if (!call) {
 
511
                error("No active call");
 
512
                telephony_terminate_call_rsp(telephony_device,
 
513
                                                CME_ERROR_NOT_ALLOWED);
 
514
                return;
 
515
        }
 
516
 
 
517
        alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING);
 
518
        if (call->on_hold && alerting)
 
519
                err = release_call(alerting);
 
520
        else if (call->conference)
 
521
                err = release_conference();
 
522
        else
 
523
                err = release_call(call);
 
524
 
 
525
        if (err < 0)
 
526
                telephony_terminate_call_rsp(telephony_device,
 
527
                                                CME_ERROR_AG_FAILURE);
 
528
        else
 
529
                telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
 
530
}
 
531
 
 
532
void telephony_answer_call_req(void *telephony_device)
 
533
{
 
534
        struct csd_call *call;
 
535
 
 
536
        call = find_call_with_status(CSD_CALL_STATUS_COMING);
 
537
        if (!call)
 
538
                call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
 
539
 
 
540
        if (!call)
 
541
                call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
 
542
 
 
543
        if (!call)
 
544
                call = find_call_with_status(CSD_CALL_STATUS_WAITING);
 
545
 
 
546
        if (!call) {
 
547
                telephony_answer_call_rsp(telephony_device,
 
548
                                                CME_ERROR_NOT_ALLOWED);
 
549
                return;
 
550
        }
 
551
 
 
552
        if (answer_call(call) < 0)
 
553
                telephony_answer_call_rsp(telephony_device,
 
554
                                                CME_ERROR_AG_FAILURE);
 
555
        else
 
556
                telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
 
557
}
 
558
 
 
559
static int send_method_call(const char *dest, const char *path,
 
560
                                const char *interface, const char *method,
 
561
                                DBusPendingCallNotifyFunction cb,
 
562
                                void *user_data, int type, ...)
 
563
{
 
564
        DBusMessage *msg;
 
565
        DBusPendingCall *call;
 
566
        va_list args;
 
567
 
 
568
        msg = dbus_message_new_method_call(dest, path, interface, method);
 
569
        if (!msg) {
 
570
                error("Unable to allocate new D-Bus %s message", method);
 
571
                return -ENOMEM;
 
572
        }
 
573
 
 
574
        va_start(args, type);
 
575
 
 
576
        if (!dbus_message_append_args_valist(msg, type, args)) {
 
577
                dbus_message_unref(msg);
 
578
                va_end(args);
 
579
                return -EIO;
 
580
        }
 
581
 
 
582
        va_end(args);
 
583
 
 
584
        if (!cb) {
 
585
                g_dbus_send_message(connection, msg);
 
586
                return 0;
 
587
        }
 
588
 
 
589
        if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
 
590
                error("Sending %s failed", method);
 
591
                dbus_message_unref(msg);
 
592
                return -EIO;
 
593
        }
 
594
 
 
595
        dbus_pending_call_set_notify(call, cb, user_data, NULL);
 
596
        pending = g_slist_prepend(pending, call);
 
597
        dbus_message_unref(msg);
 
598
 
 
599
        return 0;
 
600
}
 
601
 
 
602
static const char *memory_dial_lookup(int location)
 
603
{
 
604
        if (location == 1)
 
605
                return vmbx;
 
606
        else
 
607
                return NULL;
 
608
}
 
609
 
 
610
void telephony_dial_number_req(void *telephony_device, const char *number)
 
611
{
 
612
        uint32_t flags = callerid;
 
613
        int ret;
 
614
 
 
615
        DBG("telephony-maemo6: dial request to %s", number);
 
616
 
 
617
        if (strncmp(number, "*31#", 4) == 0) {
 
618
                number += 4;
 
619
                flags = CALL_FLAG_PRESENTATION_ALLOWED;
 
620
        } else if (strncmp(number, "#31#", 4) == 0) {
 
621
                number += 4;
 
622
                flags = CALL_FLAG_PRESENTATION_RESTRICTED;
 
623
        } else if (number[0] == '>') {
 
624
                const char *location = &number[1];
 
625
 
 
626
                number = memory_dial_lookup(strtol(&number[1], NULL, 0));
 
627
                if (!number) {
 
628
                        error("No number at memory location %s", location);
 
629
                        telephony_dial_number_rsp(telephony_device,
 
630
                                                CME_ERROR_INVALID_INDEX);
 
631
                        return;
 
632
                }
 
633
        }
 
634
 
 
635
        ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
636
                                CSD_CALL_INTERFACE, "CreateWith",
 
637
                                NULL, NULL,
 
638
                                DBUS_TYPE_STRING, &number,
 
639
                                DBUS_TYPE_UINT32, &flags,
 
640
                                DBUS_TYPE_INVALID);
 
641
        if (ret < 0) {
 
642
                telephony_dial_number_rsp(telephony_device,
 
643
                                                CME_ERROR_AG_FAILURE);
 
644
                return;
 
645
        }
 
646
 
 
647
        telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
 
648
}
 
649
 
 
650
void telephony_transmit_dtmf_req(void *telephony_device, char tone)
 
651
{
 
652
        int ret;
 
653
        char buf[2] = { tone, '\0' }, *buf_ptr = buf;
 
654
 
 
655
        DBG("telephony-maemo6: transmit dtmf: %s", buf);
 
656
 
 
657
        ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
658
                                CSD_CALL_INTERFACE, "SendDTMF",
 
659
                                NULL, NULL,
 
660
                                DBUS_TYPE_STRING, &buf_ptr,
 
661
                                DBUS_TYPE_INVALID);
 
662
        if (ret < 0) {
 
663
                telephony_transmit_dtmf_rsp(telephony_device,
 
664
                                                CME_ERROR_AG_FAILURE);
 
665
                return;
 
666
        }
 
667
 
 
668
        telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
 
669
}
 
670
 
 
671
void telephony_subscriber_number_req(void *telephony_device)
 
672
{
 
673
        DBG("telephony-maemo6: subscriber number request");
 
674
        if (msisdn)
 
675
                telephony_subscriber_number_ind(msisdn,
 
676
                                                number_type(msisdn),
 
677
                                                SUBSCRIBER_SERVICE_VOICE);
 
678
        telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
 
679
}
 
680
 
 
681
static int csd_status_to_hfp(struct csd_call *call)
 
682
{
 
683
        switch (call->status) {
 
684
        case CSD_CALL_STATUS_IDLE:
 
685
        case CSD_CALL_STATUS_MO_RELEASE:
 
686
        case CSD_CALL_STATUS_MT_RELEASE:
 
687
        case CSD_CALL_STATUS_TERMINATED:
 
688
                return -1;
 
689
        case CSD_CALL_STATUS_CREATE:
 
690
                return CALL_STATUS_DIALING;
 
691
        case CSD_CALL_STATUS_WAITING:
 
692
                return CALL_STATUS_WAITING;
 
693
        case CSD_CALL_STATUS_PROCEEDING:
 
694
                /* PROCEEDING can happen in outgoing/incoming */
 
695
                if (call->originating)
 
696
                        return CALL_STATUS_DIALING;
 
697
                else
 
698
                        return CALL_STATUS_INCOMING;
 
699
        case CSD_CALL_STATUS_COMING:
 
700
                return CALL_STATUS_INCOMING;
 
701
        case CSD_CALL_STATUS_MO_ALERTING:
 
702
                return CALL_STATUS_ALERTING;
 
703
        case CSD_CALL_STATUS_MT_ALERTING:
 
704
                return CALL_STATUS_INCOMING;
 
705
        case CSD_CALL_STATUS_ANSWERED:
 
706
        case CSD_CALL_STATUS_ACTIVE:
 
707
        case CSD_CALL_STATUS_RECONNECT_PENDING:
 
708
        case CSD_CALL_STATUS_SWAP_INITIATED:
 
709
        case CSD_CALL_STATUS_HOLD_INITIATED:
 
710
                return CALL_STATUS_ACTIVE;
 
711
        case CSD_CALL_STATUS_RETRIEVE_INITIATED:
 
712
        case CSD_CALL_STATUS_HOLD:
 
713
                return CALL_STATUS_HELD;
 
714
        default:
 
715
                return -1;
 
716
        }
 
717
}
 
718
 
 
719
void telephony_list_current_calls_req(void *telephony_device)
 
720
{
 
721
        GSList *l;
 
722
        int i;
 
723
 
 
724
        DBG("telephony-maemo6: list current calls request");
 
725
 
 
726
        for (l = calls, i = 1; l != NULL; l = l->next, i++) {
 
727
                struct csd_call *call = l->data;
 
728
                int status, direction, multiparty;
 
729
 
 
730
                status = csd_status_to_hfp(call);
 
731
                if (status < 0)
 
732
                        continue;
 
733
 
 
734
                direction = call->originating ?
 
735
                                CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
 
736
 
 
737
                multiparty = call->conference ?
 
738
                                CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
 
739
 
 
740
                telephony_list_current_call_ind(i, direction, status,
 
741
                                                CALL_MODE_VOICE, multiparty,
 
742
                                                call->number,
 
743
                                                number_type(call->number));
 
744
        }
 
745
 
 
746
        telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
 
747
}
 
748
 
 
749
void telephony_operator_selection_req(void *telephony_device)
 
750
{
 
751
        telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
 
752
                                net.operator_name ? net.operator_name : "");
 
753
        telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
 
754
}
 
755
 
 
756
static void foreach_call_with_status(int status,
 
757
                                        int (*func)(struct csd_call *call))
 
758
{
 
759
        GSList *l;
 
760
 
 
761
        for (l = calls; l != NULL; l = l->next) {
 
762
                struct csd_call *call = l->data;
 
763
 
 
764
                if (call->status == status)
 
765
                        func(call);
 
766
        }
 
767
}
 
768
 
 
769
void telephony_call_hold_req(void *telephony_device, const char *cmd)
 
770
{
 
771
        const char *idx;
 
772
        struct csd_call *call;
 
773
        int err = 0;
 
774
 
 
775
        DBG("telephony-maemo6: got call hold request %s", cmd);
 
776
 
 
777
        if (strlen(cmd) > 1)
 
778
                idx = &cmd[1];
 
779
        else
 
780
                idx = NULL;
 
781
 
 
782
        if (idx)
 
783
                call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
 
784
        else
 
785
                call = NULL;
 
786
 
 
787
        switch (cmd[0]) {
 
788
        case '0':
 
789
                if (find_call_with_status(CSD_CALL_STATUS_WAITING))
 
790
                        foreach_call_with_status(CSD_CALL_STATUS_WAITING,
 
791
                                                                release_call);
 
792
                else
 
793
                        foreach_call_with_status(CSD_CALL_STATUS_HOLD,
 
794
                                                                release_call);
 
795
                break;
 
796
        case '1':
 
797
                if (idx) {
 
798
                        if (call)
 
799
                                err = release_call(call);
 
800
                        break;
 
801
                }
 
802
                foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call);
 
803
                call = find_call_with_status(CSD_CALL_STATUS_WAITING);
 
804
                if (call)
 
805
                        err = answer_call(call);
 
806
                break;
 
807
        case '2':
 
808
                if (idx) {
 
809
                        if (call)
 
810
                                err = split_call(call);
 
811
                } else {
 
812
                        struct csd_call *held, *wait;
 
813
 
 
814
                        call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
 
815
                        held = find_call_with_status(CSD_CALL_STATUS_HOLD);
 
816
                        wait = find_call_with_status(CSD_CALL_STATUS_WAITING);
 
817
 
 
818
                        if (wait)
 
819
                                err = answer_call(wait);
 
820
                        else if (call && held)
 
821
                                err = swap_calls();
 
822
                        else {
 
823
                                if (call)
 
824
                                        err = hold_call(call);
 
825
                                if (held)
 
826
                                        err = unhold_call(held);
 
827
                        }
 
828
                }
 
829
                break;
 
830
        case '3':
 
831
                if (find_call_with_status(CSD_CALL_STATUS_HOLD) ||
 
832
                                find_call_with_status(CSD_CALL_STATUS_WAITING))
 
833
                        err = create_conference();
 
834
                break;
 
835
        case '4':
 
836
                err = call_transfer();
 
837
                break;
 
838
        default:
 
839
                DBG("Unknown call hold request");
 
840
                break;
 
841
        }
 
842
 
 
843
        if (err)
 
844
                telephony_call_hold_rsp(telephony_device,
 
845
                                        CME_ERROR_AG_FAILURE);
 
846
        else
 
847
                telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
 
848
}
 
849
 
 
850
void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
 
851
{
 
852
        DBG("telephony-maemo6: got %s NR and EC request",
 
853
                        enable ? "enable" : "disable");
 
854
        telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
 
855
}
 
856
 
 
857
void telephony_key_press_req(void *telephony_device, const char *keys)
 
858
{
 
859
        struct csd_call *active, *waiting;
 
860
        int err;
 
861
 
 
862
        DBG("telephony-maemo6: got key press request for %s", keys);
 
863
 
 
864
        waiting = find_call_with_status(CSD_CALL_STATUS_COMING);
 
865
        if (!waiting)
 
866
                waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
 
867
        if (!waiting)
 
868
                waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
 
869
 
 
870
        active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
 
871
 
 
872
        if (waiting)
 
873
                err = answer_call(waiting);
 
874
        else if (active)
 
875
                err = release_call(active);
 
876
        else
 
877
                err = 0;
 
878
 
 
879
        if (err < 0)
 
880
                telephony_key_press_rsp(telephony_device,
 
881
                                                        CME_ERROR_AG_FAILURE);
 
882
        else
 
883
                telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
 
884
}
 
885
 
 
886
void telephony_voice_dial_req(void *telephony_device, gboolean enable)
 
887
{
 
888
        DBG("telephony-maemo6: got %s voice dial request",
 
889
                        enable ? "enable" : "disable");
 
890
 
 
891
        telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
 
892
}
 
893
 
 
894
static void handle_incoming_call(DBusMessage *msg)
 
895
{
 
896
        const char *number, *call_path;
 
897
        struct csd_call *call;
 
898
 
 
899
        if (!dbus_message_get_args(msg, NULL,
 
900
                                        DBUS_TYPE_OBJECT_PATH, &call_path,
 
901
                                        DBUS_TYPE_STRING, &number,
 
902
                                        DBUS_TYPE_INVALID)) {
 
903
                error("Unexpected parameters in Call.Coming() signal");
 
904
                return;
 
905
        }
 
906
 
 
907
        call = find_call(call_path);
 
908
        if (!call) {
 
909
                error("Didn't find any matching call object for %s",
 
910
                                call_path);
 
911
                return;
 
912
        }
 
913
 
 
914
        DBG("Incoming call to %s from number %s", call_path, number);
 
915
 
 
916
        g_free(call->number);
 
917
        call->number = g_strdup(number);
 
918
 
 
919
        if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) ||
 
920
                        find_call_with_status(CSD_CALL_STATUS_HOLD))
 
921
                telephony_call_waiting_ind(call->number,
 
922
                                                number_type(call->number));
 
923
        else
 
924
                telephony_incoming_call_ind(call->number,
 
925
                                                number_type(call->number));
 
926
 
 
927
        telephony_update_indicator(maemo_indicators, "callsetup",
 
928
                                        EV_CALLSETUP_INCOMING);
 
929
}
 
930
 
 
931
static void handle_outgoing_call(DBusMessage *msg)
 
932
{
 
933
        const char *number, *call_path;
 
934
        struct csd_call *call;
 
935
 
 
936
        if (!dbus_message_get_args(msg, NULL,
 
937
                                        DBUS_TYPE_OBJECT_PATH, &call_path,
 
938
                                        DBUS_TYPE_STRING, &number,
 
939
                                        DBUS_TYPE_INVALID)) {
 
940
                error("Unexpected parameters in Call.Created() signal");
 
941
                return;
 
942
        }
 
943
 
 
944
        call = find_call(call_path);
 
945
        if (!call) {
 
946
                error("Didn't find any matching call object for %s",
 
947
                                call_path);
 
948
                return;
 
949
        }
 
950
 
 
951
        DBG("Outgoing call from %s to number %s", call_path, number);
 
952
 
 
953
        g_free(call->number);
 
954
        call->number = g_strdup(number);
 
955
 
 
956
        g_free(last_dialed_number);
 
957
        last_dialed_number = g_strdup(number);
 
958
 
 
959
        if (create_request_timer) {
 
960
                g_source_remove(create_request_timer);
 
961
                create_request_timer = 0;
 
962
        }
 
963
}
 
964
 
 
965
static gboolean create_timeout(gpointer user_data)
 
966
{
 
967
        telephony_update_indicator(maemo_indicators, "callsetup",
 
968
                                        EV_CALLSETUP_INACTIVE);
 
969
        create_request_timer = 0;
 
970
        return FALSE;
 
971
}
 
972
 
 
973
static void handle_create_requested(DBusMessage *msg)
 
974
{
 
975
        DBG("Call.CreateRequested()");
 
976
 
 
977
        if (create_request_timer)
 
978
                g_source_remove(create_request_timer);
 
979
 
 
980
        create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
 
981
 
 
982
        telephony_update_indicator(maemo_indicators, "callsetup",
 
983
                                        EV_CALLSETUP_OUTGOING);
 
984
}
 
985
 
 
986
static void handle_call_status(DBusMessage *msg, const char *call_path)
 
987
{
 
988
        struct csd_call *call;
 
989
        dbus_uint32_t status, cause_type, cause, prev_status;
 
990
        int callheld = telephony_get_indicator(maemo_indicators, "callheld");
 
991
 
 
992
        if (!dbus_message_get_args(msg, NULL,
 
993
                                        DBUS_TYPE_UINT32, &status,
 
994
                                        DBUS_TYPE_UINT32, &cause_type,
 
995
                                        DBUS_TYPE_UINT32, &cause,
 
996
                                        DBUS_TYPE_INVALID)) {
 
997
                error("Unexpected paramters in Instance.CallStatus() signal");
 
998
                return;
 
999
        }
 
1000
 
 
1001
        call = find_call(call_path);
 
1002
        if (!call) {
 
1003
                error("Didn't find any matching call object for %s",
 
1004
                                call_path);
 
1005
                return;
 
1006
        }
 
1007
 
 
1008
        if (status > 16) {
 
1009
                error("Invalid call status %u", status);
 
1010
                return;
 
1011
        }
 
1012
 
 
1013
        prev_status = call->status;
 
1014
        DBG("Call %s changed from %s to %s", call_path,
 
1015
                call_status_str[prev_status], call_status_str[status]);
 
1016
 
 
1017
        if (prev_status == status) {
 
1018
                DBG("Ignoring CSD Call state change to existing state");
 
1019
                return;
 
1020
        }
 
1021
 
 
1022
        call->status = (int) status;
 
1023
 
 
1024
        switch (status) {
 
1025
        case CSD_CALL_STATUS_IDLE:
 
1026
                if (call->setup) {
 
1027
                        telephony_update_indicator(maemo_indicators,
 
1028
                                                        "callsetup",
 
1029
                                                        EV_CALLSETUP_INACTIVE);
 
1030
                        if (!call->originating)
 
1031
                                telephony_calling_stopped_ind();
 
1032
                }
 
1033
 
 
1034
                g_free(call->number);
 
1035
                call->number = NULL;
 
1036
                call->originating = FALSE;
 
1037
                call->emergency = FALSE;
 
1038
                call->on_hold = FALSE;
 
1039
                call->conference = FALSE;
 
1040
                call->setup = FALSE;
 
1041
                break;
 
1042
        case CSD_CALL_STATUS_CREATE:
 
1043
                call->originating = TRUE;
 
1044
                call->setup = TRUE;
 
1045
                break;
 
1046
        case CSD_CALL_STATUS_COMING:
 
1047
                call->originating = FALSE;
 
1048
                call->setup = TRUE;
 
1049
                break;
 
1050
        case CSD_CALL_STATUS_PROCEEDING:
 
1051
                break;
 
1052
        case CSD_CALL_STATUS_MO_ALERTING:
 
1053
                telephony_update_indicator(maemo_indicators, "callsetup",
 
1054
                                                EV_CALLSETUP_ALERTING);
 
1055
                break;
 
1056
        case CSD_CALL_STATUS_MT_ALERTING:
 
1057
                /* Some headsets expect incoming call notification before they
 
1058
                 * can send ATA command. When call changed status from waiting
 
1059
                 * to alerting we need to send missing notification. Otherwise
 
1060
                 * headsets like Nokia BH-108 or BackBeat 903 are unable to
 
1061
                 * answer incoming call that was previously waiting. */
 
1062
                if (prev_status == CSD_CALL_STATUS_WAITING)
 
1063
                        telephony_incoming_call_ind(call->number,
 
1064
                                                number_type(call->number));
 
1065
                break;
 
1066
        case CSD_CALL_STATUS_WAITING:
 
1067
                break;
 
1068
        case CSD_CALL_STATUS_ANSWERED:
 
1069
                break;
 
1070
        case CSD_CALL_STATUS_ACTIVE:
 
1071
                if (call->on_hold) {
 
1072
                        call->on_hold = FALSE;
 
1073
                        if (find_call_with_status(CSD_CALL_STATUS_HOLD))
 
1074
                                telephony_update_indicator(maemo_indicators,
 
1075
                                                        "callheld",
 
1076
                                                        EV_CALLHELD_MULTIPLE);
 
1077
                        else
 
1078
                                telephony_update_indicator(maemo_indicators,
 
1079
                                                        "callheld",
 
1080
                                                        EV_CALLHELD_NONE);
 
1081
                } else {
 
1082
                        if (!g_slist_find(active_calls, call))
 
1083
                                active_calls = g_slist_prepend(active_calls, call);
 
1084
                        if (g_slist_length(active_calls) == 1)
 
1085
                                telephony_update_indicator(maemo_indicators,
 
1086
                                                                "call",
 
1087
                                                                EV_CALL_ACTIVE);
 
1088
                        /* Upgrade callheld status if necessary */
 
1089
                        if (callheld == EV_CALLHELD_ON_HOLD)
 
1090
                                telephony_update_indicator(maemo_indicators,
 
1091
                                                        "callheld",
 
1092
                                                        EV_CALLHELD_MULTIPLE);
 
1093
                        telephony_update_indicator(maemo_indicators,
 
1094
                                                        "callsetup",
 
1095
                                                        EV_CALLSETUP_INACTIVE);
 
1096
                        if (!call->originating)
 
1097
                                telephony_calling_stopped_ind();
 
1098
                        call->setup = FALSE;
 
1099
                }
 
1100
                break;
 
1101
        case CSD_CALL_STATUS_MO_RELEASE:
 
1102
        case CSD_CALL_STATUS_MT_RELEASE:
 
1103
                active_calls = g_slist_remove(active_calls, call);
 
1104
                if (g_slist_length(active_calls) == 0)
 
1105
                        telephony_update_indicator(maemo_indicators, "call",
 
1106
                                                        EV_CALL_INACTIVE);
 
1107
                break;
 
1108
        case CSD_CALL_STATUS_HOLD_INITIATED:
 
1109
                break;
 
1110
        case CSD_CALL_STATUS_HOLD:
 
1111
                call->on_hold = TRUE;
 
1112
                if (find_non_held_call())
 
1113
                        telephony_update_indicator(maemo_indicators,
 
1114
                                                        "callheld",
 
1115
                                                        EV_CALLHELD_MULTIPLE);
 
1116
                else
 
1117
                        telephony_update_indicator(maemo_indicators,
 
1118
                                                        "callheld",
 
1119
                                                        EV_CALLHELD_ON_HOLD);
 
1120
                break;
 
1121
        case CSD_CALL_STATUS_RETRIEVE_INITIATED:
 
1122
                break;
 
1123
        case CSD_CALL_STATUS_RECONNECT_PENDING:
 
1124
                break;
 
1125
        case CSD_CALL_STATUS_TERMINATED:
 
1126
                if (call->on_hold &&
 
1127
                                !find_call_with_status(CSD_CALL_STATUS_HOLD))
 
1128
                        telephony_update_indicator(maemo_indicators,
 
1129
                                                        "callheld",
 
1130
                                                        EV_CALLHELD_NONE);
 
1131
                else if (callheld == EV_CALLHELD_MULTIPLE &&
 
1132
                                find_call_with_status(CSD_CALL_STATUS_HOLD))
 
1133
                        telephony_update_indicator(maemo_indicators,
 
1134
                                                        "callheld",
 
1135
                                                        EV_CALLHELD_ON_HOLD);
 
1136
                break;
 
1137
        case CSD_CALL_STATUS_SWAP_INITIATED:
 
1138
                break;
 
1139
        default:
 
1140
                error("Unknown call status %u", status);
 
1141
                break;
 
1142
        }
 
1143
}
 
1144
 
 
1145
static void handle_conference(DBusMessage *msg, gboolean joined)
 
1146
{
 
1147
        const char *path;
 
1148
        struct csd_call *call;
 
1149
 
 
1150
        if (!dbus_message_get_args(msg, NULL,
 
1151
                                        DBUS_TYPE_OBJECT_PATH, &path,
 
1152
                                        DBUS_TYPE_INVALID)) {
 
1153
                error("Unexpected parameters in Conference.%s",
 
1154
                                        dbus_message_get_member(msg));
 
1155
                return;
 
1156
        }
 
1157
 
 
1158
        call = find_call(path);
 
1159
        if (!call) {
 
1160
                error("Conference signal for unknown call %s", path);
 
1161
                return;
 
1162
        }
 
1163
 
 
1164
        DBG("Call %s %s the conference", path, joined ? "joined" : "left");
 
1165
 
 
1166
        call->conference = joined;
 
1167
}
 
1168
 
 
1169
static uint8_t str2status(const char *state)
 
1170
{
 
1171
        if (g_strcmp0(state, "Home") == 0)
 
1172
                return NETWORK_REG_STATUS_HOME;
 
1173
        else if (g_strcmp0(state, "Roaming") == 0)
 
1174
                return NETWORK_REG_STATUS_ROAMING;
 
1175
        else if (g_strcmp0(state, "Offline") == 0)
 
1176
                return NETWORK_REG_STATUS_OFFLINE;
 
1177
        else if (g_strcmp0(state, "Searching") == 0)
 
1178
                return NETWORK_REG_STATUS_SEARCHING;
 
1179
        else if (g_strcmp0(state, "NoSim") == 0)
 
1180
                return NETWORK_REG_STATUS_NO_SIM;
 
1181
        else if (g_strcmp0(state, "Poweroff") == 0)
 
1182
                return NETWORK_REG_STATUS_POWEROFF;
 
1183
        else if (g_strcmp0(state, "Powersafe") == 0)
 
1184
                return NETWORK_REG_STATUS_POWERSAFE;
 
1185
        else if (g_strcmp0(state, "NoCoverage") == 0)
 
1186
                return NETWORK_REG_STATUS_NO_COVERAGE;
 
1187
        else if (g_strcmp0(state, "Reject") == 0)
 
1188
                return NETWORK_REG_STATUS_REJECTED;
 
1189
        else
 
1190
                return NETWORK_REG_STATUS_UNKOWN;
 
1191
}
 
1192
 
 
1193
static void update_registration_status(const char *status)
 
1194
{
 
1195
        uint8_t new_status;
 
1196
 
 
1197
        new_status = str2status(status);
 
1198
 
 
1199
        if (net.status == new_status)
 
1200
                return;
 
1201
 
 
1202
        switch (new_status) {
 
1203
        case NETWORK_REG_STATUS_HOME:
 
1204
                telephony_update_indicator(maemo_indicators, "roam",
 
1205
                                                        EV_ROAM_INACTIVE);
 
1206
                if (net.status > NETWORK_REG_STATUS_ROAMING)
 
1207
                        telephony_update_indicator(maemo_indicators,
 
1208
                                                        "service",
 
1209
                                                        EV_SERVICE_PRESENT);
 
1210
                break;
 
1211
        case NETWORK_REG_STATUS_ROAMING:
 
1212
                telephony_update_indicator(maemo_indicators, "roam",
 
1213
                                                        EV_ROAM_ACTIVE);
 
1214
                if (net.status > NETWORK_REG_STATUS_ROAMING)
 
1215
                        telephony_update_indicator(maemo_indicators,
 
1216
                                                        "service",
 
1217
                                                        EV_SERVICE_PRESENT);
 
1218
                break;
 
1219
        case NETWORK_REG_STATUS_OFFLINE:
 
1220
        case NETWORK_REG_STATUS_SEARCHING:
 
1221
        case NETWORK_REG_STATUS_NO_SIM:
 
1222
        case NETWORK_REG_STATUS_POWEROFF:
 
1223
        case NETWORK_REG_STATUS_POWERSAFE:
 
1224
        case NETWORK_REG_STATUS_NO_COVERAGE:
 
1225
        case NETWORK_REG_STATUS_REJECTED:
 
1226
        case NETWORK_REG_STATUS_UNKOWN:
 
1227
                if (net.status < NETWORK_REG_STATUS_OFFLINE)
 
1228
                        telephony_update_indicator(maemo_indicators,
 
1229
                                                        "service",
 
1230
                                                        EV_SERVICE_NONE);
 
1231
                break;
 
1232
        }
 
1233
 
 
1234
        net.status = new_status;
 
1235
 
 
1236
        DBG("telephony-maemo6: registration status changed: %s", status);
 
1237
}
 
1238
 
 
1239
static void handle_registration_changed(DBusMessage *msg)
 
1240
{
 
1241
        const char *status;
 
1242
 
 
1243
        if (!dbus_message_get_args(msg, NULL,
 
1244
                                        DBUS_TYPE_STRING, &status,
 
1245
                                        DBUS_TYPE_INVALID)) {
 
1246
                error("Unexpected parameters in RegistrationChanged");
 
1247
                return;
 
1248
        }
 
1249
 
 
1250
        update_registration_status(status);
 
1251
}
 
1252
 
 
1253
static void update_signal_strength(int32_t signal_bars)
 
1254
{
 
1255
        if (signal_bars < 0) {
 
1256
                DBG("signal strength smaller than expected: %d < 0",
 
1257
                                                                signal_bars);
 
1258
                signal_bars = 0;
 
1259
        } else if (signal_bars > 5) {
 
1260
                DBG("signal strength greater than expected: %d > 5",
 
1261
                                                                signal_bars);
 
1262
                signal_bars = 5;
 
1263
        }
 
1264
 
 
1265
        if (net.signal_bars == signal_bars)
 
1266
                return;
 
1267
 
 
1268
        telephony_update_indicator(maemo_indicators, "signal", signal_bars);
 
1269
 
 
1270
        net.signal_bars = signal_bars;
 
1271
        DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
 
1272
}
 
1273
 
 
1274
static void handle_signal_bars_changed(DBusMessage *msg)
 
1275
{
 
1276
        int32_t signal_bars;
 
1277
 
 
1278
        if (!dbus_message_get_args(msg, NULL,
 
1279
                                        DBUS_TYPE_INT32, &signal_bars,
 
1280
                                        DBUS_TYPE_INVALID)) {
 
1281
                error("Unexpected parameters in SignalBarsChanged");
 
1282
                return;
 
1283
        }
 
1284
 
 
1285
        update_signal_strength(signal_bars);
 
1286
}
 
1287
 
 
1288
static gboolean iter_get_basic_args(DBusMessageIter *iter,
 
1289
                                        int first_arg_type, ...)
 
1290
{
 
1291
        int type;
 
1292
        va_list ap;
 
1293
 
 
1294
        va_start(ap, first_arg_type);
 
1295
 
 
1296
        for (type = first_arg_type; type != DBUS_TYPE_INVALID;
 
1297
                        type = va_arg(ap, int)) {
 
1298
                void *value = va_arg(ap, void *);
 
1299
                int real_type = dbus_message_iter_get_arg_type(iter);
 
1300
 
 
1301
                if (real_type != type) {
 
1302
                        error("iter_get_basic_args: expected %c but got %c",
 
1303
                                        (char) type, (char) real_type);
 
1304
                        break;
 
1305
                }
 
1306
 
 
1307
                dbus_message_iter_get_basic(iter, value);
 
1308
                dbus_message_iter_next(iter);
 
1309
        }
 
1310
 
 
1311
        va_end(ap);
 
1312
 
 
1313
        return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
 
1314
}
 
1315
 
 
1316
static void remove_pending(DBusPendingCall *call)
 
1317
{
 
1318
        pending = g_slist_remove(pending, call);
 
1319
        dbus_pending_call_unref(call);
 
1320
}
 
1321
 
 
1322
static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
 
1323
{
 
1324
        DBusError err;
 
1325
        DBusMessage *reply;
 
1326
        dbus_int32_t level;
 
1327
        int *value = user_data;
 
1328
 
 
1329
        reply = dbus_pending_call_steal_reply(call);
 
1330
 
 
1331
        dbus_error_init(&err);
 
1332
        if (dbus_set_error_from_message(&err, reply)) {
 
1333
                error("hald replied with an error: %s, %s",
 
1334
                                err.name, err.message);
 
1335
                dbus_error_free(&err);
 
1336
                goto done;
 
1337
        }
 
1338
 
 
1339
        if (!dbus_message_get_args(reply, NULL,
 
1340
                                DBUS_TYPE_INT32, &level,
 
1341
                                DBUS_TYPE_INVALID)) {
 
1342
                error("Unexpected args in hald reply");
 
1343
                goto done;
 
1344
        }
 
1345
 
 
1346
        *value = (int) level;
 
1347
 
 
1348
        if (value == &battchg_last)
 
1349
                DBG("telephony-maemo6: battery.charge_level.last_full is %d",
 
1350
                                *value);
 
1351
        else if (value == &battchg_design)
 
1352
                DBG("telephony-maemo6: battery.charge_level.design is %d",
 
1353
                                *value);
 
1354
        else
 
1355
                DBG("telephony-maemo6: battery.charge_level.current is %d",
 
1356
                                *value);
 
1357
 
 
1358
        if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
 
1359
                int new, max;
 
1360
 
 
1361
                if (battchg_last > 0)
 
1362
                        max = battchg_last;
 
1363
                else
 
1364
                        max = battchg_design;
 
1365
 
 
1366
                new = battchg_cur * 5 / max;
 
1367
 
 
1368
                telephony_update_indicator(maemo_indicators, "battchg", new);
 
1369
        }
 
1370
 
 
1371
done:
 
1372
        dbus_message_unref(reply);
 
1373
        remove_pending(call);
 
1374
}
 
1375
 
 
1376
static void hal_get_integer(const char *path, const char *key, void *user_data)
 
1377
{
 
1378
        send_method_call("org.freedesktop.Hal", path,
 
1379
                                "org.freedesktop.Hal.Device",
 
1380
                                "GetPropertyInteger",
 
1381
                                hal_battery_level_reply, user_data,
 
1382
                                DBUS_TYPE_STRING, &key,
 
1383
                                DBUS_TYPE_INVALID);
 
1384
}
 
1385
 
 
1386
static void handle_hal_property_modified(DBusMessage *msg)
 
1387
{
 
1388
        DBusMessageIter iter, array;
 
1389
        dbus_int32_t num_changes;
 
1390
        const char *path;
 
1391
 
 
1392
        path = dbus_message_get_path(msg);
 
1393
 
 
1394
        dbus_message_iter_init(msg, &iter);
 
1395
 
 
1396
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
 
1397
                error("Unexpected signature in hal PropertyModified signal");
 
1398
                return;
 
1399
        }
 
1400
 
 
1401
        dbus_message_iter_get_basic(&iter, &num_changes);
 
1402
        dbus_message_iter_next(&iter);
 
1403
 
 
1404
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
1405
                error("Unexpected signature in hal PropertyModified signal");
 
1406
                return;
 
1407
        }
 
1408
 
 
1409
        dbus_message_iter_recurse(&iter, &array);
 
1410
 
 
1411
        while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
 
1412
                DBusMessageIter prop;
 
1413
                const char *name;
 
1414
                dbus_bool_t added, removed;
 
1415
 
 
1416
                dbus_message_iter_recurse(&array, &prop);
 
1417
 
 
1418
                if (!iter_get_basic_args(&prop,
 
1419
                                        DBUS_TYPE_STRING, &name,
 
1420
                                        DBUS_TYPE_BOOLEAN, &added,
 
1421
                                        DBUS_TYPE_BOOLEAN, &removed,
 
1422
                                        DBUS_TYPE_INVALID)) {
 
1423
                        error("Invalid hal PropertyModified parameters");
 
1424
                        break;
 
1425
                }
 
1426
 
 
1427
                if (g_str_equal(name, "battery.charge_level.last_full"))
 
1428
                        hal_get_integer(path, name, &battchg_last);
 
1429
                else if (g_str_equal(name, "battery.charge_level.current"))
 
1430
                        hal_get_integer(path, name, &battchg_cur);
 
1431
                else if (g_str_equal(name, "battery.charge_level.design"))
 
1432
                        hal_get_integer(path, name, &battchg_design);
 
1433
 
 
1434
                dbus_message_iter_next(&array);
 
1435
        }
 
1436
}
 
1437
 
 
1438
static void csd_call_free(struct csd_call *call)
 
1439
{
 
1440
        if (!call)
 
1441
                return;
 
1442
 
 
1443
        g_free(call->object_path);
 
1444
        g_free(call->number);
 
1445
 
 
1446
        g_free(call);
 
1447
}
 
1448
 
 
1449
static void parse_call_list(DBusMessageIter *iter)
 
1450
{
 
1451
        do {
 
1452
                DBusMessageIter call_iter;
 
1453
                struct csd_call *call;
 
1454
                const char *object_path, *number;
 
1455
                dbus_uint32_t status;
 
1456
                dbus_bool_t originating, terminating, emerg, on_hold, conf;
 
1457
 
 
1458
                if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
 
1459
                        error("Unexpected signature in GetCallInfoAll reply");
 
1460
                        break;
 
1461
                }
 
1462
 
 
1463
                dbus_message_iter_recurse(iter, &call_iter);
 
1464
 
 
1465
                if (!iter_get_basic_args(&call_iter,
 
1466
                                        DBUS_TYPE_OBJECT_PATH, &object_path,
 
1467
                                        DBUS_TYPE_UINT32, &status,
 
1468
                                        DBUS_TYPE_BOOLEAN, &originating,
 
1469
                                        DBUS_TYPE_BOOLEAN, &terminating,
 
1470
                                        DBUS_TYPE_BOOLEAN, &emerg,
 
1471
                                        DBUS_TYPE_BOOLEAN, &on_hold,
 
1472
                                        DBUS_TYPE_BOOLEAN, &conf,
 
1473
                                        DBUS_TYPE_STRING, &number,
 
1474
                                        DBUS_TYPE_INVALID)) {
 
1475
                        error("Parsing call D-Bus parameters failed");
 
1476
                        break;
 
1477
                }
 
1478
 
 
1479
                call = find_call(object_path);
 
1480
                if (!call) {
 
1481
                        call = g_new0(struct csd_call, 1);
 
1482
                        call->object_path = g_strdup(object_path);
 
1483
                        call->status = (int) status;
 
1484
                        calls = g_slist_append(calls, call);
 
1485
                        DBG("telephony-maemo6: new csd call instance at %s",
 
1486
                                                                object_path);
 
1487
                }
 
1488
 
 
1489
                if (call->status == CSD_CALL_STATUS_IDLE)
 
1490
                        continue;
 
1491
 
 
1492
                /* CSD gives incorrect call_hold property sometimes */
 
1493
                if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
 
1494
                                (call->status == CSD_CALL_STATUS_HOLD &&
 
1495
                                                                !on_hold)) {
 
1496
                        error("Conflicting call status and on_hold property!");
 
1497
                        on_hold = call->status == CSD_CALL_STATUS_HOLD;
 
1498
                }
 
1499
 
 
1500
                call->originating = originating;
 
1501
                call->on_hold = on_hold;
 
1502
                call->conference = conf;
 
1503
                g_free(call->number);
 
1504
                call->number = g_strdup(number);
 
1505
 
 
1506
        } while (dbus_message_iter_next(iter));
 
1507
}
 
1508
 
 
1509
static void update_operator_name(const char *name)
 
1510
{
 
1511
        if (name == NULL)
 
1512
                return;
 
1513
 
 
1514
        g_free(net.operator_name);
 
1515
        net.operator_name = g_strndup(name, 16);
 
1516
        DBG("telephony-maemo6: operator name updated: %s", name);
 
1517
}
 
1518
 
 
1519
static void get_property_reply(DBusPendingCall *call, void *user_data)
 
1520
{
 
1521
        char *prop = user_data;
 
1522
        DBusError err;
 
1523
        DBusMessage *reply;
 
1524
        DBusMessageIter iter, sub;
 
1525
 
 
1526
        reply = dbus_pending_call_steal_reply(call);
 
1527
 
 
1528
        dbus_error_init(&err);
 
1529
        if (dbus_set_error_from_message(&err, reply)) {
 
1530
                error("csd replied with an error: %s, %s",
 
1531
                                err.name, err.message);
 
1532
                dbus_error_free(&err);
 
1533
                goto done;
 
1534
        }
 
1535
 
 
1536
        dbus_message_iter_init(reply, &iter);
 
1537
 
 
1538
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
 
1539
                error("Unexpected signature in Get return");
 
1540
                goto done;
 
1541
        }
 
1542
 
 
1543
        dbus_message_iter_recurse(&iter, &sub);
 
1544
 
 
1545
        if (g_strcmp0(prop, "RegistrationStatus") == 0) {
 
1546
                const char *status;
 
1547
 
 
1548
                dbus_message_iter_get_basic(&sub, &status);
 
1549
                update_registration_status(status);
 
1550
 
 
1551
                get_property(CSD_CSNET_OPERATOR, "OperatorName");
 
1552
                get_property(CSD_CSNET_SIGNAL, "SignalBars");
 
1553
        } else if (g_strcmp0(prop, "OperatorName") == 0) {
 
1554
                const char *name;
 
1555
 
 
1556
                dbus_message_iter_get_basic(&sub, &name);
 
1557
                update_operator_name(name);
 
1558
        } else if (g_strcmp0(prop, "SignalBars") == 0) {
 
1559
                int32_t signal_bars;
 
1560
 
 
1561
                dbus_message_iter_get_basic(&sub, &signal_bars);
 
1562
                update_signal_strength(signal_bars);
 
1563
        }
 
1564
 
 
1565
done:
 
1566
        g_free(prop);
 
1567
        dbus_message_unref(reply);
 
1568
        remove_pending(call);
 
1569
}
 
1570
 
 
1571
static int get_property(const char *iface, const char *prop)
 
1572
{
 
1573
        return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
 
1574
                                DBUS_INTERFACE_PROPERTIES, "Get",
 
1575
                                get_property_reply, g_strdup(prop),
 
1576
                                DBUS_TYPE_STRING, &iface,
 
1577
                                DBUS_TYPE_STRING, &prop,
 
1578
                                DBUS_TYPE_INVALID);
 
1579
}
 
1580
 
 
1581
static void handle_operator_name_changed(DBusMessage *msg)
 
1582
{
 
1583
        const char *name;
 
1584
 
 
1585
        if (!dbus_message_get_args(msg, NULL,
 
1586
                                        DBUS_TYPE_STRING, &name,
 
1587
                                        DBUS_TYPE_INVALID)) {
 
1588
                error("Unexpected parameters in OperatorNameChanged");
 
1589
                return;
 
1590
        }
 
1591
 
 
1592
        update_operator_name(name);
 
1593
}
 
1594
 
 
1595
static void call_info_reply(DBusPendingCall *call, void *user_data)
 
1596
{
 
1597
        DBusError err;
 
1598
        DBusMessage *reply;
 
1599
        DBusMessageIter iter, sub;;
 
1600
 
 
1601
        get_calls_active = FALSE;
 
1602
 
 
1603
        reply = dbus_pending_call_steal_reply(call);
 
1604
 
 
1605
        dbus_error_init(&err);
 
1606
        if (dbus_set_error_from_message(&err, reply)) {
 
1607
                error("csd replied with an error: %s, %s",
 
1608
                                err.name, err.message);
 
1609
                dbus_error_free(&err);
 
1610
                goto done;
 
1611
        }
 
1612
 
 
1613
        dbus_message_iter_init(reply, &iter);
 
1614
 
 
1615
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
1616
                error("Unexpected signature in GetCallInfoAll return");
 
1617
                goto done;
 
1618
        }
 
1619
 
 
1620
        dbus_message_iter_recurse(&iter, &sub);
 
1621
 
 
1622
        parse_call_list(&sub);
 
1623
 
 
1624
        get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
 
1625
 
 
1626
done:
 
1627
        dbus_message_unref(reply);
 
1628
        remove_pending(call);
 
1629
}
 
1630
 
 
1631
 
 
1632
static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
 
1633
{
 
1634
        DBusError derr;
 
1635
        DBusMessage *reply;
 
1636
        const char *name, *number, *secondname, *additionalnumber, *email;
 
1637
        int index;
 
1638
        char **number_type = user_data;
 
1639
 
 
1640
        reply = dbus_pending_call_steal_reply(call);
 
1641
 
 
1642
        dbus_error_init(&derr);
 
1643
        if (dbus_set_error_from_message(&derr, reply)) {
 
1644
                error("%s.ReadFirst replied with an error: %s, %s",
 
1645
                                CSD_SIMPB_INTERFACE, derr.name, derr.message);
 
1646
                dbus_error_free(&derr);
 
1647
                if (number_type == &vmbx)
 
1648
                        vmbx = g_strdup(getenv("VMBX_NUMBER"));
 
1649
                goto done;
 
1650
        }
 
1651
 
 
1652
        dbus_error_init(&derr);
 
1653
        if (dbus_message_get_args(reply, NULL,
 
1654
                                DBUS_TYPE_INT32, &index,
 
1655
                                DBUS_TYPE_STRING, &name,
 
1656
                                DBUS_TYPE_STRING, &number,
 
1657
                                DBUS_TYPE_STRING, &secondname,
 
1658
                                DBUS_TYPE_STRING, &additionalnumber,
 
1659
                                DBUS_TYPE_STRING, &email,
 
1660
                                DBUS_TYPE_INVALID) == FALSE) {
 
1661
                error("Unable to parse %s.ReadFirst arguments: %s, %s",
 
1662
                                CSD_SIMPB_INTERFACE, derr.name, derr.message);
 
1663
                dbus_error_free(&derr);
 
1664
                goto done;
 
1665
        }
 
1666
 
 
1667
        if (number_type == &msisdn) {
 
1668
                g_free(msisdn);
 
1669
                msisdn = g_strdup(number);
 
1670
                DBG("Got MSISDN %s (%s)", number, name);
 
1671
        } else {
 
1672
                g_free(vmbx);
 
1673
                vmbx = g_strdup(number);
 
1674
                DBG("Got voice mailbox number %s (%s)", number, name);
 
1675
        }
 
1676
 
 
1677
done:
 
1678
        dbus_message_unref(reply);
 
1679
        remove_pending(call);
 
1680
}
 
1681
 
 
1682
static void csd_init(void)
 
1683
{
 
1684
        const char *pb_type;
 
1685
        int ret;
 
1686
 
 
1687
        ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
 
1688
                                CSD_CALL_INTERFACE, "GetCallInfoAll",
 
1689
                                call_info_reply, NULL, DBUS_TYPE_INVALID);
 
1690
        if (ret < 0) {
 
1691
                error("Unable to sent GetCallInfoAll method call");
 
1692
                return;
 
1693
        }
 
1694
 
 
1695
        get_calls_active = TRUE;
 
1696
 
 
1697
        pb_type = CSD_SIMPB_TYPE_MSISDN;
 
1698
 
 
1699
        ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
 
1700
                                CSD_SIMPB_INTERFACE, "ReadFirst",
 
1701
                                phonebook_read_reply, &msisdn,
 
1702
                                DBUS_TYPE_STRING, &pb_type,
 
1703
                                DBUS_TYPE_INVALID);
 
1704
        if (ret < 0) {
 
1705
                error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
 
1706
                return;
 
1707
        }
 
1708
 
 
1709
        /* Voicemail should be in MBDN index 0 */
 
1710
        pb_type = CSD_SIMPB_TYPE_MBDN;
 
1711
 
 
1712
        ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
 
1713
                                CSD_SIMPB_INTERFACE, "ReadFirst",
 
1714
                                phonebook_read_reply, &vmbx,
 
1715
                                DBUS_TYPE_STRING, &pb_type,
 
1716
                                DBUS_TYPE_INVALID);
 
1717
        if (ret < 0) {
 
1718
                error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
 
1719
                return;
 
1720
        }
 
1721
}
 
1722
 
 
1723
static inline DBusMessage *invalid_args(DBusMessage *msg)
 
1724
{
 
1725
        return g_dbus_create_error(msg,"org.bluez.Error.InvalidArguments",
 
1726
                                        "Invalid arguments in method call");
 
1727
}
 
1728
 
 
1729
static uint32_t get_callflag(const char *callerid_setting)
 
1730
{
 
1731
        if (callerid_setting != NULL) {
 
1732
                if (g_str_equal(callerid_setting, "allowed"))
 
1733
                        return CALL_FLAG_PRESENTATION_ALLOWED;
 
1734
                else if (g_str_equal(callerid_setting, "restricted"))
 
1735
                        return CALL_FLAG_PRESENTATION_RESTRICTED;
 
1736
                else
 
1737
                        return CALL_FLAG_NONE;
 
1738
        } else
 
1739
                return CALL_FLAG_NONE;
 
1740
}
 
1741
 
 
1742
static void generate_flag_file(const char *filename)
 
1743
{
 
1744
        int fd;
 
1745
 
 
1746
        if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
 
1747
                        g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
 
1748
                        g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
 
1749
                return;
 
1750
 
 
1751
        fd = open(filename, O_WRONLY | O_CREAT, 0);
 
1752
        if (fd >= 0)
 
1753
                close(fd);
 
1754
}
 
1755
 
 
1756
static void save_callerid_to_file(const char *callerid_setting)
 
1757
{
 
1758
        char callerid_file[FILENAME_MAX];
 
1759
 
 
1760
        snprintf(callerid_file, sizeof(callerid_file), "%s%s",
 
1761
                                        CALLERID_BASE, callerid_setting);
 
1762
 
 
1763
        if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
 
1764
                rename(ALLOWED_FLAG_FILE, callerid_file);
 
1765
        else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
 
1766
                rename(RESTRICTED_FLAG_FILE, callerid_file);
 
1767
        else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
 
1768
                rename(NONE_FLAG_FILE, callerid_file);
 
1769
        else
 
1770
                generate_flag_file(callerid_file);
 
1771
}
 
1772
 
 
1773
static uint32_t callerid_from_file(void)
 
1774
{
 
1775
        if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
 
1776
                return CALL_FLAG_PRESENTATION_ALLOWED;
 
1777
        else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
 
1778
                return CALL_FLAG_PRESENTATION_RESTRICTED;
 
1779
        else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
 
1780
                return CALL_FLAG_NONE;
 
1781
        else
 
1782
                return CALL_FLAG_NONE;
 
1783
}
 
1784
 
 
1785
static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
 
1786
                                        void *data)
 
1787
{
 
1788
        const char *callerid_setting;
 
1789
 
 
1790
        if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING,
 
1791
                                                &callerid_setting,
 
1792
                                                DBUS_TYPE_INVALID) == FALSE)
 
1793
                return invalid_args(msg);
 
1794
 
 
1795
        if (g_str_equal(callerid_setting, "allowed") ||
 
1796
                        g_str_equal(callerid_setting, "restricted") ||
 
1797
                        g_str_equal(callerid_setting, "none")) {
 
1798
                save_callerid_to_file(callerid_setting);
 
1799
                callerid = get_callflag(callerid_setting);
 
1800
                DBG("telephony-maemo6 setting callerid flag: %s",
 
1801
                                                        callerid_setting);
 
1802
                return dbus_message_new_method_return(msg);
 
1803
        }
 
1804
 
 
1805
        error("telephony-maemo6: invalid argument %s for method call"
 
1806
                                        " SetCallerId", callerid_setting);
 
1807
                return invalid_args(msg);
 
1808
}
 
1809
 
 
1810
static DBusMessage *clear_lastnumber(DBusConnection *conn, DBusMessage *msg,
 
1811
                                        void *data)
 
1812
{
 
1813
        g_free(last_dialed_number);
 
1814
        last_dialed_number = NULL;
 
1815
 
 
1816
        return dbus_message_new_method_return(msg);
 
1817
}
 
1818
 
 
1819
static GDBusMethodTable telephony_maemo_methods[] = {
 
1820
        { "SetCallerId",        "s",    "",     set_callerid,
 
1821
                                                G_DBUS_METHOD_FLAG_ASYNC },
 
1822
        { "ClearLastNumber",    "",     "",     clear_lastnumber },
 
1823
        { }
 
1824
};
 
1825
 
 
1826
static void handle_modem_state(DBusMessage *msg)
 
1827
{
 
1828
        const char *state;
 
1829
 
 
1830
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
 
1831
                                                        DBUS_TYPE_INVALID)) {
 
1832
                error("Unexpected modem state parameters");
 
1833
                return;
 
1834
        }
 
1835
 
 
1836
        DBG("SSC modem state: %s", state);
 
1837
 
 
1838
        if (calls != NULL || get_calls_active)
 
1839
                return;
 
1840
 
 
1841
        if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
 
1842
                csd_init();
 
1843
}
 
1844
 
 
1845
static void modem_state_reply(DBusPendingCall *call, void *user_data)
 
1846
{
 
1847
        DBusMessage *reply = dbus_pending_call_steal_reply(call);
 
1848
        DBusError err;
 
1849
 
 
1850
        dbus_error_init(&err);
 
1851
        if (dbus_set_error_from_message(&err, reply)) {
 
1852
                error("get_modem_state: %s, %s", err.name, err.message);
 
1853
                dbus_error_free(&err);
 
1854
        } else
 
1855
                handle_modem_state(reply);
 
1856
 
 
1857
        dbus_message_unref(reply);
 
1858
        remove_pending(call);
 
1859
}
 
1860
 
 
1861
static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
 
1862
                                                                void *data)
 
1863
{
 
1864
        const char *path = dbus_message_get_path(msg);
 
1865
 
 
1866
        if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
 
1867
                handle_incoming_call(msg);
 
1868
        else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
 
1869
                handle_outgoing_call(msg);
 
1870
        else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
 
1871
                                                        "CreateRequested"))
 
1872
                handle_create_requested(msg);
 
1873
        else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
 
1874
                handle_call_status(msg, path);
 
1875
        else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
 
1876
                handle_conference(msg, TRUE);
 
1877
        else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
 
1878
                handle_conference(msg, FALSE);
 
1879
        else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION,
 
1880
                                "RegistrationChanged"))
 
1881
                handle_registration_changed(msg);
 
1882
        else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR,
 
1883
                                "OperatorNameChanged"))
 
1884
                handle_operator_name_changed(msg);
 
1885
        else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL,
 
1886
                                "SignalBarsChanged"))
 
1887
                handle_signal_bars_changed(msg);
 
1888
        else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
 
1889
                                        "PropertyModified"))
 
1890
                handle_hal_property_modified(msg);
 
1891
        else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
 
1892
                                                "modem_state_changed_ind"))
 
1893
                handle_modem_state(msg);
 
1894
 
 
1895
        return TRUE;
 
1896
}
 
1897
 
 
1898
static void add_watch(const char *sender, const char *path,
 
1899
                                const char *interface, const char *member)
 
1900
{
 
1901
        guint watch;
 
1902
 
 
1903
        watch = g_dbus_add_signal_watch(connection, sender, path, interface,
 
1904
                                        member, signal_filter, NULL, NULL);
 
1905
 
 
1906
        watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
 
1907
}
 
1908
 
 
1909
static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
 
1910
{
 
1911
        DBusError err;
 
1912
        DBusMessage *reply;
 
1913
        DBusMessageIter iter, sub;
 
1914
        const char *path;
 
1915
        int type;
 
1916
 
 
1917
        reply = dbus_pending_call_steal_reply(call);
 
1918
 
 
1919
        dbus_error_init(&err);
 
1920
        if (dbus_set_error_from_message(&err, reply)) {
 
1921
                error("hald replied with an error: %s, %s",
 
1922
                                err.name, err.message);
 
1923
                dbus_error_free(&err);
 
1924
                goto done;
 
1925
        }
 
1926
 
 
1927
        dbus_message_iter_init(reply, &iter);
 
1928
 
 
1929
        if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 
1930
                error("Unexpected signature in FindDeviceByCapability return");
 
1931
                goto done;
 
1932
        }
 
1933
 
 
1934
        dbus_message_iter_recurse(&iter, &sub);
 
1935
 
 
1936
        type = dbus_message_iter_get_arg_type(&sub);
 
1937
 
 
1938
        if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
 
1939
                error("No hal device with battery capability found");
 
1940
                goto done;
 
1941
        }
 
1942
 
 
1943
        dbus_message_iter_get_basic(&sub, &path);
 
1944
 
 
1945
        DBG("telephony-maemo6: found battery device at %s", path);
 
1946
 
 
1947
        add_watch(NULL, path, "org.freedesktop.Hal.Device",
 
1948
                                                        "PropertyModified");
 
1949
 
 
1950
        hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
 
1951
        hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
 
1952
        hal_get_integer(path, "battery.charge_level.design", &battchg_design);
 
1953
 
 
1954
done:
 
1955
        dbus_message_unref(reply);
 
1956
        remove_pending(call);
 
1957
}
 
1958
 
 
1959
int telephony_init(void)
 
1960
{
 
1961
        const char *battery_cap = "battery";
 
1962
        uint32_t features = AG_FEATURE_EC_ANDOR_NR |
 
1963
                                AG_FEATURE_INBAND_RINGTONE |
 
1964
                                AG_FEATURE_REJECT_A_CALL |
 
1965
                                AG_FEATURE_ENHANCED_CALL_STATUS |
 
1966
                                AG_FEATURE_ENHANCED_CALL_CONTROL |
 
1967
                                AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
 
1968
                                AG_FEATURE_THREE_WAY_CALLING;
 
1969
 
 
1970
        DBG("");
 
1971
 
 
1972
        connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
 
1973
 
 
1974
        add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL);
 
1975
        add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL);
 
1976
        add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL);
 
1977
        add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged");
 
1978
        add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged");
 
1979
        add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged");
 
1980
        add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind");
 
1981
 
 
1982
        if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
 
1983
                                        "get_modem_state", modem_state_reply,
 
1984
                                        NULL, DBUS_TYPE_INVALID) < 0)
 
1985
                error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
 
1986
 
 
1987
        generate_flag_file(NONE_FLAG_FILE);
 
1988
        callerid = callerid_from_file();
 
1989
 
 
1990
        if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
 
1991
                        TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
 
1992
                        NULL, NULL, NULL, NULL)) {
 
1993
                error("telephony-maemo6 interface %s init failed on path %s",
 
1994
                        TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
 
1995
        }
 
1996
 
 
1997
        DBG("telephony-maemo6 registering %s interface on path %s",
 
1998
                        TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
 
1999
 
 
2000
        telephony_ready_ind(features, maemo_indicators, response_and_hold,
 
2001
                                                                chld_str);
 
2002
        if (send_method_call("org.freedesktop.Hal",
 
2003
                                "/org/freedesktop/Hal/Manager",
 
2004
                                "org.freedesktop.Hal.Manager",
 
2005
                                "FindDeviceByCapability",
 
2006
                                hal_find_device_reply, NULL,
 
2007
                                DBUS_TYPE_STRING, &battery_cap,
 
2008
                                DBUS_TYPE_INVALID) < 0)
 
2009
                error("Unable to send HAL method call");
 
2010
 
 
2011
        return 0;
 
2012
}
 
2013
 
 
2014
static void remove_watch(gpointer data)
 
2015
{
 
2016
        g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
 
2017
}
 
2018
 
 
2019
void telephony_exit(void)
 
2020
{
 
2021
        DBG("");
 
2022
 
 
2023
        g_free(net.operator_name);
 
2024
        net.operator_name = NULL;
 
2025
 
 
2026
        g_free(last_dialed_number);
 
2027
        last_dialed_number = NULL;
 
2028
 
 
2029
        g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
 
2030
        g_slist_free(calls);
 
2031
        calls = NULL;
 
2032
 
 
2033
        g_slist_foreach(pending, (GFunc) dbus_pending_call_cancel, NULL);
 
2034
        g_slist_foreach(pending, (GFunc) dbus_pending_call_unref, NULL);
 
2035
        g_slist_free(pending);
 
2036
        pending = NULL;
 
2037
 
 
2038
        g_slist_foreach(watches, (GFunc) remove_watch, NULL);
 
2039
        g_slist_free(watches);
 
2040
        watches = NULL;
 
2041
 
 
2042
        g_dbus_unregister_interface(connection, TELEPHONY_MAEMO_PATH,
 
2043
                                                TELEPHONY_MAEMO_INTERFACE);
 
2044
 
 
2045
        dbus_connection_unref(connection);
 
2046
        connection = NULL;
 
2047
}