OSDN Git Service

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