Review Board 1.7.16


Various fixes for extenpatternmatchnew

Review Request #194 - Created March 13, 2009 and submitted

Mark Michelson
/trunk
14615
Reviewers
asterisk-dev
Asterisk
When looking into issue 14615, I found a variety of problems which I have addressed in my npm_fixes branch. Here is a summary of the fixes I made:

1. Create different trie entries for pattern and non-pattern matches which are otherwise identical. For example, if you had an extensions "NNN" and "_NNN" in your dialplan, then we need to create two separate trie entries for matching against.

2. Make sure to only apply pattern-matching logic if the extension we are matching against is a pattern extension. This is what bug 14615 is actually about. In that example, the reporter was attempting to Goto() the extension "ANSWER." The problem was that when the 'N' was encountered while looking at the pattern trie, it would not match the literal character 'N' that was being passed in. However, if the Goto() were modified to go to something like "A4SWER" it would go to the ANSWER extension. This behavior has been corrected.

3. Fixed a few places where the code could potentially crash due to dereferencing NULL pointers.

4. Changed the allocation scheme of a match_char to use the "allocation after the struct" method.

5. Did a bunch of coding guidelines-related cleanup.

6. Removed all blocks of code enclosed inside #ifdef NOTNOW...#endif. These areas were designed to use a more manual algorithm for looking up contexts than just finding them in a hashtab. The logic used in these blocks was off, and I can't think of any good reason why you would want to do this.

For anyone who wants to understand how the pattern-matching trie works before taking a crack at this review, you can find a large comment in main/pbx.c that Murf wrote that does an excellent job of explaining things. This comment block is located just below the function pbx_destroy().
I tested the following dialplan, admittedly not the most thorough, but it gets the job done:

exten => 333,1,NoOp(Starting Test, exten 333)
exten => 333,n,Goto(ANSWER,1)
exten => 333,n,Hangup

exten => NNN,1,NoOp(Starting Test, exten NNN)
exten => NNN,n,Playback(tt-monkeys)
exten => NNN,n,Hangup

exten => _NNN,1,NoOp(Starting Test, exten _NNN)
exten => _NNN,n,Playback(tt-weasels)
exten => _NNN,n,Hangup

exten => ANSWER,1,NoOp(Test no answer)
exten => ANSWER,n,Playback(vm-goodbye)
exten => ANSWER,n,Hangup

exten => _1[2-9],1,NoOp(Starting Test, exten _1[2-9])
exten => _1[2-9],n,Playback(queue-thankyou)
exten => _1[2-9],n,Hangup

With this, I could test numeric extensions, string extensions, patterns with reserved letters (i.e. N, Z, X), and patterns with bracketed expressions. In all cases, the pattern I expected to match was matched. The reporter on issue 14615 has also given the branch a test and says that things work for him in his dialplan now.

Diff revision 1 (Latest)

  1. /trunk/main/pbx.c: Loading...
/trunk/main/pbx.c
Revision 182115 New Change
1
/*
1
/*
2
 * Asterisk -- An open source telephony toolkit.
2
 * Asterisk -- An open source telephony toolkit.
3
 *
3
 *
4
 * Copyright (C) 1999 - 2008, Digium, Inc.
4
 * Copyright (C) 1999 - 2008, Digium, Inc.
5
 *
5
 *
6
 * Mark Spencer <markster@digium.com>
6
 * Mark Spencer <markster@digium.com>
7
 *
7
 *
8
 * See http://www.asterisk.org for more information about
8
 * See http://www.asterisk.org for more information about
9
 * the Asterisk project. Please do not directly contact
9
 * the Asterisk project. Please do not directly contact
10
 * any of the maintainers of this project for assistance;
10
 * any of the maintainers of this project for assistance;
11
 * the project provides a web site, mailing lists and IRC
11
 * the project provides a web site, mailing lists and IRC
12
 * channels for your use.
12
 * channels for your use.
13
 *
13
 *
14
 * This program is free software, distributed under the terms of
14
 * This program is free software, distributed under the terms of
15
* the GNU General Public License Version 2. See the LICENSE file
15
* the GNU General Public License Version 2. See the LICENSE file
16
 * at the top of the source tree.
16
 * at the top of the source tree.
17
 */
17
 */
18

    
   
18

   
19
/*! \file
19
/*! \file
20
 *
20
 *
21
 * \brief Core PBX routines.
21
 * \brief Core PBX routines.
22
 *
22
 *
23
 * \author Mark Spencer <markster@digium.com>
23
 * \author Mark Spencer <markster@digium.com>
24
 */
24
 */
25

    
   
25

   
26
#include "asterisk.h"
26
#include "asterisk.h"
27

    
   
27

   
28
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29

    
   
29

   
30
#include "asterisk/_private.h"
30
#include "asterisk/_private.h"
31
#include "asterisk/paths.h"	/* use ast_config_AST_SYSTEM_NAME */
31
#include "asterisk/paths.h"	/* use ast_config_AST_SYSTEM_NAME */
32
#include <ctype.h>
32
#include <ctype.h>
33
#include <time.h>
33
#include <time.h>
34
#include <sys/time.h>
34
#include <sys/time.h>
35
#if defined(HAVE_SYSINFO)
35
#if defined(HAVE_SYSINFO)
36
#include <sys/sysinfo.h>
36
#include <sys/sysinfo.h>
37
#endif
37
#endif
38
#if defined(SOLARIS)
38
#if defined(SOLARIS)
39
#include <sys/loadavg.h>
39
#include <sys/loadavg.h>
40
#endif
40
#endif
41

    
   
41

   
42
#include "asterisk/lock.h"
42
#include "asterisk/lock.h"
43
#include "asterisk/cli.h"
43
#include "asterisk/cli.h"
44
#include "asterisk/pbx.h"
44
#include "asterisk/pbx.h"
45
#include "asterisk/channel.h"
45
#include "asterisk/channel.h"
46
#include "asterisk/file.h"
46
#include "asterisk/file.h"
47
#include "asterisk/callerid.h"
47
#include "asterisk/callerid.h"
48
#include "asterisk/cdr.h"
48
#include "asterisk/cdr.h"
49
#include "asterisk/config.h"
49
#include "asterisk/config.h"
50
#include "asterisk/term.h"
50
#include "asterisk/term.h"
51
#include "asterisk/time.h"
51
#include "asterisk/time.h"
52
#include "asterisk/manager.h"
52
#include "asterisk/manager.h"
53
#include "asterisk/ast_expr.h"
53
#include "asterisk/ast_expr.h"
54
#include "asterisk/linkedlists.h"
54
#include "asterisk/linkedlists.h"
55
#define	SAY_STUBS	/* generate declarations and stubs for say methods */
55
#define	SAY_STUBS	/* generate declarations and stubs for say methods */
56
#include "asterisk/say.h"
56
#include "asterisk/say.h"
57
#include "asterisk/utils.h"
57
#include "asterisk/utils.h"
58
#include "asterisk/causes.h"
58
#include "asterisk/causes.h"
59
#include "asterisk/musiconhold.h"
59
#include "asterisk/musiconhold.h"
60
#include "asterisk/app.h"
60
#include "asterisk/app.h"
61
#include "asterisk/devicestate.h"
61
#include "asterisk/devicestate.h"
62
#include "asterisk/event.h"
62
#include "asterisk/event.h"
63
#include "asterisk/hashtab.h"
63
#include "asterisk/hashtab.h"
64
#include "asterisk/module.h"
64
#include "asterisk/module.h"
65
#include "asterisk/indications.h"
65
#include "asterisk/indications.h"
66
#include "asterisk/taskprocessor.h"
66
#include "asterisk/taskprocessor.h"
67
#include "asterisk/xmldoc.h"
67
#include "asterisk/xmldoc.h"
68

    
   
68

   
69
/*!
69
/*!
70
 * \note I M P O R T A N T :
70
 * \note I M P O R T A N T :
71
 *
71
 *
72
 *		The speed of extension handling will likely be among the most important
72
 *		The speed of extension handling will likely be among the most important
73
 * aspects of this PBX.  The switching scheme as it exists right now isn't
73
 * aspects of this PBX.  The switching scheme as it exists right now isn't
74
 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
74
 * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
75
 * of priorities, but a constant search time here would be great ;-)
75
 * of priorities, but a constant search time here would be great ;-)
76
 *
76
 *
77
 * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
77
 * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
78
 * here, and shows a fairly flat (constant) search time, even for over
78
 * here, and shows a fairly flat (constant) search time, even for over
79
 * 10000 patterns.
79
 * 10000 patterns.
80
 *
80
 *
81
 * Also, using a hash table for context/priority name lookup can help prevent
81
 * Also, using a hash table for context/priority name lookup can help prevent
82
 * the find_extension routines from absorbing exponential cpu cycles as the number
82
 * the find_extension routines from absorbing exponential cpu cycles as the number
83
 * of contexts/priorities grow. I've previously tested find_extension with red-black trees,
83
 * of contexts/priorities grow. I've previously tested find_extension with red-black trees,
84
 * which have O(log2(n)) speed. Right now, I'm using hash tables, which do
84
 * which have O(log2(n)) speed. Right now, I'm using hash tables, which do
85
 * searches (ideally) in O(1) time. While these techniques do not yield much
85
 * searches (ideally) in O(1) time. While these techniques do not yield much
86
 * speed in small dialplans, they are worth the trouble in large dialplans.
86
 * speed in small dialplans, they are worth the trouble in large dialplans.
87
 *
87
 *
88
 */
88
 */
89

    
   
