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 char *number; 52 guint watch; 53 }; 54 55 static DBusConnection *connection = NULL; 56 static char *modem_obj_path = NULL; 57 static char *last_dialed_number = NULL; 58 static GSList *calls = NULL; 59 60 #define OFONO_BUS_NAME "org.ofono" 61 #define OFONO_PATH "/" 62 #define OFONO_MANAGER_INTERFACE "org.ofono.Manager" 63 #define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration" 64 #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager" 65 #define OFONO_VC_INTERFACE "org.ofono.VoiceCall" 66 67 static guint registration_watch = 0; 68 static guint voice_watch = 0; 69 static guint device_watch = 0; 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 /* Response and hold state 92 * -1 = none 93 * 0 = incoming call is put on hold in the AG 94 * 1 = held incoming call is accepted in the AG 95 * 2 = held incoming call is rejected in the AG 96 */ 97 static int response_and_hold = -1; 98 99 static struct indicator ofono_indicators[] = 100 { 101 { "battchg", "0-5", 5, TRUE }, 102 { "signal", "0-5", 5, TRUE }, 103 { "service", "0,1", 1, TRUE }, 104 { "call", "0,1", 0, TRUE }, 105 { "callsetup", "0-3", 0, TRUE }, 106 { "callheld", "0-2", 0, FALSE }, 107 { "roam", "0,1", 0, TRUE }, 108 { NULL } 109 }; 110 111 static struct voice_call *find_vc(const char *path) 112 { 113 GSList *l; 114 115 for (l = calls; l != NULL; l = l->next) { 116 struct voice_call *vc = l->data; 117 118 if (g_str_equal(vc->obj_path, path)) 119 return vc; 120 } 121 122 return NULL; 123 } 124 125 static struct voice_call *find_vc_with_status(int status) 126 { 127 GSList *l; 128 129 for (l = calls; l != NULL; l = l->next) { 130 struct voice_call *vc = l->data; 131 132 if (vc->status == status) 133 return vc; 134 } 135 136 return NULL; 137 } 138 139 void telephony_device_connected(void *telephony_device) 140 { 141 DBG("telephony-ofono: device %p connected", telephony_device); 142 } 143 144 void telephony_device_disconnected(void *telephony_device) 145 { 146 DBG("telephony-ofono: device %p disconnected", telephony_device); 147 events_enabled = FALSE; 148 } 149 150 void telephony_event_reporting_req(void *telephony_device, int ind) 151 { 152 events_enabled = ind == 1 ? TRUE : FALSE; 153 154 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE); 155 } 156 157 void telephony_response_and_hold_req(void *telephony_device, int rh) 158 { 159 response_and_hold = rh; 160 161 telephony_response_and_hold_ind(response_and_hold); 162 163 telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NONE); 164 } 165 166 void telephony_last_dialed_number_req(void *telephony_device) 167 { 168 DBG("telephony-ofono: last dialed number request"); 169 170 if (last_dialed_number) 171 telephony_dial_number_req(telephony_device, last_dialed_number); 172 else 173 telephony_last_dialed_number_rsp(telephony_device, 174 CME_ERROR_NOT_ALLOWED); 175 } 176 177 static int send_method_call(const char *dest, const char *path, 178 const char *interface, const char *method, 179 DBusPendingCallNotifyFunction cb, 180 void *user_data, int type, ...) 181 { 182 DBusMessage *msg; 183 DBusPendingCall *call; 184 va_list args; 185 186 msg = dbus_message_new_method_call(dest, path, interface, method); 187 if (!msg) { 188 error("Unable to allocate new D-Bus %s message", method); 189 return -ENOMEM; 190 } 191 192 va_start(args, type); 193 194 if (!dbus_message_append_args_valist(msg, type, args)) { 195 dbus_message_unref(msg); 196 va_end(args); 197 return -EIO; 198 } 199 200 va_end(args); 201 202 if (!cb) { 203 g_dbus_send_message(connection, msg); 204 return 0; 205 } 206 207 if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) { 208 error("Sending %s failed", method); 209 dbus_message_unref(msg); 210 return -EIO; 211 } 212 213 dbus_pending_call_set_notify(call, cb, user_data, NULL); 214 dbus_pending_call_unref(call); 215 dbus_message_unref(msg); 216 217 return 0; 218 } 219 220 void telephony_terminate_call_req(void *telephony_device) 221 { 222 struct voice_call *vc; 223 int ret; 224 225 if ((vc = find_vc_with_status(CALL_STATUS_ACTIVE))) { 226 } else if ((vc = find_vc_with_status(CALL_STATUS_DIALING))) { 227 } else if ((vc = find_vc_with_status(CALL_STATUS_ALERTING))) { 228 } else if ((vc = find_vc_with_status(CALL_STATUS_INCOMING))) { 229 } 230 231 if (!vc) { 232 error("in telephony_terminate_call_req, no active call"); 233 telephony_terminate_call_rsp(telephony_device, 234 CME_ERROR_NOT_ALLOWED); 235 return; 236 } 237 238 ret = send_method_call(OFONO_BUS_NAME, vc->obj_path, 239 OFONO_VC_INTERFACE, 240 "Hangup", NULL, 241 NULL, DBUS_TYPE_INVALID); 242 243 if (ret < 0) { 244 telephony_answer_call_rsp(telephony_device, 245 CME_ERROR_AG_FAILURE); 246 return; 247 } 248 249 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE); 250 } 251 252 void telephony_answer_call_req(void *telephony_device) 253 { 254 struct voice_call *vc = find_vc_with_status(CALL_STATUS_INCOMING); 255 int ret; 256 257 if (!vc) { 258 telephony_answer_call_rsp(telephony_device, 259 CME_ERROR_NOT_ALLOWED); 260 return; 261 } 262 263 ret = send_method_call(OFONO_BUS_NAME, vc->obj_path, 264 OFONO_VC_INTERFACE, 265 "Answer", NULL, 266 NULL, DBUS_TYPE_INVALID); 267 268 if (ret < 0) { 269 telephony_answer_call_rsp(telephony_device, 270 CME_ERROR_AG_FAILURE); 271 return; 272 } 273 274 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE); 275 } 276 277 void telephony_dial_number_req(void *telephony_device, const char *number) 278 { 279 const char *clir; 280 int ret; 281 282 DBG("telephony-ofono: dial request to %s", number); 283 284 if (!modem_obj_path) { 285 telephony_dial_number_rsp(telephony_device, 286 CME_ERROR_AG_FAILURE); 287 return; 288 } 289 290 if (!strncmp(number, "*31#", 4)) { 291 number += 4; 292 clir = "enabled"; 293 } else if (!strncmp(number, "#31#", 4)) { 294 number += 4; 295 clir = "disabled"; 296 } else 297 clir = "default"; 298 299 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path, 300 OFONO_VCMANAGER_INTERFACE, 301 "Dial", NULL, NULL, 302 DBUS_TYPE_STRING, &number, 303 DBUS_TYPE_STRING, &clir, 304 DBUS_TYPE_INVALID); 305 306 if (ret < 0) 307 telephony_dial_number_rsp(telephony_device, 308 CME_ERROR_AG_FAILURE); 309 else 310 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE); 311 } 312 313 void telephony_transmit_dtmf_req(void *telephony_device, char tone) 314 { 315 char *tone_string; 316 int ret; 317 318 DBG("telephony-ofono: transmit dtmf: %c", tone); 319 320 if (!modem_obj_path) { 321 telephony_transmit_dtmf_rsp(telephony_device, 322 CME_ERROR_AG_FAILURE); 323 return; 324 } 325 326 tone_string = g_strdup_printf("%c", tone); 327 ret = send_method_call(OFONO_BUS_NAME, modem_obj_path, 328 OFONO_VCMANAGER_INTERFACE, 329 "SendTones", NULL, NULL, 330 DBUS_TYPE_STRING, &tone_string, 331 DBUS_TYPE_INVALID); 332 g_free(tone_string); 333 334 if (ret < 0) 335 telephony_transmit_dtmf_rsp(telephony_device, 336 CME_ERROR_AG_FAILURE); 337 else 338 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE); 339 } 340 341 void telephony_subscriber_number_req(void *telephony_device) 342 { 343 DBG("telephony-ofono: subscriber number request"); 344 345 if (subscriber_number) 346 telephony_subscriber_number_ind(subscriber_number, 347 NUMBER_TYPE_TELEPHONY, 348 SUBSCRIBER_SERVICE_VOICE); 349 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE); 350 } 351 352 void telephony_list_current_calls_req(void *telephony_device) 353 { 354 GSList *l; 355 int i; 356 357 DBG("telephony-ofono: list current calls request"); 358 359 for (l = calls, i = 1; l != NULL; l = l->next, i++) { 360 struct voice_call *vc = l->data; 361 int direction; 362 363 direction = vc->originating ? 364 CALL_DIR_OUTGOING : CALL_DIR_INCOMING; 365 366 telephony_list_current_call_ind(i, direction, vc->status, 367 CALL_MODE_VOICE, CALL_MULTIPARTY_NO, 368 vc->number, NUMBER_TYPE_TELEPHONY); 369 } 370 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE); 371 } 372 373 void telephony_operator_selection_req(void *telephony_device) 374 { 375 DBG("telephony-ofono: operator selection request"); 376 377 telephony_operator_selection_ind(OPERATOR_MODE_AUTO, 378 net.operator_name ? net.operator_name : ""); 379 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE); 380 } 381 382 void telephony_call_hold_req(void *telephony_device, const char *cmd) 383 { 384 DBG("telephony-ofono: got call hold request %s", cmd); 385 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE); 386 } 387 388 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable) 389 { 390 DBG("telephony-ofono: got %s NR and EC request", 391 enable ? "enable" : "disable"); 392 393 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE); 394 } 395 396 void telephony_key_press_req(void *telephony_device, const char *keys) 397 { 398 DBG("telephony-ofono: got key press request for %s", keys); 399 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE); 400 } 401 402 void telephony_voice_dial_req(void *telephony_device, gboolean enable) 403 { 404 DBG("telephony-ofono: got %s voice dial request", 405 enable ? "enable" : "disable"); 406 407 telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); 408 } 409 410 static gboolean iter_get_basic_args(DBusMessageIter *iter, 411 int first_arg_type, ...) 412 { 413 int type; 414 va_list ap; 415 416 va_start(ap, first_arg_type); 417 418 for (type = first_arg_type; type != DBUS_TYPE_INVALID; 419 type = va_arg(ap, int)) { 420 void *value = va_arg(ap, void *); 421 int real_type = dbus_message_iter_get_arg_type(iter); 422 423 if (real_type != type) { 424 error("iter_get_basic_args: expected %c but got %c", 425 (char) type, (char) real_type); 426 break; 427 } 428 429 dbus_message_iter_get_basic(iter, value); 430 dbus_message_iter_next(iter); 431 } 432 433 va_end(ap); 434 435 return type == DBUS_TYPE_INVALID ? TRUE : FALSE; 436 } 437 438 static void handle_registration_property(const char *property, DBusMessageIter sub) 439 { 440 const char *status, *operator; 441 unsigned int signals_bar; 442 443 if (g_str_equal(property, "Status")) { 444 dbus_message_iter_get_basic(&sub, &status); 445 DBG("Status is %s", status); 446 if (g_str_equal(status, "registered")) { 447 net.status = NETWORK_REG_STATUS_HOME; 448 telephony_update_indicator(ofono_indicators, 449 "roam", EV_ROAM_INACTIVE); 450 telephony_update_indicator(ofono_indicators, 451 "service", EV_SERVICE_PRESENT); 452 } else if (g_str_equal(status, "roaming")) { 453 net.status = NETWORK_REG_STATUS_ROAM; 454 telephony_update_indicator(ofono_indicators, 455 "roam", EV_ROAM_ACTIVE); 456 telephony_update_indicator(ofono_indicators, 457 "service", EV_SERVICE_PRESENT); 458 } else { 459 net.status = NETWORK_REG_STATUS_NOSERV; 460 telephony_update_indicator(ofono_indicators, 461 "roam", EV_ROAM_INACTIVE); 462 telephony_update_indicator(ofono_indicators, 463 "service", EV_SERVICE_NONE); 464 } 465 } else if (g_str_equal(property, "Operator")) { 466 dbus_message_iter_get_basic(&sub, &operator); 467 DBG("Operator is %s", operator); 468 g_free(net.operator_name); 469 net.operator_name = g_strdup(operator); 470 } else if (g_str_equal(property, "SignalStrength")) { 471 dbus_message_iter_get_basic(&sub, &signals_bar); 472 DBG("SignalStrength is %d", signals_bar); 473 net.signals_bar = signals_bar; 474 telephony_update_indicator(ofono_indicators, "signal", 475 (signals_bar + 20) / 21); 476 } 477 } 478 479 static void get_registration_reply(DBusPendingCall *call, void *user_data) 480 { 481 DBusError err; 482 DBusMessage *reply; 483 DBusMessageIter iter, iter_entry; 484 uint32_t features = AG_FEATURE_EC_ANDOR_NR | 485 AG_FEATURE_REJECT_A_CALL | 486 AG_FEATURE_ENHANCED_CALL_STATUS | 487 AG_FEATURE_EXTENDED_ERROR_RESULT_CODES; 488 489 reply = dbus_pending_call_steal_reply(call); 490 491 dbus_error_init(&err); 492 if (dbus_set_error_from_message(&err, reply)) { 493 error("ofono replied with an error: %s, %s", 494 err.name, err.message); 495 dbus_error_free(&err); 496 goto done; 497 } 498 499 dbus_message_iter_init(reply, &iter); 500 501 /* ARRAY -> ENTRY -> VARIANT */ 502 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { 503 error("Unexpected signature in GetProperties return"); 504 goto done; 505 } 506 507 dbus_message_iter_recurse(&iter, &iter_entry); 508 509 if (dbus_message_iter_get_arg_type(&iter_entry) 510 != DBUS_TYPE_DICT_ENTRY) { 511 error("Unexpected signature in GetProperties return"); 512 goto done; 513 } 514 515 while (dbus_message_iter_get_arg_type(&iter_entry) 516 != DBUS_TYPE_INVALID) { 517 DBusMessageIter iter_property, sub; 518 char *property; 519 520 dbus_message_iter_recurse(&iter_entry, &iter_property); 521 if (dbus_message_iter_get_arg_type(&iter_property) 522 != DBUS_TYPE_STRING) { 523 error("Unexpected signature in GetProperties return"); 524 goto done; 525 } 526 527 dbus_message_iter_get_basic(&iter_property, &property); 528 529 dbus_message_iter_next(&iter_property); 530 dbus_message_iter_recurse(&iter_property, &sub); 531 532 handle_registration_property(property, sub); 533 534 dbus_message_iter_next(&iter_entry); 535 } 536 537 telephony_ready_ind(features, ofono_indicators, 538 response_and_hold, chld_str); 539 540 done: 541 dbus_message_unref(reply); 542 } 543 544 static int get_registration_and_signal_status() 545 { 546 if (!modem_obj_path) 547 return -ENOENT; 548 549 return send_method_call(OFONO_BUS_NAME, modem_obj_path, 550 OFONO_NETWORKREG_INTERFACE, 551 "GetProperties", get_registration_reply, 552 NULL, DBUS_TYPE_INVALID); 553 } 554 555 static void list_modem_reply(DBusPendingCall *call, void *user_data) 556 { 557 DBusError err; 558 DBusMessage *reply; 559 DBusMessageIter iter, iter_entry, iter_property, iter_arrary, sub; 560 char *property, *modem_obj_path_local; 561 int ret; 562 563 DBG("list_modem_reply is called\n"); 564 reply = dbus_pending_call_steal_reply(call); 565 566 dbus_error_init(&err); 567 if (dbus_set_error_from_message(&err, reply)) { 568 error("ofono replied with an error: %s, %s", 569 err.name, err.message); 570 dbus_error_free(&err); 571 goto done; 572 } 573 574 dbus_message_iter_init(reply, &iter); 575 576 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { 577 error("Unexpected signature in ListModems return"); 578 goto done; 579 } 580 581 dbus_message_iter_recurse(&iter, &iter_entry); 582 583 if (dbus_message_iter_get_arg_type(&iter_entry) 584 != DBUS_TYPE_DICT_ENTRY) { 585 error("Unexpected signature in ListModems return 2, %c", 586 dbus_message_iter_get_arg_type(&iter_entry)); 587 goto done; 588 } 589 590 dbus_message_iter_recurse(&iter_entry, &iter_property); 591 592 dbus_message_iter_get_basic(&iter_property, &property); 593 594 dbus_message_iter_next(&iter_property); 595 dbus_message_iter_recurse(&iter_property, &iter_arrary); 596 dbus_message_iter_recurse(&iter_arrary, &sub); 597 while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) { 598 599 dbus_message_iter_get_basic(&sub, &modem_obj_path_local); 600 modem_obj_path = g_strdup(modem_obj_path_local); 601 if (modem_obj_path != NULL) { 602 DBG("modem_obj_path is %p, %s\n", modem_obj_path, 603 modem_obj_path); 604 break; 605 } 606 dbus_message_iter_next(&sub); 607 } 608 609 ret = get_registration_and_signal_status(); 610 if (ret < 0) 611 error("get_registration_and_signal_status() failed(%d)", ret); 612 done: 613 dbus_message_unref(reply); 614 } 615 616 static gboolean handle_registration_property_changed(DBusConnection *conn, 617 DBusMessage *msg, void *data) 618 { 619 DBusMessageIter iter, sub; 620 const char *property; 621 622 dbus_message_iter_init(msg, &iter); 623 624 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { 625 error("Unexpected signature in networkregistration" 626 " PropertyChanged signal"); 627 return TRUE; 628 } 629 dbus_message_iter_get_basic(&iter, &property); 630 DBG("in handle_registration_property_changed()," 631 " the property is %s", property); 632 633 dbus_message_iter_next(&iter); 634 dbus_message_iter_recurse(&iter, &sub); 635 636 handle_registration_property(property, sub); 637 638 return TRUE; 639 } 640 641 static void vc_getproperties_reply(DBusPendingCall *call, void *user_data) 642 { 643 DBusMessage *reply; 644 DBusError err; 645 DBusMessageIter iter, iter_entry; 646 const char *path = user_data; 647 struct voice_call *vc; 648 649 DBG("in vc_getproperties_reply"); 650 651 reply = dbus_pending_call_steal_reply(call); 652 dbus_error_init(&err); 653 if (dbus_set_error_from_message(&err, reply)) { 654 error("ofono replied with an error: %s, %s", 655 err.name, err.message); 656 dbus_error_free(&err); 657 goto done; 658 } 659 660 vc = find_vc(path); 661 if (!vc) { 662 error("in vc_getproperties_reply, vc is NULL"); 663 goto done; 664 } 665 666 dbus_message_iter_init(reply, &iter); 667 668 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { 669 error("Unexpected signature in vc_getproperties_reply()"); 670 goto done; 671 } 672 673 dbus_message_iter_recurse(&iter, &iter_entry); 674 675 if (dbus_message_iter_get_arg_type(&iter_entry) 676 != DBUS_TYPE_DICT_ENTRY) { 677 error("Unexpected signature in vc_getproperties_reply()"); 678 goto done; 679 } 680 681 while (dbus_message_iter_get_arg_type(&iter_entry) 682 != DBUS_TYPE_INVALID) { 683 DBusMessageIter iter_property, sub; 684 char *property, *cli, *state; 685 686 dbus_message_iter_recurse(&iter_entry, &iter_property); 687 if (dbus_message_iter_get_arg_type(&iter_property) 688 != DBUS_TYPE_STRING) { 689 error("Unexpected signature in" 690 " vc_getproperties_reply()"); 691 goto done; 692 } 693 694 dbus_message_iter_get_basic(&iter_property, &property); 695 696 dbus_message_iter_next(&iter_property); 697 dbus_message_iter_recurse(&iter_property, &sub); 698 if (g_str_equal(property, "LineIdentification")) { 699 dbus_message_iter_get_basic(&sub, &cli); 700 DBG("in vc_getproperties_reply(), cli is %s", cli); 701 vc->number = g_strdup(cli); 702 } else if (g_str_equal(property, "State")) { 703 dbus_message_iter_get_basic(&sub, &state); 704 DBG("in vc_getproperties_reply()," 705 " state is %s", state); 706 if (g_str_equal(state, "incoming")) 707 vc->status = CALL_STATUS_INCOMING; 708 else if (g_str_equal(state, "dialing")) 709 vc->status = CALL_STATUS_DIALING; 710 else if (g_str_equal(state, "alerting")) 711 vc->status = CALL_STATUS_ALERTING; 712 else if (g_str_equal(state, "waiting")) 713 vc->status = CALL_STATUS_WAITING; 714 } 715 716 dbus_message_iter_next(&iter_entry); 717 } 718 719 switch (vc->status) { 720 case CALL_STATUS_INCOMING: 721 printf("in CALL_STATUS_INCOMING: case\n"); 722 vc->originating = FALSE; 723 telephony_update_indicator(ofono_indicators, "callsetup", 724 EV_CALLSETUP_INCOMING); 725 telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY); 726 break; 727 case CALL_STATUS_DIALING: 728 printf("in CALL_STATUS_DIALING: case\n"); 729 vc->originating = TRUE; 730 g_free(last_dialed_number); 731 last_dialed_number = g_strdup(vc->number); 732 telephony_update_indicator(ofono_indicators, "callsetup", 733 EV_CALLSETUP_OUTGOING); 734 break; 735 case CALL_STATUS_ALERTING: 736 printf("in CALL_STATUS_ALERTING: case\n"); 737 vc->originating = TRUE; 738 g_free(last_dialed_number); 739 last_dialed_number = g_strdup(vc->number); 740 telephony_update_indicator(ofono_indicators, "callsetup", 741 EV_CALLSETUP_ALERTING); 742 break; 743 case CALL_STATUS_WAITING: 744 DBG("in CALL_STATUS_WAITING: case"); 745 vc->originating = FALSE; 746 telephony_update_indicator(ofono_indicators, "callsetup", 747 EV_CALLSETUP_INCOMING); 748 telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY); 749 break; 750 } 751 done: 752 dbus_message_unref(reply); 753 } 754 755 static void vc_free(struct voice_call *vc) 756 { 757 if (!vc) 758 return; 759 760 g_dbus_remove_watch(connection, vc->watch); 761 g_free(vc->obj_path); 762 g_free(vc->number); 763 g_free(vc); 764 } 765 766 static gboolean handle_vc_property_changed(DBusConnection *conn, 767 DBusMessage *msg, void *data) 768 { 769 struct voice_call *vc = data; 770 const char *obj_path = dbus_message_get_path(msg); 771 DBusMessageIter iter, sub; 772 const char *property, *state; 773 774 DBG("in handle_vc_property_changed, obj_path is %s", obj_path); 775 776 dbus_message_iter_init(msg, &iter); 777 778 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { 779 error("Unexpected signature in vc PropertyChanged signal"); 780 return TRUE; 781 } 782 783 dbus_message_iter_get_basic(&iter, &property); 784 DBG("in handle_vc_property_changed(), the property is %s", property); 785 786 dbus_message_iter_next(&iter); 787 dbus_message_iter_recurse(&iter, &sub); 788 if (g_str_equal(property, "State")) { 789 dbus_message_iter_get_basic(&sub, &state); 790 DBG("in handle_vc_property_changed(), State is %s", state); 791 if (g_str_equal(state, "disconnected")) { 792 printf("in disconnected case\n"); 793 if (vc->status == CALL_STATUS_ACTIVE) 794 telephony_update_indicator(ofono_indicators, 795 "call", EV_CALL_INACTIVE); 796 else 797 telephony_update_indicator(ofono_indicators, 798 "callsetup", EV_CALLSETUP_INACTIVE); 799 if (vc->status == CALL_STATUS_INCOMING) 800 telephony_calling_stopped_ind(); 801 calls = g_slist_remove(calls, vc); 802 vc_free(vc); 803 } else if (g_str_equal(state, "active")) { 804 telephony_update_indicator(ofono_indicators, 805 "call", EV_CALL_ACTIVE); 806 telephony_update_indicator(ofono_indicators, 807 "callsetup", 808 EV_CALLSETUP_INACTIVE); 809 if (vc->status == CALL_STATUS_INCOMING) 810 telephony_calling_stopped_ind(); 811 vc->status = CALL_STATUS_ACTIVE; 812 DBG("vc status is CALL_STATUS_ACTIVE"); 813 } else if (g_str_equal(state, "alerting")) { 814 telephony_update_indicator(ofono_indicators, 815 "callsetup", EV_CALLSETUP_ALERTING); 816 vc->status = CALL_STATUS_ALERTING; 817 DBG("vc status is CALL_STATUS_ALERTING"); 818 } else if (g_str_equal(state, "incoming")) { 819 /* state change from waiting to incoming */ 820 telephony_update_indicator(ofono_indicators, 821 "callsetup", EV_CALLSETUP_INCOMING); 822 telephony_incoming_call_ind(vc->number, 823 NUMBER_TYPE_TELEPHONY); 824 vc->status = CALL_STATUS_INCOMING; 825 DBG("vc status is CALL_STATUS_INCOMING"); 826 } 827 } 828 829 return TRUE; 830 } 831 832 static gboolean handle_vcmanager_property_changed(DBusConnection *conn, 833 DBusMessage *msg, void *data) 834 { 835 DBusMessageIter iter, sub, array; 836 const char *property, *vc_obj_path = NULL; 837 struct voice_call *vc, *vc_new = NULL; 838 839 DBG("in handle_vcmanager_property_changed"); 840 841 dbus_message_iter_init(msg, &iter); 842 843 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { 844 error("Unexpected signature in vcmanager" 845 " PropertyChanged signal"); 846 return TRUE; 847 } 848 849 dbus_message_iter_get_basic(&iter, &property); 850 DBG("in handle_vcmanager_property_changed()," 851 " the property is %s", property); 852 853 dbus_message_iter_next(&iter); 854 dbus_message_iter_recurse(&iter, &sub); 855 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_ARRAY) { 856 error("Unexpected signature in vcmanager" 857 " PropertyChanged signal"); 858 return TRUE; 859 } 860 dbus_message_iter_recurse(&sub, &array); 861 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { 862 dbus_message_iter_get_basic(&array, &vc_obj_path); 863 vc = find_vc(vc_obj_path); 864 if (vc) { 865 DBG("in handle_vcmanager_property_changed," 866 " found an existing vc"); 867 } else { 868 vc_new = g_new0(struct voice_call, 1); 869 vc_new->obj_path = g_strdup(vc_obj_path); 870 calls = g_slist_append(calls, vc_new); 871 vc_new->watch = g_dbus_add_signal_watch(connection, 872 NULL, vc_obj_path, 873 OFONO_VC_INTERFACE, 874 "PropertyChanged", 875 handle_vc_property_changed, 876 vc_new, NULL); 877 } 878 dbus_message_iter_next(&array); 879 } 880 881 if (!vc_new) 882 return TRUE; 883 884 send_method_call(OFONO_BUS_NAME, vc_new->obj_path, 885 OFONO_VC_INTERFACE, 886 "GetProperties", vc_getproperties_reply, 887 vc_new->obj_path, DBUS_TYPE_INVALID); 888 889 return TRUE; 890 } 891 892 static void hal_battery_level_reply(DBusPendingCall *call, void *user_data) 893 { 894 DBusMessage *reply; 895 DBusError err; 896 dbus_int32_t level; 897 int *value = user_data; 898 899 reply = dbus_pending_call_steal_reply(call); 900 901 dbus_error_init(&err); 902 if (dbus_set_error_from_message(&err, reply)) { 903 error("hald replied with an error: %s, %s", 904 err.name, err.message); 905 dbus_error_free(&err); 906 goto done; 907 } 908 909 dbus_error_init(&err); 910 if (dbus_message_get_args(reply, &err, 911 DBUS_TYPE_INT32, &level, 912 DBUS_TYPE_INVALID) == FALSE) { 913 error("Unable to parse GetPropertyInteger reply: %s, %s", 914 err.name, err.message); 915 dbus_error_free(&err); 916 goto done; 917 } 918 919 *value = (int) level; 920 921 if (value == &battchg_last) 922 DBG("telephony-ofono: battery.charge_level.last_full" 923 " is %d", *value); 924 else if (value == &battchg_design) 925 DBG("telephony-ofono: battery.charge_level.design" 926 " is %d", *value); 927 else 928 DBG("telephony-ofono: battery.charge_level.current" 929 " is %d", *value); 930 931 if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) { 932 int new, max; 933 934 if (battchg_last > 0) 935 max = battchg_last; 936 else 937 max = battchg_design; 938 939 new = battchg_cur * 5 / max; 940 941 telephony_update_indicator(ofono_indicators, "battchg", new); 942 } 943 done: 944 dbus_message_unref(reply); 945 } 946 947 static void hal_get_integer(const char *path, const char *key, void *user_data) 948 { 949 send_method_call("org.freedesktop.Hal", path, 950 "org.freedesktop.Hal.Device", 951 "GetPropertyInteger", 952 hal_battery_level_reply, user_data, 953 DBUS_TYPE_STRING, &key, 954 DBUS_TYPE_INVALID); 955 } 956 957 static gboolean handle_hal_property_modified(DBusConnection *conn, 958 DBusMessage *msg, void *data) 959 { 960 const char *path; 961 DBusMessageIter iter, array; 962 dbus_int32_t num_changes; 963 964 path = dbus_message_get_path(msg); 965 966 dbus_message_iter_init(msg, &iter); 967 968 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) { 969 error("Unexpected signature in hal PropertyModified signal"); 970 return TRUE; 971 } 972 973 dbus_message_iter_get_basic(&iter, &num_changes); 974 dbus_message_iter_next(&iter); 975 976 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { 977 error("Unexpected signature in hal PropertyModified signal"); 978 return TRUE; 979 } 980 981 dbus_message_iter_recurse(&iter, &array); 982 983 while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { 984 DBusMessageIter prop; 985 const char *name; 986 dbus_bool_t added, removed; 987 988 dbus_message_iter_recurse(&array, &prop); 989 990 if (!iter_get_basic_args(&prop, 991 DBUS_TYPE_STRING, &name, 992 DBUS_TYPE_BOOLEAN, &added, 993 DBUS_TYPE_BOOLEAN, &removed, 994 DBUS_TYPE_INVALID)) { 995 error("Invalid hal PropertyModified parameters"); 996 break; 997 } 998 999 if (g_str_equal(name, "battery.charge_level.last_full")) 1000 hal_get_integer(path, name, &battchg_last); 1001 else if (g_str_equal(name, "battery.charge_level.current")) 1002 hal_get_integer(path, name, &battchg_cur); 1003 else if (g_str_equal(name, "battery.charge_level.design")) 1004 hal_get_integer(path, name, &battchg_design); 1005 1006 dbus_message_iter_next(&array); 1007 } 1008 1009 return TRUE; 1010 } 1011 1012 static void hal_find_device_reply(DBusPendingCall *call, void *user_data) 1013 { 1014 DBusMessage *reply; 1015 DBusError err; 1016 DBusMessageIter iter, sub; 1017 int type; 1018 const char *path; 1019 1020 DBG("begin of hal_find_device_reply()"); 1021 reply = dbus_pending_call_steal_reply(call); 1022 1023 dbus_error_init(&err); 1024 1025 if (dbus_set_error_from_message(&err, reply)) { 1026 error("hald replied with an error: %s, %s", 1027 err.name, err.message); 1028 dbus_error_free(&err); 1029 goto done; 1030 } 1031 1032 dbus_message_iter_init(reply, &iter); 1033 1034 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { 1035 error("Unexpected signature in hal_find_device_reply()"); 1036 goto done; 1037 } 1038 1039 dbus_message_iter_recurse(&iter, &sub); 1040 1041 type = dbus_message_iter_get_arg_type(&sub); 1042 1043 if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) { 1044 error("No hal device with battery capability found"); 1045 goto done; 1046 } 1047 1048 dbus_message_iter_get_basic(&sub, &path); 1049 1050 DBG("telephony-ofono: found battery device at %s", path); 1051 1052 device_watch = g_dbus_add_signal_watch(connection, NULL, path, 1053 "org.freedesktop.Hal.Device", 1054 "PropertyModified", 1055 handle_hal_property_modified, 1056 NULL, NULL); 1057 1058 hal_get_integer(path, "battery.charge_level.last_full", &battchg_last); 1059 hal_get_integer(path, "battery.charge_level.current", &battchg_cur); 1060 hal_get_integer(path, "battery.charge_level.design", &battchg_design); 1061 done: 1062 dbus_message_unref(reply); 1063 } 1064 1065 int telephony_init(void) 1066 { 1067 const char *battery_cap = "battery"; 1068 int ret; 1069 1070 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); 1071 1072 registration_watch = g_dbus_add_signal_watch(connection, NULL, NULL, 1073 OFONO_NETWORKREG_INTERFACE, 1074 "PropertyChanged", 1075 handle_registration_property_changed, 1076 NULL, NULL); 1077 1078 voice_watch = g_dbus_add_signal_watch(connection, NULL, NULL, 1079 OFONO_VCMANAGER_INTERFACE, 1080 "PropertyChanged", 1081 handle_vcmanager_property_changed, 1082 NULL, NULL); 1083 1084 ret = send_method_call(OFONO_BUS_NAME, OFONO_PATH, 1085 OFONO_MANAGER_INTERFACE, "GetProperties", 1086 list_modem_reply, NULL, DBUS_TYPE_INVALID); 1087 if (ret < 0) 1088 return ret; 1089 1090 ret = send_method_call("org.freedesktop.Hal", 1091 "/org/freedesktop/Hal/Manager", 1092 "org.freedesktop.Hal.Manager", 1093 "FindDeviceByCapability", 1094 hal_find_device_reply, NULL, 1095 DBUS_TYPE_STRING, &battery_cap, 1096 DBUS_TYPE_INVALID); 1097 if (ret < 0) 1098 return ret; 1099 1100 DBG("telephony_init() successfully"); 1101 1102 return ret; 1103 } 1104 1105 void telephony_exit(void) 1106 { 1107 g_free(net.operator_name); 1108 1109 g_free(modem_obj_path); 1110 g_free(last_dialed_number); 1111 1112 g_slist_foreach(calls, (GFunc) vc_free, NULL); 1113 g_slist_free(calls); 1114 calls = NULL; 1115 1116 g_dbus_remove_watch(connection, registration_watch); 1117 g_dbus_remove_watch(connection, voice_watch); 1118 g_dbus_remove_watch(connection, device_watch); 1119 1120 dbus_connection_unref(connection); 1121 connection = NULL; 1122 } 1123