| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Copyright (C) 1999 - 2005, Digium, Inc. | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * Mark Spencer <markster@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  |  * This program is free software, distributed under the terms of | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  | /*! \file
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-10-24 20:12:06 +00:00
										 |  |  |  * \brief Dial plan macro Implementation | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Mark Spencer <markster@digium.com> | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  *  | 
					
						
							| 
									
										
										
										
											2005-11-06 15:09:47 +00:00
										 |  |  |  * \ingroup applications | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-14 20:13:06 +00:00
										 |  |  | /*** MODULEINFO
 | 
					
						
							| 
									
										
										
										
											2011-09-27 20:10:13 +00:00
										 |  |  | 	<support_level>core</support_level> | 
					
						
							| 
									
										
										
										
											2011-07-14 20:13:06 +00:00
										 |  |  | 	<replacement>app_stack (GoSub)</replacement> | 
					
						
							| 
									
										
										
										
											2011-07-15 20:41:12 +00:00
										 |  |  |  ***/ | 
					
						
							| 
									
										
										
										
											2011-07-14 20:13:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-21 06:02:45 +00:00
										 |  |  | #include "asterisk/file.h"
 | 
					
						
							|  |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/module.h"
 | 
					
						
							|  |  |  | #include "asterisk/config.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | #include "asterisk/lock.h"
 | 
					
						
							| 
									
										
										
										
											2009-06-01 20:57:31 +00:00
										 |  |  | #include "asterisk/app.h"
 | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 18:46:29 +00:00
										 |  |  | /*** DOCUMENTATION
 | 
					
						
							|  |  |  | 	<application name="Macro" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Macro Implementation. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="name" required="true"> | 
					
						
							|  |  |  | 				<para>The name of the macro</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="args"> | 
					
						
							|  |  |  | 				<argument name="arg1" required="true" /> | 
					
						
							|  |  |  | 				<argument name="arg2" multiple="true" /> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Executes a macro using the context macro-<replaceable>name</replaceable>, | 
					
						
							|  |  |  | 			jumping to the <literal>s</literal> extension of that context and executing each step, | 
					
						
							|  |  |  | 			then returning when the steps end.</para> | 
					
						
							|  |  |  | 			<para>The calling extension, context, and priority are stored in <variable>MACRO_EXTEN</variable>, | 
					
						
							|  |  |  | 			<variable>MACRO_CONTEXT</variable> and <variable>MACRO_PRIORITY</variable> respectively. Arguments | 
					
						
							|  |  |  | 			become <variable>ARG1</variable>, <variable>ARG2</variable>, etc in the macro context.</para> | 
					
						
							|  |  |  | 			<para>If you Goto out of the Macro context, the Macro will terminate and control will be returned | 
					
						
							|  |  |  | 			at the location of the Goto.</para> | 
					
						
							|  |  |  | 			<para>If <variable>MACRO_OFFSET</variable> is set at termination, Macro will attempt to continue | 
					
						
							|  |  |  | 			at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.</para> | 
					
						
							|  |  |  | 			<warning><para>Because of the way Macro is implemented (it executes the priorities contained within | 
					
						
							|  |  |  | 			it via sub-engine), and a fixed per-thread memory stack allowance, macros are limited to 7 levels | 
					
						
							|  |  |  | 			of nesting (macro calling macro calling macro, etc.); It may be possible that stack-intensive | 
					
						
							|  |  |  | 			applications in deeply nested macros could cause asterisk to crash earlier than this limit. | 
					
						
							|  |  |  | 			It is advised that if you need to deeply nest macro calls, that you use the Gosub application | 
					
						
							|  |  |  | 			(now allows arguments like a Macro) with explict Return() calls instead.</para></warning> | 
					
						
							| 
									
										
										
										
											2009-05-18 14:45:23 +00:00
										 |  |  | 			<warning><para>Use of the application <literal>WaitExten</literal> within a macro will not function | 
					
						
							|  |  |  | 			as expected. Please use the <literal>Read</literal> application in order to read DTMF from a channel | 
					
						
							|  |  |  | 			currently executing a macro.</para></warning> | 
					
						
							| 
									
										
										
										
											2008-11-05 18:46:29 +00:00
										 |  |  | 		</description> | 
					
						
							|  |  |  | 		<see-also> | 
					
						
							|  |  |  | 			<ref type="application">MacroExit</ref> | 
					
						
							|  |  |  | 			<ref type="application">Goto</ref> | 
					
						
							|  |  |  | 			<ref type="application">Gosub</ref> | 
					
						
							|  |  |  | 		</see-also> | 
					
						
							|  |  |  | 	</application> | 
					
						
							|  |  |  | 	<application name="MacroIf" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Conditional Macro implementation. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax argsep="?"> | 
					
						
							|  |  |  | 			<parameter name="expr" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="destination" required="true" argsep=":"> | 
					
						
							|  |  |  | 				<argument name="macroiftrue" required="true"> | 
					
						
							|  |  |  | 					<argument name="macroiftrue" required="true" /> | 
					
						
							|  |  |  | 					<argument name="arg1" multiple="true" /> | 
					
						
							|  |  |  | 				</argument> | 
					
						
							|  |  |  | 				<argument name="macroiffalse"> | 
					
						
							|  |  |  | 					<argument name="macroiffalse" required="true" /> | 
					
						
							|  |  |  | 					<argument name="arg1" multiple="true" /> | 
					
						
							|  |  |  | 				</argument> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Executes macro defined in <replaceable>macroiftrue</replaceable> if | 
					
						
							|  |  |  | 			<replaceable>expr</replaceable> is true (otherwise <replaceable>macroiffalse</replaceable> | 
					
						
							|  |  |  | 			if provided)</para> | 
					
						
							|  |  |  | 			<para>Arguments and return values as in application Macro()</para> | 
					
						
							| 
									
										
										
										
											2009-05-18 14:45:23 +00:00
										 |  |  | 			<xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" /> | 
					
						
							| 
									
										
										
										
											2008-11-05 18:46:29 +00:00
										 |  |  | 		</description> | 
					
						
							|  |  |  | 		<see-also> | 
					
						
							|  |  |  | 			<ref type="application">GotoIf</ref> | 
					
						
							|  |  |  | 			<ref type="application">GosubIf</ref> | 
					
						
							|  |  |  | 			<ref type="function">IF</ref> | 
					
						
							|  |  |  | 		</see-also> | 
					
						
							|  |  |  | 	</application> | 
					
						
							|  |  |  | 	<application name="MacroExclusive" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Exclusive Macro Implementation. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="name" required="true"> | 
					
						
							|  |  |  | 				<para>The name of the macro</para> | 
					
						
							|  |  |  | 			</parameter> | 
					
						
							|  |  |  | 			<parameter name="arg1" /> | 
					
						
							|  |  |  | 			<parameter name="arg2" multiple="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Executes macro defined in the context macro-<replaceable>name</replaceable>. | 
					
						
							|  |  |  | 			Only one call at a time may run the macro. (we'll wait if another call is busy | 
					
						
							|  |  |  | 			executing in the Macro)</para> | 
					
						
							|  |  |  | 			<para>Arguments and return values as in application Macro()</para> | 
					
						
							| 
									
										
										
										
											2009-05-18 14:45:23 +00:00
										 |  |  | 			<xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" /> | 
					
						
							| 
									
										
										
										
											2008-11-05 18:46:29 +00:00
										 |  |  | 		</description> | 
					
						
							|  |  |  | 		<see-also> | 
					
						
							|  |  |  | 			<ref type="application">Macro</ref> | 
					
						
							|  |  |  | 		</see-also> | 
					
						
							|  |  |  | 	</application> | 
					
						
							|  |  |  | 	<application name="MacroExit" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Exit from Macro. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax /> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Causes the currently running macro to exit as if it had | 
					
						
							|  |  |  | 			ended normally by running out of priorities to execute. | 
					
						
							|  |  |  | 			If used outside a macro, will likely cause unexpected behavior.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 		<see-also> | 
					
						
							|  |  |  | 			<ref type="application">Macro</ref> | 
					
						
							|  |  |  | 		</see-also> | 
					
						
							|  |  |  | 	</application> | 
					
						
							|  |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | #define MAX_ARGS 80
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-07 05:42:31 +00:00
										 |  |  | /* special result value used to force macro exit */ | 
					
						
							|  |  |  | #define MACRO_EXIT_RESULT 1024
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | static char *app = "Macro"; | 
					
						
							| 
									
										
										
										
											2004-11-22 23:41:34 +00:00
										 |  |  | static char *if_app = "MacroIf"; | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | static char *exclusive_app = "MacroExclusive"; | 
					
						
							| 
									
										
										
										
											2005-01-07 05:42:31 +00:00
										 |  |  | static char *exit_app = "MacroExit"; | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-15 19:10:10 +00:00
										 |  |  | static struct ast_datastore_info macro_ds_info = { | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	.type = "MACRO", | 
					
						
							|  |  |  | 	.chan_fixup = macro_fixup, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	char varname[10]; | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(new_chan, "MACRO_DEPTH", "0"); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(new_chan, "MACRO_CONTEXT", NULL); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(new_chan, "MACRO_EXTEN", NULL); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(new_chan, "MACRO_PRIORITY", NULL); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(new_chan, "MACRO_OFFSET", NULL); | 
					
						
							|  |  |  | 	for (i = 1; i < 100; i++) { | 
					
						
							|  |  |  | 		snprintf(varname, sizeof(varname), "ARG%d", i); | 
					
						
							|  |  |  | 		while (pbx_builtin_getvar_helper(new_chan, varname)) { | 
					
						
							|  |  |  | 			/* Kill all levels of arguments */ | 
					
						
							|  |  |  | 			pbx_builtin_setvar_helper(new_chan, varname, NULL); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_exten *e; | 
					
						
							|  |  |  | 	struct ast_include *i; | 
					
						
							|  |  |  | 	struct ast_context *c2; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) { | 
					
						
							|  |  |  | 		if (ast_extension_match(ast_get_extension_name(e), exten)) { | 
					
						
							|  |  |  | 			int needmatch = ast_get_extension_matchcid(e); | 
					
						
							|  |  |  | 			if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) || | 
					
						
							|  |  |  | 				(!needmatch)) { | 
					
						
							|  |  |  | 				/* This is the matching extension we want */ | 
					
						
							|  |  |  | 				struct ast_exten *p; | 
					
						
							|  |  |  | 				for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) { | 
					
						
							|  |  |  | 					if (priority != ast_get_extension_priority(p)) | 
					
						
							|  |  |  | 						continue; | 
					
						
							|  |  |  | 					return p; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* No match; run through includes */ | 
					
						
							|  |  |  | 	for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) { | 
					
						
							|  |  |  | 		for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) { | 
					
						
							|  |  |  | 			if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) { | 
					
						
							|  |  |  | 				e = find_matching_priority(c2, exten, priority, callerid); | 
					
						
							|  |  |  | 				if (e) | 
					
						
							|  |  |  | 					return e; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive) | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-12-03 19:25:33 +00:00
										 |  |  | 	const char *s; | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	char *tmp; | 
					
						
							|  |  |  | 	char *cur, *rest; | 
					
						
							|  |  |  | 	char *macro; | 
					
						
							|  |  |  | 	char fullmacro[80]; | 
					
						
							|  |  |  | 	char varname[80]; | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 	char runningapp[80], runningdata[1024]; | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	char *oldargs[MAX_ARGS + 1] = { NULL, }; | 
					
						
							|  |  |  | 	int argc, x; | 
					
						
							|  |  |  | 	int res=0; | 
					
						
							|  |  |  | 	char oldexten[256]=""; | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 	int oldpriority, gosub_level = 0; | 
					
						
							| 
									
										
										
										
											2005-09-07 20:39:20 +00:00
										 |  |  | 	char pc[80], depthc[12]; | 
					
						
							| 
									
										
										
										
											2005-07-10 23:49:57 +00:00
										 |  |  | 	char oldcontext[AST_MAX_CONTEXT] = ""; | 
					
						
							| 
									
										
										
										
											2007-02-07 15:35:44 +00:00
										 |  |  | 	const char *inhangupc; | 
					
						
							| 
									
										
										
										
											2006-08-17 15:48:49 +00:00
										 |  |  | 	int offset, depth = 0, maxdepth = 7; | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	int setmacrocontext=0; | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	int autoloopflag, inhangup = 0; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	struct ast_str *tmp_subst = NULL; | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	char *save_macro_exten; | 
					
						
							|  |  |  | 	char *save_macro_context; | 
					
						
							|  |  |  | 	char *save_macro_priority; | 
					
						
							|  |  |  | 	char *save_macro_offset; | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	struct ast_datastore *macro_store = ast_channel_datastore_find(chan, ¯o_ds_info, NULL); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-26 19:48:14 +00:00
										 |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							| 
									
										
										
										
											2007-07-31 01:10:47 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n"); | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2004-11-22 23:41:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	do { | 
					
						
							|  |  |  | 		if (macro_store) { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-12-17 21:28:51 +00:00
										 |  |  | 		if (!(macro_store = ast_datastore_alloc(¯o_ds_info, NULL))) { | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Unable to allocate new datastore.\n"); | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		/* Just the existence of this datastore is enough. */ | 
					
						
							|  |  |  | 		macro_store->inheritance = DATASTORE_INHERIT_FOREVER; | 
					
						
							|  |  |  | 		ast_channel_datastore_add(chan, macro_store); | 
					
						
							|  |  |  | 	} while (0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-17 15:48:49 +00:00
										 |  |  | 	/* does the user want a deeper rabbit hole? */ | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	ast_channel_lock(chan); | 
					
						
							|  |  |  | 	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) { | 
					
						
							| 
									
										
										
										
											2009-08-10 19:20:57 +00:00
										 |  |  | 		sscanf(s, "%30d", &maxdepth); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2005-09-07 20:39:20 +00:00
										 |  |  | 	/* Count how many levels deep the rabbit hole goes */ | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) { | 
					
						
							| 
									
										
										
										
											2009-08-10 19:20:57 +00:00
										 |  |  | 		sscanf(s, "%30d", &depth); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2007-02-07 15:35:44 +00:00
										 |  |  | 	/* Used for detecting whether to return when a Macro is called from another Macro after hangup */ | 
					
						
							|  |  |  | 	if (strcmp(chan->exten, "h") == 0) | 
					
						
							|  |  |  | 		pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1"); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) { | 
					
						
							| 
									
										
										
										
											2009-08-10 19:20:57 +00:00
										 |  |  | 		sscanf(inhangupc, "%30d", &inhangup); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ast_channel_unlock(chan); | 
					
						
							| 
									
										
										
										
											2007-02-07 15:35:44 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-17 15:48:49 +00:00
										 |  |  | 	if (depth >= maxdepth) { | 
					
						
							| 
									
										
										
										
											2005-09-07 20:39:20 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	snprintf(depthc, sizeof(depthc), "%d", depth + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 	tmp = ast_strdupa(data); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	rest = tmp; | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	macro = strsep(&rest, ","); | 
					
						
							| 
									
										
										
										
											2005-10-26 19:48:14 +00:00
										 |  |  | 	if (ast_strlen_zero(macro)) { | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "Invalid macro name specified\n"); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro); | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	if (!ast_exists_extension(chan, fullmacro, "s", 1, | 
					
						
							|  |  |  | 		S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 		if (!ast_context_find(fullmacro))  | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro); | 
					
						
							|  |  |  | 		else | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 			ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* If we are to run the macro exclusively, take the mutex */ | 
					
						
							|  |  |  | 	if (exclusive) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1, "Locking macrolock for '%s'\n", fullmacro); | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 		ast_autoservice_start(chan); | 
					
						
							|  |  |  | 		if (ast_context_lockmacro(fullmacro)) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro); | 
					
						
							|  |  |  | 			ast_autoservice_stop(chan); | 
					
						
							|  |  |  | 			return 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		ast_autoservice_stop(chan); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!(tmp_subst = ast_str_create(16))) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	/* Save old info */ | 
					
						
							|  |  |  | 	oldpriority = chan->priority; | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 	ast_copy_string(oldexten, chan->exten, sizeof(oldexten)); | 
					
						
							|  |  |  | 	ast_copy_string(oldcontext, chan->context, sizeof(oldcontext)); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	if (ast_strlen_zero(chan->macrocontext)) { | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 		ast_copy_string(chan->macrocontext, chan->context, sizeof(chan->macrocontext)); | 
					
						
							|  |  |  | 		ast_copy_string(chan->macroexten, chan->exten, sizeof(chan->macroexten)); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		chan->macropriority = chan->priority; | 
					
						
							|  |  |  | 		setmacrocontext=1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	argc = 1; | 
					
						
							|  |  |  | 	/* Save old macro variables */ | 
					
						
							| 
									
										
										
										
											2006-01-13 18:38:55 +00:00
										 |  |  | 	save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN")); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten); | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-13 18:38:55 +00:00
										 |  |  | 	save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT")); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext); | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-13 18:38:55 +00:00
										 |  |  | 	save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY")); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	snprintf(pc, sizeof(pc), "%d", oldpriority); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc); | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  |    | 
					
						
							| 
									
										
										
										
											2006-01-13 18:38:55 +00:00
										 |  |  | 	save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET")); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL); | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	/* Setup environment for new run */ | 
					
						
							|  |  |  | 	chan->exten[0] = 's'; | 
					
						
							|  |  |  | 	chan->exten[1] = '\0'; | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 	ast_copy_string(chan->context, fullmacro, sizeof(chan->context)); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	chan->priority = 1; | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	ast_channel_lock(chan); | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) { | 
					
						
							| 
									
										
										
										
											2008-08-10 14:45:25 +00:00
										 |  |  | 		const char *argp; | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  |   		/* Save copy of old arguments if we're overwriting some, otherwise
 | 
					
						
							|  |  |  | 	   	let them pass through to the other macro */ | 
					
						
							|  |  |  |   		snprintf(varname, sizeof(varname), "ARG%d", argc); | 
					
						
							| 
									
										
										
										
											2008-08-10 14:45:25 +00:00
										 |  |  | 		if ((argp = pbx_builtin_getvar_helper(chan, varname))) { | 
					
						
							|  |  |  | 			oldargs[argc] = ast_strdup(argp); | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		pbx_builtin_setvar_helper(chan, varname, cur); | 
					
						
							|  |  |  | 		argc++; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-04-30 19:21:04 +00:00
										 |  |  | 	ast_channel_unlock(chan); | 
					
						
							| 
									
										
										
										
											2005-04-29 15:04:26 +00:00
										 |  |  | 	autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP); | 
					
						
							|  |  |  | 	ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP); | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 	while (ast_exists_extension(chan, chan->context, chan->exten, chan->priority, | 
					
						
							|  |  |  | 		S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		struct ast_context *c; | 
					
						
							|  |  |  | 		struct ast_exten *e; | 
					
						
							| 
									
										
										
											
												This commits the performance mods that give the priority processing engine in the pbx, a 25-30% speed boost. The two updates used, are, first, to merge the ast_exists_extension() and the ast_spawn_extension() where they are called sequentially in a loop in the code, into a slightly upgraded version of ast_spawn_extension(), with a few extra args; and, second, I modified the substitute_variables_helper_full, so it zeroes out the byte after the evaluated string instead of demanding you pre-zero the buffer; I also went thru the code and removed the code that zeroed this buffer before every call to the substitute_variables_helper_full. The first fix provides about a 9% speedup, and the second the rest. These figures come from the 'PIPS' benchmark I describe in blogs, conf. reports, etc.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@88166 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2007-11-01 22:26:51 +00:00
										 |  |  | 		int foundx; | 
					
						
							| 
									
										
										
										
											2007-05-31 17:16:38 +00:00
										 |  |  | 		runningapp[0] = '\0'; | 
					
						
							|  |  |  | 		runningdata[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 		/* What application will execute? */ | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		if (ast_rdlock_contexts()) { | 
					
						
							|  |  |  | 			ast_log(LOG_WARNING, "Failed to lock contexts list\n"); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) { | 
					
						
							|  |  |  | 				if (!strcmp(ast_get_context_name(c), chan->context)) { | 
					
						
							|  |  |  | 					if (ast_rdlock_context(c)) { | 
					
						
							|  |  |  | 						ast_log(LOG_WARNING, "Unable to lock context?\n"); | 
					
						
							|  |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 						e = find_matching_priority(c, chan->exten, chan->priority, | 
					
						
							|  |  |  | 							S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)); | 
					
						
							| 
									
										
										
										
											2007-05-31 17:16:38 +00:00
										 |  |  | 						if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */ | 
					
						
							|  |  |  | 							ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp)); | 
					
						
							|  |  |  | 							ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata)); | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 						ast_unlock_context(c); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		ast_unlock_contexts(); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-07 20:39:20 +00:00
										 |  |  | 		/* Reset the macro depth, if it was changed in the last iteration */ | 
					
						
							|  |  |  | 		pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-14 15:48:36 +00:00
										 |  |  | 		res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, | 
					
						
							|  |  |  | 			S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL), | 
					
						
							|  |  |  | 			&foundx, 1); | 
					
						
							|  |  |  | 		if (res) { | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 			/* Something bad happened, or a hangup has been requested. */ | 
					
						
							|  |  |  | 			if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) || | 
					
						
							|  |  |  | 		    	(res == '*') || (res == '#')) { | 
					
						
							|  |  |  | 				/* Just return result as to the previous application as if it had been dialed */ | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			switch(res) { | 
					
						
							| 
									
										
										
										
											2006-02-05 17:20:29 +00:00
										 |  |  | 			case MACRO_EXIT_RESULT: | 
					
						
							|  |  |  | 				res = 0; | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 				goto out; | 
					
						
							|  |  |  | 			default: | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro); | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 				ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 				goto out; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1, "Executed application: %s\n", runningapp); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		if (!strcasecmp(runningapp, "GOSUB")) { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			gosub_level++; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1, "Incrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		} else if (!strcasecmp(runningapp, "GOSUBIF")) { | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | 			char *cond, *app_arg; | 
					
						
							|  |  |  | 			char *app2; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata); | 
					
						
							|  |  |  | 			app2 = ast_str_buffer(tmp_subst); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			cond = strsep(&app2, "?"); | 
					
						
							| 
									
										
										
										
											2008-08-10 14:45:25 +00:00
										 |  |  | 			app_arg = strsep(&app2, ":"); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			if (pbx_checkcondition(cond)) { | 
					
						
							| 
									
										
										
										
											2008-08-10 14:45:25 +00:00
										 |  |  | 				if (!ast_strlen_zero(app_arg)) { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 					gosub_level++; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 					ast_debug(1, "Incrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				if (!ast_strlen_zero(app2)) { | 
					
						
							|  |  |  | 					gosub_level++; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 					ast_debug(1, "Incrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		} else if (!strcasecmp(runningapp, "RETURN")) { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			gosub_level--; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1, "Decrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		} else if (!strcasecmp(runningapp, "STACKPOP")) { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			gosub_level--; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1, "Decrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 		} else if (!strncasecmp(runningapp, "EXEC", 4)) { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			/* Must evaluate args to find actual app */ | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 			char *tmp2, *tmp3 = NULL; | 
					
						
							|  |  |  | 			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata); | 
					
						
							|  |  |  | 			tmp2 = ast_str_buffer(tmp_subst); | 
					
						
							| 
									
										
										
										
											2007-05-08 22:40:21 +00:00
										 |  |  | 			if (!strcasecmp(runningapp, "EXECIF")) { | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | 				if ((tmp3 = strchr(tmp2, '|'))) { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 					*tmp3++ = '\0'; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				if (!pbx_checkcondition(tmp2)) { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 					tmp3 = NULL; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 				tmp3 = tmp2; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 			if (tmp3) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(1, "Last app: %s\n", tmp3); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) { | 
					
						
							|  |  |  | 				gosub_level++; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(1, "Incrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			} else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) { | 
					
						
							|  |  |  | 				gosub_level--; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(1, "Decrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			} else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) { | 
					
						
							|  |  |  | 				gosub_level--; | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 				ast_debug(1, "Decrementing gosub_level\n"); | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (gosub_level == 0 && strcasecmp(chan->context, fullmacro)) { | 
					
						
							| 
									
										
										
										
											2007-07-26 15:49:18 +00:00
										 |  |  | 			ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", chan->name, macro); | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-04-08 14:23:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		/* don't stop executing extensions when we're in "h" */ | 
					
						
							| 
									
										
										
										
											2007-08-01 15:39:54 +00:00
										 |  |  | 		if (ast_check_hangup(chan) && !inhangup) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 			ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", chan->exten, chan->macroexten, chan->priority); | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 			goto out; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		chan->priority++; | 
					
						
							|  |  |  |   	} | 
					
						
							|  |  |  | 	out: | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Don't let the channel change now. */ | 
					
						
							|  |  |  | 	ast_channel_lock(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-09-07 20:39:20 +00:00
										 |  |  | 	/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */ | 
					
						
							|  |  |  | 	snprintf(depthc, sizeof(depthc), "%d", depth); | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc); | 
					
						
							|  |  |  | 	ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP); | 
					
						
							| 
									
										
										
										
											2005-09-07 20:39:20 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-05 17:20:29 +00:00
										 |  |  |   	for (x = 1; x < argc; x++) { | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  |   		/* Restore old arguments and delete ours */ | 
					
						
							|  |  |  | 		snprintf(varname, sizeof(varname), "ARG%d", x); | 
					
						
							|  |  |  |   		if (oldargs[x]) { | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 			pbx_builtin_setvar_helper(chan, varname, oldargs[x]); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 			ast_free(oldargs[x]); | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 			pbx_builtin_setvar_helper(chan, varname, NULL); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  |   	} | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	/* Restore macro variables */ | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context); | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	if (save_macro_exten) | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(save_macro_exten); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	if (save_macro_context) | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(save_macro_context); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	if (save_macro_priority) | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(save_macro_priority); | 
					
						
							| 
									
										
										
										
											2006-02-05 17:20:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	if (setmacrocontext) { | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 		chan->macrocontext[0] = '\0'; | 
					
						
							|  |  |  | 		chan->macroexten[0] = '\0'; | 
					
						
							|  |  |  | 		chan->macropriority = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	if (!strcasecmp(chan->context, fullmacro)) { | 
					
						
							| 
									
										
										
										
											2010-11-22 19:36:10 +00:00
										 |  |  | 		const char *offsets; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  |   		/* If we're leaving the macro normally, restore original information */ | 
					
						
							|  |  |  | 		chan->priority = oldpriority; | 
					
						
							| 
									
										
										
										
											2005-07-10 23:12:25 +00:00
										 |  |  | 		ast_copy_string(chan->context, oldcontext, sizeof(chan->context)); | 
					
						
							| 
									
										
										
										
											2010-11-22 19:36:10 +00:00
										 |  |  | 		ast_copy_string(chan->exten, oldexten, sizeof(chan->exten)); | 
					
						
							|  |  |  | 		if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) { | 
					
						
							|  |  |  | 			/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
 | 
					
						
							|  |  |  | 			normally if there is any problem */ | 
					
						
							|  |  |  | 			if (sscanf(offsets, "%30d", &offset) == 1) { | 
					
						
							|  |  |  | 				if (ast_exists_extension(chan, chan->context, chan->exten, | 
					
						
							|  |  |  | 					chan->priority + offset + 1, | 
					
						
							|  |  |  | 					S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { | 
					
						
							|  |  |  | 					chan->priority += offset; | 
					
						
							| 
									
										
										
										
											2003-03-12 06:00:18 +00:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset); | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	if (save_macro_offset) | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 		ast_free(save_macro_offset); | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Unlock the macro */ | 
					
						
							|  |  |  | 	if (exclusive) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro); | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 		if (ast_context_unlockmacro(fullmacro)) { | 
					
						
							|  |  |  | 			ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro); | 
					
						
							|  |  |  | 			res = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-12-17 21:18:57 +00:00
										 |  |  | 	ast_channel_unlock(chan); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	ast_free(tmp_subst); | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-01-08 18:45:13 +00:00
										 |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int macro_exec(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-08-14 03:34:16 +00:00
										 |  |  | 	return _macro_exec(chan, data, 0); | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int macroexclusive_exec(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-08-14 03:34:16 +00:00
										 |  |  | 	return _macro_exec(chan, data, 1); | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int macroif_exec(struct ast_channel *chan, const char *data)  | 
					
						
							| 
									
										
										
										
											2004-11-22 23:41:34 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *expr = NULL, *label_a = NULL, *label_b = NULL; | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-16 14:39:29 +00:00
										 |  |  | 	if (!(expr = ast_strdupa(data))) | 
					
						
							| 
									
										
										
										
											2006-01-21 17:50:04 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ((label_a = strchr(expr, '?'))) { | 
					
						
							|  |  |  | 		*label_a = '\0'; | 
					
						
							|  |  |  | 		label_a++; | 
					
						
							|  |  |  | 		if ((label_b = strchr(label_a, ':'))) { | 
					
						
							|  |  |  | 			*label_b = '\0'; | 
					
						
							|  |  |  | 			label_b++; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-05-05 14:47:22 +00:00
										 |  |  | 		if (pbx_checkcondition(expr)) | 
					
						
							| 
									
										
										
										
											2007-07-30 14:53:14 +00:00
										 |  |  | 			res = macro_exec(chan, label_a); | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 		else if (label_b)  | 
					
						
							| 
									
										
										
										
											2007-07-30 14:53:14 +00:00
										 |  |  | 			res = macro_exec(chan, label_b); | 
					
						
							| 
									
										
										
										
											2005-10-19 18:19:02 +00:00
										 |  |  | 	} else | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Invalid Syntax.\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2004-11-22 23:41:34 +00:00
										 |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int macro_exit_exec(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2005-01-07 05:42:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	return MACRO_EXIT_RESULT; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	res = ast_unregister_application(if_app); | 
					
						
							|  |  |  | 	res |= ast_unregister_application(exit_app); | 
					
						
							|  |  |  | 	res |= ast_unregister_application(app); | 
					
						
							| 
									
										
										
										
											2006-08-14 03:24:06 +00:00
										 |  |  | 	res |= ast_unregister_application(exclusive_app); | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 	int res; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 18:46:29 +00:00
										 |  |  | 	res = ast_register_application_xml(exit_app, macro_exit_exec); | 
					
						
							|  |  |  | 	res |= ast_register_application_xml(if_app, macroif_exec); | 
					
						
							|  |  |  | 	res |= ast_register_application_xml(exclusive_app, macroexclusive_exec); | 
					
						
							|  |  |  | 	res |= ast_register_application_xml(app, macro_exec); | 
					
						
							| 
									
										
										
										
											2005-10-18 22:52:21 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							| 
									
										
										
										
											2003-02-12 13:59:15 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Macros"); |