89

   
90
/*** DOCUMENTATION
90
/*** DOCUMENTATION
91
	<application name="Answer" language="en_US">
91
	<application name="Answer" language="en_US">
92
		<synopsis>
92
		<synopsis>
93
			Answer a channel if ringing.
93
			Answer a channel if ringing.
94
		</synopsis>
94
		</synopsis>
95
		<syntax>
95
		<syntax>
96
			<parameter name="delay">
96
			<parameter name="delay">
97
				<para>Asterisk will wait this number of milliseconds before returning to
97
				<para>Asterisk will wait this number of milliseconds before returning to
98
				the dialplan after answering the call.</para>
98
				the dialplan after answering the call.</para>
99
			</parameter>
99
			</parameter>
100
			<parameter name="nocdr">
100
			<parameter name="nocdr">
101
				<para>Asterisk will send an answer signal to the calling phone, but will not
101
				<para>Asterisk will send an answer signal to the calling phone, but will not
102
				set the disposition or answer time in the CDR for this call.</para>
102
				set the disposition or answer time in the CDR for this call.</para>
103
			</parameter>
103
			</parameter>
104
		</syntax>
104
		</syntax>
105
		<description>
105
		<description>
106
			<para>If the call has not been answered, this application will
106
			<para>If the call has not been answered, this application will
107
			answer it. Otherwise, it has no effect on the call.</para>
107
			answer it. Otherwise, it has no effect on the call.</para>
108
		</description>
108
		</description>
109
		<see-also>
109
		<see-also>
110
			<ref type="application">Hangup</ref>
110
			<ref type="application">Hangup</ref>
111
		</see-also>
111
		</see-also>
112
	</application>
112
	</application>
113
	<application name="BackGround" language="en_US">
113
	<application name="BackGround" language="en_US">
114
		<synopsis>
114
		<synopsis>
115
			Play an audio file while waiting for digits of an extension to go to.
115
			Play an audio file while waiting for digits of an extension to go to.
116
		</synopsis>
116
		</synopsis>
117
		<syntax>
117
		<syntax>
118
			<parameter name="filenames" required="true" argsep="&amp;">
118
			<parameter name="filenames" required="true" argsep="&amp;">
119
				<argument name="filename1" required="true" />
119
				<argument name="filename1" required="true" />
120
				<argument name="filename2" multiple="true" />
120
				<argument name="filename2" multiple="true" />
121
			</parameter>
121
			</parameter>
122
			<parameter name="options">
122
			<parameter name="options">
123
				<optionlist>
123
				<optionlist>
124
					<option name="s">
124
					<option name="s">
125
						<para>Causes the playback of the message to be skipped
125
						<para>Causes the playback of the message to be skipped
126
						if the channel is not in the <literal>up</literal> state (i.e. it
126
						if the channel is not in the <literal>up</literal> state (i.e. it
127
						hasn't been answered yet). If this happens, the
127
						hasn't been answered yet). If this happens, the
128
						application will return immediately.</para>
128
						application will return immediately.</para>
129
					</option>
129
					</option>
130
					<option name="n">
130
					<option name="n">
131
						<para>Don't answer the channel before playing the files.</para>
131
						<para>Don't answer the channel before playing the files.</para>
132
					</option>
132
					</option>
133
					<option name="m">
133
					<option name="m">
134
						<para>Only break if a digit hit matches a one digit
134
						<para>Only break if a digit hit matches a one digit
135
						extension in the destination context.</para>
135
						extension in the destination context.</para>
136
					</option>
136
					</option>
137
				</optionlist>
137
				</optionlist>
138
			</parameter>
138
			</parameter>
139
			<parameter name="langoverride">
139
			<parameter name="langoverride">
140
				<para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
140
				<para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
141
			</parameter>
141
			</parameter>
142
			<parameter name="context">
142
			<parameter name="context">
143
				<para>This is the dialplan context that this application will use when exiting
143
				<para>This is the dialplan context that this application will use when exiting
144
				to a dialed extension.</para>
144
				to a dialed extension.</para>
145
			</parameter>
145
			</parameter>
146
		</syntax>
146
		</syntax>
147
		<description>
147
		<description>
148
			<para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
148
			<para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
149
			while waiting for an extension to be dialed by the calling channel. To continue waiting
149
			while waiting for an extension to be dialed by the calling channel. To continue waiting
150
			for digits after this application has finished playing files, the <literal>WaitExten</literal>
150
			for digits after this application has finished playing files, the <literal>WaitExten</literal>
151
			application should be used.</para>
151
			application should be used.</para>
152
			<para>If one of the requested sound files does not exist, call processing will be terminated.</para>
152
			<para>If one of the requested sound files does not exist, call processing will be terminated.</para>
153
			<para>This application sets the following channel variable upon completion:</para>
153
			<para>This application sets the following channel variable upon completion:</para>
154
			<variablelist>
154
			<variablelist>
155
				<variable name="BACKGROUNDSTATUS">
155
				<variable name="BACKGROUNDSTATUS">
156
					<para>The status of the background attempt as a text string.</para>
156
					<para>The status of the background attempt as a text string.</para>
157
					<value name="SUCCESS" />
157
					<value name="SUCCESS" />
158
					<value name="FAILED" />
158
					<value name="FAILED" />
159
				</variable>
159
				</variable>
160
			</variablelist>
160
			</variablelist>
161
		</description>
161
		</description>
162
		<see-also>
162
		<see-also>
163
			<ref type="application">ControlPlayback</ref>
163
			<ref type="application">ControlPlayback</ref>
164
			<ref type="application">WaitExten</ref>
164
			<ref type="application">WaitExten</ref>
165
			<ref type="application">BackgroundDetect</ref>
165
			<ref type="application">BackgroundDetect</ref>
166
			<ref type="function">TIMEOUT</ref>
166
			<ref type="function">TIMEOUT</ref>
167
		</see-also>
167
		</see-also>
168
	</application>
168
	</application>
169
	<application name="Busy" language="en_US">
169
	<application name="Busy" language="en_US">
170
		<synopsis>
170
		<synopsis>
171
			Indicate the Busy condition.
171
			Indicate the Busy condition.
172
		</synopsis>
172
		</synopsis>
173
		<syntax>
173
		<syntax>
174
			<parameter name="timeout">
174
			<parameter name="timeout">
175
				<para>If specified, the calling channel will be hung up after the specified number of seconds.
175
				<para>If specified, the calling channel will be hung up after the specified number of seconds.
176
				Otherwise, this application will wait until the calling channel hangs up.</para>
176
				Otherwise, this application will wait until the calling channel hangs up.</para>
177
			</parameter>
177
			</parameter>
178
		</syntax>
178
		</syntax>
179
		<description>
179
		<description>
180
			<para>This application will indicate the busy condition to the calling channel.</para>
180
			<para>This application will indicate the busy condition to the calling channel.</para>
181
		</description>
181
		</description>
182
		<see-also>
182
		<see-also>
183
			<ref type="application">Congestion</ref>
183
			<ref type="application">Congestion</ref>
184
			<ref type="application">Progess</ref>
184
			<ref type="application">Progess</ref>
185
			<ref type="application">Playtones</ref>
185
			<ref type="application">Playtones</ref>
186
			<ref type="application">Hangup</ref>
186
			<ref type="application">Hangup</ref>
187
		</see-also>
187
		</see-also>
188
	</application>
188
	</application>
189
	<application name="Congestion" language="en_US">
189
	<application name="Congestion" language="en_US">
190
		<synopsis>
190
		<synopsis>
191
			Indicate the Congestion condition.
191
			Indicate the Congestion condition.
192
		</synopsis>
192
		</synopsis>
193
		<syntax>
193
		<syntax>
194
			<parameter name="timeout">
194
			<parameter name="timeout">
195
				<para>If specified, the calling channel will be hung up after the specified number of seconds.
195
				<para>If specified, the calling channel will be hung up after the specified number of seconds.
196
				Otherwise, this application will wait until the calling channel hangs up.</para>
196
				Otherwise, this application will wait until the calling channel hangs up.</para>
197
			</parameter>
197
			</parameter>
198
		</syntax>
198
		</syntax>
199
		<description>
199
		<description>
200
			<para>This application will indicate the congestion condition to the calling channel.</para>
200
			<para>This application will indicate the congestion condition to the calling channel.</para>
201
		</description>
201
		</description>
202
		<see-also>
202
		<see-also>
203
			<ref type="application">Busy</ref>
203
			<ref type="application">Busy</ref>
204
			<ref type="application">Progess</ref>
204
			<ref type="application">Progess</ref>
205
			<ref type="application">Playtones</ref>
205
			<ref type="application">Playtones</ref>
206
			<ref type="application">Hangup</ref>
206
			<ref type="application">Hangup</ref>
207
		</see-also>
207
		</see-also>
208
	</application>
208
	</application>
209
	<application name="ExecIfTime" language="en_US">
209
	<application name="ExecIfTime" language="en_US">
210
		<synopsis>
210
		<synopsis>
211
			Conditional application execution based on the current time.
211
			Conditional application execution based on the current time.
212
		</synopsis>
212
		</synopsis>
213
		<syntax argsep="?">
213
		<syntax argsep="?">
214
			<parameter name="day_condition" required="true">
214
			<parameter name="day_condition" required="true">
215
				<argument name="times" required="true" />
215
				<argument name="times" required="true" />
216
				<argument name="weekdays" required="true" />
216
				<argument name="weekdays" required="true" />
217
				<argument name="mdays" required="true" />
217
				<argument name="mdays" required="true" />
218
				<argument name="months" required="true" />
218
				<argument name="months" required="true" />
219
				<argument name="timezone" required="false" />
219
				<argument name="timezone" required="false" />
220
			</parameter>
220
			</parameter>
221
			<parameter name="appname" required="true" hasparams="optional">
221
			<parameter name="appname" required="true" hasparams="optional">
222
				<argument name="appargs" required="true" />
222
				<argument name="appargs" required="true" />
223
			</parameter>
223
			</parameter>
224
		</syntax>
224
		</syntax>
225
		<description>
225
		<description>
226
			<para>This application will execute the specified dialplan application, with optional
226
			<para>This application will execute the specified dialplan application, with optional
227
			arguments, if the current time matches the given time specification.</para>
227
			arguments, if the current time matches the given time specification.</para>
228
		</description>
228
		</description>
229
		<see-also>
229
		<see-also>
230
			<ref type="application">Exec</ref>
230
			<ref type="application">Exec</ref>
231
			<ref type="application">TryExec</ref>
231
			<ref type="application">TryExec</ref>
232
		</see-also>
232
		</see-also>
233
	</application>
233
	</application>
234
	<application name="Goto" language="en_US">
234
	<application name="Goto" language="en_US">
235
		<synopsis>
235
		<synopsis>
236
			Jump to a particular priority, extension, or context.
236
			Jump to a particular priority, extension, or context.
237
		</synopsis>
237
		</synopsis>
238
		<syntax>
238
		<syntax>
239
			<parameter name="context" />
239
			<parameter name="context" />
240
			<parameter name="extensions" />
240
			<parameter name="extensions" />
241
			<parameter name="priority" required="true" />
241
			<parameter name="priority" required="true" />
242
		</syntax>
242
		</syntax>
243
		<description>
243
		<description>
244
			<para>This application will set the current context, extension, and priority in the channel structure.
244
			<para>This application will set the current context, extension, and priority in the channel structure.
245
			After it completes, the pbx engine will continue dialplan execution at the specified location.
245
			After it completes, the pbx engine will continue dialplan execution at the specified location.
246
			If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
246
			If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
247
			<replaceable>context</replaceable>, are specified, then this application will
247
			<replaceable>context</replaceable>, are specified, then this application will
248
			just set the specified <replaceable>priority</replaceable> of the current extension.</para>
248
			just set the specified <replaceable>priority</replaceable> of the current extension.</para>
249
			<para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
249
			<para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
250
			return a <literal>-1</literal>,	and the channel and call will be terminated.</para>
250
			return a <literal>-1</literal>,	and the channel and call will be terminated.</para>
251
			<para>If the location that is put into the channel information is bogus, and asterisk cannot
251
			<para>If the location that is put into the channel information is bogus, and asterisk cannot
252
			find that location in the dialplan, then the execution engine will try to find and execute the code in
252
			find that location in the dialplan, then the execution engine will try to find and execute the code in
253
			the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
253
			the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
254
			<literal>h</literal> extension. If either or neither the <literal>h</literal> or <literal>i</literal> extensions
254
			<literal>h</literal> extension. If either or neither the <literal>h</literal> or <literal>i</literal> extensions
255
			have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
255
			have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
256
			What this means is that, for example, you specify a context that does not exist, then
256
			What this means is that, for example, you specify a context that does not exist, then
257
			it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
257
			it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
258
			and the call will terminate!</para>
258
			and the call will terminate!</para>
259
		</description>
259
		</description>
260
		<see-also>
260
		<see-also>
261
			<ref type="application">GotoIf</ref>
261
			<ref type="application">GotoIf</ref>
262
			<ref type="application">GotoIfTime</ref>
262
			<ref type="application">GotoIfTime</ref>
263
			<ref type="application">Gosub</ref>
263
			<ref type="application">Gosub</ref>
264
			<ref type="application">Macro</ref>
264
			<ref type="application">Macro</ref>
265
		</see-also>
265
		</see-also>
266
	</application>
266
	</application>
267
	<application name="GotoIf" language="en_US">
267
	<application name="GotoIf" language="en_US">
268
		<synopsis>
268
		<synopsis>
269
			Conditional goto.
269
			Conditional goto.
270
		</synopsis>
270
		</synopsis>
271
		<syntax argsep="?">
271
		<syntax argsep="?">
272
			<parameter name="condition" required="true" />
272
			<parameter name="condition" required="true" />
273
			<parameter name="destination" required="true" argsep=":">
273
			<parameter name="destination" required="true" argsep=":">
274
				<argument name="labeliftrue">
274
				<argument name="labeliftrue">
275
					<para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.</para>
275
					<para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.</para>
276
				</argument>
276
				</argument>
277
				<argument name="labeliffalse">
277
				<argument name="labeliffalse">
278
					<para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.</para>
278
					<para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.</para>
279
				</argument>
279
				</argument>
280
			</parameter>
280
			</parameter>
281
		</syntax>
281
		</syntax>
282
		<description>
282
		<description>
283
			<para>This application will set the current context, extension, and priority in the channel structure
283
			<para>This application will set the current context, extension, and priority in the channel structure
284
			based on the evaluation of the given condition. After this application completes, the
284
			based on the evaluation of the given condition. After this application completes, the
285
			pbx engine will continue dialplan execution at the specified location in the dialplan.
285
			pbx engine will continue dialplan execution at the specified location in the dialplan.
286
			The labels are specified with the same syntax as used within the Goto application.
286
			The labels are specified with the same syntax as used within the Goto application.
287
			If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
287
			If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
288
			next instruction. If the target location is bogus, and does not exist, the execution engine will try
288
			next instruction. If the target location is bogus, and does not exist, the execution engine will try
289
			to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
289
			to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
290
			If that does not exist, it will try to execute the <literal>h</literal> extension.
290
			If that does not exist, it will try to execute the <literal>h</literal> extension.
291
			If either or neither the <literal>h</literal> or <literal>i</literal> extensions have been defined,
291
			If either or neither the <literal>h</literal> or <literal>i</literal> extensions have been defined,
292
			the channel is hung up, and the execution of instructions on the channel is terminated.
292
			the channel is hung up, and the execution of instructions on the channel is terminated.
293
			Remember that this command can set the current context, and if the context specified
293
			Remember that this command can set the current context, and if the context specified
294
			does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
294
			does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
295
			the channel and call will both be terminated!.</para>
295
			the channel and call will both be terminated!.</para>
296
		</description>
296
		</description>
297
		<see-also>
297
		<see-also>
298
			<ref type="application">Goto</ref>
298
			<ref type="application">Goto</ref>
299
			<ref type="application">GotoIfTime</ref>
299
			<ref type="application">GotoIfTime</ref>
300
			<ref type="application">GosubIf</ref>
300
			<ref type="application">GosubIf</ref>
301
			<ref type="application">MacroIf</ref>
301
			<ref type="application">MacroIf</ref>
302
		</see-also>
302
		</see-also>
303
	</application>
303
	</application>
304
	<application name="GotoIfTime" language="en_US">
304
	<application name="GotoIfTime" language="en_US">
305
		<synopsis>
305
		<synopsis>
306
			Conditional Goto based on the current time.
306
			Conditional Goto based on the current time.
307
		</synopsis>
307
		</synopsis>
308
		<syntax argsep="?">
308
		<syntax argsep="?">
309
			<parameter name="condition" required="true">
309
			<parameter name="condition" required="true">
310
				<argument name="times" required="true" />
310
				<argument name="times" required="true" />
311
				<argument name="weekdays" required="true" />
311
				<argument name="weekdays" required="true" />
312
				<argument name="mdays" required="true" />
312
				<argument name="mdays" required="true" />
313
				<argument name="months" required="true" />
313
				<argument name="months" required="true" />
314
				<argument name="timezone" required="false" />
314
				<argument name="timezone" required="false" />
315
			</parameter>
315
			</parameter>
316
			<parameter name="destination" required="true" argsep=":">
316
			<parameter name="destination" required="true" argsep=":">
317
				<argument name="labeliftrue" />
317
				<argument name="labeliftrue" />
318
				<argument name="labeliffalse" />
318
				<argument name="labeliffalse" />
319
			</parameter>
319
			</parameter>
320
		</syntax>
320
		</syntax>
321
		<description>
321
		<description>
322
			<para>This application will set the context, extension, and priority in the channel structure
322
			<para>This application will set the context, extension, and priority in the channel structure
323
			based on the evaluation of the given time specification. After this application completes,
323
			based on the evaluation of the given time specification. After this application completes,
324
			the pbx engine will continue dialplan execution at the specified location in the dialplan.
324
			the pbx engine will continue dialplan execution at the specified location in the dialplan.
325
			If the current time is within the given time specification, the channel will continue at
325
			If the current time is within the given time specification, the channel will continue at
326
			<replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
326
			<replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
327
			If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
327
			If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
328
			instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
328
			instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
329
			Further information on the time specification can be found in examples
329
			Further information on the time specification can be found in examples
330
			illustrating how to do time-based context includes in the dialplan.</para>
330
			illustrating how to do time-based context includes in the dialplan.</para>
331
		</description>
331
		</description>
332
		<see-also>
332
		<see-also>
333
			<ref type="application">GotoIf</ref>
333
			<ref type="application">GotoIf</ref>
334
			<ref type="function">IFTIME</ref>
334
			<ref type="function">IFTIME</ref>
335
		</see-also>
335
		</see-also>
336
	</application>
336
	</application>
337
	<application name="ImportVar" language="en_US">
337
	<application name="ImportVar" language="en_US">
338
		<synopsis>
338
		<synopsis>
339
			Import a variable from a channel into a new variable.
339
			Import a variable from a channel into a new variable.
340
		</synopsis>
340
		</synopsis>
341
		<syntax argsep="=">
341
		<syntax argsep="=">
342
			<parameter name="newvar" required="true" />
342
			<parameter name="newvar" required="true" />
343
			<parameter name="vardata" required="true">
343
			<parameter name="vardata" required="true">
344
				<argument name="channelname" required="true" />
344
				<argument name="channelname" required="true" />
345
				<argument name="variable" required="true" />
345
				<argument name="variable" required="true" />
346
			</parameter>
346
			</parameter>
347
		</syntax>
347
		</syntax>
348
		<description>
348
		<description>
349
			<para>This application imports a <replaceable>variable</replaceable> from the specified
349
			<para>This application imports a <replaceable>variable</replaceable> from the specified
350
			<replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
350
			<replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
351
			(<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
351
			(<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
352
			application). Variables created by this application have the same inheritance properties as those
352
			application). Variables created by this application have the same inheritance properties as those
353
			created with the <literal>Set</literal> application.</para>
353
			created with the <literal>Set</literal> application.</para>
354
		</description>
354
		</description>
355
		<see-also>
355
		<see-also>
356
			<ref type="application">Set</ref>
356
			<ref type="application">Set</ref>
357
		</see-also>
357
		</see-also>
358
	</application>
358
	</application>
359
	<application name="Hangup" language="en_US">
359
	<application name="Hangup" language="en_US">
360
		<synopsis>
360
		<synopsis>
361
			Hang up the calling channel.
361
			Hang up the calling channel.
362
		</synopsis>
362
		</synopsis>
363
		<syntax>
363
		<syntax>
364
			<parameter name="causecode">
364
			<parameter name="causecode">
365
				<para>If a <replaceable>causecode</replaceable> is given the channel's
365
				<para>If a <replaceable>causecode</replaceable> is given the channel's
366
				hangup cause will be set to the given value.</para>
366
				hangup cause will be set to the given value.</para>
367
			</parameter>
367
			</parameter>
368
		</syntax>
368
		</syntax>
369
		<description>
369
		<description>
370
			<para>This application will hang up the calling channel.</para>
370
			<para>This application will hang up the calling channel.</para>
371
		</description>
371
		</description>
372
		<see-also>
372
		<see-also>
373
			<ref type="application">Answer</ref>
373
			<ref type="application">Answer</ref>
374
			<ref type="application">Busy</ref>
374
			<ref type="application">Busy</ref>
375
			<ref type="application">Congestion</ref>
375
			<ref type="application">Congestion</ref>
376
		</see-also>
376
		</see-also>
377
	</application>
377
	</application>
378
	<application name="Incomplete" language="en_US">
378
	<application name="Incomplete" language="en_US">
379
		<synopsis>
379
		<synopsis>
380
			Returns AST_PBX_INCOMPLETE value.
380
			Returns AST_PBX_INCOMPLETE value.
381
		</synopsis>
381
		</synopsis>
382
		<syntax>
382
		<syntax>
383
			<parameter name="n">
383
			<parameter name="n">
384
				<para>If specified, then Incomplete will not attempt to answer the channel first.</para>
384
				<para>If specified, then Incomplete will not attempt to answer the channel first.</para>
385
				<note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
385
				<note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
386
			</parameter>
386
			</parameter>
387
		</syntax>
387
		</syntax>
388
		<description>
388
		<description>
389
			<para>Signals the PBX routines that the previous matched extension is incomplete
389
			<para>Signals the PBX routines that the previous matched extension is incomplete
390
			and that further input should be allowed before matching can be considered
390
			and that further input should be allowed before matching can be considered
391
			to be complete.  Can be used within a pattern match when certain criteria warrants
391
			to be complete.  Can be used within a pattern match when certain criteria warrants
392
			a longer match.</para>
392
			a longer match.</para>
393
		</description>
393
		</description>
394
	</application>
394
	</application>
395
	<application name="NoOp" language="en_US">
395
	<application name="NoOp" language="en_US">
396
		<synopsis>
396
		<synopsis>
397
			Do Nothing (No Operation).
397
			Do Nothing (No Operation).
398
		</synopsis>
398
		</synopsis>
399
		<syntax>
399
		<syntax>
400
			<parameter name="text">
400
			<parameter name="text">
401
				<para>Any text provided can be viewed at the Asterisk CLI.</para>
401
				<para>Any text provided can be viewed at the Asterisk CLI.</para>
402
			</parameter>
402
			</parameter>
403
		</syntax>
403
		</syntax>
404
		<description>
404
		<description>
405
			<para>This application does nothing. However, it is useful for debugging purposes.</para>
405
			<para>This application does nothing. However, it is useful for debugging purposes.</para>
406
			<para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
406
			<para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
407
		</description>
407
		</description>
408
		<see-also>
408
		<see-also>
409
			<ref type="application">Verbose</ref>
409
			<ref type="application">Verbose</ref>
410
			<ref type="application">Log</ref>
410
			<ref type="application">Log</ref>
411
		</see-also>
411
		</see-also>
412
	</application>
412
	</application>
413
	<application name="Proceeding" language="en_US">
413
	<application name="Proceeding" language="en_US">
414
		<synopsis>
414
		<synopsis>
415
			Indicate proceeding.
415
			Indicate proceeding.
416
		</synopsis>
416
		</synopsis>
417
		<syntax />
417
		<syntax />
418
		<description>
418
		<description>
419
			<para>This application will request that a proceeding message be provided to the calling channel.</para>
419
			<para>This application will request that a proceeding message be provided to the calling channel.</para>
420
		</description>
420
		</description>
421
	</application>
421
	</application>
422
	<application name="Progress" language="en_US">
422
	<application name="Progress" language="en_US">
423
		<synopsis>
423
		<synopsis>
424
			Indicate progress.
424
			Indicate progress.
425
		</synopsis>
425
		</synopsis>
426
		<syntax />
426
		<syntax />
427
		<description>
427
		<description>
428
			<para>This application will request that in-band progress information be provided to the calling channel.</para>
428
			<para>This application will request that in-band progress information be provided to the calling channel.</para>
429
		</description>
429
		</description>
430
		<see-also>
430
		<see-also>
431
			<ref type="application">Busy</ref>
431
			<ref type="application">Busy</ref>
432
			<ref type="application">Congestion</ref>
432
			<ref type="application">Congestion</ref>
433
			<ref type="application">Ringing</ref>
433
			<ref type="application">Ringing</ref>
434
			<ref type="application">Playtones</ref>
434
			<ref type="application">Playtones</ref>
435
		</see-also>
435
		</see-also>
436
	</application>
436
	</application>
437
	<application name="RaiseException" language="en_US">
437
	<application name="RaiseException" language="en_US">
438
		<synopsis>
438
		<synopsis>
439
			Handle an exceptional condition.
439
			Handle an exceptional condition.
440
		</synopsis>
440
		</synopsis>
441
		<syntax>
441
		<syntax>
442
			<parameter name="reason" required="true" />
442
			<parameter name="reason" required="true" />
443
		</syntax>
443
		</syntax>
444
		<description>
444
		<description>
445
			<para>This application will jump to the <literal>e</literal> extension in the current context, setting the
445
			<para>This application will jump to the <literal>e</literal> extension in the current context, setting the
446
			dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
446
			dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
447
		</description>
447
		</description>
448
		<see-also>
448
		<see-also>
449
			<ref type="function">Exception</ref>
449
			<ref type="function">Exception</ref>
450
		</see-also>
450
		</see-also>
451
	</application>
451
	</application>
452
	<application name="ResetCDR" language="en_US">
452
	<application name="ResetCDR" language="en_US">
453
		<synopsis>
453
		<synopsis>
454
			Resets the Call Data Record.
454
			Resets the Call Data Record.
455
		</synopsis>
455
		</synopsis>
456
		<syntax>
456
		<syntax>
457
			<parameter name="options">
457
			<parameter name="options">
458
				<optionlist>
458
				<optionlist>
459
					<option name="w">
459
					<option name="w">
460
						<para>Store the current CDR record before resetting it.</para>
460
						<para>Store the current CDR record before resetting it.</para>
461
					</option>
461
					</option>
462
					<option name="a">
462
					<option name="a">
463
						<para>Store any stacked records.</para>
463
						<para>Store any stacked records.</para>
464
					</option>
464
					</option>
465
					<option name="v">
465
					<option name="v">
466
						<para>Save CDR variables.</para>
466
						<para>Save CDR variables.</para>
467
					</option>
467
					</option>
468
					<option name="e">
468
					<option name="e">
469
						<para>Enable CDR only (negate effects of NoCDR).</para>
469
						<para>Enable CDR only (negate effects of NoCDR).</para>
470
					</option>
470
					</option>
471
				</optionlist>
471
				</optionlist>
472
			</parameter>
472
			</parameter>
473
		</syntax>
473
		</syntax>
474
		<description>
474
		<description>
475
			<para>This application causes the Call Data Record to be reset.</para>
475
			<para>This application causes the Call Data Record to be reset.</para>
476
		</description>
476
		</description>
477
		<see-also>
477
		<see-also>
478
			<ref type="application">ForkCDR</ref>
478
			<ref type="application">ForkCDR</ref>
479
			<ref type="application">NoCDR</ref>
479
			<ref type="application">NoCDR</ref>
480
		</see-also>
480
		</see-also>
481
	</application>
481
	</application>
482
	<application name="Ringing" language="en_US">
482
	<application name="Ringing" language="en_US">
483
		<synopsis>
483
		<synopsis>
484
			Indicate ringing tone.
484
			Indicate ringing tone.
485
		</synopsis>
485
		</synopsis>
486
		<syntax />
486
		<syntax />
487
		<description>
487
		<description>
488
			<para>This application will request that the channel indicate a ringing tone to the user.</para>
488
			<para>This application will request that the channel indicate a ringing tone to the user.</para>
489
		</description>
489
		</description>
490
		<see-also>
490
		<see-also>
491
			<ref type="application">Busy</ref>
491
			<ref type="application">Busy</ref>
492
			<ref type="application">Congestion</ref>
492
			<ref type="application">Congestion</ref>
493
			<ref type="application">Progress</ref>
493
			<ref type="application">Progress</ref>
494
			<ref type="application">Playtones</ref>
494
			<ref type="application">Playtones</ref>
495
		</see-also>
495
		</see-also>
496
	</application>
496
	</application>
497
	<application name="SayAlpha" language="en_US">
497
	<application name="SayAlpha" language="en_US">
498
		<synopsis>
498
		<synopsis>
499
			Say Alpha.
499
			Say Alpha.
500
		</synopsis>
500
		</synopsis>
501
		<syntax>
501
		<syntax>
502
			<parameter name="string" required="true" />
502
			<parameter name="string" required="true" />
503
		</syntax>
503
		</syntax>
504
		<description>
504
		<description>
505
			<para>This application will play the sounds that correspond to the letters of the
505
			<para>This application will play the sounds that correspond to the letters of the
506
			given <replaceable>string</replaceable>.</para>
506
			given <replaceable>string</replaceable>.</para>
507
		</description>
507
		</description>
508
		<see-also>
508
		<see-also>
509
			<ref type="application">SayDigits</ref>
509
			<ref type="application">SayDigits</ref>
510
			<ref type="application">SayNumber</ref>
510
			<ref type="application">SayNumber</ref>
511
			<ref type="application">SayPhonetic</ref>
511
			<ref type="application">SayPhonetic</ref>
512
			<ref type="function">CHANNEL</ref>
512
			<ref type="function">CHANNEL</ref>
513
		</see-also>
513
		</see-also>
514
	</application>
514
	</application>
515
	<application name="SayDigits" language="en_US">
515
	<application name="SayDigits" language="en_US">
516
		<synopsis>
516
		<synopsis>
517
			Say Digits.
517
			Say Digits.
518
		</synopsis>
518
		</synopsis>
519
		<syntax>
519
		<syntax>
520
			<parameter name="digits" required="true" />
520
			<parameter name="digits" required="true" />
521
		</syntax>
521
		</syntax>
522
		<description>
522
		<description>
523
			<para>This application will play the sounds that correspond to the digits of
523
			<para>This application will play the sounds that correspond to the digits of
524
			the given number. This will use the language that is currently set for the channel.</para>
524
			the given number. This will use the language that is currently set for the channel.</para>
525
		</description>
525
		</description>
526
		<see-also>
526
		<see-also>
527
			<ref type="application">SayAlpha</ref>
527
			<ref type="application">SayAlpha</ref>
528
			<ref type="application">SayNumber</ref>
528
			<ref type="application">SayNumber</ref>
529
			<ref type="application">SayPhonetic</ref>
529
			<ref type="application">SayPhonetic</ref>
530
			<ref type="function">CHANNEL</ref>
530
			<ref type="function">CHANNEL</ref>
531
		</see-also>
531
		</see-also>
532
	</application>
532
	</application>
533
	<application name="SayNumber" language="en_US">
533
	<application name="SayNumber" language="en_US">
534
		<synopsis>
534
		<synopsis>
535
			Say Number.
535
			Say Number.
536
		</synopsis>
536
		</synopsis>
537
		<syntax>
537
		<syntax>
538
			<parameter name="digits" required="true" />
538
			<parameter name="digits" required="true" />
539
			<parameter name="gender" />
539
			<parameter name="gender" />
540
		</syntax>
540
		</syntax>
541
		<description>
541
		<description>
542
			<para>This application will play the sounds that correspond to the given <replaceable>digits</replaceable>.
542
			<para>This application will play the sounds that correspond to the given <replaceable>digits</replaceable>.
543
			Optionally, a <replaceable>gender</replaceable> may be specified. This will use the language that is currently
543
			Optionally, a <replaceable>gender</replaceable> may be specified. This will use the language that is currently
544
			set for the channel. See the LANGUAGE() function for more information on setting the language for the channel.</para>
544
			set for the channel. See the LANGUAGE() function for more information on setting the language for the channel.</para>
545
		</description>
545
		</description>
546
		<see-also>
546
		<see-also>
547
			<ref type="application">SayAlpha</ref>
547
			<ref type="application">SayAlpha</ref>
548
			<ref type="application">SayDigits</ref>
548
			<ref type="application">SayDigits</ref>
549
			<ref type="application">SayPhonetic</ref>
549
			<ref type="application">SayPhonetic</ref>
550
			<ref type="function">CHANNEL</ref>
550
			<ref type="function">CHANNEL</ref>
551
		</see-also>
551
		</see-also>
552
	</application>
552
	</application>
553
	<application name="SayPhonetic" language="en_US">
553
	<application name="SayPhonetic" language="en_US">
554
		<synopsis>
554
		<synopsis>
555
			Say Phonetic.
555
			Say Phonetic.
556
		</synopsis>
556
		</synopsis>
557
		<syntax>
557
		<syntax>
558
			<parameter name="string" required="true" />
558
			<parameter name="string" required="true" />
559
		</syntax>
559
		</syntax>
560
		<description>
560
		<description>
561
			<para>This application will play the sounds from the phonetic alphabet that correspond to the
561
			<para>This application will play the sounds from the phonetic alphabet that correspond to the
562
			letters in the given <replaceable>string</replaceable>.</para>
562
			letters in the given <replaceable>string</replaceable>.</para>
563
		</description>
563
		</description>
564
		<see-also>
564
		<see-also>
565
			<ref type="application">SayAlpha</ref>
565
			<ref type="application">SayAlpha</ref>
566
			<ref type="application">SayDigits</ref>
566
			<ref type="application">SayDigits</ref>
567
			<ref type="application">SayNumber</ref>
567
			<ref type="application">SayNumber</ref>
568
		</see-also>
568
		</see-also>
569
	</application>
569
	</application>
570
	<application name="Set" language="en_US">
570
	<application name="Set" language="en_US">
571
		<synopsis>
571
		<synopsis>
572
			Set channel variable or function value.
572
			Set channel variable or function value.
573
		</synopsis>
573
		</synopsis>
574
		<syntax argsep="=">
574
		<syntax argsep="=">
575
			<parameter name="name" required="true" />
575
			<parameter name="name" required="true" />
576
			<parameter name="value" required="true" />
576
			<parameter name="value" required="true" />
577
		</syntax>
577
		</syntax>
578
		<description>
578
		<description>
579
			<para>This function can be used to set the value of channel variables or dialplan functions.
579
			<para>This function can be used to set the value of channel variables or dialplan functions.
580
			When setting variables, if the variable name is prefixed with <literal>_</literal>,
580
			When setting variables, if the variable name is prefixed with <literal>_</literal>,
581
			the variable will be inherited into channels created from the current channel.
581
			the variable will be inherited into channels created from the current channel.
582
			If the variable name is prefixed with <literal>__</literal>, the variable will be
582
			If the variable name is prefixed with <literal>__</literal>, the variable will be
583
			inherited into channels created from the current channel and all children channels.</para>
583
			inherited into channels created from the current channel and all children channels.</para>
584
			<note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
584
			<note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
585
			a <literal>[compat]</literal> category, and you have <literal>app_set = 1.6</literal> under that,then
585
			a <literal>[compat]</literal> category, and you have <literal>app_set = 1.6</literal> under that,then
586
			the behavior of this app changes, and does not strip surrounding quotes from the right hand side as
586
			the behavior of this app changes, and does not strip surrounding quotes from the right hand side as
587
			it did previously in 1.4. The <literal>app_set = 1.6</literal> is only inserted if <literal>make samples</literal>
587
			it did previously in 1.4. The <literal>app_set = 1.6</literal> is only inserted if <literal>make samples</literal>
588
			is executed, or if users insert this by hand into the <filename>asterisk.conf</filename> file.
588
			is executed, or if users insert this by hand into the <filename>asterisk.conf</filename> file.
589
			The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
589
			The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
590
			were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
590
			were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
591
			protect separators and quotes in various database access strings has been greatly
591
			protect separators and quotes in various database access strings has been greatly
592
			reduced by these changes.</para></note>
592
			reduced by these changes.</para></note>
593
		</description>
593
		</description>
594
		<see-also>
594
		<see-also>
595
			<ref type="application">MSet</ref>
595
			<ref type="application">MSet</ref>
596
			<ref type="function">GLOBAL</ref>
596
			<ref type="function">GLOBAL</ref>
597
			<ref type="function">SET</ref>
597
			<ref type="function">SET</ref>
598
			<ref type="function">ENV</ref>
598
			<ref type="function">ENV</ref>
599
		</see-also>
599
		</see-also>
600
	</application>
600
	</application>
601
	<application name="MSet" language="en_US">
601
	<application name="MSet" language="en_US">
602
		<synopsis>
602
		<synopsis>
603
			Set channel variable(s) or function value(s).
603
			Set channel variable(s) or function value(s).
604
		</synopsis>
604
		</synopsis>
605
		<syntax>
605
		<syntax>
606
			<parameter name="set1" required="true" argsep="=">
606
			<parameter name="set1" required="true" argsep="=">
607
				<argument name="name1" required="true" />
607
				<argument name="name1" required="true" />
608
				<argument name="value1" required="true" />
608
				<argument name="value1" required="true" />
609
			</parameter>
609
			</parameter>
610
			<parameter name="set2" multiple="true" argsep="=">
610
			<parameter name="set2" multiple="true" argsep="=">
611
				<argument name="name2" required="true" />
611
				<argument name="name2" required="true" />
612
				<argument name="value2" required="true" />
612
				<argument name="value2" required="true" />
613
			</parameter>
613
			</parameter>
614
		</syntax>
614
		</syntax>
615
		<description>
615
		<description>
616
			<para>This function can be used to set the value of channel variables or dialplan functions.
616
			<para>This function can be used to set the value of channel variables or dialplan functions.
617
			When setting variables, if the variable name is prefixed with <literal>_</literal>,
617
			When setting variables, if the variable name is prefixed with <literal>_</literal>,
618
			the variable will be inherited into channels created from the current channel
618
			the variable will be inherited into channels created from the current channel
619
			If the variable name is prefixed with <literal>__</literal>, the variable will be
619
			If the variable name is prefixed with <literal>__</literal>, the variable will be
620
			inherited into channels created from the current channel and all children channels.
620
			inherited into channels created from the current channel and all children channels.
621
			MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
621
			MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
622
			prone to doing things that you may not expect. For example, it strips surrounding
622
			prone to doing things that you may not expect. For example, it strips surrounding
623
			double-quotes from the right-hand side (value). If you need to put a separator
623
			double-quotes from the right-hand side (value). If you need to put a separator
624
			character (comma or vert-bar), you will need to escape them by inserting a backslash
624
			character (comma or vert-bar), you will need to escape them by inserting a backslash
625
			before them. Avoid its use if possible.</para>
625
			before them. Avoid its use if possible.</para>
626
		</description>
626
		</description>
627
		<see-also>
627
		<see-also>
628
			<ref type="application">Set</ref>
628
			<ref type="application">Set</ref>
629
		</see-also>
629
		</see-also>
630
	</application>
630
	</application>
631
	<application name="SetAMAFlags" language="en_US">
631
	<application name="SetAMAFlags" language="en_US">
632
		<synopsis>
632
		<synopsis>
633
			Set the AMA Flags.
633
			Set the AMA Flags.
634
		</synopsis>
634
		</synopsis>
635
		<syntax>
635
		<syntax>
636
			<parameter name="flag" />
636
			<parameter name="flag" />
637
		</syntax>
637
		</syntax>
638
		<description>
638
		<description>
639
			<para>This application will set the channel's AMA Flags for billing purposes.</para>
639
			<para>This application will set the channel's AMA Flags for billing purposes.</para>
640
		</description>
640
		</description>
641
		<see-also>
641
		<see-also>
642
			<ref type="function">CDR</ref>
642
			<ref type="function">CDR</ref>
643
		</see-also>
643
		</see-also>
644
	</application>
644
	</application>
645
	<application name="Wait" language="en_US">
645
	<application name="Wait" language="en_US">
646
		<synopsis>
646
		<synopsis>
647
			Waits for some time.
647
			Waits for some time.
648
		</synopsis>
648
		</synopsis>
649
		<syntax>
649
		<syntax>
650
			<parameter name="seconds" required="true">
650
			<parameter name="seconds" required="true">
651
				<para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
651
				<para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
652
				application to wait for 1.5 seconds.</para>
652
				application to wait for 1.5 seconds.</para>
653
			</parameter>
653
			</parameter>
654
		</syntax>
654
		</syntax>
655
		<description>
655
		<description>
656
			<para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
656
			<para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
657
		</description>
657
		</description>
658
	</application>
658
	</application>
659
	<application name="WaitExten" language="en_US">
659
	<application name="WaitExten" language="en_US">
660
		<synopsis>
660
		<synopsis>
661
			Waits for an extension to be entered.
661
			Waits for an extension to be entered.
662
		</synopsis>
662
		</synopsis>
663
		<syntax>
663
		<syntax>
664
			<parameter name="seconds">
664
			<parameter name="seconds">
665
				<para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
665
				<para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
666
				application to wait for 1.5 seconds.</para>
666
				application to wait for 1.5 seconds.</para>
667
			</parameter>
667
			</parameter>
668
			<parameter name="options">
668
			<parameter name="options">
669
				<optionlist>
669
				<optionlist>
670
					<option name="m">
670
					<option name="m">
671
						<para>Provide music on hold to the caller while waiting for an extension.</para>
671
						<para>Provide music on hold to the caller while waiting for an extension.</para>
672
						<argument name="x">
672
						<argument name="x">
673
							<para>Specify the class for music on hold.</para>
673
							<para>Specify the class for music on hold.</para>
674
						</argument>
674
						</argument>
675
					</option>
675
					</option>
676
				</optionlist>
676
				</optionlist>
677
			</parameter>
677
			</parameter>
678
		</syntax>
678
		</syntax>
679
		<description>
679
		<description>
680
			<para>This application waits for the user to enter a new extension for a specified number
680
			<para>This application waits for the user to enter a new extension for a specified number
681
			of <replaceable>seconds</replaceable>.</para>
681
			of <replaceable>seconds</replaceable>.</para>
682
		</description>
682
		</description>
683
		<see-also>
683
		<see-also>
684
			<ref type="application">Background</ref>
684
			<ref type="application">Background</ref>
685
			<ref type="function">TIMEOUT</ref>
685
			<ref type="function">TIMEOUT</ref>
686
		</see-also>
686
		</see-also>
687
	</application>
687
	</application>
688
	<function name="EXCEPTION" language="en_US">
688
	<function name="EXCEPTION" language="en_US">
689
		<synopsis>
689
		<synopsis>
690
			Retrieve the details of the current dialplan exception.
690
			Retrieve the details of the current dialplan exception.
691
		</synopsis>
691
		</synopsis>
692
		<syntax>
692
		<syntax>
693
			<parameter name="field" required="true">
693
			<parameter name="field" required="true">
694
				<para>The following fields are available for retrieval:</para>
694
				<para>The following fields are available for retrieval:</para>
695
				<enumlist>
695
				<enumlist>
696
					<enum name="reason">
696
					<enum name="reason">
697
						<para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom
697
						<para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom
698
						value set by the RaiseException() application</para>
698
						value set by the RaiseException() application</para>
699
					</enum>
699
					</enum>
700
					<enum name="context">
700
					<enum name="context">
701
						<para>The context executing when the exception occurred.</para>
701
						<para>The context executing when the exception occurred.</para>
702
					</enum>
702
					</enum>
703
					<enum name="exten">
703
					<enum name="exten">
704
						<para>The extension executing when the exception occurred.</para>
704
						<para>The extension executing when the exception occurred.</para>
705
					</enum>
705
					</enum>
706
					<enum name="priority">
706
					<enum name="priority">
707
						<para>The numeric priority executing when the exception occurred.</para>
707
						<para>The numeric priority executing when the exception occurred.</para>
708
					</enum>
708
					</enum>
709
				</enumlist>
709
				</enumlist>
710
			</parameter>
710
			</parameter>
711
		</syntax>
711
		</syntax>
712
		<description>
712
		<description>
713
			<para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para>
713
			<para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para>
714
		</description>
714
		</description>
715
		<see-also>
715
		<see-also>
716
			<ref type="application">RaiseException</ref>
716
			<ref type="application">RaiseException</ref>
717
		</see-also>
717
		</see-also>
718
	</function>
718
	</function>
719
 ***/
719
 ***/
720

    
   
720

   
721
#ifdef LOW_MEMORY
721
#ifdef LOW_MEMORY
722
#define EXT_DATA_SIZE 256
722
#define EXT_DATA_SIZE 256
723
#else
723
#else
724
#define EXT_DATA_SIZE 8192
724
#define EXT_DATA_SIZE 8192
725
#endif
725
#endif
726

    
   
726

   
727
#define SWITCH_DATA_LENGTH 256
727
#define SWITCH_DATA_LENGTH 256
728

    
   
728

   
729
#define VAR_BUF_SIZE 4096
729
#define VAR_BUF_SIZE 4096
730

    
   
730

   
731
#define	VAR_NORMAL		1
731
#define	VAR_NORMAL		1
732
#define	VAR_SOFTTRAN	2
732
#define	VAR_SOFTTRAN	2
733
#define	VAR_HARDTRAN	3
733
#define	VAR_HARDTRAN	3
734

    
   
734

   
735
#define BACKGROUND_SKIP		(1 << 0)
735
#define BACKGROUND_SKIP		(1 << 0)
736
#define BACKGROUND_NOANSWER	(1 << 1)
736
#define BACKGROUND_NOANSWER	(1 << 1)
737
#define BACKGROUND_MATCHEXTEN	(1 << 2)
737
#define BACKGROUND_MATCHEXTEN	(1 << 2)
738
#define BACKGROUND_PLAYBACK	(1 << 3)
738
#define BACKGROUND_PLAYBACK	(1 << 3)
739

    
   
739

   
740
AST_APP_OPTIONS(background_opts, {
740
AST_APP_OPTIONS(background_opts, {
741
	AST_APP_OPTION('s', BACKGROUND_SKIP),
741
	AST_APP_OPTION('s', BACKGROUND_SKIP),
742
	AST_APP_OPTION('n', BACKGROUND_NOANSWER),
742
	AST_APP_OPTION('n', BACKGROUND_NOANSWER),
743
	AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
743
	AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
744
	AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
744
	AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
745
});
745
});
746

    
   
746

   
747
#define WAITEXTEN_MOH		(1 << 0)
747
#define WAITEXTEN_MOH		(1 << 0)
748
#define WAITEXTEN_DIALTONE	(1 << 1)
748
#define WAITEXTEN_DIALTONE	(1 << 1)
749

    
   
749

   
750
AST_APP_OPTIONS(waitexten_opts, {
750
AST_APP_OPTIONS(waitexten_opts, {
751
	AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
751
	AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
752
	AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
752
	AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
753
});
753
});
754

    
   
754

   
755
struct ast_context;
755
struct ast_context;
756
struct ast_app;
756
struct ast_app;
757

    
   
757

   
758
static struct ast_taskprocessor *device_state_tps;
758
static struct ast_taskprocessor *device_state_tps;
759

    
   
759

   
760
AST_THREADSTORAGE(switch_data);
760
AST_THREADSTORAGE(switch_data);
761
AST_THREADSTORAGE(extensionstate_buf);
761
AST_THREADSTORAGE(extensionstate_buf);
762

    
   
762

   
763
/*!
763
/*!
764
   \brief ast_exten: An extension
764
   \brief ast_exten: An extension
765
	The dialplan is saved as a linked list with each context
765
	The dialplan is saved as a linked list with each context
766
	having it's own linked list of extensions - one item per
766
	having it's own linked list of extensions - one item per
767
	priority.
767
	priority.
768
*/
768
*/
769
struct ast_exten {
769
struct ast_exten {
770
	char *exten;			/*!< Extension name */
770
	char *exten;			/*!< Extension name */
771
	int matchcid;			/*!< Match caller id ? */
771
	int matchcid;			/*!< Match caller id ? */
772
	const char *cidmatch;		/*!< Caller id to match for this extension */
772
	const char *cidmatch;		/*!< Caller id to match for this extension */
773
	int priority;			/*!< Priority */
773
	int priority;			/*!< Priority */
774
	const char *label;		/*!< Label */
774
	const char *label;		/*!< Label */
775
	struct ast_context *parent;	/*!< The context this extension belongs to  */
775
	struct ast_context *parent;	/*!< The context this extension belongs to  */
776
	const char *app;		/*!< Application to execute */
776
	const char *app;		/*!< Application to execute */
777
	struct ast_app *cached_app;     /*!< Cached location of application */
777
	struct ast_app *cached_app;     /*!< Cached location of application */
778
	void *data;			/*!< Data to use (arguments) */
778
	void *data;			/*!< Data to use (arguments) */
779
	void (*datad)(void *);		/*!< Data destructor */
779
	void (*datad)(void *);		/*!< Data destructor */
780
	struct ast_exten *peer;		/*!< Next higher priority with our extension */
780
	struct ast_exten *peer;		/*!< Next higher priority with our extension */
781
	struct ast_hashtab *peer_table;    /*!< Priorities list in hashtab form -- only on the head of the peer list */
781
	struct ast_hashtab *peer_table;    /*!< Priorities list in hashtab form -- only on the head of the peer list */
782
	struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
782
	struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
783
	const char *registrar;		/*!< Registrar */
783
	const char *registrar;		/*!< Registrar */
784
	struct ast_exten *next;		/*!< Extension with a greater ID */
784
	struct ast_exten *next;		/*!< Extension with a greater ID */
785
	char stuff[0];
785
	char stuff[0];
786
};
786
};
787

    
   
787

   
788
/*! \brief ast_include: include= support in extensions.conf */
788
/*! \brief ast_include: include= support in extensions.conf */
789
struct ast_include {
789
struct ast_include {
790
	const char *name;
790
	const char *name;
791
	const char *rname;			/*!< Context to include */
791
	const char *rname;			/*!< Context to include */
792
	const char *registrar;			/*!< Registrar */
792
	const char *registrar;			/*!< Registrar */
793
	int hastime;				/*!< If time construct exists */
793
	int hastime;				/*!< If time construct exists */
794
	struct ast_timing timing;               /*!< time construct */
794
	struct ast_timing timing;               /*!< time construct */
795
	struct ast_include *next;		/*!< Link them together */
795
	struct ast_include *next;		/*!< Link them together */
796
	char stuff[0];
796
	char stuff[0];
797
};
797
};
798

    
   
798

   
799
/*! \brief ast_sw: Switch statement in extensions.conf */
799
/*! \brief ast_sw: Switch statement in extensions.conf */
800
struct ast_sw {
800
struct ast_sw {
801
	char *name;
801
	char *name;
802
	const char *registrar;			/*!< Registrar */
802
	const char *registrar;			/*!< Registrar */
803
	char *data;				/*!< Data load */
803
	char *data;				/*!< Data load */
804
	int eval;
804
	int eval;
805
	AST_LIST_ENTRY(ast_sw) list;
805
	AST_LIST_ENTRY(ast_sw) list;
806
	char stuff[0];
806
	char stuff[0];
807
};
807
};
808

    
   
808

   
809
/*! \brief ast_ignorepat: Ignore patterns in dial plan */
809
/*! \brief ast_ignorepat: Ignore patterns in dial plan */
810
struct ast_ignorepat {
810
struct ast_ignorepat {
811
	const char *registrar;
811
	const char *registrar;
812
	struct ast_ignorepat *next;
812
	struct ast_ignorepat *next;
813
	const char pattern[0];
813
	const char pattern[0];
814
};
814
};
815

    
   
815

   
816
/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
816
/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
817
struct match_char
817
struct match_char
818
{
818
{
819
	int is_pattern; /* the pattern started with '_' */
819
	int is_pattern; /* the pattern started with '_' */
820
	int deleted;    /* if this is set, then... don't return it */
820
	int deleted;    /* if this is set, then... don't return it */
821
	char *x;       /* the pattern itself-- matches a single char */

   
822
	int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
821
	int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
823
	struct match_char *alt_char;
822
	struct match_char *alt_char;
824
	struct match_char *next_char;
823
	struct match_char *next_char;
825
	struct ast_exten *exten; /* attached to last char of a pattern for exten */
824
	struct ast_exten *exten; /* attached to last char of a pattern for exten */

    
   
825
	char x[1];       /* the pattern itself-- matches a single char */
826
};
826
};
827

    
   
