1 /* 2 * 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2006-2007 Nokia Corporation 6 * Copyright (C) 2004-2009 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 <stdint.h> 32 #include <glib.h> 33 #include <dbus/dbus.h> 34 #include <gdbus.h> 35 36 #include "logging.h" 37 #include "telephony.h" 38 39 static const char *chld_str = "0,1,1x,2,2x,3,4"; 40 static char *subscriber_number = NULL; 41 static char *active_call_number = NULL; 42 static int active_call_status = 0; 43 static int active_call_dir = 0; 44 45 static gboolean events_enabled = FALSE; 46 47 /* Response and hold state 48 * -1 = none 49 * 0 = incoming call is put on hold in the AG 50 * 1 = held incoming call is accepted in the AG 51 * 2 = held incoming call is rejected in the AG 52 */ 53 static int response_and_hold = -1; 54 55 static struct indicator dummy_indicators[] = 56 { 57 { "battchg", "0-5", 5, TRUE }, 58 { "signal", "0-5", 5, TRUE }, 59 { "service", "0,1", 1, TRUE }, 60 { "call", "0,1", 0, TRUE }, 61 { "callsetup", "0-3", 0, TRUE }, 62 { "callheld", "0-2", 0, FALSE }, 63 { "roam", "0,1", 0, TRUE }, 64 { NULL } 65 }; 66 67 static inline DBusMessage *invalid_args(DBusMessage *msg) 68 { 69 return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments", 70 "Invalid arguments in method call"); 71 } 72 73 void telephony_device_connected(void *telephony_device) 74 { 75 debug("telephony-dummy: device %p connected", telephony_device); 76 } 77 78 void telephony_device_disconnected(void *telephony_device) 79 { 80 debug("telephony-dummy: device %p disconnected", telephony_device); 81 events_enabled = FALSE; 82 } 83 84 void telephony_event_reporting_req(void *telephony_device, int ind) 85 { 86 events_enabled = ind == 1 ? TRUE : FALSE; 87 88 telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE); 89 } 90 91 void telephony_response_and_hold_req(void *telephony_device, int rh) 92 { 93 response_and_hold = rh; 94 95 telephony_response_and_hold_ind(response_and_hold); 96 97 telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NONE); 98 } 99 100 void telephony_last_dialed_number_req(void *telephony_device) 101 { 102 telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE); 103 104 /* Notify outgoing call set-up successfully initiated */ 105 telephony_update_indicator(dummy_indicators, "callsetup", 106 EV_CALLSETUP_OUTGOING); 107 telephony_update_indicator(dummy_indicators, "callsetup", 108 EV_CALLSETUP_ALERTING); 109 110 active_call_status = CALL_STATUS_ALERTING; 111 active_call_dir = CALL_DIR_OUTGOING; 112 } 113 114 void telephony_terminate_call_req(void *telephony_device) 115 { 116 g_free(active_call_number); 117 active_call_number = NULL; 118 119 telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE); 120 121 if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) 122 telephony_update_indicator(dummy_indicators, "callsetup", 123 EV_CALLSETUP_INACTIVE); 124 else 125 telephony_update_indicator(dummy_indicators, "call", 126 EV_CALL_INACTIVE); 127 } 128 129 void telephony_answer_call_req(void *telephony_device) 130 { 131 telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE); 132 133 telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE); 134 telephony_update_indicator(dummy_indicators, "callsetup", 135 EV_CALLSETUP_INACTIVE); 136 137 active_call_status = CALL_STATUS_ACTIVE; 138 } 139 140 void telephony_dial_number_req(void *telephony_device, const char *number) 141 { 142 g_free(active_call_number); 143 active_call_number = g_strdup(number); 144 145 debug("telephony-dummy: dial request to %s", active_call_number); 146 147 telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE); 148 149 /* Notify outgoing call set-up successfully initiated */ 150 telephony_update_indicator(dummy_indicators, "callsetup", 151 EV_CALLSETUP_OUTGOING); 152 telephony_update_indicator(dummy_indicators, "callsetup", 153 EV_CALLSETUP_ALERTING); 154 155 active_call_status = CALL_STATUS_ALERTING; 156 active_call_dir = CALL_DIR_OUTGOING; 157 } 158 159 void telephony_transmit_dtmf_req(void *telephony_device, char tone) 160 { 161 debug("telephony-dummy: transmit dtmf: %c", tone); 162 telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE); 163 } 164 165 void telephony_subscriber_number_req(void *telephony_device) 166 { 167 debug("telephony-dummy: subscriber number request"); 168 if (subscriber_number) 169 telephony_subscriber_number_ind(subscriber_number, 170 NUMBER_TYPE_TELEPHONY, 171 SUBSCRIBER_SERVICE_VOICE); 172 telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE); 173 } 174 175 void telephony_list_current_calls_req(void *telephony_device) 176 { 177 debug("telephony-dummy: list current calls request"); 178 if (active_call_number) 179 telephony_list_current_call_ind(1, active_call_dir, 180 active_call_status, 181 CALL_MODE_VOICE, 182 CALL_MULTIPARTY_NO, 183 active_call_number, 184 NUMBER_TYPE_TELEPHONY); 185 telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE); 186 } 187 188 void telephony_operator_selection_req(void *telephony_device) 189 { 190 telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator"); 191 telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE); 192 } 193 194 void telephony_call_hold_req(void *telephony_device, const char *cmd) 195 { 196 debug("telephony-dymmy: got call hold request %s", cmd); 197 telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE); 198 } 199 200 void telephony_nr_and_ec_req(void *telephony_device, gboolean enable) 201 { 202 debug("telephony-dummy: got %s NR and EC request", 203 enable ? "enable" : "disable"); 204 205 telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE); 206 } 207 208 void telephony_key_press_req(void *telephony_device, const char *keys) 209 { 210 debug("telephony-dummy: got key press request for %s", keys); 211 telephony_key_press_rsp(telephony_device, CME_ERROR_NONE); 212 } 213 214 /* D-Bus method handlers */ 215 static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg, 216 void *data) 217 { 218 const char *number; 219 220 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, 221 DBUS_TYPE_INVALID)) 222 return invalid_args(msg); 223 224 debug("telephony-dummy: outgoing call to %s", number); 225 226 g_free(active_call_number); 227 active_call_number = g_strdup(number); 228 229 telephony_update_indicator(dummy_indicators, "callsetup", 230 EV_CALLSETUP_OUTGOING); 231 telephony_update_indicator(dummy_indicators, "callsetup", 232 EV_CALLSETUP_ALERTING); 233 234 active_call_status = CALL_STATUS_ALERTING; 235 active_call_dir = CALL_DIR_OUTGOING; 236 237 return dbus_message_new_method_return(msg); 238 } 239 240 static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg, 241 void *data) 242 { 243 const char *number; 244 245 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, 246 DBUS_TYPE_INVALID)) 247 return invalid_args(msg); 248 249 debug("telephony-dummy: incoming call to %s", number); 250 251 g_free(active_call_number); 252 active_call_number = g_strdup(number); 253 254 telephony_update_indicator(dummy_indicators, "callsetup", 255 EV_CALLSETUP_INCOMING); 256 257 active_call_status = CALL_STATUS_INCOMING; 258 active_call_dir = CALL_DIR_INCOMING; 259 260 telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY); 261 262 return dbus_message_new_method_return(msg); 263 } 264 265 static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg, 266 void *data) 267 { 268 debug("telephony-dummy: cancel call"); 269 270 g_free(active_call_number); 271 active_call_number = NULL; 272 273 if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) { 274 telephony_update_indicator(dummy_indicators, "callsetup", 275 EV_CALLSETUP_INACTIVE); 276 telephony_calling_stopped_ind(); 277 } 278 279 if (telephony_get_indicator(dummy_indicators, "call") > 0) 280 telephony_update_indicator(dummy_indicators, "call", 281 EV_CALL_INACTIVE); 282 283 return dbus_message_new_method_return(msg); 284 } 285 286 static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg, 287 void *data) 288 { 289 dbus_uint32_t strength; 290 291 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength, 292 DBUS_TYPE_INVALID)) 293 return invalid_args(msg); 294 295 if (strength > 5) 296 return invalid_args(msg); 297 298 telephony_update_indicator(dummy_indicators, "signal", strength); 299 300 debug("telephony-dummy: signal strength set to %u", strength); 301 302 return dbus_message_new_method_return(msg); 303 } 304 305 static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg, 306 void *data) 307 { 308 dbus_uint32_t level; 309 310 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level, 311 DBUS_TYPE_INVALID)) 312 return invalid_args(msg); 313 314 if (level > 5) 315 return invalid_args(msg); 316 317 telephony_update_indicator(dummy_indicators, "battchg", level); 318 319 debug("telephony-dummy: battery level set to %u", level); 320 321 return dbus_message_new_method_return(msg); 322 } 323 324 static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg, 325 void *data) 326 { 327 dbus_bool_t roaming; 328 int val; 329 330 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming, 331 DBUS_TYPE_INVALID)) 332 return invalid_args(msg); 333 334 val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE; 335 336 telephony_update_indicator(dummy_indicators, "roam", val); 337 338 debug("telephony-dummy: roaming status set to %d", val); 339 340 return dbus_message_new_method_return(msg); 341 } 342 343 static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg, 344 void *data) 345 { 346 dbus_bool_t registration; 347 int val; 348 349 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, ®istration, 350 DBUS_TYPE_INVALID)) 351 return invalid_args(msg); 352 353 val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE; 354 355 telephony_update_indicator(dummy_indicators, "service", val); 356 357 debug("telephony-dummy: registration status set to %d", val); 358 359 return dbus_message_new_method_return(msg); 360 } 361 362 static DBusMessage *set_subscriber_number(DBusConnection *conn, 363 DBusMessage *msg, 364 void *data) 365 { 366 const char *number; 367 368 if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, 369 DBUS_TYPE_INVALID)) 370 return invalid_args(msg); 371 372 g_free(subscriber_number); 373 subscriber_number = g_strdup(number); 374 375 debug("telephony-dummy: subscriber number set to %s", number); 376 377 return dbus_message_new_method_return(msg); 378 } 379 380 static GDBusMethodTable dummy_methods[] = { 381 { "OutgoingCall", "s", "", outgoing_call }, 382 { "IncomingCall", "s", "", incoming_call }, 383 { "CancelCall", "", "", cancel_call }, 384 { "SignalStrength", "u", "", signal_strength }, 385 { "BatteryLevel", "u", "", battery_level }, 386 { "RoamingStatus", "b", "", roaming_status }, 387 { "RegistrationStatus", "b", "", registration_status }, 388 { "SetSubscriberNumber","s", "", set_subscriber_number }, 389 { } 390 }; 391 392 static DBusConnection *connection = NULL; 393 394 int telephony_init(void) 395 { 396 uint32_t features = AG_FEATURE_REJECT_A_CALL | 397 AG_FEATURE_ENHANCED_CALL_STATUS | 398 AG_FEATURE_EXTENDED_ERROR_RESULT_CODES; 399 400 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); 401 402 g_dbus_register_interface(connection, "/org/bluez/test", 403 "org.bluez.TelephonyTest", 404 dummy_methods, NULL, 405 NULL, NULL, NULL); 406 407 telephony_ready_ind(features, dummy_indicators, response_and_hold, 408 chld_str); 409 410 return 0; 411 } 412 413 void telephony_exit(void) 414 { 415 dbus_connection_unref(connection); 416 connection = NULL; 417 } 418