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