827

   
828
struct scoreboard  /* make sure all fields are 0 before calling new_find_extension */
828
struct scoreboard  /* make sure all fields are 0 before calling new_find_extension */
829
{
829
{
830
	int total_specificity;
830
	int total_specificity;
831
	int total_length;
831
	int total_length;
832
	char last_char;   /* set to ! or . if they are the end of the pattern */
832
	char last_char;   /* set to ! or . if they are the end of the pattern */
833
	int canmatch;     /* if the string to match was just too short */
833
	int canmatch;     /* if the string to match was just too short */
834
	struct match_char *node;
834
	struct match_char *node;
835
	struct ast_exten *canmatch_exten;
835
	struct ast_exten *canmatch_exten;
836
	struct ast_exten *exten;
836
	struct ast_exten *exten;
837
};
837
};
838

    
   
838

   
839
/*! \brief ast_context: An extension context */
839
/*! \brief ast_context: An extension context */
840
struct ast_context {
840
struct ast_context {
841
	ast_rwlock_t lock;			/*!< A lock to prevent multiple threads from clobbering the context */
841
	ast_rwlock_t lock;			/*!< A lock to prevent multiple threads from clobbering the context */
842
	struct ast_exten *root;			/*!< The root of the list of extensions */
842
	struct ast_exten *root;			/*!< The root of the list of extensions */
843
	struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
843
	struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
844
	struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
844
	struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
845
	struct ast_context *next;		/*!< Link them together */
845
	struct ast_context *next;		/*!< Link them together */
846
	struct ast_include *includes;		/*!< Include other contexts */
846
	struct ast_include *includes;		/*!< Include other contexts */
847
	struct ast_ignorepat *ignorepats;	/*!< Patterns for which to continue playing dialtone */
847
	struct ast_ignorepat *ignorepats;	/*!< Patterns for which to continue playing dialtone */
848
	char *registrar;			/*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
848
	char *registrar;			/*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
849
	int refcount;                   /*!< each module that would have created this context should inc/dec this as appropriate */
849
	int refcount;                   /*!< each module that would have created this context should inc/dec this as appropriate */
850
	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;	/*!< Alternative switches */
850
	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;	/*!< Alternative switches */
851
	ast_mutex_t macrolock;			/*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
851
	ast_mutex_t macrolock;			/*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
852
	char name[0];				/*!< Name of the context */
852
	char name[0];				/*!< Name of the context */
853
};
853
};
854

    
   
854

   
855
/*! \brief ast_app: A registered application */
855
/*! \brief ast_app: A registered application */
856
struct ast_app {
856
struct ast_app {
857
	int (*execute)(struct ast_channel *chan, void *data);
857
	int (*execute)(struct ast_channel *chan, void *data);
858
	AST_DECLARE_STRING_FIELDS(
858
	AST_DECLARE_STRING_FIELDS(
859
		AST_STRING_FIELD(synopsis);     /*!< Synopsis text for 'show applications' */
859
		AST_STRING_FIELD(synopsis);     /*!< Synopsis text for 'show applications' */
860
		AST_STRING_FIELD(description);  /*!< Description (help text) for 'show application &lt;name&gt;' */
860
		AST_STRING_FIELD(description);  /*!< Description (help text) for 'show application &lt;name&gt;' */
861
		AST_STRING_FIELD(syntax);       /*!< Syntax text for 'core show applications' */
861
		AST_STRING_FIELD(syntax);       /*!< Syntax text for 'core show applications' */
862
		AST_STRING_FIELD(arguments);    /*!< Arguments description */
862
		AST_STRING_FIELD(arguments);    /*!< Arguments description */
863
		AST_STRING_FIELD(seealso);      /*!< See also */
863
		AST_STRING_FIELD(seealso);      /*!< See also */
864
	);
864
	);
865
	enum ast_doc_src docsrc;/*!< Where the documentation come from. */
865
	enum ast_doc_src docsrc;/*!< Where the documentation come from. */
866
	AST_RWLIST_ENTRY(ast_app) list;		/*!< Next app in list */
866
	AST_RWLIST_ENTRY(ast_app) list;		/*!< Next app in list */
867
	struct ast_module *module;		/*!< Module this app belongs to */
867
	struct ast_module *module;		/*!< Module this app belongs to */
868
	char name[0];				/*!< Name of the application */
868
	char name[0];				/*!< Name of the application */
869
};
869
};
870

    
   
870

   
871
/*! \brief ast_state_cb: An extension state notify register item */
871
/*! \brief ast_state_cb: An extension state notify register item */
872
struct ast_state_cb {
872
struct ast_state_cb {
873
	int id;
873
	int id;
874
	void *data;
874
	void *data;
875
	ast_state_cb_type callback;
875
	ast_state_cb_type callback;
876
	AST_LIST_ENTRY(ast_state_cb) entry;
876
	AST_LIST_ENTRY(ast_state_cb) entry;
877
};
877
};
878

    
   
878

   
879
/*! \brief Structure for dial plan hints
879
/*! \brief Structure for dial plan hints
880

    
   
880

   
881
  \note Hints are pointers from an extension in the dialplan to one or
881
  \note Hints are pointers from an extension in the dialplan to one or
882
  more devices (tech/name)
882
  more devices (tech/name)
883
	- See \ref AstExtState
883
	- See \ref AstExtState
884
*/
884
*/
885
struct ast_hint {
885
struct ast_hint {
886
	struct ast_exten *exten;	/*!< Extension */
886
	struct ast_exten *exten;	/*!< Extension */
887
	int laststate;			/*!< Last known state */
887
	int laststate;			/*!< Last known state */
888
	AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks; /*!< Callback list for this extension */
888
	AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks; /*!< Callback list for this extension */
889
	AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
889
	AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
890
};
890
};
891

    
   
891

   
892
static const struct cfextension_states {
892
static const struct cfextension_states {
893
	int extension_state;
893
	int extension_state;
894
	const char * const text;
894
	const char * const text;
895
} extension_states[] = {
895
} extension_states[] = {
896
	{ AST_EXTENSION_NOT_INUSE,                     "Idle" },
896
	{ AST_EXTENSION_NOT_INUSE,                     "Idle" },
897
	{ AST_EXTENSION_INUSE,                         "InUse" },
897
	{ AST_EXTENSION_INUSE,                         "InUse" },
898
	{ AST_EXTENSION_BUSY,                          "Busy" },
898
	{ AST_EXTENSION_BUSY,                          "Busy" },
899
	{ AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
899
	{ AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
900
	{ AST_EXTENSION_RINGING,                       "Ringing" },
900
	{ AST_EXTENSION_RINGING,                       "Ringing" },
901
	{ AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
901
	{ AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
902
	{ AST_EXTENSION_ONHOLD,                        "Hold" },
902
	{ AST_EXTENSION_ONHOLD,                        "Hold" },
903
	{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
903
	{ AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
904
};
904
};
905

    
   
905

   
906
struct statechange {
906
struct statechange {
907
	AST_LIST_ENTRY(statechange) entry;
907
	AST_LIST_ENTRY(statechange) entry;
908
	char dev[0];
908
	char dev[0];
909
};
909
};
910

    
   
910

   
911
struct pbx_exception {
911
struct pbx_exception {
912
	AST_DECLARE_STRING_FIELDS(
912
	AST_DECLARE_STRING_FIELDS(
913
		AST_STRING_FIELD(context);	/*!< Context associated with this exception */
913
		AST_STRING_FIELD(context);	/*!< Context associated with this exception */
914
		AST_STRING_FIELD(exten);	/*!< Exten associated with this exception */
914
		AST_STRING_FIELD(exten);	/*!< Exten associated with this exception */
915
		AST_STRING_FIELD(reason);		/*!< The exception reason */
915
		AST_STRING_FIELD(reason);		/*!< The exception reason */
916
	);
916
	);
917

    
   
917

   
918
	int priority;				/*!< Priority associated with this exception */
918
	int priority;				/*!< Priority associated with this exception */
919
};
919
};
920

    
   
920

   
921
static int pbx_builtin_answer(struct ast_channel *, void *);
921
static int pbx_builtin_answer(struct ast_channel *, void *);
922
static int pbx_builtin_goto(struct ast_channel *, void *);
922
static int pbx_builtin_goto(struct ast_channel *, void *);
923
static int pbx_builtin_hangup(struct ast_channel *, void *);
923
static int pbx_builtin_hangup(struct ast_channel *, void *);
924
static int pbx_builtin_background(struct ast_channel *, void *);
924
static int pbx_builtin_background(struct ast_channel *, void *);
925
static int pbx_builtin_wait(struct ast_channel *, void *);
925
static int pbx_builtin_wait(struct ast_channel *, void *);
926
static int pbx_builtin_waitexten(struct ast_channel *, void *);
926
static int pbx_builtin_waitexten(struct ast_channel *, void *);
927
static int pbx_builtin_incomplete(struct ast_channel *, void *);
927
static int pbx_builtin_incomplete(struct ast_channel *, void *);
928
static int pbx_builtin_resetcdr(struct ast_channel *, void *);
928
static int pbx_builtin_resetcdr(struct ast_channel *, void *);
929
static int pbx_builtin_setamaflags(struct ast_channel *, void *);
929
static int pbx_builtin_setamaflags(struct ast_channel *, void *);
930
static int pbx_builtin_ringing(struct ast_channel *, void *);
930
static int pbx_builtin_ringing(struct ast_channel *, void *);
931
static int pbx_builtin_proceeding(struct ast_channel *, void *);
931
static int pbx_builtin_proceeding(struct ast_channel *, void *);
932
static int pbx_builtin_progress(struct ast_channel *, void *);
932
static int pbx_builtin_progress(struct ast_channel *, void *);
933
static int pbx_builtin_congestion(struct ast_channel *, void *);
933
static int pbx_builtin_congestion(struct ast_channel *, void *);
934
static int pbx_builtin_busy(struct ast_channel *, void *);
934
static int pbx_builtin_busy(struct ast_channel *, void *);
935
static int pbx_builtin_noop(struct ast_channel *, void *);
935
static int pbx_builtin_noop(struct ast_channel *, void *);
936
static int pbx_builtin_gotoif(struct ast_channel *, void *);
936
static int pbx_builtin_gotoif(struct ast_channel *, void *);
937
static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
937
static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
938
static int pbx_builtin_execiftime(struct ast_channel *, void *);
938
static int pbx_builtin_execiftime(struct ast_channel *, void *);
939
static int pbx_builtin_saynumber(struct ast_channel *, void *);
939
static int pbx_builtin_saynumber(struct ast_channel *, void *);
940
static int pbx_builtin_saydigits(struct ast_channel *, void *);
940
static int pbx_builtin_saydigits(struct ast_channel *, void *);
941
static int pbx_builtin_saycharacters(struct ast_channel *, void *);
941
static int pbx_builtin_saycharacters(struct ast_channel *, void *);
942
static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
942
static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
943
static int matchcid(const char *cidpattern, const char *callerid);
943
static int matchcid(const char *cidpattern, const char *callerid);
944
int pbx_builtin_setvar(struct ast_channel *, void *);
944
int pbx_builtin_setvar(struct ast_channel *, void *);
945
void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
945
void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
946
int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
946
int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
947
static int pbx_builtin_importvar(struct ast_channel *, void *);
947
static int pbx_builtin_importvar(struct ast_channel *, void *);
948
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
948
static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
949
static void new_find_extension(const char *str, struct scoreboard *score,
949
static void new_find_extension(const char *str, struct scoreboard *score,
950
		struct match_char *tree, int length, int spec, const char *callerid,
950
		struct match_char *tree, int length, int spec, const char *callerid,
951
		const char *label, enum ext_match_t action);
951
		const char *label, enum ext_match_t action);
952
static struct match_char *already_in_tree(struct match_char *current, char *pat);
952
static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern);
953
static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
953
static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
954
		struct ast_exten *e1, int findonly);
954
		struct ast_exten *e1, int findonly);
955
static struct match_char *add_pattern_node(struct ast_context *con,
955
static struct match_char *add_pattern_node(struct ast_context *con,
956
		struct match_char *current, char *pattern, int is_pattern,
956
		struct match_char *current, char *pattern, int is_pattern,
957
		int already, int specificity, struct match_char **parent);
957
		int already, int specificity, struct match_char **parent);
958
static void create_match_char_tree(struct ast_context *con);
958
static void create_match_char_tree(struct ast_context *con);
959
static struct ast_exten *get_canmatch_exten(struct match_char *node);
959
static struct ast_exten *get_canmatch_exten(struct match_char *node);
960
static void destroy_pattern_tree(struct match_char *pattern_tree);
960
static void destroy_pattern_tree(struct match_char *pattern_tree);
961
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
961
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
962
static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
962
static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
963
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
963
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
964
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
964
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
965
unsigned int ast_hashtab_hash_contexts(const void *obj);
965
unsigned int ast_hashtab_hash_contexts(const void *obj);
966
static unsigned int hashtab_hash_extens(const void *obj);
966
static unsigned int hashtab_hash_extens(const void *obj);
967
static unsigned int hashtab_hash_priority(const void *obj);
967
static unsigned int hashtab_hash_priority(const void *obj);
968
static unsigned int hashtab_hash_labels(const void *obj);
968
static unsigned int hashtab_hash_labels(const void *obj);
969
static void __ast_internal_context_destroy( struct ast_context *con);
969
static void __ast_internal_context_destroy( struct ast_context *con);
970
static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
970
static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
971
	int priority, const char *label, const char *callerid,
971
	int priority, const char *label, const char *callerid,
972
	const char *application, void *data, void (*datad)(void *), const char *registrar);
972
	const char *application, void *data, void (*datad)(void *), const char *registrar);
973
static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
973
static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
974
	struct ast_exten *el, struct ast_exten *e, int replace, int lockhints);
974
	struct ast_exten *el, struct ast_exten *e, int replace, int lockhints);
975
static int ast_add_extension2_lockopt(struct ast_context *con,
975
static int ast_add_extension2_lockopt(struct ast_context *con,
976
	int replace, const char *extension, int priority, const char *label, const char *callerid,
976
	int replace, const char *extension, int priority, const char *label, const char *callerid,
977
	const char *application, void *data, void (*datad)(void *),
977
	const char *application, void *data, void (*datad)(void *),
978
	const char *registrar, int lockconts, int lockhints);
978
	const char *registrar, int lockconts, int lockhints);
979

    
   
979

   
980
/* a func for qsort to use to sort a char array */
980
/* a func for qsort to use to sort a char array */
981
static int compare_char(const void *a, const void *b)
981
static int compare_char(const void *a, const void *b)
982
{
982
{
983
	const char *ac = a;
983
	const char *ac = a;
984
	const char *bc = b;
984
	const char *bc = b;
985
	if ((*ac) < (*bc))
985
	if ((*ac) < (*bc))
986
		return -1;
986
		return -1;
987
	else if ((*ac) == (*bc))
987
	else if ((*ac) == (*bc))
988
		return 0;
988
		return 0;
989
	else
989
	else
990
		return 1;
990
		return 1;
991
}
991
}
992

    
   
992

   
993
/* labels, contexts are case sensitive  priority numbers are ints */
993
/* labels, contexts are case sensitive  priority numbers are ints */
994
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
994
int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
995
{
995
{
996
	const struct ast_context *ac = ah_a;
996
	const struct ast_context *ac = ah_a;
997
	const struct ast_context *bc = ah_b;
997
	const struct ast_context *bc = ah_b;
998
	if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
998
	if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
999
		return 1;
999
		return 1;
1000
	/* assume context names are registered in a string table! */
1000
	/* assume context names are registered in a string table! */
1001
	return strcmp(ac->name, bc->name);
1001
	return strcmp(ac->name, bc->name);
1002
}
1002
}
1003

    
   
1003

   
1004
static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
1004
static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
1005
{
1005
{
1006
	const struct ast_exten *ac = ah_a;
1006
	const struct ast_exten *ac = ah_a;
1007
	const struct ast_exten *bc = ah_b;
1007
	const struct ast_exten *bc = ah_b;
1008
	int x = strcmp(ac->exten, bc->exten);
1008
	int x = strcmp(ac->exten, bc->exten);
1009
	if (x) { /* if exten names are diff, then return */
1009
	if (x) { /* if exten names are diff, then return */
1010
		return x;
1010
		return x;
1011
	}
1011
	}
1012

    
   
1012

   
1013
	/* but if they are the same, do the cidmatch values match? */
1013
	/* but if they are the same, do the cidmatch values match? */
1014
	if (ac->matchcid && bc->matchcid) {
1014
	if (ac->matchcid && bc->matchcid) {
1015
		return strcmp(ac->cidmatch,bc->cidmatch);
1015
		return strcmp(ac->cidmatch,bc->cidmatch);
1016
	} else if (!ac->matchcid && !bc->matchcid) {
1016
	} else if (!ac->matchcid && !bc->matchcid) {
1017
		return 0; /* if there's no matchcid on either side, then this is a match */
1017
		return 0; /* if there's no matchcid on either side, then this is a match */
1018
	} else {
1018
	} else {
1019
		return 1; /* if there's matchcid on one but not the other, they are different */
1019
		return 1; /* if there's matchcid on one but not the other, they are different */
1020
	}
1020
	}
1021
}
1021
}
1022

    
   
1022

   
1023
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
1023
static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
1024
{
1024
{
1025
	const struct ast_exten *ac = ah_a;
1025
	const struct ast_exten *ac = ah_a;
1026
	const struct ast_exten *bc = ah_b;
1026
	const struct ast_exten *bc = ah_b;
1027
	return ac->priority != bc->priority;
1027
	return ac->priority != bc->priority;
1028
}
1028
}
1029

    
   
1029

   
1030
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
1030
static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
1031
{
1031
{
1032
	const struct ast_exten *ac = ah_a;
1032
	const struct ast_exten *ac = ah_a;
1033
	const struct ast_exten *bc = ah_b;
1033
	const struct ast_exten *bc = ah_b;
1034
	return strcmp(ac->label, bc->label);
1034
	return strcmp(ac->label, bc->label);
1035
}
1035
}
1036

    
   
1036

   
1037
unsigned int ast_hashtab_hash_contexts(const void *obj)
1037
unsigned int ast_hashtab_hash_contexts(const void *obj)
1038
{
1038
{
1039
	const struct ast_context *ac = obj;
1039
	const struct ast_context *ac = obj;
1040
	return ast_hashtab_hash_string(ac->name);
1040
	return ast_hashtab_hash_string(ac->name);
1041
}
1041
}
1042

    
   
1042

   
1043
static unsigned int hashtab_hash_extens(const void *obj)
1043
static unsigned int hashtab_hash_extens(const void *obj)
1044
{
1044
{
1045
	const struct ast_exten *ac = obj;
1045
	const struct ast_exten *ac = obj;
1046
	unsigned int x = ast_hashtab_hash_string(ac->exten);
1046
	unsigned int x = ast_hashtab_hash_string(ac->exten);
1047
	unsigned int y = 0;
1047
	unsigned int y = 0;
1048
	if (ac->matchcid)
1048
	if (ac->matchcid)
1049
		y = ast_hashtab_hash_string(ac->cidmatch);
1049
		y = ast_hashtab_hash_string(ac->cidmatch);
1050
	return x+y;
1050
	return x+y;
1051
}
1051
}
1052

    
   
1052

   
1053
static unsigned int hashtab_hash_priority(const void *obj)
1053
static unsigned int hashtab_hash_priority(const void *obj)
1054
{
1054
{
1055
	const struct ast_exten *ac = obj;
1055
	const struct ast_exten *ac = obj;
1056
	return ast_hashtab_hash_int(ac->priority);
1056
	return ast_hashtab_hash_int(ac->priority);
1057
}
1057
}
1058

    
   
1058

   
1059
static unsigned int hashtab_hash_labels(const void *obj)
1059
static unsigned int hashtab_hash_labels(const void *obj)
1060
{
1060
{
1061
	const struct ast_exten *ac = obj;
1061
	const struct ast_exten *ac = obj;
1062
	return ast_hashtab_hash_string(ac->label);
1062
	return ast_hashtab_hash_string(ac->label);
1063
}
1063
}
1064

    
   
1064

   
1065

    
   
1065

   
1066
AST_RWLOCK_DEFINE_STATIC(globalslock);
1066
AST_RWLOCK_DEFINE_STATIC(globalslock);
1067
static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1067
static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
1068

    
   
1068

   
1069
static int autofallthrough = 1;
1069
static int autofallthrough = 1;
1070
static int extenpatternmatchnew = 0;
1070
static int extenpatternmatchnew = 0;
1071
static char *overrideswitch = NULL;
1071
static char *overrideswitch = NULL;
1072

    
   
1072

   
1073
/*! \brief Subscription for device state change events */
1073
/*! \brief Subscription for device state change events */
1074
static struct ast_event_sub *device_state_sub;
1074
static struct ast_event_sub *device_state_sub;
1075

    
   
1075

   
1076
AST_MUTEX_DEFINE_STATIC(maxcalllock);
1076
AST_MUTEX_DEFINE_STATIC(maxcalllock);
1077
static int countcalls;
1077
static int countcalls;
1078
static int totalcalls;
1078
static int totalcalls;
1079

    
   
1079

   
1080
static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
1080
static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
1081

    
   
1081

   
1082
/*! \brief Declaration of builtin applications */
1082
/*! \brief Declaration of builtin applications */
1083
static struct pbx_builtin {
1083
static struct pbx_builtin {
1084
	char name[AST_MAX_APP];
1084
	char name[AST_MAX_APP];
1085
	int (*execute)(struct ast_channel *chan, void *data);
1085
	int (*execute)(struct ast_channel *chan, void *data);
1086
} builtins[] =
1086
} builtins[] =
1087
{
1087
{
1088
	/* These applications are built into the PBX core and do not
1088
	/* These applications are built into the PBX core and do not
1089
	   need separate modules */
1089
	   need separate modules */
1090

    
   
1090

   
1091
	{ "Answer",         pbx_builtin_answer },
1091
	{ "Answer",         pbx_builtin_answer },
1092
	{ "BackGround",     pbx_builtin_background },
1092
	{ "BackGround",     pbx_builtin_background },
1093
	{ "Busy",           pbx_builtin_busy },
1093
	{ "Busy",           pbx_builtin_busy },
1094
	{ "Congestion",     pbx_builtin_congestion },
1094
	{ "Congestion",     pbx_builtin_congestion },
1095
	{ "ExecIfTime",     pbx_builtin_execiftime },
1095
	{ "ExecIfTime",     pbx_builtin_execiftime },
1096
	{ "Goto",           pbx_builtin_goto },
1096
	{ "Goto",           pbx_builtin_goto },
1097
	{ "GotoIf",         pbx_builtin_gotoif },
1097
	{ "GotoIf",         pbx_builtin_gotoif },
1098
	{ "GotoIfTime",     pbx_builtin_gotoiftime },
1098
	{ "GotoIfTime",     pbx_builtin_gotoiftime },
1099
	{ "ImportVar",      pbx_builtin_importvar },
1099
	{ "ImportVar",      pbx_builtin_importvar },
1100
	{ "Hangup",         pbx_builtin_hangup },
1100
	{ "Hangup",         pbx_builtin_hangup },
1101
	{ "Incomplete",     pbx_builtin_incomplete },
1101
	{ "Incomplete",     pbx_builtin_incomplete },
1102
	{ "NoOp",           pbx_builtin_noop },
1102
	{ "NoOp",           pbx_builtin_noop },
1103
	{ "Proceeding",     pbx_builtin_proceeding },
1103
	{ "Proceeding",     pbx_builtin_proceeding },
1104
	{ "Progress",       pbx_builtin_progress },
1104
	{ "Progress",       pbx_builtin_progress },
1105
	{ "RaiseException", pbx_builtin_raise_exception },
1105
	{ "RaiseException", pbx_builtin_raise_exception },
1106
	{ "ResetCDR",       pbx_builtin_resetcdr },
1106
	{ "ResetCDR",       pbx_builtin_resetcdr },
1107
	{ "Ringing",        pbx_builtin_ringing },
1107
	{ "Ringing",        pbx_builtin_ringing },
1108
	{ "SayAlpha",       pbx_builtin_saycharacters },
1108
	{ "SayAlpha",       pbx_builtin_saycharacters },
1109
	{ "SayDigits",      pbx_builtin_saydigits },
1109
	{ "SayDigits",      pbx_builtin_saydigits },
1110
	{ "SayNumber",      pbx_builtin_saynumber },
1110
	{ "SayNumber",      pbx_builtin_saynumber },
1111
	{ "SayPhonetic",    pbx_builtin_sayphonetic },
1111
	{ "SayPhonetic",    pbx_builtin_sayphonetic },
1112
	{ "Set",            pbx_builtin_setvar },
1112
	{ "Set",            pbx_builtin_setvar },
1113
	{ "MSet",           pbx_builtin_setvar_multiple },
1113
	{ "MSet",           pbx_builtin_setvar_multiple },
1114
	{ "SetAMAFlags",    pbx_builtin_setamaflags },
1114
	{ "SetAMAFlags",    pbx_builtin_setamaflags },
1115
	{ "Wait",           pbx_builtin_wait },
1115
	{ "Wait",           pbx_builtin_wait },
1116
	{ "WaitExten",      pbx_builtin_waitexten }
1116
	{ "WaitExten",      pbx_builtin_waitexten }
1117
};
1117
};
1118

    
   
1118

   
1119
static struct ast_context *contexts;
1119
static struct ast_context *contexts;
1120
static struct ast_hashtab *contexts_table = NULL;
1120
static struct ast_hashtab *contexts_table = NULL;
1121

    
   
1121

   
1122
AST_RWLOCK_DEFINE_STATIC(conlock);		/*!< Lock for the ast_context list */
1122
AST_RWLOCK_DEFINE_STATIC(conlock);		/*!< Lock for the ast_context list */
1123

    
   
1123

   
1124
static AST_RWLIST_HEAD_STATIC(apps, ast_app);
1124
static AST_RWLIST_HEAD_STATIC(apps, ast_app);
1125

    
   
1125

   
1126
static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
1126
static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
1127

    
   
1127

   
1128
static int stateid = 1;
1128
static int stateid = 1;
1129
/* WARNING:
1129
/* WARNING:
1130
   When holding this list's lock, do _not_ do anything that will cause conlock
1130
   When holding this list's lock, do _not_ do anything that will cause conlock
1131
   to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
1131
   to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
1132
   function will take the locks in conlock/hints order, so any other
1132
   function will take the locks in conlock/hints order, so any other
1133
   paths that require both locks must also take them in that order.
1133
   paths that require both locks must also take them in that order.
1134
*/
1134
*/
1135
static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
1135
static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
1136

    
   
1136

   
1137
static AST_LIST_HEAD_NOLOCK_STATIC(statecbs, ast_state_cb);
1137
static AST_LIST_HEAD_NOLOCK_STATIC(statecbs, ast_state_cb);
1138

    
   
1138

   
1139
#ifdef CONTEXT_DEBUG
1139
#ifdef CONTEXT_DEBUG
1140

    
   
1140

   
1141
/* these routines are provided for doing run-time checks
1141
/* these routines are provided for doing run-time checks
1142
   on the extension structures, in case you are having
1142
   on the extension structures, in case you are having
1143
   problems, this routine might help you localize where
1143
   problems, this routine might help you localize where
1144
   the problem is occurring. It's kinda like a debug memory
1144
   the problem is occurring. It's kinda like a debug memory
1145
   allocator's arena checker... It'll eat up your cpu cycles!
1145
   allocator's arena checker... It'll eat up your cpu cycles!
1146
   but you'll see, if you call it in the right places,
1146
   but you'll see, if you call it in the right places,
1147
   right where your problems began...
1147
   right where your problems began...
1148
*/
1148
*/
1149

    
   
1149

   
1150
/* you can break on the check_contexts_trouble()
1150
/* you can break on the check_contexts_trouble()
1151
routine in your debugger to stop at the moment
1151
routine in your debugger to stop at the moment
1152
there's a problem */
1152
there's a problem */
1153
void check_contexts_trouble(void);
1153
void check_contexts_trouble(void);
1154

    
   
1154

   
1155
void check_contexts_trouble(void)
1155
void check_contexts_trouble(void)
1156
{
1156
{
1157
	int x = 1;
1157
	int x = 1;
1158
	x = 2;
1158
	x = 2;
1159
}
1159
}
1160

    
   
1160

   
1161
static struct ast_context *find_context_locked(const char *context);
1161
static struct ast_context *find_context_locked(const char *context);
1162
static struct ast_context *find_context(const char *context);
1162
static struct ast_context *find_context(const char *context);
1163
int check_contexts(char *, int);
1163
int check_contexts(char *, int);
1164

    
   
