1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2010, Mathieu Parent <math.parent@gmail.com>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Mathieu Parent <math.parent@gmail.com>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Mathieu Parent <math.parent@gmail.com>
27  *
28  *
29  * skinny_api.c -- Skinny Call Control Protocol (SCCP) Endpoint Module
30  *
31  */
32 
33 #include <switch.h>
34 #include "mod_skinny.h"
35 #include "skinny_protocol.h"
36 #include "skinny_tables.h"
37 
38 /*****************************************************************************/
39 /* skinny_api_list_* */
40 /*****************************************************************************/
41 
skinny_api_list_profiles(const char * line,const char * cursor,switch_console_callback_match_t ** matches)42 static switch_status_t skinny_api_list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches)
43 {
44 	switch_console_callback_match_t *my_matches = NULL;
45 	switch_status_t status = SWITCH_STATUS_FALSE;
46 	switch_hash_index_t *hi;
47 	void *val;
48 	skinny_profile_t *profile;
49 
50 	/* walk profiles */
51 	switch_mutex_lock(skinny_globals.mutex);
52 	for (hi = switch_core_hash_first(skinny_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
53 		switch_core_hash_this(hi, NULL, NULL, &val);
54 		profile = (skinny_profile_t *) val;
55 
56 		switch_console_push_match(&my_matches, profile->name);
57 	}
58 	switch_mutex_unlock(skinny_globals.mutex);
59 
60 	if (my_matches) {
61 		*matches = my_matches;
62 		status = SWITCH_STATUS_SUCCESS;
63 	}
64 
65 	return status;
66 }
67 
68 struct match_helper {
69 	switch_console_callback_match_t *my_matches;
70 };
71 
skinny_api_list_devices_callback(void * pArg,int argc,char ** argv,char ** columnNames)72 static int skinny_api_list_devices_callback(void *pArg, int argc, char **argv, char **columnNames)
73 {
74 	struct match_helper *h = (struct match_helper *) pArg;
75 	char *device_name = argv[0];
76 
77 	switch_console_push_match(&h->my_matches, device_name);
78 	return 0;
79 }
80 
skinny_api_list_devices(const char * line,const char * cursor,switch_console_callback_match_t ** matches)81 static switch_status_t skinny_api_list_devices(const char *line, const char *cursor, switch_console_callback_match_t **matches)
82 {
83 	struct match_helper h = { 0 };
84 	switch_status_t status = SWITCH_STATUS_FALSE;
85 	skinny_profile_t *profile = NULL;
86 	char *sql;
87 
88 	char *myline;
89 	char *argv[1024] = { 0 };
90 	int argc = 0;
91 
92 	if (!(myline = strdup(line))) {
93 		status = SWITCH_STATUS_MEMERR;
94 		return status;
95 	}
96 	if (!(argc = switch_separate_string(myline, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || argc < 4) {
97 		switch_safe_free(myline);
98 		return status;
99 	}
100 
101 	if(!strcasecmp(argv[1], "profile")) {/* skinny profile <profile_name> ... */
102 		profile = skinny_find_profile(argv[2]);
103 	} else if(!strcasecmp(argv[2], "profile")) {/* skinny status profile <profile_name> ... */
104 		profile = skinny_find_profile(argv[3]);
105 	}
106 
107 	if(profile) {
108 		if ((sql = switch_mprintf("SELECT name FROM skinny_devices"))) {
109 			skinny_execute_sql_callback(profile, profile->sql_mutex, sql, skinny_api_list_devices_callback, &h);
110 			switch_safe_free(sql);
111 		}
112 	}
113 
114 	if (h.my_matches) {
115 		*matches = h.my_matches;
116 		status = SWITCH_STATUS_SUCCESS;
117 	}
118 
119 	switch_safe_free(myline);
120 
121 	return status;
122 }
123 
skinny_api_list_reset_types(const char * line,const char * cursor,switch_console_callback_match_t ** matches)124 static switch_status_t skinny_api_list_reset_types(const char *line, const char *cursor, switch_console_callback_match_t **matches)
125 {
126 	switch_status_t status = SWITCH_STATUS_FALSE;
127 	SKINNY_PUSH_DEVICE_RESET_TYPES
128 		return status;
129 }
130 
skinny_api_list_stimuli(const char * line,const char * cursor,switch_console_callback_match_t ** matches)131 static switch_status_t skinny_api_list_stimuli(const char *line, const char *cursor, switch_console_callback_match_t **matches)
132 {
133 	switch_status_t status = SWITCH_STATUS_FALSE;
134 	SKINNY_PUSH_STIMULI
135 		return status;
136 }
137 
skinny_api_list_ring_types(const char * line,const char * cursor,switch_console_callback_match_t ** matches)138 static switch_status_t skinny_api_list_ring_types(const char *line, const char *cursor, switch_console_callback_match_t **matches)
139 {
140 	switch_status_t status = SWITCH_STATUS_FALSE;
141 	SKINNY_PUSH_RING_TYPES
142 		return status;
143 }
144 
skinny_api_list_ring_modes(const char * line,const char * cursor,switch_console_callback_match_t ** matches)145 static switch_status_t skinny_api_list_ring_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches)
146 {
147 	switch_status_t status = SWITCH_STATUS_FALSE;
148 	SKINNY_PUSH_RING_MODES
149 		return status;
150 }
151 
skinny_api_list_stimulus_instances(const char * line,const char * cursor,switch_console_callback_match_t ** matches)152 static switch_status_t skinny_api_list_stimulus_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches)
153 {
154 	switch_status_t status = SWITCH_STATUS_FALSE;
155 	switch_console_callback_match_t *my_matches = NULL;
156 
157 	switch_console_push_match(&my_matches, "<stimulus_instance>");
158 	switch_console_push_match(&my_matches, "0");
159 
160 	if (my_matches) {
161 		*matches = my_matches;
162 		status = SWITCH_STATUS_SUCCESS;
163 	}
164 	return status;
165 }
166 
skinny_api_list_stimulus_modes(const char * line,const char * cursor,switch_console_callback_match_t ** matches)167 static switch_status_t skinny_api_list_stimulus_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches)
168 {
169 	switch_status_t status = SWITCH_STATUS_FALSE;
170 	SKINNY_PUSH_LAMP_MODES
171 		return status;
172 }
173 
skinny_api_list_speaker_modes(const char * line,const char * cursor,switch_console_callback_match_t ** matches)174 static switch_status_t skinny_api_list_speaker_modes(const char *line, const char *cursor, switch_console_callback_match_t **matches)
175 {
176 	switch_status_t status = SWITCH_STATUS_FALSE;
177 	SKINNY_PUSH_SPEAKER_MODES
178 		return status;
179 }
180 
skinny_api_list_call_states(const char * line,const char * cursor,switch_console_callback_match_t ** matches)181 static switch_status_t skinny_api_list_call_states(const char *line, const char *cursor, switch_console_callback_match_t **matches)
182 {
183 	switch_status_t status = SWITCH_STATUS_FALSE;
184 	SKINNY_PUSH_CALL_STATES
185 		return status;
186 }
187 
skinny_api_list_line_instances(const char * line,const char * cursor,switch_console_callback_match_t ** matches)188 static switch_status_t skinny_api_list_line_instances(const char *line, const char *cursor, switch_console_callback_match_t **matches)
189 {
190 	switch_status_t status = SWITCH_STATUS_FALSE;
191 	switch_console_callback_match_t *my_matches = NULL;
192 
193 	/* TODO */
194 	switch_console_push_match(&my_matches, "1");
195 	switch_console_push_match(&my_matches, "<line_instance>");
196 
197 	if (my_matches) {
198 		*matches = my_matches;
199 		status = SWITCH_STATUS_SUCCESS;
200 	}
201 	return status;
202 }
203 
skinny_api_list_call_ids(const char * line,const char * cursor,switch_console_callback_match_t ** matches)204 static switch_status_t skinny_api_list_call_ids(const char *line, const char *cursor, switch_console_callback_match_t **matches)
205 {
206 	switch_status_t status = SWITCH_STATUS_FALSE;
207 	switch_console_callback_match_t *my_matches = NULL;
208 
209 	/* TODO */
210 	switch_console_push_match(&my_matches, "1345");
211 	switch_console_push_match(&my_matches, "<call_id>");
212 
213 	if (my_matches) {
214 		*matches = my_matches;
215 		status = SWITCH_STATUS_SUCCESS;
216 	}
217 	return status;
218 }
219 
skinny_api_list_settings(const char * line,const char * cursor,switch_console_callback_match_t ** matches)220 static switch_status_t skinny_api_list_settings(const char *line, const char *cursor, switch_console_callback_match_t **matches)
221 {
222 	switch_status_t status = SWITCH_STATUS_FALSE;
223 	switch_console_callback_match_t *my_matches = NULL;
224 
225 	switch_console_push_match(&my_matches, "domain");
226 	switch_console_push_match(&my_matches, "ip");
227 	switch_console_push_match(&my_matches, "port");
228 	switch_console_push_match(&my_matches, "patterns-dialplan");
229 	switch_console_push_match(&my_matches, "patterns-context");
230 	switch_console_push_match(&my_matches, "dialplan");
231 	switch_console_push_match(&my_matches, "context");
232 	switch_console_push_match(&my_matches, "keep-alive");
233 	switch_console_push_match(&my_matches, "date-format");
234 	switch_console_push_match(&my_matches, "odbc-dsn");
235 	switch_console_push_match(&my_matches, "debug");
236 	switch_console_push_match(&my_matches, "auto-restart");
237 	switch_console_push_match(&my_matches, "ext-voicemail");
238 	switch_console_push_match(&my_matches, "ext-redial");
239 	switch_console_push_match(&my_matches, "ext-meetme");
240 	switch_console_push_match(&my_matches, "ext-pickup");
241 	switch_console_push_match(&my_matches, "ext-cfwdall");
242 
243 	if (my_matches) {
244 		*matches = my_matches;
245 		status = SWITCH_STATUS_SUCCESS;
246 	}
247 	return status;
248 }
249 
250 /*****************************************************************************/
251 /* skinny_api_cmd_* */
252 /*****************************************************************************/
skinny_api_cmd_status_profile(const char * profile_name,switch_stream_handle_t * stream)253 static switch_status_t skinny_api_cmd_status_profile(const char *profile_name, switch_stream_handle_t *stream)
254 {
255 	skinny_profile_t *profile;
256 	if ((profile = skinny_find_profile(profile_name))) {
257 		skinny_profile_dump(profile, stream);
258 	} else {
259 		stream->write_function(stream, "Profile not found!\n");
260 	}
261 
262 	return SWITCH_STATUS_SUCCESS;
263 }
264 
skinny_api_cmd_status_profile_device(const char * profile_name,const char * device_name,switch_stream_handle_t * stream)265 static switch_status_t skinny_api_cmd_status_profile_device(const char *profile_name, const char *device_name, switch_stream_handle_t *stream)
266 {
267 	skinny_profile_t *profile;
268 	if ((profile = skinny_find_profile(profile_name))) {
269 		dump_device(profile, device_name, stream);
270 	} else {
271 		stream->write_function(stream, "Profile not found!\n");
272 	}
273 
274 	return SWITCH_STATUS_SUCCESS;
275 }
276 
skinny_api_cmd_profile_device_kill(const char * profile_name,const char * device_name,switch_stream_handle_t * stream)277 static switch_status_t skinny_api_cmd_profile_device_kill(const char *profile_name, const char *device_name, switch_stream_handle_t *stream)
278 {
279 	skinny_profile_t *profile;
280 
281 	if ((profile = skinny_find_profile(profile_name))) {
282 		listener_t *listener = NULL;
283 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
284 		if(listener) {
285 			kill_listener(listener, NULL);
286 			stream->write_function(stream, "+OK\n");
287 		} else {
288 			stream->write_function(stream, "Listener not found!\n");
289 		}
290 	} else {
291 		stream->write_function(stream, "Profile not found!\n");
292 	}
293 
294 	return SWITCH_STATUS_SUCCESS;
295 }
296 
skinny_api_cmd_profile_kill_all(const char * profile_name,switch_stream_handle_t * stream)297 static switch_status_t skinny_api_cmd_profile_kill_all(const char *profile_name, switch_stream_handle_t *stream)
298 {
299 	skinny_profile_t *profile;
300 
301 	if ((profile = skinny_find_profile(profile_name))) {
302 		profile_walk_listeners(profile, kill_listener, NULL);
303 		stream->write_function(stream, "+OK\n");
304 	} else {
305 		stream->write_function(stream, "Profile not found!\n");
306 	}
307 
308 	return SWITCH_STATUS_SUCCESS;
309 }
310 
skinny_api_cmd_profile_device_send_ringer_message(const char * profile_name,const char * device_name,const char * ring_type,const char * ring_mode,switch_stream_handle_t * stream)311 static switch_status_t skinny_api_cmd_profile_device_send_ringer_message(const char *profile_name, const char *device_name, const char *ring_type, const char *ring_mode, switch_stream_handle_t *stream)
312 {
313 	skinny_profile_t *profile;
314 
315 	if ((profile = skinny_find_profile(profile_name))) {
316 		listener_t *listener = NULL;
317 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
318 		if(listener) {
319 			send_set_ringer(listener, skinny_str2ring_type(ring_type), skinny_str2ring_mode(ring_mode), 0, 0);
320 			stream->write_function(stream, "+OK\n");
321 		} else {
322 			stream->write_function(stream, "Listener not found!\n");
323 		}
324 	} else {
325 		stream->write_function(stream, "Profile not found!\n");
326 	}
327 
328 	return SWITCH_STATUS_SUCCESS;
329 }
330 
skinny_api_cmd_profile_device_send_lamp_message(const char * profile_name,const char * device_name,const char * stimulus,const char * instance,const char * lamp_mode,switch_stream_handle_t * stream)331 static switch_status_t skinny_api_cmd_profile_device_send_lamp_message(const char *profile_name, const char *device_name, const char *stimulus, const char *instance, const char *lamp_mode, switch_stream_handle_t *stream)
332 {
333 	skinny_profile_t *profile;
334 
335 	if ((profile = skinny_find_profile(profile_name))) {
336 		listener_t *listener = NULL;
337 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
338 		if(listener) {
339 			send_set_lamp(listener, skinny_str2button(stimulus), atoi(instance), skinny_str2lamp_mode(lamp_mode));
340 			stream->write_function(stream, "+OK\n");
341 		} else {
342 			stream->write_function(stream, "Listener not found!\n");
343 		}
344 	} else {
345 		stream->write_function(stream, "Profile not found!\n");
346 	}
347 
348 	return SWITCH_STATUS_SUCCESS;
349 }
350 
skinny_api_cmd_profile_device_send_speaker_mode_message(const char * profile_name,const char * device_name,const char * speaker_mode,switch_stream_handle_t * stream)351 static switch_status_t skinny_api_cmd_profile_device_send_speaker_mode_message(const char *profile_name, const char *device_name, const char *speaker_mode, switch_stream_handle_t *stream)
352 {
353 	skinny_profile_t *profile;
354 
355 	if ((profile = skinny_find_profile(profile_name))) {
356 		listener_t *listener = NULL;
357 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
358 		if(listener) {
359 			send_set_speaker_mode(listener, skinny_str2speaker_mode(speaker_mode));
360 			stream->write_function(stream, "+OK\n");
361 		} else {
362 			stream->write_function(stream, "Listener not found!\n");
363 		}
364 	} else {
365 		stream->write_function(stream, "Profile not found!\n");
366 	}
367 
368 	return SWITCH_STATUS_SUCCESS;
369 }
370 
skinny_api_cmd_profile_device_send_call_state_message(const char * profile_name,const char * device_name,const char * call_state,const char * line_instance,const char * call_id,switch_stream_handle_t * stream)371 static switch_status_t skinny_api_cmd_profile_device_send_call_state_message(const char *profile_name, const char *device_name, const char *call_state, const char *line_instance, const char *call_id, switch_stream_handle_t *stream)
372 {
373 	skinny_profile_t *profile;
374 
375 	if ((profile = skinny_find_profile(profile_name))) {
376 		listener_t *listener = NULL;
377 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
378 		if(listener) {
379 			send_call_state(listener, skinny_str2call_state(call_state), atoi(line_instance), atoi(call_id));
380 			stream->write_function(stream, "+OK\n");
381 		} else {
382 			stream->write_function(stream, "Listener not found!\n");
383 		}
384 	} else {
385 		stream->write_function(stream, "Profile not found!\n");
386 	}
387 
388 	return SWITCH_STATUS_SUCCESS;
389 }
390 
skinny_api_cmd_profile_device_send_forward_stat_message(const char * profile_name,const char * device_name,const char * number,switch_stream_handle_t * stream)391 static switch_status_t skinny_api_cmd_profile_device_send_forward_stat_message(const char *profile_name, const char *device_name, const char *number, switch_stream_handle_t *stream)
392 {
393 	skinny_profile_t *profile;
394 
395 	if ((profile = skinny_find_profile(profile_name))) {
396 		listener_t *listener = NULL;
397 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
398 		if(listener) {
399 
400 			send_forward_stat(listener, number);
401 
402 			stream->write_function(stream, "+OK\n");
403 		} else {
404 			stream->write_function(stream, "Listener not found!\n");
405 		}
406 	} else {
407 		stream->write_function(stream, "Profile not found!\n");
408 	}
409 
410 	return SWITCH_STATUS_SUCCESS;
411 }
412 
skinny_api_cmd_profile_device_send_display_prompt_status_message(const char * profile_name,const char * device_name,const char * display,switch_stream_handle_t * stream)413 static switch_status_t skinny_api_cmd_profile_device_send_display_prompt_status_message(const char *profile_name, const char *device_name, const char *display, switch_stream_handle_t *stream)
414 {
415 	skinny_profile_t *profile;
416 
417 	if ((profile = skinny_find_profile(profile_name))) {
418 		listener_t *listener = NULL;
419 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
420 		if(listener) {
421 
422 			send_display_prompt_status(listener, 0, display, 0, 0);
423 
424 			stream->write_function(stream, "+OK\n");
425 		} else {
426 			stream->write_function(stream, "Listener not found!\n");
427 		}
428 	} else {
429 		stream->write_function(stream, "Profile not found!\n");
430 	}
431 
432 	return SWITCH_STATUS_SUCCESS;
433 }
434 
skinny_api_cmd_profile_device_send_reset_message(const char * profile_name,const char * device_name,const char * reset_type,switch_stream_handle_t * stream)435 static switch_status_t skinny_api_cmd_profile_device_send_reset_message(const char *profile_name, const char *device_name, const char *reset_type, switch_stream_handle_t *stream)
436 {
437 	skinny_profile_t *profile;
438 
439 	if ((profile = skinny_find_profile(profile_name))) {
440 		listener_t *listener = NULL;
441 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
442 		if(listener) {
443 			send_reset(listener, skinny_str2device_reset_type(reset_type));
444 			stream->write_function(stream, "+OK\n");
445 		} else {
446 			stream->write_function(stream, "Listener not found!\n");
447 		}
448 	} else {
449 		stream->write_function(stream, "Profile not found!\n");
450 	}
451 
452 	return SWITCH_STATUS_SUCCESS;
453 }
454 
skinny_api_cmd_profile_device_send_data(const char * profile_name,const char * device_name,const char * message_type,char * params,const char * body,switch_stream_handle_t * stream)455 static switch_status_t skinny_api_cmd_profile_device_send_data(const char *profile_name, const char *device_name, const char *message_type, char *params, const char *body, switch_stream_handle_t *stream)
456 {
457 	skinny_profile_t *profile;
458 
459 	if ((profile = skinny_find_profile(profile_name))) {
460 		listener_t *listener = NULL;
461 		skinny_profile_find_listener_by_device_name(profile, device_name, &listener);
462 		if(listener) {
463 			switch_event_t *event = NULL;
464 			char *argv[64] = { 0 };
465 			int argc = 0;
466 			int x = 0;
467 			/* skinny::user_to_device event */
468 			skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_USER_TO_DEVICE);
469 			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Message-Id-String", "%s", message_type);
470 			argc = switch_separate_string(params, ';', argv, (sizeof(argv) / sizeof(argv[0])));
471 			for (x = 0; x < argc; x++) {
472 				char *var_name, *var_value = NULL;
473 				var_name = argv[x];
474 				if (var_name && (var_value = strchr(var_name, '='))) {
475 					*var_value++ = '\0';
476 				}
477 				if (zstr(var_name)) {
478 					stream->write_function(stream, "-ERR No variable specified\n");
479 				} else {
480 					char *tmp = switch_mprintf("Skinny-UserToDevice-%s", var_name);
481 					switch_event_add_header(event, SWITCH_STACK_BOTTOM, tmp, "%s", var_value);
482 					switch_safe_free(tmp);
483 					/*
484 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Application-Id", "%d", request->data.extended_data.application_id);
485 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Line-Instance", "%d", request->data.extended_data.line_instance);
486 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Call-Id", "%d", request->data.extended_data.call_id);
487 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Transaction-Id", "%d", request->data.extended_data.transaction_id);
488 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Data-Length", "%d", request->data.extended_data.data_length);
489 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Sequence-Flag", "%d", request->data.extended_data.sequence_flag);
490 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Display-Priority", "%d", request->data.extended_data.display_priority);
491 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Conference-Id", "%d", request->data.extended_data.conference_id);
492 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-App-Instance-Id", "%d", request->data.extended_data.app_instance_id);
493 					   switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-UserToDevice-Routing-Id", "%d", request->data.extended_data.routing_id);
494 					 */
495 				}
496 			}
497 			switch_event_add_body(event, "%s", body);
498 			switch_event_fire(&event);
499 			stream->write_function(stream, "+OK\n");
500 		} else {
501 			stream->write_function(stream, "Listener not found!\n");
502 		}
503 	} else {
504 		stream->write_function(stream, "Profile not found!\n");
505 	}
506 
507 	return SWITCH_STATUS_SUCCESS;
508 }
509 
510 
skinny_api_cmd_profile_set(const char * profile_name,const char * name,const char * value,switch_stream_handle_t * stream)511 static switch_status_t skinny_api_cmd_profile_set(const char *profile_name, const char *name, const char *value, switch_stream_handle_t *stream)
512 {
513 	skinny_profile_t *profile;
514 
515 	if ((profile = skinny_find_profile(profile_name))) {
516 		if (skinny_profile_set(profile, name, value) == SWITCH_STATUS_SUCCESS) {
517 			skinny_profile_respawn(profile, 0);
518 			stream->write_function(stream, "+OK\n");
519 		} else {
520 			stream->write_function(stream, "Unable to set skinny setting '%s'. Does it exists?\n", name);
521 		}
522 	} else {
523 		stream->write_function(stream, "Profile not found!\n");
524 	}
525 
526 	return SWITCH_STATUS_SUCCESS;
527 }
528 
529 /*****************************************************************************/
530 /* API */
531 /*****************************************************************************/
SWITCH_STANDARD_API(skinny_function)532 SWITCH_STANDARD_API(skinny_function)
533 {
534 	char *argv[1024] = { 0 };
535 	int argc = 0;
536 	char *mycmd = NULL;
537 	switch_status_t status = SWITCH_STATUS_SUCCESS;
538 	const char *usage_string = "USAGE:\n"
539 		"--------------------------------------------------------------------------------\n"
540 		"skinny help\n"
541 		"skinny status profile <profile_name>\n"
542 		"skinny status profile <profile_name> device <device_name>\n"
543 		"skinny profile <profile_name> device <device_name> send ResetMessage [DeviceReset|DeviceRestart]\n"
544 		"skinny profile <profile_name> device <device_name> send SetRingerMessage <ring_type> <ring_mode>\n"
545 		"skinny profile <profile_name> device <device_name> send SetLampMessage <stimulus> <instance> <lamp_mode>\n"
546 		"skinny profile <profile_name> device <device_name> send SetSpeakerModeMessage <speaker_mode>\n"
547 		"skinny profile <profile_name> device <device_name> send CallStateMessage <call_state> <line_instance> <call_id>\n"
548 		"skinny profile <profile_name> device <device_name> send ForwardStatMessage <number>\n"
549 		"skinny profile <profile_name> device <device_name> send DisplayPromptStatus <message>\n"
550 		"skinny profile <profile_name> device <device_name> send <UserToDeviceDataMessage|UserToDeviceDataVersion1Message> [ <param>=<value>;... ] <data>\n"
551 		"skinny profile <profile_name> set <name> <value>\n"
552 		"--------------------------------------------------------------------------------\n";
553 	if (session) {
554 		return SWITCH_STATUS_FALSE;
555 	}
556 
557 	if (zstr(cmd)) {
558 		stream->write_function(stream, "%s", usage_string);
559 		goto done;
560 	}
561 
562 	if (!(mycmd = strdup(cmd))) {
563 		status = SWITCH_STATUS_MEMERR;
564 		goto done;
565 	}
566 
567 	if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || !argv[0]) {
568 		stream->write_function(stream, "%s", usage_string);
569 		goto done;
570 	}
571 
572 	if (!strcasecmp(argv[0], "help")) {/* skinny help */
573 		stream->write_function(stream, "%s", usage_string);
574 	} else if (argc == 3 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile")) {
575 		/* skinny status profile <profile_name> */
576 		status = skinny_api_cmd_status_profile(argv[2], stream);
577 	} else if (argc == 3 && !strcasecmp(argv[0], "profile") && !strcasecmp(argv[2], "kill_all")) {
578 		/* skinny profile <profile_name> kill_all */
579 		status = skinny_api_cmd_profile_kill_all(argv[1],stream);
580 	} else if (argc == 5 && !strcasecmp(argv[0], "status") && !strcasecmp(argv[1], "profile") && !strcasecmp(argv[3], "device")) {
581 		/* skinny status profile <profile_name> device <device_name> */
582 		status = skinny_api_cmd_status_profile_device(argv[2], argv[4], stream);
583 	} else if (argc == 5 && !strcasecmp(argv[0], "profile") && !strcasecmp(argv[2], "device") && !strcasecmp(argv[4], "kill")) {
584 		/* skinny profile <profile_name> device <device_name> kill */
585 		status = skinny_api_cmd_profile_device_kill(argv[1],argv[3],stream);
586 	} else if (argc >= 6 && !strcasecmp(argv[0], "profile") && !strcasecmp(argv[2], "device") && !strcasecmp(argv[4], "send")) {
587 		/* skinny profile <profile_name> device <device_name> send ... */
588 		switch(skinny_str2message_type(argv[5])) {
589 			case SET_RINGER_MESSAGE:
590 				if(argc == 8) {
591 					/* SetRingerMessage <ring_type> <ring_mode> */
592 					status = skinny_api_cmd_profile_device_send_ringer_message(argv[1], argv[3], argv[6], argv[7], stream);
593 				}
594 				break;
595 			case SET_LAMP_MESSAGE:
596 				if (argc == 9) {
597 					/* SetLampMessage <stimulus> <instance> <lamp_mode> */
598 					status = skinny_api_cmd_profile_device_send_lamp_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream);
599 				}
600 				break;
601 			case SET_SPEAKER_MODE_MESSAGE:
602 				if (argc == 7) {
603 					/* SetSpeakerModeMessage <speaker_mode> */
604 					status = skinny_api_cmd_profile_device_send_speaker_mode_message(argv[1], argv[3], argv[6], stream);
605 				}
606 				break;
607 			case CALL_STATE_MESSAGE:
608 				if (argc == 9) {
609 					/* CallStateMessage <call_state> <line_instance> <call_id> */
610 					status = skinny_api_cmd_profile_device_send_call_state_message(argv[1], argv[3], argv[6], argv[7], argv[8], stream);
611 				}
612 				break;
613 			case FORWARD_STAT_MESSAGE:
614 				if (argc == 7) {
615 					/* ForwardStatMessage <number> */
616 					status = skinny_api_cmd_profile_device_send_forward_stat_message(argv[1], argv[3], argv[6], stream);
617 				} else if (argc == 6) {
618 					/* ForwardStatMessage */
619 					status = skinny_api_cmd_profile_device_send_forward_stat_message(argv[1], argv[3], NULL, stream);
620 				}
621 				break;
622 			case DISPLAY_PROMPT_STATUS_MESSAGE:
623 				if (argc == 7) {
624 					/* DisplayPromptStatus <display> */
625 					status = skinny_api_cmd_profile_device_send_display_prompt_status_message(argv[1], argv[3], argv[6], stream);
626 				}
627 				break;
628 			case RESET_MESSAGE:
629 				if (argc == 7) {
630 					/* ResetMessage <reset_type> */
631 					status = skinny_api_cmd_profile_device_send_reset_message(argv[1], argv[3], argv[6], stream);
632 				}
633 				break;
634 			case USER_TO_DEVICE_DATA_MESSAGE:
635 			case USER_TO_DEVICE_DATA_VERSION1_MESSAGE:
636 				if(argc == 8) {
637 					/* <UserToDeviceDataMessage|UserToDeviceDataVersion1Message> [ <param>=<value>;... ] <data> */
638 					status = skinny_api_cmd_profile_device_send_data(argv[1], argv[3], argv[5], argv[6], argv[7], stream);
639 				} else if(argc == 7) {
640 					/* <UserToDeviceDataMessage|UserToDeviceDataVersion1Message> <data> */
641 					status = skinny_api_cmd_profile_device_send_data(argv[1], argv[3], argv[5], "", argv[6], stream);
642 				}
643 				break;
644 			default:
645 				stream->write_function(stream, "Unhandled message %s\n", argv[5]);
646 		}
647 	} else if (argc == 5 && !strcasecmp(argv[0], "profile") && !strcasecmp(argv[2], "set")) {
648 		/* skinny profile <profile_name> set <name> <value> */
649 		status = skinny_api_cmd_profile_set(argv[1], argv[3], argv[4], stream);
650 	} else {
651 		stream->write_function(stream, "%s", usage_string);
652 	}
653 
654 done:
655 	switch_safe_free(mycmd);
656 	return status;
657 }
658 
skinny_api_register(switch_loadable_module_interface_t ** module_interface)659 switch_status_t skinny_api_register(switch_loadable_module_interface_t **module_interface)
660 {
661 	switch_api_interface_t *api_interface;
662 
663 	SWITCH_ADD_API(api_interface, "skinny", "Skinny Controls", skinny_function, "<cmd> <args>");
664 	switch_console_set_complete("add skinny help");
665 
666 	switch_console_set_complete("add skinny status profile ::skinny::list_profiles");
667 	switch_console_set_complete("add skinny status profile ::skinny::list_profiles device ::skinny::list_devices");
668 
669 	switch_console_set_complete("add skinny profile ::skinny::list_profiles kill_all");
670 
671 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices kill");
672 
673 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send ResetMessage ::skinny::list_reset_types");
674 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetRingerMessage ::skinny::list_ring_types ::skinny::list_ring_modes");
675 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetLampMessage ::skinny::list_stimuli ::skinny::list_stimulus_instances ::skinny::list_stimulus_modes");
676 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send SetSpeakerModeMessage ::skinny::list_speaker_modes");
677 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send CallStateMessage ::skinny::list_call_states ::skinny::list_line_instances ::skinny::list_call_ids");
678 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send ForwardStatMessage");
679 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send DisplayPromptStatusMessage");
680 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send UserToDeviceDataMessage");
681 	switch_console_set_complete("add skinny profile ::skinny::list_profiles device ::skinny::list_devices send UserToDeviceDataVersion1Message");
682 	switch_console_set_complete("add skinny profile ::skinny::list_profiles set ::skinny::list_settings");
683 
684 	switch_console_add_complete_func("::skinny::list_profiles", skinny_api_list_profiles);
685 	switch_console_add_complete_func("::skinny::list_devices", skinny_api_list_devices);
686 	switch_console_add_complete_func("::skinny::list_reset_types", skinny_api_list_reset_types);
687 	switch_console_add_complete_func("::skinny::list_ring_types", skinny_api_list_ring_types);
688 	switch_console_add_complete_func("::skinny::list_ring_modes", skinny_api_list_ring_modes);
689 	switch_console_add_complete_func("::skinny::list_stimuli", skinny_api_list_stimuli);
690 	switch_console_add_complete_func("::skinny::list_stimulus_instances", skinny_api_list_stimulus_instances);
691 	switch_console_add_complete_func("::skinny::list_stimulus_modes", skinny_api_list_stimulus_modes);
692 	switch_console_add_complete_func("::skinny::list_speaker_modes", skinny_api_list_speaker_modes);
693 	switch_console_add_complete_func("::skinny::list_call_states", skinny_api_list_call_states);
694 	switch_console_add_complete_func("::skinny::list_line_instances", skinny_api_list_line_instances);
695 	switch_console_add_complete_func("::skinny::list_call_ids", skinny_api_list_call_ids);
696 	switch_console_add_complete_func("::skinny::list_settings", skinny_api_list_settings);
697 	return SWITCH_STATUS_SUCCESS;
698 }
699 
skinny_api_unregister()700 switch_status_t skinny_api_unregister()
701 {
702 	switch_console_set_complete("del skinny");
703 
704 	return SWITCH_STATUS_SUCCESS;
705 }
706 
707 /* For Emacs:
708  * Local Variables:
709  * mode:c
710  * indent-tabs-mode:t
711  * tab-width:4
712  * c-basic-offset:4
713  * End:
714  * For VIM:
715  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
716  */
717 
718