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