1164

   
1165
int check_contexts(char *file, int line )
1165
int check_contexts(char *file, int line )
1166
{
1166
{
1167
	struct ast_hashtab_iter *t1;
1167
	struct ast_hashtab_iter *t1;
1168
	struct ast_context *c1, *c2;
1168
	struct ast_context *c1, *c2;
1169
	int found = 0;
1169
	int found = 0;
1170
	struct ast_exten *e1, *e2, *e3;
1170
	struct ast_exten *e1, *e2, *e3;
1171
	struct ast_exten ex;
1171
	struct ast_exten ex;
1172

    
   
1172

   
1173
	/* try to find inconsistencies */
1173
	/* try to find inconsistencies */
1174
	/* is every context in the context table in the context list and vice-versa ? */
1174
	/* is every context in the context table in the context list and vice-versa ? */
1175

    
   
1175

   
1176
	if (!contexts_table) {
1176
	if (!contexts_table) {
1177
		ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
1177
		ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
1178
		usleep(500000);
1178
		usleep(500000);
1179
	}
1179
	}
1180

    
   
1180

   
1181
	t1 = ast_hashtab_start_traversal(contexts_table);
1181
	t1 = ast_hashtab_start_traversal(contexts_table);
1182
	while( (c1 = ast_hashtab_next(t1))) {
1182
	while( (c1 = ast_hashtab_next(t1))) {
1183
		for(c2=contexts;c2;c2=c2->next) {
1183
		for(c2=contexts;c2;c2=c2->next) {
1184
			if (!strcmp(c1->name, c2->name)) {
1184
			if (!strcmp(c1->name, c2->name)) {
1185
				found = 1;
1185
				found = 1;
1186
				break;
1186
				break;
1187
			}
1187
			}
1188
		}
1188
		}
1189
		if (!found) {
1189
		if (!found) {
1190
			ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
1190
			ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
1191
			check_contexts_trouble();
1191
			check_contexts_trouble();
1192
		}
1192
		}
1193
	}
1193
	}
1194
	ast_hashtab_end_traversal(t1);
1194
	ast_hashtab_end_traversal(t1);
1195
	for(c2=contexts;c2;c2=c2->next) {
1195
	for(c2=contexts;c2;c2=c2->next) {
1196
		c1 = find_context_locked(c2->name);
1196
		c1 = find_context_locked(c2->name);
1197
		if (!c1) {
1197
		if (!c1) {
1198
			ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
1198
			ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
1199
			check_contexts_trouble();
1199
			check_contexts_trouble();
1200
		} else
1200
		} else
1201
			ast_unlock_contexts();
1201
			ast_unlock_contexts();
1202
	}
1202
	}
1203

    
   
1203

   
1204
	/* loop thru all contexts, and verify the exten structure compares to the 
1204
	/* loop thru all contexts, and verify the exten structure compares to the 
1205
	   hashtab structure */
1205
	   hashtab structure */
1206
	for(c2=contexts;c2;c2=c2->next) {
1206
	for(c2=contexts;c2;c2=c2->next) {
1207
		c1 = find_context_locked(c2->name);
1207
		c1 = find_context_locked(c2->name);
1208
		if (c1)
1208
		if (c1)
1209
		{
1209
		{
1210

    
   
1210

   
1211
			ast_unlock_contexts();
1211
			ast_unlock_contexts();
1212

    
   
1212

   
1213
			/* is every entry in the root list also in the root_table? */
1213
			/* is every entry in the root list also in the root_table? */
1214
			for(e1 = c1->root; e1; e1=e1->next)
1214
			for(e1 = c1->root; e1; e1=e1->next)
1215
			{
1215
			{
1216
				char dummy_name[1024];
1216
				char dummy_name[1024];
1217
				ex.exten = dummy_name;
1217
				ex.exten = dummy_name;
1218
				ex.matchcid = e1->matchcid;
1218
				ex.matchcid = e1->matchcid;
1219
				ex.cidmatch = e1->cidmatch;
1219
				ex.cidmatch = e1->cidmatch;
1220
				ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
1220
				ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
1221
				e2 = ast_hashtab_lookup(c1->root_table, &ex);
1221
				e2 = ast_hashtab_lookup(c1->root_table, &ex);
1222
				if (!e2) {
1222
				if (!e2) {
1223
					if (e1->matchcid) {
1223
					if (e1->matchcid) {
1224
						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
1224
						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
1225
					} else {
1225
					} else {
1226
						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
1226
						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
1227
					}
1227
					}
1228
					check_contexts_trouble();
1228
					check_contexts_trouble();
1229
				}
1229
				}
1230
			}
1230
			}
1231

    
   
1231

   
1232
			/* is every entry in the root_table also in the root list? */ 
1232
			/* is every entry in the root_table also in the root list? */ 
1233
			if (!c2->root_table) {
1233
			if (!c2->root_table) {
1234
				if (c2->root) {
1234
				if (c2->root) {
1235
					ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
1235
					ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
1236
					usleep(500000);
1236
					usleep(500000);
1237
				}
1237
				}
1238
			} else {
1238
			} else {
1239
				t1 = ast_hashtab_start_traversal(c2->root_table);
1239
				t1 = ast_hashtab_start_traversal(c2->root_table);
1240
				while( (e2 = ast_hashtab_next(t1)) ) {
1240
				while( (e2 = ast_hashtab_next(t1)) ) {
1241
					for(e1=c2->root;e1;e1=e1->next) {
1241
					for(e1=c2->root;e1;e1=e1->next) {
1242
						if (!strcmp(e1->exten, e2->exten)) {
1242
						if (!strcmp(e1->exten, e2->exten)) {
1243
							found = 1;
1243
							found = 1;
1244
							break;
1244
							break;
1245
						}
1245
						}
1246
					}
1246
					}
1247
					if (!found) {
1247
					if (!found) {
1248
						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
1248
						ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
1249
						check_contexts_trouble();
1249
						check_contexts_trouble();
1250
					}
1250
					}
1251

    
   
1251

   
1252
				}
1252
				}
1253
				ast_hashtab_end_traversal(t1);
1253
				ast_hashtab_end_traversal(t1);
1254
			}
1254
			}
1255
		}
1255
		}
1256
		/* is every priority reflected in the peer_table at the head of the list? */
1256
		/* is every priority reflected in the peer_table at the head of the list? */
1257

    
   
1257

   
1258
		/* is every entry in the root list also in the root_table? */
1258
		/* is every entry in the root list also in the root_table? */
1259
		/* are the per-extension peer_tables in the right place? */
1259
		/* are the per-extension peer_tables in the right place? */
1260

    
   
1260

   
1261
		for(e1 = c2->root; e1; e1 = e1->next) {
1261
		for(e1 = c2->root; e1; e1 = e1->next) {
1262

    
   
1262

   
1263
			for(e2=e1;e2;e2=e2->peer) {
1263
			for(e2=e1;e2;e2=e2->peer) {
1264
				ex.priority = e2->priority;
1264
				ex.priority = e2->priority;
1265
				if (e2 != e1 && e2->peer_table) {
1265
				if (e2 != e1 && e2->peer_table) {
1266
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
1266
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
1267
					check_contexts_trouble();
1267
					check_contexts_trouble();
1268
				}
1268
				}
1269

    
   
1269

   
1270
				if (e2 != e1 && e2->peer_label_table) {
1270
				if (e2 != e1 && e2->peer_label_table) {
1271
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
1271
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
1272
					check_contexts_trouble();
1272
					check_contexts_trouble();
1273
				}
1273
				}
1274

    
   
1274

   
1275
				if (e2 == e1 && !e2->peer_table){
1275
				if (e2 == e1 && !e2->peer_table){
1276
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
1276
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
1277
					check_contexts_trouble();
1277
					check_contexts_trouble();
1278
				}
1278
				}
1279

    
   
1279

   
1280
				if (e2 == e1 && !e2->peer_label_table) {
1280
				if (e2 == e1 && !e2->peer_label_table) {
1281
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
1281
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
1282
					check_contexts_trouble();
1282
					check_contexts_trouble();
1283
				}
1283
				}
1284

    
   
1284

   
1285

    
   
1285

   
1286
				e3 = ast_hashtab_lookup(e1->peer_table, &ex);
1286
				e3 = ast_hashtab_lookup(e1->peer_table, &ex);
1287
				if (!e3) {
1287
				if (!e3) {
1288
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
1288
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
1289
					check_contexts_trouble();
1289
					check_contexts_trouble();
1290
				}
1290
				}
1291
			}
1291
			}
1292

    
   
1292

   
1293
			if (!e1->peer_table){
1293
			if (!e1->peer_table){
1294
				ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
1294
				ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
1295
				usleep(500000);
1295
				usleep(500000);
1296
			}
1296
			}
1297

    
   
1297

   
1298
			/* is every entry in the peer_table also in the peer list? */
1298
			/* is every entry in the peer_table also in the peer list? */
1299
			t1 = ast_hashtab_start_traversal(e1->peer_table);
1299
			t1 = ast_hashtab_start_traversal(e1->peer_table);
1300
			while( (e2 = ast_hashtab_next(t1)) ) {
1300
			while( (e2 = ast_hashtab_next(t1)) ) {
1301
				for(e3=e1;e3;e3=e3->peer) {
1301
				for(e3=e1;e3;e3=e3->peer) {
1302
					if (e3->priority == e2->priority) {
1302
					if (e3->priority == e2->priority) {
1303
						found = 1;
1303
						found = 1;
1304
						break;
1304
						break;
1305
					}
1305
					}
1306
				}
1306
				}
1307
				if (!found) {
1307
				if (!found) {
1308
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
1308
					ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
1309
					check_contexts_trouble();
1309
					check_contexts_trouble();
1310
				}
1310
				}
1311
			}
1311
			}
1312
			ast_hashtab_end_traversal(t1);
1312
			ast_hashtab_end_traversal(t1);
1313
		}
1313
		}
1314
	}
1314
	}
1315
	return 0;
1315
	return 0;
1316
}
1316
}
1317
#endif
1317
#endif
1318

    
   
1318

   
1319
/*
1319
/*
1320
   \note This function is special. It saves the stack so that no matter
1320
   \note This function is special. It saves the stack so that no matter
1321
   how many times it is called, it returns to the same place */
1321
   how many times it is called, it returns to the same place */
1322
int pbx_exec(struct ast_channel *c, /*!< Channel */
1322
int pbx_exec(struct ast_channel *c, /*!< Channel */
1323
	     struct ast_app *app,       /*!< Application */
1323
	     struct ast_app *app,       /*!< Application */
1324
	     void *data)                /*!< Data for execution */
1324
	     void *data)                /*!< Data for execution */
1325
{
1325
{
1326
	int res;
1326
	int res;
1327
	struct ast_module_user *u = NULL;
1327
	struct ast_module_user *u = NULL;
1328
	const char *saved_c_appl;
1328
	const char *saved_c_appl;
1329
	const char *saved_c_data;
1329
	const char *saved_c_data;
1330

    
   
1330

   
1331
	if (c->cdr && !ast_check_hangup(c))
1331
	if (c->cdr && !ast_check_hangup(c))
1332
		ast_cdr_setapp(c->cdr, app->name, data);
1332
		ast_cdr_setapp(c->cdr, app->name, data);
1333

    
   
1333

   
1334
	/* save channel values */
1334
	/* save channel values */
1335
	saved_c_appl= c->appl;
1335
	saved_c_appl= c->appl;
1336
	saved_c_data= c->data;
1336
	saved_c_data= c->data;
1337

    
   
1337

   
1338
	c->appl = app->name;
1338
	c->appl = app->name;
1339
	c->data = data;
1339
	c->data = data;
1340
	if (app->module)
1340
	if (app->module)
1341
		u = __ast_module_user_add(app->module, c);
1341
		u = __ast_module_user_add(app->module, c);
1342
	res = app->execute(c, S_OR(data, ""));
1342
	res = app->execute(c, S_OR(data, ""));
1343
	if (app->module && u)
1343
	if (app->module && u)
1344
		__ast_module_user_remove(app->module, u);
1344
		__ast_module_user_remove(app->module, u);
1345
	/* restore channel values */
1345
	/* restore channel values */
1346
	c->appl = saved_c_appl;
1346
	c->appl = saved_c_appl;
1347
	c->data = saved_c_data;
1347
	c->data = saved_c_data;
1348
	return res;
1348
	return res;
1349
}
1349
}
1350

    
   
1350

   
1351

    
   
1351

   
1352
/*! Go no deeper than this through includes (not counting loops) */
1352
/*! Go no deeper than this through includes (not counting loops) */
1353
#define AST_PBX_MAX_STACK	128
1353
#define AST_PBX_MAX_STACK	128
1354

    
   
1354

   
1355
/*! \brief Find application handle in linked list
1355
/*! \brief Find application handle in linked list
1356
 */
1356
 */
1357
struct ast_app *pbx_findapp(const char *app)
1357
struct ast_app *pbx_findapp(const char *app)
1358
{
1358
{
1359
	struct ast_app *tmp;
1359
	struct ast_app *tmp;
1360

    
   
1360

   
1361
	AST_RWLIST_RDLOCK(&apps);
1361
	AST_RWLIST_RDLOCK(&apps);
1362
	AST_RWLIST_TRAVERSE(&apps, tmp, list) {
1362
	AST_RWLIST_TRAVERSE(&apps, tmp, list) {
1363
		if (!strcasecmp(tmp->name, app))
1363
		if (!strcasecmp(tmp->name, app))
1364
			break;
1364
			break;
1365
	}
1365
	}
1366
	AST_RWLIST_UNLOCK(&apps);
1366
	AST_RWLIST_UNLOCK(&apps);
1367

    
   
1367

   
1368
	return tmp;
1368
	return tmp;
1369
}
1369
}
1370

    
   
1370

   
1371
static struct ast_switch *pbx_findswitch(const char *sw)
1371
static struct ast_switch *pbx_findswitch(const char *sw)
1372
{
1372
{
1373
	struct ast_switch *asw;
1373
	struct ast_switch *asw;
1374

    
   
1374

   
1375
	AST_RWLIST_RDLOCK(&switches);
1375
	AST_RWLIST_RDLOCK(&switches);
1376
	AST_RWLIST_TRAVERSE(&switches, asw, list) {
1376
	AST_RWLIST_TRAVERSE(&switches, asw, list) {
1377
		if (!strcasecmp(asw->name, sw))
1377
		if (!strcasecmp(asw->name, sw))
1378
			break;
1378
			break;
1379
	}
1379
	}
1380
	AST_RWLIST_UNLOCK(&switches);
1380
	AST_RWLIST_UNLOCK(&switches);
1381

    
   
1381

   
1382
	return asw;
1382
	return asw;
1383
}
1383
}
1384

    
   
1384

   
1385
static inline int include_valid(struct ast_include *i)
1385
static inline int include_valid(struct ast_include *i)
1386
{
1386
{
1387
	if (!i->hastime)
1387
	if (!i->hastime)
1388
		return 1;
1388
		return 1;
1389

    
   
1389

   
1390
	return ast_check_timing(&(i->timing));
1390
	return ast_check_timing(&(i->timing));
1391
}
1391
}
1392

    
   
1392

   
1393
static void pbx_destroy(struct ast_pbx *p)
1393
static void pbx_destroy(struct ast_pbx *p)
1394
{
1394
{
1395
	ast_free(p);
1395
	ast_free(p);
1396
}
1396
}
1397

    
   
1397

   
1398
/* form a tree that fully describes all the patterns in a context's extensions
1398
/* form a tree that fully describes all the patterns in a context's extensions
1399
 * in this tree, a "node" represents an individual character or character set
1399
 * in this tree, a "node" represents an individual character or character set
1400
 * meant to match the corresponding character in a dial string. The tree
1400
 * meant to match the corresponding character in a dial string. The tree
1401
 * consists of a series of match_char structs linked in a chain
1401
 * consists of a series of match_char structs linked in a chain
1402
 * via the alt_char pointers. More than one pattern can share the same parts of the
1402
 * via the alt_char pointers. More than one pattern can share the same parts of the
1403
 * tree as other extensions with the same pattern to that point.
1403
 * tree as other extensions with the same pattern to that point.
1404
 * My first attempt to duplicate the finding of the 'best' pattern was flawed in that
1404
 * My first attempt to duplicate the finding of the 'best' pattern was flawed in that
1405
 * I misunderstood the general algorithm. I thought that the 'best' pattern
1405
 * I misunderstood the general algorithm. I thought that the 'best' pattern
1406
 * was the one with lowest total score. This was not true. Thus, if you have
1406
 * was the one with lowest total score. This was not true. Thus, if you have
1407
 * patterns "1XXXXX" and "X11111", you would be tempted to say that "X11111" is
1407
 * patterns "1XXXXX" and "X11111", you would be tempted to say that "X11111" is
1408
 * the "best" match because it has fewer X's, and is therefore more specific,
1408
 * the "best" match because it has fewer X's, and is therefore more specific,
1409
 * but this is not how the old algorithm works. It sorts matching patterns
1409
 * but this is not how the old algorithm works. It sorts matching patterns
1410
 * in a similar collating sequence as sorting alphabetic strings, from left to
1410
 * in a similar collating sequence as sorting alphabetic strings, from left to
1411
 * right. Thus, "1XXXXX" comes before "X11111", and would be the "better" match,
1411
 * right. Thus, "1XXXXX" comes before "X11111", and would be the "better" match,
1412
 * because "1" is more specific than "X".
1412
 * because "1" is more specific than "X".
1413
 * So, to accomodate this philosophy, I sort the tree branches along the alt_char
1413
 * So, to accomodate this philosophy, I sort the tree branches along the alt_char
1414
 * line so they are lowest to highest in specificity numbers. This way, as soon
1414
 * line so they are lowest to highest in specificity numbers. This way, as soon
1415
 * as we encounter our first complete match, we automatically have the "best"
1415
 * as we encounter our first complete match, we automatically have the "best"
1416
 * match and can stop the traversal immediately. Same for CANMATCH/MATCHMORE.
1416
 * match and can stop the traversal immediately. Same for CANMATCH/MATCHMORE.
1417
 * If anyone would like to resurrect the "wrong" pattern trie searching algorithm,
1417
 * If anyone would like to resurrect the "wrong" pattern trie searching algorithm,
1418
 * they are welcome to revert pbx to before 1 Apr 2008.
1418
 * they are welcome to revert pbx to before 1 Apr 2008.
1419
 * As an example, consider these 4 extensions:
1419
 * As an example, consider these 4 extensions:
1420
 * (a) NXXNXXXXXX
1420
 * (a) NXXNXXXXXX
1421
 * (b) 307754XXXX
1421
 * (b) 307754XXXX
1422
 * (c) fax
1422
 * (c) fax
1423
 * (d) NXXXXXXXXX
1423
 * (d) NXXXXXXXXX
1424
 *
1424
 *
1425
 * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
1425
 * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
1426
 * most numbers. For all numbers beginning with 307754, (b) should always win.
1426
 * most numbers. For all numbers beginning with 307754, (b) should always win.
1427
 *
1427
 *
1428
 * These pattern should form a (sorted) tree that looks like this:
1428
 * These pattern should form a (sorted) tree that looks like this:
1429
 *   { "3" }  --next-->  { "0" }  --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
1429
 *   { "3" }  --next-->  { "0" }  --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
1430
 *      |
1430
 *      |
1431
 *      |alt
1431
 *      |alt
1432
 *      |
1432
 *      |
1433
 *   { "f" }  --next-->  { "a" }  --next--> { "x"  exten_match: (c) }
1433
 *   { "f" }  --next-->  { "a" }  --next--> { "x"  exten_match: (c) }
1434
 *   { "N" }  --next-->  { "X" }  --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
1434
 *   { "N" }  --next-->  { "X" }  --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
1435
 *      |                                                        |
1435
 *      |                                                        |
1436
 *      |                                                        |alt
1436
 *      |                                                        |alt
1437
 *      |alt                                                     |
1437
 *      |alt                                                     |
1438
 *      |                                                     { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
1438
 *      |                                                     { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
1439
 *      |
1439
 *      |
1440
 *     NULL
1440
 *     NULL
1441
 *
1441
 *
1442
 *   In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
1442
 *   In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
1443
 *   fewer CPU cycles than a call to strchr("23456789",*z), where *z is the char to match...
1443
 *   fewer CPU cycles than a call to strchr("23456789",*z), where *z is the char to match...
1444
 *
1444
 *
1445
 *   traversal is pretty simple: one routine merely traverses the alt list, and for each matching char in the pattern,  it calls itself
1445
 *   traversal is pretty simple: one routine merely traverses the alt list, and for each matching char in the pattern,  it calls itself
1446
 *   on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
1446
 *   on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
1447
 *   We pass a pointer to a scoreboard down through, also.
1447
 *   We pass a pointer to a scoreboard down through, also.
1448
 *   The scoreboard isn't as necessary to the revised algorithm, but I kept it as a handy way to return the matched extension.
1448
 *   The scoreboard isn't as necessary to the revised algorithm, but I kept it as a handy way to return the matched extension.
1449
 *   The first complete match ends the traversal, which should make this version of the pattern matcher faster
1449
 *   The first complete match ends the traversal, which should make this version of the pattern matcher faster
1450
 *   the previous. The same goes for "CANMATCH" or "MATCHMORE"; the first such match ends the traversal. In both
1450
 *   the previous. The same goes for "CANMATCH" or "MATCHMORE"; the first such match ends the traversal. In both
1451
 *   these cases, the reason we can stop immediately, is because the first pattern match found will be the "best"
1451
 *   these cases, the reason we can stop immediately, is because the first pattern match found will be the "best"
1452
 *   according to the sort criteria.
1452
 *   according to the sort criteria.
1453
 *   Hope the limit on stack depth won't be a problem... this routine should
1453
 *   Hope the limit on stack depth won't be a problem... this routine should
1454
 *   be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
1454
 *   be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
1455
 *
1455
 *
1456
 *   In the above example, with the number "3077549999" as the pattern, the traversor could match extensions a, b and d.  All are
1456
 *   In the above example, with the number "3077549999" as the pattern, the traversor could match extensions a, b and d.  All are
1457
 *   of length 10; they have total specificities of  24580, 10246, and 25090, respectively, not that this matters
1457
 *   of length 10; they have total specificities of  24580, 10246, and 25090, respectively, not that this matters
1458
 *   at all. (b) wins purely because the first character "3" is much more specific (lower specificity) than "N". I have
1458
 *   at all. (b) wins purely because the first character "3" is much more specific (lower specificity) than "N". I have
1459
 *   left the specificity totals in the code as an artifact; at some point, I will strip it out.
1459
 *   left the specificity totals in the code as an artifact; at some point, I will strip it out.
1460
 *
1460
 *
1461
 *   Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown,
1461
 *   Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown,
1462
 *   because it's a function of how many extensions are stored in a context. With thousands of extensions, the speedup
1462
 *   because it's a function of how many extensions are stored in a context. With thousands of extensions, the speedup
1463
 *   can be very noticeable. The new matching algorithm can run several hundreds of times faster, if not a thousand or
1463
 *   can be very noticeable. The new matching algorithm can run several hundreds of times faster, if not a thousand or
1464
 *   more times faster in extreme cases.
1464
 *   more times faster in extreme cases.
1465
 *
1465
 *
1466
 *   MatchCID patterns are also supported, and stored in the tree just as the extension pattern is. Thus, you
1466
 *   MatchCID patterns are also supported, and stored in the tree just as the extension pattern is. Thus, you
1467
 *   can have patterns in your CID field as well.
1467
 *   can have patterns in your CID field as well.
1468
 *
1468
 *
1469
 * */
1469
 * */
1470

    
   
1470

   
1471

    
   
1471

   
1472
static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
1472
static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
1473
{
1473
{
1474
	/* if this extension is marked as deleted, then skip this -- if it never shows
1474
	/* if this extension is marked as deleted, then skip this -- if it never shows
1475
	   on the scoreboard, it will never be found, nor will halt the traversal. */
1475
	   on the scoreboard, it will never be found, nor will halt the traversal. */
1476
	if (deleted)
1476
	if (deleted)
1477
		return;
1477
		return;
1478
	board->total_specificity = spec;
1478
	board->total_specificity = spec;
1479
	board->total_length = length;
1479
	board->total_length = length;
1480
	board->exten = exten;
1480
	board->exten = exten;
1481
	board->last_char = last;
1481
	board->last_char = last;
1482
	board->node = node;
1482
	board->node = node;
1483
#ifdef NEED_DEBUG_HERE
1483
#ifdef NEED_DEBUG_HERE
1484
	ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
1484
	ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
1485
#endif
1485
#endif
1486
}
1486
}
1487

    
   
1487

   
1488
void log_match_char_tree(struct match_char *node, char *prefix)
1488
void log_match_char_tree(struct match_char *node, char *prefix)
1489
{
1489
{
1490
	char extenstr[40];
1490
	char extenstr[40];
1491
	struct ast_str *my_prefix = ast_str_alloca(1024);
1491
	struct ast_str *my_prefix = ast_str_alloca(1024);
1492

    
   
1492

   
1493
	extenstr[0] = '\0';
1493
	extenstr[0] = '\0';
1494

    
   
1494

   
1495
	if (node && node->exten && node->exten)
1495
	if (node && node->exten)
1496
		snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
1496
		snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
1497

    
   
1497

   
1498
	if (strlen(node->x) > 1) {
1498
	if (strlen(node->x) > 1) {
1499
		ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
1499
		ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
1500
			node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
1500
			node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
1501
			node->exten ? node->exten->exten : "", extenstr);
1501
			node->exten ? node->exten->exten : "", extenstr);
1502
	} else {
1502
	} else {
1503
		ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
1503
		ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
1504
			node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
1504
			node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
1505
			node->exten ? node->exten->exten : "", extenstr);
1505
			node->exten ? node->exten->exten : "", extenstr);
1506
	}
1506
	}
1507

    
   
1507

   
1508
	ast_str_set(&my_prefix, 0, "%s+       ", prefix);
1508
	ast_str_set(&my_prefix, 0, "%s+       ", prefix);
1509

    
   
1509

   
1510
	if (node->next_char)
1510
	if (node->next_char)
1511
		log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
1511
		log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
1512

    
   
1512

   
1513
	if (node->alt_char)
1513
	if (node->alt_char)
1514
		log_match_char_tree(node->alt_char, prefix);
1514
		log_match_char_tree(node->alt_char, prefix);
1515
}
1515
}
1516

    
   
1516

   
1517
static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
1517
static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
1518
{
1518
{
1519
	char extenstr[40];
1519
	char extenstr[40];
1520
	struct ast_str *my_prefix = ast_str_alloca(1024);
1520
	struct ast_str *my_prefix = ast_str_alloca(1024);
1521

    
   
1521

   
1522
	extenstr[0] = '\0';
1522
	extenstr[0] = '\0';
1523

    
   
1523

   
1524
	if (node && node->exten && node->exten)
1524
	if (node && node->exten)
1525
		snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
1525
		snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
1526

    
   
1526

   
1527
	if (strlen(node->x) > 1) {
1527
	if (strlen(node->x) > 1) {
1528
		ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1528
		ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1529
			node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1529
			node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1530
			node->exten ? node->exten->exten : "", extenstr);
1530
			node->exten ? node->exten->exten : "", extenstr);
1531
	} else {
1531
	} else {
1532
		ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1532
		ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
1533
			node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1533
			node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
1534
			node->exten ? node->exten->exten : "", extenstr);
1534
			node->exten ? node->exten->exten : "", extenstr);
1535
	}
1535
	}
1536

    
   
1536

   
1537
	ast_str_set(&my_prefix, 0, "%s+       ", prefix);
1537
	ast_str_set(&my_prefix, 0, "%s+       ", prefix);
1538

    
   
1538

   
1539
	if (node->next_char)
1539
	if (node->next_char)
1540
		cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
1540
		cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
1541

    
   
1541

   
1542
	if (node->alt_char)
1542
	if (node->alt_char)
1543
		cli_match_char_tree(node->alt_char, prefix, fd);
1543
		cli_match_char_tree(node->alt_char, prefix, fd);
1544
}
1544
}
1545

    
   
1545

   
1546
static struct ast_exten *get_canmatch_exten(struct match_char *node)
1546
static struct ast_exten *get_canmatch_exten(struct match_char *node)
1547
{
1547
{
1548
	/* find the exten at the end of the rope */
1548
	/* find the exten at the end of the rope */
1549
	struct match_char *node2 = node;
1549
	struct match_char *node2 = node;
1550

    
   
1550

   
1551
	for (node2 = node; node2; node2 = node2->next_char) {
1551
	for (node2 = node; node2; node2 = node2->next_char) {
1552
		if (node2->exten) {
1552
		if (node2->exten) {
1553
#ifdef NEED_DEBUG_HERE
1553
#ifdef NEED_DEBUG_HERE
1554
			ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
1554
			ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
1555
#endif
1555
#endif
1556
			return node2->exten;
1556
			return node2->exten;
1557
		}
1557
		}
1558
	}
1558
	}
1559
#ifdef NEED_DEBUG_HERE
1559
#ifdef NEED_DEBUG_HERE
1560
	ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
1560
	ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
1561
#endif
1561
#endif
1562
	return 0;
1562
	return 0;
1563
}
1563
}
1564

    
   
1564

   
1565
static struct ast_exten *trie_find_next_match(struct match_char *node)
1565
static struct ast_exten *trie_find_next_match(struct match_char *node)
1566
{
1566
{
1567
	struct match_char *m3;
1567
	struct match_char *m3;
1568
	struct match_char *m4;
1568
	struct match_char *m4;
1569
	struct ast_exten *e3;
1569
	struct ast_exten *e3;
1570

    
   
1570

   
1571
	if (node && node->x[0] == '.' && !node->x[1]) { /* dot and ! will ALWAYS be next match in a matchmore */
1571
	if (node && node->x[0] == '.' && !node->x[1]) { /* dot and ! will ALWAYS be next match in a matchmore */
1572
		return node->exten;
1572
		return node->exten;
1573
	}
1573
	}
1574

    
   
1574

   
1575
	if (node && node->x[0] == '!' && !node->x[1]) {
1575
	if (node && node->x[0] == '!' && !node->x[1]) {
1576
		return node->exten;
1576
		return node->exten;
1577
	}
1577
	}
1578

    
   
1578

   
1579
	if (!node || !node->next_char) {
1579
	if (!node || !node->next_char) {
1580
		return NULL;
1580
		return NULL;
1581
	}
1581
	}
1582

    
   
1582

   
1583
	m3 = node->next_char;
1583
	m3 = node->next_char;
1584

    
   
1584

   
1585
	if (m3->exten) {
1585
	if (m3->exten) {
1586
		return m3->exten;
1586
		return m3->exten;
1587
	}
1587
	}
1588
	for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
1588
	for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
1589
		if (m4->exten) {
1589
		if (m4->exten) {
1590
			return m4->exten;
1590
			return m4->exten;
1591
		}
1591
		}
1592
	}
1592
	}
1593
	for (m4 = m3; m4; m4 = m4->alt_char) {
1593
	for (m4 = m3; m4; m4 = m4->alt_char) {
1594
		e3 = trie_find_next_match(m3);
1594
		e3 = trie_find_next_match(m3);
1595
		if (e3) {
1595
		if (e3) {
1596
			return e3;
1596
			return e3;
1597
		}
1597
		}
1598
	}
1598
	}

    
   
1599

   
1599
	return NULL;
1600
	return NULL;
1600
}
1601
}
1601

    
   
1602

   
1602
#ifdef DEBUG_THIS
1603
#ifdef DEBUG_THIS
1603
static char *action2str(enum ext_match_t action)
1604
static char *action2str(enum ext_match_t action)
1604
{
1605
{
1605
	switch (action) {
1606
	switch (action) {
1606
	case E_MATCH:
1607
	case E_MATCH:
1607
		return "MATCH";
1608
		return "MATCH";
1608
	case E_CANMATCH:
1609
	case E_CANMATCH:
1609
		return "CANMATCH";
1610
		return "CANMATCH";
1610
	case E_MATCHMORE:
1611
	case E_MATCHMORE:
1611
		return "MATCHMORE";
1612
		return "MATCHMORE";
1612
	case E_FINDLABEL:
1613
	case E_FINDLABEL:
1613
		return "FINDLABEL";
1614
		return "FINDLABEL";
1614
	case E_SPAWN:
1615
	case E_SPAWN:
1615
		return "SPAWN";
1616
		return "SPAWN";
1616
	default:
1617
	default:
1617
		return "?ACTION?";
1618
		return "?ACTION?";
1618
	}
1619
	}
1619
}
1620
}
1620

    
   
1621

   
1621
#endif
1622
#endif
1622

    
   
1623

   
1623
static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *label, const char *callerid, enum ext_match_t action)
1624
static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *label, const char *callerid, enum ext_match_t action)
1624
{
1625
{
1625
	struct match_char *p; /* note minimal stack storage requirements */
1626
	struct match_char *p; /* note minimal stack storage requirements */
1626
	struct ast_exten pattern = { .label = label };
1627
	struct ast_exten pattern = { .label = label };
1627
#ifdef DEBUG_THIS
1628
#ifdef DEBUG_THIS
1628
	if (tree)
1629
	if (tree)
1629
		ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
1630
		ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
1630
	else
1631
	else
1631
		ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
1632
		ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
1632
#endif
1633
#endif
1633
	for (p = tree; p; p = p->alt_char) {
1634
	for (p = tree; p; p = p->alt_char) {

    
   
1635
		if (p->is_pattern) {
1634
		if (p->x[0] == 'N') {
1636
			if (p->x[0] == 'N') {
1635
			if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
1637
				if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
1636
#define NEW_MATCHER_CHK_MATCH	       \
1638
#define	NEW_MATCHER_CHK_MATCH	       \
1637
				if (p->exten && !(*(str + 1))) { /* if a shorter pattern matches along the way, might as well report it */           \
1639
					if (p->exten && !(*(str + 1))) { /* if a shorter pattern matches along the way, might as well report it */             \
1638
					if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */   \
1640
						if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */   \
1639
						update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p);           \
1641
							update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p);                 \
1640
						if (!p->deleted) {                                                                                           \
1642
							if (!p->deleted) {                                                                                           \
1641
							if (action == E_FINDLABEL) {                                                                             \
1643
								if (action == E_FINDLABEL) {                                                                             \
1642
								if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) {                                  \
1644
									if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) {                                  \
1643
									ast_debug(4, "Found label in preferred extension\n");                                            \
1645
										ast_debug(4, "Found label in preferred extension\n");                                            \
1644
									return;                                                                                          \
1646
										return;                                                                                          \
1645
								}                                                                                                    \
1647
									}                                                                                                    \
1646
							} else {                                                                                                 \
1648
								} else {                                                                                                 \
1647
								ast_debug(4,"returning an exact match-- first found-- %s\n", p->exten->exten);                       \
1649
									ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->exten);                       \
1648
								return; /* the first match, by definition, will be the best, because of the sorted tree */           \
1650
									return; /* the first match, by definition, will be the best, because of the sorted tree */           \
1649
							}                                                                                                        \
1651
								}                                                                                                        \
1650
						}                                                                                                            \
1652
							}                                                                                                            \
1651
					}                                                                                                                \
1653
						}                                                                                                                \
1652
				}
1654
					}
