| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2005-09-14 20:46:50 +00:00
										 |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  |  * Copyright (C) 2005-2006, Digium, Inc. | 
					
						
							| 
									
										
										
										
											2005-05-05 12:48:52 +00:00
										 |  |  |  * Portions Copyright (C) 2005, Tilghman Lesher.  All rights reserved. | 
					
						
							|  |  |  |  * Portions Copyright (C) 2005, Anthony Minessale II | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											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. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +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 String manipulation dialplan functions | 
					
						
							| 
									
										
										
										
											2005-12-30 21:18:06 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \author Tilghman Lesher | 
					
						
							|  |  |  |  * \author Anothony Minessale II  | 
					
						
							| 
									
										
										
										
											2007-01-24 09:05:29 +00:00
										 |  |  |  * \ingroup functions | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-06-07 18:54:56 +00:00
										 |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ASTERISK_FILE_VERSION(__FILE__, "$Revision$") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | #include <regex.h>
 | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | #include <ctype.h>
 | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | #include "asterisk/module.h"
 | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | #include "asterisk/channel.h"
 | 
					
						
							|  |  |  | #include "asterisk/pbx.h"
 | 
					
						
							|  |  |  | #include "asterisk/utils.h"
 | 
					
						
							|  |  |  | #include "asterisk/app.h"
 | 
					
						
							| 
									
										
										
										
											2005-05-05 05:50:11 +00:00
										 |  |  | #include "asterisk/localtime.h"
 | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | #include "asterisk/test.h"
 | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | AST_THREADSTORAGE(result_buf); | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | AST_THREADSTORAGE(tmp_buf); | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | /*** DOCUMENTATION
 | 
					
						
							|  |  |  | 	<function name="FIELDQTY" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Count the fields with an arbitrary delimiter | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="delim" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							| 
									
										
										
										
											2009-05-31 17:52:28 +00:00
										 |  |  | 			<para>The delimiter may be specified as a special or extended ASCII character, by encoding it.  The characters | 
					
						
							|  |  |  | 			<literal>\n</literal>, <literal>\r</literal>, and <literal>\t</literal> are all recognized as the newline, | 
					
						
							|  |  |  | 			carriage return, and tab characters, respectively.  Also, octal and hexadecimal specifications are recognized | 
					
						
							|  |  |  | 			by the patterns <literal>\0nnn</literal> and <literal>\xHH</literal>, respectively.  For example, if you wanted | 
					
						
							|  |  |  | 			to encode a comma as the delimiter, you could use either <literal>\054</literal> or <literal>\x2C</literal>.</para> | 
					
						
							|  |  |  | 			<para>Example: If ${example} contains <literal>ex-amp-le</literal>, then ${FIELDQTY(example,-)} returns 3.</para> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2010-08-03 20:25:10 +00:00
										 |  |  | 	<function name="FIELDNUM" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Return the 1-based offset of a field in a list | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="delim" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="value" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Search the variable named <replaceable>varname</replaceable> for the string <replaceable>value</replaceable> | 
					
						
							|  |  |  | 			delimited by <replaceable>delim</replaceable> and return a 1-based offset as to its location. If not found | 
					
						
							|  |  |  | 			or an error occured, return <literal>0</literal>.</para> | 
					
						
							|  |  |  | 			<para>The delimiter may be specified as a special or extended ASCII character, by encoding it.  The characters | 
					
						
							|  |  |  | 			<literal>\n</literal>, <literal>\r</literal>, and <literal>\t</literal> are all recognized as the newline, | 
					
						
							|  |  |  | 			carriage return, and tab characters, respectively.  Also, octal and hexadecimal specifications are recognized | 
					
						
							|  |  |  | 			by the patterns <literal>\0nnn</literal> and <literal>\xHH</literal>, respectively.  For example, if you wanted | 
					
						
							|  |  |  | 			to encode a comma as the delimiter, you could use either <literal>\054</literal> or <literal>\x2C</literal>.</para> | 
					
						
							|  |  |  | 		        <para>Example: If ${example} contains <literal>ex-amp-le</literal>, then ${FIELDNUM(example,-,amp)} returns 2.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	<function name="LISTFILTER" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis>Remove an item from a list, by name.</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="delim" required="true" default="," /> | 
					
						
							|  |  |  | 			<parameter name="value" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Remove <replaceable>value</replaceable> from the list contained in the <replaceable>varname</replaceable> | 
					
						
							|  |  |  | 			variable, where the list delimiter is specified by the <replaceable>delim</replaceable> parameter.  This is | 
					
						
							|  |  |  | 			very useful for removing a single channel name from a list of channels, for example.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 	<function name="FILTER" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Filter the string to include only the allowed characters | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="allowed-chars" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Permits all characters listed in <replaceable>allowed-chars</replaceable>,  | 
					
						
							|  |  |  | 			filtering all others outs. In addition to literally listing the characters,  | 
					
						
							|  |  |  | 			you may also use ranges of characters (delimited by a <literal>-</literal></para> | 
					
						
							|  |  |  | 			<para>Hexadecimal characters started with a <literal>\x</literal>(i.e. \x20)</para> | 
					
						
							|  |  |  | 			<para>Octal characters started with a <literal>\0</literal> (i.e. \040)</para> | 
					
						
							|  |  |  | 			<para>Also <literal>\t</literal>,<literal>\n</literal> and <literal>\r</literal> are recognized.</para>  | 
					
						
							|  |  |  | 			<note><para>If you want the <literal>-</literal> character it needs to be prefixed with a  | 
					
						
							|  |  |  | 			<literal>\</literal></para></note> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	<function name="REPLACE" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Replace a set of characters in a given string with another character. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="find-chars" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="replace-char" required="false" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Iterates through a string replacing all the <replaceable>find-chars</replaceable> with | 
					
						
							|  |  |  | 			<replaceable>replace-char</replaceable>.  <replaceable>replace-char</replaceable> may be either | 
					
						
							|  |  |  | 			empty or contain one character.  If empty, all <replaceable>find-chars</replaceable> will be | 
					
						
							|  |  |  | 			deleted from the output.</para> | 
					
						
							|  |  |  | 			<note><para>The replacement only occurs in the output.  The original variable is not | 
					
						
							|  |  |  | 			altered.</para></note> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="PASSTHRU" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Pass the given argument back as a value. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="string" required="false" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Literally returns the given <replaceable>string</replaceable>.  The intent is to permit | 
					
						
							|  |  |  | 			other dialplan functions which take a variable name as an argument to be able to take a literal | 
					
						
							|  |  |  | 			string, instead.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 	<function name="REGEX" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Check string against a regular expression. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax argsep=" "> | 
					
						
							|  |  |  | 			<parameter name=""regular expression"" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Return <literal>1</literal> on regular expression match or <literal>0</literal> otherwise</para> | 
					
						
							|  |  |  | 			<para>Please note that the space following the double quotes separating the  | 
					
						
							|  |  |  | 			regex from the data is optional and if present, is skipped. If a space is  | 
					
						
							|  |  |  | 			desired at the beginning of the data, then put two spaces there; the second  | 
					
						
							|  |  |  | 			will not be skipped.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<application name="ClearHash" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Clear the keys from a specified hashname. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="hashname" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Clears all keys out of the specified <replaceable>hashname</replaceable>.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</application> | 
					
						
							|  |  |  | 	<function name="HASH" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Implementation of a dialplan associative array | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="hashname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="hashkey" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>In two arguments mode, gets and sets values to corresponding keys within | 
					
						
							|  |  |  | 			a named associative array. The single-argument mode will only work when assigned | 
					
						
							|  |  |  | 			to from a function defined by func_odbc</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="HASHKEYS" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Retrieve the keys of the HASH() function. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="hashname" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Returns a comma-delimited list of the current keys of the associative array  | 
					
						
							|  |  |  | 			defined by the HASH() function. Note that if you iterate over the keys of  | 
					
						
							|  |  |  | 			the result, adding keys during iteration will cause the result of the HASHKEYS() | 
					
						
							|  |  |  | 			function to change.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="KEYPADHASH" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Hash the letters in string into equivalent keypad numbers. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: ${KEYPADHASH(Les)} returns "537"</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="ARRAY" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Allows setting multiple variables at once. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="var1" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="var2" required="false" multiple="true" /> | 
					
						
							|  |  |  | 			<parameter name="varN" required="false" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>The comma-delimited list passed as a value to which the function is set will  | 
					
						
							|  |  |  | 			be interpreted as a set of values to which the comma-delimited list of  | 
					
						
							| 
									
										
										
										
											2008-11-02 02:50:33 +00:00
										 |  |  | 			variable names in the argument should be set.</para> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 			<para>Example: Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="STRPTIME" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Returns the epoch of the arbitrary date/time string structured as described by the format. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="datetime" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="timezone" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="format" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>This is useful for converting a date into <literal>EPOCH</literal> time,  | 
					
						
							|  |  |  | 			possibly to pass to an application like SayUnixTime or to calculate the difference | 
					
						
							|  |  |  | 			between the two date strings</para> | 
					
						
							|  |  |  | 			<para>Example: ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="STRFTIME" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Returns the current date/time in the specified format. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="epoch" /> | 
					
						
							|  |  |  | 			<parameter name="timezone" /> | 
					
						
							|  |  |  | 			<parameter name="format" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>STRFTIME supports all of the same formats as the underlying C function | 
					
						
							|  |  |  | 			<emphasis>strftime(3)</emphasis>. | 
					
						
							|  |  |  | 			It also supports the following format: <literal>%[n]q</literal> - fractions of a second, | 
					
						
							|  |  |  | 			with leading zeros.</para> | 
					
						
							|  |  |  | 			<para>Example: <literal>%3q</literal> will give milliseconds and <literal>%1q</literal> | 
					
						
							|  |  |  | 			will give tenths of a second. The default is set at milliseconds (n=3). | 
					
						
							|  |  |  | 			The common case is to use it in combination with %S, as in <literal>%S.%3q</literal>.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 		<see-also> | 
					
						
							|  |  |  | 			<ref type="manpage">strftime(3)</ref> | 
					
						
							|  |  |  | 		</see-also> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="EVAL" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Evaluate stored variables | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="variable" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Using EVAL basically causes a string to be evaluated twice. | 
					
						
							|  |  |  | 			When a variable or expression is in the dialplan, it will be | 
					
						
							|  |  |  | 			evaluated at runtime. However, if the results of the evaluation | 
					
						
							|  |  |  | 			is in fact another variable or expression, using EVAL will have it | 
					
						
							|  |  |  | 			evaluated a second time.</para> | 
					
						
							|  |  |  | 			<para>Example: If the <variable>MYVAR</variable> contains | 
					
						
							|  |  |  | 			<variable>OTHERVAR</variable>, then the result of ${EVAL( | 
					
						
							|  |  |  | 			<variable>MYVAR</variable>)} in the dialplan will be the | 
					
						
							|  |  |  | 			contents of <variable>OTHERVAR</variable>. Normally just | 
					
						
							|  |  |  | 			putting <variable>MYVAR</variable> in the dialplan the result | 
					
						
							|  |  |  | 			would be <variable>OTHERVAR</variable>.</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="TOUPPER" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Convert string to all uppercase letters. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: ${TOUPPER(Example)} returns "EXAMPLE"</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="TOLOWER" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Convert string to all lowercase letters. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: ${TOLOWER(Example)} returns "example"</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="LEN" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Return the length of the string given. | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: ${LEN(example)} returns 7</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="QUOTE" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Quotes a given string, escaping embedded quotes as necessary | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: ${QUOTE(ab"c"de)} will return "abcde"</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | 	<function name="CSV_QUOTE" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Quotes a given string for use in a CSV file, escaping embedded quotes as necessary | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="string" required="true" /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: ${CSV_QUOTE("a,b" 123)} will return """a,b"" 123"</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	<function name="SHIFT" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Removes and returns the first item off of a variable containing delimited text | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="delimiter" required="false" default="," /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example:</para> | 
					
						
							|  |  |  | 			<para>exten => s,1,Set(array=one,two,three)</para> | 
					
						
							| 
									
										
										
										
											2009-04-23 00:44:18 +00:00
										 |  |  | 			<para>exten => s,n,While($["${SET(var=${SHIFT(array)})}" != ""])</para> | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 			<para>exten => s,n,NoOp(var is ${var})</para> | 
					
						
							|  |  |  | 			<para>exten => s,n,EndWhile</para> | 
					
						
							|  |  |  | 			<para>This would iterate over each value in array, left to right, and | 
					
						
							|  |  |  | 				would result in NoOp(var is one), NoOp(var is two), and | 
					
						
							|  |  |  | 				NoOp(var is three) being executed. | 
					
						
							|  |  |  | 			</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function>	 | 
					
						
							|  |  |  | 	<function name="POP" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Removes and returns the last item off of a variable containing delimited text | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="delimiter" required="false" default="," /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example:</para> | 
					
						
							|  |  |  | 			<para>exten => s,1,Set(array=one,two,three)</para> | 
					
						
							| 
									
										
										
										
											2009-04-23 00:44:18 +00:00
										 |  |  | 			<para>exten => s,n,While($["${SET(var=${POP(array)})}" != ""])</para> | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 			<para>exten => s,n,NoOp(var is ${var})</para> | 
					
						
							|  |  |  | 			<para>exten => s,n,EndWhile</para> | 
					
						
							|  |  |  | 			<para>This would iterate over each value in array, right to left, and | 
					
						
							|  |  |  | 				would result in NoOp(var is three), NoOp(var is two), and | 
					
						
							|  |  |  | 				NoOp(var is one) being executed. | 
					
						
							|  |  |  | 			</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function>	 | 
					
						
							|  |  |  | 	<function name="PUSH" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Appends one or more values to the end of a variable containing delimited text | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="delimiter" required="false" default="," /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: Set(PUSH(array)=one,two,three) would append one, | 
					
						
							|  |  |  | 				two, and three to the end of the values stored in the variable | 
					
						
							|  |  |  | 				"array". | 
					
						
							|  |  |  | 			</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							|  |  |  | 	<function name="UNSHIFT" language="en_US"> | 
					
						
							|  |  |  | 		<synopsis> | 
					
						
							|  |  |  | 			Inserts one or more values to the beginning of a variable containing delimited text | 
					
						
							|  |  |  | 		</synopsis> | 
					
						
							|  |  |  | 		<syntax> | 
					
						
							|  |  |  | 			<parameter name="varname" required="true" /> | 
					
						
							|  |  |  | 			<parameter name="delimiter" required="false" default="," /> | 
					
						
							|  |  |  | 		</syntax> | 
					
						
							|  |  |  | 		<description> | 
					
						
							|  |  |  | 			<para>Example: Set(UNSHIFT(array)=one,two,three) would insert one, | 
					
						
							|  |  |  | 				two, and three before the values stored in the variable | 
					
						
							|  |  |  | 				"array". | 
					
						
							|  |  |  | 			</para> | 
					
						
							|  |  |  | 		</description> | 
					
						
							|  |  |  | 	</function> | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  |  ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd, | 
					
						
							|  |  |  | 			     char *parse, char *buf, struct ast_str **sbuf, ssize_t len) | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	char *varsubst; | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	struct ast_str *str = ast_str_thread_get(&result_buf, 16); | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 	int fieldcount = 0; | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			     AST_APP_ARG(varname); | 
					
						
							|  |  |  | 			     AST_APP_ARG(delim); | 
					
						
							|  |  |  | 		); | 
					
						
							| 
									
										
										
										
											2007-10-26 00:11:31 +00:00
										 |  |  | 	char delim[2] = ""; | 
					
						
							|  |  |  | 	size_t delim_used; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	if (!str) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, parse); | 
					
						
							|  |  |  | 	if (args.delim) { | 
					
						
							| 
									
										
										
										
											2007-10-26 00:11:31 +00:00
										 |  |  | 		ast_get_encoded_char(args.delim, delim, &delim_used); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-01 21:27:22 +00:00
										 |  |  | 		varsubst = alloca(strlen(args.varname) + 4); | 
					
						
							| 
									
										
										
										
											2007-02-01 20:12:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-01 21:27:22 +00:00
										 |  |  | 		sprintf(varsubst, "${%s}", args.varname); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 		ast_str_substitute_variables(&str, 0, chan, varsubst); | 
					
						
							|  |  |  | 		if (ast_str_strlen(str) == 0) { | 
					
						
							| 
									
										
										
										
											2007-05-29 21:59:21 +00:00
										 |  |  | 			fieldcount = 0; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			char *varval = ast_str_buffer(str); | 
					
						
							|  |  |  | 			while (strsep(&varval, delim)) { | 
					
						
							| 
									
										
										
										
											2007-05-29 21:59:21 +00:00
										 |  |  | 				fieldcount++; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2007-05-29 21:59:21 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 		fieldcount = 1; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	if (sbuf) { | 
					
						
							|  |  |  | 		ast_str_set(sbuf, len, "%d", fieldcount); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		snprintf(buf, len, "%d", fieldcount); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int function_fieldqty(struct ast_channel *chan, const char *cmd, | 
					
						
							|  |  |  | 			     char *parse, char *buf, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int function_fieldqty_str(struct ast_channel *chan, const char *cmd, | 
					
						
							|  |  |  | 				 char *parse, struct ast_str **buf, ssize_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function fieldqty_function = { | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 	.name = "FIELDQTY", | 
					
						
							|  |  |  | 	.read = function_fieldqty, | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	.read2 = function_fieldqty_str, | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-03 20:25:10 +00:00
										 |  |  | static int function_fieldnum_helper(struct ast_channel *chan, const char *cmd, | 
					
						
							|  |  |  | 				char *parse, char *buf, struct ast_str **sbuf, ssize_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *varsubst, *field; | 
					
						
							|  |  |  | 	struct ast_str *str = ast_str_thread_get(&result_buf, 16); | 
					
						
							|  |  |  | 	int fieldindex = 0, res = 0; | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(varname); | 
					
						
							|  |  |  | 		AST_APP_ARG(delim); | 
					
						
							|  |  |  | 		AST_APP_ARG(field); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 	char delim[2] = ""; | 
					
						
							|  |  |  | 	size_t delim_used; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!str) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(args, parse); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (args.argc < 3) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Usage: FIELDNUM(<listname>,<delimiter>,<fieldvalue>)\n"); | 
					
						
							|  |  |  | 		res = -1; | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		varsubst = alloca(strlen(args.varname) + 4); | 
					
						
							|  |  |  | 		sprintf(varsubst, "${%s}", args.varname); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ast_str_substitute_variables(&str, 0, chan, varsubst); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ast_str_strlen(str) == 0 || ast_strlen_zero(args.delim)) { | 
					
						
							|  |  |  | 			fieldindex = 0; | 
					
						
							|  |  |  | 		} else if (ast_get_encoded_char(args.delim, delim, &delim_used) == -1) { | 
					
						
							|  |  |  | 			res = -1; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			char *varval = ast_str_buffer(str); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			while ((field = strsep(&varval, delim)) != NULL) { | 
					
						
							|  |  |  | 				fieldindex++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (!strcasecmp(field, args.field)) { | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if (!field) { | 
					
						
							|  |  |  | 				fieldindex = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			res = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (sbuf) { | 
					
						
							|  |  |  | 		ast_str_set(sbuf, len, "%d", fieldindex); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		snprintf(buf, len, "%d", fieldindex); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int function_fieldnum(struct ast_channel *chan, const char *cmd, | 
					
						
							|  |  |  | 			     char *parse, char *buf, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return function_fieldnum_helper(chan, cmd, parse, buf, NULL, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int function_fieldnum_str(struct ast_channel *chan, const char *cmd, | 
					
						
							|  |  |  | 				 char *parse, struct ast_str **buf, ssize_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return function_fieldnum_helper(chan, cmd, parse, NULL, buf, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function fieldnum_function = { | 
					
						
							|  |  |  | 	.name = "FIELDNUM", | 
					
						
							|  |  |  | 	.read = function_fieldnum, | 
					
						
							|  |  |  | 	.read2 = function_fieldnum_str, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len) | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(listname); | 
					
						
							|  |  |  | 		AST_APP_ARG(delimiter); | 
					
						
							|  |  |  | 		AST_APP_ARG(fieldvalue); | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	const char *ptr; | 
					
						
							|  |  |  | 	struct ast_str *orig_list = ast_str_thread_get(&tmp_buf, 16); | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	const char *begin, *cur, *next; | 
					
						
							| 
									
										
										
										
											2008-12-13 08:36:35 +00:00
										 |  |  | 	int dlen, flen, first = 1; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	struct ast_str *result, **result_ptr = &result; | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	char *delim, *varsubst; | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(args, parse); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	if (buf) { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 		if (!(result = ast_str_thread_get(&result_buf, 16))) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		/* Place the result directly into the output buffer */ | 
					
						
							|  |  |  | 		result_ptr = bufstr; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	if (args.argc < 3) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	varsubst = alloca(strlen(args.listname) + 4); | 
					
						
							|  |  |  | 	sprintf(varsubst, "${%s}", args.listname); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	/* If we don't lock the channel, the variable could disappear out from underneath us. */ | 
					
						
							|  |  |  | 	if (chan) { | 
					
						
							|  |  |  | 		ast_channel_lock(chan); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	ast_str_substitute_variables(&orig_list, 0, chan, varsubst); | 
					
						
							| 
									
										
										
										
											2010-03-10 20:30:34 +00:00
										 |  |  | 	if (!ast_str_strlen(orig_list)) { | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname); | 
					
						
							|  |  |  | 		if (chan) { | 
					
						
							|  |  |  | 			ast_channel_unlock(chan); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* If the string isn't there, just copy out the string and be done with it. */ | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (!(ptr = strstr(ast_str_buffer(orig_list), args.fieldvalue))) { | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 		if (buf) { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 			ast_copy_string(buf, ast_str_buffer(orig_list), len); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 			ast_str_set(result_ptr, len, "%s", ast_str_buffer(orig_list)); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 		if (chan) { | 
					
						
							|  |  |  | 			ast_channel_unlock(chan); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dlen = strlen(args.delimiter); | 
					
						
							|  |  |  | 	delim = alloca(dlen + 1); | 
					
						
							|  |  |  | 	ast_get_encoded_str(args.delimiter, delim, dlen + 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((dlen = strlen(delim)) == 0) { | 
					
						
							|  |  |  | 		delim = ","; | 
					
						
							|  |  |  | 		dlen = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	flen = strlen(args.fieldvalue); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-20 16:50:38 +00:00
										 |  |  | 	ast_str_reset(*result_ptr); | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	/* Enough space for any result */ | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	if (len > -1) { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 		ast_str_make_space(result_ptr, len ? len : ast_str_strlen(orig_list) + 1); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	begin = ast_str_buffer(orig_list); | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	next = strstr(begin, delim); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		/* Find next boundary */ | 
					
						
							|  |  |  | 		if (next) { | 
					
						
							|  |  |  | 			cur = next; | 
					
						
							|  |  |  | 			next = strstr(cur + dlen, delim); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			cur = strchr(begin + dlen, '\0'); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) { | 
					
						
							|  |  |  | 			/* Skip field */ | 
					
						
							|  |  |  | 			begin += flen + dlen; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			/* Copy field to output */ | 
					
						
							| 
									
										
										
										
											2008-12-13 08:36:35 +00:00
										 |  |  | 			if (!first) { | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 				ast_str_append(result_ptr, len, "%s", delim); | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-10 20:54:03 +00:00
										 |  |  | 			ast_str_append_substr(result_ptr, len, begin, cur - begin); | 
					
						
							| 
									
										
										
										
											2008-12-13 08:36:35 +00:00
										 |  |  | 			first = 0; | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 			begin = cur + dlen; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} while (*cur != '\0'); | 
					
						
							|  |  |  | 	if (chan) { | 
					
						
							|  |  |  | 		ast_channel_unlock(chan); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	if (buf) { | 
					
						
							|  |  |  | 		ast_copy_string(buf, ast_str_buffer(result), len); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return listfilter(chan, cmd, parse, buf, NULL, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return listfilter(chan, cmd, parse, NULL, buf, len); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | static struct ast_custom_function listfilter_function = { | 
					
						
							|  |  |  | 	.name = "LISTFILTER", | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	.read = listfilter_read, | 
					
						
							|  |  |  | 	.read2 = listfilter_read2, | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		  size_t len) | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			     AST_APP_ARG(allowed); | 
					
						
							|  |  |  | 			     AST_APP_ARG(string); | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2010-02-10 21:19:35 +00:00
										 |  |  | 	char *outbuf = buf; | 
					
						
							|  |  |  | 	unsigned char ac; | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 	char allowed[256] = ""; | 
					
						
							|  |  |  | 	size_t allowedlen = 0; | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 	int32_t bitfield[8] = { 0, }; /* 256 bits */ | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 	AST_STANDARD_RAW_ARGS(args, parse); | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 	if (!args.string) { | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n"); | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-10 15:36:57 +00:00
										 |  |  | 	if (args.allowed[0] == '"' && !ast_opt_dont_warn) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "FILTER allowed characters includes the quote (\") character.  This may not be what you want.\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 	/* Expand ranges */ | 
					
						
							| 
									
										
										
										
											2010-02-10 21:19:35 +00:00
										 |  |  | 	for (; *(args.allowed);) { | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 		char c1 = 0, c2 = 0; | 
					
						
							|  |  |  | 		size_t consumed = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-26 00:11:31 +00:00
										 |  |  | 		if (ast_get_encoded_char(args.allowed, &c1, &consumed)) | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 			return -1; | 
					
						
							|  |  |  | 		args.allowed += consumed; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (*(args.allowed) == '-') { | 
					
						
							| 
									
										
										
										
											2007-10-26 00:11:31 +00:00
										 |  |  | 			if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed)) | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 				c2 = -1; | 
					
						
							|  |  |  | 			args.allowed += consumed + 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-10 15:36:57 +00:00
										 |  |  | 			if ((c2 < c1 || c2 == -1) && !ast_opt_dont_warn) { | 
					
						
							|  |  |  | 				ast_log(LOG_WARNING, "Range wrapping in FILTER(%s,%s).  This may not be what you want.\n", parse, args.string); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 			/*!\note
 | 
					
						
							|  |  |  | 			 * Looks a little strange, until you realize that we can overflow | 
					
						
							|  |  |  | 			 * the size of a char. | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 			for (ac = c1; ac != c2; ac++) { | 
					
						
							|  |  |  | 				bitfield[ac / 32] |= 1 << (ac % 32); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2010-02-10 21:19:35 +00:00
										 |  |  | 			bitfield[ac / 32] |= 1 << (ac % 32); | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			ast_debug(4, "c1=%d, c2=%d\n", c1, c2); | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2010-02-10 21:19:35 +00:00
										 |  |  | 			ac = (unsigned char) c1; | 
					
						
							| 
									
										
										
										
											2010-02-10 21:24:10 +00:00
										 |  |  | 			ast_debug(4, "c1=%d, consumed=%d, args.allowed=%s\n", c1, (int) consumed, args.allowed - consumed); | 
					
						
							| 
									
										
										
										
											2010-02-10 21:19:35 +00:00
										 |  |  | 			bitfield[ac / 32] |= 1 << (ac % 32); | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (ac = 1; ac != 0; ac++) { | 
					
						
							|  |  |  | 		if (bitfield[ac / 32] & (1 << (ac % 32))) { | 
					
						
							|  |  |  | 			allowed[allowedlen++] = ac; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(1, "Allowed: %s\n", allowed); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 	for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) { | 
					
						
							| 
									
										
										
										
											2007-10-12 17:32:38 +00:00
										 |  |  | 		if (strchr(allowed, *(args.string))) | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			*outbuf++ = *(args.string); | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	*outbuf = '\0'; | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function filter_function = { | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | 	.name = "FILTER", | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	.read = filter, | 
					
						
							| 
									
										
										
										
											2005-12-23 21:03:25 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(varname); | 
					
						
							|  |  |  | 		AST_APP_ARG(find); | 
					
						
							|  |  |  | 		AST_APP_ARG(replace); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 	char *strptr, *varsubst; | 
					
						
							|  |  |  | 	struct ast_str *str = ast_str_thread_get(&result_buf, 16); | 
					
						
							|  |  |  | 	char find[256]; /* Only 256 characters possible */ | 
					
						
							|  |  |  | 	char replace[2] = ""; | 
					
						
							|  |  |  | 	size_t unused; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(args, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!str) { | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (args.argc < 2) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Usage: %s(<varname>,<search-chars>[,<replace-char>])\n", cmd); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Decode escapes */ | 
					
						
							|  |  |  | 	ast_get_encoded_str(args.find, find, sizeof(find)); | 
					
						
							|  |  |  | 	ast_get_encoded_char(args.replace, replace, &unused); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(find) || ast_strlen_zero(args.varname)) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "The characters to search for and the variable name must not be empty.\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	varsubst = alloca(strlen(args.varname) + 4); | 
					
						
							|  |  |  | 	sprintf(varsubst, "${%s}", args.varname); | 
					
						
							|  |  |  | 	ast_str_substitute_variables(&str, 0, chan, varsubst); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!ast_str_strlen(str)) { | 
					
						
							|  |  |  | 		/* Blank, nothing to replace */ | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_debug(3, "String to search: (%s)\n", ast_str_buffer(str)); | 
					
						
							|  |  |  | 	ast_debug(3, "Characters to find: (%s)\n", find); | 
					
						
							|  |  |  | 	ast_debug(3, "Character to replace with: (%s)\n", replace); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (strptr = ast_str_buffer(str); *strptr; strptr++) { | 
					
						
							|  |  |  | 		/* buf is already a mutable buffer, so we construct the result
 | 
					
						
							|  |  |  | 		 * directly there */ | 
					
						
							|  |  |  | 		if (strchr(find, *strptr)) { | 
					
						
							|  |  |  | 			if (ast_strlen_zero(replace)) { | 
					
						
							|  |  |  | 				/* Remove character */ | 
					
						
							|  |  |  | 				strcpy(strptr, strptr + 1); /* SAFE */ | 
					
						
							|  |  |  | 				strptr--; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				/* Replace character */ | 
					
						
							|  |  |  | 				*strptr = *replace; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_str_set(buf, len, "%s", ast_str_buffer(str)); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function replace_function = { | 
					
						
							|  |  |  | 	.name = "REPLACE", | 
					
						
							|  |  |  | 	.read2 = replace, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		 size_t len) | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			     AST_APP_ARG(null); | 
					
						
							|  |  |  | 			     AST_APP_ARG(reg); | 
					
						
							|  |  |  | 			     AST_APP_ARG(str); | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 	int errcode; | 
					
						
							|  |  |  | 	regex_t regexbuf; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-31 04:19:54 +00:00
										 |  |  | 	buf[0] = '\0'; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	AST_NONSTANDARD_APP_ARGS(args, parse, '"'); | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-07-03 06:32:35 +00:00
										 |  |  | 	if (args.argc != 3) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
											  
											
												As per discussion on bug 7862, the problem wasn't the fact that the documentation differed from behavior, but rather that users are used to REGEX having that space after the double quote in 1.2.x. So, in keeping with history, I investigated a little deeper, and discovered that the change in behavior was due to the modification of the function to use the AST_DECLARE_APP_ARGS and AST_NONSTANDARD_APP_ARGS() to parse the args. The code to skip the blank was left out. So, what I did was add code to throw out the first blank (space or tab) after the double quote, IF IT IS THERE. If not, nothing is done.Verbage is added to the function description saying that the space is optional, and skipped if it is there. If a space is desired, then the documentation advises putting two spaces there. This should make it compatible for 1.2 users, and not mess up new users who are used to using it with no space. It WILL mess up new users who WANT a space. Hopefully, they will double check the doc strings for this func and add the extra space. Hopefully, this class of new user is very small.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@42423 65c4cc65-6c06-0410-ace0-fbb531ad65f3
											
										 
											2006-09-08 16:44:38 +00:00
										 |  |  | 	if ((*args.str == ' ') || (*args.str == '\t')) | 
					
						
							|  |  |  | 		args.str++; | 
					
						
							| 
									
										
										
										
											2006-07-03 06:32:35 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 	ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str); | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if ((errcode = regcomp(®exbuf, args.reg, REG_EXTENDED | REG_NOSUB))) { | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		regerror(errcode, ®exbuf, buf, len); | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-10-12 01:09:04 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-08-31 04:07:35 +00:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	strcpy(buf, regexec(®exbuf, args.str, 0, NULL, 0) ? "0" : "1"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-12 01:09:04 +00:00
										 |  |  | 	regfree(®exbuf); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function regex_function = { | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 	.name = "REGEX", | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	.read = regex, | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | #define HASH_PREFIX	"~HASH~%s~"
 | 
					
						
							|  |  |  | #define HASH_FORMAT	HASH_PREFIX "%s~"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static char *app_clearhash = "ClearHash"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */ | 
					
						
							|  |  |  | static void clearvar_prefix(struct ast_channel *chan, const char *prefix) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_var_t *var; | 
					
						
							|  |  |  | 	int len = strlen(prefix); | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) { | 
					
						
							|  |  |  | 		if (strncasecmp(prefix, ast_var_name(var), len) == 0) { | 
					
						
							| 
									
										
										
										
											2007-11-08 05:28:47 +00:00
										 |  |  | 			AST_LIST_REMOVE_CURRENT(entries); | 
					
						
							| 
									
										
										
										
											2007-06-06 21:20:11 +00:00
										 |  |  | 			ast_free(var); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_END | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-21 21:13:09 +00:00
										 |  |  | static int exec_clearhash(struct ast_channel *chan, const char *data) | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char prefix[80]; | 
					
						
							|  |  |  | 	snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null"); | 
					
						
							|  |  |  | 	clearvar_prefix(chan, prefix); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int array(struct ast_channel *chan, const char *cmd, char *var, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		 const char *value) | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-01-16 17:31:30 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(arg1, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			     AST_APP_ARG(var)[100]; | 
					
						
							| 
									
										
										
										
											2006-01-16 17:31:30 +00:00
										 |  |  | 	); | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(arg2, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			     AST_APP_ARG(val)[100]; | 
					
						
							| 
									
										
										
										
											2006-01-16 17:31:30 +00:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 	char *origvar = "", *value2, varname[256]; | 
					
						
							|  |  |  | 	int i, ishash = 0; | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	value2 = ast_strdupa(value); | 
					
						
							| 
									
										
										
										
											2006-01-21 20:57:06 +00:00
										 |  |  | 	if (!var || !value2) | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 	if (!strcmp(cmd, "HASH")) { | 
					
						
							|  |  |  | 		const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~"); | 
					
						
							|  |  |  | 		origvar = var; | 
					
						
							|  |  |  | 		if (var2) | 
					
						
							|  |  |  | 			var = ast_strdupa(var2); | 
					
						
							| 
									
										
										
										
											2007-10-28 14:11:01 +00:00
										 |  |  | 		else { | 
					
						
							|  |  |  | 			if (chan) | 
					
						
							|  |  |  | 				ast_autoservice_stop(chan); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 			return -1; | 
					
						
							| 
									
										
										
										
											2007-10-28 14:11:01 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 		ishash = 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 	/* The functions this will generally be used with are SORT and ODBC_*, which
 | 
					
						
							|  |  |  | 	 * both return comma-delimited lists.  However, if somebody uses literal lists, | 
					
						
							|  |  |  | 	 * their commas will be translated to vertical bars by the load, and I don't | 
					
						
							|  |  |  | 	 * want them to be surprised by the result.  Hence, we prefer commas as the | 
					
						
							|  |  |  | 	 * delimiter, but we'll fall back to vertical bars if commas aren't found. | 
					
						
							|  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2010-09-24 13:54:17 +00:00
										 |  |  | 	ast_debug(1, "array (%s=%s)\n", var, S_OR(value2, "")); | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(arg1, var); | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(arg2, value2); | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-16 17:31:30 +00:00
										 |  |  | 	for (i = 0; i < arg1.argc; i++) { | 
					
						
							| 
									
										
										
										
											2007-06-14 19:39:12 +00:00
										 |  |  | 		ast_debug(1, "array set value (%s=%s)\n", arg1.var[i], | 
					
						
							| 
									
										
										
										
											2010-09-24 13:54:17 +00:00
										 |  |  | 				S_OR(arg2.val[i], "")); | 
					
						
							| 
									
										
										
										
											2006-01-16 17:31:30 +00:00
										 |  |  | 		if (i < arg2.argc) { | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 			if (ishash) { | 
					
						
							| 
									
										
										
										
											2010-01-18 19:26:07 +00:00
										 |  |  | 				if (origvar[0] == '_') { | 
					
						
							|  |  |  | 					if (origvar[1] == '_') { | 
					
						
							|  |  |  | 						snprintf(varname, sizeof(varname), "__" HASH_FORMAT, origvar + 2, arg1.var[i]); | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						snprintf(varname, sizeof(varname), "_" HASH_FORMAT, origvar + 1, arg1.var[i]); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 				pbx_builtin_setvar_helper(chan, varname, arg2.val[i]); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			/* We could unset the variable, by passing a NULL, but due to
 | 
					
						
							|  |  |  | 			 * pushvar semantics, that could create some undesired behavior. */ | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 			if (ishash) { | 
					
						
							|  |  |  | 				snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]); | 
					
						
							|  |  |  | 				pbx_builtin_setvar_helper(chan, varname, ""); | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				pbx_builtin_setvar_helper(chan, arg1.var[i], ""); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct ast_var_t *newvar; | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	struct ast_str *prefix = ast_str_alloca(80); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	ast_str_set(&prefix, -1, HASH_PREFIX, data); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 	memset(buf, 0, len); | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 	AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) { | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 		if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) { | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 			/* Copy everything after the prefix */ | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 			strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 			/* Trim the trailing ~ */ | 
					
						
							|  |  |  | 			buf[strlen(buf) - 1] = ','; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* Trim the trailing comma */ | 
					
						
							|  |  |  | 	buf[strlen(buf) - 1] = '\0'; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct ast_var_t *newvar; | 
					
						
							|  |  |  | 	struct ast_str *prefix = ast_str_alloca(80); | 
					
						
							|  |  |  | 	char *tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_str_set(&prefix, -1, HASH_PREFIX, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) { | 
					
						
							|  |  |  | 		if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) { | 
					
						
							|  |  |  | 			/* Copy everything after the prefix */ | 
					
						
							|  |  |  | 			ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix)); | 
					
						
							|  |  |  | 			/* Trim the trailing ~ */ | 
					
						
							|  |  |  | 			tmp = ast_str_buffer(*buf); | 
					
						
							|  |  |  | 			tmp[ast_str_strlen(*buf) - 1] = ','; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	/* Trim the trailing comma */ | 
					
						
							|  |  |  | 	tmp = ast_str_buffer(*buf); | 
					
						
							|  |  |  | 	tmp[ast_str_strlen(*buf) - 1] = '\0'; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value) | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char varname[256]; | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(arg, | 
					
						
							|  |  |  | 		AST_APP_ARG(hashname); | 
					
						
							|  |  |  | 		AST_APP_ARG(hashkey); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 	if (!strchr(var, ',')) { | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 		/* Single argument version */ | 
					
						
							|  |  |  | 		return array(chan, "HASH", var, value); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(arg, var); | 
					
						
							| 
									
										
										
										
											2010-01-18 19:26:07 +00:00
										 |  |  | 	if (arg.hashname[0] == '_') { | 
					
						
							|  |  |  | 		if (arg.hashname[1] == '_') { | 
					
						
							|  |  |  | 			snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 	pbx_builtin_setvar_helper(chan, varname, value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char varname[256]; | 
					
						
							|  |  |  | 	const char *varvalue; | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(arg, | 
					
						
							|  |  |  | 		AST_APP_ARG(hashname); | 
					
						
							|  |  |  | 		AST_APP_ARG(hashkey); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(arg, data); | 
					
						
							|  |  |  | 	if (arg.argc == 2) { | 
					
						
							|  |  |  | 		snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey); | 
					
						
							|  |  |  | 		varvalue = pbx_builtin_getvar_helper(chan, varname); | 
					
						
							|  |  |  | 		if (varvalue) | 
					
						
							|  |  |  | 			ast_copy_string(buf, varvalue, len); | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			*buf = '\0'; | 
					
						
							|  |  |  | 	} else if (arg.argc == 1) { | 
					
						
							|  |  |  | 		char colnames[4096]; | 
					
						
							|  |  |  | 		int i; | 
					
						
							|  |  |  | 		AST_DECLARE_APP_ARGS(arg2, | 
					
						
							|  |  |  | 			AST_APP_ARG(col)[100]; | 
					
						
							|  |  |  | 		); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Get column names, in no particular order */ | 
					
						
							|  |  |  | 		hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames)); | 
					
						
							|  |  |  | 		pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-02 21:08:33 +00:00
										 |  |  | 		AST_STANDARD_APP_ARGS(arg2, colnames); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 		*buf = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Now get the corresponding column values, in exactly the same order */ | 
					
						
							|  |  |  | 		for (i = 0; i < arg2.argc; i++) { | 
					
						
							|  |  |  | 			snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]); | 
					
						
							|  |  |  | 			varvalue = pbx_builtin_getvar_helper(chan, varname); | 
					
						
							| 
									
										
										
										
											2008-03-07 06:54:47 +00:00
										 |  |  | 			strncat(buf, varvalue, len - strlen(buf) - 1); | 
					
						
							|  |  |  | 			strncat(buf, ",", len - strlen(buf) - 1); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* Strip trailing comma */ | 
					
						
							|  |  |  | 		buf[strlen(buf) - 1] = '\0'; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function hash_function = { | 
					
						
							|  |  |  | 	.name = "HASH", | 
					
						
							|  |  |  | 	.write = hash_write, | 
					
						
							|  |  |  | 	.read = hash_read, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function hashkeys_function = { | 
					
						
							|  |  |  | 	.name = "HASHKEYS", | 
					
						
							|  |  |  | 	.read = hashkeys_read, | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	.read2 = hashkeys_read2, | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function array_function = { | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | 	.name = "ARRAY", | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	.write = array, | 
					
						
							| 
									
										
										
										
											2005-12-27 06:50:25 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *bufptr = buf, *dataptr = data; | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (len < 3){ /* at least two for quotes and one for binary zero */ | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, "Not enough buffer"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-21 22:45:32 +00:00
										 |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "No argument specified!\n"); | 
					
						
							|  |  |  | 		ast_copy_string(buf, "\"\"", len); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | 	*bufptr++ = '"'; | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | 	for (; bufptr < buf + len - 3; dataptr++) { | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | 		if (*dataptr == '\\') { | 
					
						
							|  |  |  | 			*bufptr++ = '\\'; | 
					
						
							|  |  |  | 			*bufptr++ = '\\'; | 
					
						
							|  |  |  | 		} else if (*dataptr == '"') { | 
					
						
							|  |  |  | 			*bufptr++ = '\\'; | 
					
						
							|  |  |  | 			*bufptr++ = '"'; | 
					
						
							|  |  |  | 		} else if (*dataptr == '\0') { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			*bufptr++ = *dataptr; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	*bufptr++ = '"'; | 
					
						
							|  |  |  | 	*bufptr = '\0'; | 
					
						
							| 
									
										
										
										
											2006-02-23 23:36:53 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function quote_function = { | 
					
						
							|  |  |  | 	.name = "QUOTE", | 
					
						
							| 
									
										
										
										
											2006-02-23 23:36:53 +00:00
										 |  |  | 	.read = quote, | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *bufptr = buf, *dataptr = data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-24 06:39:27 +00:00
										 |  |  | 	if (len < 3) { /* at least two for quotes and one for binary zero */ | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | 		ast_log(LOG_ERROR, "Not enough buffer"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							| 
									
										
										
										
											2010-02-24 06:39:27 +00:00
										 |  |  | 		ast_copy_string(buf, "\"\"", len); | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*bufptr++ = '"'; | 
					
						
							|  |  |  | 	for (; bufptr < buf + len - 3; dataptr++){ | 
					
						
							|  |  |  | 		if (*dataptr == '"') { | 
					
						
							|  |  |  | 			*bufptr++ = '"'; | 
					
						
							|  |  |  | 			*bufptr++ = '"'; | 
					
						
							|  |  |  | 		} else if (*dataptr == '\0') { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			*bufptr++ = *dataptr; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	*bufptr++ = '"'; | 
					
						
							|  |  |  | 	*bufptr='\0'; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function csv_quote_function = { | 
					
						
							|  |  |  | 	.name = "CSV_QUOTE", | 
					
						
							|  |  |  | 	.read = csv_quote, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int length = 0; | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (data) | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 		length = strlen(data); | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	snprintf(buf, buflen, "%d", length); | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function len_function = { | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | 	.name = "LEN", | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	.read = len, | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	.read_max = 12, | 
					
						
							| 
									
										
										
										
											2005-05-05 05:39:33 +00:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:50:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse, | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 			char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2005-05-05 05:50:11 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			     AST_APP_ARG(epoch); | 
					
						
							|  |  |  | 			     AST_APP_ARG(timezone); | 
					
						
							|  |  |  | 			     AST_APP_ARG(format); | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	struct timeval when; | 
					
						
							| 
									
										
										
										
											2007-07-18 19:47:20 +00:00
										 |  |  | 	struct ast_tm tm; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:50:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-10-17 17:54:32 +00:00
										 |  |  | 	buf[0] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-14 19:30:37 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, parse); | 
					
						
							| 
									
										
										
										
											2005-10-17 17:54:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL); | 
					
						
							|  |  |  | 	ast_localtime(&when, &tm, args.timezone); | 
					
						
							| 
									
										
										
										
											2005-10-17 17:54:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-15 00:24:24 +00:00
										 |  |  | 	if (!args.format) | 
					
						
							|  |  |  | 		args.format = "%c"; | 
					
						
							| 
									
										
										
										
											2005-10-17 17:54:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	if (ast_strftime(buf, buflen, args.format, &tm) <= 0) | 
					
						
							| 
									
										
										
										
											2005-10-17 17:54:32 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n"); | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	buf[buflen - 1] = '\0'; | 
					
						
							| 
									
										
										
										
											2005-10-17 17:54:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-05-05 05:50:11 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function strftime_function = { | 
					
						
							| 
									
										
										
										
											2005-05-05 05:50:11 +00:00
										 |  |  | 	.name = "STRFTIME", | 
					
						
							|  |  |  | 	.read = acf_strftime, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2005-05-15 23:53:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data, | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 			char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 			     AST_APP_ARG(timestring); | 
					
						
							|  |  |  | 			     AST_APP_ARG(timezone); | 
					
						
							|  |  |  | 			     AST_APP_ARG(format); | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | 	); | 
					
						
							| 
									
										
										
										
											2008-10-01 23:02:25 +00:00
										 |  |  | 	struct ast_tm tm; | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | 	buf[0] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!data) { | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		ast_log(LOG_ERROR, | 
					
						
							|  |  |  | 				"Asterisk function STRPTIME() requires an argument.\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_STANDARD_APP_ARGS(args, data); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 	if (ast_strlen_zero(args.format)) { | 
					
						
							|  |  |  | 		ast_log(LOG_ERROR, | 
					
						
							| 
									
										
										
										
											2007-07-23 19:51:41 +00:00
										 |  |  | 				"No format supplied to STRPTIME(<timestring>,<timezone>,<format>)"); | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-10-01 23:02:25 +00:00
										 |  |  | 	if (!ast_strptime(args.timestring, args.format, &tm)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n"); | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 		struct timeval when; | 
					
						
							| 
									
										
										
										
											2008-10-01 23:02:25 +00:00
										 |  |  | 		when = ast_mktime(&tm, args.timezone); | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 		snprintf(buf, buflen, "%d", (int) when.tv_sec); | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function strptime_function = { | 
					
						
							| 
									
										
										
										
											2006-01-22 08:09:02 +00:00
										 |  |  | 	.name = "STRPTIME", | 
					
						
							|  |  |  | 	.read = acf_strptime, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-01-06 00:13:33 +00:00
										 |  |  | static int function_eval(struct ast_channel *chan, const char *cmd, char *data, | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 			 char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2005-05-15 23:53:11 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2005-11-08 01:55:31 +00:00
										 |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							| 
									
										
										
										
											2005-09-25 20:47:00 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n"); | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2005-05-15 23:53:11 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2005-09-25 20:47:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	pbx_substitute_variables_helper(chan, data, buf, buflen - 1); | 
					
						
							| 
									
										
										
										
											2005-05-15 23:53:11 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-12 04:28:58 +00:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2005-05-15 23:53:11 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int function_eval2(struct ast_channel *chan, const char *cmd, char *data, | 
					
						
							|  |  |  | 			 struct ast_str **buf, ssize_t buflen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (ast_strlen_zero(data)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n"); | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_str_substitute_variables(buf, buflen, chan, data); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | static struct ast_custom_function eval_function = { | 
					
						
							| 
									
										
										
										
											2005-05-15 23:53:11 +00:00
										 |  |  | 	.name = "EVAL", | 
					
						
							|  |  |  | 	.read = function_eval, | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	.read2 = function_eval2, | 
					
						
							| 
									
										
										
										
											2005-05-15 23:53:11 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2006-02-15 00:59:01 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *bufptr, *dataptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) { | 
					
						
							| 
									
										
										
										
											2008-10-26 20:25:08 +00:00
										 |  |  | 		if (*dataptr == '\0') { | 
					
						
							|  |  |  | 			*bufptr++ = '\0'; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} else if (*dataptr == '1') { | 
					
						
							| 
									
										
										
										
											2006-02-15 00:59:01 +00:00
										 |  |  | 			*bufptr++ = '1'; | 
					
						
							|  |  |  | 		} else if (strchr("AaBbCc2", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '2'; | 
					
						
							|  |  |  | 		} else if (strchr("DdEeFf3", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '3'; | 
					
						
							|  |  |  | 		} else if (strchr("GgHhIi4", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '4'; | 
					
						
							|  |  |  | 		} else if (strchr("JjKkLl5", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '5'; | 
					
						
							|  |  |  | 		} else if (strchr("MmNnOo6", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '6'; | 
					
						
							|  |  |  | 		} else if (strchr("PpQqRrSs7", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '7'; | 
					
						
							|  |  |  | 		} else if (strchr("TtUuVv8", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '8'; | 
					
						
							|  |  |  | 		} else if (strchr("WwXxYyZz9", *dataptr)) { | 
					
						
							|  |  |  | 			*bufptr++ = '9'; | 
					
						
							|  |  |  | 		} else if (*dataptr == '0') { | 
					
						
							|  |  |  | 			*bufptr++ = '0'; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	buf[buflen - 1] = '\0'; | 
					
						
							| 
									
										
										
										
											2006-02-15 00:59:01 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function keypadhash_function = { | 
					
						
							|  |  |  | 	.name = "KEYPADHASH", | 
					
						
							|  |  |  | 	.read = keypadhash, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *bufptr = buf, *dataptr = data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++))); | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *bufptr, *dataptr = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buflen > -1) { | 
					
						
							|  |  |  | 		ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	bufptr = ast_str_buffer(*buf); | 
					
						
							|  |  |  | 	while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++))); | 
					
						
							|  |  |  | 	ast_str_update(*buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | static struct ast_custom_function toupper_function = { | 
					
						
							|  |  |  | 	.name = "TOUPPER", | 
					
						
							|  |  |  | 	.read = string_toupper, | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	.read2 = string_toupper2, | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	char *bufptr = buf, *dataptr = data; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-07 01:07:40 +00:00
										 |  |  | 	while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++))); | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *bufptr, *dataptr = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (buflen > -1) { | 
					
						
							|  |  |  | 		ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	bufptr = ast_str_buffer(*buf); | 
					
						
							|  |  |  | 	while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++))); | 
					
						
							|  |  |  | 	ast_str_update(*buf); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | static struct ast_custom_function tolower_function = { | 
					
						
							|  |  |  | 	.name = "TOLOWER", | 
					
						
							|  |  |  | 	.read = string_tolower, | 
					
						
							| 
									
										
										
										
											2009-04-29 18:53:01 +00:00
										 |  |  | 	.read2 = string_tolower2, | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | #define beginning	(cmd[0] == 'S') /* SHIFT */
 | 
					
						
							|  |  |  | 	char *after, delimiter[2] = ",", *varsubst; | 
					
						
							|  |  |  | 	size_t unused; | 
					
						
							|  |  |  | 	struct ast_str *before = ast_str_thread_get(&result_buf, 16); | 
					
						
							|  |  |  | 	char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(var); | 
					
						
							|  |  |  | 		AST_APP_ARG(delimiter); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (!before) { | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, data); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ast_strlen_zero(args.var)) { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 		ast_log(LOG_WARNING, "%s requires a variable name\n", cmd); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	varsubst = alloca(strlen(args.var) + 4); | 
					
						
							|  |  |  | 	sprintf(varsubst, "${%s}", args.var); | 
					
						
							|  |  |  | 	ast_str_substitute_variables(&before, 0, chan, varsubst); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) { | 
					
						
							|  |  |  | 		ast_get_encoded_char(args.delimiter, delimiter, &unused); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (!ast_str_strlen(before)) { | 
					
						
							|  |  |  | 		/* Nothing to pop */ | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) { | 
					
						
							|  |  |  | 		/* Only one entry in array */ | 
					
						
							|  |  |  | 		ast_str_set(buf, len, "%s", ast_str_buffer(before)); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 		pbx_builtin_setvar_helper(chan, args.var, ""); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		*after++ = '\0'; | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 		ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after); | 
					
						
							|  |  |  | 		pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before)); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | #undef beginning
 | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function shift_function = { | 
					
						
							|  |  |  | 	.name = "SHIFT", | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	.read2 = shift_pop, | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function pop_function = { | 
					
						
							|  |  |  | 	.name = "POP", | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	.read2 = shift_pop, | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value) | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | #define beginning	(cmd[0] == 'U') /* UNSHIFT */
 | 
					
						
							|  |  |  | 	char delimiter[2] = ",", *varsubst; | 
					
						
							|  |  |  | 	size_t unused; | 
					
						
							|  |  |  | 	struct ast_str *buf, *previous_value; | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	AST_DECLARE_APP_ARGS(args, | 
					
						
							|  |  |  | 		AST_APP_ARG(var); | 
					
						
							|  |  |  | 		AST_APP_ARG(delimiter); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (!(buf = ast_str_thread_get(&result_buf, 16)) || | 
					
						
							|  |  |  | 		!(previous_value = ast_str_thread_get(&tmp_buf, 16))) { | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	AST_STANDARD_APP_ARGS(args, data); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (ast_strlen_zero(args.var)) { | 
					
						
							|  |  |  | 		ast_log(LOG_WARNING, "%s requires a variable name\n", cmd); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) { | 
					
						
							|  |  |  | 		ast_get_encoded_char(args.delimiter, delimiter, &unused); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	varsubst = alloca(strlen(args.var) + 4); | 
					
						
							|  |  |  | 	sprintf(varsubst, "${%s}", args.var); | 
					
						
							|  |  |  | 	ast_str_substitute_variables(&previous_value, 0, chan, varsubst); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	if (!ast_str_strlen(previous_value)) { | 
					
						
							|  |  |  | 		ast_str_set(&buf, 0, "%s", new_value); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 		ast_str_set(&buf, 0, "%s%c%s", | 
					
						
							|  |  |  | 			beginning ? new_value : ast_str_buffer(previous_value), | 
					
						
							|  |  |  | 			delimiter[0], | 
					
						
							|  |  |  | 			beginning ? ast_str_buffer(previous_value) : new_value); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | #undef beginning
 | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ast_custom_function push_function = { | 
					
						
							|  |  |  | 	.name = "PUSH", | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	.write = unshift_push, | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | static struct ast_custom_function unshift_function = { | 
					
						
							|  |  |  | 	.name = "UNSHIFT", | 
					
						
							|  |  |  | 	.write = unshift_push, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	ast_str_set(buf, len, "%s", data); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | static struct ast_custom_function passthru_function = { | 
					
						
							|  |  |  | 	.name = "PASSTHRU", | 
					
						
							|  |  |  | 	.read2 = passthru, | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | #ifdef TEST_FRAMEWORK
 | 
					
						
							| 
									
										
										
										
											2010-08-03 20:25:10 +00:00
										 |  |  | AST_TEST_DEFINE(test_FIELDNUM) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, res = AST_TEST_PASS; | 
					
						
							|  |  |  | 	struct ast_channel *chan; | 
					
						
							|  |  |  | 	struct ast_str *str; | 
					
						
							|  |  |  | 	char expression[256]; | 
					
						
							|  |  |  | 	struct { | 
					
						
							|  |  |  | 		const char *fields; | 
					
						
							|  |  |  | 		const char *delim; | 
					
						
							|  |  |  | 		const char *field; | 
					
						
							|  |  |  | 		const char *expected; | 
					
						
							|  |  |  | 	} test_args[] = { | 
					
						
							|  |  |  | 		{"abc,def,ghi,jkl", "\\,",     "ghi", "3"}, | 
					
						
							|  |  |  | 		{"abc def ghi jkl", " ",       "abc", "1"}, | 
					
						
							|  |  |  | 		{"abc/def/ghi/jkl", "\\\\x2f", "def", "2"}, | 
					
						
							|  |  |  | 		{"abc$def$ghi$jkl", "",        "ghi", "0"}, | 
					
						
							|  |  |  | 		{"abc,def,ghi,jkl", "-",       "",    "0"}, | 
					
						
							|  |  |  | 		{"abc-def-ghi-jkl", "-",       "mno", "0"} | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case TEST_INIT: | 
					
						
							|  |  |  | 		info->name = "func_FIELDNUM_test"; | 
					
						
							|  |  |  | 		info->category = "/funcs/func_strings/"; | 
					
						
							|  |  |  | 		info->summary = "Test FIELDNUM function"; | 
					
						
							|  |  |  | 		info->description = "Verify FIELDNUM behavior"; | 
					
						
							|  |  |  | 		return AST_TEST_NOT_RUN; | 
					
						
							|  |  |  | 	case TEST_EXECUTE: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(chan = ast_dummy_channel_alloc())) { | 
					
						
							|  |  |  | 		ast_test_status_update(test, "Unable to allocate dummy channel\n"); | 
					
						
							|  |  |  | 		return AST_TEST_FAIL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!(str = ast_str_create(16))) { | 
					
						
							|  |  |  | 		ast_test_status_update(test, "Unable to allocate dynamic string buffer\n"); | 
					
						
							|  |  |  | 		ast_channel_release(chan); | 
					
						
							|  |  |  | 		return AST_TEST_FAIL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < ARRAY_LEN(test_args); i++) { | 
					
						
							|  |  |  | 		struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields); | 
					
						
							|  |  |  | 		AST_LIST_INSERT_HEAD(&chan->varshead, var, entries); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field); | 
					
						
							|  |  |  | 		ast_str_substitute_variables(&str, 0, chan, expression); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		AST_LIST_REMOVE(&chan->varshead, var, entries); | 
					
						
							|  |  |  | 		ast_var_delete(var); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) { | 
					
						
							|  |  |  | 			ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n", | 
					
						
							|  |  |  | 				expression, ast_str_buffer(str), test_args[i].expected); | 
					
						
							|  |  |  | 			res = AST_TEST_FAIL; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_free(str); | 
					
						
							|  |  |  | 	ast_channel_release(chan); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | AST_TEST_DEFINE(test_FILTER) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int i, res = AST_TEST_PASS; | 
					
						
							|  |  |  | 	const char *test_strings[][2] = { | 
					
						
							|  |  |  | 		{"A-R",            "DAHDI"}, | 
					
						
							|  |  |  | 		{"A\\-R",          "A"}, | 
					
						
							|  |  |  | 		{"\\x41-R",        "DAHDI"}, | 
					
						
							|  |  |  | 		{"0-9A-Ca-c",      "0042133333A12212"}, | 
					
						
							|  |  |  | 		{"0-9a-cA-C_+\\-", "0042133333A12212"}, | 
					
						
							|  |  |  | 		{NULL,             NULL}, | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch (cmd) { | 
					
						
							|  |  |  | 	case TEST_INIT: | 
					
						
							|  |  |  | 		info->name = "func_FILTER_test"; | 
					
						
							| 
									
										
										
										
											2010-07-09 17:00:22 +00:00
										 |  |  | 		info->category = "/funcs/func_strings/"; | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 		info->summary = "Test FILTER function"; | 
					
						
							|  |  |  | 		info->description = "Verify FILTER behavior"; | 
					
						
							|  |  |  | 		return AST_TEST_NOT_RUN; | 
					
						
							|  |  |  | 	case TEST_EXECUTE: | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; test_strings[i][0]; i++) { | 
					
						
							|  |  |  | 		char tmp[256], tmp2[256] = ""; | 
					
						
							|  |  |  | 		snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]); | 
					
						
							|  |  |  | 		pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1); | 
					
						
							|  |  |  | 		if (strcmp(test_strings[i][1], tmp2)) { | 
					
						
							|  |  |  | 			ast_test_status_update(test, "Format string '%s' substituted to '%s'.  Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]); | 
					
						
							|  |  |  | 			res = AST_TEST_FAIL; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int unload_module(void) | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-03 20:25:10 +00:00
										 |  |  | 	AST_TEST_UNREGISTER(test_FIELDNUM); | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 	AST_TEST_UNREGISTER(test_FILTER); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&fieldqty_function); | 
					
						
							| 
									
										
										
										
											2010-08-03 20:25:10 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&fieldnum_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&filter_function); | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&replace_function); | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&listfilter_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(®ex_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&array_function); | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | 	res |= ast_custom_function_unregister("e_function); | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&csv_quote_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&len_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&strftime_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&strptime_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&eval_function); | 
					
						
							| 
									
										
										
										
											2006-02-15 00:59:01 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&keypadhash_function); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&hashkeys_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&hash_function); | 
					
						
							|  |  |  | 	res |= ast_unregister_application(app_clearhash); | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&toupper_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&tolower_function); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&shift_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&pop_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&push_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_unregister(&unshift_function); | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	res |= ast_custom_function_unregister(&passthru_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | static int load_module(void) | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	int res = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-03 20:25:10 +00:00
										 |  |  | 	AST_TEST_REGISTER(test_FIELDNUM); | 
					
						
							| 
									
										
										
										
											2010-02-10 14:06:12 +00:00
										 |  |  | 	AST_TEST_REGISTER(test_FILTER); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_register(&fieldqty_function); | 
					
						
							| 
									
										
										
										
											2010-08-03 20:25:10 +00:00
										 |  |  | 	res |= ast_custom_function_register(&fieldnum_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_register(&filter_function); | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	res |= ast_custom_function_register(&replace_function); | 
					
						
							| 
									
										
										
										
											2008-11-05 21:58:48 +00:00
										 |  |  | 	res |= ast_custom_function_register(&listfilter_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_register(®ex_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&array_function); | 
					
						
							| 
									
										
										
										
											2006-02-23 22:59:16 +00:00
										 |  |  | 	res |= ast_custom_function_register("e_function); | 
					
						
							| 
									
										
										
										
											2009-09-30 19:42:36 +00:00
										 |  |  | 	res |= ast_custom_function_register(&csv_quote_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 	res |= ast_custom_function_register(&len_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&strftime_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&strptime_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&eval_function); | 
					
						
							| 
									
										
										
										
											2006-02-15 00:59:01 +00:00
										 |  |  | 	res |= ast_custom_function_register(&keypadhash_function); | 
					
						
							| 
									
										
										
										
											2006-12-28 20:13:00 +00:00
										 |  |  | 	res |= ast_custom_function_register(&hashkeys_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&hash_function); | 
					
						
							| 
									
										
										
										
											2008-11-01 21:10:07 +00:00
										 |  |  | 	res |= ast_register_application_xml(app_clearhash, exec_clearhash); | 
					
						
							| 
									
										
										
										
											2008-01-09 21:37:26 +00:00
										 |  |  | 	res |= ast_custom_function_register(&toupper_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&tolower_function); | 
					
						
							| 
									
										
										
										
											2009-04-22 20:07:41 +00:00
										 |  |  | 	res |= ast_custom_function_register(&shift_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&pop_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&push_function); | 
					
						
							|  |  |  | 	res |= ast_custom_function_register(&unshift_function); | 
					
						
							| 
									
										
										
										
											2009-11-24 04:58:44 +00:00
										 |  |  | 	res |= ast_custom_function_register(&passthru_function); | 
					
						
							| 
									
										
										
										
											2006-02-11 03:14:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-08-21 02:11:39 +00:00
										 |  |  | AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions"); |