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