1653

    
   
1655
					
1654
#define NEW_MATCHER_RECURSE	           \
1656
#define	NEW_MATCHER_RECURSE	           \
1655
				if (p->next_char && ( *(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0)               \
1657
					if (p->next_char && (*(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0)                 \
1656
                                                 || p->next_char->x[0] == '!')) {                                        \
1658
        	                                       || p->next_char->x[0] == '!')) {                                          \
1657
					if (*(str + 1) || p->next_char->x[0] == '!') {                                                       \
1659
						if (*(str + 1) || p->next_char->x[0] == '!') {                                                         \
1658
						new_find_extension(str + 1, score, p->next_char, length + 1, spec+p->specificity, callerid, label, action); \
1660
							new_find_extension(str + 1, score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
1659
						if (score->exten)  {                                                                             \
1661
							if (score->exten)  {                                                                             \
1660
					        ast_debug(4, "returning an exact match-- %s\n", score->exten->exten);                        \
1662
						        ast_debug(4 ,"returning an exact match-- %s\n", score->exten->exten);                         \
1661
							return; /* the first match is all we need */                                                 \
1663
								return; /* the first match is all we need */                                                 \
1662
						}												                                                 \
1664
							}												                                                 \
1663
					} else {                                                                                             \
1665
						} else {                                                                                             \
1664
						new_find_extension("/", score, p->next_char, length + 1, spec+p->specificity, callerid, label, action);	 \
1666
							new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action);	 \
1665
						if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {      \
1667
							if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {      \
1666
					        ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten :     \
1668
						        ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten :     \
1667
                                       "NULL");                                                                          \
1669
        	                               "NULL");                                                                        \
1668
							return; /* the first match is all we need */                                                 \
1670
								return; /* the first match is all we need */                                                 \
1669
						}												                                                 \
1671
							}												                                                 \
1670
					}                                                                                                    \
1672
						}                                                                                                    \
1671
				} else if (p->next_char && !*(str + 1)) {                                                                \
1673
					} else if (p->next_char && !*(str + 1)) {                                                                  \
1672
					score->canmatch = 1;                                                                                 \
1674
						score->canmatch = 1;                                                                                 \
1673
					score->canmatch_exten = get_canmatch_exten(p);                                                       \
1675
						score->canmatch_exten = get_canmatch_exten(p);                                                       \
1674
					if (action == E_CANMATCH || action == E_MATCHMORE) {                                                 \
1676
						if (action == E_CANMATCH || action == E_MATCHMORE) {                                                 \
1675
				        ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str);                                 \
1677
					        ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str);                                  \
1676
						return;                                                                                          \
1678
							return;                                                                                          \
1677
					}												                                                     \
1679
						}												                                                     \
1678
				}
1680
					}
1679

    
   
1681
					
1680
				NEW_MATCHER_CHK_MATCH;
1682
					NEW_MATCHER_CHK_MATCH;
1681
				NEW_MATCHER_RECURSE;
1683
					NEW_MATCHER_RECURSE;
1682
			}
1684
				}
1683
		} else if (p->x[0] == 'Z') {
1685
			} else if (p->x[0] == 'Z') {
1684
			if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
1686
				if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
1685
				NEW_MATCHER_CHK_MATCH;
1687
					NEW_MATCHER_CHK_MATCH;
1686
				NEW_MATCHER_RECURSE;
1688
					NEW_MATCHER_RECURSE;
1687
			}
1689
				}
1688
		} else if (p->x[0] == 'X') {
1690
			} else if (p->x[0] == 'X') { 
1689
			if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
1691
				if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
1690
				NEW_MATCHER_CHK_MATCH;
1692
					NEW_MATCHER_CHK_MATCH;
1691
				NEW_MATCHER_RECURSE;
1693
					NEW_MATCHER_RECURSE;
1692
			}
1694
				}
1693
		} else if (p->x[0] == '.' && p->x[1] == 0) {
1695
			} else if (p->x[0] == '.' && p->x[1] == 0) {
1694
			/* how many chars will the . match against? */
1696
				/* how many chars will the . match against? */
1695
			int i = 0;
1697
				int i = 0;
1696
			const char *str2 = str;
1698
				const char *str2 = str;
1697
			while (*str2 && *str2 != '/') {
1699
				while (*str2 && *str2 != '/') {
1698
				str2++;
1700
					str2++;
1699
				i++;
1701
					i++;
1700
			}
1702
				}
1701
			if (p->exten && *str2 != '/') {
1703
				if (p->exten && *str2 != '/') {
1702
				update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
1704
					update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
1703
				if (score->exten) {
1705
					if (score->exten) {
1704
					ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
1706
						ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
1705
					return; /* the first match is all we need */
1707
						return; /* the first match is all we need */
1706
				}
1708
					}
1707
			}
1709
				}
1708
			if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1710
				if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1709
				new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid, label, action);
1711
					new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
1710
				if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1712
					if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1711
					ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
1713
						ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
1712
					return; /* the first match is all we need */
1714
						return; /* the first match is all we need */
1713
				}
1715
					}
1714
			}
1716
				}
1715
		} else if (p->x[0] == '!' && p->x[1] == 0) {
1717
			} else if (p->x[0] == '!' && p->x[1] == 0) {
1716
			/* how many chars will the . match against? */
1718
				/* how many chars will the . match against? */
1717
			int i = 1;
1719
				int i = 1;
1718
			const char *str2 = str;
1720
				const char *str2 = str;
1719
			while (*str2 && *str2 != '/') {
1721
				while (*str2 && *str2 != '/') {
1720
				str2++;
1722
					str2++;
1721
				i++;
1723
					i++;
1722
			}
1724
				}
1723
			if (p->exten && *str2 != '/') {
1725
				if (p->exten && *str2 != '/') {
1724
				update_scoreboard(score, length + 1, spec+(p->specificity * i), p->exten, '!', callerid, p->deleted, p);
1726
					update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
1725
				if (score->exten) {
1727
					if (score->exten) {
1726
					ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
1728
						ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
1727
					return; /* the first match is all we need */
1729
						return; /* the first match is all we need */
1728
				}
1730
					}
1729
			}
1731
				}
1730
			if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1732
				if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
1731
				new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
1733
					new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
1732
				if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1734
					if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1733
					ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
1735
						ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
1734
					return; /* the first match is all we need */
1736
						return; /* the first match is all we need */
1735
				}
1737
					}
1736
			}
1738
				}
1737
		} else if (p->x[0] == '/' && p->x[1] == 0) {
1739
			} else if (p->x[0] == '/' && p->x[1] == 0) {
1738
			/* the pattern in the tree includes the cid match! */
1740
				/* the pattern in the tree includes the cid match! */
1739
			if (p->next_char && callerid && *callerid) {
1741
				if (p->next_char && callerid && *callerid) {
1740
				new_find_extension(callerid, score, p->next_char, length+1, spec, callerid, label, action);
1742
					new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
1741
				if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1743
					if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
1742
					ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
1744
						ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
1743
					return; /* the first match is all we need */
1745
						return; /* the first match is all we need */
1744
				}
1746
					}
1745
			}
1747
				}
1746
		} else if (strchr(p->x, *str)) {
1748
			} else if (strchr(p->x, *str)) {
1747
			ast_debug(4, "Nothing strange about this match\n");
1749
				ast_debug(4, "Nothing strange about this match\n");
1748
			NEW_MATCHER_CHK_MATCH;
1750
				NEW_MATCHER_CHK_MATCH;
1749
			NEW_MATCHER_RECURSE;
1751
				NEW_MATCHER_RECURSE;
1750
		}
1752
			}

    
   
1753
		} else if (strchr(p->x, *str)) {

    
   
1754
			ast_debug(4, "Nothing strange about this match\n");

    
   
1755
			NEW_MATCHER_CHK_MATCH;

    
   
1756
			NEW_MATCHER_RECURSE;

    
   
1757
		}
1751
	}
1758
	}
1752
	ast_debug(4, "return at end of func\n");
1759
	ast_debug(4, "return at end of func\n");
1753
}
1760
}
1754

    
   
1761

   
1755
/* the algorithm for forming the extension pattern tree is also a bit simple; you
1762
/* the algorithm for forming the extension pattern tree is also a bit simple; you
1756
 * traverse all the extensions in a context, and for each char of the extension,
1763
 * traverse all the extensions in a context, and for each char of the extension,
1757
 * you see if it exists in the tree; if it doesn't, you add it at the appropriate
1764
 * you see if it exists in the tree; if it doesn't, you add it at the appropriate
1758
 * spot. What more can I say? At the end of each exten, you cap it off by adding the
1765
 * spot. What more can I say? At the end of each exten, you cap it off by adding the
1759
 * address of the extension involved. Duplicate patterns will be complained about.
1766
 * address of the extension involved. Duplicate patterns will be complained about.
1760
 *
1767
 *
1761
 * Ideally, this would be done for each context after it is created and fully
1768
 * Ideally, this would be done for each context after it is created and fully
1762
 * filled. It could be done as a finishing step after extensions.conf or .ael is
1769
 * filled. It could be done as a finishing step after extensions.conf or .ael is
1763
 * loaded, or it could be done when the first search is encountered. It should only
1770
 * loaded, or it could be done when the first search is encountered. It should only
1764
 * have to be done once, until the next unload or reload.
1771
 * have to be done once, until the next unload or reload.
1765
 *
1772
 *
1766
 * I guess forming this pattern tree would be analogous to compiling a regex. Except
1773
 * I guess forming this pattern tree would be analogous to compiling a regex. Except
1767
 * that a regex only handles 1 pattern, really. This trie holds any number
1774
 * that a regex only handles 1 pattern, really. This trie holds any number
1768
 * of patterns. Well, really, it **could** be considered a single pattern,
1775
 * of patterns. Well, really, it **could** be considered a single pattern,
1769
 * where the "|" (or) operator is allowed, I guess, in a way, sort of...
1776
 * where the "|" (or) operator is allowed, I guess, in a way, sort of...
1770
 */
1777
 */
1771

    
   
1778

   
1772
static struct match_char *already_in_tree(struct match_char *current, char *pat)
1779
static struct match_char *already_in_tree(struct match_char *current, char *pat, int is_pattern)
1773
{
1780
{
1774
	struct match_char *t;
1781
	struct match_char *t;
1775

    
   
1782

   
1776
	if (!current) {
1783
	if (!current) {
1777
		return 0;
1784
		return 0;
1778
	}
1785
	}
1779

    
   
1786

   
1780
	for (t = current; t; t = t->alt_char) {
1787
	for (t = current; t; t = t->alt_char) {
1781
		if (!strcmp(pat, t->x)) { /* uh, we may want to sort exploded [] contents to make matching easy */
1788
		if (is_pattern == t->is_pattern && !strcmp(pat, t->x)) {/* uh, we may want to sort exploded [] contents to make matching easy */
1782
			return t;
1789
			return t;
1783
		}
1790
		}
1784
	}
1791
	}
1785

    
   
1792

   
1786
	return 0;
1793
	return 0;
1787
}
1794
}
1788

    
   
1795

   
1789
/* The first arg is the location of the tree ptr, or the
1796
/* The first arg is the location of the tree ptr, or the
1790
   address of the next_char ptr in the node, so we can mess
1797
   address of the next_char ptr in the node, so we can mess
1791
   with it, if we need to insert at the beginning of the list */
1798
   with it, if we need to insert at the beginning of the list */
1792

    
   
1799

   
1793
static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
1800
static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
1794
{
1801
{
1795
	struct match_char *curr, *lcurr;
1802
	struct match_char *curr, *lcurr;
1796

    
   
1803

   
1797
	/* insert node into the tree at "current", so the alt_char list from current is
1804
	/* insert node into the tree at "current", so the alt_char list from current is
1798
	   sorted in increasing value as you go to the leaves */
1805
	   sorted in increasing value as you go to the leaves */
1799
	if (!(*parent_ptr)) {
1806
	if (!(*parent_ptr)) {
1800
		*parent_ptr = node;
1807
		*parent_ptr = node;
1801
	} else {
1808
		return;
1802
		if ((*parent_ptr)->specificity > node->specificity) {
1809
	}

    
   
1810

   

    
   
1811
	if ((*parent_ptr)->specificity > node->specificity){
1803
			/* insert at head */
1812
		/* insert at head */
1804
			node->alt_char = (*parent_ptr);
1813
		node->alt_char = (*parent_ptr);
1805
			*parent_ptr = node;
1814
		*parent_ptr = node;
1806
		} else {
1815
		return;

    
   
1816
	} 

    
   
1817

   
1807
			lcurr = *parent_ptr;
1818
	lcurr = *parent_ptr;
1808
			for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
1819
	for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
1809
				if (curr->specificity > node->specificity) {
1820
		if (curr->specificity > node->specificity) {
1810
					node->alt_char = curr;
1821
			node->alt_char = curr;
1811
					lcurr->alt_char = node;
1822
			lcurr->alt_char = node;
1812
					break;
1823
			break;
1813
				}
1824
		}
1814
				lcurr = curr;
1825
		lcurr = curr;
1815
			}
1826
	}

    
   
1827

   
1816
			if (!curr) {
1828
	if (!curr) {
1817
				lcurr->alt_char = node;
1829
		lcurr->alt_char = node;
1818
			}
1830
	}
1819
		}

   
1820
	}

   
1821
}

   
1822

    
   

   
1823

    
   
1831

   

    
   
1832
}
1824

    
   
1833

   
1825
static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity, struct match_char **nextcharptr)
1834
static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity, struct match_char **nextcharptr)
1826
{
1835
{
1827
	struct match_char *m;
1836
	struct match_char *m;
1828

    
   
1837
	
1829
	if (!(m = ast_calloc(1, sizeof(*m)))) {
1838
	if (!(m = ast_calloc(1, sizeof(*m) + strlen(pattern)))) {
1830
		return NULL;
1839
		return NULL;
1831
	}
1840
	}
1832

    
   
1841

   
1833
	if (!(m->x = ast_strdup(pattern))) {
1842
	/* strcpy is safe here since we know its size and have allocated
1834
		ast_free(m);
1843
	 * just enough space for when we allocated m
1835
		return NULL;
1844
	 */
1836
	}
1845
	strcpy(m->x, pattern);
1837

    
   
1846

   
1838
	/* the specificity scores are the same as used in the old
1847
	/* the specificity scores are the same as used in the old
1839
	   pattern matcher. */
1848
	   pattern matcher. */
1840
	m->is_pattern = is_pattern;
1849
	m->is_pattern = is_pattern;
1841
	if (specificity == 1 && is_pattern && pattern[0] == 'N')
1850
	if (specificity == 1 && is_pattern && pattern[0] == 'N')
1842
		m->specificity = 0x0802;
1851
		m->specificity = 0x0802;
1843
	else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
1852
	else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
1844
		m->specificity = 0x0901;
1853
		m->specificity = 0x0901;
1845
	else if (specificity == 1 && is_pattern && pattern[0] == 'X')
1854
	else if (specificity == 1 && is_pattern && pattern[0] == 'X')
1846
		m->specificity = 0x0a00;
1855
		m->specificity = 0x0a00;
1847
	else if (specificity == 1 && is_pattern && pattern[0] == '.')
1856
	else if (specificity == 1 && is_pattern && pattern[0] == '.')
1848
		m->specificity = 0x10000;
1857
		m->specificity = 0x10000;
1849
	else if (specificity == 1 && is_pattern && pattern[0] == '!')
1858
	else if (specificity == 1 && is_pattern && pattern[0] == '!')
1850
		m->specificity = 0x20000;
1859
		m->specificity = 0x20000;
1851
	else
1860
	else
1852
		m->specificity = specificity;
1861
		m->specificity = specificity;
1853

    
   
1862

   
1854
	if (!con->pattern_tree) {
1863
	if (!con->pattern_tree) {
1855
		insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
1864
		insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
1856
	} else {
1865
	} else {
1857
		if (already) { /* switch to the new regime (traversing vs appending)*/
1866
		if (already) { /* switch to the new regime (traversing vs appending)*/
1858
			insert_in_next_chars_alt_char_list(nextcharptr, m);
1867
			insert_in_next_chars_alt_char_list(nextcharptr, m);
1859
		} else {
1868
		} else {
1860
			insert_in_next_chars_alt_char_list(&current->next_char, m);
1869
			insert_in_next_chars_alt_char_list(&current->next_char, m);
1861
		}
1870
		}
1862
	}
1871
	}
1863

    
   
1872

   
1864
	return m;
1873
	return m;
1865
}
1874
}
1866

    
   
1875

   
1867
static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
1876
static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
1868
{
1877
{
1869
	struct match_char *m1 = NULL, *m2 = NULL, **m0;
1878
	struct match_char *m1 = NULL, *m2 = NULL, **m0;
1870
	int specif;
1879
	int specif;
1871
	int already;
1880
	int already;
1872
	int pattern = 0;
1881
	int pattern = 0;
1873
	char buf[256];
1882
	char buf[256];
1874
	char extenbuf[512];
1883
	char extenbuf[512];
1875
	char *s1 = extenbuf;
1884
	char *s1 = extenbuf;
1876
	int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
1885
	int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
1877

    
   
1886

   
1878

    
   
1887

   
1879
	ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
1888
	ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
1880

    
   
1889

   
1881
	if (e1->matchcid &&  l1 <= sizeof(extenbuf)) {
1890
	if (e1->matchcid &&  l1 <= sizeof(extenbuf)) {
1882
		strcat(extenbuf, "/");
1891
		strcat(extenbuf, "/");
1883
		strcat(extenbuf, e1->cidmatch);
1892
		strcat(extenbuf, e1->cidmatch);
1884
	} else if (l1 > sizeof(extenbuf)) {
1893
	} else if (l1 > sizeof(extenbuf)) {
1885
		ast_log(LOG_ERROR, "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
1894
		ast_log(LOG_ERROR, "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
1886
		return 0;
1895
		return 0;
1887
	}
1896
	}
1888
#ifdef NEED_DEBUG
1897
#ifdef NEED_DEBUG
1889
	ast_log(LOG_DEBUG, "Adding exten %s%c%s to tree\n", s1, e1->matchcid ? '/' : ' ', e1->matchcid ? e1->cidmatch : "");
1898
	ast_log(LOG_DEBUG, "Adding exten %s%c%s to tree\n", s1, e1->matchcid ? '/' : ' ', e1->matchcid ? e1->cidmatch : "");
1890
#endif
1899
#endif
1891
	m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
1900
	m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
1892
	m0 = &con->pattern_tree;
1901
	m0 = &con->pattern_tree;
1893
	already = 1;
1902
	already = 1;
1894

    
   
1903

   
1895
	if ( *s1 == '_') {
1904
	if ( *s1 == '_') {
1896
		pattern = 1;
1905
		pattern = 1;
1897
		s1++;
1906
		s1++;
1898
	}
1907
	}
1899
	while( *s1 ) {
1908
	while (*s1) {
1900
		if (pattern && *s1 == '[' && *(s1-1) != '\\') {
1909
		if (pattern && *s1 == '[' && *(s1 - 1) != '\\') {
1901
			char *s2 = buf;
1910
			char *s2 = buf;
1902
			buf[0] = 0;
1911
			buf[0] = 0;
1903
			s1++; /* get past the '[' */
1912
			s1++; /* get past the '[' */
1904
			while (*s1 != ']' && *(s1 - 1) != '\\' ) {
1913
			while (*s1 != ']' && *(s1 - 1) != '\\') {
1905
				if (*s1 == '\\') {
1914
				if (*s1 == '\\') {
1906
					if (*(s1 + 1) == ']') {
1915
					if (*(s1 + 1) == ']') {
1907
						*s2++ = ']';
1916
						*s2++ = ']';
1908
						s1++; s1++;
1917
						s1 += 2;
1909
					} else if (*(s1 + 1) == '\\') {
1918
					} else if (*(s1 + 1) == '\\') {
1910
						*s2++ = '\\';
1919
						*s2++ = '\\';
1911
						s1++; s1++;
1920
						s1 += 2;
1912
					} else if (*(s1 + 1) == '-') {
1921
					} else if (*(s1 + 1) == '-') {
1913
						*s2++ = '-';
1922
						*s2++ = '-';
1914
						s1++; s1++;
1923
						s1 += 2;
1915
					} else if (*(s1 + 1) == '[') {
1924
					} else if (*(s1 + 1) == '[') {
1916
						*s2++ = '[';
1925
						*s2++ = '[';
1917
						s1++; s1++;
1926
						s1 += 2;
1918
					}
1927
					}
1919
				} else if (*s1 == '-') { /* remember to add some error checking to all this! */
1928
				} else if (*s1 == '-') { /* remember to add some error checking to all this! */
1920
					char s3 = *(s1 - 1);
1929
					char s3 = *(s1 - 1);
1921
					char s4 = *(s1 + 1);
1930
					char s4 = *(s1 + 1);
1922
					for (s3++; s3 <= s4; s3++) {
1931
					for (s3++; s3 <= s4; s3++) {
1923
						*s2++ = s3;
1932
						*s2++ = s3;
1924
					}
1933
					}
1925
					s1++; s1++;
1934
					s1 += 2;
1926
				} else if (*s1 == '\0') {
1935
				} else if (*s1 == '\0') {
1927
					ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
1936
					ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
1928
					break;
1937
					break;
1929
				} else {
1938
				} else {
1930
					*s2++ = *s1++;
1939
					*s2++ = *s1++;
1931
				}
1940
				}
1932
			}
1941
			}
1933
			*s2 = 0; /* null terminate the exploded range */
1942
			*s2 = 0; /* null terminate the exploded range */
1934
			/* sort the characters */
1943
			/* sort the characters */
1935

    
   
1944

   
1936
			specif = strlen(buf);
1945
			specif = strlen(buf);
1937
			qsort(buf, specif, 1, compare_char);
1946
			qsort(buf, specif, 1, compare_char);
1938
			specif <<= 8;
1947
			specif <<= 8;
1939
			specif += buf[0];
1948
			specif += buf[0];
1940
		} else {
1949
		} else {
1941

    
   

   
1942
			if (*s1 == '\\') {
1950
			if (*s1 == '\\') {
1943
				s1++;
1951
				s1++;
1944
				buf[0] = *s1;
1952
				buf[0] = *s1;
1945
			} else {
1953
			} else {
1946
				if (pattern) {
1954
				if (pattern) {
1947
					if (*s1 == 'n') /* make sure n,x,z patterns are canonicalized to N,X,Z */
1955
					if (*s1 == 'n') { /* make sure n,x,z patterns are canonicalized to N,X,Z */
1948
						*s1 = 'N';
1956
						*s1 = 'N';
1949
					else if (*s1 == 'x')
1957
					} else if (*s1 == 'x') {
1950
						*s1 = 'X';
1958
						*s1 = 'X';
1951
					else if (*s1 == 'z')
1959
					} else if (*s1 == 'z') {
1952
						*s1 = 'Z';
1960
						*s1 = 'Z';
1953
				}
1961
					}

    
   
1962
				}
1954
				buf[0] = *s1;
1963
				buf[0] = *s1;
1955
			}
1964
			}
1956
			buf[1] = 0;
1965
			buf[1] = 0;
1957
			specif = 1;
1966
			specif = 1;
1958
		}
1967
		}
1959
		m2 = 0;
1968
		m2 = 0;
1960
		if (already && (m2 = already_in_tree(m1,buf)) && m2->next_char) {
1969
		if (already && (m2 = already_in_tree(m1, buf, pattern)) && m2->next_char) {
1961
			if (!(*(s1 + 1))) {  /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
1970
			if (!(*(s1 + 1))) {  /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
1962
								  * a shorter pattern might win if the longer one doesn't match */
1971
								a shorter pattern might win if the longer one doesn't match */

    
   
1972
				if (m2->exten) {

    
   
1973
					ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten);

    
   
1974
				}
1963
				m2->exten = e1;
1975
				m2->exten = e1;
1964
				m2->deleted = 0;
1976
				m2->deleted = 0;
1965
			}
1977
			}
1966
			m1 = m2->next_char; /* m1 points to the node to compare against */
1978
			m1 = m2->next_char; /* m1 points to the node to compare against */
1967
			m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
1979
			m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
1968
		} else { /* not already OR not m2 OR nor m2->next_char */
1980
		} else { /* not already OR not m2 OR nor m2->next_char */
1969
			if (m2) {
1981
			if (m2) {
1970
				if (findonly) {
1982
				if (findonly) {
1971
					return m2;
1983
					return m2;
1972
				}
1984
				}
1973
				m1 = m2; /* while m0 stays the same */
1985
				m1 = m2; /* while m0 stays the same */
1974
			} else {
1986
			} else {
1975
				if (findonly) {
1987
				if (findonly) {
1976
					return m1;
1988
					return m1;
1977
				}
1989
				}
1978
				m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0); /* m1 is the node just added */
1990
				if (!(m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0))) { /* m1 is the node just added */

    
   
1991
					return NULL;

    
   
1992
				}
1979
				m0 = &m1->next_char;
1993
				m0 = &m1->next_char;
1980
			}
1994
			}
1981

    
   

   
1982
			if (!(*(s1 + 1))) {
1995
			if (!(*(s1 + 1))) {

    
   
1996
				if (m2) {

    
   
1997
					ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n", m2->exten->exten, e1->exten);

    
   
1998
				}
1983
				m1->deleted = 0;
1999
				m1->deleted = 0;
1984
				m1->exten = e1;
2000
				m1->exten = e1;
1985
			}
2001
			}
1986

    
   
2002

   

    
   
2003
			/* The 'already' variable is a mini-optimization designed to make it so that we

    
   
2004
			 * don't have to call already_in_tree when we know it will return false.

    
   
2005
			 */
1987
			already = 0;
2006
			already = 0;
1988
		}
2007
		}
1989
		s1++; /* advance to next char */
2008
		s1++; /* advance to next char */
1990
	}
2009
	}
1991
	return m1;
2010
	return m1;
1992
}
2011
}
1993

    
   
2012

   
1994
static void create_match_char_tree(struct ast_context *con)
2013
static void create_match_char_tree(struct ast_context *con)
1995
{
2014
{
1996
	struct ast_hashtab_iter *t1;
2015
	struct ast_hashtab_iter *t1;
1997
	struct ast_exten *e1;
2016
	struct ast_exten *e1;
1998
#ifdef NEED_DEBUG
2017
#ifdef NEED_DEBUG
1999
	int biggest_bucket, resizes, numobjs, numbucks;
2018
	int biggest_bucket, resizes, numobjs, numbucks;
2000

    
   
2019

   
2001
	ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
2020
	ast_log(LOG_DEBUG,"Creating Extension Trie for context %s(%p)\n", con->name, con);
2002
	ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
2021
	ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
2003
	ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
2022
	ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
2004
			numobjs, numbucks, biggest_bucket, resizes);
2023
			numobjs, numbucks, biggest_bucket, resizes);
2005
#endif
2024
#endif
2006
	t1 = ast_hashtab_start_traversal(con->root_table);
2025
	t1 = ast_hashtab_start_traversal(con->root_table);
2007
	while ((e1 = ast_hashtab_next(t1))) {
2026
	while ((e1 = ast_hashtab_next(t1))) {
2008
		if (e1->exten) {
2027
		if (e1->exten) {
2009
			add_exten_to_pattern_tree(con, e1, 0);
2028
			add_exten_to_pattern_tree(con, e1, 0);
2010
		} else {
2029
		} else {
2011
			ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
2030
			ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
2012
		}
2031
		}
2013
	}
2032
	}
2014
	ast_hashtab_end_traversal(t1);
2033
	ast_hashtab_end_traversal(t1);
2015
}
2034
}
2016

    
   
2035

   
2017
static void destroy_pattern_tree(struct match_char *pattern_tree) /* pattern tree is a simple binary tree, sort of, so the proper way to destroy it is... recursively! */
2036
static void destroy_pattern_tree(struct match_char *pattern_tree) /* pattern tree is a simple binary tree, sort of, so the proper way to destroy it is... recursively! */
2018
{
2037
{
2019
	/* destroy all the alternates */
2038
	/* destroy all the alternates */
2020
	if (pattern_tree->alt_char) {
2039
	if (pattern_tree->alt_char) {
2021
		destroy_pattern_tree(pattern_tree->alt_char);
2040
		destroy_pattern_tree(pattern_tree->alt_char);
2022
		pattern_tree->alt_char = 0;
2041
		pattern_tree->alt_char = 0;
2023
	}
2042
	}
2024
	/* destroy all the nexts */
2043
	/* destroy all the nexts */
2025
	if (pattern_tree->next_char) {
2044
	if (pattern_tree->next_char) {
2026
		destroy_pattern_tree(pattern_tree->next_char);
2045
		destroy_pattern_tree(pattern_tree->next_char);
2027
		pattern_tree->next_char = 0;
2046
		pattern_tree->next_char = 0;
2028
	}
2047
	}
2029
	pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
2048
	pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
2030
	if (pattern_tree->x) {
2049
	ast_free(pattern_tree);
2031
		free(pattern_tree->x);

   
2032
	}

   
2033
	free(pattern_tree);

   
2034
}
2050
}
2035

    
   
