1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
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  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  *
28  *
29  * mod_basic.c -- BASIC Module
30  *
31  */
32 #include <switch.h>
33 #include "my_basic.h"
34 
35 /* Prototypes */
36 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_basic_shutdown);
37 SWITCH_MODULE_RUNTIME_FUNCTION(mod_basic_runtime);
38 SWITCH_MODULE_LOAD_FUNCTION(mod_basic_load);
39 
40 /* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
41  * Defines a switch_loadable_module_function_table_t and a static const char[] modname
42  */
43 SWITCH_MODULE_DEFINITION(mod_basic, mod_basic_load, mod_basic_shutdown, NULL);
44 
45 static struct {
46 	int integer;
47 } globals;
48 
49 
50 
do_config(switch_bool_t reload)51 static switch_status_t do_config(switch_bool_t reload)
52 {
53 	memset(&globals, 0, sizeof(globals));
54 
55 	return SWITCH_STATUS_SUCCESS;
56 }
57 
_on_error(mb_interpreter_t * s,mb_error_e e,char * m,int p,unsigned short row,unsigned short col,int abort_code)58 static void _on_error(mb_interpreter_t* s, mb_error_e e, char* m, int p, unsigned short row, unsigned short col, int abort_code) {
59 	mb_unrefvar(s);
60 	if(SE_NO_ERR != e) {
61 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
62 						  "Error:\n    [POS] %d, [ROW] %d, [COL] %d,\n    [CODE] %d, [MESSAGE] %s, [ABORT CODE] %d\n", p, row, col, e, m, abort_code);
63 	}
64 }
65 
66 typedef struct fs_data {
67 	switch_core_session_t *session;
68 	int argc;
69 	char *argv[128];
70 	switch_event_t *vars;
71 } fs_data_t;
72 
73 
fun_execute(mb_interpreter_t * s,void ** l)74 static int fun_execute(mb_interpreter_t* s, void** l)
75 {
76 	int result = MB_FUNC_OK;
77 	fs_data_t *fsdata = (fs_data_t *) mb_get_user_data(s);
78 	mb_value_t app;
79 	mb_value_t arg;
80 	int null_arg = 0;
81 
82 	mb_assert(s && l);
83 
84 	mb_check(mb_attempt_func_begin(s, l));
85 
86 	if ((result = mb_pop_value(s, l, &app)) != MB_FUNC_OK) {
87 		goto end;
88 	}
89 
90 	if ((result = mb_pop_value(s, l, &arg)) != MB_FUNC_OK) {
91 		null_arg++;
92 		result = 0;
93 	}
94 
95 	if (app.type == MB_DT_STRING && (arg.type == MB_DT_STRING || null_arg) && fsdata->session) {
96 		switch_core_session_execute_application(fsdata->session, app.value.string, null_arg ? NULL : arg.value.string);
97 	} else {
98 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad args or no fsdata->session\n");
99 		result = MB_FUNC_WARNING;
100 	}
101 
102 	mb_check(mb_attempt_func_end(s, l));
103 
104  end:
105 
106 	return result;
107 }
108 
109 
fun_setvar(mb_interpreter_t * s,void ** l)110 static int fun_setvar(mb_interpreter_t* s, void** l)
111 {
112 	int result = MB_FUNC_OK;
113 	fs_data_t *fsdata = (fs_data_t *) mb_get_user_data(s);
114 	mb_value_t var;
115 	mb_value_t val;
116 
117 	mb_assert(s && l);
118 
119 	mb_check(mb_attempt_func_begin(s, l));
120 
121 	if ((result = mb_pop_value(s, l, &var)) != MB_FUNC_OK) {
122 		goto end;
123 	}
124 
125 	if ((result = mb_pop_value(s, l, &val)) != MB_FUNC_OK) {
126 		goto end;
127 	}
128 
129 	if (var.type == MB_DT_STRING && val.type == MB_DT_STRING && fsdata->session) {
130 		switch_channel_t *channel = switch_core_session_get_channel(fsdata->session);
131 		switch_channel_set_variable(channel, var.value.string, val.value.string);
132 	} else {
133 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad args or no session\n");
134 		result = MB_FUNC_WARNING;
135 	}
136 
137 	mb_check(mb_attempt_func_end(s, l));
138 
139  end:
140 
141 	return result;
142 }
143 
fun_getarg(mb_interpreter_t * s,void ** l)144 static int fun_getarg(mb_interpreter_t* s, void** l)
145 {
146 	int result = MB_FUNC_OK;
147 	fs_data_t *fsdata = (fs_data_t *) mb_get_user_data(s);
148 	mb_value_t idx;
149 
150 	mb_assert(s && l);
151 
152 	mb_check(mb_attempt_func_begin(s, l));
153 
154 	if ((result = mb_pop_value(s, l, &idx)) != MB_FUNC_OK) {
155 		goto end;
156 	}
157 
158 	if (idx.type == MB_DT_INT && fsdata->argc) {
159 		if (idx.value.integer < fsdata->argc) {
160 			mb_push_string(s, l, strdup(fsdata->argv[idx.value.integer]));
161 		}
162 	} else {
163 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad args or no session\n");
164 		result = MB_FUNC_WARNING;
165 	}
166 
167 	mb_check(mb_attempt_func_end(s, l));
168 
169  end:
170 
171 	return result;
172 }
173 
fun_getvar(mb_interpreter_t * s,void ** l)174 static int fun_getvar(mb_interpreter_t* s, void** l)
175 {
176 	int result = MB_FUNC_OK;
177 	fs_data_t *fsdata = (fs_data_t *) mb_get_user_data(s);
178 	mb_value_t var;
179 
180 	mb_assert(s && l);
181 
182 	mb_check(mb_attempt_func_begin(s, l));
183 
184 	if ((result = mb_pop_value(s, l, &var)) != MB_FUNC_OK) {
185 		goto end;
186 	}
187 
188 	if (var.type == MB_DT_STRING && fsdata->session) {
189 		switch_channel_t *channel = switch_core_session_get_channel(fsdata->session);
190 		const char *value = switch_channel_get_variable(channel, var.value.string);
191 
192 		mb_push_string(s, l, strdup(value));
193 
194 	} else {
195 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad args or no session\n");
196 		result = MB_FUNC_WARNING;
197 	}
198 
199 	mb_check(mb_attempt_func_end(s, l));
200 
201  end:
202 
203 	return result;
204 }
205 
fun_api(mb_interpreter_t * s,void ** l)206 static int fun_api(mb_interpreter_t* s, void** l)
207 {
208 	int result = MB_FUNC_OK;
209 	fs_data_t *fsdata = (fs_data_t *) mb_get_user_data(s);
210 	mb_value_t app;
211 	mb_value_t arg;
212 
213 	mb_assert(s && l);
214 
215 	mb_check(mb_attempt_func_begin(s, l));
216 
217 	if ((result = mb_pop_value(s, l, &app)) != MB_FUNC_OK) {
218 		goto end;
219 	}
220 
221 	if ((result = mb_pop_value(s, l, &arg)) != MB_FUNC_OK) {
222 		goto end;
223 	}
224 
225 	if (app.type == MB_DT_STRING && arg.type == MB_DT_STRING) {
226 		switch_stream_handle_t stream = { 0 };
227 		SWITCH_STANDARD_STREAM(stream);
228 
229 		switch_api_execute(app.value.string, arg.value.string, fsdata->session, &stream);
230 		mb_push_string(s, l, (char *) stream.data);
231 		//switch_safe_free(stream.data);
232 	} else {
233 		result = MB_FUNC_WARNING;
234 	}
235 
236 	mb_check(mb_attempt_func_end(s, l));
237 
238  end:
239 
240 	return result;
241 }
242 
243 
fun_log(mb_interpreter_t * s,void ** l)244 static int fun_log(mb_interpreter_t* s, void** l)
245 {
246 	int result = MB_FUNC_OK;
247 	fs_data_t *fsdata = (fs_data_t *) mb_get_user_data(s);
248 	mb_value_t level;
249 	mb_value_t data;
250 
251 	mb_assert(s && l);
252 
253 	mb_check(mb_attempt_func_begin(s, l));
254 
255 	if ((result = mb_pop_value(s, l, &level)) != MB_FUNC_OK) {
256 		goto end;
257 	}
258 
259 	if ((result = mb_pop_value(s, l, &data)) != MB_FUNC_OK) {
260 		goto end;
261 	}
262 
263 	if (level.type == MB_DT_STRING && data.type == MB_DT_STRING) {
264 		switch_log_level_t fslevel = SWITCH_LOG_DEBUG;
265 
266 		fslevel = switch_log_str2level(level.value.string);
267 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(fsdata->session), fslevel, "%s\n", data.value.string);
268 	} else {
269 		result = MB_FUNC_WARNING;
270 	}
271 
272 	mb_check(mb_attempt_func_end(s, l));
273 
274  end:
275 
276 	return result;
277 }
278 
279 
bprint(const char * fmt,...)280 static int bprint(const char *fmt, ...)
281 {
282 	char *data = NULL;
283 	va_list ap;
284 	int ret = 0;
285 
286 	va_start(ap, fmt);
287 	ret = switch_vasprintf(&data, fmt, ap);
288 	va_end(ap);
289 
290 	if (data) {
291 		switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, "%s\n", data);
292 	}
293 
294 	switch_safe_free(data);
295 
296 	return ret;
297 
298 }
299 
300 
SWITCH_STANDARD_APP(basic_function)301 SWITCH_STANDARD_APP(basic_function)
302 {
303 	const char *file;
304 	char *fdup = NULL;
305 	mb_interpreter_t *bi = 0;
306 	fs_data_t fsdata = { 0 };
307 	char *mydata = NULL;
308 
309 	if (data) {
310 		mydata = strdup((char *) data);
311 	} else {
312 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing data\n");
313 		return;
314 	}
315 
316 	fsdata.argc = switch_split(mydata, ' ', fsdata.argv);
317 
318 	file = fsdata.argv[0];
319 
320 	if (zstr(file)) {
321 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing file\n");
322 		goto end;
323 	}
324 
325 	if (!switch_is_file_path(file)) {
326 		fdup = switch_mprintf("%s/%s", SWITCH_GLOBAL_dirs.script_dir, file);
327 		switch_assert(fdup);
328 		file = fdup;
329 	}
330 
331 	mb_open(&bi);
332 	mb_set_error_handler(bi, _on_error);
333 	mb_set_printer(bi, bprint);
334 	fsdata.session = session;
335 	mb_set_user_data(bi, (void *) &fsdata);
336 
337 	mb_register_func(bi, "FS_EXECUTE", fun_execute);
338 	mb_register_func(bi, "FS_GETARG", fun_getarg);
339 	mb_register_func(bi, "FS_GETVAR", fun_getvar);
340 	mb_register_func(bi, "FS_SETVAR", fun_setvar);
341 	mb_register_func(bi, "FS_API", fun_api);
342 	mb_register_func(bi, "FS_LOG", fun_log);
343 
344 	if (mb_load_file(bi, file) == MB_FUNC_OK) {
345 		mb_run(bi);
346 	} else {
347 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error executing file\n");
348 	}
349 
350 	mb_close(&bi);
351 
352  end:
353 	switch_safe_free(fdup);
354 	switch_safe_free(mydata);
355 }
356 
SWITCH_STANDARD_API(basic_api_function)357 SWITCH_STANDARD_API(basic_api_function)
358 {
359 
360 	basic_function(session, cmd);
361 
362 	return SWITCH_STATUS_SUCCESS;
363 }
364 
365 /* Macro expands to: switch_status_t mod_basic_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_basic_load)366 SWITCH_MODULE_LOAD_FUNCTION(mod_basic_load)
367 {
368 	switch_api_interface_t *api_interface;
369 	switch_application_interface_t *app_interface;
370 
371 	/* connect my internal structure to the blank pointer passed to me */
372 	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
373 
374 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Hello World!\n");
375 
376 	do_config(SWITCH_FALSE);
377 
378 	SWITCH_ADD_API(api_interface, "basic", "Basic API", basic_api_function, "syntax");
379 	SWITCH_ADD_APP(app_interface, "basic", "", "", basic_function, "<file>", SAF_NONE);
380 
381 	mb_init();
382 
383 	/* indicate that the module should continue to be loaded */
384 	return SWITCH_STATUS_SUCCESS;
385 }
386 
387 /*
388   Called when the system shuts down
389   Macro expands to: switch_status_t mod_basic_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_basic_shutdown)390 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_basic_shutdown)
391 {
392 	/* Cleanup dynamically allocated config settings */
393 	mb_dispose();
394 
395 	return SWITCH_STATUS_SUCCESS;
396 }
397 
398 
399 /*
400   If it exists, this is called in it's own thread when the module-load completes
401   If it returns anything but SWITCH_STATUS_TERM it will be called again automatically
402   Macro expands to: switch_status_t mod_basic_runtime()
403 SWITCH_MODULE_RUNTIME_FUNCTION(mod_basic_runtime)
404 {
405 	while(looping)
406 	{
407 		switch_cond_next();
408 	}
409 	return SWITCH_STATUS_TERM;
410 }
411 */
412 
413 /* For Emacs:
414  * Local Variables:
415  * mode:c
416  * indent-tabs-mode:t
417  * tab-width:4
418  * c-basic-offset:4
419  * End:
420  * For VIM:
421  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet
422  */
423