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