2051

   
2036
/*
2052
/*
2037
 * Special characters used in patterns:
2053
 * Special characters used in patterns:
2038
 *	'_'	underscore is the leading character of a pattern.
2054
 *	'_'	underscore is the leading character of a pattern.
2039
 *		In other position it is treated as a regular char.
2055
 *		In other position it is treated as a regular char.
2040
 *	.	one or more of any character. Only allowed at the end of
2056
 *	.	one or more of any character. Only allowed at the end of
2041
 *		a pattern.
2057
 *		a pattern.
2042
 *	!	zero or more of anything. Also impacts the result of CANMATCH
2058
 *	!	zero or more of anything. Also impacts the result of CANMATCH
2043
 *		and MATCHMORE. Only allowed at the end of a pattern.
2059
 *		and MATCHMORE. Only allowed at the end of a pattern.
2044
 *		In the core routine, ! causes a match with a return code of 2.
2060
 *		In the core routine, ! causes a match with a return code of 2.
2045
 *		In turn, depending on the search mode: (XXX check if it is implemented)
2061
 *		In turn, depending on the search mode: (XXX check if it is implemented)
2046
 *		- E_MATCH retuns 1 (does match)
2062
 *		- E_MATCH retuns 1 (does match)
2047
 *		- E_MATCHMORE returns 0 (no match)
2063
 *		- E_MATCHMORE returns 0 (no match)
2048
 *		- E_CANMATCH returns 1 (does match)
2064
 *		- E_CANMATCH returns 1 (does match)
2049
 *
2065
 *
2050
 *	/	should not appear as it is considered the separator of the CID info.
2066
 *	/	should not appear as it is considered the separator of the CID info.
2051
 *		XXX at the moment we may stop on this char.
2067
 *		XXX at the moment we may stop on this char.
2052
 *
2068
 *
2053
 *	X Z N	match ranges 0-9, 1-9, 2-9 respectively.
2069
 *	X Z N	match ranges 0-9, 1-9, 2-9 respectively.
2054
 *	[	denotes the start of a set of character. Everything inside
2070
 *	[	denotes the start of a set of character. Everything inside
2055
 *		is considered literally. We can have ranges a-d and individual
2071
 *		is considered literally. We can have ranges a-d and individual
2056
 *		characters. A '[' and '-' can be considered literally if they
2072
 *		characters. A '[' and '-' can be considered literally if they
2057
 *		are just before ']'.
2073
 *		are just before ']'.
2058
 *		XXX currently there is no way to specify ']' in a range, nor \ is
2074
 *		XXX currently there is no way to specify ']' in a range, nor \ is
2059
 *		considered specially.
2075
 *		considered specially.
2060
 *
2076
 *
2061
 * When we compare a pattern with a specific extension, all characters in the extension
2077
 * When we compare a pattern with a specific extension, all characters in the extension
2062
 * itself are considered literally.
2078
 * itself are considered literally.
2063
 * XXX do we want to consider space as a separator as well ?
2079
 * XXX do we want to consider space as a separator as well ?
2064
 * XXX do we want to consider the separators in non-patterns as well ?
2080
 * XXX do we want to consider the separators in non-patterns as well ?
2065
 */
2081
 */
2066

    
   
2082

   
2067
/*!
2083
/*!
2068
 * \brief helper functions to sort extensions and patterns in the desired way,
2084
 * \brief helper functions to sort extensions and patterns in the desired way,
2069
 * so that more specific patterns appear first.
2085
 * so that more specific patterns appear first.
2070
 *
2086
 *
2071
 * ext_cmp1 compares individual characters (or sets of), returning
2087
 * ext_cmp1 compares individual characters (or sets of), returning
2072
 * an int where bits 0-7 are the ASCII code of the first char in the set,
2088
 * an int where bits 0-7 are the ASCII code of the first char in the set,
2073
 * while bit 8-15 are the cardinality of the set minus 1.
2089
 * while bit 8-15 are the cardinality of the set minus 1.
2074
 * This way more specific patterns (smaller cardinality) appear first.
2090
 * This way more specific patterns (smaller cardinality) appear first.
2075
 * Wildcards have a special value, so that we can directly compare them to
2091
 * Wildcards have a special value, so that we can directly compare them to
2076
 * sets by subtracting the two values. In particular:
2092
 * sets by subtracting the two values. In particular:
2077
 *  0x000xx		one character, xx
2093
 *  0x000xx		one character, xx
2078
 *  0x0yyxx		yy character set starting with xx
2094
 *  0x0yyxx		yy character set starting with xx
2079
 *  0x10000		'.' (one or more of anything)
2095
 *  0x10000		'.' (one or more of anything)
2080
 *  0x20000		'!' (zero or more of anything)
2096
 *  0x20000		'!' (zero or more of anything)
2081
 *  0x30000		NUL (end of string)
2097
 *  0x30000		NUL (end of string)
2082
 *  0x40000		error in set.
2098
 *  0x40000		error in set.
2083
 * The pointer to the string is advanced according to needs.
2099
 * The pointer to the string is advanced according to needs.
2084
 * NOTES:
2100
 * NOTES:
2085
 *	1. the empty set is equivalent to NUL.
2101
 *	1. the empty set is equivalent to NUL.
2086
 *	2. given that a full set has always 0 as the first element,
2102
 *	2. given that a full set has always 0 as the first element,
2087
 *	   we could encode the special cases as 0xffXX where XX
2103
 *	   we could encode the special cases as 0xffXX where XX
2088
 *	   is 1, 2, 3, 4 as used above.
2104
 *	   is 1, 2, 3, 4 as used above.
2089
 */
2105
 */
2090
static int ext_cmp1(const char **p)
2106
static int ext_cmp1(const char **p)
2091
{
2107
{
2092
	uint32_t chars[8];
2108
	uint32_t chars[8];
2093
	int c, cmin = 0xff, count = 0;
2109
	int c, cmin = 0xff, count = 0;
2094
	const char *end;
2110
	const char *end;
2095

    
   
2111

   
2096
	/* load, sign extend and advance pointer until we find
2112
	/* load, sign extend and advance pointer until we find
2097
	 * a valid character.
2113
	 * a valid character.
2098
	 */
2114
	 */
2099
	c = *(*p)++;
2115
	c = *(*p)++;
2100

    
   
2116

   
2101
	/* always return unless we have a set of chars */
2117
	/* always return unless we have a set of chars */
2102
	switch (toupper(c)) {
2118
	switch (toupper(c)) {
2103
	default:	/* ordinary character */
2119
	default:	/* ordinary character */
2104
		return 0x0000 | (c & 0xff);
2120
		return 0x0000 | (c & 0xff);
2105

    
   
2121

   
2106
	case 'N':	/* 2..9 */
2122
	case 'N':	/* 2..9 */
2107
		return 0x0800 | '2' ;
2123
		return 0x0800 | '2' ;
2108

    
   
2124

   
2109
	case 'X':	/* 0..9 */
2125
	case 'X':	/* 0..9 */
2110
		return 0x0A00 | '0';
2126
		return 0x0A00 | '0';
2111

    
   
2127

   
2112
	case 'Z':	/* 1..9 */
2128
	case 'Z':	/* 1..9 */
2113
		return 0x0900 | '1';
2129
		return 0x0900 | '1';
2114

    
   
2130

   
2115
	case '.':	/* wildcard */
2131
	case '.':	/* wildcard */
2116
		return 0x10000;
2132
		return 0x10000;
2117

    
   
2133

   
2118
	case '!':	/* earlymatch */
2134
	case '!':	/* earlymatch */
2119
		return 0x20000;	/* less specific than NULL */
2135
		return 0x20000;	/* less specific than NULL */
2120

    
   
2136

   
2121
	case '\0':	/* empty string */
2137
	case '\0':	/* empty string */
2122
		*p = NULL;
2138
		*p = NULL;
2123
		return 0x30000;
2139
		return 0x30000;
2124

    
   
2140

   
2125
	case '[':	/* pattern */
2141
	case '[':	/* pattern */
2126
		break;
2142
		break;
2127
	}
2143
	}
2128
	/* locate end of set */
2144
	/* locate end of set */
2129
	end = strchr(*p, ']');
2145
	end = strchr(*p, ']');
2130

    
   
2146

   
2131
	if (end == NULL) {
2147
	if (end == NULL) {
2132
		ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2148
		ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2133
		return 0x40000;	/* XXX make this entry go last... */
2149
		return 0x40000;	/* XXX make this entry go last... */
2134
	}
2150
	}
2135

    
   
2151

   
2136
	memset(chars, '\0', sizeof(chars));	/* clear all chars in the set */
2152
	memset(chars, '\0', sizeof(chars));	/* clear all chars in the set */
2137
	for (; *p < end  ; (*p)++) {
2153
	for (; *p < end  ; (*p)++) {
2138
		unsigned char c1, c2;	/* first-last char in range */
2154
		unsigned char c1, c2;	/* first-last char in range */
2139
		c1 = (unsigned char)((*p)[0]);
2155
		c1 = (unsigned char)((*p)[0]);
2140
		if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
2156
		if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
2141
			c2 = (unsigned char)((*p)[2]);
2157
			c2 = (unsigned char)((*p)[2]);
2142
			*p += 2;	/* skip a total of 3 chars */
2158
			*p += 2;	/* skip a total of 3 chars */
2143
		} else			/* individual character */
2159
		} else			/* individual character */
2144
			c2 = c1;
2160
			c2 = c1;
2145
		if (c1 < cmin)
2161
		if (c1 < cmin)
2146
			cmin = c1;
2162
			cmin = c1;
2147
		for (; c1 <= c2; c1++) {
2163
		for (; c1 <= c2; c1++) {
2148
			uint32_t mask = 1 << (c1 % 32);
2164
			uint32_t mask = 1 << (c1 % 32);
2149
			if ( (chars[ c1 / 32 ] & mask) == 0)
2165
			if ( (chars[ c1 / 32 ] & mask) == 0)
2150
				count += 0x100;
2166
				count += 0x100;
2151
			chars[ c1 / 32 ] |= mask;
2167
			chars[ c1 / 32 ] |= mask;
2152
		}
2168
		}
2153
	}
2169
	}
2154
	(*p)++;
2170
	(*p)++;
2155
	return count == 0 ? 0x30000 : (count | cmin);
2171
	return count == 0 ? 0x30000 : (count | cmin);
2156
}
2172
}
2157

    
   
2173

   
2158
/*!
2174
/*!
2159
 * \brief the full routine to compare extensions in rules.
2175
 * \brief the full routine to compare extensions in rules.
2160
 */
2176
 */
2161
static int ext_cmp(const char *a, const char *b)
2177
static int ext_cmp(const char *a, const char *b)
2162
{
2178
{
2163
	/* make sure non-patterns come first.
2179
	/* make sure non-patterns come first.
2164
	 * If a is not a pattern, it either comes first or
2180
	 * If a is not a pattern, it either comes first or
2165
	 * we use strcmp to compare the strings.
2181
	 * we use strcmp to compare the strings.
2166
	 */
2182
	 */
2167
	int ret = 0;
2183
	int ret = 0;
2168

    
   
2184

   
2169
	if (a[0] != '_')
2185
	if (a[0] != '_')
2170
		return (b[0] == '_') ? -1 : strcmp(a, b);
2186
		return (b[0] == '_') ? -1 : strcmp(a, b);
2171

    
   
2187

   
2172
	/* Now we know a is a pattern; if b is not, a comes first */
2188
	/* Now we know a is a pattern; if b is not, a comes first */
2173
	if (b[0] != '_')
2189
	if (b[0] != '_')
2174
		return 1;
2190
		return 1;
2175
#if 0	/* old mode for ext matching */
2191
#if 0	/* old mode for ext matching */
2176
	return strcmp(a, b);
2192
	return strcmp(a, b);
2177
#endif
2193
#endif
2178
	/* ok we need full pattern sorting routine */
2194
	/* ok we need full pattern sorting routine */
2179
	while (!ret && a && b)
2195
	while (!ret && a && b)
2180
		ret = ext_cmp1(&a) - ext_cmp1(&b);
2196
		ret = ext_cmp1(&a) - ext_cmp1(&b);
2181
	if (ret == 0)
2197
	if (ret == 0)
2182
		return 0;
2198
		return 0;
2183
	else
2199
	else
2184
		return (ret > 0) ? 1 : -1;
2200
		return (ret > 0) ? 1 : -1;
2185
}
2201
}
2186

    
   
2202

   
2187
int ast_extension_cmp(const char *a, const char *b)
2203
int ast_extension_cmp(const char *a, const char *b)
2188
{
2204
{
2189
	return ext_cmp(a, b);
2205
	return ext_cmp(a, b);
2190
}
2206
}
2191

    
   
2207

   
2192
/*!
2208
/*!
2193
 * \internal
2209
 * \internal
2194
 * \brief used ast_extension_{match|close}
2210
 * \brief used ast_extension_{match|close}
2195
 * mode is as follows:
2211
 * mode is as follows:
2196
 *	E_MATCH		success only on exact match
2212
 *	E_MATCH		success only on exact match
2197
 *	E_MATCHMORE	success only on partial match (i.e. leftover digits in pattern)
2213
 *	E_MATCHMORE	success only on partial match (i.e. leftover digits in pattern)
2198
 *	E_CANMATCH	either of the above.
2214
 *	E_CANMATCH	either of the above.
2199
 * \retval 0 on no-match
2215
 * \retval 0 on no-match
2200
 * \retval 1 on match
2216
 * \retval 1 on match
2201
 * \retval 2 on early match.
2217
 * \retval 2 on early match.
2202
 */
2218
 */
2203

    
   
2219

   
2204
static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
2220
static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
2205
{
2221
{
2206
	mode &= E_MATCH_MASK;	/* only consider the relevant bits */
2222
	mode &= E_MATCH_MASK;	/* only consider the relevant bits */
2207

    
   
2223

   
2208
#ifdef NEED_DEBUG_HERE
2224
#ifdef NEED_DEBUG_HERE
2209
	ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
2225
	ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
2210
#endif
2226
#endif
2211

    
   
2227

   
2212
	if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */
2228
	if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */
2213
#ifdef NEED_DEBUG_HERE
2229
#ifdef NEED_DEBUG_HERE
2214
		ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
2230
		ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
2215
#endif
2231
#endif
2216
		return 1;
2232
		return 1;
2217
	}
2233
	}
2218

    
   
2234

   
2219
	if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
2235
	if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
2220
		int ld = strlen(data), lp = strlen(pattern);
2236
		int ld = strlen(data), lp = strlen(pattern);
2221

    
   
2237

   
2222
		if (lp < ld) {		/* pattern too short, cannot match */
2238
		if (lp < ld) {		/* pattern too short, cannot match */
2223
#ifdef NEED_DEBUG_HERE
2239
#ifdef NEED_DEBUG_HERE
2224
			ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
2240
			ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
2225
#endif
2241
#endif
2226
			return 0;
2242
			return 0;
2227
		}
2243
		}
2228
		/* depending on the mode, accept full or partial match or both */
2244
		/* depending on the mode, accept full or partial match or both */
2229
		if (mode == E_MATCH) {
2245
		if (mode == E_MATCH) {
2230
#ifdef NEED_DEBUG_HERE
2246
#ifdef NEED_DEBUG_HERE
2231
			ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
2247
			ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
2232
#endif
2248
#endif
2233
			return !strcmp(pattern, data); /* 1 on match, 0 on fail */
2249
			return !strcmp(pattern, data); /* 1 on match, 0 on fail */
2234
		}
2250
		}
2235
		if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */
2251
		if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */
2236
#ifdef NEED_DEBUG_HERE
2252
#ifdef NEED_DEBUG_HERE
2237
			ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
2253
			ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
2238
#endif
2254
#endif
2239
			return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
2255
			return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
2240
		} else {
2256
		} else {
2241
#ifdef NEED_DEBUG_HERE
2257
#ifdef NEED_DEBUG_HERE
2242
			ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
2258
			ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
2243
#endif
2259
#endif
2244
			return 0;
2260
			return 0;
2245
		}
2261
		}
2246
	}
2262
	}
2247
	pattern++; /* skip leading _ */
2263
	pattern++; /* skip leading _ */
2248
	/*
2264
	/*
2249
	 * XXX below we stop at '/' which is a separator for the CID info. However we should
2265
	 * XXX below we stop at '/' which is a separator for the CID info. However we should
2250
	 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
2266
	 * not store '/' in the pattern at all. When we insure it, we can remove the checks.
2251
	 */
2267
	 */
2252
	while (*data && *pattern && *pattern != '/') {
2268
	while (*data && *pattern && *pattern != '/') {
2253
		const char *end;
2269
		const char *end;
2254

    
   
2270

   
2255
		if (*data == '-') { /* skip '-' in data (just a separator) */
2271
		if (*data == '-') { /* skip '-' in data (just a separator) */
2256
			data++;
2272
			data++;
2257
			continue;
2273
			continue;
2258
		}
2274
		}
2259
		switch (toupper(*pattern)) {
2275
		switch (toupper(*pattern)) {
2260
		case '[':	/* a range */
2276
		case '[':	/* a range */
2261
			end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
2277
			end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
2262
			if (end == NULL) {
2278
			if (end == NULL) {
2263
				ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2279
				ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
2264
				return 0;	/* unconditional failure */
2280
				return 0;	/* unconditional failure */
2265
			}
2281
			}
2266
			for (pattern++; pattern != end; pattern++) {
2282
			for (pattern++; pattern != end; pattern++) {
2267
				if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
2283
				if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
2268
					if (*data >= pattern[0] && *data <= pattern[2])
2284
					if (*data >= pattern[0] && *data <= pattern[2])
2269
						break;	/* match found */
2285
						break;	/* match found */
2270
					else {
2286
					else {
2271
						pattern += 2; /* skip a total of 3 chars */
2287
						pattern += 2; /* skip a total of 3 chars */
2272
						continue;
2288
						continue;
2273
					}
2289
					}
2274
				} else if (*data == pattern[0])
2290
				} else if (*data == pattern[0])
2275
					break;	/* match found */
2291
					break;	/* match found */
2276
			}
2292
			}
2277
			if (pattern == end) {
2293
			if (pattern == end) {
2278
#ifdef NEED_DEBUG_HERE
2294
#ifdef NEED_DEBUG_HERE
2279
				ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
2295
				ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
2280
#endif
2296
#endif
2281
				return 0;
2297
				return 0;
2282
			}
2298
			}
2283
			pattern = end;	/* skip and continue */
2299
			pattern = end;	/* skip and continue */
2284
			break;
2300
			break;
2285
		case 'N':
2301
		case 'N':
2286
			if (*data < '2' || *data > '9') {
2302
			if (*data < '2' || *data > '9') {
2287
#ifdef NEED_DEBUG_HERE
2303
#ifdef NEED_DEBUG_HERE
2288
				ast_log(LOG_NOTICE,"return (0) N is matched\n");
2304
				ast_log(LOG_NOTICE,"return (0) N is matched\n");
2289
#endif
2305
#endif
2290
				return 0;
2306
				return 0;
2291
			}
2307
			}
2292
			break;
2308
			break;
2293
		case 'X':
2309
		case 'X':
2294
			if (*data < '0' || *data > '9') {
2310
			if (*data < '0' || *data > '9') {
2295
#ifdef NEED_DEBUG_HERE
2311
#ifdef NEED_DEBUG_HERE
2296
				ast_log(LOG_NOTICE,"return (0) X is matched\n");
2312
				ast_log(LOG_NOTICE,"return (0) X is matched\n");
2297
#endif
2313
#endif
2298
				return 0;
2314
				return 0;
2299
			}
2315
			}
2300
			break;
2316
			break;
2301
		case 'Z':
2317
		case 'Z':
2302
			if (*data < '1' || *data > '9') {
2318
			if (*data < '1' || *data > '9') {
2303
#ifdef NEED_DEBUG_HERE
2319
#ifdef NEED_DEBUG_HERE
2304
				ast_log(LOG_NOTICE,"return (0) Z is matched\n");
2320
				ast_log(LOG_NOTICE,"return (0) Z is matched\n");
2305
#endif
2321
#endif
2306
				return 0;
2322
				return 0;
2307
			}
2323
			}
2308
			break;
2324
			break;
2309
		case '.':	/* Must match, even with more digits */
2325
		case '.':	/* Must match, even with more digits */
2310
#ifdef NEED_DEBUG_HERE
2326
#ifdef NEED_DEBUG_HERE
2311
			ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
2327
			ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
2312
#endif
2328
#endif
2313
			return 1;
2329
			return 1;
2314
		case '!':	/* Early match */
2330
		case '!':	/* Early match */
2315
#ifdef NEED_DEBUG_HERE
2331
#ifdef NEED_DEBUG_HERE
2316
			ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
2332
			ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
2317
#endif
2333
#endif
2318
			return 2;
2334
			return 2;
2319
		case ' ':
2335
		case ' ':
2320
		case '-':	/* Ignore these in patterns */
2336
		case '-':	/* Ignore these in patterns */
2321
			data--; /* compensate the final data++ */
2337
			data--; /* compensate the final data++ */
2322
			break;
2338
			break;
2323
		default:
2339
		default:
2324
			if (*data != *pattern) {
2340
			if (*data != *pattern) {
2325
#ifdef NEED_DEBUG_HERE
2341
#ifdef NEED_DEBUG_HERE
2326
				ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
2342
				ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
2327
#endif
2343
#endif
2328
				return 0;
2344
				return 0;
2329
			}
2345
			}
2330
		}
2346
		}
2331
		data++;
2347
		data++;
2332
		pattern++;
2348
		pattern++;
2333
	}
2349
	}
2334
	if (*data)			/* data longer than pattern, no match */ {
2350
	if (*data)			/* data longer than pattern, no match */ {
2335
#ifdef NEED_DEBUG_HERE
2351
#ifdef NEED_DEBUG_HERE
2336
		ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
2352
		ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
2337
#endif
2353
#endif
2338
		return 0;
2354
		return 0;
2339
	}
2355
	}
2340

    
   
2356

   
2341
	/*
2357
	/*
2342
	 * match so far, but ran off the end of the data.
2358
	 * match so far, but ran off the end of the data.
2343
	 * Depending on what is next, determine match or not.
2359
	 * Depending on what is next, determine match or not.
2344
	 */
2360
	 */
2345
	if (*pattern == '\0' || *pattern == '/') {	/* exact match */
2361
	if (*pattern == '\0' || *pattern == '/') {	/* exact match */
2346
#ifdef NEED_DEBUG_HERE
2362
#ifdef NEED_DEBUG_HERE
2347
		ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
2363
		ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
2348
#endif
2364
#endif
2349
		return (mode == E_MATCHMORE) ? 0 : 1;	/* this is a failure for E_MATCHMORE */
2365
		return (mode == E_MATCHMORE) ? 0 : 1;	/* this is a failure for E_MATCHMORE */
2350
	} else if (*pattern == '!')	{		/* early match */
2366
	} else if (*pattern == '!')	{		/* early match */
2351
#ifdef NEED_DEBUG_HERE
2367
#ifdef NEED_DEBUG_HERE
2352
		ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
2368
		ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
2353
#endif
2369
#endif
2354
		return 2;
2370
		return 2;
2355
	} else {						/* partial match */
2371
	} else {						/* partial match */
2356
#ifdef NEED_DEBUG_HERE
2372
#ifdef NEED_DEBUG_HERE
2357
		ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
2373
		ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
2358
#endif
2374
#endif
2359
		return (mode == E_MATCH) ? 0 : 1;	/* this is a failure for E_MATCH */
2375
		return (mode == E_MATCH) ? 0 : 1;	/* this is a failure for E_MATCH */
2360
	}
2376
	}
2361
}
2377
}
2362

    
   
2378

   
2363
/*
2379
/*
2364
 * Wrapper around _extension_match_core() to do performance measurement
2380
 * Wrapper around _extension_match_core() to do performance measurement
2365
 * using the profiling code.
2381
 * using the profiling code.
2366
 */
2382
 */
2367
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
2383
static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
2368
{
2384
{
2369
	int i;
2385
	int i;
2370
	static int prof_id = -2;	/* marker for 'unallocated' id */
2386
	static int prof_id = -2;	/* marker for 'unallocated' id */
2371
	if (prof_id == -2) {
2387
	if (prof_id == -2) {
2372
		prof_id = ast_add_profile("ext_match", 0);
2388
		prof_id = ast_add_profile("ext_match", 0);
2373
	}
2389
	}
2374
	ast_mark(prof_id, 1);
2390
	ast_mark(prof_id, 1);
2375
	i = _extension_match_core(pattern, data, mode);
2391
	i = _extension_match_core(pattern, data, mode);
2376
	ast_mark(prof_id, 0);
2392
	ast_mark(prof_id, 0);
2377
	return i;
2393
	return i;
2378
}
2394
}
2379

    
   
2395

   
2380
int ast_extension_match(const char *pattern, const char *data)
2396
int ast_extension_match(const char *pattern, const char *data)
2381
{
2397
{
2382
	return extension_match_core(pattern, data, E_MATCH);
2398
	return extension_match_core(pattern, data, E_MATCH);
2383
}
2399
}
2384

    
   
2400

   
2385
int ast_extension_close(const char *pattern, const char *data, int needmore)
2401
int ast_extension_close(const char *pattern, const char *data, int needmore)
2386
{
2402
{
2387
	if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
2403
	if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
2388
		ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
2404
		ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
2389
	return extension_match_core(pattern, data, needmore);
2405
	return extension_match_core(pattern, data, needmore);
2390
}
2406
}
2391

    
   
2407

   
2392
struct fake_context /* this struct is purely for matching in the hashtab */
2408
struct fake_context /* this struct is purely for matching in the hashtab */
2393
{
2409
{
2394
	ast_rwlock_t lock;
2410
	ast_rwlock_t lock;
2395
	struct ast_exten *root;
2411
	struct ast_exten *root;
2396
	struct ast_hashtab *root_table;
2412
	struct ast_hashtab *root_table;
2397
	struct match_char *pattern_tree;
2413
	struct match_char *pattern_tree;
2398
	struct ast_context *next;
2414
	struct ast_context *next;
2399
	struct ast_include *includes;
2415
	struct ast_include *includes;
2400
	struct ast_ignorepat *ignorepats;
2416
	struct ast_ignorepat *ignorepats;
2401
	const char *registrar;
2417
	const char *registrar;
2402
	int refcount;
2418
	int refcount;
2403
	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
2419
	AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
2404
	ast_mutex_t macrolock;
2420
	ast_mutex_t macrolock;
2405
	char name[256];
2421
	char name[256];
2406
};
2422
};
2407

    
   
2423

   
2408
struct ast_context *ast_context_find(const char *name)
2424
struct ast_context *ast_context_find(const char *name)
2409
{
2425
{
2410
	struct ast_context *tmp = NULL;
2426
	struct ast_context *tmp = NULL;
2411
	struct fake_context item;
2427
	struct fake_context item;
2412

    
   
2428

   
2413
	ast_copy_string(item.name, name, sizeof(item.name));
2429
	ast_copy_string(item.name, name, sizeof(item.name));
2414

    
   
2430

   
2415
	ast_rdlock_contexts();
2431
	ast_rdlock_contexts();
2416
	if( contexts_table ) {
2432
	if( contexts_table ) {
2417
		tmp = ast_hashtab_lookup(contexts_table,&item);
2433
		tmp = ast_hashtab_lookup(contexts_table,&item);
2418
	} else {
2434
	} else {
2419
		while ( (tmp = ast_walk_contexts(tmp)) ) {
2435
		while ( (tmp = ast_walk_contexts(tmp)) ) {
2420
			if (!name || !strcasecmp(name, tmp->name)) {
2436
			if (!name || !strcasecmp(name, tmp->name)) {
2421
				break;
2437
				break;
2422
			}
2438
			}
2423
		}
2439
		}
2424
	}
2440
	}
2425
	ast_unlock_contexts();
2441
	ast_unlock_contexts();
2426
	return tmp;
2442
	return tmp;
2427
}
2443
}
2428

    
   
2444

   
2429
#define STATUS_NO_CONTEXT	1
2445
#define STATUS_NO_CONTEXT	1
2430
#define STATUS_NO_EXTENSION	2
2446
#define STATUS_NO_EXTENSION	2
2431
#define STATUS_NO_PRIORITY	3
2447
#define STATUS_NO_PRIORITY	3
2432
#define STATUS_NO_LABEL		4
2448
#define STATUS_NO_LABEL		4
2433
#define STATUS_SUCCESS		5
2449
#define STATUS_SUCCESS		5
2434

    
   
2450

   
2435
static int matchcid(const char *cidpattern, const char *callerid)
2451
static int matchcid(const char *cidpattern, const char *callerid)
2436
{
2452
{
2437
	/* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
2453
	/* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
2438
	   failing to get a number should count as a match, otherwise not */
2454
	   failing to get a number should count as a match, otherwise not */
2439

    
   
2455

   
2440
	if (ast_strlen_zero(callerid)) {
2456
	if (ast_strlen_zero(callerid)) {
2441
		return ast_strlen_zero(cidpattern) ? 1 : 0;
2457
		return ast_strlen_zero(cidpattern) ? 1 : 0;
2442
	}
2458
	}
2443

    
   
2459

   
2444
	return ast_extension_match(cidpattern, callerid);
2460
	return ast_extension_match(cidpattern, callerid);
2445
}
2461
}
2446

    
   
2462

   
2447
struct ast_exten *pbx_find_extension(struct ast_channel *chan,
2463
struct ast_exten *pbx_find_extension(struct ast_channel *chan,
2448
	struct ast_context *bypass, struct pbx_find_info *q,
2464
	struct ast_context *bypass, struct pbx_find_info *q,
2449
	const char *context, const char *exten, int priority,
2465
	const char *context, const char *exten, int priority,
2450
	const char *label, const char *callerid, enum ext_match_t action)
2466
	const char *label, const char *callerid, enum ext_match_t action)
