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