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