2451
{
2467
{
2452
	int x, res;
2468
	int x, res;
2453
	struct ast_context *tmp = NULL;
2469
	struct ast_context *tmp = NULL;
2454
	struct ast_exten *e = NULL, *eroot = NULL;
2470
	struct ast_exten *e = NULL, *eroot = NULL;
2455
	struct ast_include *i = NULL;
2471
	struct ast_include *i = NULL;
2456
	struct ast_sw *sw = NULL;
2472
	struct ast_sw *sw = NULL;
2457
	struct ast_exten pattern = {NULL, };
2473
	struct ast_exten pattern = {NULL, };
2458
	struct scoreboard score = {0, };
2474
	struct scoreboard score = {0, };
2459
	struct ast_str *tmpdata = NULL;
2475
	struct ast_str *tmpdata = NULL;
2460

    
   
2476

   
2461
	pattern.label = label;
2477
	pattern.label = label;
2462
	pattern.priority = priority;
2478
	pattern.priority = priority;
2463
#ifdef NEED_DEBUG_HERE
2479
#ifdef NEED_DEBUG_HERE
2464
	ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
2480
	ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
2465
#endif
2481
#endif
2466

    
   
2482

   
2467
	/* Initialize status if appropriate */
2483
	/* Initialize status if appropriate */
2468
	if (q->stacklen == 0) {
2484
	if (q->stacklen == 0) {
2469
		q->status = STATUS_NO_CONTEXT;
2485
		q->status = STATUS_NO_CONTEXT;
2470
		q->swo = NULL;
2486
		q->swo = NULL;
2471
		q->data = NULL;
2487
		q->data = NULL;
2472
		q->foundcontext = NULL;
2488
		q->foundcontext = NULL;
2473
	} else if (q->stacklen >= AST_PBX_MAX_STACK) {
2489
	} else if (q->stacklen >= AST_PBX_MAX_STACK) {
2474
		ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
2490
		ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
2475
		return NULL;
2491
		return NULL;
2476
	}
2492
	}
2477

    
   
2493

   
2478
	/* Check first to see if we've already been checked */
2494
	/* Check first to see if we've already been checked */
2479
	for (x = 0; x < q->stacklen; x++) {
2495
	for (x = 0; x < q->stacklen; x++) {
2480
		if (!strcasecmp(q->incstack[x], context))
2496
		if (!strcasecmp(q->incstack[x], context))
2481
			return NULL;
2497
			return NULL;
2482
	}
2498
	}
2483

    
   
2499

   
2484
	if (bypass) { /* bypass means we only look there */
2500
	if (bypass) { /* bypass means we only look there */
2485
		tmp = bypass;
2501
		tmp = bypass;
2486
	} else {      /* look in contexts */
2502
	} else {      /* look in contexts */
2487
		struct fake_context item;
2503
		struct fake_context item;
2488

    
   
2504

   
2489
		ast_copy_string(item.name, context, sizeof(item.name));
2505
		ast_copy_string(item.name, context, sizeof(item.name));
2490

    
   
2506

   
2491
		tmp = ast_hashtab_lookup(contexts_table, &item);
2507
		tmp = ast_hashtab_lookup(contexts_table, &item);
2492
#ifdef NOTNOW

   
2493
		tmp = NULL;

   
2494
		while ((tmp = ast_walk_contexts(tmp)) ) {

   
2495
			if (!strcmp(tmp->name, context)) {

   
2496
				break;

   
2497
			}

   
2498
		}

   
2499
#endif

   
2500
		if (!tmp) {
2508
		if (!tmp) {
2501
			return NULL;
2509
			return NULL;
2502
		}
2510
		}
2503
	}
2511
	}
2504

    
   
2512

   
2505
	if (q->status < STATUS_NO_EXTENSION)
2513
	if (q->status < STATUS_NO_EXTENSION)
2506
		q->status = STATUS_NO_EXTENSION;
2514
		q->status = STATUS_NO_EXTENSION;
2507

    
   
2515

   
2508
	/* Do a search for matching extension */
2516
	/* Do a search for matching extension */
2509

    
   
2517

   
2510
	eroot = NULL;
2518
	eroot = NULL;
2511
	score.total_specificity = 0;
2519
	score.total_specificity = 0;
2512
	score.exten = 0;
2520
	score.exten = 0;
2513
	score.total_length = 0;
2521
	score.total_length = 0;
2514
	if (!tmp->pattern_tree && tmp->root_table) {
2522
	if (!tmp->pattern_tree && tmp->root_table) {
2515
		create_match_char_tree(tmp);
2523
		create_match_char_tree(tmp);
2516
#ifdef NEED_DEBUG
2524
#ifdef NEED_DEBUG
2517
		ast_log(LOG_DEBUG, "Tree Created in context %s:\n", context);
2525
		ast_log(LOG_DEBUG, "Tree Created in context %s:\n", context);
2518
		log_match_char_tree(tmp->pattern_tree," ");
2526
		log_match_char_tree(tmp->pattern_tree," ");
2519
#endif
2527
#endif
2520
	}
2528
	}
2521
#ifdef NEED_DEBUG
2529
#ifdef NEED_DEBUG
2522
	ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
2530
	ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
2523
	log_match_char_tree(tmp->pattern_tree, "::  ");
2531
	log_match_char_tree(tmp->pattern_tree, "::  ");
2524
#endif
2532
#endif
2525

    
   
2533

   
2526
	do {
2534
	do {
2527
		if (!ast_strlen_zero(overrideswitch)) {
2535
		if (!ast_strlen_zero(overrideswitch)) {
2528
			char *osw = ast_strdupa(overrideswitch), *name;
2536
			char *osw = ast_strdupa(overrideswitch), *name;
2529
			struct ast_switch *asw;
2537
			struct ast_switch *asw;
2530
			ast_switch_f *aswf = NULL;
2538
			ast_switch_f *aswf = NULL;
2531
			char *datap;
2539
			char *datap;
2532
			int eval = 0;
2540
			int eval = 0;
2533

    
   
2541

   
2534
			name = strsep(&osw, "/");
2542
			name = strsep(&osw, "/");
2535
			asw = pbx_findswitch(name);
2543
			asw = pbx_findswitch(name);
2536

    
   
2544

   
2537
			if (!asw) {
2545
			if (!asw) {
2538
				ast_log(LOG_WARNING, "No such switch '%s'\n", name);
2546
				ast_log(LOG_WARNING, "No such switch '%s'\n", name);
2539
				break;
2547
				break;
2540
			}
2548
			}
2541

    
   
2549

   
2542
			if (osw && strchr(osw, '$')) {
2550
			if (osw && strchr(osw, '$')) {
2543
				eval = 1;
2551
				eval = 1;
2544
			}
2552
			}
2545

    
   
2553

   
2546
			if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2554
			if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2547
				ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!");
2555
				ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!");
2548
				break;
2556
				break;
2549
			} else if (eval) {
2557
			} else if (eval) {
2550
				/* Substitute variables now */
2558
				/* Substitute variables now */
2551
				pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2559
				pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2552
				datap = ast_str_buffer(tmpdata);
2560
				datap = ast_str_buffer(tmpdata);
2553
			} else {
2561
			} else {
2554
				datap = osw;
2562
				datap = osw;
2555
			}
2563
			}
2556

    
   
2564

   
2557
			/* equivalent of extension_match_core() at the switch level */
2565
			/* equivalent of extension_match_core() at the switch level */
2558
			if (action == E_CANMATCH)
2566
			if (action == E_CANMATCH)
2559
				aswf = asw->canmatch;
2567
				aswf = asw->canmatch;
2560
			else if (action == E_MATCHMORE)
2568
			else if (action == E_MATCHMORE)
2561
				aswf = asw->matchmore;
2569
				aswf = asw->matchmore;
2562
			else /* action == E_MATCH */
2570
			else /* action == E_MATCH */
2563
				aswf = asw->exists;
2571
				aswf = asw->exists;
2564
			if (!aswf) {
2572
			if (!aswf) {
2565
				res = 0;
2573
				res = 0;
2566
			} else {
2574
			} else {
2567
				if (chan) {
2575
				if (chan) {
2568
					ast_autoservice_start(chan);
2576
					ast_autoservice_start(chan);
2569
				}
2577
				}
2570
				res = aswf(chan, context, exten, priority, callerid, datap);
2578
				res = aswf(chan, context, exten, priority, callerid, datap);
2571
				if (chan) {
2579
				if (chan) {
2572
					ast_autoservice_stop(chan);
2580
					ast_autoservice_stop(chan);
2573
				}
2581
				}
2574
			}
2582
			}
2575
			if (res) {	/* Got a match */
2583
			if (res) {	/* Got a match */
2576
				q->swo = asw;
2584
				q->swo = asw;
2577
				q->data = datap;
2585
				q->data = datap;
2578
				q->foundcontext = context;
2586
				q->foundcontext = context;
2579
				/* XXX keep status = STATUS_NO_CONTEXT ? */
2587
				/* XXX keep status = STATUS_NO_CONTEXT ? */
2580
				return NULL;
2588
				return NULL;
2581
			}
2589
			}
2582
		}
2590
		}
2583
	} while (0);
2591
	} while (0);
2584

    
   
2592

   
2585
	if (extenpatternmatchnew) {
2593
	if (extenpatternmatchnew) {
2586
		new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
2594
		new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
2587
		eroot = score.exten;
2595
		eroot = score.exten;
2588

    
   
2596

   
2589
		if (score.last_char == '!' && action == E_MATCHMORE) {
2597
		if (score.last_char == '!' && action == E_MATCHMORE) {
2590
			/* We match an extension ending in '!'.
2598
			/* We match an extension ending in '!'.
2591
			 * The decision in this case is final and is NULL (no match).
2599
			 * The decision in this case is final and is NULL (no match).
2592
			 */
2600
			 */
2593
#ifdef NEED_DEBUG_HERE
2601
#ifdef NEED_DEBUG_HERE
2594
			ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
2602
			ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
2595
#endif
2603
#endif
2596
			return NULL;
2604
			return NULL;
2597
		}
2605
		}
2598

    
   
2606

   
2599
		if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
2607
		if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
2600
			q->status = STATUS_SUCCESS;
2608
			q->status = STATUS_SUCCESS;
2601
#ifdef NEED_DEBUG_HERE
2609
#ifdef NEED_DEBUG_HERE
2602
			ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
2610
			ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
2603
#endif
2611
#endif
2604
			return score.canmatch_exten;
2612
			return score.canmatch_exten;
2605
		}
2613
		}
2606

    
   
2614

   
2607
		if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
2615
		if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
2608
			if (score.node) {
2616
			if (score.node) {
2609
				struct ast_exten *z = trie_find_next_match(score.node);
2617
				struct ast_exten *z = trie_find_next_match(score.node);
2610
				if (z) {
2618
				if (z) {
2611
#ifdef NEED_DEBUG_HERE
2619
#ifdef NEED_DEBUG_HERE
2612
					ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
2620
					ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
2613
#endif
2621
#endif
2614
				} else {
2622
				} else {
2615
					if (score.canmatch_exten) {
2623
					if (score.canmatch_exten) {
2616
#ifdef NEED_DEBUG_HERE
2624
#ifdef NEED_DEBUG_HERE
2617
						ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
2625
						ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
2618
#endif
2626
#endif
2619
						return score.canmatch_exten;
2627
						return score.canmatch_exten;
2620
					} else {
2628
					} else {
2621
#ifdef NEED_DEBUG_HERE
2629
#ifdef NEED_DEBUG_HERE
2622
						ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
2630
						ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
2623
#endif
2631
#endif
2624
					}
2632
					}
2625
				}
2633
				}
2626
				return z;
2634
				return z;
2627
			}
2635
			}
2628
#ifdef NEED_DEBUG_HERE
2636
#ifdef NEED_DEBUG_HERE
2629
			ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
2637
			ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
2630
#endif
2638
#endif
2631
			return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
2639
			return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
2632
		}
2640
		}
2633

    
   
2641

   
2634
		if (eroot) {
2642
		if (eroot) {
2635
			/* found entry, now look for the right priority */
2643
			/* found entry, now look for the right priority */
2636
			if (q->status < STATUS_NO_PRIORITY)
2644
			if (q->status < STATUS_NO_PRIORITY)
2637
				q->status = STATUS_NO_PRIORITY;
2645
				q->status = STATUS_NO_PRIORITY;
2638
			e = NULL;
2646
			e = NULL;
2639
			if (action == E_FINDLABEL && label ) {
2647
			if (action == E_FINDLABEL && label ) {
2640
				if (q->status < STATUS_NO_LABEL)
2648
				if (q->status < STATUS_NO_LABEL)
2641
					q->status = STATUS_NO_LABEL;
2649
					q->status = STATUS_NO_LABEL;
2642
				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2650
				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2643
			} else {
2651
			} else {
2644
				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2652
				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2645
			}
2653
			}
2646
			if (e) {	/* found a valid match */
2654
			if (e) {	/* found a valid match */
2647
				q->status = STATUS_SUCCESS;
2655
				q->status = STATUS_SUCCESS;
2648
				q->foundcontext = context;
2656
				q->foundcontext = context;
2649
#ifdef NEED_DEBUG_HERE
2657
#ifdef NEED_DEBUG_HERE
2650
				ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
2658
				ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
2651
#endif
2659
#endif
2652
				return e;
2660
				return e;
2653
			}
2661
			}
2654
		}
2662
		}
2655
	} else {   /* the old/current default exten pattern match algorithm */
2663
	} else {   /* the old/current default exten pattern match algorithm */
2656

    
   
2664

   
2657
		/* scan the list trying to match extension and CID */
2665
		/* scan the list trying to match extension and CID */
2658
		eroot = NULL;
2666
		eroot = NULL;
2659
		while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
2667
		while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
2660
			int match = extension_match_core(eroot->exten, exten, action);
2668
			int match = extension_match_core(eroot->exten, exten, action);
2661
			/* 0 on fail, 1 on match, 2 on earlymatch */
2669
			/* 0 on fail, 1 on match, 2 on earlymatch */
2662

    
   
2670

   
2663
			if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
2671
			if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
2664
				continue;	/* keep trying */
2672
				continue;	/* keep trying */
2665
			if (match == 2 && action == E_MATCHMORE) {
2673
			if (match == 2 && action == E_MATCHMORE) {
2666
				/* We match an extension ending in '!'.
2674
				/* We match an extension ending in '!'.
2667
				 * The decision in this case is final and is NULL (no match).
2675
				 * The decision in this case is final and is NULL (no match).
2668
				 */
2676
				 */
2669
				return NULL;
2677
				return NULL;
2670
			}
2678
			}
2671
			/* found entry, now look for the right priority */
2679
			/* found entry, now look for the right priority */
2672
			if (q->status < STATUS_NO_PRIORITY)
2680
			if (q->status < STATUS_NO_PRIORITY)
2673
				q->status = STATUS_NO_PRIORITY;
2681
				q->status = STATUS_NO_PRIORITY;
2674
			e = NULL;
2682
			e = NULL;
2675
			if (action == E_FINDLABEL && label ) {
2683
			if (action == E_FINDLABEL && label ) {
2676
				if (q->status < STATUS_NO_LABEL)
2684
				if (q->status < STATUS_NO_LABEL)
2677
					q->status = STATUS_NO_LABEL;
2685
					q->status = STATUS_NO_LABEL;
2678
				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2686
				e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
2679
			} else {
2687
			} else {
2680
				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2688
				e = ast_hashtab_lookup(eroot->peer_table, &pattern);
2681
			}
2689
			}
2682
#ifdef NOTNOW

   
2683
			while ( (e = ast_walk_extension_priorities(eroot, e)) ) {

   
2684
				/* Match label or priority */

   
2685
				if (action == E_FINDLABEL) {

   
2686
					if (q->status < STATUS_NO_LABEL)

   
2687
						q->status = STATUS_NO_LABEL;

   
2688
					if (label && e->label && !strcmp(label, e->label))

   
2689
						break;	/* found it */

   
2690
				} else if (e->priority == priority) {

   
2691
					break;	/* found it */

   
2692
				} /* else keep searching */

   
2693
			}

   
2694
#endif

   
2695
			if (e) {	/* found a valid match */
2690
			if (e) {	/* found a valid match */
2696
				q->status = STATUS_SUCCESS;
2691
				q->status = STATUS_SUCCESS;
2697
				q->foundcontext = context;
2692
				q->foundcontext = context;
2698
				return e;
2693
				return e;
2699
			}
2694
			}
2700
		}
2695
		}
2701
	}
2696
	}
2702

    
   
2697

   
2703
	/* Check alternative switches */
2698
	/* Check alternative switches */
2704
	AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
2699
	AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
2705
		struct ast_switch *asw = pbx_findswitch(sw->name);
2700
		struct ast_switch *asw = pbx_findswitch(sw->name);
2706
		ast_switch_f *aswf = NULL;
2701
		ast_switch_f *aswf = NULL;
2707
		char *datap;
2702
		char *datap;
2708

    
   
2703

   
2709
		if (!asw) {
2704
		if (!asw) {
2710
			ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
2705
			ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
2711
			continue;
2706
			continue;
2712
		}
2707
		}
2713

    
   
2708

   
2714
		/* Substitute variables now */
2709
		/* Substitute variables now */
2715
		if (sw->eval) {
2710
		if (sw->eval) {
2716
			if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2711
			if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
2717
				ast_log(LOG_WARNING, "Can't evaluate switch?!");
2712
				ast_log(LOG_WARNING, "Can't evaluate switch?!");
2718
				continue;
2713
				continue;
2719
			}
2714
			}
2720
			pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2715
			pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
2721
		}
2716
		}
2722

    
   
2717

   
2723
		/* equivalent of extension_match_core() at the switch level */
2718
		/* equivalent of extension_match_core() at the switch level */
2724
		if (action == E_CANMATCH)
2719
		if (action == E_CANMATCH)
2725
			aswf = asw->canmatch;
2720
			aswf = asw->canmatch;
2726
		else if (action == E_MATCHMORE)
2721
		else if (action == E_MATCHMORE)
2727
			aswf = asw->matchmore;
2722
			aswf = asw->matchmore;
2728
		else /* action == E_MATCH */
2723
		else /* action == E_MATCH */
2729
			aswf = asw->exists;
2724
			aswf = asw->exists;
2730
		datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
2725
		datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
2731
		if (!aswf)
2726
		if (!aswf)
2732
			res = 0;
2727
			res = 0;
2733
		else {
2728
		else {
2734
			if (chan)
2729
			if (chan)
2735
				ast_autoservice_start(chan);
2730
				ast_autoservice_start(chan);
2736
			res = aswf(chan, context, exten, priority, callerid, datap);
2731
			res = aswf(chan, context, exten, priority, callerid, datap);
2737
			if (chan)
2732
			if (chan)
2738
				ast_autoservice_stop(chan);
2733
				ast_autoservice_stop(chan);
2739
		}
2734
		}
2740
		if (res) {	/* Got a match */
2735
		if (res) {	/* Got a match */
2741
			q->swo = asw;
2736
			q->swo = asw;
2742
			q->data = datap;
2737
			q->data = datap;
2743
			q->foundcontext = context;
2738
			q->foundcontext = context;
2744
			/* XXX keep status = STATUS_NO_CONTEXT ? */
2739
			/* XXX keep status = STATUS_NO_CONTEXT ? */
2745
			return NULL;
2740
			return NULL;
2746
		}
2741
		}
2747
	}
2742
	}
2748
	q->incstack[q->stacklen++] = tmp->name;	/* Setup the stack */
2743
	q->incstack[q->stacklen++] = tmp->name;	/* Setup the stack */
2749
	/* Now try any includes we have in this context */
2744
	/* Now try any includes we have in this context */
2750
	for (i = tmp->includes; i; i = i->next) {
2745
	for (i = tmp->includes; i; i = i->next) {
2751
		if (include_valid(i)) {
2746
		if (include_valid(i)) {
2752
			if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
2747
			if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
2753
#ifdef NEED_DEBUG_HERE
2748
#ifdef NEED_DEBUG_HERE
2754
				ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
2749
				ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
2755
#endif
2750
#endif
2756
				return e;
2751
				return e;
2757
			}
2752
			}
2758
			if (q->swo)
2753
			if (q->swo)
2759
				return NULL;
2754
				return NULL;
2760
		}
2755
		}
2761
	}
2756
	}
2762
	return NULL;
2757
	return NULL;
2763
}
2758
}
2764

    
   
2759

   
2765
/*!
2760
/*!
2766
 * \brief extract offset:length from variable name.
2761
 * \brief extract offset:length from variable name.
2767
 * \return 1 if there is a offset:length part, which is
2762
 * \return 1 if there is a offset:length part, which is
2768
 * trimmed off (values go into variables)
2763
 * trimmed off (values go into variables)
2769
 */
2764
 */
2770
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
2765
static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
2771
{
2766
{
2772
	int parens = 0;
2767
	int parens = 0;
2773

    
   
2768

   
2774
	*offset = 0;
2769
	*offset = 0;
2775
	*length = INT_MAX;
2770
	*length = INT_MAX;
2776
	*isfunc = 0;
2771
	*isfunc = 0;
2777
	for (; *var; var++) {
2772
	for (; *var; var++) {
2778
		if (*var == '(') {
2773
		if (*var == '(') {
2779
			(*isfunc)++;
2774
			(*isfunc)++;
2780
			parens++;
2775
			parens++;
2781
		} else if (*var == ')') {
2776
		} else if (*var == ')') {
2782
			parens--;
2777
			parens--;
2783
		} else if (*var == ':' && parens == 0) {
2778
		} else if (*var == ':' && parens == 0) {
2784
			*var++ = '\0';
2779
			*var++ = '\0';
2785
			sscanf(var, "%d:%d", offset, length);
2780
			sscanf(var, "%d:%d", offset, length);
2786
			return 1; /* offset:length valid */
2781
			return 1; /* offset:length valid */
2787
		}
2782
		}
2788
	}
2783
	}
2789
	return 0;
2784
	return 0;
2790
}
2785
}
2791

    
   
2786

   
2792
/*!
2787
/*!
2793
 *\brief takes a substring. It is ok to call with value == workspace.
2788
 *\brief takes a substring. It is ok to call with value == workspace.
2794
 * \param value
2789
 * \param value
2795
 * \param offset < 0 means start from the end of the string and set the beginning
2790
 * \param offset < 0 means start from the end of the string and set the beginning
2796
 *   to be that many characters back.
2791
 *   to be that many characters back.
2797
 * \param length is the length of the substring, a value less than 0 means to leave
2792
 * \param length is the length of the substring, a value less than 0 means to leave
2798
 * that many off the end.
2793
 * that many off the end.
2799
 * \param workspace
2794
 * \param workspace
2800
 * \param workspace_len
2795
 * \param workspace_len
2801
 * Always return a copy in workspace.
2796
 * Always return a copy in workspace.
2802
 */
2797
 */
2803
static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
2798
static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
2804
{
2799
{
2805
	char *ret = workspace;
2800
	char *ret = workspace;
2806
	int lr;	/* length of the input string after the copy */
2801
	int lr;	/* length of the input string after the copy */
2807

    
   
2802

   
2808
	ast_copy_string(workspace, value, workspace_len); /* always make a copy */
2803
	ast_copy_string(workspace, value, workspace_len); /* always make a copy */
2809

    
   
2804

   
2810
	lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
2805
	lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
2811

    
   
2806

   
2812
	/* Quick check if no need to do anything */
2807
	/* Quick check if no need to do anything */
2813
	if (offset == 0 && length >= lr)	/* take the whole string */
2808
	if (offset == 0 && length >= lr)	/* take the whole string */
2814
		return ret;
2809
		return ret;
2815

    
   
2810

   
2816
	if (offset < 0)	{	/* translate negative offset into positive ones */
2811
	if (offset < 0)	{	/* translate negative offset into positive ones */
2817
		offset = lr + offset;
2812
		offset = lr + offset;
2818
		if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
2813
		if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
2819
			offset = 0;
2814
			offset = 0;
2820
	}
2815
	}
2821

    
   
2816

   
2822
	/* too large offset result in empty string so we know what to return */
2817
	/* too large offset result in empty string so we know what to return */
2823
	if (offset >= lr)
2818
	if (offset >= lr)
2824
		return ret + lr;	/* the final '\0' */
2819
		return ret + lr;	/* the final '\0' */
2825

    
   
2820

   
2826
	ret += offset;		/* move to the start position */
2821
	ret += offset;		/* move to the start position */
2827
	if (length >= 0 && length < lr - offset)	/* truncate if necessary */
2822
	if (length >= 0 && length < lr - offset)	/* truncate if necessary */
2828
		ret[length] = '\0';
2823
		ret[length] = '\0';
2829
	else if (length < 0) {
2824
	else if (length < 0) {
2830
		if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
2825
		if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
2831
			ret[lr + length - offset] = '\0';
2826
			ret[lr + length - offset] = '\0';
2832
		else
2827
		else
2833
			ret[0] = '\0';
2828
			ret[0] = '\0';
2834
	}
2829
	}
2835

    
   
2830

   
2836
	return ret;
2831
	return ret;
2837
}
2832
}
2838

    
   
2833

   
2839
/*! \brief  Support for Asterisk built-in variables in the dialplan
2834
/*! \brief  Support for Asterisk built-in variables in the dialplan
2840

    
   
2835

   
2841
\note	See also
2836
\note	See also
2842
	- \ref AstVar	Channel variables
2837
	- \ref AstVar	Channel variables
2843
	- \ref AstCauses The HANGUPCAUSE variable
2838
	- \ref AstCauses The HANGUPCAUSE variable
2844
 */
2839
 */
2845
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
2840
void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
2846
{
2841
{
2847
	const char not_found = '\0';
2842
	const char not_found = '\0';
2848
	char *tmpvar;
2843
	char *tmpvar;
2849
	const char *s;	/* the result */
2844
	const char *s;	/* the result */
2850
	int offset, length;
2845
	int offset, length;
2851
	int i, need_substring;
2846
	int i, need_substring;
2852
	struct varshead *places[2] = { headp, &globals };	/* list of places where we may look */
2847
	struct varshead *places[2] = { headp, &globals };	/* list of places where we may look */
2853

    
   
2848

   
2854
	if (c) {
2849
	if (c) {
2855
		ast_channel_lock(c);
2850
		ast_channel_lock(c);
2856
		places[0] = &c->varshead;
2851
		places[0] = &c->varshead;
2857
	}
2852
	}
2858
	/*
2853
	/*
2859
	 * Make a copy of var because parse_variable_name() modifies the string.
2854
	 * Make a copy of var because parse_variable_name() modifies the string.
2860
	 * Then if called directly, we might need to run substring() on the result;
2855
	 * Then if called directly, we might need to run substring() on the result;
2861
	 * remember this for later in 'need_substring', 'offset' and 'length'
2856
	 * remember this for later in 'need_substring', 'offset' and 'length'
2862
	 */
2857
	 */
2863
	tmpvar = ast_strdupa(var);	/* parse_variable_name modifies the string */
2858
	tmpvar = ast_strdupa(var);	/* parse_variable_name modifies the string */
2864
	need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
2859
	need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
2865

    
   
2860

   
2866
	/*
2861
	/*
2867
	 * Look first into predefined variables, then into variable lists.
2862
	 * Look first into predefined variables, then into variable lists.
2868
	 * Variable 's' points to the result, according to the following rules:
2863
	 * Variable 's' points to the result, according to the following rules:
2869
	 * s == &not_found (set at the beginning) means that we did not find a
2864
	 * s == &not_found (set at the beginning) means that we did not find a
2870
	 *	matching variable and need to look into more places.
2865
	 *	matching variable and need to look into more places.
2871
	 * If s != &not_found, s is a valid result string as follows:
2866
	 * If s != &not_found, s is a valid result string as follows:
2872
	 * s = NULL if the variable does not have a value;
2867
	 * s = NULL if the variable does not have a value;
2873
	 *	you typically do this when looking for an unset predefined variable.
2868
	 *	you typically do this when looking for an unset predefined variable.
2874
	 * s = workspace if the result has been assembled there;
2869
	 * s = workspace if the result has been assembled there;
2875
	 *	typically done when the result is built e.g. with an snprintf(),
2870
	 *	typically done when the result is built e.g. with an snprintf(),
2876
	 *	so we don't need to do an additional copy.
2871
	 *	so we don't need to do an additional copy.
2877
	 * s != workspace in case we have a string, that needs to be copied
2872
	 * s != workspace in case we have a string, that needs to be copied
2878
	 *	(the ast_copy_string is done once for all at the end).
2873
	 *	(the ast_copy_string is done once for all at the end).
2879
	 *	Typically done when the result is already available in some string.
2874
	 *	Typically done when the result is already available in some string.
2880
	 */
2875
	 */
2881
	s = &not_found;	/* default value */
2876
	s = &not_found;	/* default value */
2882
	if (c) {	/* This group requires a valid channel */
2877
	if (c) {	/* This group requires a valid channel */
2883
		/* Names with common parts are looked up a piece at a time using strncmp. */
2878
		/* Names with common parts are looked up a piece at a time using strncmp. */
2884
		if (!strncmp(var, "CALL", 4)) {
2879
		if (!strncmp(var, "CALL", 4)) {
2885
			if (!strncmp(var + 4, "ING", 3)) {
2880
			if (!strncmp(var + 4, "ING", 3)) {
2886
				if (!strcmp(var + 7, "PRES")) {			/* CALLINGPRES */
2881
				if (!strcmp(var + 7, "PRES")) {			/* CALLINGPRES */
2887
					snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
2882
					snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
2888
					s = workspace;
2883
					s = workspace;
2889
				} else if (!strcmp(var + 7, "ANI2")) {		/* CALLINGANI2 */
2884
				} else if (!strcmp(var + 7, "ANI2")) {		/* CALLINGANI2 */
2890
					snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
2885
					snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
2891
					s = workspace;
2886
					s = workspace;
2892
				} else if (!strcmp(var + 7, "TON")) {		/* CALLINGTON */
2887
				} else if (!strcmp(var + 7, "TON")) {		/* CALLINGTON */
2893
					snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
2888
					snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
2894
					s = workspace;
2889
					s = workspace;
2895
				} else if (!strcmp(var + 7, "TNS")) {		/* CALLINGTNS */
2890
				} else if (!strcmp(var + 7, "TNS")) {		/* CALLINGTNS */
2896
					snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
2891
					snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
2897
					s = workspace;
2892
					s = workspace;
2898
				}
2893
				}
2899
			}
2894
			}
2900
		} else if (!strcmp(var, "HINT")) {
2895
		} else if (!strcmp(var, "HINT")) {
2901
			s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
2896
			s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
2902
		} else if (!strcmp(var, "HINTNAME")) {
2897
		} else if (!strcmp(var, "HINTNAME")) {
2903
			s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
2898
			s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
2904
		} else if (!strcmp(var, "EXTEN")) {
2899
		} else if (!strcmp(var, "EXTEN")) {
2905
			s = c->exten;
2900
			s = c->exten;
2906
		} else if (!strcmp(var, "CONTEXT")) {
2901
		} else if (!strcmp(var, "CONTEXT")) {
2907
			s = c->context;
2902
			s = c->context;
2908
		} else if (!strcmp(var, "PRIORITY")) {
2903
		} else if (!strcmp(var, "PRIORITY")) {
2909
			snprintf(workspace, workspacelen, "%d", c->priority);
2904
			snprintf(workspace, workspacelen, "%d", c->priority);
2910
			s = workspace;
2905
			s = workspace;
2911
		} else if (!strcmp(var, "CHANNEL")) {
2906
		} else if (!strcmp(var, "CHANNEL")) {
2912
			s = c->name;
2907
			s = c->name;
2913
		} else if (!strcmp(var, "UNIQUEID")) {
2908
		} else if (!strcmp(var, "UNIQUEID")) {
2914
			s = c->uniqueid;
2909
			s = c->uniqueid;
2915
		} else if (!strcmp(var, "HANGUPCAUSE")) {
2910
		} else if (!strcmp(var, "HANGUPCAUSE")) {
2916
			snprintf(workspace, workspacelen, "%d", c->hangupcause);
2911
			snprintf(workspace, workspacelen, "%d", c->hangupcause);
2917
			s = workspace;
2912
			s = workspace;
2918
		}
2913
		}
2919
	}
2914
	}
2920
	if (s == &not_found) { /* look for more */
2915
	if (s == &not_found) { /* look for more */
2921
		if (!strcmp(var, "EPOCH")) {
2916
		if (!strcmp(var, "EPOCH")) {
2922
			snprintf(workspace, workspacelen, "%u",(int)time(NULL));
2917
			snprintf(workspace, workspacelen, "%u",(int)time(NULL));
2923
			s = workspace;
2918
			s = workspace;
2924
		} else if (!strcmp(var, "SYSTEMNAME")) {
2919
		} else if (!strcmp(var, "SYSTEMNAME")) {
2925
			s = ast_config_AST_SYSTEM_NAME;
2920
			s = ast_config_AST_SYSTEM_NAME;
2926
		} else if (!strcmp(var, "ENTITYID")) {
2921
		} else if (!strcmp(var, "ENTITYID")) {
2927
			ast_eid_to_str(workspace, workspacelen, &g_eid);
2922
			ast_eid_to_str(workspace, workspacelen, &g_eid);
2928
			s = workspace;
2923
			s = workspace;
2929
		}
2924
		}
2930
	}
2925
	}
2931
	/* if not found, look into chanvars or global vars */
2926
	/* if not found, look into chanvars or global vars */
2932
	for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
2927
	for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
2933
		struct ast_var_t *variables;
2928
		struct ast_var_t *variables;
2934
		if (!places[i])
2929
		if (!places[i])
2935
			continue;
2930
			continue;
2936
		if (places[i] == &globals)
2931
		if (places[i] == &globals)
2937
			ast_rwlock_rdlock(&globalslock);
2932
			ast_rwlock_rdlock(&globalslock);
2938
		AST_LIST_TRAVERSE(places[i], variables, entries) {
2933
		AST_LIST_TRAVERSE(places[i], variables, entries) {
2939
			if (!strcasecmp(ast_var_name(variables), var)) {
2934
			if (!strcasecmp(ast_var_name(variables), var)) {
2940
				s = ast_var_value(variables);
2935
				s = ast_var_value(variables);
2941
				break;
2936
				break;
2942
			}
2937
			}
2943
		}
2938
		}
2944
		if (places[i] == &globals)
2939
		if (places[i] == &globals)
2945
			ast_rwlock_unlock(&globalslock);
2940
			ast_rwlock_unlock(&globalslock);
2946
	}
2941
	}
