From 77d324f70e43dbb3cd784892ba78c2596355617f Mon Sep 17 00:00:00 2001
From: Marc Olivier Chouinard <mochouinard@moctel.com>
Date: Tue, 27 Dec 2011 19:53:21 -0500
Subject: [PATCH] mod_abstraction: New module.  Currently implement API
 abstraction.  Allow to simplify/standarize API name.  Initially built for
 mod_voicemail_ivr.  Allow to use scripting language as VM Storage by binding
 an API with specific argument to an different api call like python and send
 to it argument initially provided.

---
 build/modules.conf.in                         |   1 +
 conf/autoload_configs/abstraction.conf.xml    |   5 +
 src/mod/applications/mod_abstraction/Makefile |   2 +
 .../mod_abstraction/mod_abstraction.c         | 166 ++++++++++++++++++
 4 files changed, 174 insertions(+)
 create mode 100644 conf/autoload_configs/abstraction.conf.xml
 create mode 100644 src/mod/applications/mod_abstraction/Makefile
 create mode 100644 src/mod/applications/mod_abstraction/mod_abstraction.c

diff --git a/build/modules.conf.in b/build/modules.conf.in
index 40d55c7fb8..e8a1c27d63 100644
--- a/build/modules.conf.in
+++ b/build/modules.conf.in
@@ -41,6 +41,7 @@ applications/mod_valet_parking
 #applications/mod_fsk
 #applications/mod_ladspa
 #applications/mod_mongo
+#applications/mod_abstraction
 applications/mod_sms
 codecs/mod_g723_1
 codecs/mod_amr
diff --git a/conf/autoload_configs/abstraction.conf.xml b/conf/autoload_configs/abstraction.conf.xml
new file mode 100644
index 0000000000..d4b1dfd274
--- /dev/null
+++ b/conf/autoload_configs/abstraction.conf.xml
@@ -0,0 +1,5 @@
+<configuration name="abstraction.conf" description="Abstraction">
+<apis>
+	<api name="user_name" description="Return Name for extension" syntax="<exten>" parse="(.*)" destination="user_data" argument="$1@default var effective_caller_id_name"/>
+</apis>
+</configuration>
diff --git a/src/mod/applications/mod_abstraction/Makefile b/src/mod/applications/mod_abstraction/Makefile
new file mode 100644
index 0000000000..53a1f3700f
--- /dev/null
+++ b/src/mod/applications/mod_abstraction/Makefile
@@ -0,0 +1,2 @@
+BASE=../../../..
+include $(BASE)/build/modmake.rules
\ No newline at end of file
diff --git a/src/mod/applications/mod_abstraction/mod_abstraction.c b/src/mod/applications/mod_abstraction/mod_abstraction.c
new file mode 100644
index 0000000000..b1af6a6271
--- /dev/null
+++ b/src/mod/applications/mod_abstraction/mod_abstraction.c
@@ -0,0 +1,166 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Marc Olivier Chouinard <mochouinard@moctel.com>
+ *
+ *
+ * mod_abstraction.c -- Abstraction
+ *
+ */
+#include <switch.h>
+
+/* Prototypes */
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_abstraction_shutdown);
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_abstraction_runtime);
+SWITCH_MODULE_LOAD_FUNCTION(mod_abstraction_load);
+
+const char *global_cf = "abstraction.conf";
+
+/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime) 
+ * Defines a switch_loadable_module_function_table_t and a static const char[] modname
+ */
+SWITCH_MODULE_DEFINITION(mod_abstraction, mod_abstraction_load, mod_abstraction_shutdown, NULL);
+
+SWITCH_STANDARD_API(api_abstraction_function)
+{
+	const char *api_name = switch_event_get_header(stream->param_event, "API-Command");
+	switch_xml_t cfg, xml, x_apis, x_api;
+
+	if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
+		goto end;
+	}
+
+	if (!(x_apis = switch_xml_child(cfg, "apis"))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No apis group\n");
+		goto end;
+	}
+
+	if ((x_api = switch_xml_find_child_multi(x_apis, "api", "name", api_name , NULL))) {
+		const char *parse = switch_xml_attr_soft(x_api, "parse");
+		const char *destination = switch_xml_attr_soft(x_api, "destination");
+		const char *arguments = switch_xml_attr_soft(x_api, "argument");
+
+		int proceed = 0;
+		switch_regex_t *re = NULL;
+		int ovector[30];
+
+		if ((proceed = switch_regex_perform(cmd, parse, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
+			const char *api_args = NULL;
+			char *substituted = NULL;
+
+			if (cmd && strchr(parse, '(')) {
+				uint32_t len = (uint32_t) (strlen(cmd) + strlen(arguments) + 10) * proceed;
+				if (!(substituted = malloc(len))) {
+					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n");
+					proceed = 0;
+					goto end;
+				}
+				memset(substituted, 0, len);
+				switch_perform_substitution(re, proceed, arguments, cmd , substituted, len, ovector);
+				api_args = substituted;
+			} else {
+				api_args = arguments;
+			}
+			switch_api_execute(destination, api_args, session, stream);
+
+			switch_safe_free(substituted);	
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No match for API %s  (%s != %s)\n", api_name, parse, cmd);
+		}
+		switch_regex_safe_free(re);
+	
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "API %s doesn't exist inside the xml structure.  You might have forgot to reload the module after editing it\n", api_name);
+	}
+
+end:
+	if (xml)
+		switch_xml_free(xml);
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* Macro expands to: switch_status_t mod_abstraction_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
+SWITCH_MODULE_LOAD_FUNCTION(mod_abstraction_load)
+{
+	switch_status_t status = SWITCH_STATUS_TERM;
+	switch_api_interface_t *api_interface;
+	switch_xml_t cfg, xml, x_apis, x_api;
+	int count = 0;
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+	if (!(xml = switch_xml_open_cfg(global_cf, &cfg, NULL))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf);
+		goto end;
+	}
+
+	if (!(x_apis = switch_xml_child(cfg, "apis"))) {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No apis group\n");
+		goto end;
+	}
+
+	for (x_api = switch_xml_child(x_apis, "api"); x_api; x_api = x_api->next) {
+		const char *name = switch_xml_attr_soft(x_api, "name");
+		const char *description = switch_xml_attr_soft(x_api, "description");
+		const char *syntax = switch_xml_attr_soft(x_api, "syntax");
+		SWITCH_ADD_API(api_interface, name, description, api_abstraction_function, syntax);
+		count++;
+
+	}
+	if (count > 0) {
+		status = SWITCH_STATUS_SUCCESS;
+	} else {
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No API abstraction defined\n");
+	}
+end:
+	if (xml)
+		switch_xml_free(xml);
+
+	return status;
+}
+
+/*
+   Called when the system shuts down
+   Macro expands to: switch_status_t mod_abstraction_shutdown() */
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_abstraction_shutdown)
+{
+	/* Cleanup dynamically allocated config settings */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4
+ */