2947
	if (s == &not_found || s == NULL)
2942
	if (s == &not_found || s == NULL)
2948
		*ret = NULL;
2943
		*ret = NULL;
2949
	else {
2944
	else {
2950
		if (s != workspace)
2945
		if (s != workspace)
2951
			ast_copy_string(workspace, s, workspacelen);
2946
			ast_copy_string(workspace, s, workspacelen);
2952
		*ret = workspace;
2947
		*ret = workspace;
2953
		if (need_substring)
2948
		if (need_substring)
2954
			*ret = substring(*ret, offset, length, workspace, workspacelen);
2949
			*ret = substring(*ret, offset, length, workspace, workspacelen);
2955
	}
2950
	}
2956

    
   
2951

   
2957
	if (c)
2952
	if (c)
2958
		ast_channel_unlock(c);
2953
		ast_channel_unlock(c);
2959
}
2954
}
2960

    
   
2955

   
2961
static void exception_store_free(void *data)
2956
static void exception_store_free(void *data)
2962
{
2957
{
2963
	struct pbx_exception *exception = data;
2958
	struct pbx_exception *exception = data;
2964
	ast_string_field_free_memory(exception);
2959
	ast_string_field_free_memory(exception);
2965
	ast_free(exception);
2960
	ast_free(exception);
2966
}
2961
}
2967

    
   
2962

   
2968
static struct ast_datastore_info exception_store_info = {
2963
static struct ast_datastore_info exception_store_info = {
2969
	.type = "EXCEPTION",
2964
	.type = "EXCEPTION",
2970
	.destroy = exception_store_free,
2965
	.destroy = exception_store_free,
2971
};
2966
};
2972

    
   
2967

   
2973
int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
2968
int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
2974
{
2969
{
2975
	const char *reason = vreason;
2970
	const char *reason = vreason;
2976
	struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
2971
	struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
2977
	struct pbx_exception *exception = NULL;
2972
	struct pbx_exception *exception = NULL;
2978

    
   
2973

   
2979
	if (!ds) {
2974
	if (!ds) {
2980
		ds = ast_datastore_alloc(&exception_store_info, NULL);
2975
		ds = ast_datastore_alloc(&exception_store_info, NULL);
2981
		if (!ds)
2976
		if (!ds)
2982
			return -1;
2977
			return -1;
2983
		exception = ast_calloc(1, sizeof(struct pbx_exception));
2978
		exception = ast_calloc(1, sizeof(struct pbx_exception));
2984
		if (!exception) {
2979
		if (!exception) {
2985
			ast_datastore_free(ds);
2980
			ast_datastore_free(ds);
2986
			return -1;
2981
			return -1;
2987
		}
2982
		}
2988
		if (ast_string_field_init(exception, 128)) {
2983
		if (ast_string_field_init(exception, 128)) {
2989
			ast_free(exception);
2984
			ast_free(exception);
2990
			ast_datastore_free(ds);
2985
			ast_datastore_free(ds);
2991
			return -1;
2986
			return -1;
2992
		}
2987
		}
2993
		ds->data = exception;
2988
		ds->data = exception;
2994
		ast_channel_datastore_add(chan, ds);
2989
		ast_channel_datastore_add(chan, ds);
2995
	} else
2990
	} else
2996
		exception = ds->data;
2991
		exception = ds->data;
2997

    
   
2992

   
2998
	ast_string_field_set(exception, reason, reason);
2993
	ast_string_field_set(exception, reason, reason);
2999
	ast_string_field_set(exception, context, chan->context);
2994
	ast_string_field_set(exception, context, chan->context);
3000
	ast_string_field_set(exception, exten, chan->exten);
2995
	ast_string_field_set(exception, exten, chan->exten);
3001
	exception->priority = chan->priority;
2996
	exception->priority = chan->priority;
3002
	set_ext_pri(chan, "e", 0);
2997
	set_ext_pri(chan, "e", 0);
3003
	return 0;
2998
	return 0;
3004
}
2999
}
3005

    
   
3000

   
3006
static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
3001
static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
3007
{
3002
{
3008
	struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
3003
	struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
3009
	struct pbx_exception *exception = NULL;
3004
	struct pbx_exception *exception = NULL;
3010
	if (!ds || !ds->data)
3005
	if (!ds || !ds->data)
3011
		return -1;
3006
		return -1;
3012
	exception = ds->data;
3007
	exception = ds->data;
3013
	if (!strcasecmp(data, "REASON"))
3008
	if (!strcasecmp(data, "REASON"))
3014
		ast_copy_string(buf, exception->reason, buflen);
3009
		ast_copy_string(buf, exception->reason, buflen);
3015
	else if (!strcasecmp(data, "CONTEXT"))
3010
	else if (!strcasecmp(data, "CONTEXT"))
3016
		ast_copy_string(buf, exception->context, buflen);
3011
		ast_copy_string(buf, exception->context, buflen);
3017
	else if (!strncasecmp(data, "EXTEN", 5))
3012
	else if (!strncasecmp(data, "EXTEN", 5))
3018
		ast_copy_string(buf, exception->exten, buflen);
3013
		ast_copy_string(buf, exception->exten, buflen);
3019
	else if (!strcasecmp(data, "PRIORITY"))
3014
	else if (!strcasecmp(data, "PRIORITY"))
3020
		snprintf(buf, buflen, "%d", exception->priority);
3015
		snprintf(buf, buflen, "%d", exception->priority);
3021
	else
3016
	else
3022
		return -1;
3017
		return -1;
3023
	return 0;
3018
	return 0;
3024
}
3019
}
3025

    
   
3020

   
3026
static struct ast_custom_function exception_function = {
3021
static struct ast_custom_function exception_function = {
3027
	.name = "EXCEPTION",
3022
	.name = "EXCEPTION",
3028
	.read = acf_exception_read,
3023
	.read = acf_exception_read,
3029
};
3024
};
3030

    
   
3025

   
3031
static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3026
static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3032
{
3027
{
3033
	struct ast_custom_function *acf;
3028
	struct ast_custom_function *acf;
3034
	int count_acf = 0;
3029
	int count_acf = 0;
3035
	int like = 0;
3030
	int like = 0;
3036

    
   
3031

   
3037
	switch (cmd) {
3032
	switch (cmd) {
3038
	case CLI_INIT:
3033
	case CLI_INIT:
3039
		e->command = "core show functions [like]";
3034
		e->command = "core show functions [like]";
3040
		e->usage =
3035
		e->usage =
3041
			"Usage: core show functions [like <text>]\n"
3036
			"Usage: core show functions [like <text>]\n"
3042
			"       List builtin functions, optionally only those matching a given string\n";
3037
			"       List builtin functions, optionally only those matching a given string\n";
3043
		return NULL;
3038
		return NULL;
3044
	case CLI_GENERATE:
3039
	case CLI_GENERATE:
3045
		return NULL;
3040
		return NULL;
3046
	}
3041
	}
3047

    
   
3042

   
3048
	if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
3043
	if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
3049
		like = 1;
3044
		like = 1;
3050
	} else if (a->argc != 3) {
3045
	} else if (a->argc != 3) {
3051
		return CLI_SHOWUSAGE;
3046
		return CLI_SHOWUSAGE;
3052
	}
3047
	}
3053

    
   
3048

   
3054
	ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
3049
	ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
3055

    
   
3050

   
3056
	AST_RWLIST_RDLOCK(&acf_root);
3051
	AST_RWLIST_RDLOCK(&acf_root);
3057
	AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
3052
	AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
3058
		if (!like || strstr(acf->name, a->argv[4])) {
3053
		if (!like || strstr(acf->name, a->argv[4])) {
3059
			count_acf++;
3054
			count_acf++;
3060
			ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
3055
			ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
3061
		}
3056
		}
3062
	}
3057
	}
3063
	AST_RWLIST_UNLOCK(&acf_root);
3058
	AST_RWLIST_UNLOCK(&acf_root);
3064

    
   
3059

   
3065
	ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
3060
	ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
3066

    
   
3061

   
3067
	return CLI_SUCCESS;
3062
	return CLI_SUCCESS;
3068
}
3063
}
3069

    
   
3064

   
3070
static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3065
static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3071
{
3066
{
3072
	struct ast_custom_function *acf;
3067
	struct ast_custom_function *acf;
3073
	/* Maximum number of characters added by terminal coloring is 22 */
3068
	/* Maximum number of characters added by terminal coloring is 22 */
3074
	char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
3069
	char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
3075
	char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
3070
	char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
3076
	char stxtitle[40], *syntax = NULL, *arguments = NULL;
3071
	char stxtitle[40], *syntax = NULL, *arguments = NULL;
3077
	int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
3072
	int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
3078
	char *ret = NULL;
3073
	char *ret = NULL;
3079
	int which = 0;
3074
	int which = 0;
3080
	int wordlen;
3075
	int wordlen;
3081

    
   
3076

   
3082
	switch (cmd) {
3077
	switch (cmd) {
3083
	case CLI_INIT:
3078
	case CLI_INIT:
3084
		e->command = "core show function";
3079
		e->command = "core show function";
3085
		e->usage =
3080
		e->usage =
3086
			"Usage: core show function <function>\n"
3081
			"Usage: core show function <function>\n"
3087
			"       Describe a particular dialplan function.\n";
3082
			"       Describe a particular dialplan function.\n";
3088
		return NULL;
3083
		return NULL;
3089
	case CLI_GENERATE:
3084
	case CLI_GENERATE:
3090
		wordlen = strlen(a->word);
3085
		wordlen = strlen(a->word);
3091
		/* case-insensitive for convenience in this 'complete' function */
3086
		/* case-insensitive for convenience in this 'complete' function */
3092
		AST_RWLIST_RDLOCK(&acf_root);
3087
		AST_RWLIST_RDLOCK(&acf_root);
3093
		AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
3088
		AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
3094
			if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
3089
			if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
3095
				ret = ast_strdup(acf->name);
3090
				ret = ast_strdup(acf->name);
3096
				break;
3091
				break;
3097
			}
3092
			}
3098
		}
3093
		}
3099
		AST_RWLIST_UNLOCK(&acf_root);
3094
		AST_RWLIST_UNLOCK(&acf_root);
3100

    
   
3095

   
3101
		return ret;
3096
		return ret;
3102
	}
3097
	}
3103

    
   
3098

   
3104
	if (a->argc < 4) {
3099
	if (a->argc < 4) {
3105
		return CLI_SHOWUSAGE;
3100
		return CLI_SHOWUSAGE;
3106
	}
3101
	}
3107

    
   
3102

   
3108
	if (!(acf = ast_custom_function_find(a->argv[3]))) {
3103
	if (!(acf = ast_custom_function_find(a->argv[3]))) {
3109
		ast_cli(a->fd, "No function by that name registered.\n");
3104
		ast_cli(a->fd, "No function by that name registered.\n");
3110
		return CLI_FAILURE;
3105
		return CLI_FAILURE;
3111
	}
3106
	}
3112

    
   
3107

   
3113
	syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3108
	syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3114
	if (!(syntax = ast_malloc(syntax_size))) {
3109
	if (!(syntax = ast_malloc(syntax_size))) {
3115
		ast_cli(a->fd, "Memory allocation failure!\n");
3110
		ast_cli(a->fd, "Memory allocation failure!\n");
3116
		return CLI_FAILURE;
3111
		return CLI_FAILURE;
3117
	}
3112
	}
3118

    
   
3113

   
3119
	snprintf(info, sizeof(info), "\n  -= Info about function '%s' =- \n\n", acf->name);
3114
	snprintf(info, sizeof(info), "\n  -= Info about function '%s' =- \n\n", acf->name);
3120
	term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
3115
	term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
3121
	term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
3116
	term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
3122
	term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
3117
	term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
3123
	term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
3118
	term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
3124
	term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
3119
	term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
3125
	term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
3120
	term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
3126
	term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
3121
	term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
3127
#ifdef AST_XML_DOCS
3122
#ifdef AST_XML_DOCS
3128
	if (acf->docsrc == AST_XML_DOC) {
3123
	if (acf->docsrc == AST_XML_DOC) {
3129
		arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
3124
		arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
3130
		synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
3125
		synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
3131
		description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
3126
		description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
3132
		seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
3127
		seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
3133
	} else
3128
	} else
3134
#endif
3129
#endif
3135
	{
3130
	{
3136
		synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3131
		synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3137
		synopsis = ast_malloc(synopsis_size);
3132
		synopsis = ast_malloc(synopsis_size);
3138

    
   
3133

   
3139
		description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3134
		description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3140
		description = ast_malloc(description_size);
3135
		description = ast_malloc(description_size);
3141

    
   
3136

   
3142
		arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3137
		arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3143
		arguments = ast_malloc(arguments_size);
3138
		arguments = ast_malloc(arguments_size);
3144

    
   
3139

   
3145
		seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3140
		seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
3146
		seealso = ast_malloc(seealso_size);
3141
		seealso = ast_malloc(seealso_size);
3147

    
   
3142

   
3148
		/* check allocated memory. */
3143
		/* check allocated memory. */
3149
		if (!synopsis || !description || !arguments || !seealso) {
3144
		if (!synopsis || !description || !arguments || !seealso) {
3150
			ast_free(synopsis);
3145
			ast_free(synopsis);
3151
			ast_free(description);
3146
			ast_free(description);
3152
			ast_free(arguments);
3147
			ast_free(arguments);
3153
			ast_free(seealso);
3148
			ast_free(seealso);
3154
			ast_free(syntax);
3149
			ast_free(syntax);
3155
			return CLI_FAILURE;
3150
			return CLI_FAILURE;
3156
		}
3151
		}
3157

    
   
3152

   
3158
		term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
3153
		term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
3159
		term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
3154
		term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
3160
		term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
3155
		term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
3161
		term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
3156
		term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
3162
	}
3157
	}
3163

    
   
3158

   
3164
	ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
3159
	ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
3165
			infotitle, syntitle, synopsis, destitle, description,
3160
			infotitle, syntitle, synopsis, destitle, description,
3166
			stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
3161
			stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
3167

    
   
3162

   
3168
	ast_free(arguments);
3163
	ast_free(arguments);
3169
	ast_free(synopsis);
3164
	ast_free(synopsis);
3170
	ast_free(description);
3165
	ast_free(description);
3171
	ast_free(seealso);
3166
	ast_free(seealso);
3172
	ast_free(syntax);
3167
	ast_free(syntax);
3173

    
   
3168

   
3174
	return CLI_SUCCESS;
3169
	return CLI_SUCCESS;
3175
}
3170
}
3176

    
   
3171

   
3177
struct ast_custom_function *ast_custom_function_find(const char *name)
3172
struct ast_custom_function *ast_custom_function_find(const char *name)
3178
{
3173
{
3179
	struct ast_custom_function *acf = NULL;
3174
	struct ast_custom_function *acf = NULL;
3180

    
   
3175

   
3181
	AST_RWLIST_RDLOCK(&acf_root);
3176
	AST_RWLIST_RDLOCK(&acf_root);
3182
	AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
3177
	AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
3183
		if (!strcmp(name, acf->name))
3178
		if (!strcmp(name, acf->name))
3184
			break;
3179
			break;
3185
	}
3180
	}
3186
	AST_RWLIST_UNLOCK(&acf_root);
3181
	AST_RWLIST_UNLOCK(&acf_root);
3187

    
   
3182

   
3188
	return acf;
3183
	return acf;
3189
}
3184
}
3190

    
   
3185

   
3191
int ast_custom_function_unregister(struct ast_custom_function *acf)
3186
int ast_custom_function_unregister(struct ast_custom_function *acf)
3192
{
3187
{
3193
	struct ast_custom_function *cur;
3188
	struct ast_custom_function *cur;
3194

    
   
3189

   
3195
	if (!acf) {
3190
	if (!acf) {
3196
		return -1;
3191
		return -1;
3197
	}
3192
	}
3198

    
   
3193

   
3199
	AST_RWLIST_WRLOCK(&acf_root);
3194
	AST_RWLIST_WRLOCK(&acf_root);
3200
	if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
3195
	if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
3201
		if (cur->docsrc == AST_XML_DOC) {
3196
		if (cur->docsrc == AST_XML_DOC) {
3202
			ast_string_field_free_memory(acf);
3197
			ast_string_field_free_memory(acf);
3203
		}
3198
		}
3204
		ast_verb(2, "Unregistered custom function %s\n", cur->name);
3199
		ast_verb(2, "Unregistered custom function %s\n", cur->name);
3205
	}
3200
	}
3206
	AST_RWLIST_UNLOCK(&acf_root);
3201
	AST_RWLIST_UNLOCK(&acf_root);
3207

    
   
3202

   
3208
	return cur ? 0 : -1;
3203
	return cur ? 0 : -1;
3209
}
3204
}
3210

    
   
3205

   
3211
/*! \internal
3206
/*! \internal
3212
 *  \brief Retrieve the XML documentation of a specified ast_custom_function,
3207
 *  \brief Retrieve the XML documentation of a specified ast_custom_function,
3213
 *         and populate ast_custom_function string fields.
3208
 *         and populate ast_custom_function string fields.
3214
 *  \param acf ast_custom_function structure with empty 'desc' and 'synopsis'
3209
 *  \param acf ast_custom_function structure with empty 'desc' and 'synopsis'
3215
 *             but with a function 'name'.
3210
 *             but with a function 'name'.
3216
 *  \retval -1 On error.
3211
 *  \retval -1 On error.
3217
 *  \retval 0 On succes.
3212
 *  \retval 0 On succes.
3218
 */
3213
 */
3219
static int acf_retrieve_docs(struct ast_custom_function *acf)
3214
static int acf_retrieve_docs(struct ast_custom_function *acf)
3220
{
3215
{
3221
#ifdef AST_XML_DOCS
3216
#ifdef AST_XML_DOCS
3222
	char *tmpxml;
3217
	char *tmpxml;
3223

    
   
3218

   
3224
	/* Let's try to find it in the Documentation XML */
3219
	/* Let's try to find it in the Documentation XML */
3225
	if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
3220
	if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
3226
		return 0;
3221
		return 0;
3227
	}
3222
	}
3228

    
   
3223

   
3229
	if (ast_string_field_init(acf, 128)) {
3224
	if (ast_string_field_init(acf, 128)) {
3230
		return -1;
3225
		return -1;
3231
	}
3226
	}
3232

    
   
3227

   
3233
	/* load synopsis */
3228
	/* load synopsis */
3234
	tmpxml = ast_xmldoc_build_synopsis("function", acf->name);
3229
	tmpxml = ast_xmldoc_build_synopsis("function", acf->name);
3235
	ast_string_field_set(acf, synopsis, tmpxml);
3230
	ast_string_field_set(acf, synopsis, tmpxml);
3236
	ast_free(tmpxml);
3231
	ast_free(tmpxml);
3237

    
   
3232

   
3238
	/* load description */
3233
	/* load description */
3239
	tmpxml = ast_xmldoc_build_description("function", acf->name);
3234
	tmpxml = ast_xmldoc_build_description("function", acf->name);
3240
	ast_string_field_set(acf, desc, tmpxml);
3235
	ast_string_field_set(acf, desc, tmpxml);
3241
	ast_free(tmpxml);
3236
	ast_free(tmpxml);
3242

    
   
3237

   
3243
	/* load syntax */
3238
	/* load syntax */
3244
	tmpxml = ast_xmldoc_build_syntax("function", acf->name);
3239
	tmpxml = ast_xmldoc_build_syntax("function", acf->name);
3245
	ast_string_field_set(acf, syntax, tmpxml);
3240
	ast_string_field_set(acf, syntax, tmpxml);
3246
	ast_free(tmpxml);
3241
	ast_free(tmpxml);
3247

    
   
3242

   
3248
	/* load arguments */
3243
	/* load arguments */
3249
	tmpxml = ast_xmldoc_build_arguments("function", acf->name);
3244
	tmpxml = ast_xmldoc_build_arguments("function", acf->name);
3250
	ast_string_field_set(acf, arguments, tmpxml);
3245
	ast_string_field_set(acf, arguments, tmpxml);
3251
	ast_free(tmpxml);
3246
	ast_free(tmpxml);
3252

    
   
3247

   
3253
	/* load seealso */
3248
	/* load seealso */
3254
	tmpxml = ast_xmldoc_build_seealso("function", acf->name);
3249
	tmpxml = ast_xmldoc_build_seealso("function", acf->name);
3255
	ast_string_field_set(acf, seealso, tmpxml);
3250
	ast_string_field_set(acf, seealso, tmpxml);
3256
	ast_free(tmpxml);
3251
	ast_free(tmpxml);
3257

    
   
3252

   
3258
	acf->docsrc = AST_XML_DOC;
3253
	acf->docsrc = AST_XML_DOC;
3259
#endif
3254
#endif
3260

    
   
3255

   
3261
	return 0;
3256
	return 0;
3262
}
3257
}
3263

    
   
3258

   
3264
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
3259
int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
3265
{
3260
{
3266
	struct ast_custom_function *cur;
3261
	struct ast_custom_function *cur;
3267
	char tmps[80];
3262
	char tmps[80];
3268

    
   
3263

   
3269
	if (!acf) {
3264
	if (!acf) {
3270
		return -1;
3265
		return -1;
3271
	}
3266
	}
3272

    
   
3267

   
3273
	acf->mod = mod;
3268
	acf->mod = mod;
3274
	acf->docsrc = AST_STATIC_DOC;
3269
	acf->docsrc = AST_STATIC_DOC;
3275

    
   
3270

   
3276
	if (acf_retrieve_docs(acf)) {
3271
	if (acf_retrieve_docs(acf)) {
3277
		return -1;
3272
		return -1;
3278
	}
3273
	}
3279

    
   
3274

   
3280
	AST_RWLIST_WRLOCK(&acf_root);
3275
	AST_RWLIST_WRLOCK(&acf_root);
3281

    
   
3276

   
3282
	AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
3277
	AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
3283
		if (!strcmp(acf->name, cur->name)) {
3278
		if (!strcmp(acf->name, cur->name)) {
3284
			ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
3279
			ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
3285
			AST_RWLIST_UNLOCK(&acf_root);
3280
			AST_RWLIST_UNLOCK(&acf_root);
3286
			return -1;
3281
			return -1;
3287
		}
3282
		}
3288
	}
3283
	}
3289

    
   
3284

   
3290
	/* Store in alphabetical order */
3285
	/* Store in alphabetical order */
3291
	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
3286
	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
3292
		if (strcasecmp(acf->name, cur->name) < 0) {
3287
		if (strcasecmp(acf->name, cur->name) < 0) {
3293
			AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
3288
			AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
3294
			break;
3289
			break;
3295
		}
3290
		}
3296
	}
3291
	}
3297
	AST_RWLIST_TRAVERSE_SAFE_END;
3292
	AST_RWLIST_TRAVERSE_SAFE_END;
3298

    
   
3293

   
3299
	if (!cur) {
3294
	if (!cur) {
3300
		AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
3295
		AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
3301
	}
3296
	}
3302

    
   
3297

   
3303
	AST_RWLIST_UNLOCK(&acf_root);
3298
	AST_RWLIST_UNLOCK(&acf_root);
3304

    
   
3299

   
3305
	ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
3300
	ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
3306

    
   
3301

   
3307
	return 0;
3302
	return 0;
3308
}
3303
}
3309

    
   
3304

   
3310
/*! \brief return a pointer to the arguments of the function,
3305
/*! \brief return a pointer to the arguments of the function,
3311
 * and terminates the function name with '\\0'
3306
 * and terminates the function name with '\\0'
3312
 */
3307
 */
3313
static char *func_args(char *function)
3308
static char *func_args(char *function)
3314
{
3309
{
3315
	char *args = strchr(function, '(');
3310
	char *args = strchr(function, '(');
3316

    
   
3311

   
3317
	if (!args) {
3312
	if (!args) {
3318
		ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
3313
		ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
3319
	} else {
3314
	} else {
3320
		char *p;
3315
		char *p;
3321
		*args++ = '\0';
3316
		*args++ = '\0';
3322
		if ((p = strrchr(args, ')'))) {
3317
		if ((p = strrchr(args, ')'))) {
3323
			*p = '\0';
3318
			*p = '\0';
3324
		} else {
3319
		} else {
3325
			ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
3320
			ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
3326
		}
3321
		}
3327
	}
3322
	}
3328
	return args;
3323
	return args;
3329
}
3324
}
3330

    
   
3325

   
3331
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
3326
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
3332
{
3327
{
3333
	char *copy = ast_strdupa(function);
3328
	char *copy = ast_strdupa(function);
3334
	char *args = func_args(copy);
3329
	char *args = func_args(copy);
3335
	struct ast_custom_function *acfptr = ast_custom_function_find(copy);
3330
	struct ast_custom_function *acfptr = ast_custom_function_find(copy);
3336

    
   
3331

   
3337
	if (acfptr == NULL)
3332
	if (acfptr == NULL)
3338
		ast_log(LOG_ERROR, "Function %s not registered\n", copy);
3333
		ast_log(LOG_ERROR, "Function %s not registered\n", copy);
3339
	else if (!acfptr->read)
3334
	else if (!acfptr->read)
3340
		ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
3335
		ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
3341
	else {
3336
	else {
3342
		int res;
3337
		int res;
3343
		struct ast_module_user *u = NULL;
3338
		struct ast_module_user *u = NULL;
3344
		if (acfptr->mod)
3339
		if (acfptr->mod)
3345
			u = __ast_module_user_add(acfptr->mod, chan);
3340
			u = __ast_module_user_add(acfptr->mod, chan);
3346
		res = acfptr->read(chan, copy, args, workspace, len);
3341
		res = acfptr->read(chan, copy, args, workspace, len);
3347
		if (acfptr->mod && u)
3342
		if (acfptr->mod && u)
3348
			__ast_module_user_remove(acfptr->mod, u);
3343
			__ast_module_user_remove(acfptr->mod, u);
3349
		return res;
3344
		return res;
3350
	}
3345
	}
3351
	return -1;
3346
	return -1;
3352
}
3347
}
3353

    
   
3348

   
3354
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
3349
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
3355
{
3350
{
3356
	char *copy = ast_strdupa(function);
3351
	char *copy = ast_strdupa(function);
3357
	char *args = func_args(copy);
3352
	char *args = func_args(copy);
3358
	struct ast_custom_function *acfptr = ast_custom_function_find(copy);
3353
	struct ast_custom_function *acfptr = ast_custom_function_find(copy);
3359

    
   
3354

   
3360
	if (acfptr == NULL)
3355
	if (acfptr == NULL)
3361
		ast_log(LOG_ERROR, "Function %s not registered\n", copy);
3356
		ast_log(LOG_ERROR, "Function %s not registered\n", copy);
3362
	else if (!acfptr->write)
3357
	else if (!acfptr->write)
3363
		ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
3358
		ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
3364
	else {
3359
	else {
3365
		int res;
3360
		int res;
3366
		struct ast_module_user *u = NULL;
3361
		struct ast_module_user *u = NULL;
3367
		if (acfptr->mod)
3362
		if (acfptr->mod)
3368
			u = __ast_module_user_add(acfptr->mod, chan);
3363
			u = __ast_module_user_add(acfptr->mod, chan);
3369
		res = acfptr->write(chan, copy, args, value);
3364
		res = acfptr->write(chan, copy, args, value);
3370
		if (acfptr->mod && u)
3365
		if (acfptr->mod && u)
3371
			__ast_module_user_remove(acfptr->mod, u);
3366
			__ast_module_user_remove(acfptr->mod, u);
3372
		return res;
3367
		return res;
3373
	}
3368
	}
3374

    
   
3369

   
3375
	return -1;
3370
	return -1;
3376
}
3371
}
3377

    
   
3372

   
3378
void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
3373
void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
3379
{
3374
{
3380
	/* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
3375
	/* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
3381
	char *cp4;
3376
	char *cp4;
3382
	const char *tmp, *whereweare, *orig_cp2 = cp2;
3377
	const char *tmp, *whereweare, *orig_cp2 = cp2;
3383
	int length, offset, offset2, isfunction;
3378
	int length, offset, offset2, isfunction;
3384
	char *workspace = NULL;
3379
	char *workspace = NULL;
3385
	char *ltmp = NULL, *var = NULL;
3380
	char *ltmp = NULL, *var = NULL;
3386
	char *nextvar, *nextexp, *nextthing;
3381
	char *nextvar, *nextexp, *nextthing;
3387
	char *vars, *vare;
3382
	char *vars, *vare;
3388
	int pos, brackets, needsub, len;
3383
	int pos, brackets, needsub, len;
3389

    
   
3384

   
3390
	*cp2 = 0; /* just in case nothing ends up there */
3385
	*cp2 = 0; /* just in case nothing ends up there */
3391
	whereweare=tmp=cp1;
3386
	whereweare=tmp=cp1;
3392
	while (!ast_strlen_zero(whereweare) && count) {
3387
	while (!ast_strlen_zero(whereweare) && count) {
3393
		/* Assume we're copying the whole remaining string */
3388
		/* Assume we're copying the whole remaining string */
3394
		pos = strlen(whereweare);
3389
		pos = strlen(whereweare);
3395
		nextvar = NULL;
3390
		nextvar = NULL;
3396
		nextexp = NULL;
3391
		nextexp = NULL;
3397
		nextthing = strchr(whereweare, '$');
3392
		nextthing = strchr(whereweare, '$');
3398
		if (nextthing) {
3393
		if (nextthing) {
3399
			switch (nextthing[1]) {
3394
			switch (nextthing[1]) {
3400
			case '{':
3395
			case '{':
3401
				nextvar = nextthing;
3396
				nextvar = nextthing;
3402
				pos = nextvar - whereweare;
3397
				pos = nextvar - whereweare;
3403
				break;
3398
				break;
3404
			case '[':
3399
			case '[':
3405
				nextexp = nextthing;
3400
				nextexp = nextthing;
3406
				pos = nextexp - whereweare;
3401
				pos = nextexp - whereweare;
3407
				break;
3402
				break;
3408
			default:
3403
			default:
3409
				pos = 1;
3404
				pos = 1;
3410
			}
3405
			}
3411
		}
3406
		}
3412

    
   
3407

   
3413
		if (pos) {
3408
		if (pos) {
3414
			/* Can't copy more than 'count' bytes */
3409
			/* Can't copy more than 'count' bytes */
3415
			if (pos > count)
3410
			if (pos > count)
3416
				pos = count;
3411
				pos = count;
3417

    
   
3412

   
3418
			/* Copy that many bytes */
3413
			/* Copy that many bytes */
3419
			memcpy(cp2, whereweare, pos);
3414