Thu Apr 28 2011 16:56:47

Asterisk developer's documentation


pbx.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2008, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Core PBX routines.
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  */
00025 #include "asterisk.h"
00026 
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 303548 $")
00028 
00029 #include "asterisk/_private.h"
00030 #include "asterisk/paths.h"   /* use ast_config_AST_SYSTEM_NAME */
00031 #include <ctype.h>
00032 #include <time.h>
00033 #include <sys/time.h>
00034 #if defined(HAVE_SYSINFO)
00035 #include <sys/sysinfo.h>
00036 #endif
00037 #if defined(SOLARIS)
00038 #include <sys/loadavg.h>
00039 #endif
00040 
00041 #include "asterisk/lock.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/cdr.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/term.h"
00050 #include "asterisk/time.h"
00051 #include "asterisk/manager.h"
00052 #include "asterisk/ast_expr.h"
00053 #include "asterisk/linkedlists.h"
00054 #define  SAY_STUBS   /* generate declarations and stubs for say methods */
00055 #include "asterisk/say.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/causes.h"
00058 #include "asterisk/musiconhold.h"
00059 #include "asterisk/app.h"
00060 #include "asterisk/devicestate.h"
00061 #include "asterisk/event.h"
00062 #include "asterisk/hashtab.h"
00063 #include "asterisk/module.h"
00064 #include "asterisk/indications.h"
00065 #include "asterisk/taskprocessor.h"
00066 #include "asterisk/xmldoc.h"
00067 #include "asterisk/astobj2.h"
00068 
00069 /*!
00070  * \note I M P O R T A N T :
00071  *
00072  *    The speed of extension handling will likely be among the most important
00073  * aspects of this PBX.  The switching scheme as it exists right now isn't
00074  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
00075  * of priorities, but a constant search time here would be great ;-)
00076  *
00077  * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
00078  * here, and shows a fairly flat (constant) search time, even for over
00079  * 10000 patterns.
00080  *
00081  * Also, using a hash table for context/priority name lookup can help prevent
00082  * the find_extension routines from absorbing exponential cpu cycles as the number
00083  * of contexts/priorities grow. I've previously tested find_extension with red-black trees,
00084  * which have O(log2(n)) speed. Right now, I'm using hash tables, which do
00085  * searches (ideally) in O(1) time. While these techniques do not yield much
00086  * speed in small dialplans, they are worth the trouble in large dialplans.
00087  *
00088  */
00089 
00090 /*** DOCUMENTATION
00091    <application name="Answer" language="en_US">
00092       <synopsis>
00093          Answer a channel if ringing.
00094       </synopsis>
00095       <syntax>
00096          <parameter name="delay">
00097             <para>Asterisk will wait this number of milliseconds before returning to
00098             the dialplan after answering the call.</para>
00099          </parameter>
00100          <parameter name="nocdr">
00101             <para>Asterisk will send an answer signal to the calling phone, but will not
00102             set the disposition or answer time in the CDR for this call.</para>
00103          </parameter>
00104       </syntax>
00105       <description>
00106          <para>If the call has not been answered, this application will
00107          answer it. Otherwise, it has no effect on the call.</para>
00108       </description>
00109       <see-also>
00110          <ref type="application">Hangup</ref>
00111       </see-also>
00112    </application>
00113    <application name="BackGround" language="en_US">
00114       <synopsis>
00115          Play an audio file while waiting for digits of an extension to go to.
00116       </synopsis>
00117       <syntax>
00118          <parameter name="filenames" required="true" argsep="&amp;">
00119             <argument name="filename1" required="true" />
00120             <argument name="filename2" multiple="true" />
00121          </parameter>
00122          <parameter name="options">
00123             <optionlist>
00124                <option name="s">
00125                   <para>Causes the playback of the message to be skipped
00126                   if the channel is not in the <literal>up</literal> state (i.e. it
00127                   hasn't been answered yet). If this happens, the
00128                   application will return immediately.</para>
00129                </option>
00130                <option name="n">
00131                   <para>Don't answer the channel before playing the files.</para>
00132                </option>
00133                <option name="m">
00134                   <para>Only break if a digit hit matches a one digit
00135                   extension in the destination context.</para>
00136                </option>
00137             </optionlist>
00138          </parameter>
00139          <parameter name="langoverride">
00140             <para>Explicitly specifies which language to attempt to use for the requested sound files.</para>
00141          </parameter>
00142          <parameter name="context">
00143             <para>This is the dialplan context that this application will use when exiting
00144             to a dialed extension.</para>
00145          </parameter>
00146       </syntax>
00147       <description>
00148          <para>This application will play the given list of files <emphasis>(do not put extension)</emphasis>
00149          while waiting for an extension to be dialed by the calling channel. To continue waiting
00150          for digits after this application has finished playing files, the <literal>WaitExten</literal>
00151          application should be used.</para>
00152          <para>If one of the requested sound files does not exist, call processing will be terminated.</para>
00153          <para>This application sets the following channel variable upon completion:</para>
00154          <variablelist>
00155             <variable name="BACKGROUNDSTATUS">
00156                <para>The status of the background attempt as a text string.</para>
00157                <value name="SUCCESS" />
00158                <value name="FAILED" />
00159             </variable>
00160          </variablelist>
00161       </description>
00162       <see-also>
00163          <ref type="application">ControlPlayback</ref>
00164          <ref type="application">WaitExten</ref>
00165          <ref type="application">BackgroundDetect</ref>
00166          <ref type="function">TIMEOUT</ref>
00167       </see-also>
00168    </application>
00169    <application name="Busy" language="en_US">
00170       <synopsis>
00171          Indicate the Busy condition.
00172       </synopsis>
00173       <syntax>
00174          <parameter name="timeout">
00175             <para>If specified, the calling channel will be hung up after the specified number of seconds.
00176             Otherwise, this application will wait until the calling channel hangs up.</para>
00177          </parameter>
00178       </syntax>
00179       <description>
00180          <para>This application will indicate the busy condition to the calling channel.</para>
00181       </description>
00182       <see-also>
00183          <ref type="application">Congestion</ref>
00184          <ref type="application">Progess</ref>
00185          <ref type="application">Playtones</ref>
00186          <ref type="application">Hangup</ref>
00187       </see-also>
00188    </application>
00189    <application name="Congestion" language="en_US">
00190       <synopsis>
00191          Indicate the Congestion condition.
00192       </synopsis>
00193       <syntax>
00194          <parameter name="timeout">
00195             <para>If specified, the calling channel will be hung up after the specified number of seconds.
00196             Otherwise, this application will wait until the calling channel hangs up.</para>
00197          </parameter>
00198       </syntax>
00199       <description>
00200          <para>This application will indicate the congestion condition to the calling channel.</para>
00201       </description>
00202       <see-also>
00203          <ref type="application">Busy</ref>
00204          <ref type="application">Progess</ref>
00205          <ref type="application">Playtones</ref>
00206          <ref type="application">Hangup</ref>
00207       </see-also>
00208    </application>
00209    <application name="ExecIfTime" language="en_US">
00210       <synopsis>
00211          Conditional application execution based on the current time.
00212       </synopsis>
00213       <syntax argsep="?">
00214          <parameter name="day_condition" required="true">
00215             <argument name="times" required="true" />
00216             <argument name="weekdays" required="true" />
00217             <argument name="mdays" required="true" />
00218             <argument name="months" required="true" />
00219             <argument name="timezone" required="false" />
00220          </parameter>
00221          <parameter name="appname" required="true" hasparams="optional">
00222             <argument name="appargs" required="true" />
00223          </parameter>
00224       </syntax>
00225       <description>
00226          <para>This application will execute the specified dialplan application, with optional
00227          arguments, if the current time matches the given time specification.</para>
00228       </description>
00229       <see-also>
00230          <ref type="application">Exec</ref>
00231          <ref type="application">TryExec</ref>
00232       </see-also>
00233    </application>
00234    <application name="Goto" language="en_US">
00235       <synopsis>
00236          Jump to a particular priority, extension, or context.
00237       </synopsis>
00238       <syntax>
00239          <parameter name="context" />
00240          <parameter name="extensions" />
00241          <parameter name="priority" required="true" />
00242       </syntax>
00243       <description>
00244          <para>This application will set the current context, extension, and priority in the channel structure.
00245          After it completes, the pbx engine will continue dialplan execution at the specified location.
00246          If no specific <replaceable>extension</replaceable>, or <replaceable>extension</replaceable> and
00247          <replaceable>context</replaceable>, are specified, then this application will
00248          just set the specified <replaceable>priority</replaceable> of the current extension.</para>
00249          <para>At least a <replaceable>priority</replaceable> is required as an argument, or the goto will
00250          return a <literal>-1</literal>,  and the channel and call will be terminated.</para>
00251          <para>If the location that is put into the channel information is bogus, and asterisk cannot
00252          find that location in the dialplan, then the execution engine will try to find and execute the code in
00253          the <literal>i</literal> (invalid) extension in the current context. If that does not exist, it will try to execute the
00254          <literal>h</literal> extension. If either or neither the <literal>h</literal> or <literal>i</literal> extensions
00255          have been defined, the channel is hung up, and the execution of instructions on the channel is terminated.
00256          What this means is that, for example, you specify a context that does not exist, then
00257          it will not be possible to find the <literal>h</literal> or <literal>i</literal> extensions,
00258          and the call will terminate!</para>
00259       </description>
00260       <see-also>
00261          <ref type="application">GotoIf</ref>
00262          <ref type="application">GotoIfTime</ref>
00263          <ref type="application">Gosub</ref>
00264          <ref type="application">Macro</ref>
00265       </see-also>
00266    </application>
00267    <application name="GotoIf" language="en_US">
00268       <synopsis>
00269          Conditional goto.
00270       </synopsis>
00271       <syntax argsep="?">
00272          <parameter name="condition" required="true" />
00273          <parameter name="destination" required="true" argsep=":">
00274             <argument name="labeliftrue">
00275                <para>Continue at <replaceable>labeliftrue</replaceable> if the condition is true.</para>
00276             </argument>
00277             <argument name="labeliffalse">
00278                <para>Continue at <replaceable>labeliffalse</replaceable> if the condition is false.</para>
00279             </argument>
00280          </parameter>
00281       </syntax>
00282       <description>
00283          <para>This application will set the current context, extension, and priority in the channel structure
00284          based on the evaluation of the given condition. After this application completes, the
00285          pbx engine will continue dialplan execution at the specified location in the dialplan.
00286          The labels are specified with the same syntax as used within the Goto application.
00287          If the label chosen by the condition is omitted, no jump is performed, and the execution passes to the
00288          next instruction. If the target location is bogus, and does not exist, the execution engine will try
00289          to find and execute the code in the <literal>i</literal> (invalid) extension in the current context.
00290          If that does not exist, it will try to execute the <literal>h</literal> extension.
00291          If either or neither the <literal>h</literal> or <literal>i</literal> extensions have been defined,
00292          the channel is hung up, and the execution of instructions on the channel is terminated.
00293          Remember that this command can set the current context, and if the context specified
00294          does not exist, then it will not be able to find any 'h' or 'i' extensions there, and
00295          the channel and call will both be terminated!.</para>
00296       </description>
00297       <see-also>
00298          <ref type="application">Goto</ref>
00299          <ref type="application">GotoIfTime</ref>
00300          <ref type="application">GosubIf</ref>
00301          <ref type="application">MacroIf</ref>
00302       </see-also>
00303    </application>
00304    <application name="GotoIfTime" language="en_US">
00305       <synopsis>
00306          Conditional Goto based on the current time.
00307       </synopsis>
00308       <syntax argsep="?">
00309          <parameter name="condition" required="true">
00310             <argument name="times" required="true" />
00311             <argument name="weekdays" required="true" />
00312             <argument name="mdays" required="true" />
00313             <argument name="months" required="true" />
00314             <argument name="timezone" required="false" />
00315          </parameter>
00316          <parameter name="destination" required="true" argsep=":">
00317             <argument name="labeliftrue" />
00318             <argument name="labeliffalse" />
00319          </parameter>
00320       </syntax>
00321       <description>
00322          <para>This application will set the context, extension, and priority in the channel structure
00323          based on the evaluation of the given time specification. After this application completes,
00324          the pbx engine will continue dialplan execution at the specified location in the dialplan.
00325          If the current time is within the given time specification, the channel will continue at
00326          <replaceable>labeliftrue</replaceable>. Otherwise the channel will continue at <replaceable>labeliffalse</replaceable>.
00327          If the label chosen by the condition is omitted, no jump is performed, and execution passes to the next
00328          instruction. If the target jump location is bogus, the same actions would be taken as for <literal>Goto</literal>.
00329          Further information on the time specification can be found in examples
00330          illustrating how to do time-based context includes in the dialplan.</para>
00331       </description>
00332       <see-also>
00333          <ref type="application">GotoIf</ref>
00334          <ref type="function">IFTIME</ref>
00335       </see-also>
00336    </application>
00337    <application name="ImportVar" language="en_US">
00338       <synopsis>
00339          Import a variable from a channel into a new variable.
00340       </synopsis>
00341       <syntax argsep="=">
00342          <parameter name="newvar" required="true" />
00343          <parameter name="vardata" required="true">
00344             <argument name="channelname" required="true" />
00345             <argument name="variable" required="true" />
00346          </parameter>
00347       </syntax>
00348       <description>
00349          <para>This application imports a <replaceable>variable</replaceable> from the specified
00350          <replaceable>channel</replaceable> (as opposed to the current one) and stores it as a variable
00351          (<replaceable>newvar</replaceable>) in the current channel (the channel that is calling this
00352          application). Variables created by this application have the same inheritance properties as those
00353          created with the <literal>Set</literal> application.</para>
00354       </description>
00355       <see-also>
00356          <ref type="application">Set</ref>
00357       </see-also>
00358    </application>
00359    <application name="Hangup" language="en_US">
00360       <synopsis>
00361          Hang up the calling channel.
00362       </synopsis>
00363       <syntax>
00364          <parameter name="causecode">
00365             <para>If a <replaceable>causecode</replaceable> is given the channel's
00366             hangup cause will be set to the given value.</para>
00367          </parameter>
00368       </syntax>
00369       <description>
00370          <para>This application will hang up the calling channel.</para>
00371       </description>
00372       <see-also>
00373          <ref type="application">Answer</ref>
00374          <ref type="application">Busy</ref>
00375          <ref type="application">Congestion</ref>
00376       </see-also>
00377    </application>
00378    <application name="Incomplete" language="en_US">
00379       <synopsis>
00380          Returns AST_PBX_INCOMPLETE value.
00381       </synopsis>
00382       <syntax>
00383          <parameter name="n">
00384             <para>If specified, then Incomplete will not attempt to answer the channel first.</para>
00385             <note><para>Most channel types need to be in Answer state in order to receive DTMF.</para></note>
00386          </parameter>
00387       </syntax>
00388       <description>
00389          <para>Signals the PBX routines that the previous matched extension is incomplete
00390          and that further input should be allowed before matching can be considered
00391          to be complete.  Can be used within a pattern match when certain criteria warrants
00392          a longer match.</para>
00393       </description>
00394    </application>
00395    <application name="NoOp" language="en_US">
00396       <synopsis>
00397          Do Nothing (No Operation).
00398       </synopsis>
00399       <syntax>
00400          <parameter name="text">
00401             <para>Any text provided can be viewed at the Asterisk CLI.</para>
00402          </parameter>
00403       </syntax>
00404       <description>
00405          <para>This application does nothing. However, it is useful for debugging purposes.</para>
00406          <para>This method can be used to see the evaluations of variables or functions without having any effect.</para>
00407       </description>
00408       <see-also>
00409          <ref type="application">Verbose</ref>
00410          <ref type="application">Log</ref>
00411       </see-also>
00412    </application>
00413    <application name="Proceeding" language="en_US">
00414       <synopsis>
00415          Indicate proceeding.
00416       </synopsis>
00417       <syntax />
00418       <description>
00419          <para>This application will request that a proceeding message be provided to the calling channel.</para>
00420       </description>
00421    </application>
00422    <application name="Progress" language="en_US">
00423       <synopsis>
00424          Indicate progress.
00425       </synopsis>
00426       <syntax />
00427       <description>
00428          <para>This application will request that in-band progress information be provided to the calling channel.</para>
00429       </description>
00430       <see-also>
00431          <ref type="application">Busy</ref>
00432          <ref type="application">Congestion</ref>
00433          <ref type="application">Ringing</ref>
00434          <ref type="application">Playtones</ref>
00435       </see-also>
00436    </application>
00437    <application name="RaiseException" language="en_US">
00438       <synopsis>
00439          Handle an exceptional condition.
00440       </synopsis>
00441       <syntax>
00442          <parameter name="reason" required="true" />
00443       </syntax>
00444       <description>
00445          <para>This application will jump to the <literal>e</literal> extension in the current context, setting the
00446          dialplan function EXCEPTION(). If the <literal>e</literal> extension does not exist, the call will hangup.</para>
00447       </description>
00448       <see-also>
00449          <ref type="function">Exception</ref>
00450       </see-also>
00451    </application>
00452    <application name="ResetCDR" language="en_US">
00453       <synopsis>
00454          Resets the Call Data Record.
00455       </synopsis>
00456       <syntax>
00457          <parameter name="options">
00458             <optionlist>
00459                <option name="w">
00460                   <para>Store the current CDR record before resetting it.</para>
00461                </option>
00462                <option name="a">
00463                   <para>Store any stacked records.</para>
00464                </option>
00465                <option name="v">
00466                   <para>Save CDR variables.</para>
00467                </option>
00468                <option name="e">
00469                   <para>Enable CDR only (negate effects of NoCDR).</para>
00470                </option>
00471             </optionlist>
00472          </parameter>
00473       </syntax>
00474       <description>
00475          <para>This application causes the Call Data Record to be reset.</para>
00476       </description>
00477       <see-also>
00478          <ref type="application">ForkCDR</ref>
00479          <ref type="application">NoCDR</ref>
00480       </see-also>
00481    </application>
00482    <application name="Ringing" language="en_US">
00483       <synopsis>
00484          Indicate ringing tone.
00485       </synopsis>
00486       <syntax />
00487       <description>
00488          <para>This application will request that the channel indicate a ringing tone to the user.</para>
00489       </description>
00490       <see-also>
00491          <ref type="application">Busy</ref>
00492          <ref type="application">Congestion</ref>
00493          <ref type="application">Progress</ref>
00494          <ref type="application">Playtones</ref>
00495       </see-also>
00496    </application>
00497    <application name="SayAlpha" language="en_US">
00498       <synopsis>
00499          Say Alpha.
00500       </synopsis>
00501       <syntax>
00502          <parameter name="string" required="true" />
00503       </syntax>
00504       <description>
00505          <para>This application will play the sounds that correspond to the letters of the
00506          given <replaceable>string</replaceable>.</para>
00507       </description>
00508       <see-also>
00509          <ref type="application">SayDigits</ref>
00510          <ref type="application">SayNumber</ref>
00511          <ref type="application">SayPhonetic</ref>
00512          <ref type="function">CHANNEL</ref>
00513       </see-also>
00514    </application>
00515    <application name="SayDigits" language="en_US">
00516       <synopsis>
00517          Say Digits.
00518       </synopsis>
00519       <syntax>
00520          <parameter name="digits" required="true" />
00521       </syntax>
00522       <description>
00523          <para>This application will play the sounds that correspond to the digits of
00524          the given number. This will use the language that is currently set for the channel.</para>
00525       </description>
00526       <see-also>
00527          <ref type="application">SayAlpha</ref>
00528          <ref type="application">SayNumber</ref>
00529          <ref type="application">SayPhonetic</ref>
00530          <ref type="function">CHANNEL</ref>
00531       </see-also>
00532    </application>
00533    <application name="SayNumber" language="en_US">
00534       <synopsis>
00535          Say Number.
00536       </synopsis>
00537       <syntax>
00538          <parameter name="digits" required="true" />
00539          <parameter name="gender" />
00540       </syntax>
00541       <description>
00542          <para>This application will play the sounds that correspond to the given <replaceable>digits</replaceable>.
00543          Optionally, a <replaceable>gender</replaceable> may be specified. This will use the language that is currently
00544          set for the channel. See the LANGUAGE() function for more information on setting the language for the channel.</para>
00545       </description>
00546       <see-also>
00547          <ref type="application">SayAlpha</ref>
00548          <ref type="application">SayDigits</ref>
00549          <ref type="application">SayPhonetic</ref>
00550          <ref type="function">CHANNEL</ref>
00551       </see-also>
00552    </application>
00553    <application name="SayPhonetic" language="en_US">
00554       <synopsis>
00555          Say Phonetic.
00556       </synopsis>
00557       <syntax>
00558          <parameter name="string" required="true" />
00559       </syntax>
00560       <description>
00561          <para>This application will play the sounds from the phonetic alphabet that correspond to the
00562          letters in the given <replaceable>string</replaceable>.</para>
00563       </description>
00564       <see-also>
00565          <ref type="application">SayAlpha</ref>
00566          <ref type="application">SayDigits</ref>
00567          <ref type="application">SayNumber</ref>
00568       </see-also>
00569    </application>
00570    <application name="Set" language="en_US">
00571       <synopsis>
00572          Set channel variable or function value.
00573       </synopsis>
00574       <syntax argsep="=">
00575          <parameter name="name" required="true" />
00576          <parameter name="value" required="true" />
00577       </syntax>
00578       <description>
00579          <para>This function can be used to set the value of channel variables or dialplan functions.
00580          When setting variables, if the variable name is prefixed with <literal>_</literal>,
00581          the variable will be inherited into channels created from the current channel.
00582          If the variable name is prefixed with <literal>__</literal>, the variable will be
00583          inherited into channels created from the current channel and all children channels.</para>
00584          <note><para>If (and only if), in <filename>/etc/asterisk/asterisk.conf</filename>, you have
00585          a <literal>[compat]</literal> category, and you have <literal>app_set = 1.6</literal> under that,then
00586          the behavior of this app changes, and does not strip surrounding quotes from the right hand side as
00587          it did previously in 1.4. The <literal>app_set = 1.6</literal> is only inserted if <literal>make samples</literal>
00588          is executed, or if users insert this by hand into the <filename>asterisk.conf</filename> file.
00589          The advantages of not stripping out quoting, and not caring about the separator characters (comma and vertical bar)
00590          were sufficient to make these changes in 1.6. Confusion about how many backslashes would be needed to properly
00591          protect separators and quotes in various database access strings has been greatly
00592          reduced by these changes.</para></note>
00593       </description>
00594       <see-also>
00595          <ref type="application">MSet</ref>
00596          <ref type="function">GLOBAL</ref>
00597          <ref type="function">SET</ref>
00598          <ref type="function">ENV</ref>
00599       </see-also>
00600    </application>
00601    <application name="MSet" language="en_US">
00602       <synopsis>
00603          Set channel variable(s) or function value(s).
00604       </synopsis>
00605       <syntax>
00606          <parameter name="set1" required="true" argsep="=">
00607             <argument name="name1" required="true" />
00608             <argument name="value1" required="true" />
00609          </parameter>
00610          <parameter name="set2" multiple="true" argsep="=">
00611             <argument name="name2" required="true" />
00612             <argument name="value2" required="true" />
00613          </parameter>
00614       </syntax>
00615       <description>
00616          <para>This function can be used to set the value of channel variables or dialplan functions.
00617          When setting variables, if the variable name is prefixed with <literal>_</literal>,
00618          the variable will be inherited into channels created from the current channel
00619          If the variable name is prefixed with <literal>__</literal>, the variable will be
00620          inherited into channels created from the current channel and all children channels.
00621          MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus
00622          prone to doing things that you may not expect. For example, it strips surrounding
00623          double-quotes from the right-hand side (value). If you need to put a separator
00624          character (comma or vert-bar), you will need to escape them by inserting a backslash
00625          before them. Avoid its use if possible.</para>
00626       </description>
00627       <see-also>
00628          <ref type="application">Set</ref>
00629       </see-also>
00630    </application>
00631    <application name="SetAMAFlags" language="en_US">
00632       <synopsis>
00633          Set the AMA Flags.
00634       </synopsis>
00635       <syntax>
00636          <parameter name="flag" />
00637       </syntax>
00638       <description>
00639          <para>This application will set the channel's AMA Flags for billing purposes.</para>
00640       </description>
00641       <see-also>
00642          <ref type="function">CDR</ref>
00643       </see-also>
00644    </application>
00645    <application name="Wait" language="en_US">
00646       <synopsis>
00647          Waits for some time.
00648       </synopsis>
00649       <syntax>
00650          <parameter name="seconds" required="true">
00651             <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
00652             application to wait for 1.5 seconds.</para>
00653          </parameter>
00654       </syntax>
00655       <description>
00656          <para>This application waits for a specified number of <replaceable>seconds</replaceable>.</para>
00657       </description>
00658    </application>
00659    <application name="WaitExten" language="en_US">
00660       <synopsis>
00661          Waits for an extension to be entered.
00662       </synopsis>
00663       <syntax>
00664          <parameter name="seconds">
00665             <para>Can be passed with fractions of a second. For example, <literal>1.5</literal> will ask the
00666             application to wait for 1.5 seconds.</para>
00667          </parameter>
00668          <parameter name="options">
00669             <optionlist>
00670                <option name="m">
00671                   <para>Provide music on hold to the caller while waiting for an extension.</para>
00672                   <argument name="x">
00673                      <para>Specify the class for music on hold.</para>
00674                   </argument>
00675                </option>
00676             </optionlist>
00677          </parameter>
00678       </syntax>
00679       <description>
00680          <para>This application waits for the user to enter a new extension for a specified number
00681          of <replaceable>seconds</replaceable>.</para>
00682          <xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
00683       </description>
00684       <see-also>
00685          <ref type="application">Background</ref>
00686          <ref type="function">TIMEOUT</ref>
00687       </see-also>
00688    </application>
00689    <function name="EXCEPTION" language="en_US">
00690       <synopsis>
00691          Retrieve the details of the current dialplan exception.
00692       </synopsis>
00693       <syntax>
00694          <parameter name="field" required="true">
00695             <para>The following fields are available for retrieval:</para>
00696             <enumlist>
00697                <enum name="reason">
00698                   <para>INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom
00699                   value set by the RaiseException() application</para>
00700                </enum>
00701                <enum name="context">
00702                   <para>The context executing when the exception occurred.</para>
00703                </enum>
00704                <enum name="exten">
00705                   <para>The extension executing when the exception occurred.</para>
00706                </enum>
00707                <enum name="priority">
00708                   <para>The numeric priority executing when the exception occurred.</para>
00709                </enum>
00710             </enumlist>
00711          </parameter>
00712       </syntax>
00713       <description>
00714          <para>Retrieve the details (specified <replaceable>field</replaceable>) of the current dialplan exception.</para>
00715       </description>
00716       <see-also>
00717          <ref type="application">RaiseException</ref>
00718       </see-also>
00719    </function>
00720  ***/
00721 
00722 #ifdef LOW_MEMORY
00723 #define EXT_DATA_SIZE 256
00724 #else
00725 #define EXT_DATA_SIZE 8192
00726 #endif
00727 
00728 #define SWITCH_DATA_LENGTH 256
00729 
00730 #define VAR_BUF_SIZE 4096
00731 
00732 #define  VAR_NORMAL     1
00733 #define  VAR_SOFTTRAN   2
00734 #define  VAR_HARDTRAN   3
00735 
00736 #define BACKGROUND_SKIP    (1 << 0)
00737 #define BACKGROUND_NOANSWER   (1 << 1)
00738 #define BACKGROUND_MATCHEXTEN (1 << 2)
00739 #define BACKGROUND_PLAYBACK   (1 << 3)
00740 
00741 AST_APP_OPTIONS(background_opts, {
00742    AST_APP_OPTION('s', BACKGROUND_SKIP),
00743    AST_APP_OPTION('n', BACKGROUND_NOANSWER),
00744    AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
00745    AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
00746 });
00747 
00748 #define WAITEXTEN_MOH      (1 << 0)
00749 #define WAITEXTEN_DIALTONE (1 << 1)
00750 
00751 AST_APP_OPTIONS(waitexten_opts, {
00752    AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
00753    AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
00754 });
00755 
00756 struct ast_context;
00757 struct ast_app;
00758 
00759 static struct ast_taskprocessor *device_state_tps;
00760 
00761 AST_THREADSTORAGE(switch_data);
00762 AST_THREADSTORAGE(extensionstate_buf);
00763 
00764 /*!
00765    \brief ast_exten: An extension
00766    The dialplan is saved as a linked list with each context
00767    having it's own linked list of extensions - one item per
00768    priority.
00769 */
00770 struct ast_exten {
00771    char *exten;         /*!< Extension name */
00772    int matchcid;        /*!< Match caller id ? */
00773    const char *cidmatch;      /*!< Caller id to match for this extension */
00774    int priority;        /*!< Priority */
00775    const char *label;      /*!< Label */
00776    struct ast_context *parent;   /*!< The context this extension belongs to  */
00777    const char *app;     /*!< Application to execute */
00778    struct ast_app *cached_app;     /*!< Cached location of application */
00779    void *data;       /*!< Data to use (arguments) */
00780    void (*datad)(void *);     /*!< Data destructor */
00781    struct ast_exten *peer;    /*!< Next higher priority with our extension */
00782    struct ast_hashtab *peer_table;    /*!< Priorities list in hashtab form -- only on the head of the peer list */
00783    struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
00784    const char *registrar;     /*!< Registrar */
00785    struct ast_exten *next;    /*!< Extension with a greater ID */
00786    char stuff[0];
00787 };
00788 
00789 /*! \brief ast_include: include= support in extensions.conf */
00790 struct ast_include {
00791    const char *name;
00792    const char *rname;         /*!< Context to include */
00793    const char *registrar;        /*!< Registrar */
00794    int hastime;            /*!< If time construct exists */
00795    struct ast_timing timing;               /*!< time construct */
00796    struct ast_include *next;     /*!< Link them together */
00797    char stuff[0];
00798 };
00799 
00800 /*! \brief ast_sw: Switch statement in extensions.conf */
00801 struct ast_sw {
00802    char *name;
00803    const char *registrar;        /*!< Registrar */
00804    char *data;          /*!< Data load */
00805    int eval;
00806    AST_LIST_ENTRY(ast_sw) list;
00807    char stuff[0];
00808 };
00809 
00810 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
00811 struct ast_ignorepat {
00812    const char *registrar;
00813    struct ast_ignorepat *next;
00814    const char pattern[0];
00815 };
00816 
00817 /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
00818 struct match_char
00819 {
00820    int is_pattern; /* the pattern started with '_' */
00821    int deleted;    /* if this is set, then... don't return it */
00822    char *x;       /* the pattern itself-- matches a single char */
00823    int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
00824    struct match_char *alt_char;
00825    struct match_char *next_char;
00826    struct ast_exten *exten; /* attached to last char of a pattern for exten */
00827 };
00828 
00829 struct scoreboard  /* make sure all fields are 0 before calling new_find_extension */
00830 {
00831    int total_specificity;
00832    int total_length;
00833    char last_char;   /* set to ! or . if they are the end of the pattern */
00834    int canmatch;     /* if the string to match was just too short */
00835    struct match_char *node;
00836    struct ast_exten *canmatch_exten;
00837    struct ast_exten *exten;
00838 };
00839 
00840 /*! \brief ast_context: An extension context */
00841 struct ast_context {
00842    ast_rwlock_t lock;         /*!< A lock to prevent multiple threads from clobbering the context */
00843    struct ast_exten *root;       /*!< The root of the list of extensions */
00844    struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
00845    struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
00846    struct ast_context *next;     /*!< Link them together */
00847    struct ast_include *includes;    /*!< Include other contexts */
00848    struct ast_ignorepat *ignorepats;   /*!< Patterns for which to continue playing dialtone */
00849    char *registrar;        /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
00850    int refcount;                   /*!< each module that would have created this context should inc/dec this as appropriate */
00851    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;   /*!< Alternative switches */
00852    ast_mutex_t macrolock;        /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
00853    char name[0];           /*!< Name of the context */
00854 };
00855 
00856 /*! \brief ast_app: A registered application */
00857 struct ast_app {
00858    int (*execute)(struct ast_channel *chan, void *data);
00859    AST_DECLARE_STRING_FIELDS(
00860       AST_STRING_FIELD(synopsis);     /*!< Synopsis text for 'show applications' */
00861       AST_STRING_FIELD(description);  /*!< Description (help text) for 'show application &lt;name&gt;' */
00862       AST_STRING_FIELD(syntax);       /*!< Syntax text for 'core show applications' */
00863       AST_STRING_FIELD(arguments);    /*!< Arguments description */
00864       AST_STRING_FIELD(seealso);      /*!< See also */
00865    );
00866    enum ast_doc_src docsrc;/*!< Where the documentation come from. */
00867    AST_RWLIST_ENTRY(ast_app) list;     /*!< Next app in list */
00868    struct ast_module *module;    /*!< Module this app belongs to */
00869    char name[0];           /*!< Name of the application */
00870 };
00871 
00872 /*! \brief ast_state_cb: An extension state notify register item */
00873 struct ast_state_cb {
00874    int id;
00875    void *data;
00876    ast_state_cb_type callback;
00877    AST_LIST_ENTRY(ast_state_cb) entry;
00878 };
00879 
00880 /*! \brief Structure for dial plan hints
00881 
00882   \note Hints are pointers from an extension in the dialplan to one or
00883   more devices (tech/name)
00884    - See \ref AstExtState
00885 */
00886 struct ast_hint {
00887    struct ast_exten *exten;   /*!< Extension */
00888    int laststate;       /*!< Last known state */
00889    struct ao2_container *callbacks; /*!< Callback container for this extension */
00890 };
00891 
00892 /* --- Hash tables of various objects --------*/
00893 #ifdef LOW_MEMORY
00894 static const int HASH_EXTENHINT_SIZE = 17;
00895 #else
00896 static const int HASH_EXTENHINT_SIZE = 563;
00897 #endif
00898 
00899 static const struct cfextension_states {
00900    int extension_state;
00901    const char * const text;
00902 } extension_states[] = {
00903    { AST_EXTENSION_NOT_INUSE,                     "Idle" },
00904    { AST_EXTENSION_INUSE,                         "InUse" },
00905    { AST_EXTENSION_BUSY,                          "Busy" },
00906    { AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
00907    { AST_EXTENSION_RINGING,                       "Ringing" },
00908    { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
00909    { AST_EXTENSION_ONHOLD,                        "Hold" },
00910    { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
00911 };
00912 
00913 struct statechange {
00914    AST_LIST_ENTRY(statechange) entry;
00915    char dev[0];
00916 };
00917 
00918 struct pbx_exception {
00919    AST_DECLARE_STRING_FIELDS(
00920       AST_STRING_FIELD(context); /*!< Context associated with this exception */
00921       AST_STRING_FIELD(exten);   /*!< Exten associated with this exception */
00922       AST_STRING_FIELD(reason);     /*!< The exception reason */
00923    );
00924 
00925    int priority;           /*!< Priority associated with this exception */
00926 };
00927 
00928 static int pbx_builtin_answer(struct ast_channel *, void *);
00929 static int pbx_builtin_goto(struct ast_channel *, void *);
00930 static int pbx_builtin_hangup(struct ast_channel *, void *);
00931 static int pbx_builtin_background(struct ast_channel *, void *);
00932 static int pbx_builtin_wait(struct ast_channel *, void *);
00933 static int pbx_builtin_waitexten(struct ast_channel *, void *);
00934 static int pbx_builtin_incomplete(struct ast_channel *, void *);
00935 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00936 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
00937 static int pbx_builtin_ringing(struct ast_channel *, void *);
00938 static int pbx_builtin_proceeding(struct ast_channel *, void *);
00939 static int pbx_builtin_progress(struct ast_channel *, void *);
00940 static int pbx_builtin_congestion(struct ast_channel *, void *);
00941 static int pbx_builtin_busy(struct ast_channel *, void *);
00942 static int pbx_builtin_noop(struct ast_channel *, void *);
00943 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00944 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00945 static int pbx_builtin_execiftime(struct ast_channel *, void *);
00946 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00947 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00948 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
00949 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
00950 static int matchcid(const char *cidpattern, const char *callerid);
00951 int pbx_builtin_setvar(struct ast_channel *, void *);
00952 void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
00953 int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
00954 static int pbx_builtin_importvar(struct ast_channel *, void *);
00955 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri);
00956 static void new_find_extension(const char *str, struct scoreboard *score,
00957       struct match_char *tree, int length, int spec, const char *callerid,
00958       const char *label, enum ext_match_t action);
00959 static struct match_char *already_in_tree(struct match_char *current, char *pat);
00960 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con,
00961       struct ast_exten *e1, int findonly);
00962 static struct match_char *add_pattern_node(struct ast_context *con,
00963       struct match_char *current, char *pattern, int is_pattern,
00964       int already, int specificity, struct match_char **parent);
00965 static void create_match_char_tree(struct ast_context *con);
00966 static struct ast_exten *get_canmatch_exten(struct match_char *node);
00967 static void destroy_pattern_tree(struct match_char *pattern_tree);
00968 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
00969 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
00970 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
00971 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
00972 unsigned int ast_hashtab_hash_contexts(const void *obj);
00973 static unsigned int hashtab_hash_extens(const void *obj);
00974 static unsigned int hashtab_hash_priority(const void *obj);
00975 static unsigned int hashtab_hash_labels(const void *obj);
00976 static void __ast_internal_context_destroy( struct ast_context *con);
00977 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
00978    int priority, const char *label, const char *callerid,
00979    const char *application, void *data, void (*datad)(void *), const char *registrar);
00980 static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
00981    struct ast_exten *el, struct ast_exten *e, int replace, int lockhints);
00982 static int ast_add_extension2_lockopt(struct ast_context *con,
00983    int replace, const char *extension, int priority, const char *label, const char *callerid,
00984    const char *application, void *data, void (*datad)(void *),
00985    const char *registrar, int lockconts, int lockhints);
00986 
00987 /* a func for qsort to use to sort a char array */
00988 static int compare_char(const void *a, const void *b)
00989 {
00990    const char *ac = a;
00991    const char *bc = b;
00992    if ((*ac) < (*bc))
00993       return -1;
00994    else if ((*ac) == (*bc))
00995       return 0;
00996    else
00997       return 1;
00998 }
00999 
01000 /* labels, contexts are case sensitive  priority numbers are ints */
01001 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
01002 {
01003    const struct ast_context *ac = ah_a;
01004    const struct ast_context *bc = ah_b;
01005    if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
01006       return 1;
01007    /* assume context names are registered in a string table! */
01008    return strcmp(ac->name, bc->name);
01009 }
01010 
01011 static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
01012 {
01013    const struct ast_exten *ac = ah_a;
01014    const struct ast_exten *bc = ah_b;
01015    int x = strcmp(ac->exten, bc->exten);
01016    if (x) { /* if exten names are diff, then return */
01017       return x;
01018    }
01019 
01020    /* but if they are the same, do the cidmatch values match? */
01021    if (ac->matchcid && bc->matchcid) {
01022       return strcmp(ac->cidmatch,bc->cidmatch);
01023    } else if (!ac->matchcid && !bc->matchcid) {
01024       return 0; /* if there's no matchcid on either side, then this is a match */
01025    } else {
01026       return 1; /* if there's matchcid on one but not the other, they are different */
01027    }
01028 }
01029 
01030 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
01031 {
01032    const struct ast_exten *ac = ah_a;
01033    const struct ast_exten *bc = ah_b;
01034    return ac->priority != bc->priority;
01035 }
01036 
01037 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
01038 {
01039    const struct ast_exten *ac = ah_a;
01040    const struct ast_exten *bc = ah_b;
01041    return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
01042 }
01043 
01044 unsigned int ast_hashtab_hash_contexts(const void *obj)
01045 {
01046    const struct ast_context *ac = obj;
01047    return ast_hashtab_hash_string(ac->name);
01048 }
01049 
01050 static unsigned int hashtab_hash_extens(const void *obj)
01051 {
01052    const struct ast_exten *ac = obj;
01053    unsigned int x = ast_hashtab_hash_string(ac->exten);
01054    unsigned int y = 0;
01055    if (ac->matchcid)
01056       y = ast_hashtab_hash_string(ac->cidmatch);
01057    return x+y;
01058 }
01059 
01060 static unsigned int hashtab_hash_priority(const void *obj)
01061 {
01062    const struct ast_exten *ac = obj;
01063    return ast_hashtab_hash_int(ac->priority);
01064 }
01065 
01066 static unsigned int hashtab_hash_labels(const void *obj)
01067 {
01068    const struct ast_exten *ac = obj;
01069    return ast_hashtab_hash_string(S_OR(ac->label, ""));
01070 }
01071 
01072 
01073 AST_RWLOCK_DEFINE_STATIC(globalslock);
01074 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
01075 
01076 static int autofallthrough = 1;
01077 static int extenpatternmatchnew = 0;
01078 static char *overrideswitch = NULL;
01079 
01080 /*! \brief Subscription for device state change events */
01081 static struct ast_event_sub *device_state_sub;
01082 
01083 AST_MUTEX_DEFINE_STATIC(maxcalllock);
01084 static int countcalls;
01085 static int totalcalls;
01086 
01087 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
01088 
01089 /*! \brief Declaration of builtin applications */
01090 static struct pbx_builtin {
01091    char name[AST_MAX_APP];
01092    int (*execute)(struct ast_channel *chan, void *data);
01093 } builtins[] =
01094 {
01095    /* These applications are built into the PBX core and do not
01096       need separate modules */
01097 
01098    { "Answer",         pbx_builtin_answer },
01099    { "BackGround",     pbx_builtin_background },
01100    { "Busy",           pbx_builtin_busy },
01101    { "Congestion",     pbx_builtin_congestion },
01102    { "ExecIfTime",     pbx_builtin_execiftime },
01103    { "Goto",           pbx_builtin_goto },
01104    { "GotoIf",         pbx_builtin_gotoif },
01105    { "GotoIfTime",     pbx_builtin_gotoiftime },
01106    { "ImportVar",      pbx_builtin_importvar },
01107    { "Hangup",         pbx_builtin_hangup },
01108    { "Incomplete",     pbx_builtin_incomplete },
01109    { "NoOp",           pbx_builtin_noop },
01110    { "Proceeding",     pbx_builtin_proceeding },
01111    { "Progress",       pbx_builtin_progress },
01112    { "RaiseException", pbx_builtin_raise_exception },
01113    { "ResetCDR",       pbx_builtin_resetcdr },
01114    { "Ringing",        pbx_builtin_ringing },
01115    { "SayAlpha",       pbx_builtin_saycharacters },
01116    { "SayDigits",      pbx_builtin_saydigits },
01117    { "SayNumber",      pbx_builtin_saynumber },
01118    { "SayPhonetic",    pbx_builtin_sayphonetic },
01119    { "Set",            pbx_builtin_setvar },
01120    { "MSet",           pbx_builtin_setvar_multiple },
01121    { "SetAMAFlags",    pbx_builtin_setamaflags },
01122    { "Wait",           pbx_builtin_wait },
01123    { "WaitExten",      pbx_builtin_waitexten }
01124 };
01125 
01126 static struct ast_context *contexts;
01127 static struct ast_hashtab *contexts_table = NULL;
01128 
01129 /*!\brief Lock for the ast_context list
01130  * This lock MUST be recursive, or a deadlock on reload may result.  See
01131  * https://issues.asterisk.org/view.php?id=17643
01132  */
01133 AST_MUTEX_DEFINE_STATIC(conlock);
01134 
01135 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
01136 
01137 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
01138 
01139 static int stateid = 1;
01140 /* WARNING:
01141    When holding this container's lock, do _not_ do anything that will cause conlock
01142    to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
01143    function will take the locks in conlock/hints order, so any other
01144    paths that require both locks must also take them in that order.
01145 */
01146 static struct ao2_container *hints;
01147 
01148 static struct ao2_container *statecbs;
01149 
01150 #ifdef CONTEXT_DEBUG
01151 
01152 /* these routines are provided for doing run-time checks
01153    on the extension structures, in case you are having
01154    problems, this routine might help you localize where
01155    the problem is occurring. It's kinda like a debug memory
01156    allocator's arena checker... It'll eat up your cpu cycles!
01157    but you'll see, if you call it in the right places,
01158    right where your problems began...
01159 */
01160 
01161 /* you can break on the check_contexts_trouble()
01162 routine in your debugger to stop at the moment
01163 there's a problem */
01164 void check_contexts_trouble(void);
01165 
01166 void check_contexts_trouble(void)
01167 {
01168    int x = 1;
01169    x = 2;
01170 }
01171 
01172 static struct ast_context *find_context_locked(const char *context);
01173 static struct ast_context *find_context(const char *context);
01174 int check_contexts(char *, int);
01175 
01176 int check_contexts(char *file, int line )
01177 {
01178    struct ast_hashtab_iter *t1;
01179    struct ast_context *c1, *c2;
01180    int found = 0;
01181    struct ast_exten *e1, *e2, *e3;
01182    struct ast_exten ex;
01183 
01184    /* try to find inconsistencies */
01185    /* is every context in the context table in the context list and vice-versa ? */
01186 
01187    if (!contexts_table) {
01188       ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
01189       usleep(500000);
01190    }
01191 
01192    t1 = ast_hashtab_start_traversal(contexts_table);
01193    while( (c1 = ast_hashtab_next(t1))) {
01194       for(c2=contexts;c2;c2=c2->next) {
01195          if (!strcmp(c1->name, c2->name)) {
01196             found = 1;
01197             break;
01198          }
01199       }
01200       if (!found) {
01201          ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
01202          check_contexts_trouble();
01203       }
01204    }
01205    ast_hashtab_end_traversal(t1);
01206    for(c2=contexts;c2;c2=c2->next) {
01207       c1 = find_context_locked(c2->name);
01208       if (!c1) {
01209          ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
01210          check_contexts_trouble();
01211       } else
01212          ast_unlock_contexts();
01213    }
01214 
01215    /* loop thru all contexts, and verify the exten structure compares to the 
01216       hashtab structure */
01217    for(c2=contexts;c2;c2=c2->next) {
01218       c1 = find_context_locked(c2->name);
01219       if (c1)
01220       {
01221 
01222          ast_unlock_contexts();
01223 
01224          /* is every entry in the root list also in the root_table? */
01225          for(e1 = c1->root; e1; e1=e1->next)
01226          {
01227             char dummy_name[1024];
01228             ex.exten = dummy_name;
01229             ex.matchcid = e1->matchcid;
01230             ex.cidmatch = e1->cidmatch;
01231             ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
01232             e2 = ast_hashtab_lookup(c1->root_table, &ex);
01233             if (!e2) {
01234                if (e1->matchcid) {
01235                   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 );
01236                } else {
01237                   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 );
01238                }
01239                check_contexts_trouble();
01240             }
01241          }
01242 
01243          /* is every entry in the root_table also in the root list? */ 
01244          if (!c2->root_table) {
01245             if (c2->root) {
01246                ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
01247                usleep(500000);
01248             }
01249          } else {
01250             t1 = ast_hashtab_start_traversal(c2->root_table);
01251             while( (e2 = ast_hashtab_next(t1)) ) {
01252                for(e1=c2->root;e1;e1=e1->next) {
01253                   if (!strcmp(e1->exten, e2->exten)) {
01254                      found = 1;
01255                      break;
01256                   }
01257                }
01258                if (!found) {
01259                   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);
01260                   check_contexts_trouble();
01261                }
01262 
01263             }
01264             ast_hashtab_end_traversal(t1);
01265          }
01266       }
01267       /* is every priority reflected in the peer_table at the head of the list? */
01268 
01269       /* is every entry in the root list also in the root_table? */
01270       /* are the per-extension peer_tables in the right place? */
01271 
01272       for(e1 = c2->root; e1; e1 = e1->next) {
01273 
01274          for(e2=e1;e2;e2=e2->peer) {
01275             ex.priority = e2->priority;
01276             if (e2 != e1 && e2->peer_table) {
01277                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 );
01278                check_contexts_trouble();
01279             }
01280 
01281             if (e2 != e1 && e2->peer_label_table) {
01282                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 );
01283                check_contexts_trouble();
01284             }
01285 
01286             if (e2 == e1 && !e2->peer_table){
01287                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 );
01288                check_contexts_trouble();
01289             }
01290 
01291             if (e2 == e1 && !e2->peer_label_table) {
01292                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 );
01293                check_contexts_trouble();
01294             }
01295 
01296 
01297             e3 = ast_hashtab_lookup(e1->peer_table, &ex);
01298             if (!e3) {
01299                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 );
01300                check_contexts_trouble();
01301             }
01302          }
01303 
01304          if (!e1->peer_table){
01305             ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
01306             usleep(500000);
01307          }
01308 
01309          /* is every entry in the peer_table also in the peer list? */
01310          t1 = ast_hashtab_start_traversal(e1->peer_table);
01311          while( (e2 = ast_hashtab_next(t1)) ) {
01312             for(e3=e1;e3;e3=e3->peer) {
01313                if (e3->priority == e2->priority) {
01314                   found = 1;
01315                   break;
01316                }
01317             }
01318             if (!found) {
01319                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 );
01320                check_contexts_trouble();
01321             }
01322          }
01323          ast_hashtab_end_traversal(t1);
01324       }
01325    }
01326    return 0;
01327 }
01328 #endif
01329 
01330 /*
01331    \note This function is special. It saves the stack so that no matter
01332    how many times it is called, it returns to the same place */
01333 int pbx_exec(struct ast_channel *c, /*!< Channel */
01334         struct ast_app *app,       /*!< Application */
01335         void *data)                /*!< Data for execution */
01336 {
01337    int res;
01338    struct ast_module_user *u = NULL;
01339    const char *saved_c_appl;
01340    const char *saved_c_data;
01341 
01342    if (c->cdr && !ast_check_hangup(c))
01343       ast_cdr_setapp(c->cdr, app->name, data);
01344 
01345    /* save channel values */
01346    saved_c_appl= c->appl;
01347    saved_c_data= c->data;
01348 
01349    c->appl = app->name;
01350    c->data = data;
01351    if (app->module)
01352       u = __ast_module_user_add(app->module, c);
01353    if (strcasecmp(app->name, "system") && !ast_strlen_zero(data) &&
01354          strchr(data, '|') && !strchr(data, ',') && !ast_opt_dont_warn) {
01355       ast_log(LOG_WARNING, "The application delimiter is now the comma, not "
01356          "the pipe.  Did you forget to convert your dialplan?  (%s(%s))\n",
01357          app->name, (char *) data);
01358    }
01359    res = app->execute(c, S_OR((char *) data, ""));
01360    if (app->module && u)
01361       __ast_module_user_remove(app->module, u);
01362    /* restore channel values */
01363    c->appl = saved_c_appl;
01364    c->data = saved_c_data;
01365    return res;
01366 }
01367 
01368 
01369 /*! Go no deeper than this through includes (not counting loops) */
01370 #define AST_PBX_MAX_STACK  128
01371 
01372 /*! \brief Find application handle in linked list
01373  */
01374 struct ast_app *pbx_findapp(const char *app)
01375 {
01376    struct ast_app *tmp;
01377 
01378    AST_RWLIST_RDLOCK(&apps);
01379    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
01380       if (!strcasecmp(tmp->name, app))
01381          break;
01382    }
01383    AST_RWLIST_UNLOCK(&apps);
01384 
01385    return tmp;
01386 }
01387 
01388 static struct ast_switch *pbx_findswitch(const char *sw)
01389 {
01390    struct ast_switch *asw;
01391 
01392    AST_RWLIST_RDLOCK(&switches);
01393    AST_RWLIST_TRAVERSE(&switches, asw, list) {
01394       if (!strcasecmp(asw->name, sw))
01395          break;
01396    }
01397    AST_RWLIST_UNLOCK(&switches);
01398 
01399    return asw;
01400 }
01401 
01402 static inline int include_valid(struct ast_include *i)
01403 {
01404    if (!i->hastime)
01405       return 1;
01406 
01407    return ast_check_timing(&(i->timing));
01408 }
01409 
01410 static void pbx_destroy(struct ast_pbx *p)
01411 {
01412    ast_free(p);
01413 }
01414 
01415 /* form a tree that fully describes all the patterns in a context's extensions
01416  * in this tree, a "node" represents an individual character or character set
01417  * meant to match the corresponding character in a dial string. The tree
01418  * consists of a series of match_char structs linked in a chain
01419  * via the alt_char pointers. More than one pattern can share the same parts of the
01420  * tree as other extensions with the same pattern to that point.
01421  * My first attempt to duplicate the finding of the 'best' pattern was flawed in that
01422  * I misunderstood the general algorithm. I thought that the 'best' pattern
01423  * was the one with lowest total score. This was not true. Thus, if you have
01424  * patterns "1XXXXX" and "X11111", you would be tempted to say that "X11111" is
01425  * the "best" match because it has fewer X's, and is therefore more specific,
01426  * but this is not how the old algorithm works. It sorts matching patterns
01427  * in a similar collating sequence as sorting alphabetic strings, from left to
01428  * right. Thus, "1XXXXX" comes before "X11111", and would be the "better" match,
01429  * because "1" is more specific than "X".
01430  * So, to accomodate this philosophy, I sort the tree branches along the alt_char
01431  * line so they are lowest to highest in specificity numbers. This way, as soon
01432  * as we encounter our first complete match, we automatically have the "best"
01433  * match and can stop the traversal immediately. Same for CANMATCH/MATCHMORE.
01434  * If anyone would like to resurrect the "wrong" pattern trie searching algorithm,
01435  * they are welcome to revert pbx to before 1 Apr 2008.
01436  * As an example, consider these 4 extensions:
01437  * (a) NXXNXXXXXX
01438  * (b) 307754XXXX
01439  * (c) fax
01440  * (d) NXXXXXXXXX
01441  *
01442  * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
01443  * most numbers. For all numbers beginning with 307754, (b) should always win.
01444  *
01445  * These pattern should form a (sorted) tree that looks like this:
01446  *   { "3" }  --next-->  { "0" }  --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
01447  *      |
01448  *      |alt
01449  *      |
01450  *   { "f" }  --next-->  { "a" }  --next--> { "x"  exten_match: (c) }
01451  *   { "N" }  --next-->  { "X" }  --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
01452  *      |                                                        |
01453  *      |                                                        |alt
01454  *      |alt                                                     |
01455  *      |                                                     { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
01456  *      |
01457  *     NULL
01458  *
01459  *   In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
01460  *   fewer CPU cycles than a call to strchr("23456789",*z), where *z is the char to match...
01461  *
01462  *   traversal is pretty simple: one routine merely traverses the alt list, and for each matching char in the pattern,  it calls itself
01463  *   on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
01464  *   We pass a pointer to a scoreboard down through, also.
01465  *   The scoreboard isn't as necessary to the revised algorithm, but I kept it as a handy way to return the matched extension.
01466  *   The first complete match ends the traversal, which should make this version of the pattern matcher faster
01467  *   the previous. The same goes for "CANMATCH" or "MATCHMORE"; the first such match ends the traversal. In both
01468  *   these cases, the reason we can stop immediately, is because the first pattern match found will be the "best"
01469  *   according to the sort criteria.
01470  *   Hope the limit on stack depth won't be a problem... this routine should
01471  *   be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
01472  *
01473  *   In the above example, with the number "3077549999" as the pattern, the traversor could match extensions a, b and d.  All are
01474  *   of length 10; they have total specificities of  24580, 10246, and 25090, respectively, not that this matters
01475  *   at all. (b) wins purely because the first character "3" is much more specific (lower specificity) than "N". I have
01476  *   left the specificity totals in the code as an artifact; at some point, I will strip it out.
01477  *
01478  *   Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown,
01479  *   because it's a function of how many extensions are stored in a context. With thousands of extensions, the speedup
01480  *   can be very noticeable. The new matching algorithm can run several hundreds of times faster, if not a thousand or
01481  *   more times faster in extreme cases.
01482  *
01483  *   MatchCID patterns are also supported, and stored in the tree just as the extension pattern is. Thus, you
01484  *   can have patterns in your CID field as well.
01485  *
01486  * */
01487 
01488 
01489 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)
01490 {
01491    /* if this extension is marked as deleted, then skip this -- if it never shows
01492       on the scoreboard, it will never be found, nor will halt the traversal. */
01493    if (deleted)
01494       return;
01495    board->total_specificity = spec;
01496    board->total_length = length;
01497    board->exten = exten;
01498    board->last_char = last;
01499    board->node = node;
01500 #ifdef NEED_DEBUG_HERE
01501    ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
01502 #endif
01503 }
01504 
01505 void log_match_char_tree(struct match_char *node, char *prefix)
01506 {
01507    char extenstr[40];
01508    struct ast_str *my_prefix = ast_str_alloca(1024);
01509 
01510    extenstr[0] = '\0';
01511 
01512    if (node && node->exten && node->exten)
01513       snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01514 
01515    if (strlen(node->x) > 1) {
01516       ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
01517          node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
01518          node->exten ? node->exten->exten : "", extenstr);
01519    } else {
01520       ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N',
01521          node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"",
01522          node->exten ? node->exten->exten : "", extenstr);
01523    }
01524 
01525    ast_str_set(&my_prefix, 0, "%s+       ", prefix);
01526 
01527    if (node->next_char)
01528       log_match_char_tree(node->next_char, ast_str_buffer(my_prefix));
01529 
01530    if (node->alt_char)
01531       log_match_char_tree(node->alt_char, prefix);
01532 }
01533 
01534 static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
01535 {
01536    char extenstr[40];
01537    struct ast_str *my_prefix = ast_str_alloca(1024);
01538 
01539    extenstr[0] = '\0';
01540 
01541    if (node && node->exten && node->exten)
01542       snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01543 
01544    if (strlen(node->x) > 1) {
01545       ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
01546          node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
01547          node->exten ? node->exten->exten : "", extenstr);
01548    } else {
01549       ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
01550          node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
01551          node->exten ? node->exten->exten : "", extenstr);
01552    }
01553 
01554    ast_str_set(&my_prefix, 0, "%s+       ", prefix);
01555 
01556    if (node->next_char)
01557       cli_match_char_tree(node->next_char, ast_str_buffer(my_prefix), fd);
01558 
01559    if (node->alt_char)
01560       cli_match_char_tree(node->alt_char, prefix, fd);
01561 }
01562 
01563 static struct ast_exten *get_canmatch_exten(struct match_char *node)
01564 {
01565    /* find the exten at the end of the rope */
01566    struct match_char *node2 = node;
01567 
01568    for (node2 = node; node2; node2 = node2->next_char) {
01569       if (node2->exten) {
01570 #ifdef NEED_DEBUG_HERE
01571          ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
01572 #endif
01573          return node2->exten;
01574       }
01575    }
01576 #ifdef NEED_DEBUG_HERE
01577    ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
01578 #endif
01579    return 0;
01580 }
01581 
01582 static struct ast_exten *trie_find_next_match(struct match_char *node)
01583 {
01584    struct match_char *m3;
01585    struct match_char *m4;
01586    struct ast_exten *e3;
01587 
01588    if (node && node->x[0] == '.' && !node->x[1]) { /* dot and ! will ALWAYS be next match in a matchmore */
01589       return node->exten;
01590    }
01591 
01592    if (node && node->x[0] == '!' && !node->x[1]) {
01593       return node->exten;
01594    }
01595 
01596    if (!node || !node->next_char) {
01597       return NULL;
01598    }
01599 
01600    m3 = node->next_char;
01601 
01602    if (m3->exten) {
01603       return m3->exten;
01604    }
01605    for (m4 = m3->alt_char; m4; m4 = m4->alt_char) {
01606       if (m4->exten) {
01607          return m4->exten;
01608       }
01609    }
01610    for (m4 = m3; m4; m4 = m4->alt_char) {
01611       e3 = trie_find_next_match(m3);
01612       if (e3) {
01613          return e3;
01614       }
01615    }
01616    return NULL;
01617 }
01618 
01619 #ifdef DEBUG_THIS
01620 static char *action2str(enum ext_match_t action)
01621 {
01622    switch (action) {
01623    case E_MATCH:
01624       return "MATCH";
01625    case E_CANMATCH:
01626       return "CANMATCH";
01627    case E_MATCHMORE:
01628       return "MATCHMORE";
01629    case E_FINDLABEL:
01630       return "FINDLABEL";
01631    case E_SPAWN:
01632       return "SPAWN";
01633    default:
01634       return "?ACTION?";
01635    }
01636 }
01637 
01638 #endif
01639 
01640 static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action)
01641 {
01642    struct match_char *p; /* note minimal stack storage requirements */
01643    struct ast_exten pattern = { .label = label };
01644 #ifdef DEBUG_THIS
01645    if (tree)
01646       ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
01647    else
01648       ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
01649 #endif
01650    for (p = tree; p; p = p->alt_char) {
01651       if (p->x[0] == 'N') {
01652          if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
01653 #define NEW_MATCHER_CHK_MATCH        \
01654             if (p->exten && !(*(str + 1))) { /* if a shorter pattern matches along the way, might as well report it */           \
01655                if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */   \
01656                   update_scoreboard(score, length + 1, spec + p->specificity, p->exten, 0, callerid, p->deleted, p);           \
01657                   if (!p->deleted) {                                                                                           \
01658                      if (action == E_FINDLABEL) {                                                                             \
01659                         if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) {                                  \
01660                            ast_debug(4, "Found label in preferred extension\n");                                            \
01661                            return;                                                                                          \
01662                         }                                                                                                    \
01663                      } else {                                                                                                 \
01664                         ast_debug(4,"returning an exact match-- first found-- %s\n", p->exten->exten);                       \
01665                         return; /* the first match, by definition, will be the best, because of the sorted tree */           \
01666                      }                                                                                                        \
01667                   }                                                                                                            \
01668                }                                                                                                                \
01669             }
01670 
01671 #define NEW_MATCHER_RECURSE              \
01672             if (p->next_char && ( *(str + 1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0)               \
01673                                                  || p->next_char->x[0] == '!')) {                                        \
01674                if (*(str + 1) || p->next_char->x[0] == '!') {                                                       \
01675                   new_find_extension(str + 1, score, p->next_char, length + 1, spec+p->specificity, callerid, label, action); \
01676                   if (score->exten)  {                                                                             \
01677                        ast_debug(4, "returning an exact match-- %s\n", score->exten->exten);                        \
01678                      return; /* the first match is all we need */                                                 \
01679                   }                                                                                    \
01680                } else {                                                                                             \
01681                   new_find_extension("/", score, p->next_char, length + 1, spec+p->specificity, callerid, label, action);   \
01682                   if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {      \
01683                        ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten :     \
01684                                        "NULL");                                                                          \
01685                      return; /* the first match is all we need */                                                 \
01686                   }                                                                                    \
01687                }                                                                                                    \
01688             } else if (p->next_char && !*(str + 1)) {                                                                \
01689                score->canmatch = 1;                                                                                 \
01690                score->canmatch_exten = get_canmatch_exten(p);                                                       \
01691                if (action == E_CANMATCH || action == E_MATCHMORE) {                                                 \
01692                     ast_debug(4, "returning a canmatch/matchmore--- str=%s\n", str);                                 \
01693                   return;                                                                                          \
01694                }                                                                                        \
01695             }
01696 
01697             NEW_MATCHER_CHK_MATCH;
01698             NEW_MATCHER_RECURSE;
01699          }
01700       } else if (p->x[0] == 'Z') {
01701          if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
01702             NEW_MATCHER_CHK_MATCH;
01703             NEW_MATCHER_RECURSE;
01704          }
01705       } else if (p->x[0] == 'X') {
01706          if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
01707             NEW_MATCHER_CHK_MATCH;
01708             NEW_MATCHER_RECURSE;
01709          }
01710       } else if (p->x[0] == '.' && p->x[1] == 0) {
01711          /* how many chars will the . match against? */
01712          int i = 0;
01713          const char *str2 = str;
01714          while (*str2 && *str2 != '/') {
01715             str2++;
01716             i++;
01717          }
01718          if (p->exten && *str2 != '/') {
01719             update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
01720             if (score->exten) {
01721                ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
01722                return; /* the first match is all we need */
01723             }
01724          }
01725          if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01726             new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid, label, action);
01727             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01728                ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
01729                return; /* the first match is all we need */
01730             }
01731          }
01732       } else if (p->x[0] == '!' && p->x[1] == 0) {
01733          /* how many chars will the . match against? */
01734          int i = 1;
01735          const char *str2 = str;
01736          while (*str2 && *str2 != '/') {
01737             str2++;
01738             i++;
01739          }
01740          if (p->exten && *str2 != '/') {
01741             update_scoreboard(score, length + 1, spec+(p->specificity * i), p->exten, '!', callerid, p->deleted, p);
01742             if (score->exten) {
01743                ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
01744                return; /* the first match is all we need */
01745             }
01746          }
01747          if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01748             new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
01749             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01750                ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
01751                return; /* the first match is all we need */
01752             }
01753          }
01754       } else if (p->x[0] == '/' && p->x[1] == 0) {
01755          /* the pattern in the tree includes the cid match! */
01756          if (p->next_char && callerid && *callerid) {
01757             new_find_extension(callerid, score, p->next_char, length+1, spec, callerid, label, action);
01758             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01759                ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
01760                return; /* the first match is all we need */
01761             }
01762          }
01763       } else if (strchr(p->x, *str)) {
01764          ast_debug(4, "Nothing strange about this match\n");
01765          NEW_MATCHER_CHK_MATCH;
01766          NEW_MATCHER_RECURSE;
01767       }
01768    }
01769    ast_debug(4, "return at end of func\n");
01770 }
01771 
01772 /* the algorithm for forming the extension pattern tree is also a bit simple; you
01773  * traverse all the extensions in a context, and for each char of the extension,
01774  * you see if it exists in the tree; if it doesn't, you add it at the appropriate
01775  * spot. What more can I say? At the end of each exten, you cap it off by adding the
01776  * address of the extension involved. Duplicate patterns will be complained about.
01777  *
01778  * Ideally, this would be done for each context after it is created and fully
01779  * filled. It could be done as a finishing step after extensions.conf or .ael is
01780  * loaded, or it could be done when the first search is encountered. It should only
01781  * have to be done once, until the next unload or reload.
01782  *
01783  * I guess forming this pattern tree would be analogous to compiling a regex. Except
01784  * that a regex only handles 1 pattern, really. This trie holds any number
01785  * of patterns. Well, really, it **could** be considered a single pattern,
01786  * where the "|" (or) operator is allowed, I guess, in a way, sort of...
01787  */
01788 
01789 static struct match_char *already_in_tree(struct match_char *current, char *pat)
01790 {
01791    struct match_char *t;
01792 
01793    if (!current) {
01794       return 0;
01795    }
01796 
01797    for (t = current; t; t = t->alt_char) {
01798       if (!strcmp(pat, t->x)) { /* uh, we may want to sort exploded [] contents to make matching easy */
01799          return t;
01800       }
01801    }
01802 
01803    return 0;
01804 }
01805 
01806 /* The first arg is the location of the tree ptr, or the
01807    address of the next_char ptr in the node, so we can mess
01808    with it, if we need to insert at the beginning of the list */
01809 
01810 static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
01811 {
01812    struct match_char *curr, *lcurr;
01813 
01814    /* insert node into the tree at "current", so the alt_char list from current is
01815       sorted in increasing value as you go to the leaves */
01816    if (!(*parent_ptr)) {
01817       *parent_ptr = node;
01818    } else {
01819       if ((*parent_ptr)->specificity > node->specificity) {
01820          /* insert at head */
01821          node->alt_char = (*parent_ptr);
01822          *parent_ptr = node;
01823       } else {
01824          lcurr = *parent_ptr;
01825          for (curr = (*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
01826             if (curr->specificity > node->specificity) {
01827                node->alt_char = curr;
01828                lcurr->alt_char = node;
01829                break;
01830             }
01831             lcurr = curr;
01832          }
01833          if (!curr) {
01834             lcurr->alt_char = node;
01835          }
01836       }
01837    }
01838 }
01839 
01840 
01841 
01842 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)
01843 {
01844    struct match_char *m;
01845 
01846    if (!(m = ast_calloc(1, sizeof(*m)))) {
01847       return NULL;
01848    }
01849 
01850    if (!(m->x = ast_strdup(pattern))) {
01851       ast_free(m);
01852       return NULL;
01853    }
01854 
01855    /* the specificity scores are the same as used in the old
01856       pattern matcher. */
01857    m->is_pattern = is_pattern;
01858    if (specificity == 1 && is_pattern && pattern[0] == 'N')
01859       m->specificity = 0x0832;
01860    else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
01861       m->specificity = 0x0931;
01862    else if (specificity == 1 && is_pattern && pattern[0] == 'X')
01863       m->specificity = 0x0a30;
01864    else if (specificity == 1 && is_pattern && pattern[0] == '.')
01865       m->specificity = 0x18000;
01866    else if (specificity == 1 && is_pattern && pattern[0] == '!')
01867       m->specificity = 0x28000;
01868    else
01869       m->specificity = specificity;
01870 
01871    if (!con->pattern_tree) {
01872       insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
01873    } else {
01874       if (already) { /* switch to the new regime (traversing vs appending)*/
01875          insert_in_next_chars_alt_char_list(nextcharptr, m);
01876       } else {
01877          insert_in_next_chars_alt_char_list(&current->next_char, m);
01878       }
01879    }
01880 
01881    return m;
01882 }
01883 
01884 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
01885 {
01886    struct match_char *m1 = NULL, *m2 = NULL, **m0;
01887    int specif;
01888    int already;
01889    int pattern = 0;
01890    char buf[256];
01891    char extenbuf[512];
01892    char *s1 = extenbuf;
01893    int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
01894 
01895 
01896    ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
01897 
01898    if (e1->matchcid &&  l1 <= sizeof(extenbuf)) {
01899       strcat(extenbuf, "/");
01900       strcat(extenbuf, e1->cidmatch);
01901    } else if (l1 > sizeof(extenbuf)) {
01902       ast_log(LOG_ERROR, "The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
01903       return 0;
01904    }
01905 #ifdef NEED_DEBUG
01906    ast_log(LOG_DEBUG, "Adding exten %s%c%s to tree\n", s1, e1->matchcid ? '/' : ' ', e1->matchcid ? e1->cidmatch : "");
01907 #endif
01908    m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
01909    m0 = &con->pattern_tree;
01910    already = 1;
01911 
01912    if ( *s1 == '_') {
01913       pattern = 1;
01914       s1++;
01915    }
01916    while( *s1 ) {
01917       if (pattern && *s1 == '[' && *(s1-1) != '\\') {
01918          char *s2 = buf;
01919          buf[0] = 0;
01920          s1++; /* get past the '[' */
01921          while (*s1 != ']' && *(s1 - 1) != '\\' ) {
01922             if (*s1 == '\\') {
01923                if (*(s1 + 1) == ']') {
01924                   *s2++ = ']';
01925                   s1++; s1++;
01926                } else if (*(s1 + 1) == '\\') {
01927                   *s2++ = '\\';
01928                   s1++; s1++;
01929                } else if (*(s1 + 1) == '-') {
01930                   *s2++ = '-';
01931                   s1++; s1++;
01932                } else if (*(s1 + 1) == '[') {
01933                   *s2++ = '[';
01934                   s1++; s1++;
01935                }
01936             } else if (*s1 == '-') { /* remember to add some error checking to all this! */
01937                char s3 = *(s1 - 1);
01938                char s4 = *(s1 + 1);
01939                for (s3++; s3 <= s4; s3++) {
01940                   *s2++ = s3;
01941                }
01942                s1++; s1++;
01943             } else if (*s1 == '\0') {
01944                ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
01945                break;
01946             } else {
01947                *s2++ = *s1++;
01948             }
01949          }
01950          *s2 = 0; /* null terminate the exploded range */
01951          /* sort the characters */
01952 
01953          specif = strlen(buf);
01954          qsort(buf, specif, 1, compare_char);
01955          specif <<= 8;
01956          specif += buf[0];
01957       } else if (*s1 == '-') {
01958          /* Skip dashes in patterns */
01959          s1++;
01960          continue;
01961       } else {
01962 
01963          if (*s1 == '\\') {
01964             s1++;
01965             buf[0] = *s1;
01966          } else {
01967             if (pattern) {
01968                if (*s1 == 'n') /* make sure n,x,z patterns are canonicalized to N,X,Z */
01969                   *s1 = 'N';
01970                else if (*s1 == 'x')
01971                   *s1 = 'X';
01972                else if (*s1 == 'z')
01973                   *s1 = 'Z';
01974             }
01975             buf[0] = *s1;
01976          }
01977          buf[1] = 0;
01978          specif = 1;
01979       }
01980       m2 = 0;
01981       if (already && (m2 = already_in_tree(m1,buf)) && m2->next_char) {
01982          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...
01983                           * a shorter pattern might win if the longer one doesn't match */
01984             m2->exten = e1;
01985             m2->deleted = 0;
01986          }
01987          m1 = m2->next_char; /* m1 points to the node to compare against */
01988          m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
01989       } else { /* not already OR not m2 OR nor m2->next_char */
01990          if (m2) {
01991             if (findonly) {
01992                return m2;
01993             }
01994             m1 = m2; /* while m0 stays the same */
01995          } else {
01996             if (findonly) {
01997                return m1;
01998             }
01999             m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0); /* m1 is the node just added */
02000             m0 = &m1->next_char;
02001          }
02002 
02003          if (!(*(s1 + 1))) {
02004             m1->deleted = 0;
02005             m1->exten = e1;
02006          }
02007 
02008          already = 0;
02009       }
02010       s1++; /* advance to next char */
02011    }
02012    return m1;
02013 }
02014 
02015 static void create_match_char_tree(struct ast_context *con)
02016 {
02017    struct ast_hashtab_iter *t1;
02018    struct ast_exten *e1;
02019 #ifdef NEED_DEBUG
02020    int biggest_bucket, resizes, numobjs, numbucks;
02021 
02022    ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
02023    ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
02024    ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
02025          numobjs, numbucks, biggest_bucket, resizes);
02026 #endif
02027    t1 = ast_hashtab_start_traversal(con->root_table);
02028    while ((e1 = ast_hashtab_next(t1))) {
02029       if (e1->exten) {
02030          add_exten_to_pattern_tree(con, e1, 0);
02031       } else {
02032          ast_log(LOG_ERROR, "Attempt to create extension with no extension name.\n");
02033       }
02034    }
02035    ast_hashtab_end_traversal(t1);
02036 }
02037 
02038 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! */
02039 {
02040    /* destroy all the alternates */
02041    if (pattern_tree->alt_char) {
02042       destroy_pattern_tree(pattern_tree->alt_char);
02043       pattern_tree->alt_char = 0;
02044    }
02045    /* destroy all the nexts */
02046    if (pattern_tree->next_char) {
02047       destroy_pattern_tree(pattern_tree->next_char);
02048       pattern_tree->next_char = 0;
02049    }
02050    pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
02051    if (pattern_tree->x) {
02052       free(pattern_tree->x);
02053    }
02054    free(pattern_tree);
02055 }
02056 
02057 /*
02058  * Special characters used in patterns:
02059  * '_'   underscore is the leading character of a pattern.
02060  *    In other position it is treated as a regular char.
02061  * .  one or more of any character. Only allowed at the end of
02062  *    a pattern.
02063  * !  zero or more of anything. Also impacts the result of CANMATCH
02064  *    and MATCHMORE. Only allowed at the end of a pattern.
02065  *    In the core routine, ! causes a match with a return code of 2.
02066  *    In turn, depending on the search mode: (XXX check if it is implemented)
02067  *    - E_MATCH retuns 1 (does match)
02068  *    - E_MATCHMORE returns 0 (no match)
02069  *    - E_CANMATCH returns 1 (does match)
02070  *
02071  * /  should not appear as it is considered the separator of the CID info.
02072  *    XXX at the moment we may stop on this char.
02073  *
02074  * X Z N match ranges 0-9, 1-9, 2-9 respectively.
02075  * [  denotes the start of a set of character. Everything inside
02076  *    is considered literally. We can have ranges a-d and individual
02077  *    characters. A '[' and '-' can be considered literally if they
02078  *    are just before ']'.
02079  *    XXX currently there is no way to specify ']' in a range, nor \ is
02080  *    considered specially.
02081  *
02082  * When we compare a pattern with a specific extension, all characters in the extension
02083  * itself are considered literally.
02084  * XXX do we want to consider space as a separator as well ?
02085  * XXX do we want to consider the separators in non-patterns as well ?
02086  */
02087 
02088 /*!
02089  * \brief helper functions to sort extensions and patterns in the desired way,
02090  * so that more specific patterns appear first.
02091  *
02092  * ext_cmp1 compares individual characters (or sets of), returning
02093  * an int where bits 0-7 are the ASCII code of the first char in the set,
02094  * while bit 8-15 are the cardinality of the set minus 1.
02095  * This way more specific patterns (smaller cardinality) appear first.
02096  * Wildcards have a special value, so that we can directly compare them to
02097  * sets by subtracting the two values. In particular:
02098  *  0x000xx    one character, xx
02099  *  0x0yyxx    yy character set starting with xx
02100  *  0x10000    '.' (one or more of anything)
02101  *  0x20000    '!' (zero or more of anything)
02102  *  0x30000    NUL (end of string)
02103  *  0x40000    error in set.
02104  * The pointer to the string is advanced according to needs.
02105  * NOTES:
02106  * 1. the empty set is equivalent to NUL.
02107  * 2. given that a full set has always 0 as the first element,
02108  *    we could encode the special cases as 0xffXX where XX
02109  *    is 1, 2, 3, 4 as used above.
02110  */
02111 static int ext_cmp1(const char **p, unsigned char *bitwise)
02112 {
02113    int c, cmin = 0xff, count = 0;
02114    const char *end;
02115 
02116    /* load value and advance pointer */
02117    c = *(*p)++;
02118 
02119    /* always return unless we have a set of chars */
02120    switch (toupper(c)) {
02121    default: /* ordinary character */
02122       bitwise[c / 8] = 1 << (c % 8);
02123       return 0x0100 | (c & 0xff);
02124 
02125    case 'N':   /* 2..9 */
02126       bitwise[6] = 0xfc;
02127       bitwise[7] = 0x03;
02128       return 0x0800 | '2';
02129 
02130    case 'X':   /* 0..9 */
02131       bitwise[6] = 0xff;
02132       bitwise[7] = 0x03;
02133       return 0x0A00 | '0';
02134 
02135    case 'Z':   /* 1..9 */
02136       bitwise[6] = 0xfe;
02137       bitwise[7] = 0x03;
02138       return 0x0900 | '1';
02139 
02140    case '.':   /* wildcard */
02141       return 0x18000;
02142 
02143    case '!':   /* earlymatch */
02144       return 0x28000;   /* less specific than NULL */
02145 
02146    case '\0':  /* empty string */
02147       *p = NULL;
02148       return 0x30000;
02149 
02150    case '[':   /* pattern */
02151       break;
02152    }
02153    /* locate end of set */
02154    end = strchr(*p, ']');
02155 
02156    if (end == NULL) {
02157       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
02158       return 0x40000;   /* XXX make this entry go last... */
02159    }
02160 
02161    for (; *p < end  ; (*p)++) {
02162       unsigned char c1, c2;   /* first-last char in range */
02163       c1 = (unsigned char)((*p)[0]);
02164       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
02165          c2 = (unsigned char)((*p)[2]);
02166          *p += 2;    /* skip a total of 3 chars */
02167       } else {        /* individual character */
02168          c2 = c1;
02169       }
02170       if (c1 < cmin) {
02171          cmin = c1;
02172       }
02173       for (; c1 <= c2; c1++) {
02174          unsigned char mask = 1 << (c1 % 8);
02175          /*!\note If two patterns score the same, the one with the lowest
02176           * ascii values will compare as coming first. */
02177          /* Flag the character as included (used) and count it. */
02178          if (!(bitwise[ c1 / 8 ] & mask)) {
02179             bitwise[ c1 / 8 ] |= mask;
02180             count += 0x100;
02181          }
02182       }
02183    }
02184    (*p)++;
02185    return count == 0 ? 0x30000 : (count | cmin);
02186 }
02187 
02188 /*!
02189  * \brief the full routine to compare extensions in rules.
02190  */
02191 static int ext_cmp(const char *a, const char *b)
02192 {
02193    /* make sure non-patterns come first.
02194     * If a is not a pattern, it either comes first or
02195     * we do a more complex pattern comparison.
02196     */
02197    int ret = 0;
02198 
02199    if (a[0] != '_')
02200       return (b[0] == '_') ? -1 : strcmp(a, b);
02201 
02202    /* Now we know a is a pattern; if b is not, a comes first */
02203    if (b[0] != '_')
02204       return 1;
02205 
02206    /* ok we need full pattern sorting routine.
02207     * skip past the underscores */
02208    ++a; ++b;
02209    do {
02210       unsigned char bitwise[2][32] = { { 0, } };
02211       ret = ext_cmp1(&a, bitwise[0]) - ext_cmp1(&b, bitwise[1]);
02212       if (ret == 0) {
02213          /* Are the classes different, even though they score the same? */
02214          ret = memcmp(bitwise[0], bitwise[1], 32);
02215       }
02216    } while (!ret && a && b);
02217    if (ret == 0) {
02218       return 0;
02219    } else {
02220       return (ret > 0) ? 1 : -1;
02221    }
02222 }
02223 
02224 int ast_extension_cmp(const char *a, const char *b)
02225 {
02226    return ext_cmp(a, b);
02227 }
02228 
02229 /*!
02230  * \internal
02231  * \brief used ast_extension_{match|close}
02232  * mode is as follows:
02233  * E_MATCH     success only on exact match
02234  * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
02235  * E_CANMATCH  either of the above.
02236  * \retval 0 on no-match
02237  * \retval 1 on match
02238  * \retval 2 on early match.
02239  */
02240 
02241 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
02242 {
02243    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
02244 
02245 #ifdef NEED_DEBUG_HERE
02246    ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
02247 #endif
02248 
02249    if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */
02250 #ifdef NEED_DEBUG_HERE
02251       ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
02252 #endif
02253       return 1;
02254    }
02255 
02256    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
02257       int ld = strlen(data), lp = strlen(pattern);
02258 
02259       if (lp < ld) {    /* pattern too short, cannot match */
02260 #ifdef NEED_DEBUG_HERE
02261          ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
02262 #endif
02263          return 0;
02264       }
02265       /* depending on the mode, accept full or partial match or both */
02266       if (mode == E_MATCH) {
02267 #ifdef NEED_DEBUG_HERE
02268          ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
02269 #endif
02270          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
02271       }
02272       if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */
02273 #ifdef NEED_DEBUG_HERE
02274          ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
02275 #endif
02276          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
02277       } else {
02278 #ifdef NEED_DEBUG_HERE
02279          ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
02280 #endif
02281          return 0;
02282       }
02283    }
02284    pattern++; /* skip leading _ */
02285    /*
02286     * XXX below we stop at '/' which is a separator for the CID info. However we should
02287     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
02288     */
02289    while (*data && *pattern && *pattern != '/') {
02290       const char *end;
02291 
02292       if (*data == '-') { /* skip '-' in data (just a separator) */
02293          data++;
02294          continue;
02295       }
02296       switch (toupper(*pattern)) {
02297       case '[':   /* a range */
02298          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
02299          if (end == NULL) {
02300             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
02301             return 0;   /* unconditional failure */
02302          }
02303          for (pattern++; pattern != end; pattern++) {
02304             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
02305                if (*data >= pattern[0] && *data <= pattern[2])
02306                   break;   /* match found */
02307                else {
02308                   pattern += 2; /* skip a total of 3 chars */
02309                   continue;
02310                }
02311             } else if (*data == pattern[0])
02312                break;   /* match found */
02313          }
02314          if (pattern == end) {
02315 #ifdef NEED_DEBUG_HERE
02316             ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
02317 #endif
02318             return 0;
02319          }
02320          pattern = end; /* skip and continue */
02321          break;
02322       case 'N':
02323          if (*data < '2' || *data > '9') {
02324 #ifdef NEED_DEBUG_HERE
02325             ast_log(LOG_NOTICE,"return (0) N is matched\n");
02326 #endif
02327             return 0;
02328          }
02329          break;
02330       case 'X':
02331          if (*data < '0' || *data > '9') {
02332 #ifdef NEED_DEBUG_HERE
02333             ast_log(LOG_NOTICE,"return (0) X is matched\n");
02334 #endif
02335             return 0;
02336          }
02337          break;
02338       case 'Z':
02339          if (*data < '1' || *data > '9') {
02340 #ifdef NEED_DEBUG_HERE
02341             ast_log(LOG_NOTICE,"return (0) Z is matched\n");
02342 #endif
02343             return 0;
02344          }
02345          break;
02346       case '.':   /* Must match, even with more digits */
02347 #ifdef NEED_DEBUG_HERE
02348          ast_log(LOG_NOTICE, "return (1) when '.' is matched\n");
02349 #endif
02350          return 1;
02351       case '!':   /* Early match */
02352 #ifdef NEED_DEBUG_HERE
02353          ast_log(LOG_NOTICE, "return (2) when '!' is matched\n");
02354 #endif
02355          return 2;
02356       case ' ':
02357       case '-':   /* Ignore these in patterns */
02358          data--; /* compensate the final data++ */
02359          break;
02360       default:
02361          if (*data != *pattern) {
02362 #ifdef NEED_DEBUG_HERE
02363             ast_log(LOG_NOTICE, "return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
02364 #endif
02365             return 0;
02366          }
02367       }
02368       data++;
02369       pattern++;
02370    }
02371    if (*data)        /* data longer than pattern, no match */ {
02372 #ifdef NEED_DEBUG_HERE
02373       ast_log(LOG_NOTICE, "return (0) when data longer than pattern\n");
02374 #endif
02375       return 0;
02376    }
02377 
02378    /*
02379     * match so far, but ran off the end of the data.
02380     * Depending on what is next, determine match or not.
02381     */
02382    if (*pattern == '\0' || *pattern == '/') {   /* exact match */
02383 #ifdef NEED_DEBUG_HERE
02384       ast_log(LOG_NOTICE, "at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
02385 #endif
02386       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
02387    } else if (*pattern == '!')   {     /* early match */
02388 #ifdef NEED_DEBUG_HERE
02389       ast_log(LOG_NOTICE, "at end, return (2) when '!' is matched\n");
02390 #endif
02391       return 2;
02392    } else {                /* partial match */
02393 #ifdef NEED_DEBUG_HERE
02394       ast_log(LOG_NOTICE, "at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
02395 #endif
02396       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
02397    }
02398 }
02399 
02400 /*
02401  * Wrapper around _extension_match_core() to do performance measurement
02402  * using the profiling code.
02403  */
02404 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
02405 {
02406    int i;
02407    static int prof_id = -2;   /* marker for 'unallocated' id */
02408    if (prof_id == -2) {
02409       prof_id = ast_add_profile("ext_match", 0);
02410    }
02411    ast_mark(prof_id, 1);
02412    i = _extension_match_core(pattern, data, mode);
02413    ast_mark(prof_id, 0);
02414    return i;
02415 }
02416 
02417 int ast_extension_match(const char *pattern, const char *data)
02418 {
02419    return extension_match_core(pattern, data, E_MATCH);
02420 }
02421 
02422 int ast_extension_close(const char *pattern, const char *data, int needmore)
02423 {
02424    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
02425       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
02426    return extension_match_core(pattern, data, needmore);
02427 }
02428 
02429 struct fake_context /* this struct is purely for matching in the hashtab */
02430 {
02431    ast_rwlock_t lock;
02432    struct ast_exten *root;
02433    struct ast_hashtab *root_table;
02434    struct match_char *pattern_tree;
02435    struct ast_context *next;
02436    struct ast_include *includes;
02437    struct ast_ignorepat *ignorepats;
02438    const char *registrar;
02439    int refcount;
02440    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
02441    ast_mutex_t macrolock;
02442    char name[256];
02443 };
02444 
02445 struct ast_context *ast_context_find(const char *name)
02446 {
02447    struct ast_context *tmp = NULL;
02448    struct fake_context item;
02449 
02450    ast_copy_string(item.name, name, sizeof(item.name));
02451 
02452    ast_rdlock_contexts();
02453    if( contexts_table ) {
02454       tmp = ast_hashtab_lookup(contexts_table,&item);
02455    } else {
02456       while ( (tmp = ast_walk_contexts(tmp)) ) {
02457          if (!name || !strcasecmp(name, tmp->name)) {
02458             break;
02459          }
02460       }
02461    }
02462    ast_unlock_contexts();
02463    return tmp;
02464 }
02465 
02466 #define STATUS_NO_CONTEXT  1
02467 #define STATUS_NO_EXTENSION   2
02468 #define STATUS_NO_PRIORITY 3
02469 #define STATUS_NO_LABEL    4
02470 #define STATUS_SUCCESS     5
02471 
02472 static int matchcid(const char *cidpattern, const char *callerid)
02473 {
02474    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
02475       failing to get a number should count as a match, otherwise not */
02476 
02477    if (ast_strlen_zero(callerid)) {
02478       return ast_strlen_zero(cidpattern) ? 1 : 0;
02479    }
02480 
02481    return ast_extension_match(cidpattern, callerid);
02482 }
02483 
02484 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
02485    struct ast_context *bypass, struct pbx_find_info *q,
02486    const char *context, const char *exten, int priority,
02487    const char *label, const char *callerid, enum ext_match_t action)
02488 {
02489    int x, res;
02490    struct ast_context *tmp = NULL;
02491    struct ast_exten *e = NULL, *eroot = NULL;
02492    struct ast_include *i = NULL;
02493    struct ast_sw *sw = NULL;
02494    struct ast_exten pattern = {NULL, };
02495    struct scoreboard score = {0, };
02496    struct ast_str *tmpdata = NULL;
02497 
02498    pattern.label = label;
02499    pattern.priority = priority;
02500 #ifdef NEED_DEBUG_HERE
02501    ast_log(LOG_NOTICE, "Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int) action);
02502 #endif
02503 
02504    /* Initialize status if appropriate */
02505    if (q->stacklen == 0) {
02506       q->status = STATUS_NO_CONTEXT;
02507       q->swo = NULL;
02508       q->data = NULL;
02509       q->foundcontext = NULL;
02510    } else if (q->stacklen >= AST_PBX_MAX_STACK) {
02511       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
02512       return NULL;
02513    }
02514 
02515    /* Check first to see if we've already been checked */
02516    for (x = 0; x < q->stacklen; x++) {
02517       if (!strcasecmp(q->incstack[x], context))
02518          return NULL;
02519    }
02520 
02521    if (bypass) { /* bypass means we only look there */
02522       tmp = bypass;
02523    } else {      /* look in contexts */
02524       struct fake_context item;
02525 
02526       ast_copy_string(item.name, context, sizeof(item.name));
02527 
02528       tmp = ast_hashtab_lookup(contexts_table, &item);
02529 #ifdef NOTNOW
02530       tmp = NULL;
02531       while ((tmp = ast_walk_contexts(tmp)) ) {
02532          if (!strcmp(tmp->name, context)) {
02533             break;
02534          }
02535       }
02536 #endif
02537       if (!tmp) {
02538          return NULL;
02539       }
02540    }
02541 
02542    if (q->status < STATUS_NO_EXTENSION)
02543       q->status = STATUS_NO_EXTENSION;
02544 
02545    /* Do a search for matching extension */
02546 
02547    eroot = NULL;
02548    score.total_specificity = 0;
02549    score.exten = 0;
02550    score.total_length = 0;
02551    if (!tmp->pattern_tree && tmp->root_table) {
02552       create_match_char_tree(tmp);
02553 #ifdef NEED_DEBUG
02554       ast_log(LOG_DEBUG, "Tree Created in context %s:\n", context);
02555       log_match_char_tree(tmp->pattern_tree," ");
02556 #endif
02557    }
02558 #ifdef NEED_DEBUG
02559    ast_log(LOG_NOTICE, "The Trie we are searching in:\n");
02560    log_match_char_tree(tmp->pattern_tree, "::  ");
02561 #endif
02562 
02563    do {
02564       if (!ast_strlen_zero(overrideswitch)) {
02565          char *osw = ast_strdupa(overrideswitch), *name;
02566          struct ast_switch *asw;
02567          ast_switch_f *aswf = NULL;
02568          char *datap;
02569          int eval = 0;
02570 
02571          name = strsep(&osw, "/");
02572          asw = pbx_findswitch(name);
02573 
02574          if (!asw) {
02575             ast_log(LOG_WARNING, "No such switch '%s'\n", name);
02576             break;
02577          }
02578 
02579          if (osw && strchr(osw, '$')) {
02580             eval = 1;
02581          }
02582 
02583          if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02584             ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!");
02585             break;
02586          } else if (eval) {
02587             /* Substitute variables now */
02588             pbx_substitute_variables_helper(chan, osw, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
02589             datap = ast_str_buffer(tmpdata);
02590          } else {
02591             datap = osw;
02592          }
02593 
02594          /* equivalent of extension_match_core() at the switch level */
02595          if (action == E_CANMATCH)
02596             aswf = asw->canmatch;
02597          else if (action == E_MATCHMORE)
02598             aswf = asw->matchmore;
02599          else /* action == E_MATCH */
02600             aswf = asw->exists;
02601          if (!aswf) {
02602             res = 0;
02603          } else {
02604             if (chan) {
02605                ast_autoservice_start(chan);
02606             }
02607             res = aswf(chan, context, exten, priority, callerid, datap);
02608             if (chan) {
02609                ast_autoservice_stop(chan);
02610             }
02611          }
02612          if (res) {  /* Got a match */
02613             q->swo = asw;
02614             q->data = datap;
02615             q->foundcontext = context;
02616             /* XXX keep status = STATUS_NO_CONTEXT ? */
02617             return NULL;
02618          }
02619       }
02620    } while (0);
02621 
02622    if (extenpatternmatchnew) {
02623       new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
02624       eroot = score.exten;
02625 
02626       if (score.last_char == '!' && action == E_MATCHMORE) {
02627          /* We match an extension ending in '!'.
02628           * The decision in this case is final and is NULL (no match).
02629           */
02630 #ifdef NEED_DEBUG_HERE
02631          ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
02632 #endif
02633          return NULL;
02634       }
02635 
02636       if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
02637          q->status = STATUS_SUCCESS;
02638 #ifdef NEED_DEBUG_HERE
02639          ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
02640 #endif
02641          return score.canmatch_exten;
02642       }
02643 
02644       if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
02645          if (score.node) {
02646             struct ast_exten *z = trie_find_next_match(score.node);
02647             if (z) {
02648 #ifdef NEED_DEBUG_HERE
02649                ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
02650 #endif
02651             } else {
02652                if (score.canmatch_exten) {
02653 #ifdef NEED_DEBUG_HERE
02654                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
02655 #endif
02656                   return score.canmatch_exten;
02657                } else {
02658 #ifdef NEED_DEBUG_HERE
02659                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
02660 #endif
02661                }
02662             }
02663             return z;
02664          }
02665 #ifdef NEED_DEBUG_HERE
02666          ast_log(LOG_NOTICE, "Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
02667 #endif
02668          return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
02669       }
02670 
02671       if (eroot) {
02672          /* found entry, now look for the right priority */
02673          if (q->status < STATUS_NO_PRIORITY)
02674             q->status = STATUS_NO_PRIORITY;
02675          e = NULL;
02676          if (action == E_FINDLABEL && label ) {
02677             if (q->status < STATUS_NO_LABEL)
02678                q->status = STATUS_NO_LABEL;
02679             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02680          } else {
02681             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02682          }
02683          if (e) { /* found a valid match */
02684             q->status = STATUS_SUCCESS;
02685             q->foundcontext = context;
02686 #ifdef NEED_DEBUG_HERE
02687             ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
02688 #endif
02689             return e;
02690          }
02691       }
02692    } else {   /* the old/current default exten pattern match algorithm */
02693 
02694       /* scan the list trying to match extension and CID */
02695       eroot = NULL;
02696       while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
02697          int match = extension_match_core(eroot->exten, exten, action);
02698          /* 0 on fail, 1 on match, 2 on earlymatch */
02699 
02700          if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
02701             continue;   /* keep trying */
02702          if (match == 2 && action == E_MATCHMORE) {
02703             /* We match an extension ending in '!'.
02704              * The decision in this case is final and is NULL (no match).
02705              */
02706             return NULL;
02707          }
02708          /* found entry, now look for the right priority */
02709          if (q->status < STATUS_NO_PRIORITY)
02710             q->status = STATUS_NO_PRIORITY;
02711          e = NULL;
02712          if (action == E_FINDLABEL && label ) {
02713             if (q->status < STATUS_NO_LABEL)
02714                q->status = STATUS_NO_LABEL;
02715             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02716          } else {
02717             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02718          }
02719 #ifdef NOTNOW
02720          while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
02721             /* Match label or priority */
02722             if (action == E_FINDLABEL) {
02723                if (q->status < STATUS_NO_LABEL)
02724                   q->status = STATUS_NO_LABEL;
02725                if (label && e->label && !strcmp(label, e->label))
02726                   break;   /* found it */
02727             } else if (e->priority == priority) {
02728                break;   /* found it */
02729             } /* else keep searching */
02730          }
02731 #endif
02732          if (e) { /* found a valid match */
02733             q->status = STATUS_SUCCESS;
02734             q->foundcontext = context;
02735             return e;
02736          }
02737       }
02738    }
02739 
02740    /* Check alternative switches */
02741    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
02742       struct ast_switch *asw = pbx_findswitch(sw->name);
02743       ast_switch_f *aswf = NULL;
02744       char *datap;
02745 
02746       if (!asw) {
02747          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
02748          continue;
02749       }
02750 
02751       /* Substitute variables now */
02752       if (sw->eval) {
02753          if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02754             ast_log(LOG_WARNING, "Can't evaluate switch?!");
02755             continue;
02756          }
02757          pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
02758       }
02759 
02760       /* equivalent of extension_match_core() at the switch level */
02761       if (action == E_CANMATCH)
02762          aswf = asw->canmatch;
02763       else if (action == E_MATCHMORE)
02764          aswf = asw->matchmore;
02765       else /* action == E_MATCH */
02766          aswf = asw->exists;
02767       datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
02768       if (!aswf)
02769          res = 0;
02770       else {
02771          if (chan)
02772             ast_autoservice_start(chan);
02773          res = aswf(chan, context, exten, priority, callerid, datap);
02774          if (chan)
02775             ast_autoservice_stop(chan);
02776       }
02777       if (res) {  /* Got a match */
02778          q->swo = asw;
02779          q->data = datap;
02780          q->foundcontext = context;
02781          /* XXX keep status = STATUS_NO_CONTEXT ? */
02782          return NULL;
02783       }
02784    }
02785    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
02786    /* Now try any includes we have in this context */
02787    for (i = tmp->includes; i; i = i->next) {
02788       if (include_valid(i)) {
02789          if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
02790 #ifdef NEED_DEBUG_HERE
02791             ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
02792 #endif
02793             return e;
02794          }
02795          if (q->swo)
02796             return NULL;
02797       }
02798    }
02799    return NULL;
02800 }
02801 
02802 /*!
02803  * \brief extract offset:length from variable name.
02804  * \return 1 if there is a offset:length part, which is
02805  * trimmed off (values go into variables)
02806  */
02807 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
02808 {
02809    int parens = 0;
02810 
02811    *offset = 0;
02812    *length = INT_MAX;
02813    *isfunc = 0;
02814    for (; *var; var++) {
02815       if (*var == '(') {
02816          (*isfunc)++;
02817          parens++;
02818       } else if (*var == ')') {
02819          parens--;
02820       } else if (*var == ':' && parens == 0) {
02821          *var++ = '\0';
02822          sscanf(var, "%30d:%30d", offset, length);
02823          return 1; /* offset:length valid */
02824       }
02825    }
02826    return 0;
02827 }
02828 
02829 /*!
02830  *\brief takes a substring. It is ok to call with value == workspace.
02831  * \param value
02832  * \param offset < 0 means start from the end of the string and set the beginning
02833  *   to be that many characters back.
02834  * \param length is the length of the substring, a value less than 0 means to leave
02835  * that many off the end.
02836  * \param workspace
02837  * \param workspace_len
02838  * Always return a copy in workspace.
02839  */
02840 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
02841 {
02842    char *ret = workspace;
02843    int lr;  /* length of the input string after the copy */
02844 
02845    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
02846 
02847    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
02848 
02849    /* Quick check if no need to do anything */
02850    if (offset == 0 && length >= lr) /* take the whole string */
02851       return ret;
02852 
02853    if (offset < 0)   {  /* translate negative offset into positive ones */
02854       offset = lr + offset;
02855       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
02856          offset = 0;
02857    }
02858 
02859    /* too large offset result in empty string so we know what to return */
02860    if (offset >= lr)
02861       return ret + lr;  /* the final '\0' */
02862 
02863    ret += offset;    /* move to the start position */
02864    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
02865       ret[length] = '\0';
02866    else if (length < 0) {
02867       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
02868          ret[lr + length - offset] = '\0';
02869       else
02870          ret[0] = '\0';
02871    }
02872 
02873    return ret;
02874 }
02875 
02876 /*! \brief  Support for Asterisk built-in variables in the dialplan
02877 
02878 \note See also
02879    - \ref AstVar  Channel variables
02880    - \ref AstCauses The HANGUPCAUSE variable
02881  */
02882 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
02883 {
02884    const char not_found = '\0';
02885    char *tmpvar;
02886    const char *s; /* the result */
02887    int offset, length;
02888    int i, need_substring;
02889    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
02890 
02891    if (c) {
02892       ast_channel_lock(c);
02893       places[0] = &c->varshead;
02894    }
02895    /*
02896     * Make a copy of var because parse_variable_name() modifies the string.
02897     * Then if called directly, we might need to run substring() on the result;
02898     * remember this for later in 'need_substring', 'offset' and 'length'
02899     */
02900    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
02901    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
02902 
02903    /*
02904     * Look first into predefined variables, then into variable lists.
02905     * Variable 's' points to the result, according to the following rules:
02906     * s == &not_found (set at the beginning) means that we did not find a
02907     * matching variable and need to look into more places.
02908     * If s != &not_found, s is a valid result string as follows:
02909     * s = NULL if the variable does not have a value;
02910     * you typically do this when looking for an unset predefined variable.
02911     * s = workspace if the result has been assembled there;
02912     * typically done when the result is built e.g. with an snprintf(),
02913     * so we don't need to do an additional copy.
02914     * s != workspace in case we have a string, that needs to be copied
02915     * (the ast_copy_string is done once for all at the end).
02916     * Typically done when the result is already available in some string.
02917     */
02918    s = &not_found;   /* default value */
02919    if (c) { /* This group requires a valid channel */
02920       /* Names with common parts are looked up a piece at a time using strncmp. */
02921       if (!strncmp(var, "CALL", 4)) {
02922          if (!strncmp(var + 4, "ING", 3)) {
02923             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
02924                snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
02925                s = workspace;
02926             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
02927                snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
02928                s = workspace;
02929             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
02930                snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
02931                s = workspace;
02932             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
02933                snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
02934                s = workspace;
02935             }
02936          }
02937       } else if (!strcmp(var, "HINT")) {
02938          s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
02939       } else if (!strcmp(var, "HINTNAME")) {
02940          s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
02941       } else if (!strcmp(var, "EXTEN")) {
02942          s = c->exten;
02943       } else if (!strcmp(var, "CONTEXT")) {
02944          s = c->context;
02945       } else if (!strcmp(var, "PRIORITY")) {
02946          snprintf(workspace, workspacelen, "%d", c->priority);
02947          s = workspace;
02948       } else if (!strcmp(var, "CHANNEL")) {
02949          s = c->name;
02950       } else if (!strcmp(var, "UNIQUEID")) {
02951          s = c->uniqueid;
02952       } else if (!strcmp(var, "HANGUPCAUSE")) {
02953          snprintf(workspace, workspacelen, "%d", c->hangupcause);
02954          s = workspace;
02955       }
02956    }
02957    if (s == &not_found) { /* look for more */
02958       if (!strcmp(var, "EPOCH")) {
02959          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
02960          s = workspace;
02961       } else if (!strcmp(var, "SYSTEMNAME")) {
02962          s = ast_config_AST_SYSTEM_NAME;
02963       } else if (!strcmp(var, "ENTITYID")) {
02964          ast_eid_to_str(workspace, workspacelen, &ast_eid_default);
02965          s = workspace;
02966       }
02967    }
02968    /* if not found, look into chanvars or global vars */
02969    for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
02970       struct ast_var_t *variables;
02971       if (!places[i])
02972          continue;
02973       if (places[i] == &globals)
02974          ast_rwlock_rdlock(&globalslock);
02975       AST_LIST_TRAVERSE(places[i], variables, entries) {
02976          if (!strcasecmp(ast_var_name(variables), var)) {
02977             s = ast_var_value(variables);
02978             break;
02979          }
02980       }
02981       if (places[i] == &globals)
02982          ast_rwlock_unlock(&globalslock);
02983    }
02984    if (s == &not_found || s == NULL)
02985       *ret = NULL;
02986    else {
02987       if (s != workspace)
02988          ast_copy_string(workspace, s, workspacelen);
02989       *ret = workspace;
02990       if (need_substring)
02991          *ret = substring(*ret, offset, length, workspace, workspacelen);
02992    }
02993 
02994    if (c)
02995       ast_channel_unlock(c);
02996 }
02997 
02998 static void exception_store_free(void *data)
02999 {
03000    struct pbx_exception *exception = data;
03001    ast_string_field_free_memory(exception);
03002    ast_free(exception);
03003 }
03004 
03005 static struct ast_datastore_info exception_store_info = {
03006    .type = "EXCEPTION",
03007    .destroy = exception_store_free,
03008 };
03009 
03010 int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
03011 {
03012    const char *reason = vreason;
03013    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
03014    struct pbx_exception *exception = NULL;
03015 
03016    if (!ds) {
03017       ds = ast_datastore_alloc(&exception_store_info, NULL);
03018       if (!ds)
03019          return -1;
03020       exception = ast_calloc(1, sizeof(struct pbx_exception));
03021       if (!exception) {
03022          ast_datastore_free(ds);
03023          return -1;
03024       }
03025       if (ast_string_field_init(exception, 128)) {
03026          ast_free(exception);
03027          ast_datastore_free(ds);
03028          return -1;
03029       }
03030       ds->data = exception;
03031       ast_channel_datastore_add(chan, ds);
03032    } else
03033       exception = ds->data;
03034 
03035    ast_string_field_set(exception, reason, reason);
03036    ast_string_field_set(exception, context, chan->context);
03037    ast_string_field_set(exception, exten, chan->exten);
03038    exception->priority = chan->priority;
03039    set_ext_pri(chan, "e", 0);
03040    return 0;
03041 }
03042 
03043 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
03044 {
03045    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
03046    struct pbx_exception *exception = NULL;
03047    if (!ds || !ds->data)
03048       return -1;
03049    exception = ds->data;
03050    if (!strcasecmp(data, "REASON"))
03051       ast_copy_string(buf, exception->reason, buflen);
03052    else if (!strcasecmp(data, "CONTEXT"))
03053       ast_copy_string(buf, exception->context, buflen);
03054    else if (!strncasecmp(data, "EXTEN", 5))
03055       ast_copy_string(buf, exception->exten, buflen);
03056    else if (!strcasecmp(data, "PRIORITY"))
03057       snprintf(buf, buflen, "%d", exception->priority);
03058    else
03059       return -1;
03060    return 0;
03061 }
03062 
03063 static struct ast_custom_function exception_function = {
03064    .name = "EXCEPTION",
03065    .read = acf_exception_read,
03066 };
03067 
03068 static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03069 {
03070    struct ast_custom_function *acf;
03071    int count_acf = 0;
03072    int like = 0;
03073 
03074    switch (cmd) {
03075    case CLI_INIT:
03076       e->command = "core show functions [like]";
03077       e->usage =
03078          "Usage: core show functions [like <text>]\n"
03079          "       List builtin functions, optionally only those matching a given string\n";
03080       return NULL;
03081    case CLI_GENERATE:
03082       return NULL;
03083    }
03084 
03085    if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
03086       like = 1;
03087    } else if (a->argc != 3) {
03088       return CLI_SHOWUSAGE;
03089    }
03090 
03091    ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
03092 
03093    AST_RWLIST_RDLOCK(&acf_root);
03094    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03095       if (!like || strstr(acf->name, a->argv[4])) {
03096          count_acf++;
03097          ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n",
03098             S_OR(acf->name, ""),
03099             S_OR(acf->syntax, ""),
03100             S_OR(acf->synopsis, ""));
03101       }
03102    }
03103    AST_RWLIST_UNLOCK(&acf_root);
03104 
03105    ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
03106 
03107    return CLI_SUCCESS;
03108 }
03109 
03110 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03111 {
03112    struct ast_custom_function *acf;
03113    /* Maximum number of characters added by terminal coloring is 22 */
03114    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], argtitle[40], seealsotitle[40];
03115    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *seealso = NULL;
03116    char stxtitle[40], *syntax = NULL, *arguments = NULL;
03117    int syntax_size, description_size, synopsis_size, arguments_size, seealso_size;
03118    char *ret = NULL;
03119    int which = 0;
03120    int wordlen;
03121 
03122    switch (cmd) {
03123    case CLI_INIT:
03124       e->command = "core show function";
03125       e->usage =
03126          "Usage: core show function <function>\n"
03127          "       Describe a particular dialplan function.\n";
03128       return NULL;
03129    case CLI_GENERATE:
03130       wordlen = strlen(a->word);
03131       /* case-insensitive for convenience in this 'complete' function */
03132       AST_RWLIST_RDLOCK(&acf_root);
03133       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03134          if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
03135             ret = ast_strdup(acf->name);
03136             break;
03137          }
03138       }
03139       AST_RWLIST_UNLOCK(&acf_root);
03140 
03141       return ret;
03142    }
03143 
03144    if (a->argc < 4) {
03145       return CLI_SHOWUSAGE;
03146    }
03147 
03148    if (!(acf = ast_custom_function_find(a->argv[3]))) {
03149       ast_cli(a->fd, "No function by that name registered.\n");
03150       return CLI_FAILURE;
03151    }
03152 
03153    syntax_size = strlen(S_OR(acf->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03154    if (!(syntax = ast_malloc(syntax_size))) {
03155       ast_cli(a->fd, "Memory allocation failure!\n");
03156       return CLI_FAILURE;
03157    }
03158 
03159    snprintf(info, sizeof(info), "\n  -= Info about function '%s' =- \n\n", acf->name);
03160    term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
03161    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03162    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03163    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
03164    term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
03165    term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
03166    term_color(syntax, S_OR(acf->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
03167 #ifdef AST_XML_DOCS
03168    if (acf->docsrc == AST_XML_DOC) {
03169       arguments = ast_xmldoc_printable(S_OR(acf->arguments, "Not available"), 1);
03170       synopsis = ast_xmldoc_printable(S_OR(acf->synopsis, "Not available"), 1);
03171       description = ast_xmldoc_printable(S_OR(acf->desc, "Not available"), 1);
03172       seealso = ast_xmldoc_printable(S_OR(acf->seealso, "Not available"), 1);
03173    } else
03174 #endif
03175    {
03176       synopsis_size = strlen(S_OR(acf->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03177       synopsis = ast_malloc(synopsis_size);
03178 
03179       description_size = strlen(S_OR(acf->desc, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03180       description = ast_malloc(description_size);
03181 
03182       arguments_size = strlen(S_OR(acf->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03183       arguments = ast_malloc(arguments_size);
03184 
03185       seealso_size = strlen(S_OR(acf->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
03186       seealso = ast_malloc(seealso_size);
03187 
03188       /* check allocated memory. */
03189       if (!synopsis || !description || !arguments || !seealso) {
03190          ast_free(synopsis);
03191          ast_free(description);
03192          ast_free(arguments);
03193          ast_free(seealso);
03194          ast_free(syntax);
03195          return CLI_FAILURE;
03196       }
03197 
03198       term_color(arguments, S_OR(acf->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
03199       term_color(synopsis, S_OR(acf->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
03200       term_color(description, S_OR(acf->desc, "Not available"), COLOR_CYAN, 0, description_size);
03201       term_color(seealso, S_OR(acf->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
03202    }
03203 
03204    ast_cli(a->fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
03205          infotitle, syntitle, synopsis, destitle, description,
03206          stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
03207 
03208    ast_free(arguments);
03209    ast_free(synopsis);
03210    ast_free(description);
03211    ast_free(seealso);
03212    ast_free(syntax);
03213 
03214    return CLI_SUCCESS;
03215 }
03216 
03217 struct ast_custom_function *ast_custom_function_find(const char *name)
03218 {
03219    struct ast_custom_function *acf = NULL;
03220 
03221    AST_RWLIST_RDLOCK(&acf_root);
03222    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
03223       if (!strcmp(name, acf->name))
03224          break;
03225    }
03226    AST_RWLIST_UNLOCK(&acf_root);
03227 
03228    return acf;
03229 }
03230 
03231 int ast_custom_function_unregister(struct ast_custom_function *acf)
03232 {
03233    struct ast_custom_function *cur;
03234 
03235    if (!acf) {
03236       return -1;
03237    }
03238 
03239    AST_RWLIST_WRLOCK(&acf_root);
03240    if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist))) {
03241       if (cur->docsrc == AST_XML_DOC) {
03242          ast_string_field_free_memory(acf);
03243       }
03244       ast_verb(2, "Unregistered custom function %s\n", cur->name);
03245    }
03246    AST_RWLIST_UNLOCK(&acf_root);
03247 
03248    return cur ? 0 : -1;
03249 }
03250 
03251 /*! \internal
03252  *  \brief Retrieve the XML documentation of a specified ast_custom_function,
03253  *         and populate ast_custom_function string fields.
03254  *  \param acf ast_custom_function structure with empty 'desc' and 'synopsis'
03255  *             but with a function 'name'.
03256  *  \retval -1 On error.
03257  *  \retval 0 On succes.
03258  */
03259 static int acf_retrieve_docs(struct ast_custom_function *acf)
03260 {
03261 #ifdef AST_XML_DOCS
03262    char *tmpxml;
03263 
03264    /* Let's try to find it in the Documentation XML */
03265    if (!ast_strlen_zero(acf->desc) || !ast_strlen_zero(acf->synopsis)) {
03266       return 0;
03267    }
03268 
03269    if (ast_string_field_init(acf, 128)) {
03270       return -1;
03271    }
03272 
03273    /* load synopsis */
03274    tmpxml = ast_xmldoc_build_synopsis("function", acf->name);
03275    ast_string_field_set(acf, synopsis, tmpxml);
03276    ast_free(tmpxml);
03277 
03278    /* load description */
03279    tmpxml = ast_xmldoc_build_description("function", acf->name);
03280    ast_string_field_set(acf, desc, tmpxml);
03281    ast_free(tmpxml);
03282 
03283    /* load syntax */
03284    tmpxml = ast_xmldoc_build_syntax("function", acf->name);
03285    ast_string_field_set(acf, syntax, tmpxml);
03286    ast_free(tmpxml);
03287 
03288    /* load arguments */
03289    tmpxml = ast_xmldoc_build_arguments("function", acf->name);
03290    ast_string_field_set(acf, arguments, tmpxml);
03291    ast_free(tmpxml);
03292 
03293    /* load seealso */
03294    tmpxml = ast_xmldoc_build_seealso("function", acf->name);
03295    ast_string_field_set(acf, seealso, tmpxml);
03296    ast_free(tmpxml);
03297 
03298    acf->docsrc = AST_XML_DOC;
03299 #endif
03300 
03301    return 0;
03302 }
03303 
03304 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
03305 {
03306    struct ast_custom_function *cur;
03307    char tmps[80];
03308 
03309    if (!acf) {
03310       return -1;
03311    }
03312 
03313    acf->mod = mod;
03314    acf->docsrc = AST_STATIC_DOC;
03315 
03316    if (acf_retrieve_docs(acf)) {
03317       return -1;
03318    }
03319 
03320    AST_RWLIST_WRLOCK(&acf_root);
03321 
03322    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
03323       if (!strcmp(acf->name, cur->name)) {
03324          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
03325          AST_RWLIST_UNLOCK(&acf_root);
03326          return -1;
03327       }
03328    }
03329 
03330    /* Store in alphabetical order */
03331    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
03332       if (strcasecmp(acf->name, cur->name) < 0) {
03333          AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
03334          break;
03335       }
03336    }
03337    AST_RWLIST_TRAVERSE_SAFE_END;
03338 
03339    if (!cur) {
03340       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
03341    }
03342 
03343    AST_RWLIST_UNLOCK(&acf_root);
03344 
03345    ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
03346 
03347    return 0;
03348 }
03349 
03350 /*! \brief return a pointer to the arguments of the function,
03351  * and terminates the function name with '\\0'
03352  */
03353 static char *func_args(char *function)
03354 {
03355    char *args = strchr(function, '(');
03356 
03357    if (!args) {
03358       ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses.  Assuming null argument.\n", function);
03359    } else {
03360       char *p;
03361       *args++ = '\0';
03362       if ((p = strrchr(args, ')'))) {
03363          *p = '\0';
03364       } else {
03365          ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
03366       }
03367    }
03368    return args;
03369 }
03370 
03371 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
03372 {
03373    char *copy = ast_strdupa(function);
03374    char *args = func_args(copy);
03375    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03376 
03377    if (acfptr == NULL)
03378       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03379    else if (!acfptr->read)
03380       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
03381    else {
03382       int res;
03383       struct ast_module_user *u = NULL;
03384       if (acfptr->mod)
03385          u = __ast_module_user_add(acfptr->mod, chan);
03386       res = acfptr->read(chan, copy, args, workspace, len);
03387       if (acfptr->mod && u)
03388          __ast_module_user_remove(acfptr->mod, u);
03389       return res;
03390    }
03391    return -1;
03392 }
03393 
03394 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
03395 {
03396    char *copy = ast_strdupa(function);
03397    char *args = func_args(copy);
03398    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
03399 
03400    if (acfptr == NULL)
03401       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
03402    else if (!acfptr->write)
03403       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
03404    else {
03405       int res;
03406       struct ast_module_user *u = NULL;
03407       if (acfptr->mod)
03408          u = __ast_module_user_add(acfptr->mod, chan);
03409       res = acfptr->write(chan, copy, args, value);
03410       if (acfptr->mod && u)
03411          __ast_module_user_remove(acfptr->mod, u);
03412       return res;
03413    }
03414 
03415    return -1;
03416 }
03417 
03418 void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count, size_t *used)
03419 {
03420    /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
03421    char *cp4;
03422    const char *tmp, *whereweare, *orig_cp2 = cp2;
03423    int length, offset, offset2, isfunction;
03424    char *workspace = NULL;
03425    char *ltmp = NULL, *var = NULL;
03426    char *nextvar, *nextexp, *nextthing;
03427    char *vars, *vare;
03428    int pos, brackets, needsub, len;
03429 
03430    *cp2 = 0; /* just in case nothing ends up there */
03431    whereweare=tmp=cp1;
03432    while (!ast_strlen_zero(whereweare) && count) {
03433       /* Assume we're copying the whole remaining string */
03434       pos = strlen(whereweare);
03435       nextvar = NULL;
03436       nextexp = NULL;
03437       nextthing = strchr(whereweare, '$');
03438       if (nextthing) {
03439          switch (nextthing[1]) {
03440          case '{':
03441             nextvar = nextthing;
03442             pos = nextvar - whereweare;
03443             break;
03444          case '[':
03445             nextexp = nextthing;
03446             pos = nextexp - whereweare;
03447             break;
03448          default:
03449             pos = 1;
03450          }
03451       }
03452 
03453       if (pos) {
03454          /* Can't copy more than 'count' bytes */
03455          if (pos > count)
03456             pos = count;
03457 
03458          /* Copy that many bytes */
03459          memcpy(cp2, whereweare, pos);
03460 
03461          count -= pos;
03462          cp2 += pos;
03463          whereweare += pos;
03464          *cp2 = 0;
03465       }
03466 
03467       if (nextvar) {
03468          /* We have a variable.  Find the start and end, and determine
03469             if we are going to have to recursively call ourselves on the
03470             contents */
03471          vars = vare = nextvar + 2;
03472          brackets = 1;
03473          needsub = 0;
03474 
03475          /* Find the end of it */
03476          while (brackets && *vare) {
03477             if ((vare[0] == '$') && (vare[1] == '{')) {
03478                needsub++;
03479             } else if (vare[0] == '{') {
03480                brackets++;
03481             } else if (vare[0] == '}') {
03482                brackets--;
03483             } else if ((vare[0] == '$') && (vare[1] == '['))
03484                needsub++;
03485             vare++;
03486          }
03487          if (brackets)
03488             ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
03489          len = vare - vars - 1;
03490 
03491          /* Skip totally over variable string */
03492          whereweare += (len + 3);
03493 
03494          if (!var)
03495             var = alloca(VAR_BUF_SIZE);
03496 
03497          /* Store variable name (and truncate) */
03498          ast_copy_string(var, vars, len + 1);
03499 
03500          /* Substitute if necessary */
03501          if (needsub) {
03502             size_t used;
03503             if (!ltmp)
03504                ltmp = alloca(VAR_BUF_SIZE);
03505 
03506             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
03507             vars = ltmp;
03508          } else {
03509             vars = var;
03510          }
03511 
03512          if (!workspace)
03513             workspace = alloca(VAR_BUF_SIZE);
03514 
03515          workspace[0] = '\0';
03516 
03517          parse_variable_name(vars, &offset, &offset2, &isfunction);
03518          if (isfunction) {
03519             /* Evaluate function */
03520             if (c || !headp)
03521                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03522             else {
03523                struct varshead old;
03524                struct ast_channel *bogus = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
03525                if (bogus) {
03526                   memcpy(&old, &bogus->varshead, sizeof(old));
03527                   memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
03528                   cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03529                   /* Don't deallocate the varshead that was passed in */
03530                   memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
03531                   ast_channel_free(bogus);
03532                } else
03533                   ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
03534             }
03535             ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
03536          } else {
03537             /* Retrieve variable value */
03538             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
03539          }
03540          if (cp4) {
03541             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
03542 
03543             length = strlen(cp4);
03544             if (length > count)
03545                length = count;
03546             memcpy(cp2, cp4, length);
03547             count -= length;
03548             cp2 += length;
03549             *cp2 = 0;
03550          }
03551       } else if (nextexp) {
03552          /* We have an expression.  Find the start and end, and determine
03553             if we are going to have to recursively call ourselves on the
03554             contents */
03555          vars = vare = nextexp + 2;
03556          brackets = 1;
03557          needsub = 0;
03558 
03559          /* Find the end of it */
03560          while (brackets && *vare) {
03561             if ((vare[0] == '$') && (vare[1] == '[')) {
03562                needsub++;
03563                brackets++;
03564                vare++;
03565             } else if (vare[0] == '[') {
03566                brackets++;
03567             } else if (vare[0] == ']') {
03568                brackets--;
03569             } else if ((vare[0] == '$') && (vare[1] == '{')) {
03570                needsub++;
03571                vare++;
03572             }
03573             vare++;
03574          }
03575          if (brackets)
03576             ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
03577          len = vare - vars - 1;
03578 
03579          /* Skip totally over expression */
03580          whereweare += (len + 3);
03581 
03582          if (!var)
03583             var = alloca(VAR_BUF_SIZE);
03584 
03585          /* Store variable name (and truncate) */
03586          ast_copy_string(var, vars, len + 1);
03587 
03588          /* Substitute if necessary */
03589          if (needsub) {
03590             size_t used;
03591             if (!ltmp)
03592                ltmp = alloca(VAR_BUF_SIZE);
03593 
03594             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1, &used);
03595             vars = ltmp;
03596          } else {
03597             vars = var;
03598          }
03599 
03600          length = ast_expr(vars, cp2, count, c);
03601 
03602          if (length) {
03603             ast_debug(1, "Expression result is '%s'\n", cp2);
03604             count -= length;
03605             cp2 += length;
03606             *cp2 = 0;
03607          }
03608       }
03609    }
03610    *used = cp2 - orig_cp2;
03611 }
03612 
03613 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
03614 {
03615    size_t used;
03616    pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count, &used);
03617 }
03618 
03619 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
03620 {
03621    size_t used;
03622    pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count, &used);
03623 }
03624 
03625 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
03626 {
03627    const char *tmp;
03628 
03629    /* Nothing more to do */
03630    if (!e->data) {
03631       *passdata = '\0';
03632       return;
03633    }
03634 
03635    /* No variables or expressions in e->data, so why scan it? */
03636    if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
03637       ast_copy_string(passdata, e->data, datalen);
03638       return;
03639    }
03640 
03641    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
03642 }
03643 
03644 /*!
03645  * \brief The return value depends on the action:
03646  *
03647  * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
03648  * and return 0 on failure, -1 on match;
03649  * E_FINDLABEL maps the label to a priority, and returns
03650  * the priority on success, ... XXX
03651  * E_SPAWN, spawn an application,
03652  *
03653  * \retval 0 on success.
03654  * \retval  -1 on failure.
03655  *
03656  * \note The channel is auto-serviced in this function, because doing an extension
03657  * match may block for a long time.  For example, if the lookup has to use a network
03658  * dialplan switch, such as DUNDi or IAX2, it may take a while.  However, the channel
03659  * auto-service code will queue up any important signalling frames to be processed
03660  * after this is done.
03661  */
03662 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
03663   const char *context, const char *exten, int priority,
03664   const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
03665 {
03666    struct ast_exten *e;
03667    struct ast_app *app;
03668    int res;
03669    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
03670    char passdata[EXT_DATA_SIZE];
03671 
03672    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
03673 
03674    ast_rdlock_contexts();
03675    if (found)
03676       *found = 0;
03677 
03678    e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
03679    if (e) {
03680       if (found)
03681          *found = 1;
03682       if (matching_action) {
03683          ast_unlock_contexts();
03684          return -1;  /* success, we found it */
03685       } else if (action == E_FINDLABEL) { /* map the label to a priority */
03686          res = e->priority;
03687          ast_unlock_contexts();
03688          return res; /* the priority we were looking for */
03689       } else { /* spawn */
03690          if (!e->cached_app)
03691             e->cached_app = pbx_findapp(e->app);
03692          app = e->cached_app;
03693          ast_unlock_contexts();
03694          if (!app) {
03695             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
03696             return -1;
03697          }
03698          if (c->context != context)
03699             ast_copy_string(c->context, context, sizeof(c->context));
03700          if (c->exten != exten)
03701             ast_copy_string(c->exten, exten, sizeof(c->exten));
03702          c->priority = priority;
03703          pbx_substitute_variables(passdata, sizeof(passdata), c, e);
03704 #ifdef CHANNEL_TRACE
03705          ast_channel_trace_update(c);
03706 #endif
03707          ast_debug(1, "Launching '%s'\n", app->name);
03708          if (VERBOSITY_ATLEAST(3)) {
03709             char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
03710             ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
03711                exten, context, priority,
03712                term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
03713                term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
03714                term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
03715                "in new stack");
03716          }
03717          manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
03718                "Channel: %s\r\n"
03719                "Context: %s\r\n"
03720                "Extension: %s\r\n"
03721                "Priority: %d\r\n"
03722                "Application: %s\r\n"
03723                "AppData: %s\r\n"
03724                "Uniqueid: %s\r\n",
03725                c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
03726          return pbx_exec(c, app, passdata);  /* 0 on success, -1 on failure */
03727       }
03728    } else if (q.swo) {  /* not found here, but in another switch */
03729       if (found)
03730          *found = 1;
03731       ast_unlock_contexts();
03732       if (matching_action) {
03733          return -1;
03734       } else {
03735          if (!q.swo->exec) {
03736             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
03737             res = -1;
03738          }
03739          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
03740       }
03741    } else { /* not found anywhere, see what happened */
03742       ast_unlock_contexts();
03743       /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
03744       switch (q.status) {
03745       case STATUS_NO_CONTEXT:
03746          if (!matching_action && !combined_find_spawn)
03747             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
03748          break;
03749       case STATUS_NO_EXTENSION:
03750          if (!matching_action && !combined_find_spawn)
03751             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
03752          break;
03753       case STATUS_NO_PRIORITY:
03754          if (!matching_action && !combined_find_spawn)
03755             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
03756          break;
03757       case STATUS_NO_LABEL:
03758          if (context && !combined_find_spawn)
03759             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
03760          break;
03761       default:
03762          ast_debug(1, "Shouldn't happen!\n");
03763       }
03764 
03765       return (matching_action) ? 0 : -1;
03766    }
03767 }
03768 
03769 /*! \brief Find hint for given extension in context */
03770 static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
03771 {
03772    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
03773    return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
03774 }
03775 
03776 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
03777 {
03778    struct ast_exten *e;
03779    ast_rdlock_contexts();
03780    e = ast_hint_extension_nolock(c, context, exten);
03781    ast_unlock_contexts();
03782    return e;
03783 }
03784 
03785 enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
03786 {
03787    switch (devstate) {
03788    case AST_DEVICE_ONHOLD:
03789       return AST_EXTENSION_ONHOLD;
03790    case AST_DEVICE_BUSY:
03791       return AST_EXTENSION_BUSY;
03792    case AST_DEVICE_UNKNOWN:
03793       return AST_EXTENSION_NOT_INUSE;
03794    case AST_DEVICE_UNAVAILABLE:
03795    case AST_DEVICE_INVALID:
03796       return AST_EXTENSION_UNAVAILABLE;
03797    case AST_DEVICE_RINGINUSE:
03798       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
03799    case AST_DEVICE_RINGING:
03800       return AST_EXTENSION_RINGING;
03801    case AST_DEVICE_INUSE:
03802       return AST_EXTENSION_INUSE;
03803    case AST_DEVICE_NOT_INUSE:
03804       return AST_EXTENSION_NOT_INUSE;
03805    case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
03806       break;
03807    }
03808 
03809    return AST_EXTENSION_NOT_INUSE;
03810 }
03811 
03812 /*! \brief Check state of extension by using hints */
03813 static int ast_extension_state2(struct ast_exten *e)
03814 {
03815    struct ast_str *hint = ast_str_thread_get(&extensionstate_buf, 16);
03816    char *cur, *rest;
03817    struct ast_devstate_aggregate agg;
03818 
03819    if (!e)
03820       return -1;
03821 
03822    ast_devstate_aggregate_init(&agg);
03823 
03824    ast_str_set(&hint, 0, "%s", ast_get_extension_app(e));
03825 
03826    rest = ast_str_buffer(hint);  /* One or more devices separated with a & character */
03827 
03828    while ( (cur = strsep(&rest, "&")) ) {
03829       ast_devstate_aggregate_add(&agg, ast_device_state(cur));
03830    }
03831 
03832    return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
03833 }
03834 
03835 /*! \brief Return extension_state as string */
03836 const char *ast_extension_state2str(int extension_state)
03837 {
03838    int i;
03839 
03840    for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
03841       if (extension_states[i].extension_state == extension_state)
03842          return extension_states[i].text;
03843    }
03844    return "Unknown";
03845 }
03846 
03847 /*! \brief Check extension state for an extension by using hint */
03848 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
03849 {
03850    struct ast_exten *e;
03851 
03852    if (!(e = ast_hint_extension(c, context, exten))) {  /* Do we have a hint for this extension ? */
03853       return -1;                   /* No hint, return -1 */
03854    }
03855 
03856    if (e->exten[0] == '_') {
03857       /* Create this hint on-the-fly */
03858       ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
03859          e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
03860          e->registrar);
03861       if (!(e = ast_hint_extension(c, context, exten))) {
03862          /* Improbable, but not impossible */
03863          return -1;
03864       }
03865    }
03866 
03867    return ast_extension_state2(e);  /* Check all devices in the hint */
03868 }
03869 
03870 static int handle_statechange(void *datap)
03871 {
03872    struct ast_hint *hint;
03873    struct ast_str *str;
03874    struct statechange *sc = datap;
03875    struct ao2_iterator i;
03876    struct ao2_iterator cb_iter;
03877 
03878    if (!(str = ast_str_create(1024))) {
03879       return -1;
03880    }
03881 
03882    i = ao2_iterator_init(hints, 0);
03883    for (hint = ao2_iterator_next(&i); hint; ao2_ref(hint, -1), hint = ao2_iterator_next(&i)) {
03884       struct ast_state_cb *state_cb;
03885       char *cur, *parse;
03886       int state;
03887 
03888       ast_str_set(&str, 0, "%s", ast_get_extension_app(hint->exten));
03889       parse = str->str;
03890 
03891       while ( (cur = strsep(&parse, "&")) ) {
03892          if (!strcasecmp(cur, sc->dev)) {
03893             break;
03894          }
03895       }
03896 
03897       if (!cur) {
03898          continue;
03899       }
03900 
03901       /* Get device state for this hint */
03902       state = ast_extension_state2(hint->exten);
03903 
03904       if ((state == -1) || (state == hint->laststate)) {
03905          continue;
03906       }
03907 
03908       /* Device state changed since last check - notify the watchers */
03909 
03910       ao2_lock(hints);
03911       ao2_lock(hint);
03912 
03913       if (hint->exten == NULL) {
03914          /* the extension has been destroyed */
03915          ao2_unlock(hint);
03916          ao2_unlock(hints);
03917          continue;
03918       }
03919 
03920       /* For general callbacks */
03921       cb_iter = ao2_iterator_init(statecbs, 0);
03922       for (state_cb = ao2_iterator_next(&cb_iter); state_cb; ao2_ref(state_cb, -1), state_cb = ao2_iterator_next(&cb_iter)) {
03923          state_cb->callback(hint->exten->parent->name, hint->exten->exten, state, state_cb->data);
03924       }
03925       ao2_iterator_destroy(&cb_iter);
03926 
03927       /* For extension callbacks */
03928       cb_iter = ao2_iterator_init(hint->callbacks, 0);
03929       for (state_cb = ao2_iterator_next(&cb_iter); state_cb; ao2_ref(state_cb, -1), state_cb = ao2_iterator_next(&cb_iter)) {
03930          state_cb->callback(hint->exten->parent->name, hint->exten->exten, state, state_cb->data);
03931       }
03932       ao2_iterator_destroy(&cb_iter);
03933 
03934       hint->laststate = state;   /* record we saw the change */
03935       ao2_unlock(hint);
03936       ao2_unlock(hints);
03937    }
03938    ao2_iterator_destroy(&i);
03939    ast_free(str);
03940    ast_free(sc);
03941    return 0;
03942 }
03943 
03944 /*! \brief  Add watcher for extension states */
03945 int ast_extension_state_add(const char *context, const char *exten,
03946              ast_state_cb_type callback, void *data)
03947 {
03948    struct ast_hint *hint;
03949    struct ast_state_cb *state_cb;
03950    struct ast_exten *e;
03951 
03952    /* If there's no context and extension:  add callback to statecbs list */
03953    if (!context && !exten) {
03954       ao2_lock(hints);
03955 
03956       state_cb = ao2_find(statecbs, callback, 0);
03957       if (state_cb) {
03958          state_cb->data = data;
03959          ao2_ref(state_cb, -1);
03960          ao2_unlock(hints);
03961          return 0;
03962       }
03963 
03964       /* Now insert the callback */
03965       if (!(state_cb = ao2_alloc(sizeof(*state_cb), NULL))) {
03966          ao2_unlock(hints);
03967          return -1;
03968       }
03969       state_cb->id = 0;
03970       state_cb->callback = callback;
03971       state_cb->data = data;
03972 
03973       ao2_link(statecbs, state_cb);
03974       ao2_ref(state_cb, -1);
03975 
03976       ao2_unlock(hints);
03977       return 0;
03978    }
03979 
03980    if (!context || !exten)
03981       return -1;
03982 
03983    /* This callback type is for only one hint, so get the hint */
03984    e = ast_hint_extension(NULL, context, exten);
03985    if (!e) {
03986       return -1;
03987    }
03988 
03989    /* If this is a pattern, dynamically create a new extension for this
03990     * particular match.  Note that this will only happen once for each
03991     * individual extension, because the pattern will no longer match first.
03992     */
03993    if (e->exten[0] == '_') {
03994       ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
03995          e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
03996          e->registrar);
03997       e = ast_hint_extension(NULL, context, exten);
03998       if (!e || e->exten[0] == '_') {
03999          return -1;
04000       }
04001    }
04002 
04003    /* Find the hint in the list of hints */
04004    hint = ao2_find(hints, e, 0);
04005 
04006    if (!hint) {
04007       return -1;
04008    }
04009 
04010    /* Now insert the callback in the callback list  */
04011    if (!(state_cb = ao2_alloc(sizeof(*state_cb), NULL))) {
04012       ao2_ref(hint, -1);
04013       return -1;
04014    }
04015 
04016    state_cb->id = stateid++;     /* Unique ID for this callback */
04017    state_cb->callback = callback;   /* Pointer to callback routine */
04018    state_cb->data = data;     /* Data for the callback */
04019 
04020    ao2_lock(hint);
04021    ao2_link(hint->callbacks, state_cb);
04022    ao2_ref(state_cb, -1);
04023    ao2_unlock(hint);
04024 
04025    ao2_ref(hint, -1);
04026 
04027    return state_cb->id;
04028 }
04029 
04030 /*! \brief Remove a watcher from the callback list */
04031 static int find_hint_by_cb_id(void *obj, void *arg, int flags)
04032 {
04033    struct ast_state_cb *state_cb;
04034    const struct ast_hint *hint = obj;
04035    int *id = arg;
04036 
04037    if ((state_cb = ao2_find(hint->callbacks, id, 0))) {
04038       ao2_ref(state_cb, -1);
04039       return CMP_MATCH | CMP_STOP;
04040    }
04041 
04042    return 0;
04043 }
04044 
04045 /*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
04046 int ast_extension_state_del(int id, ast_state_cb_type callback)
04047 {
04048    struct ast_state_cb *p_cur = NULL;
04049    int ret = -1;
04050 
04051    if (!id && !callback) {
04052       return -1;
04053    }
04054 
04055    if (!id) {  /* id == 0 is a callback without extension */
04056       ao2_lock(hints);
04057       p_cur = ao2_find(statecbs, callback, OBJ_UNLINK);
04058       if (p_cur) {
04059          ret = 0;
04060          ao2_ref(p_cur, -1);
04061       }
04062       ao2_unlock(hints);
04063    } else { /* callback with extension, find the callback based on ID */
04064       struct ast_hint *hint;
04065 
04066       hint = ao2_callback(hints, 0, find_hint_by_cb_id, &id);
04067 
04068       if (hint) {
04069          ao2_lock(hint);
04070          p_cur = ao2_find(hint->callbacks, &id, OBJ_UNLINK);
04071          if (p_cur) {
04072             ret = 0;
04073             ao2_ref(p_cur, -1);
04074          }
04075          ao2_unlock(hint);
04076          ao2_ref(hint, -1);
04077       }
04078    }
04079 
04080    return ret;
04081 }
04082 
04083 
04084 static int hint_id_cmp(void *obj, void *arg, int flags)
04085 {
04086    const struct ast_state_cb *cb = obj;
04087    int *id = arg;
04088 
04089    return (cb->id == *id) ? CMP_MATCH | CMP_STOP : 0;
04090 }
04091 
04092 /*! \brief Add hint to hint list, check initial extension state */
04093 static int ast_add_hint(struct ast_exten *e)
04094 {
04095    struct ast_hint *hint;
04096 
04097    if (!e) {
04098       return -1;
04099    }
04100 
04101    /* Search if hint exists, do nothing */   
04102    hint = ao2_find(hints, e, 0);
04103    if (hint) {
04104       ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
04105       ao2_ref(hint, -1);
04106       return -1;
04107    }
04108 
04109    ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
04110 
04111    if (!(hint = ao2_alloc(sizeof(*hint), NULL))) {
04112       return -1;
04113    }
04114    if (!(hint->callbacks = ao2_container_alloc(1, NULL, hint_id_cmp))) {
04115       return -1;
04116    }
04117 
04118    /* Initialize and insert new item at the top */
04119    hint->exten = e;
04120    hint->laststate = ast_extension_state2(e);
04121 
04122    ao2_link(hints, hint);
04123 
04124    ao2_ref(hint, -1);
04125 
04126    return 0;
04127 }
04128 
04129 /*! \brief Change hint for an extension */
04130 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
04131 {
04132    struct ast_hint *hint;
04133 
04134    hint = ao2_find(hints, oe, 0);
04135 
04136    if (!hint) {
04137       return -1;
04138    }
04139 
04140    ao2_lock(hint);
04141    hint->exten = ne;
04142    ao2_unlock(hint);
04143    ao2_ref(hint, -1);
04144 
04145    return 0;
04146 }
04147 
04148 /*! \brief Remove hint from extension */
04149 static int ast_remove_hint(struct ast_exten *e)
04150 {
04151    /* Cleanup the Notifys if hint is removed */
04152    struct ast_hint *hint;
04153    struct ast_state_cb *state_cb;
04154 
04155    if (!e) {
04156       return -1;
04157    }
04158 
04159    hint = ao2_find(hints, e, 0);
04160 
04161    if (!hint) {
04162       return -1;
04163    }
04164    ao2_lock(hint);
04165 
04166    while ((state_cb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
04167       /* Notify with -1 and remove all callbacks */
04168       state_cb->callback(hint->exten->parent->name, hint->exten->exten,
04169          AST_EXTENSION_DEACTIVATED, state_cb->data);
04170       ao2_ref(state_cb, -1);
04171    }
04172 
04173    hint->exten = NULL;
04174    ao2_unlink(hints, hint);
04175    ao2_ref(hint->callbacks, -1);
04176    ao2_unlock(hint);
04177    ao2_ref(hint, -1);
04178 
04179    return 0;
04180 }
04181 
04182 
04183 /*! \brief Get hint for channel */
04184 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
04185 {
04186    struct ast_exten *e = ast_hint_extension(c, context, exten);
04187 
04188    if (e) {
04189       if (hint)
04190          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
04191       if (name) {
04192          const char *tmp = ast_get_extension_app_data(e);
04193          if (tmp)
04194             ast_copy_string(name, tmp, namesize);
04195       }
04196       return -1;
04197    }
04198    return 0;
04199 }
04200 
04201 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
04202 {
04203    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
04204 }
04205 
04206 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
04207 {
04208    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
04209 }
04210 
04211 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
04212 {
04213    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
04214 }
04215 
04216 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
04217 {
04218    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
04219 }
04220 
04221 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
04222 {
04223    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
04224 }
04225 
04226 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
04227 {
04228    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
04229 }
04230 
04231 /*! helper function to set extension and priority */
04232 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
04233 {
04234    ast_channel_lock(c);
04235    ast_copy_string(c->exten, exten, sizeof(c->exten));
04236    c->priority = pri;
04237    ast_channel_unlock(c);
04238 }
04239 
04240 /*!
04241  * \brief collect digits from the channel into the buffer.
04242  * \param waittime is in milliseconds
04243  * \retval 0 on timeout or done.
04244  * \retval -1 on error.
04245 */
04246 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
04247 {
04248    int digit;
04249 
04250    buf[pos] = '\0';  /* make sure it is properly terminated */
04251    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
04252       /* As long as we're willing to wait, and as long as it's not defined,
04253          keep reading digits until we can't possibly get a right answer anymore.  */
04254       digit = ast_waitfordigit(c, waittime);
04255       if (c->_softhangup & AST_SOFTHANGUP_ASYNCGOTO) {
04256          ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
04257       } else {
04258          if (!digit) /* No entry */
04259             break;
04260          if (digit < 0) /* Error, maybe a  hangup */
04261             return -1;
04262          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
04263             buf[pos++] = digit;
04264             buf[pos] = '\0';
04265          }
04266          waittime = c->pbx->dtimeoutms;
04267       }
04268    }
04269    return 0;
04270 }
04271 
04272 static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
04273       struct ast_pbx_args *args)
04274 {
04275    int found = 0; /* set if we find at least one match */
04276    int res = 0;
04277    int autoloopflag;
04278    int error = 0;    /* set an error conditions */
04279 
04280    /* A little initial setup here */
04281    if (c->pbx) {
04282       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
04283       /* XXX and now what ? */
04284       ast_free(c->pbx);
04285    }
04286    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
04287       return -1;
04288    /* Set reasonable defaults */
04289    c->pbx->rtimeoutms = 10000;
04290    c->pbx->dtimeoutms = 5000;
04291 
04292    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
04293    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
04294 
04295    /* Start by trying whatever the channel is set to */
04296    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
04297       /* If not successful fall back to 's' */
04298       ast_verb(2, "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
04299       /* XXX the original code used the existing priority in the call to
04300        * ast_exists_extension(), and reset it to 1 afterwards.
04301        * I believe the correct thing is to set it to 1 immediately.
04302        */
04303       set_ext_pri(c, "s", 1);
04304       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
04305          /* JK02: And finally back to default if everything else failed */
04306          ast_verb(2, "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
04307          ast_copy_string(c->context, "default", sizeof(c->context));
04308       }
04309    }
04310    if (c->cdr) {
04311       /* allow CDR variables that have been collected after channel was created to be visible during call */
04312       ast_cdr_update(c);
04313    }
04314    for (;;) {
04315       char dst_exten[256]; /* buffer to accumulate digits */
04316       int pos = 0;      /* XXX should check bounds */
04317       int digit = 0;
04318       int invalid = 0;
04319       int timeout = 0;
04320 
04321       /* loop on priorities in this context/exten */
04322       while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) {
04323          if (c->_softhangup & AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
04324             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
04325             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
04326             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
04327             ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
04328          } else if (c->_softhangup & AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04329             pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
04330             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
04331             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
04332             ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
04333          } else if (c->_softhangup & AST_SOFTHANGUP_ASYNCGOTO) {
04334             ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
04335             continue;
04336          } else if (ast_check_hangup(c)) {
04337             ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
04338                c->exten, c->priority);
04339             error = 1;
04340             break;
04341          }
04342          c->priority++;
04343       } /* end while  - from here on we can use 'break' to go out */
04344       if (found && res) {
04345          /* Something bad happened, or a hangup has been requested. */
04346          if (strchr("0123456789ABCDEF*#", res)) {
04347             ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
04348             pos = 0;
04349             dst_exten[pos++] = digit = res;
04350             dst_exten[pos] = '\0';
04351          } else if (res == AST_PBX_INCOMPLETE) {
04352             ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
04353             ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
04354 
04355             /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
04356             if (!ast_matchmore_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
04357                invalid = 1;
04358             } else {
04359                ast_copy_string(dst_exten, c->exten, sizeof(dst_exten));
04360                digit = 1;
04361                pos = strlen(dst_exten);
04362             }
04363          } else {
04364             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04365             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04366 
04367             if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04368                /* if we are already on the 'e' exten, don't jump to it again */
04369                if (!strcmp(c->exten, "e")) {
04370                   ast_verb(2, "Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", c->context, c->exten, c->priority, c->name);
04371                   error = 1;
04372                } else {
04373                   pbx_builtin_raise_exception(c, "ERROR");
04374                   continue;
04375                }
04376             }
04377 
04378             if (c->_softhangup & AST_SOFTHANGUP_ASYNCGOTO) {
04379                ast_channel_clear_softhangup(c, AST_SOFTHANGUP_ASYNCGOTO);
04380                continue;
04381             } else if (c->_softhangup & AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
04382                set_ext_pri(c, "T", 1);
04383                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
04384                memset(&c->whentohangup, 0, sizeof(c->whentohangup));
04385                ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
04386                continue;
04387             } else {
04388                if (c->cdr)
04389                   ast_cdr_update(c);
04390                error = 1;
04391                break;
04392             }
04393          }
04394       }
04395       if (error)
04396          break;
04397 
04398       /*!\note
04399        * We get here on a failure of some kind:  non-existing extension or
04400        * hangup.  We have options, here.  We can either catch the failure
04401        * and continue, or we can drop out entirely. */
04402 
04403       if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
04404          /*!\note
04405           * If there is no match at priority 1, it is not a valid extension anymore.
04406           * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
04407           * neither exist.
04408           */
04409          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
04410             ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
04411             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
04412             set_ext_pri(c, "i", 1);
04413          } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04414             pbx_builtin_raise_exception(c, "INVALID");
04415          } else {
04416             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
04417                c->name, c->exten, c->context);
04418             error = 1; /* we know what to do with it */
04419             break;
04420          }
04421       } else if (c->_softhangup & AST_SOFTHANGUP_TIMEOUT) {
04422          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
04423          ast_channel_clear_softhangup(c, AST_SOFTHANGUP_TIMEOUT);
04424       } else { /* keypress received, get more digits for a full extension */
04425          int waittime = 0;
04426          if (digit)
04427             waittime = c->pbx->dtimeoutms;
04428          else if (!autofallthrough)
04429             waittime = c->pbx->rtimeoutms;
04430          if (!waittime) {
04431             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
04432             if (!status)
04433                status = "UNKNOWN";
04434             ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
04435             if (!strcasecmp(status, "CONGESTION"))
04436                res = pbx_builtin_congestion(c, "10");
04437             else if (!strcasecmp(status, "CHANUNAVAIL"))
04438                res = pbx_builtin_congestion(c, "10");
04439             else if (!strcasecmp(status, "BUSY"))
04440                res = pbx_builtin_busy(c, "10");
04441             error = 1; /* XXX disable message */
04442             break;   /* exit from the 'for' loop */
04443          }
04444 
04445          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
04446             break;
04447          if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
04448             timeout = 1;
04449          if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
04450             set_ext_pri(c, dst_exten, 1);
04451          else {
04452             /* No such extension */
04453             if (!timeout && !ast_strlen_zero(dst_exten)) {
04454                /* An invalid extension */
04455                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
04456                   ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
04457                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
04458                   set_ext_pri(c, "i", 1);
04459                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04460                   pbx_builtin_raise_exception(c, "INVALID");
04461                } else {
04462                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
04463                   found = 1; /* XXX disable message */
04464                   break;
04465                }
04466             } else {
04467                /* A simple timeout */
04468                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
04469                   ast_verb(3, "Timeout on %s\n", c->name);
04470                   set_ext_pri(c, "t", 1);
04471                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
04472                   pbx_builtin_raise_exception(c, "RESPONSETIMEOUT");
04473                } else {
04474                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
04475                   found = 1; /* XXX disable message */
04476                   break;
04477                }
04478             }
04479          }
04480          if (c->cdr) {
04481             ast_verb(2, "CDR updated on %s\n",c->name);
04482             ast_cdr_update(c);
04483          }
04484       }
04485    }
04486 
04487    if (!found && !error) {
04488       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
04489    }
04490 
04491    if (!args || !args->no_hangup_chan) {
04492       ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
04493    }
04494 
04495    if ((!args || !args->no_hangup_chan) &&
04496          !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) &&
04497          ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
04498       set_ext_pri(c, "h", 1);
04499       if (c->cdr && ast_opt_end_cdr_before_h_exten) {
04500          ast_cdr_end(c->cdr);
04501       }
04502       while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
04503          c->priority++;
04504       }
04505       if (found && res) {
04506          /* Something bad happened, or a hangup has been requested. */
04507          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04508          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
04509       }
04510    }
04511    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
04512    ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
04513    pbx_destroy(c->pbx);
04514    c->pbx = NULL;
04515 
04516    if (!args || !args->no_hangup_chan) {
04517       ast_hangup(c);
04518    }
04519 
04520    return 0;
04521 }
04522 
04523 /*!
04524  * \brief Increase call count for channel
04525  * \retval 0 on success
04526  * \retval non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached 
04527 */
04528 static int increase_call_count(const struct ast_channel *c)
04529 {
04530    int failed = 0;
04531    double curloadavg;
04532 #if defined(HAVE_SYSINFO)
04533    long curfreemem;
04534    struct sysinfo sys_info;
04535 #endif
04536 
04537    ast_mutex_lock(&maxcalllock);
04538    if (option_maxcalls) {
04539       if (countcalls >= option_maxcalls) {
04540          ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
04541          failed = -1;
04542       }
04543    }
04544    if (option_maxload) {
04545       getloadavg(&curloadavg, 1);
04546       if (curloadavg >= option_maxload) {
04547          ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
04548          failed = -1;
04549       }
04550    }
04551 #if defined(HAVE_SYSINFO)
04552    if (option_minmemfree) {
04553       if (!sysinfo(&sys_info)) {
04554          /* make sure that the free system memory is above the configured low watermark
04555           * convert the amount of freeram from mem_units to MB */
04556          curfreemem = sys_info.freeram / sys_info.mem_unit;
04557          curfreemem /= 1024 * 1024;
04558          if (curfreemem < option_minmemfree) {
04559             ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
04560             failed = -1;
04561          }
04562       }
04563    }
04564 #endif
04565 
04566    if (!failed) {
04567       countcalls++;
04568       totalcalls++;
04569    }
04570    ast_mutex_unlock(&maxcalllock);
04571 
04572    return failed;
04573 }
04574 
04575 static void decrease_call_count(void)
04576 {
04577    ast_mutex_lock(&maxcalllock);
04578    if (countcalls > 0)
04579       countcalls--;
04580    ast_mutex_unlock(&maxcalllock);
04581 }
04582 
04583 static void destroy_exten(struct ast_exten *e)
04584 {
04585    if (e->priority == PRIORITY_HINT)
04586       ast_remove_hint(e);
04587 
04588    if (e->peer_table)
04589       ast_hashtab_destroy(e->peer_table,0);
04590    if (e->peer_label_table)
04591       ast_hashtab_destroy(e->peer_label_table, 0);
04592    if (e->datad)
04593       e->datad(e->data);
04594    ast_free(e);
04595 }
04596 
04597 static void *pbx_thread(void *data)
04598 {
04599    /* Oh joyeous kernel, we're a new thread, with nothing to do but
04600       answer this channel and get it going.
04601    */
04602    /* NOTE:
04603       The launcher of this function _MUST_ increment 'countcalls'
04604       before invoking the function; it will be decremented when the
04605       PBX has finished running on the channel
04606     */
04607    struct ast_channel *c = data;
04608 
04609    __ast_pbx_run(c, NULL);
04610    decrease_call_count();
04611 
04612    pthread_exit(NULL);
04613 
04614    return NULL;
04615 }
04616 
04617 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
04618 {
04619    pthread_t t;
04620 
04621    if (!c) {
04622       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
04623       return AST_PBX_FAILED;
04624    }
04625 
04626    if (increase_call_count(c))
04627       return AST_PBX_CALL_LIMIT;
04628 
04629    /* Start a new thread, and get something handling this channel. */
04630    if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
04631       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
04632       decrease_call_count();
04633       return AST_PBX_FAILED;
04634    }
04635 
04636    return AST_PBX_SUCCESS;
04637 }
04638 
04639 enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
04640 {
04641    enum ast_pbx_result res = AST_PBX_SUCCESS;
04642 
04643    if (increase_call_count(c)) {
04644       return AST_PBX_CALL_LIMIT;
04645    }
04646 
04647    res = __ast_pbx_run(c, args);
04648 
04649    decrease_call_count();
04650 
04651    return res;
04652 }
04653 
04654 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
04655 {
04656    return ast_pbx_run_args(c, NULL);
04657 }
04658 
04659 int ast_active_calls(void)
04660 {
04661    return countcalls;
04662 }
04663 
04664 int ast_processed_calls(void)
04665 {
04666    return totalcalls;
04667 }
04668 
04669 int pbx_set_autofallthrough(int newval)
04670 {
04671    int oldval = autofallthrough;
04672    autofallthrough = newval;
04673    return oldval;
04674 }
04675 
04676 int pbx_set_extenpatternmatchnew(int newval)
04677 {
04678    int oldval = extenpatternmatchnew;
04679    extenpatternmatchnew = newval;
04680    return oldval;
04681 }
04682 
04683 void pbx_set_overrideswitch(const char *newval)
04684 {
04685    if (overrideswitch) {
04686       ast_free(overrideswitch);
04687    }
04688    if (!ast_strlen_zero(newval)) {
04689       overrideswitch = ast_strdup(newval);
04690    } else {
04691       overrideswitch = NULL;
04692    }
04693 }
04694 
04695 /*!
04696  * \brief lookup for a context with a given name,
04697  * \retval found context or NULL if not found.
04698 */
04699 static struct ast_context *find_context(const char *context)
04700 {
04701    struct ast_context *c = NULL;
04702    struct fake_context item;
04703 
04704    ast_copy_string(item.name, context, sizeof(item.name));
04705 
04706    c = ast_hashtab_lookup(contexts_table,&item);
04707 
04708    return c;
04709 }
04710 
04711 /*!
04712  * \brief lookup for a context with a given name,
04713  * \retval with conlock held if found.
04714  * \retval NULL if not found.
04715 */
04716 static struct ast_context *find_context_locked(const char *context)
04717 {
04718    struct ast_context *c = NULL;
04719    struct fake_context item;
04720 
04721    ast_copy_string(item.name, context, sizeof(item.name));
04722 
04723    ast_rdlock_contexts();
04724    c = ast_hashtab_lookup(contexts_table,&item);
04725 
04726 #ifdef NOTNOW
04727 
04728    while ( (c = ast_walk_contexts(c)) ) {
04729       if (!strcmp(ast_get_context_name(c), context))
04730          return c;
04731    }
04732 #endif
04733    if (!c)
04734       ast_unlock_contexts();
04735 
04736    return c;
04737 }
04738 
04739 /*!
04740  * \brief Remove included contexts.
04741  * This function locks contexts list by &conlist, search for the right context
04742  * structure, leave context list locked and call ast_context_remove_include2
04743  * which removes include, unlock contexts list and return ...
04744 */
04745 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
04746 {
04747    int ret = -1;
04748    struct ast_context *c = find_context_locked(context);
04749 
04750    if (c) {
04751       /* found, remove include from this context ... */
04752       ret = ast_context_remove_include2(c, include, registrar);
04753       ast_unlock_contexts();
04754    }
04755    return ret;
04756 }
04757 
04758 /*!
04759  * \brief Locks context, remove included contexts, unlocks context.
04760  * When we call this function, &conlock lock must be locked, because when
04761  * we giving *con argument, some process can remove/change this context
04762  * and after that there can be segfault.
04763  *
04764  * \retval 0 on success.
04765  * \retval -1 on failure.
04766  */
04767 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
04768 {
04769    struct ast_include *i, *pi = NULL;
04770    int ret = -1;
04771 
04772    ast_wrlock_context(con);
04773 
04774    /* find our include */
04775    for (i = con->includes; i; pi = i, i = i->next) {
04776       if (!strcmp(i->name, include) &&
04777             (!registrar || !strcmp(i->registrar, registrar))) {
04778          /* remove from list */
04779          ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
04780          if (pi)
04781             pi->next = i->next;
04782          else
04783             con->includes = i->next;
04784          /* free include and return */
04785          ast_destroy_timing(&(i->timing));
04786          ast_free(i);
04787          ret = 0;
04788          break;
04789       }
04790    }
04791 
04792    ast_unlock_context(con);
04793 
04794    return ret;
04795 }
04796 
04797 /*!
04798  * \note This function locks contexts list by &conlist, search for the rigt context
04799  * structure, leave context list locked and call ast_context_remove_switch2
04800  * which removes switch, unlock contexts list and return ...
04801  */
04802 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
04803 {
04804    int ret = -1; /* default error return */
04805    struct ast_context *c = find_context_locked(context);
04806 
04807    if (c) {
04808       /* remove switch from this context ... */
04809       ret = ast_context_remove_switch2(c, sw, data, registrar);
04810       ast_unlock_contexts();
04811    }
04812    return ret;
04813 }
04814 
04815 /*!
04816  * \brief This function locks given context, removes switch, unlock context and
04817  * return.
04818  * \note When we call this function, &conlock lock must be locked, because when
04819  * we giving *con argument, some process can remove/change this context
04820  * and after that there can be segfault.
04821  *
04822  */
04823 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
04824 {
04825    struct ast_sw *i;
04826    int ret = -1;
04827 
04828    ast_wrlock_context(con);
04829 
04830    /* walk switches */
04831    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
04832       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
04833          (!registrar || !strcmp(i->registrar, registrar))) {
04834          /* found, remove from list */
04835          ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
04836          AST_LIST_REMOVE_CURRENT(list);
04837          ast_free(i); /* free switch and return */
04838          ret = 0;
04839          break;
04840       }
04841    }
04842    AST_LIST_TRAVERSE_SAFE_END;
04843 
04844    ast_unlock_context(con);
04845 
04846    return ret;
04847 }
04848 
04849 /*
04850  * \note This functions lock contexts list, search for the right context,
04851  * call ast_context_remove_extension2, unlock contexts list and return.
04852  * In this function we are using
04853  */
04854 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
04855 {
04856    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
04857 }
04858 
04859 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
04860 {
04861    int ret = -1; /* default error return */
04862    struct ast_context *c = find_context_locked(context);
04863 
04864    if (c) { /* ... remove extension ... */
04865       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1);
04866       ast_unlock_contexts();
04867    }
04868    return ret;
04869 }
04870 
04871 /*!
04872  * \brief This functionc locks given context, search for the right extension and
04873  * fires out all peer in this extensions with given priority. If priority
04874  * is set to 0, all peers are removed. After that, unlock context and
04875  * return.
04876  * \note When do you want to call this function, make sure that &conlock is locked,
04877  * because some process can handle with your *con context before you lock
04878  * it.
04879  *
04880  */
04881 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
04882 {
04883    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
04884 }
04885 
04886 int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar, int already_locked)
04887 {
04888    struct ast_exten *exten, *prev_exten = NULL;
04889    struct ast_exten *peer;
04890    struct ast_exten ex, *exten2, *exten3;
04891    char dummy_name[1024];
04892    struct ast_exten *previous_peer = NULL;
04893    struct ast_exten *next_peer = NULL;
04894    int found = 0;
04895 
04896    if (!already_locked)
04897       ast_wrlock_context(con);
04898 
04899    /* Handle this is in the new world */
04900 
04901    /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL
04902     * peers, not just those matching the callerid. */
04903 #ifdef NEED_DEBUG
04904    ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
04905 #endif
04906 #ifdef CONTEXT_DEBUG
04907    check_contexts(__FILE__, __LINE__);
04908 #endif
04909    /* find this particular extension */
04910    ex.exten = dummy_name;
04911    ex.matchcid = matchcallerid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
04912    ex.cidmatch = callerid;
04913    ast_copy_string(dummy_name, extension, sizeof(dummy_name));
04914    exten = ast_hashtab_lookup(con->root_table, &ex);
04915    if (exten) {
04916       if (priority == 0) {
04917          exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04918          if (!exten2)
04919             ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
04920          if (con->pattern_tree) {
04921             struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04922 
04923             if (x->exten) { /* this test for safety purposes */
04924                x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04925                x->exten = 0; /* get rid of what will become a bad pointer */
04926             } else {
04927                ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
04928             }
04929          }
04930       } else {
04931          ex.priority = priority;
04932          exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
04933          if (exten2) {
04934 
04935             if (exten2->label) { /* if this exten has a label, remove that, too */
04936                exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
04937                if (!exten3)
04938                   ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
04939             }
04940 
04941             exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
04942             if (!exten3)
04943                ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
04944             if (exten2 == exten && exten2->peer) {
04945                exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04946                ast_hashtab_insert_immediate(con->root_table, exten2->peer);
04947             }
04948             if (ast_hashtab_size(exten->peer_table) == 0) {
04949                /* well, if the last priority of an exten is to be removed,
04950                   then, the extension is removed, too! */
04951                exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
04952                if (!exten3)
04953                   ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
04954                if (con->pattern_tree) {
04955                   struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04956                   if (x->exten) { /* this test for safety purposes */
04957                      x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04958                      x->exten = 0; /* get rid of what will become a bad pointer */
04959                   }
04960                }
04961             }
04962          } else {
04963             ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
04964                   priority, exten->exten, con->name);
04965          }
04966       }
04967    } else {
04968       /* hmmm? this exten is not in this pattern tree? */
04969       ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
04970             extension, con->name);
04971    }
04972 #ifdef NEED_DEBUG
04973    if (con->pattern_tree) {
04974       ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
04975       log_match_char_tree(con->pattern_tree, " ");
04976    }
04977 #endif
04978 
04979    /* scan the extension list to find first matching extension-registrar */
04980    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
04981       if (!strcmp(exten->exten, extension) &&
04982          (!registrar || !strcmp(exten->registrar, registrar)) &&
04983          (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
04984          break;
04985    }
04986    if (!exten) {
04987       /* we can't find right extension */
04988       if (!already_locked)
04989          ast_unlock_context(con);
04990       return -1;
04991    }
04992 
04993    /* scan the priority list to remove extension with exten->priority == priority */
04994    for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
04995        peer && !strcmp(peer->exten, extension) && (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
04996          peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
04997       if ((priority == 0 || peer->priority == priority) &&
04998             (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) &&
04999             (!registrar || !strcmp(peer->registrar, registrar) )) {
05000          found = 1;
05001 
05002          /* we are first priority extension? */
05003          if (!previous_peer) {
05004             /*
05005              * We are first in the priority chain, so must update the extension chain.
05006              * The next node is either the next priority or the next extension
05007              */
05008             struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
05009             if (peer->peer) {
05010                /* move the peer_table and peer_label_table down to the next peer, if
05011                   it is there */
05012                peer->peer->peer_table = peer->peer_table;
05013                peer->peer->peer_label_table = peer->peer_label_table;
05014                peer->peer_table = NULL;
05015                peer->peer_label_table = NULL;
05016             }
05017             if (!prev_exten) {   /* change the root... */
05018                con->root = next_node;
05019             } else {
05020                prev_exten->next = next_node; /* unlink */
05021             }
05022             if (peer->peer)   { /* update the new head of the pri list */
05023                peer->peer->next = peer->next;
05024             }
05025          } else { /* easy, we are not first priority in extension */
05026             previous_peer->peer = peer->peer;
05027          }
05028 
05029          /* now, free whole priority extension */
05030          destroy_exten(peer);
05031       } else {
05032          previous_peer = peer;
05033       }
05034    }
05035    if (!already_locked)
05036       ast_unlock_context(con);
05037    return found ? 0 : -1;
05038 }
05039 
05040 
05041 /*!
05042  * \note This function locks contexts list by &conlist, searches for the right context
05043  * structure, and locks the macrolock mutex in that context.
05044  * macrolock is used to limit a macro to be executed by one call at a time.
05045  */
05046 int ast_context_lockmacro(const char *context)
05047 {
05048    struct ast_context *c = NULL;
05049    int ret = -1;
05050    struct fake_context item;
05051 
05052    ast_rdlock_contexts();
05053 
05054    ast_copy_string(item.name, context, sizeof(item.name));
05055 
05056    c = ast_hashtab_lookup(contexts_table,&item);
05057    if (c)
05058       ret = 0;
05059 
05060 
05061 #ifdef NOTNOW
05062 
05063    while ((c = ast_walk_contexts(c))) {
05064       if (!strcmp(ast_get_context_name(c), context)) {
05065          ret = 0;
05066          break;
05067       }
05068    }
05069 
05070 #endif
05071    ast_unlock_contexts();
05072 
05073    /* if we found context, lock macrolock */
05074    if (ret == 0) {
05075       ret = ast_mutex_lock(&c->macrolock);
05076    }
05077 
05078    return ret;
05079 }
05080 
05081 /*!
05082  * \note This function locks contexts list by &conlist, searches for the right context
05083  * structure, and unlocks the macrolock mutex in that context.
05084  * macrolock is used to limit a macro to be executed by one call at a time.
05085  */
05086 int ast_context_unlockmacro(const char *context)
05087 {
05088    struct ast_context *c = NULL;
05089    int ret = -1;
05090    struct fake_context item;
05091 
05092    ast_rdlock_contexts();
05093 
05094    ast_copy_string(item.name, context, sizeof(item.name));
05095 
05096    c = ast_hashtab_lookup(contexts_table,&item);
05097    if (c)
05098       ret = 0;
05099 #ifdef NOTNOW
05100 
05101    while ((c = ast_walk_contexts(c))) {
05102       if (!strcmp(ast_get_context_name(c), context)) {
05103          ret = 0;
05104          break;
05105       }
05106    }
05107 
05108 #endif
05109    ast_unlock_contexts();
05110 
05111    /* if we found context, unlock macrolock */
05112    if (ret == 0) {
05113       ret = ast_mutex_unlock(&c->macrolock);
05114    }
05115 
05116    return ret;
05117 }
05118 
05119 /*! \brief Dynamically register a new dial plan application */
05120 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description, void *mod)
05121 {
05122    struct ast_app *tmp, *cur = NULL;
05123    char tmps[80];
05124    int length, res;
05125 #ifdef AST_XML_DOCS
05126    char *tmpxml;
05127 #endif
05128 
05129    AST_RWLIST_WRLOCK(&apps);
05130    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
05131       if (!(res = strcasecmp(app, tmp->name))) {
05132          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
05133          AST_RWLIST_UNLOCK(&apps);
05134          return -1;
05135       } else if (res < 0)
05136          break;
05137    }
05138 
05139    length = sizeof(*tmp) + strlen(app) + 1;
05140 
05141    if (!(tmp = ast_calloc(1, length))) {
05142       AST_RWLIST_UNLOCK(&apps);
05143       return -1;
05144    }
05145 
05146    if (ast_string_field_init(tmp, 128)) {
05147       AST_RWLIST_UNLOCK(&apps);
05148       ast_free(tmp);
05149       return -1;
05150    }
05151 
05152 #ifdef AST_XML_DOCS
05153    /* Try to lookup the docs in our XML documentation database */
05154    if (ast_strlen_zero(synopsis) && ast_strlen_zero(description)) {
05155       /* load synopsis */
05156       tmpxml = ast_xmldoc_build_synopsis("application", app);
05157       ast_string_field_set(tmp, synopsis, tmpxml);
05158       ast_free(tmpxml);
05159 
05160       /* load description */
05161       tmpxml = ast_xmldoc_build_description("application", app);
05162       ast_string_field_set(tmp, description, tmpxml);
05163       ast_free(tmpxml);
05164 
05165       /* load syntax */
05166       tmpxml = ast_xmldoc_build_syntax("application", app);
05167       ast_string_field_set(tmp, syntax, tmpxml);
05168       ast_free(tmpxml);
05169 
05170       /* load arguments */
05171       tmpxml = ast_xmldoc_build_arguments("application", app);
05172       ast_string_field_set(tmp, arguments, tmpxml);
05173       ast_free(tmpxml);
05174 
05175       /* load seealso */
05176       tmpxml = ast_xmldoc_build_seealso("application", app);
05177       ast_string_field_set(tmp, seealso, tmpxml);
05178       ast_free(tmpxml);
05179       tmp->docsrc = AST_XML_DOC;
05180    } else {
05181 #endif
05182       ast_string_field_set(tmp, synopsis, synopsis);
05183       ast_string_field_set(tmp, description, description);
05184       tmp->docsrc = AST_STATIC_DOC;
05185 #ifdef AST_XML_DOCS
05186    }
05187 #endif
05188 
05189    strcpy(tmp->name, app);
05190    tmp->execute = execute;
05191    tmp->module = mod;
05192 
05193    /* Store in alphabetical order */
05194    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
05195       if (strcasecmp(tmp->name, cur->name) < 0) {
05196          AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
05197          break;
05198       }
05199    }
05200    AST_RWLIST_TRAVERSE_SAFE_END;
05201    if (!cur)
05202       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
05203 
05204    ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
05205 
05206    AST_RWLIST_UNLOCK(&apps);
05207 
05208    return 0;
05209 }
05210 
05211 /*
05212  * Append to the list. We don't have a tail pointer because we need
05213  * to scan the list anyways to check for duplicates during insertion.
05214  */
05215 int ast_register_switch(struct ast_switch *sw)
05216 {
05217    struct ast_switch *tmp;
05218 
05219    AST_RWLIST_WRLOCK(&switches);
05220    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
05221       if (!strcasecmp(tmp->name, sw->name)) {
05222          AST_RWLIST_UNLOCK(&switches);
05223          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
05224          return -1;
05225       }
05226    }
05227    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
05228    AST_RWLIST_UNLOCK(&switches);
05229 
05230    return 0;
05231 }
05232 
05233 void ast_unregister_switch(struct ast_switch *sw)
05234 {
05235    AST_RWLIST_WRLOCK(&switches);
05236    AST_RWLIST_REMOVE(&switches, sw, list);
05237    AST_RWLIST_UNLOCK(&switches);
05238 }
05239 
05240 /*
05241  * Help for CLI commands ...
05242  */
05243 
05244 static void print_app_docs(struct ast_app *aa, int fd)
05245 {
05246    /* Maximum number of characters added by terminal coloring is 22 */
05247    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40], stxtitle[40], argtitle[40];
05248    char seealsotitle[40];
05249    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL, *syntax = NULL, *arguments = NULL;
05250    char *seealso = NULL;
05251    int syntax_size, synopsis_size, description_size, arguments_size, seealso_size;
05252 
05253    snprintf(info, sizeof(info), "\n  -= Info about application '%s' =- \n\n", aa->name);
05254    term_color(infotitle, info, COLOR_MAGENTA, 0, sizeof(infotitle));
05255 
05256    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
05257    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
05258    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
05259    term_color(argtitle, "[Arguments]\n", COLOR_MAGENTA, 0, 40);
05260    term_color(seealsotitle, "[See Also]\n", COLOR_MAGENTA, 0, 40);
05261 
05262 #ifdef AST_XML_DOCS
05263    if (aa->docsrc == AST_XML_DOC) {
05264       description = ast_xmldoc_printable(S_OR(aa->description, "Not available"), 1);
05265       arguments = ast_xmldoc_printable(S_OR(aa->arguments, "Not available"), 1);
05266       synopsis = ast_xmldoc_printable(S_OR(aa->synopsis, "Not available"), 1);
05267       seealso = ast_xmldoc_printable(S_OR(aa->seealso, "Not available"), 1);
05268 
05269       if (!synopsis || !description || !arguments || !seealso) {
05270          goto return_cleanup;
05271       }
05272    } else
05273 #endif
05274    {
05275       synopsis_size = strlen(S_OR(aa->synopsis, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
05276       synopsis = ast_malloc(synopsis_size);
05277 
05278       description_size = strlen(S_OR(aa->description, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
05279       description = ast_malloc(description_size);
05280 
05281       arguments_size = strlen(S_OR(aa->arguments, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
05282       arguments = ast_malloc(arguments_size);
05283 
05284       seealso_size = strlen(S_OR(aa->seealso, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
05285       seealso = ast_malloc(seealso_size);
05286 
05287       if (!synopsis || !description || !arguments || !seealso) {
05288          goto return_cleanup;
05289       }
05290 
05291       term_color(synopsis, S_OR(aa->synopsis, "Not available"), COLOR_CYAN, 0, synopsis_size);
05292       term_color(description, S_OR(aa->description, "Not available"),   COLOR_CYAN, 0, description_size);
05293       term_color(arguments, S_OR(aa->arguments, "Not available"), COLOR_CYAN, 0, arguments_size);
05294       term_color(seealso, S_OR(aa->seealso, "Not available"), COLOR_CYAN, 0, seealso_size);
05295    }
05296 
05297    /* Handle the syntax the same for both XML and raw docs */
05298    syntax_size = strlen(S_OR(aa->syntax, "Not Available")) + AST_TERM_MAX_ESCAPE_CHARS;
05299    if (!(syntax = ast_malloc(syntax_size))) {
05300       goto return_cleanup;
05301    }
05302    term_color(syntax, S_OR(aa->syntax, "Not available"), COLOR_CYAN, 0, syntax_size);
05303 
05304    ast_cli(fd, "%s%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n\n%s%s\n",
05305          infotitle, syntitle, synopsis, destitle, description,
05306          stxtitle, syntax, argtitle, arguments, seealsotitle, seealso);
05307 
05308 return_cleanup:
05309    ast_free(description);
05310    ast_free(arguments);
05311    ast_free(synopsis);
05312    ast_free(seealso);
05313    ast_free(syntax);
05314 }
05315 
05316 /*
05317  * \brief 'show application' CLI command implementation function...
05318  */
05319 static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05320 {
05321    struct ast_app *aa;
05322    int app, no_registered_app = 1;
05323    char *ret = NULL;
05324    int which = 0;
05325    int wordlen;
05326 
05327    switch (cmd) {
05328    case CLI_INIT:
05329       e->command = "core show application";
05330       e->usage =
05331          "Usage: core show application <application> [<application> [<application> [...]]]\n"
05332          "       Describes a particular application.\n";
05333       return NULL;
05334    case CLI_GENERATE:
05335       /*
05336        * There is a possibility to show informations about more than one
05337        * application at one time. You can type 'show application Dial Echo' and
05338        * you will see informations about these two applications ...
05339        */
05340       wordlen = strlen(a->word);
05341       /* return the n-th [partial] matching entry */
05342       AST_RWLIST_RDLOCK(&apps);
05343       AST_RWLIST_TRAVERSE(&apps, aa, list) {
05344          if (!strncasecmp(a->word, aa->name, wordlen) && ++which > a->n) {
05345             ret = ast_strdup(aa->name);
05346             break;
05347          }
05348       }
05349       AST_RWLIST_UNLOCK(&apps);
05350 
05351       return ret;
05352    }
05353 
05354    if (a->argc < 4) {
05355       return CLI_SHOWUSAGE;
05356    }
05357 
05358    AST_RWLIST_RDLOCK(&apps);
05359    AST_RWLIST_TRAVERSE(&apps, aa, list) {
05360       /* Check for each app that was supplied as an argument */
05361       for (app = 3; app < a->argc; app++) {
05362          if (strcasecmp(aa->name, a->argv[app])) {
05363             continue;
05364          }
05365 
05366          /* We found it! */
05367          no_registered_app = 0;
05368 
05369          print_app_docs(aa, a->fd);
05370       }
05371    }
05372    AST_RWLIST_UNLOCK(&apps);
05373 
05374    /* we found at least one app? no? */
05375    if (no_registered_app) {
05376       ast_cli(a->fd, "Your application(s) is (are) not registered\n");
05377       return CLI_FAILURE;
05378    }
05379 
05380    return CLI_SUCCESS;
05381 }
05382 
05383 /*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
05384 static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05385 {
05386    struct ast_hint *hint;
05387    int num = 0;
05388    int watchers;
05389    struct ao2_iterator i;
05390 
05391    switch (cmd) {
05392    case CLI_INIT:
05393       e->command = "core show hints";
05394       e->usage =
05395          "Usage: core show hints\n"
05396          "       List registered hints\n";
05397       return NULL;
05398    case CLI_GENERATE:
05399       return NULL;
05400    }
05401 
05402    if (ao2_container_count(hints) == 0) {
05403       ast_cli(a->fd, "There are no registered dialplan hints\n");
05404       return CLI_SUCCESS;
05405    }
05406    /* ... we have hints ... */
05407    ast_cli(a->fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
05408 
05409    i = ao2_iterator_init(hints, 0);
05410    for (hint = ao2_iterator_next(&i); hint; ao2_ref(hint, -1), hint = ao2_iterator_next(&i)) {
05411 
05412       watchers = ao2_container_count(hint->callbacks);
05413       ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
05414          ast_get_extension_name(hint->exten),
05415          ast_get_context_name(ast_get_extension_context(hint->exten)),
05416          ast_get_extension_app(hint->exten),
05417          ast_extension_state2str(hint->laststate), watchers);
05418       num++;
05419    }
05420 
05421    ao2_iterator_destroy(&i);
05422    ast_cli(a->fd, "----------------\n");
05423    ast_cli(a->fd, "- %d hints registered\n", num);
05424    return CLI_SUCCESS;
05425 }
05426 
05427 /*! \brief autocomplete for CLI command 'core show hint' */
05428 static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
05429 {
05430    struct ast_hint *hint;
05431    char *ret = NULL;
05432    int which = 0;
05433    int wordlen;
05434    struct ao2_iterator i;
05435 
05436    if (pos != 3)
05437       return NULL;
05438 
05439    wordlen = strlen(word);
05440 
05441    /* walk through all hints */
05442    i = ao2_iterator_init(hints, 0);
05443    for (hint = ao2_iterator_next(&i); hint; ao2_unlock(hint), ao2_ref(hint, -1), hint = ao2_iterator_next(&i)) {
05444       ao2_lock(hint);
05445       if (!strncasecmp(word, hint->exten ? ast_get_extension_name(hint->exten) : "", wordlen) && ++which > state) {
05446          ret = ast_strdup(ast_get_extension_name(hint->exten));
05447          ao2_unlock(hint);
05448          break;
05449       }
05450    }
05451    ao2_iterator_destroy(&i);
05452 
05453    return ret;
05454 }
05455 
05456 /*! \brief  handle_show_hint: CLI support for listing registered dial plan hint */
05457 static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05458 {
05459    struct ast_hint *hint;
05460    int watchers;
05461    int num = 0, extenlen;
05462    struct ao2_iterator i;
05463 
05464    switch (cmd) {
05465    case CLI_INIT:
05466       e->command = "core show hint";
05467       e->usage =
05468          "Usage: core show hint <exten>\n"
05469          "       List registered hint\n";
05470       return NULL;
05471    case CLI_GENERATE:
05472       return complete_core_show_hint(a->line, a->word, a->pos, a->n);
05473    }
05474 
05475    if (a->argc < 4)
05476       return CLI_SHOWUSAGE;
05477 
05478    if (ao2_container_count(hints) == 0) {
05479       ast_cli(a->fd, "There are no registered dialplan hints\n");
05480       return CLI_SUCCESS;
05481    }
05482    
05483    extenlen = strlen(a->argv[3]);
05484    i = ao2_iterator_init(hints, 0);
05485    for (hint = ao2_iterator_next(&i); hint; ao2_unlock(hint), ao2_ref(hint, -1), hint = ao2_iterator_next(&i)) {
05486       ao2_lock(hint);
05487       if (!strncasecmp(hint->exten ? ast_get_extension_name(hint->exten) : "", a->argv[3], extenlen)) {
05488          watchers = ao2_container_count(hint->callbacks);
05489          ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
05490             ast_get_extension_name(hint->exten),
05491             ast_get_context_name(ast_get_extension_context(hint->exten)),
05492             ast_get_extension_app(hint->exten),
05493             ast_extension_state2str(hint->laststate), watchers);
05494          num++;
05495       }
05496    }
05497    ao2_iterator_destroy(&i);
05498    if (!num)
05499       ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
05500    else
05501       ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
05502    return CLI_SUCCESS;
05503 }
05504 
05505 
05506 /*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
05507 static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05508 {
05509    struct ast_switch *sw;
05510 
05511    switch (cmd) {
05512    case CLI_INIT:
05513       e->command = "core show switches";
05514       e->usage =
05515          "Usage: core show switches\n"
05516          "       List registered switches\n";
05517       return NULL;
05518    case CLI_GENERATE:
05519       return NULL;
05520    }
05521 
05522    AST_RWLIST_RDLOCK(&switches);
05523 
05524    if (AST_RWLIST_EMPTY(&switches)) {
05525       AST_RWLIST_UNLOCK(&switches);
05526       ast_cli(a->fd, "There are no registered alternative switches\n");
05527       return CLI_SUCCESS;
05528    }
05529 
05530    ast_cli(a->fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
05531    AST_RWLIST_TRAVERSE(&switches, sw, list)
05532       ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
05533 
05534    AST_RWLIST_UNLOCK(&switches);
05535 
05536    return CLI_SUCCESS;
05537 }
05538 
05539 static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05540 {
05541    struct ast_app *aa;
05542    int like = 0, describing = 0;
05543    int total_match = 0;    /* Number of matches in like clause */
05544    int total_apps = 0;     /* Number of apps registered */
05545    static char* choices[] = { "like", "describing", NULL };
05546 
05547    switch (cmd) {
05548    case CLI_INIT:
05549       e->command = "core show applications [like|describing]";
05550       e->usage =
05551          "Usage: core show applications [{like|describing} <text>]\n"
05552          "       List applications which are currently available.\n"
05553          "       If 'like', <text> will be a substring of the app name\n"
05554          "       If 'describing', <text> will be a substring of the description\n";
05555       return NULL;
05556    case CLI_GENERATE:
05557       return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
05558    }
05559 
05560    AST_RWLIST_RDLOCK(&apps);
05561 
05562    if (AST_RWLIST_EMPTY(&apps)) {
05563       ast_cli(a->fd, "There are no registered applications\n");
05564       AST_RWLIST_UNLOCK(&apps);
05565       return CLI_SUCCESS;
05566    }
05567 
05568    /* core list applications like <keyword> */
05569    if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
05570       like = 1;
05571    } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
05572       describing = 1;
05573    }
05574 
05575    /* core list applications describing <keyword1> [<keyword2>] [...] */
05576    if ((!like) && (!describing)) {
05577       ast_cli(a->fd, "    -= Registered Asterisk Applications =-\n");
05578    } else {
05579       ast_cli(a->fd, "    -= Matching Asterisk Applications =-\n");
05580    }
05581 
05582    AST_RWLIST_TRAVERSE(&apps, aa, list) {
05583       int printapp = 0;
05584       total_apps++;
05585       if (like) {
05586          if (strcasestr(aa->name, a->argv[4])) {
05587             printapp = 1;
05588             total_match++;
05589          }
05590       } else if (describing) {
05591          if (aa->description) {
05592             /* Match all words on command line */
05593             int i;
05594             printapp = 1;
05595             for (i = 4; i < a->argc; i++) {
05596                if (!strcasestr(aa->description, a->argv[i])) {
05597                   printapp = 0;
05598                } else {
05599                   total_match++;
05600                }
05601             }
05602          }
05603       } else {
05604          printapp = 1;
05605       }
05606 
05607       if (printapp) {
05608          ast_cli(a->fd,"  %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
05609       }
05610    }
05611    if ((!like) && (!describing)) {
05612       ast_cli(a->fd, "    -= %d Applications Registered =-\n",total_apps);
05613    } else {
05614       ast_cli(a->fd, "    -= %d Applications Matching =-\n",total_match);
05615    }
05616 
05617    AST_RWLIST_UNLOCK(&apps);
05618 
05619    return CLI_SUCCESS;
05620 }
05621 
05622 /*
05623  * 'show dialplan' CLI command implementation functions ...
05624  */
05625 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
05626    int state)
05627 {
05628    struct ast_context *c = NULL;
05629    char *ret = NULL;
05630    int which = 0;
05631    int wordlen;
05632 
05633    /* we are do completion of [exten@]context on second position only */
05634    if (pos != 2)
05635       return NULL;
05636 
05637    ast_rdlock_contexts();
05638 
05639    wordlen = strlen(word);
05640 
05641    /* walk through all contexts and return the n-th match */
05642    while ( (c = ast_walk_contexts(c)) ) {
05643       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
05644          ret = ast_strdup(ast_get_context_name(c));
05645          break;
05646       }
05647    }
05648 
05649    ast_unlock_contexts();
05650 
05651    return ret;
05652 }
05653 
05654 /*! \brief Counters for the show dialplan manager command */
05655 struct dialplan_counters {
05656    int total_items;
05657    int total_context;
05658    int total_exten;
05659    int total_prio;
05660    int context_existence;
05661    int extension_existence;
05662 };
05663 
05664 /*! \brief helper function to print an extension */
05665 static void print_ext(struct ast_exten *e, char * buf, int buflen)
05666 {
05667    int prio = ast_get_extension_priority(e);
05668    if (prio == PRIORITY_HINT) {
05669       snprintf(buf, buflen, "hint: %s",
05670          ast_get_extension_app(e));
05671    } else {
05672       snprintf(buf, buflen, "%d. %s(%s)",
05673          prio, ast_get_extension_app(e),
05674          (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
05675    }
05676 }
05677 
05678 /* XXX not verified */
05679 static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
05680 {
05681    struct ast_context *c = NULL;
05682    int res = 0, old_total_exten = dpc->total_exten;
05683 
05684    ast_rdlock_contexts();
05685 
05686    /* walk all contexts ... */
05687    while ( (c = ast_walk_contexts(c)) ) {
05688       struct ast_exten *e;
05689       struct ast_include *i;
05690       struct ast_ignorepat *ip;
05691       char buf[256], buf2[256];
05692       int context_info_printed = 0;
05693 
05694       if (context && strcmp(ast_get_context_name(c), context))
05695          continue;   /* skip this one, name doesn't match */
05696 
05697       dpc->context_existence = 1;
05698 
05699       ast_rdlock_context(c);
05700 
05701       /* are we looking for exten too? if yes, we print context
05702        * only if we find our extension.
05703        * Otherwise print context even if empty ?
05704        * XXX i am not sure how the rinclude is handled.
05705        * I think it ought to go inside.
05706        */
05707       if (!exten) {
05708          dpc->total_context++;
05709          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05710             ast_get_context_name(c), ast_get_context_registrar(c));
05711          context_info_printed = 1;
05712       }
05713 
05714       /* walk extensions ... */
05715       e = NULL;
05716       while ( (e = ast_walk_context_extensions(c, e)) ) {
05717          struct ast_exten *p;
05718 
05719          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
05720             continue;   /* skip, extension match failed */
05721 
05722          dpc->extension_existence = 1;
05723 
05724          /* may we print context info? */
05725          if (!context_info_printed) {
05726             dpc->total_context++;
05727             if (rinclude) { /* TODO Print more info about rinclude */
05728                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
05729                   ast_get_context_name(c), ast_get_context_registrar(c));
05730             } else {
05731                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05732                   ast_get_context_name(c), ast_get_context_registrar(c));
05733             }
05734             context_info_printed = 1;
05735          }
05736          dpc->total_prio++;
05737 
05738          /* write extension name and first peer */
05739          if (e->matchcid)
05740             snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
05741          else
05742             snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
05743 
05744          print_ext(e, buf2, sizeof(buf2));
05745 
05746          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
05747             ast_get_extension_registrar(e));
05748 
05749          dpc->total_exten++;
05750          /* walk next extension peers */
05751          p = e;   /* skip the first one, we already got it */
05752          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05753             const char *el = ast_get_extension_label(p);
05754             dpc->total_prio++;
05755             if (el)
05756                snprintf(buf, sizeof(buf), "   [%s]", el);
05757             else
05758                buf[0] = '\0';
05759             print_ext(p, buf2, sizeof(buf2));
05760 
05761             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
05762                ast_get_extension_registrar(p));
05763          }
05764       }
05765 
05766       /* walk included and write info ... */
05767       i = NULL;
05768       while ( (i = ast_walk_context_includes(c, i)) ) {
05769          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
05770          if (exten) {
05771             /* Check all includes for the requested extension */
05772             if (includecount >= AST_PBX_MAX_STACK) {
05773                ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
05774             } else {
05775                int dupe = 0;
05776                int x;
05777                for (x = 0; x < includecount; x++) {
05778                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
05779                      dupe++;
05780                      break;
05781                   }
05782                }
05783                if (!dupe) {
05784                   includes[includecount] = ast_get_include_name(i);
05785                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
05786                } else {
05787                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
05788                }
05789             }
05790          } else {
05791             ast_cli(fd, "  Include =>        %-45s [%s]\n",
05792                buf, ast_get_include_registrar(i));
05793          }
05794       }
05795 
05796       /* walk ignore patterns and write info ... */
05797       ip = NULL;
05798       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05799          const char *ipname = ast_get_ignorepat_name(ip);
05800          char ignorepat[AST_MAX_EXTENSION];
05801          snprintf(buf, sizeof(buf), "'%s'", ipname);
05802          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05803          if (!exten || ast_extension_match(ignorepat, exten)) {
05804             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
05805                buf, ast_get_ignorepat_registrar(ip));
05806          }
05807       }
05808       if (!rinclude) {
05809          struct ast_sw *sw = NULL;
05810          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05811             snprintf(buf, sizeof(buf), "'%s/%s'",
05812                ast_get_switch_name(sw),
05813                ast_get_switch_data(sw));
05814             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
05815                buf, ast_get_switch_registrar(sw));
05816          }
05817       }
05818 
05819       ast_unlock_context(c);
05820 
05821       /* if we print something in context, make an empty line */
05822       if (context_info_printed)
05823          ast_cli(fd, "\n");
05824    }
05825    ast_unlock_contexts();
05826 
05827    return (dpc->total_exten == old_total_exten) ? -1 : res;
05828 }
05829 
05830 static int show_debug_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
05831 {
05832    struct ast_context *c = NULL;
05833    int res = 0, old_total_exten = dpc->total_exten;
05834 
05835    ast_cli(fd,"\n     In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
05836 
05837    ast_cli(fd,"\n           Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
05838    ast_cli(fd,    "                        Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
05839    ast_cli(fd,    "                              <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
05840    ast_cli(fd,    "                              <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
05841    ast_cli(fd,    "                              [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
05842    ast_cli(fd,    "                        In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
05843    ast_cli(fd,    "                        are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
05844    ast_rdlock_contexts();
05845 
05846    /* walk all contexts ... */
05847    while ( (c = ast_walk_contexts(c)) ) {
05848       int context_info_printed = 0;
05849 
05850       if (context && strcmp(ast_get_context_name(c), context))
05851          continue;   /* skip this one, name doesn't match */
05852 
05853       dpc->context_existence = 1;
05854 
05855       if (!c->pattern_tree)
05856          ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
05857 
05858       ast_rdlock_context(c);
05859 
05860       dpc->total_context++;
05861       ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05862          ast_get_context_name(c), ast_get_context_registrar(c));
05863       context_info_printed = 1;
05864 
05865       if (c->pattern_tree)
05866       {
05867          cli_match_char_tree(c->pattern_tree, " ", fd);
05868       } else {
05869          ast_cli(fd,"\n     No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
05870       }
05871 
05872       ast_unlock_context(c);
05873 
05874       /* if we print something in context, make an empty line */
05875       if (context_info_printed)
05876          ast_cli(fd, "\n");
05877    }
05878    ast_unlock_contexts();
05879 
05880    return (dpc->total_exten == old_total_exten) ? -1 : res;
05881 }
05882 
05883 static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05884 {
05885    char *exten = NULL, *context = NULL;
05886    /* Variables used for different counters */
05887    struct dialplan_counters counters;
05888    const char *incstack[AST_PBX_MAX_STACK];
05889 
05890    switch (cmd) {
05891    case CLI_INIT:
05892       e->command = "dialplan show";
05893       e->usage =
05894          "Usage: dialplan show [[exten@]context]\n"
05895          "       Show dialplan\n";
05896       return NULL;
05897    case CLI_GENERATE:
05898       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05899    }
05900 
05901    memset(&counters, 0, sizeof(counters));
05902 
05903    if (a->argc != 2 && a->argc != 3)
05904       return CLI_SHOWUSAGE;
05905 
05906    /* we obtain [exten@]context? if yes, split them ... */
05907    if (a->argc == 3) {
05908       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05909          context = ast_strdupa(a->argv[2]);
05910          exten = strsep(&context, "@");
05911          /* change empty strings to NULL */
05912          if (ast_strlen_zero(exten))
05913             exten = NULL;
05914       } else { /* no '@' char, only context given */
05915          context = a->argv[2];
05916       }
05917       if (ast_strlen_zero(context))
05918          context = NULL;
05919    }
05920    /* else Show complete dial plan, context and exten are NULL */
05921    show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05922 
05923    /* check for input failure and throw some error messages */
05924    if (context && !counters.context_existence) {
05925       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05926       return CLI_FAILURE;
05927    }
05928 
05929    if (exten && !counters.extension_existence) {
05930       if (context)
05931          ast_cli(a->fd, "There is no existence of %s@%s extension\n",
05932             exten, context);
05933       else
05934          ast_cli(a->fd,
05935             "There is no existence of '%s' extension in all contexts\n",
05936             exten);
05937       return CLI_FAILURE;
05938    }
05939 
05940    ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
05941             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
05942             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
05943             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05944 
05945    /* everything ok */
05946    return CLI_SUCCESS;
05947 }
05948 
05949 /*! \brief Send ack once */
05950 static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05951 {
05952    char *exten = NULL, *context = NULL;
05953    /* Variables used for different counters */
05954    struct dialplan_counters counters;
05955    const char *incstack[AST_PBX_MAX_STACK];
05956 
05957    switch (cmd) {
05958    case CLI_INIT:
05959       e->command = "dialplan debug";
05960       e->usage =
05961          "Usage: dialplan debug [context]\n"
05962          "       Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
05963       return NULL;
05964    case CLI_GENERATE:
05965       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05966    }
05967 
05968    memset(&counters, 0, sizeof(counters));
05969 
05970    if (a->argc != 2 && a->argc != 3)
05971       return CLI_SHOWUSAGE;
05972 
05973    /* we obtain [exten@]context? if yes, split them ... */
05974    /* note: we ignore the exten totally here .... */
05975    if (a->argc == 3) {
05976       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05977          context = ast_strdupa(a->argv[2]);
05978          exten = strsep(&context, "@");
05979          /* change empty strings to NULL */
05980          if (ast_strlen_zero(exten))
05981             exten = NULL;
05982       } else { /* no '@' char, only context given */
05983          context = a->argv[2];
05984       }
05985       if (ast_strlen_zero(context))
05986          context = NULL;
05987    }
05988    /* else Show complete dial plan, context and exten are NULL */
05989    show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05990 
05991    /* check for input failure and throw some error messages */
05992    if (context && !counters.context_existence) {
05993       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05994       return CLI_FAILURE;
05995    }
05996 
05997 
05998    ast_cli(a->fd,"-= %d %s. =-\n",
05999          counters.total_context, counters.total_context == 1 ? "context" : "contexts");
06000 
06001    /* everything ok */
06002    return CLI_SUCCESS;
06003 }
06004 
06005 /*! \brief Send ack once */
06006 static void manager_dpsendack(struct mansession *s, const struct message *m)
06007 {
06008    astman_send_listack(s, m, "DialPlan list will follow", "start");
06009 }
06010 
06011 /*! \brief Show dialplan extensions
06012  * XXX this function is similar but not exactly the same as the CLI's
06013  * show dialplan. Must check whether the difference is intentional or not.
06014  */
06015 static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
06016                const char *actionidtext, const char *context,
06017                const char *exten, struct dialplan_counters *dpc,
06018                struct ast_include *rinclude)
06019 {
06020    struct ast_context *c;
06021    int res = 0, old_total_exten = dpc->total_exten;
06022 
06023    if (ast_strlen_zero(exten))
06024       exten = NULL;
06025    if (ast_strlen_zero(context))
06026       context = NULL;
06027 
06028    ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
06029 
06030    /* try to lock contexts */
06031    if (ast_rdlock_contexts()) {
06032       astman_send_error(s, m, "Failed to lock contexts");
06033       ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
06034       return -1;
06035    }
06036 
06037    c = NULL;      /* walk all contexts ... */
06038    while ( (c = ast_walk_contexts(c)) ) {
06039       struct ast_exten *e;
06040       struct ast_include *i;
06041       struct ast_ignorepat *ip;
06042 
06043       if (context && strcmp(ast_get_context_name(c), context) != 0)
06044          continue;   /* not the name we want */
06045 
06046       dpc->context_existence = 1;
06047 
06048       ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
06049 
06050       if (ast_rdlock_context(c)) {  /* failed to lock */
06051          ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
06052          continue;
06053       }
06054 
06055       /* XXX note- an empty context is not printed */
06056       e = NULL;      /* walk extensions in context  */
06057       while ( (e = ast_walk_context_extensions(c, e)) ) {
06058          struct ast_exten *p;
06059 
06060          /* looking for extension? is this our extension? */
06061          if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
06062             /* not the one we are looking for, continue */
06063             ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
06064             continue;
06065          }
06066          ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
06067 
06068          dpc->extension_existence = 1;
06069 
06070          /* may we print context info? */
06071          dpc->total_context++;
06072          dpc->total_exten++;
06073 
06074          p = NULL;      /* walk next extension peers */
06075          while ( (p = ast_walk_extension_priorities(e, p)) ) {
06076             int prio = ast_get_extension_priority(p);
06077 
06078             dpc->total_prio++;
06079             if (!dpc->total_items++)
06080                manager_dpsendack(s, m);
06081             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
06082             astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
06083 
06084             /* XXX maybe make this conditional, if p != e ? */
06085             if (ast_get_extension_label(p))
06086                astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
06087 
06088             if (prio == PRIORITY_HINT) {
06089                astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
06090             } else {
06091                astman_append(s, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p));
06092             }
06093             astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
06094          }
06095       }
06096 
06097       i = NULL;      /* walk included and write info ... */
06098       while ( (i = ast_walk_context_includes(c, i)) ) {
06099          if (exten) {
06100             /* Check all includes for the requested extension */
06101             manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
06102          } else {
06103             if (!dpc->total_items++)
06104                manager_dpsendack(s, m);
06105             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
06106             astman_append(s, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
06107             astman_append(s, "\r\n");
06108             ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
06109          }
06110       }
06111 
06112       ip = NULL;  /* walk ignore patterns and write info ... */
06113       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
06114          const char *ipname = ast_get_ignorepat_name(ip);
06115          char ignorepat[AST_MAX_EXTENSION];
06116 
06117          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
06118          if (!exten || ast_extension_match(ignorepat, exten)) {
06119             if (!dpc->total_items++)
06120                manager_dpsendack(s, m);
06121             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
06122             astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
06123             astman_append(s, "\r\n");
06124          }
06125       }
06126       if (!rinclude) {
06127          struct ast_sw *sw = NULL;
06128          while ( (sw = ast_walk_context_switches(c, sw)) ) {
06129             if (!dpc->total_items++)
06130                manager_dpsendack(s, m);
06131             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
06132             astman_append(s, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw));  
06133             astman_append(s, "\r\n");
06134             ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
06135          }
06136       }
06137 
06138       ast_unlock_context(c);
06139    }
06140    ast_unlock_contexts();
06141 
06142    if (dpc->total_exten == old_total_exten) {
06143       ast_debug(3, "manager_show_dialplan: Found nothing new\n");
06144       /* Nothing new under the sun */
06145       return -1;
06146    } else {
06147       return res;
06148    }
06149 }
06150 
06151 /*! \brief  Manager listing of dial plan */
06152 static int manager_show_dialplan(struct mansession *s, const struct message *m)
06153 {
06154    const char *exten, *context;
06155    const char *id = astman_get_header(m, "ActionID");
06156    char idtext[256];
06157    int res;
06158 
06159    /* Variables used for different counters */
06160    struct dialplan_counters counters;
06161 
06162    if (!ast_strlen_zero(id))
06163       snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
06164    else
06165       idtext[0] = '\0';
06166 
06167    memset(&counters, 0, sizeof(counters));
06168 
06169    exten = astman_get_header(m, "Extension");
06170    context = astman_get_header(m, "Context");
06171 
06172    res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
06173 
06174    if (context && !counters.context_existence) {
06175       char errorbuf[BUFSIZ];
06176 
06177       snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
06178       astman_send_error(s, m, errorbuf);
06179       return 0;
06180    }
06181    if (exten && !counters.extension_existence) {
06182       char errorbuf[BUFSIZ];
06183 
06184       if (context)
06185          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
06186       else
06187          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
06188       astman_send_error(s, m, errorbuf);
06189       return 0;
06190    }
06191 
06192    astman_append(s, "Event: ShowDialPlanComplete\r\n"
06193       "EventList: Complete\r\n"
06194       "ListItems: %d\r\n"
06195       "ListExtensions: %d\r\n"
06196       "ListPriorities: %d\r\n"
06197       "ListContexts: %d\r\n"
06198       "%s"
06199       "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
06200 
06201    /* everything ok */
06202    return 0;
06203 }
06204 
06205 static char mandescr_show_dialplan[] =
06206 "Description: Show dialplan contexts and extensions.\n"
06207 "Be aware that showing the full dialplan may take a lot of capacity\n"
06208 "Variables: \n"
06209 " ActionID: <id>     Action ID for this AMI transaction (optional)\n"
06210 " Extension: <extension>   Extension (Optional)\n"
06211 " Context: <context>    Context (Optional)\n"
06212 "\n";
06213 
06214 /*! \brief CLI support for listing global variables in a parseable way */
06215 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06216 {
06217    int i = 0;
06218    struct ast_var_t *newvariable;
06219 
06220    switch (cmd) {
06221    case CLI_INIT:
06222       e->command = "dialplan show globals";
06223       e->usage =
06224          "Usage: dialplan show globals\n"
06225          "       List current global dialplan variables and their values\n";
06226       return NULL;
06227    case CLI_GENERATE:
06228       return NULL;
06229    }
06230 
06231    ast_rwlock_rdlock(&globalslock);
06232    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
06233       i++;
06234       ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
06235    }
06236    ast_rwlock_unlock(&globalslock);
06237    ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
06238 
06239    return CLI_SUCCESS;
06240 }
06241 
06242 #ifdef AST_DEVMODE
06243 static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06244 {
06245    struct ast_devstate_aggregate agg;
06246    int i, j, exten, combined;
06247 
06248    switch (cmd) {
06249    case CLI_INIT:
06250       e->command = "core show device2extenstate";
06251       e->usage =
06252          "Usage: core show device2extenstate\n"
06253          "       Lists device state to extension state combinations.\n";
06254    case CLI_GENERATE:
06255       return NULL;
06256    }
06257    for (i = 0; i < AST_DEVICE_TOTAL; i++) {
06258       for (j = 0; j < AST_DEVICE_TOTAL; j++) {
06259          ast_devstate_aggregate_init(&agg);
06260          ast_devstate_aggregate_add(&agg, i);
06261          ast_devstate_aggregate_add(&agg, j);
06262          combined = ast_devstate_aggregate_result(&agg);
06263          exten = ast_devstate_to_extenstate(combined);
06264          ast_cli(a->fd, "\n Exten:%14s  CombinedDevice:%12s  Dev1:%12s  Dev2:%12s", ast_extension_state2str(exten), ast_devstate_str(combined), ast_devstate_str(j), ast_devstate_str(i));
06265       }
06266    }
06267    ast_cli(a->fd, "\n");
06268    return CLI_SUCCESS;
06269 }
06270 #endif
06271 
06272 /*! \brief CLI support for listing chanvar's variables in a parseable way */
06273 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06274 {
06275    struct ast_channel *chan = NULL;
06276    struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */
06277 
06278    switch (cmd) {
06279    case CLI_INIT:
06280       e->command = "dialplan show chanvar";
06281       e->usage =
06282          "Usage: dialplan show chanvar <channel>\n"
06283          "       List current channel variables and their values\n";
06284       return NULL;
06285    case CLI_GENERATE:
06286       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
06287    }
06288 
06289    if (a->argc != e->args + 1)
06290       return CLI_SHOWUSAGE;
06291 
06292    if (!(chan = ast_get_channel_by_name_locked(a->argv[e->args]))) {
06293       ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
06294       return CLI_FAILURE;
06295    }
06296 
06297    pbx_builtin_serialize_variables(chan, &vars);
06298    if (ast_str_strlen(vars)) {
06299       ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], ast_str_buffer(vars));
06300    }
06301    ast_channel_unlock(chan);
06302    return CLI_SUCCESS;
06303 }
06304 
06305 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06306 {
06307    switch (cmd) {
06308    case CLI_INIT:
06309       e->command = "dialplan set global";
06310       e->usage =
06311          "Usage: dialplan set global <name> <value>\n"
06312          "       Set global dialplan variable <name> to <value>\n";
06313       return NULL;
06314    case CLI_GENERATE:
06315       return NULL;
06316    }
06317 
06318    if (a->argc != e->args + 2)
06319       return CLI_SHOWUSAGE;
06320 
06321    pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
06322    ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
06323 
06324    return CLI_SUCCESS;
06325 }
06326 
06327 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06328 {
06329    struct ast_channel *chan;
06330    const char *chan_name, *var_name, *var_value;
06331 
06332    switch (cmd) {
06333    case CLI_INIT:
06334       e->command = "dialplan set chanvar";
06335       e->usage =
06336          "Usage: dialplan set chanvar <channel> <varname> <value>\n"
06337          "       Set channel variable <varname> to <value>\n";
06338       return NULL;
06339    case CLI_GENERATE:
06340       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
06341    }
06342 
06343    if (a->argc != e->args + 3)
06344       return CLI_SHOWUSAGE;
06345 
06346    chan_name = a->argv[e->args];
06347    var_name = a->argv[e->args + 1];
06348    var_value = a->argv[e->args + 2];
06349 
06350    if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
06351       ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
06352       return CLI_FAILURE;
06353    }
06354 
06355    pbx_builtin_setvar_helper(chan, var_name, var_value);
06356    ast_channel_unlock(chan);
06357    ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
06358 
06359    return CLI_SUCCESS;
06360 }
06361 
06362 static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06363 {
06364    int oldval = 0;
06365 
06366    switch (cmd) {
06367    case CLI_INIT:
06368       e->command = "dialplan set extenpatternmatchnew true";
06369       e->usage =
06370          "Usage: dialplan set extenpatternmatchnew true|false\n"
06371          "       Use the NEW extension pattern matching algorithm, true or false.\n";
06372       return NULL;
06373    case CLI_GENERATE:
06374       return NULL;
06375    }
06376 
06377    if (a->argc != 4)
06378       return CLI_SHOWUSAGE;
06379 
06380    oldval =  pbx_set_extenpatternmatchnew(1);
06381 
06382    if (oldval)
06383       ast_cli(a->fd, "\n    -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
06384    else
06385       ast_cli(a->fd, "\n    -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
06386 
06387    return CLI_SUCCESS;
06388 }
06389 
06390 static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
06391 {
06392    int oldval = 0;
06393 
06394    switch (cmd) {
06395    case CLI_INIT:
06396       e->command = "dialplan set extenpatternmatchnew false";
06397       e->usage =
06398          "Usage: dialplan set extenpatternmatchnew true|false\n"
06399          "       Use the NEW extension pattern matching algorithm, true or false.\n";
06400       return NULL;
06401    case CLI_GENERATE:
06402       return NULL;
06403    }
06404 
06405    if (a->argc != 4)
06406       return CLI_SHOWUSAGE;
06407 
06408    oldval =  pbx_set_extenpatternmatchnew(0);
06409 
06410    if (!oldval)
06411       ast_cli(a->fd, "\n    -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
06412    else
06413       ast_cli(a->fd, "\n    -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
06414 
06415    return CLI_SUCCESS;
06416 }
06417 
06418 /*
06419  * CLI entries for upper commands ...
06420  */
06421 static struct ast_cli_entry pbx_cli[] = {
06422    AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
06423    AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
06424    AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
06425    AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
06426    AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
06427    AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables"),
06428 #ifdef AST_DEVMODE
06429    AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
06430 #endif
06431    AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
06432    AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
06433    AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
06434    AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable"),
06435    AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable"),
06436    AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
06437    AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
06438    AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
06439    AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
06440 };
06441 
06442 static void unreference_cached_app(struct ast_app *app)
06443 {
06444    struct ast_context *context = NULL;
06445    struct ast_exten *eroot = NULL, *e = NULL;
06446 
06447    ast_rdlock_contexts();
06448    while ((context = ast_walk_contexts(context))) {
06449       while ((eroot = ast_walk_context_extensions(context, eroot))) {
06450          while ((e = ast_walk_extension_priorities(eroot, e))) {
06451             if (e->cached_app == app)
06452                e->cached_app = NULL;
06453          }
06454       }
06455    }
06456    ast_unlock_contexts();
06457 
06458    return;
06459 }
06460 
06461 int ast_unregister_application(const char *app)
06462 {
06463    struct ast_app *tmp;
06464 
06465    AST_RWLIST_WRLOCK(&apps);
06466    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
06467       if (!strcasecmp(app, tmp->name)) {
06468          unreference_cached_app(tmp);
06469          AST_RWLIST_REMOVE_CURRENT(list);
06470          ast_verb(2, "Unregistered application '%s'\n", tmp->name);
06471          ast_string_field_free_memory(tmp);
06472          ast_free(tmp);
06473          break;
06474       }
06475    }
06476    AST_RWLIST_TRAVERSE_SAFE_END;
06477    AST_RWLIST_UNLOCK(&apps);
06478 
06479    return tmp ? 0 : -1;
06480 }
06481 
06482 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
06483 {
06484    struct ast_context *tmp, **local_contexts;
06485    struct fake_context search;
06486    int length = sizeof(struct ast_context) + strlen(name) + 1;
06487 
06488    if (!contexts_table) {
06489       contexts_table = ast_hashtab_create(17,
06490                                  ast_hashtab_compare_contexts,
06491                                  ast_hashtab_resize_java,
06492                                  ast_hashtab_newsize_java,
06493                                  ast_hashtab_hash_contexts,
06494                                  0);
06495    }
06496 
06497    ast_copy_string(search.name, name, sizeof(search.name));
06498    if (!extcontexts) {
06499       ast_rdlock_contexts();
06500       local_contexts = &contexts;
06501       tmp = ast_hashtab_lookup(contexts_table, &search);
06502       ast_unlock_contexts();
06503       if (tmp) {
06504          tmp->refcount++;
06505          return tmp;
06506       }
06507    } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
06508       local_contexts = extcontexts;
06509       tmp = ast_hashtab_lookup(exttable, &search);
06510       if (tmp) {
06511          tmp->refcount++;
06512          return tmp;
06513       }
06514    }
06515 
06516    if ((tmp = ast_calloc(1, length))) {
06517       ast_rwlock_init(&tmp->lock);
06518       ast_mutex_init(&tmp->macrolock);
06519       strcpy(tmp->name, name);
06520       tmp->root = NULL;
06521       tmp->root_table = NULL;
06522       tmp->registrar = ast_strdup(registrar);
06523       tmp->includes = NULL;
06524       tmp->ignorepats = NULL;
06525       tmp->refcount = 1;
06526    } else {
06527       ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
06528       return NULL;
06529    }
06530 
06531    if (!extcontexts) {
06532       ast_wrlock_contexts();
06533       tmp->next = *local_contexts;
06534       *local_contexts = tmp;
06535       ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
06536       ast_unlock_contexts();
06537       ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
06538       ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
06539    } else {
06540       tmp->next = *local_contexts;
06541       if (exttable)
06542          ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
06543 
06544       *local_contexts = tmp;
06545       ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
06546       ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
06547    }
06548    return tmp;
06549 }
06550 
06551 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
06552 
06553 struct store_hint {
06554    char *context;
06555    char *exten;
06556    AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
06557    int laststate;
06558    AST_LIST_ENTRY(store_hint) list;
06559    char data[1];
06560 };
06561 
06562 AST_LIST_HEAD(store_hints, store_hint);
06563 
06564 static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
06565 {
06566    struct ast_include *i;
06567    struct ast_ignorepat *ip;
06568    struct ast_sw *sw;
06569 
06570    ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar);
06571    /* copy in the includes, switches, and ignorepats */
06572    /* walk through includes */
06573    for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
06574       if (strcmp(ast_get_include_registrar(i), registrar) == 0)
06575          continue; /* not mine */
06576       ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
06577    }
06578 
06579    /* walk through switches */
06580    for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
06581       if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
06582          continue; /* not mine */
06583       ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
06584    }
06585 
06586    /* walk thru ignorepats ... */
06587    for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
06588       if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
06589          continue; /* not mine */
06590       ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
06591    }
06592 }
06593 
06594 
06595 /* the purpose of this routine is to duplicate a context, with all its substructure,
06596    except for any extens that have a matching registrar */
06597 static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
06598 {
06599    struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
06600    struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
06601    struct ast_hashtab_iter *exten_iter;
06602    struct ast_hashtab_iter *prio_iter;
06603    int insert_count = 0;
06604    int first = 1;
06605 
06606    /* We'll traverse all the extensions/prios, and see which are not registrar'd with
06607       the current registrar, and copy them to the new context. If the new context does not
06608       exist, we'll create it "on demand". If no items are in this context to copy, then we'll
06609       only create the empty matching context if the old one meets the criteria */
06610 
06611    if (context->root_table) {
06612       exten_iter = ast_hashtab_start_traversal(context->root_table);
06613       while ((exten_item=ast_hashtab_next(exten_iter))) {
06614          if (new) {
06615             new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
06616          } else {
06617             new_exten_item = NULL;
06618          }
06619          prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
06620          while ((prio_item=ast_hashtab_next(prio_iter))) {
06621             int res1;
06622             char *dupdstr;
06623 
06624             if (new_exten_item) {
06625                new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
06626             } else {
06627                new_prio_item = NULL;
06628             }
06629             if (strcmp(prio_item->registrar,registrar) == 0) {
06630                continue;
06631             }
06632             /* make sure the new context exists, so we have somewhere to stick this exten/prio */
06633             if (!new) {
06634                new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
06635             }
06636 
06637             /* copy in the includes, switches, and ignorepats */
06638             if (first) { /* but, only need to do this once */
06639                context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06640                first = 0;
06641             }
06642 
06643             if (!new) {
06644                ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
06645                return; /* no sense continuing. */
06646             }
06647             /* we will not replace existing entries in the new context with stuff from the old context.
06648                but, if this is because of some sort of registrar conflict, we ought to say something... */
06649 
06650             dupdstr = ast_strdup(prio_item->data);
06651 
06652             res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
06653                                 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
06654             if (!res1 && new_exten_item && new_prio_item){
06655                ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
06656                      context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
06657             } else {
06658                /* we do NOT pass the priority data from the old to the new -- we pass a copy of it, so no changes to the current dialplan take place,
06659                 and no double frees take place, either! */
06660                insert_count++;
06661             }
06662          }
06663          ast_hashtab_end_traversal(prio_iter);
06664       }
06665       ast_hashtab_end_traversal(exten_iter);
06666    }
06667 
06668    if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
06669         (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
06670       /* we could have given it the registrar of the other module who incremented the refcount,
06671          but that's not available, so we give it the registrar we know about */
06672       new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
06673 
06674       /* copy in the includes, switches, and ignorepats */
06675       context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06676    }
06677 }
06678 
06679 
06680 /* XXX this does not check that multiple contexts are merged */
06681 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
06682 {
06683    double ft;
06684    struct ast_context *tmp, *oldcontextslist;
06685    struct ast_hashtab *oldtable;
06686    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
06687    struct store_hint *this;
06688    struct ast_hint *hint;
06689    struct ast_exten *exten;
06690    int length;
06691    struct ast_state_cb *thiscb;
06692    struct ast_hashtab_iter *iter;
06693    struct ao2_iterator i;
06694 
06695    /* it is very important that this function hold the hint list lock _and_ the conlock
06696       during its operation; not only do we need to ensure that the list of contexts
06697       and extensions does not change, but also that no hint callbacks (watchers) are
06698       added or removed during the merge/delete process
06699 
06700       in addition, the locks _must_ be taken in this order, because there are already
06701       other code paths that use this order
06702    */
06703 
06704    struct timeval begintime, writelocktime, endlocktime, enddeltime;
06705 
06706    begintime = ast_tvnow();
06707    ast_rdlock_contexts();
06708    iter = ast_hashtab_start_traversal(contexts_table);
06709    while ((tmp = ast_hashtab_next(iter))) {
06710       context_merge(extcontexts, exttable, tmp, registrar);
06711    }
06712    ast_hashtab_end_traversal(iter);
06713 
06714    ao2_lock(hints);
06715    writelocktime = ast_tvnow();
06716 
06717    /* preserve all watchers for hints */
06718    i = ao2_iterator_init(hints, AO2_ITERATOR_DONTLOCK);
06719    for (hint = ao2_iterator_next(&i); hint; ao2_ref(hint, -1), hint = ao2_iterator_next(&i)) {
06720       if (ao2_container_count(hint->callbacks)) {
06721 
06722          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
06723          if (!(this = ast_calloc(1, length))) {
06724             continue;
06725          }
06726          ao2_lock(hint);
06727 
06728          if (hint->exten == NULL) {
06729             ao2_unlock(hint);
06730             continue;
06731          }
06732 
06733          /* this removes all the callbacks from the hint into 'this'. */
06734          while ((thiscb = ao2_callback(hint->callbacks, OBJ_UNLINK, NULL, NULL))) {
06735             AST_LIST_INSERT_TAIL(&this->callbacks, thiscb, entry);
06736             /* We intentionally do not unref thiscb to account for the non-ao2 reference in this->callbacks */
06737          }
06738 
06739          this->laststate = hint->laststate;
06740          this->context = this->data;
06741          strcpy(this->data, hint->exten->parent->name);
06742          this->exten = this->data + strlen(this->context) + 1;
06743          strcpy(this->exten, hint->exten->exten);
06744          ao2_unlock(hint);
06745          AST_LIST_INSERT_HEAD(&store, this, list);
06746       }
06747    }
06748 
06749    /* save the old table and list */
06750    oldtable = contexts_table;
06751    oldcontextslist = contexts;
06752 
06753    /* move in the new table and list */
06754    contexts_table = exttable;
06755    contexts = *extcontexts;
06756 
06757    /* restore the watchers for hints that can be found; notify those that
06758       cannot be restored
06759    */
06760    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
06761       struct pbx_find_info q = { .stacklen = 0 };
06762       exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
06763       /* If this is a pattern, dynamically create a new extension for this
06764        * particular match.  Note that this will only happen once for each
06765        * individual extension, because the pattern will no longer match first.
06766        */
06767       if (exten && exten->exten[0] == '_') {
06768          ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
06769             0, exten->app, ast_strdup(exten->data), ast_free_ptr, exten->registrar);
06770          /* rwlocks are not recursive locks */
06771          exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
06772       }
06773 
06774       /* Find the hint in the list of hints */
06775       hint = ao2_find(hints, exten, 0);
06776       if (!exten || !hint) {
06777          /* this hint has been removed, notify the watchers */
06778          while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) {
06779             thiscb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, thiscb->data);
06780             ao2_ref(thiscb, -1);  /* Ref that we added when putting into this->callbacks */
06781          }
06782       } else {
06783          ao2_lock(hint);
06784          while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) {
06785             ao2_link(hint->callbacks, thiscb);
06786             ao2_ref(thiscb, -1);  /* Ref that we added when putting into this->callbacks */
06787          }
06788          hint->laststate = this->laststate;
06789          ao2_unlock(hint);
06790       }
06791       ast_free(this);
06792       if (hint) {
06793          ao2_ref(hint, -1);
06794       }
06795    }
06796 
06797    ao2_unlock(hints);
06798    ast_unlock_contexts();
06799    endlocktime = ast_tvnow();
06800 
06801    /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
06802       is now freely using the new stuff instead */
06803 
06804    ast_hashtab_destroy(oldtable, NULL);
06805 
06806    for (tmp = oldcontextslist; tmp; ) {
06807       struct ast_context *next;  /* next starting point */
06808       next = tmp->next;
06809       __ast_internal_context_destroy(tmp);
06810       tmp = next;
06811    }
06812    enddeltime = ast_tvnow();
06813 
06814    ft = ast_tvdiff_us(writelocktime, begintime);
06815    ft /= 1000000.0;
06816    ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
06817 
06818    ft = ast_tvdiff_us(endlocktime, writelocktime);
06819    ft /= 1000000.0;
06820    ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
06821 
06822    ft = ast_tvdiff_us(enddeltime, endlocktime);
06823    ft /= 1000000.0;
06824    ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
06825 
06826    ft = ast_tvdiff_us(enddeltime, begintime);
06827    ft /= 1000000.0;
06828    ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
06829    return;
06830 }
06831 
06832 /*
06833  * errno values
06834  *  EBUSY  - can't lock
06835  *  ENOENT - no existence of context
06836  */
06837 int ast_context_add_include(const char *context, const char *include, const char *registrar)
06838 {
06839    int ret = -1;
06840    struct ast_context *c = find_context_locked(context);
06841 
06842    if (c) {
06843       ret = ast_context_add_include2(c, include, registrar);
06844       ast_unlock_contexts();
06845    }
06846    return ret;
06847 }
06848 
06849 /*! \brief Helper for get_range.
06850  * return the index of the matching entry, starting from 1.
06851  * If names is not supplied, try numeric values.
06852  */
06853 static int lookup_name(const char *s, char *const names[], int max)
06854 {
06855    int i;
06856 
06857    if (names && *s > '9') {
06858       for (i = 0; names[i]; i++) {
06859          if (!strcasecmp(s, names[i])) {
06860             return i;
06861          }
06862       }
06863    }
06864 
06865    /* Allow months and weekdays to be specified as numbers, as well */
06866    if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
06867       /* What the array offset would have been: "1" would be at offset 0 */
06868       return i - 1;
06869    }
06870    return -1; /* error return */
06871 }
06872 
06873 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
06874  * names, if supplied, is an array of names that should be mapped to numbers.
06875  */
06876 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
06877 {
06878    int start, end; /* start and ending position */
06879    unsigned int mask = 0;
06880    char *part;
06881 
06882    /* Check for whole range */
06883    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
06884       return (1 << max) - 1;
06885    }
06886 
06887    while ((part = strsep(&src, "&"))) {
06888       /* Get start and ending position */
06889       char *endpart = strchr(part, '-');
06890       if (endpart) {
06891          *endpart++ = '\0';
06892       }
06893       /* Find the start */
06894       if ((start = lookup_name(part, names, max)) < 0) {
06895          ast_log(LOG_WARNING, "Invalid %s '%s', skipping element\n", msg, part);
06896          continue;
06897       }
06898       if (endpart) { /* find end of range */
06899          if ((end = lookup_name(endpart, names, max)) < 0) {
06900             ast_log(LOG_WARNING, "Invalid end %s '%s', skipping element\n", msg, endpart);
06901             continue;
06902          }
06903       } else {
06904          end = start;
06905       }
06906       /* Fill the mask. Remember that ranges are cyclic */
06907       mask |= (1 << end);   /* initialize with last element */
06908       while (start != end) {
06909          mask |= (1 << start);
06910          if (++start >= max) {
06911             start = 0;
06912          }
06913       }
06914    }
06915    return mask;
06916 }
06917 
06918 /*! \brief store a bitmask of valid times, one bit each 1 minute */
06919 static void get_timerange(struct ast_timing *i, char *times)
06920 {
06921    char *endpart, *part;
06922    int x;
06923    int st_h, st_m;
06924    int endh, endm;
06925    int minute_start, minute_end;
06926 
06927    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
06928    memset(i->minmask, 0, sizeof(i->minmask));
06929 
06930    /* 1-minute per bit */
06931    /* Star is all times */
06932    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
06933       /* 48, because each hour takes 2 integers; 30 bits each */
06934       for (x = 0; x < 48; x++) {
06935          i->minmask[x] = 0x3fffffff; /* 30 bits */
06936       }
06937       return;
06938    }
06939    /* Otherwise expect a range */
06940    while ((part = strsep(&times, "&"))) {
06941       if (!(endpart = strchr(part, '-'))) {
06942          if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
06943             ast_log(LOG_WARNING, "%s isn't a valid time.\n", part);
06944             continue;
06945          }
06946          i->minmask[st_h * 2 + (st_m >= 30 ? 1 : 0)] |= (1 << (st_m % 30));
06947          continue;
06948       }
06949       *endpart++ = '\0';
06950       /* why skip non digits? Mostly to skip spaces */
06951       while (*endpart && !isdigit(*endpart)) {
06952          endpart++;
06953       }
06954       if (!*endpart) {
06955          ast_log(LOG_WARNING, "Invalid time range starting with '%s-'.\n", part);
06956          continue;
06957       }
06958       if (sscanf(part, "%2d:%2d", &st_h, &st_m) != 2 || st_h < 0 || st_h > 23 || st_m < 0 || st_m > 59) {
06959          ast_log(LOG_WARNING, "'%s' isn't a valid start time.\n", part);
06960          continue;
06961       }
06962       if (sscanf(endpart, "%2d:%2d", &endh, &endm) != 2 || endh < 0 || endh > 23 || endm < 0 || endm > 59) {
06963          ast_log(LOG_WARNING, "'%s' isn't a valid end time.\n", endpart);
06964          continue;
06965       }
06966       minute_start = st_h * 60 + st_m;
06967       minute_end = endh * 60 + endm;
06968       /* Go through the time and enable each appropriate bit */
06969       for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
06970          i->minmask[x / 30] |= (1 << (x % 30));
06971       }
06972       /* Do the last one */
06973       i->minmask[x / 30] |= (1 << (x % 30));
06974    }
06975    /* All done */
06976    return;
06977 }
06978 
06979 static char *days[] =
06980 {
06981    "sun",
06982    "mon",
06983    "tue",
06984    "wed",
06985    "thu",
06986    "fri",
06987    "sat",
06988    NULL,
06989 };
06990 
06991 static char *months[] =
06992 {
06993    "jan",
06994    "feb",
06995    "mar",
06996    "apr",
06997    "may",
06998    "jun",
06999    "jul",
07000    "aug",
07001    "sep",
07002    "oct",
07003    "nov",
07004    "dec",
07005    NULL,
07006 };
07007 
07008 int ast_build_timing(struct ast_timing *i, const char *info_in)
07009 {
07010    char *info_save, *info;
07011    int j, num_fields, last_sep = -1;
07012 
07013    /* Check for empty just in case */
07014    if (ast_strlen_zero(info_in)) {
07015       return 0;
07016    }
07017 
07018    /* make a copy just in case we were passed a static string */
07019    info_save = info = ast_strdupa(info_in);
07020 
07021    /* count the number of fields in the timespec */
07022    for (j = 0, num_fields = 1; info[j] != '\0'; j++) {
07023       if (info[j] == ',') {
07024          last_sep = j;
07025          num_fields++;
07026       }
07027    }
07028 
07029    /* save the timezone, if it is specified */
07030    if (num_fields == 5) {
07031       i->timezone = ast_strdup(info + last_sep + 1);
07032    } else {
07033       i->timezone = NULL;
07034    }
07035 
07036    /* Assume everything except time */
07037    i->monthmask = 0xfff;   /* 12 bits */
07038    i->daymask = 0x7fffffffU; /* 31 bits */
07039    i->dowmask = 0x7f; /* 7 bits */
07040    /* on each call, use strsep() to move info to the next argument */
07041    get_timerange(i, strsep(&info, "|,"));
07042    if (info)
07043       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
07044    if (info)
07045       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
07046    if (info)
07047       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
07048    return 1;
07049 }
07050 
07051 int ast_check_timing(const struct ast_timing *i)
07052 {
07053    struct ast_tm tm;
07054    struct timeval now = ast_tvnow();
07055 
07056    ast_localtime(&now, &tm, i->timezone);
07057 
07058    /* If it's not the right month, return */
07059    if (!(i->monthmask & (1 << tm.tm_mon)))
07060       return 0;
07061 
07062    /* If it's not that time of the month.... */
07063    /* Warning, tm_mday has range 1..31! */
07064    if (!(i->daymask & (1 << (tm.tm_mday-1))))
07065       return 0;
07066 
07067    /* If it's not the right day of the week */
07068    if (!(i->dowmask & (1 << tm.tm_wday)))
07069       return 0;
07070 
07071    /* Sanity check the hour just to be safe */
07072    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
07073       ast_log(LOG_WARNING, "Insane time...\n");
07074       return 0;
07075    }
07076 
07077    /* Now the tough part, we calculate if it fits
07078       in the right time based on min/hour */
07079    if (!(i->minmask[tm.tm_hour * 2 + (tm.tm_min >= 30 ? 1 : 0)] & (1 << (tm.tm_min >= 30 ? tm.tm_min - 30 : tm.tm_min))))
07080       return 0;
07081 
07082    /* If we got this far, then we're good */
07083    return 1;
07084 }
07085 
07086 int ast_destroy_timing(struct ast_timing *i)
07087 {
07088    if (i->timezone) {
07089       ast_free(i->timezone);
07090       i->timezone = NULL;
07091    }
07092    return 0;
07093 }
07094 /*
07095  * errno values
07096  *  ENOMEM - out of memory
07097  *  EBUSY  - can't lock
07098  *  EEXIST - already included
07099  *  EINVAL - there is no existence of context for inclusion
07100  */
07101 int ast_context_add_include2(struct ast_context *con, const char *value,
07102    const char *registrar)
07103 {
07104    struct ast_include *new_include;
07105    char *c;
07106    struct ast_include *i, *il = NULL; /* include, include_last */
07107    int length;
07108    char *p;
07109 
07110    length = sizeof(struct ast_include);
07111    length += 2 * (strlen(value) + 1);
07112 
07113    /* allocate new include structure ... */
07114    if (!(new_include = ast_calloc(1, length)))
07115       return -1;
07116    /* Fill in this structure. Use 'p' for assignments, as the fields
07117     * in the structure are 'const char *'
07118     */
07119    p = new_include->stuff;
07120    new_include->name = p;
07121    strcpy(p, value);
07122    p += strlen(value) + 1;
07123    new_include->rname = p;
07124    strcpy(p, value);
07125    /* Strip off timing info, and process if it is there */
07126    if ( (c = strchr(p, ',')) ) {
07127       *c++ = '\0';
07128       new_include->hastime = ast_build_timing(&(new_include->timing), c);
07129    }
07130    new_include->next      = NULL;
07131    new_include->registrar = registrar;
07132 
07133    ast_wrlock_context(con);
07134 
07135    /* ... go to last include and check if context is already included too... */
07136    for (i = con->includes; i; i = i->next) {
07137       if (!strcasecmp(i->name, new_include->name)) {
07138          ast_destroy_timing(&(new_include->timing));
07139          ast_free(new_include);
07140          ast_unlock_context(con);
07141          errno = EEXIST;
07142          return -1;
07143       }
07144       il = i;
07145    }
07146 
07147    /* ... include new context into context list, unlock, return */
07148    if (il)
07149       il->next = new_include;
07150    else
07151       con->includes = new_include;
07152    ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
07153 
07154    ast_unlock_context(con);
07155 
07156    return 0;
07157 }
07158 
07159 /*
07160  * errno values
07161  *  EBUSY  - can't lock
07162  *  ENOENT - no existence of context
07163  */
07164 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
07165 {
07166    int ret = -1;
07167    struct ast_context *c = find_context_locked(context);
07168 
07169    if (c) { /* found, add switch to this context */
07170       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
07171       ast_unlock_contexts();
07172    }
07173    return ret;
07174 }
07175 
07176 /*
07177  * errno values
07178  *  ENOMEM - out of memory
07179  *  EBUSY  - can't lock
07180  *  EEXIST - already included
07181  *  EINVAL - there is no existence of context for inclusion
07182  */
07183 int ast_context_add_switch2(struct ast_context *con, const char *value,
07184    const char *data, int eval, const char *registrar)
07185 {
07186    struct ast_sw *new_sw;
07187    struct ast_sw *i;
07188    int length;
07189    char *p;
07190 
07191    length = sizeof(struct ast_sw);
07192    length += strlen(value) + 1;
07193    if (data)
07194       length += strlen(data);
07195    length++;
07196 
07197    /* allocate new sw structure ... */
07198    if (!(new_sw = ast_calloc(1, length)))
07199       return -1;
07200    /* ... fill in this structure ... */
07201    p = new_sw->stuff;
07202    new_sw->name = p;
07203    strcpy(new_sw->name, value);
07204    p += strlen(value) + 1;
07205    new_sw->data = p;
07206    if (data) {
07207       strcpy(new_sw->data, data);
07208       p += strlen(data) + 1;
07209    } else {
07210       strcpy(new_sw->data, "");
07211       p++;
07212    }
07213    new_sw->eval     = eval;
07214    new_sw->registrar = registrar;
07215 
07216    /* ... try to lock this context ... */
07217    ast_wrlock_context(con);
07218 
07219    /* ... go to last sw and check if context is already swd too... */
07220    AST_LIST_TRAVERSE(&con->alts, i, list) {
07221       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
07222          ast_free(new_sw);
07223          ast_unlock_context(con);
07224          errno = EEXIST;
07225          return -1;
07226       }
07227    }
07228 
07229    /* ... sw new context into context list, unlock, return */
07230    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
07231 
07232    ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
07233 
07234    ast_unlock_context(con);
07235 
07236    return 0;
07237 }
07238 
07239 /*
07240  * EBUSY  - can't lock
07241  * ENOENT - there is not context existence
07242  */
07243 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
07244 {
07245    int ret = -1;
07246    struct ast_context *c = find_context_locked(context);
07247 
07248    if (c) {
07249       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
07250       ast_unlock_contexts();
07251    }
07252    return ret;
07253 }
07254 
07255 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
07256 {
07257    struct ast_ignorepat *ip, *ipl = NULL;
07258 
07259    ast_wrlock_context(con);
07260 
07261    for (ip = con->ignorepats; ip; ip = ip->next) {
07262       if (!strcmp(ip->pattern, ignorepat) &&
07263          (!registrar || (registrar == ip->registrar))) {
07264          if (ipl) {
07265             ipl->next = ip->next;
07266             ast_free(ip);
07267          } else {
07268             con->ignorepats = ip->next;
07269             ast_free(ip);
07270          }
07271          ast_unlock_context(con);
07272          return 0;
07273       }
07274       ipl = ip;
07275    }
07276 
07277    ast_unlock_context(con);
07278    errno = EINVAL;
07279    return -1;
07280 }
07281 
07282 /*
07283  * EBUSY - can't lock
07284  * ENOENT - there is no existence of context
07285  */
07286 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
07287 {
07288    int ret = -1;
07289    struct ast_context *c = find_context_locked(context);
07290 
07291    if (c) {
07292       ret = ast_context_add_ignorepat2(c, value, registrar);
07293       ast_unlock_contexts();
07294    }
07295    return ret;
07296 }
07297 
07298 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
07299 {
07300    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
07301    int length;
07302    char *pattern;
07303    length = sizeof(struct ast_ignorepat);
07304    length += strlen(value) + 1;
07305    if (!(ignorepat = ast_calloc(1, length)))
07306       return -1;
07307    /* The cast to char * is because we need to write the initial value.
07308     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
07309     * sees the cast as dereferencing a type-punned pointer and warns about
07310     * it.  This is the workaround (we're telling gcc, yes, that's really
07311     * what we wanted to do).
07312     */
07313    pattern = (char *) ignorepat->pattern;
07314    strcpy(pattern, value);
07315    ignorepat->next = NULL;
07316    ignorepat->registrar = registrar;
07317    ast_wrlock_context(con);
07318    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
07319       ignorepatl = ignorepatc;
07320       if (!strcasecmp(ignorepatc->pattern, value)) {
07321          /* Already there */
07322          ast_unlock_context(con);
07323          errno = EEXIST;
07324          return -1;
07325       }
07326    }
07327    if (ignorepatl)
07328       ignorepatl->next = ignorepat;
07329    else
07330       con->ignorepats = ignorepat;
07331    ast_unlock_context(con);
07332    return 0;
07333 
07334 }
07335 
07336 int ast_ignore_pattern(const char *context, const char *pattern)
07337 {
07338    struct ast_context *con = ast_context_find(context);
07339    if (con) {
07340       struct ast_ignorepat *pat;
07341       for (pat = con->ignorepats; pat; pat = pat->next) {
07342          if (ast_extension_match(pat->pattern, pattern))
07343             return 1;
07344       }
07345    }
07346 
07347    return 0;
07348 }
07349 
07350 /*
07351  * ast_add_extension_nolock -- use only in situations where the conlock is already held
07352  * ENOENT  - no existence of context
07353  *
07354  */
07355 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
07356    int priority, const char *label, const char *callerid,
07357    const char *application, void *data, void (*datad)(void *), const char *registrar)
07358 {
07359    int ret = -1;
07360    struct ast_context *c = find_context(context);
07361 
07362    if (c) {
07363       ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
07364          application, data, datad, registrar, 0, 0);
07365    }
07366 
07367    return ret;
07368 }
07369 /*
07370  * EBUSY   - can't lock
07371  * ENOENT  - no existence of context
07372  *
07373  */
07374 int ast_add_extension(const char *context, int replace, const char *extension,
07375    int priority, const char *label, const char *callerid,
07376    const char *application, void *data, void (*datad)(void *), const char *registrar)
07377 {
07378    int ret = -1;
07379    struct ast_context *c = find_context_locked(context);
07380 
07381    if (c) {
07382       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
07383          application, data, datad, registrar);
07384       ast_unlock_contexts();
07385    }
07386 
07387    return ret;
07388 }
07389 
07390 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
07391 {
07392    if (!chan)
07393       return -1;
07394 
07395    ast_channel_lock(chan);
07396 
07397    if (!ast_strlen_zero(context))
07398       ast_copy_string(chan->context, context, sizeof(chan->context));
07399    if (!ast_strlen_zero(exten))
07400       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
07401    if (priority > -1) {
07402       chan->priority = priority;
07403       /* see flag description in channel.h for explanation */
07404       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
07405          chan->priority--;
07406    }
07407 
07408    ast_channel_unlock(chan);
07409 
07410    return 0;
07411 }
07412 
07413 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
07414 {
07415    int res = 0;
07416 
07417    ast_channel_lock(chan);
07418 
07419    if (chan->pbx) { /* This channel is currently in the PBX */
07420       ast_explicit_goto(chan, context, exten, priority + 1);
07421       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
07422    } else {
07423       /* In order to do it when the channel doesn't really exist within
07424          the PBX, we have to make a new channel, masquerade, and start the PBX
07425          at the new location */
07426       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
07427       if (!tmpchan) {
07428          res = -1;
07429       } else {
07430          if (chan->cdr) {
07431             ast_cdr_discard(tmpchan->cdr);
07432             tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
07433          }
07434          /* Make formats okay */
07435          tmpchan->readformat = chan->readformat;
07436          tmpchan->writeformat = chan->writeformat;
07437          /* Setup proper location */
07438          ast_explicit_goto(tmpchan,
07439             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
07440 
07441          /* Masquerade into temp channel */
07442          if (ast_channel_masquerade(tmpchan, chan)) {
07443             /* Failed to set up the masquerade.  It's probably chan_local
07444              * in the middle of optimizing itself out.  Sad. :( */
07445             ast_hangup(tmpchan);
07446             tmpchan = NULL;
07447             res = -1;
07448          } else {
07449             /* Grab the locks and get going */
07450             ast_channel_lock(tmpchan);
07451             ast_do_masquerade(tmpchan);
07452             ast_channel_unlock(tmpchan);
07453             /* Start the PBX going on our stolen channel */
07454             if (ast_pbx_start(tmpchan)) {
07455                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
07456                ast_hangup(tmpchan);
07457                res = -1;
07458             }
07459          }
07460       }
07461    }
07462    ast_channel_unlock(chan);
07463    return res;
07464 }
07465 
07466 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
07467 {
07468    struct ast_channel *chan;
07469    int res = -1;
07470 
07471    chan = ast_get_channel_by_name_locked(channame);
07472    if (chan) {
07473       res = ast_async_goto(chan, context, exten, priority);
07474       ast_channel_unlock(chan);
07475    }
07476    return res;
07477 }
07478 
07479 /*! \brief copy a string skipping whitespace */
07480 static int ext_strncpy(char *dst, const char *src, int len)
07481 {
07482    int count = 0;
07483    int insquares = 0;
07484 
07485    while (*src && (count < len - 1)) {
07486       if (*src == '[') {
07487          insquares = 1;
07488       } else if (*src == ']') {
07489          insquares = 0;
07490       } else if (*src == ' ' && !insquares) {
07491          src++;
07492          continue;
07493       }
07494       *dst = *src;
07495       dst++;
07496       src++;
07497       count++;
07498    }
07499    *dst = '\0';
07500 
07501    return count;
07502 }
07503 
07504 /*!
07505  * \brief add the extension in the priority chain.
07506  * \retval 0 on success.
07507  * \retval -1 on failure.
07508 */
07509 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
07510    struct ast_exten *el, struct ast_exten *e, int replace)
07511 {
07512    return add_pri_lockopt(con, tmp, el, e, replace, 1);
07513 }
07514 
07515 /*!
07516  * \brief add the extension in the priority chain.
07517  * \retval 0 on success.
07518  * \retval -1 on failure.
07519 */
07520 static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
07521    struct ast_exten *el, struct ast_exten *e, int replace, int lockhints)
07522 {
07523    struct ast_exten *ep;
07524    struct ast_exten *eh=e;
07525 
07526    for (ep = NULL; e ; ep = e, e = e->peer) {
07527       if (e->priority >= tmp->priority)
07528          break;
07529    }
07530    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
07531       ast_hashtab_insert_safe(eh->peer_table, tmp);
07532 
07533       if (tmp->label) {
07534          ast_hashtab_insert_safe(eh->peer_label_table, tmp);
07535       }
07536       ep->peer = tmp;
07537       return 0;   /* success */
07538    }
07539    if (e->priority == tmp->priority) {
07540       /* Can't have something exactly the same.  Is this a
07541          replacement?  If so, replace, otherwise, bonk. */
07542       if (!replace) {
07543          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
07544          if (tmp->datad) {
07545             tmp->datad(tmp->data);
07546             /* if you free this, null it out */
07547             tmp->data = NULL;
07548          }
07549 
07550          ast_free(tmp);
07551          return -1;
07552       }
07553       /* we are replacing e, so copy the link fields and then update
07554        * whoever pointed to e to point to us
07555        */
07556       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
07557       tmp->peer = e->peer; /* always meaningful */
07558       if (ep)  {     /* We're in the peer list, just insert ourselves */
07559          ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
07560 
07561          if (e->label) {
07562             ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
07563          }
07564 
07565          ast_hashtab_insert_safe(eh->peer_table,tmp);
07566          if (tmp->label) {
07567             ast_hashtab_insert_safe(eh->peer_label_table,tmp);
07568          }
07569 
07570          ep->peer = tmp;
07571       } else if (el) {     /* We're the first extension. Take over e's functions */
07572          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
07573          tmp->peer_table = e->peer_table;
07574          tmp->peer_label_table = e->peer_label_table;
07575          ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
07576          ast_hashtab_insert_safe(tmp->peer_table,tmp);
07577          if (e->label) {
07578             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
07579          }
07580          if (tmp->label) {
07581             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07582          }
07583 
07584          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07585          ast_hashtab_insert_safe(con->root_table, tmp);
07586          el->next = tmp;
07587          /* The pattern trie points to this exten; replace the pointer,
07588             and all will be well */
07589          if (x) { /* if the trie isn't formed yet, don't sweat this */
07590             if (x->exten) { /* this test for safety purposes */
07591                x->exten = tmp; /* replace what would become a bad pointer */
07592             } else {
07593                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
07594             }
07595          }
07596       } else {       /* We're the very first extension.  */
07597          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
07598          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07599          ast_hashtab_insert_safe(con->root_table, tmp);
07600          tmp->peer_table = e->peer_table;
07601          tmp->peer_label_table = e->peer_label_table;
07602          ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
07603          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07604          if (e->label) {
07605             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
07606          }
07607          if (tmp->label) {
07608             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07609          }
07610 
07611          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07612          ast_hashtab_insert_safe(con->root_table, tmp);
07613          con->root = tmp;
07614          /* The pattern trie points to this exten; replace the pointer,
07615             and all will be well */
07616          if (x) { /* if the trie isn't formed yet; no problem */
07617             if (x->exten) { /* this test for safety purposes */
07618                x->exten = tmp; /* replace what would become a bad pointer */
07619             } else {
07620                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
07621             }
07622          }
07623       }
07624       if (tmp->priority == PRIORITY_HINT)
07625          ast_change_hint(e,tmp);
07626       /* Destroy the old one */
07627       if (e->datad)
07628          e->datad(e->data);
07629       ast_free(e);
07630    } else { /* Slip ourselves in just before e */
07631       tmp->peer = e;
07632       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
07633       if (ep) {         /* Easy enough, we're just in the peer list */
07634          if (tmp->label) {
07635             ast_hashtab_insert_safe(eh->peer_label_table, tmp);
07636          }
07637          ast_hashtab_insert_safe(eh->peer_table, tmp);
07638          ep->peer = tmp;
07639       } else {       /* we are the first in some peer list, so link in the ext list */
07640          tmp->peer_table = e->peer_table;
07641          tmp->peer_label_table = e->peer_label_table;
07642          e->peer_table = 0;
07643          e->peer_label_table = 0;
07644          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07645          if (tmp->label) {
07646             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07647          }
07648          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07649          ast_hashtab_insert_safe(con->root_table, tmp);
07650          if (el)
07651             el->next = tmp;   /* in the middle... */
07652          else
07653             con->root = tmp; /* ... or at the head */
07654          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
07655       }
07656       /* And immediately return success. */
07657       if (tmp->priority == PRIORITY_HINT) {
07658          if (lockhints) {
07659             ast_add_hint(tmp);
07660          } else {
07661             ast_add_hint(tmp);
07662          }
07663       }
07664    }
07665    return 0;
07666 }
07667 
07668 /*! \brief
07669  * Main interface to add extensions to the list for out context.
07670  *
07671  * We sort extensions in order of matching preference, so that we can
07672  * stop the search as soon as we find a suitable match.
07673  * This ordering also takes care of wildcards such as '.' (meaning
07674  * "one or more of any character") and '!' (which is 'earlymatch',
07675  * meaning "zero or more of any character" but also impacts the
07676  * return value from CANMATCH and EARLYMATCH.
07677  *
07678  * The extension match rules defined in the devmeeting 2006.05.05 are
07679  * quite simple: WE SELECT THE LONGEST MATCH.
07680  * In detail, "longest" means the number of matched characters in
07681  * the extension. In case of ties (e.g. _XXX and 333) in the length
07682  * of a pattern, we give priority to entries with the smallest cardinality
07683  * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
07684  * while the latter has 7, etc.
07685  * In case of same cardinality, the first element in the range counts.
07686  * If we still have a tie, any final '!' will make this as a possibly
07687  * less specific pattern.
07688  *
07689  * EBUSY - can't lock
07690  * EEXIST - extension with the same priority exist and no replace is set
07691  *
07692  */
07693 int ast_add_extension2(struct ast_context *con,
07694    int replace, const char *extension, int priority, const char *label, const char *callerid,
07695    const char *application, void *data, void (*datad)(void *),
07696    const char *registrar)
07697 {
07698    return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
07699 }
07700 
07701 /*! \brief
07702  * Does all the work of ast_add_extension2, but adds two args, to determine if
07703  * context and hint locking should be done. In merge_and_delete, we need to do
07704  * this without locking, as the locks are already held.
07705  */
07706 static int ast_add_extension2_lockopt(struct ast_context *con,
07707    int replace, const char *extension, int priority, const char *label, const char *callerid,
07708    const char *application, void *data, void (*datad)(void *),
07709    const char *registrar, int lockconts, int lockhints)
07710 {
07711    /*
07712     * Sort extensions (or patterns) according to the rules indicated above.
07713     * These are implemented by the function ext_cmp()).
07714     * All priorities for the same ext/pattern/cid are kept in a list,
07715     * using the 'peer' field  as a link field..
07716     */
07717    struct ast_exten *tmp, *tmp2, *e, *el = NULL;
07718    int res;
07719    int length;
07720    char *p;
07721    char expand_buf[VAR_BUF_SIZE];
07722    struct ast_exten dummy_exten = {0};
07723    char dummy_name[1024];
07724 
07725    if (ast_strlen_zero(extension)) {
07726       ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
07727             con->name);
07728       return -1;
07729    }
07730 
07731    /* If we are adding a hint evalulate in variables and global variables */
07732    if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) {
07733       struct ast_channel c = {0, };
07734 
07735       ast_copy_string(c.exten, extension, sizeof(c.exten));
07736       ast_copy_string(c.context, con->name, sizeof(c.context));
07737       pbx_substitute_variables_helper(&c, application, expand_buf, sizeof(expand_buf));
07738       application = expand_buf;
07739    }
07740 
07741    length = sizeof(struct ast_exten);
07742    length += strlen(extension) + 1;
07743    length += strlen(application) + 1;
07744    if (label)
07745       length += strlen(label) + 1;
07746    if (callerid)
07747       length += strlen(callerid) + 1;
07748    else
07749       length ++;  /* just the '\0' */
07750 
07751    /* Be optimistic:  Build the extension structure first */
07752    if (!(tmp = ast_calloc(1, length)))
07753       return -1;
07754 
07755    if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
07756       label = 0;
07757 
07758    /* use p as dst in assignments, as the fields are const char * */
07759    p = tmp->stuff;
07760    if (label) {
07761       tmp->label = p;
07762       strcpy(p, label);
07763       p += strlen(label) + 1;
07764    }
07765    tmp->exten = p;
07766    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
07767    tmp->priority = priority;
07768    tmp->cidmatch = p;   /* but use p for assignments below */
07769 
07770    /* Blank callerid and NULL callerid are two SEPARATE things.  Do NOT confuse the two!!! */
07771    if (callerid) {
07772       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
07773       tmp->matchcid = 1;
07774    } else {
07775       *p++ = '\0';
07776       tmp->matchcid = 0;
07777    }
07778    tmp->app = p;
07779    strcpy(p, application);
07780    tmp->parent = con;
07781    tmp->data = data;
07782    tmp->datad = datad;
07783    tmp->registrar = registrar;
07784 
07785    if (lockconts) {
07786       ast_wrlock_context(con);
07787    }
07788 
07789    if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
07790                         an extension, and the trie exists, then we need to incrementally add this pattern to it. */
07791       ast_copy_string(dummy_name, extension, sizeof(dummy_name));
07792       dummy_exten.exten = dummy_name;
07793       dummy_exten.matchcid = 0;
07794       dummy_exten.cidmatch = 0;
07795       tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
07796       if (!tmp2) {
07797          /* hmmm, not in the trie; */
07798          add_exten_to_pattern_tree(con, tmp, 0);
07799          ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
07800       }
07801    }
07802    res = 0; /* some compilers will think it is uninitialized otherwise */
07803    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
07804       res = ext_cmp(e->exten, tmp->exten);
07805       if (res == 0) { /* extension match, now look at cidmatch */
07806          if (!e->matchcid && !tmp->matchcid)
07807             res = 0;
07808          else if (tmp->matchcid && !e->matchcid)
07809             res = 1;
07810          else if (e->matchcid && !tmp->matchcid)
07811             res = -1;
07812          else
07813             res = ext_cmp(e->cidmatch, tmp->cidmatch);
07814       }
07815       if (res >= 0)
07816          break;
07817    }
07818    if (e && res == 0) { /* exact match, insert in the pri chain */
07819       res = add_pri(con, tmp, el, e, replace);
07820       if (lockconts) {
07821          ast_unlock_context(con);
07822       }
07823       if (res < 0) {
07824          errno = EEXIST;   /* XXX do we care ? */
07825          return 0; /* XXX should we return -1 maybe ? */
07826       }
07827    } else {
07828       /*
07829        * not an exact match, this is the first entry with this pattern,
07830        * so insert in the main list right before 'e' (if any)
07831        */
07832       tmp->next = e;
07833       if (el) {  /* there is another exten already in this context */
07834          el->next = tmp;
07835          tmp->peer_table = ast_hashtab_create(13,
07836                      hashtab_compare_exten_numbers,
07837                      ast_hashtab_resize_java,
07838                      ast_hashtab_newsize_java,
07839                      hashtab_hash_priority,
07840                      0);
07841          tmp->peer_label_table = ast_hashtab_create(7,
07842                         hashtab_compare_exten_labels,
07843                         ast_hashtab_resize_java,
07844                         ast_hashtab_newsize_java,
07845                         hashtab_hash_labels,
07846                         0);
07847          if (label) {
07848             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07849          }
07850          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07851       } else {  /* this is the first exten in this context */
07852          if (!con->root_table)
07853             con->root_table = ast_hashtab_create(27,
07854                                        hashtab_compare_extens,
07855                                        ast_hashtab_resize_java,
07856                                        ast_hashtab_newsize_java,
07857                                        hashtab_hash_extens,
07858                                        0);
07859          con->root = tmp;
07860          con->root->peer_table = ast_hashtab_create(13,
07861                         hashtab_compare_exten_numbers,
07862                         ast_hashtab_resize_java,
07863                         ast_hashtab_newsize_java,
07864                         hashtab_hash_priority,
07865                         0);
07866          con->root->peer_label_table = ast_hashtab_create(7,
07867                            hashtab_compare_exten_labels,
07868                            ast_hashtab_resize_java,
07869                            ast_hashtab_newsize_java,
07870                            hashtab_hash_labels,
07871                            0);
07872          if (label) {
07873             ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
07874          }
07875          ast_hashtab_insert_safe(con->root->peer_table, tmp);
07876 
07877       }
07878       ast_hashtab_insert_safe(con->root_table, tmp);
07879       if (lockconts) {
07880          ast_unlock_context(con);
07881       }
07882       if (tmp->priority == PRIORITY_HINT) {
07883          if (lockhints) {
07884             ast_add_hint(tmp);
07885          } else {
07886             ast_add_hint(tmp);
07887          }
07888       }
07889    }
07890    if (option_debug) {
07891       if (tmp->matchcid) {
07892          ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07893                  tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07894       } else {
07895          ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
07896                  tmp->exten, tmp->priority, con->name, con);
07897       }
07898    }
07899 
07900    if (tmp->matchcid) {
07901       ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07902              tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07903    } else {
07904       ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
07905              tmp->exten, tmp->priority, con->name, con);
07906    }
07907 
07908    return 0;
07909 }
07910 
07911 struct async_stat {
07912    pthread_t p;
07913    struct ast_channel *chan;
07914    char context[AST_MAX_CONTEXT];
07915    char exten[AST_MAX_EXTENSION];
07916    int priority;
07917    int timeout;
07918    char app[AST_MAX_EXTENSION];
07919    char appdata[1024];
07920 };
07921 
07922 static void *async_wait(void *data)
07923 {
07924    struct async_stat *as = data;
07925    struct ast_channel *chan = as->chan;
07926    int timeout = as->timeout;
07927    int res;
07928    struct ast_frame *f;
07929    struct ast_app *app;
07930 
07931    while (timeout && (chan->_state != AST_STATE_UP)) {
07932       res = ast_waitfor(chan, timeout);
07933       if (res < 1)
07934          break;
07935       if (timeout > -1)
07936          timeout = res;
07937       f = ast_read(chan);
07938       if (!f)
07939          break;
07940       if (f->frametype == AST_FRAME_CONTROL) {
07941          if ((f->subclass == AST_CONTROL_BUSY)  ||
07942              (f->subclass == AST_CONTROL_CONGESTION) ) {
07943             ast_frfree(f);
07944             break;
07945          }
07946       }
07947       ast_frfree(f);
07948    }
07949    if (chan->_state == AST_STATE_UP) {
07950       if (!ast_strlen_zero(as->app)) {
07951          app = pbx_findapp(as->app);
07952          if (app) {
07953             ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
07954             pbx_exec(chan, app, as->appdata);
07955          } else
07956             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
07957       } else {
07958          if (!ast_strlen_zero(as->context))
07959             ast_copy_string(chan->context, as->context, sizeof(chan->context));
07960          if (!ast_strlen_zero(as->exten))
07961             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
07962          if (as->priority > 0)
07963             chan->priority = as->priority;
07964          /* Run the PBX */
07965          if (ast_pbx_run(chan)) {
07966             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
07967          } else {
07968             /* PBX will have taken care of this */
07969             chan = NULL;
07970          }
07971       }
07972    }
07973    ast_free(as);
07974    if (chan)
07975       ast_hangup(chan);
07976    return NULL;
07977 }
07978 
07979 /*!
07980  * \brief Function to post an empty cdr after a spool call fails.
07981  * \note This function posts an empty cdr for a failed spool call
07982 */
07983 static int ast_pbx_outgoing_cdr_failed(void)
07984 {
07985    /* allocate a channel */
07986    struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
07987 
07988    if (!chan)
07989       return -1;  /* failure */
07990 
07991    if (!chan->cdr) {
07992       /* allocation of the cdr failed */
07993       ast_channel_free(chan);   /* free the channel */
07994       return -1;                /* return failure */
07995    }
07996 
07997    /* allocation of the cdr was successful */
07998    ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
07999    ast_cdr_start(chan->cdr);       /* record the start and stop time */
08000    ast_cdr_end(chan->cdr);
08001    ast_cdr_failed(chan->cdr);      /* set the status to failed */
08002    ast_cdr_detach(chan->cdr);      /* post and free the record */
08003    chan->cdr = NULL;
08004    ast_channel_free(chan);         /* free the channel */
08005 
08006    return 0;  /* success */
08007 }
08008 
08009 int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
08010 {
08011    struct ast_channel *chan;
08012    struct async_stat *as;
08013    int res = -1, cdr_res = -1;
08014    struct outgoing_helper oh;
08015 
08016    if (synchronous) {
08017       oh.context = context;
08018       oh.exten = exten;
08019       oh.priority = priority;
08020       oh.cid_num = cid_num;
08021       oh.cid_name = cid_name;
08022       oh.account = account;
08023       oh.vars = vars;
08024       oh.parent_channel = NULL;
08025 
08026       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
08027       if (channel) {
08028          *channel = chan;
08029          if (chan)
08030             ast_channel_lock(chan);
08031       }
08032       if (chan) {
08033          if (chan->_state == AST_STATE_UP) {
08034                res = 0;
08035             ast_verb(4, "Channel %s was answered.\n", chan->name);
08036 
08037             if (synchronous > 1) {
08038                if (channel)
08039                   ast_channel_unlock(chan);
08040                if (ast_pbx_run(chan)) {
08041                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
08042                   if (channel)
08043                      *channel = NULL;
08044                   ast_hangup(chan);
08045                   chan = NULL;
08046                   res = -1;
08047                }
08048             } else {
08049                if (ast_pbx_start(chan)) {
08050                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
08051                   if (channel) {
08052                      *channel = NULL;
08053                      ast_channel_unlock(chan);
08054                   }
08055                   ast_hangup(chan);
08056                   res = -1;
08057                }
08058                chan = NULL;
08059             }
08060          } else {
08061             ast_verb(4, "Channel %s was never answered.\n", chan->name);
08062 
08063             if (chan->cdr) { /* update the cdr */
08064                /* here we update the status of the call, which sould be busy.
08065                 * if that fails then we set the status to failed */
08066                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
08067                   ast_cdr_failed(chan->cdr);
08068             }
08069 
08070             if (channel) {
08071                *channel = NULL;
08072                ast_channel_unlock(chan);
08073             }
08074             ast_hangup(chan);
08075             chan = NULL;
08076          }
08077       }
08078 
08079       if (res < 0) { /* the call failed for some reason */
08080          if (*reason == 0) { /* if the call failed (not busy or no answer)
08081                         * update the cdr with the failed message */
08082             cdr_res = ast_pbx_outgoing_cdr_failed();
08083             if (cdr_res != 0) {
08084                res = cdr_res;
08085                goto outgoing_exten_cleanup;
08086             }
08087          }
08088 
08089          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
08090          /* check if "failed" exists */
08091          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
08092             chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
08093             if (chan) {
08094                char failed_reason[4] = "";
08095                if (!ast_strlen_zero(context))
08096                   ast_copy_string(chan->context, context, sizeof(chan->context));
08097                set_ext_pri(chan, "failed", 1);
08098                ast_set_variables(chan, vars);
08099                snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
08100                pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
08101                if (account)
08102                   ast_cdr_setaccount(chan, account);
08103                if (ast_pbx_run(chan)) {
08104                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
08105                   ast_hangup(chan);
08106                }
08107                chan = NULL;
08108             }
08109          }
08110       }
08111    } else {
08112       if (!(as = ast_calloc(1, sizeof(*as)))) {
08113          res = -1;
08114          goto outgoing_exten_cleanup;
08115       }
08116       chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
08117       if (channel) {
08118          *channel = chan;
08119          if (chan)
08120             ast_channel_lock(chan);
08121       }
08122       if (!chan) {
08123          ast_free(as);
08124          res = -1;
08125          goto outgoing_exten_cleanup;
08126       }
08127       as->chan = chan;
08128       ast_copy_string(as->context, context, sizeof(as->context));
08129       set_ext_pri(as->chan,  exten, priority);
08130       as->timeout = timeout;
08131       ast_set_variables(chan, vars);
08132       if (account)
08133          ast_cdr_setaccount(chan, account);
08134       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
08135          ast_log(LOG_WARNING, "Failed to start async wait\n");
08136          ast_free(as);
08137          if (channel) {
08138             *channel = NULL;
08139             ast_channel_unlock(chan);
08140          }
08141          ast_hangup(chan);
08142          res = -1;
08143          goto outgoing_exten_cleanup;
08144       }
08145       res = 0;
08146    }
08147 outgoing_exten_cleanup:
08148    ast_variables_destroy(vars);
08149    return res;
08150 }
08151 
08152 struct app_tmp {
08153    char app[256];
08154    char data[256];
08155    struct ast_channel *chan;
08156    pthread_t t;
08157 };
08158 
08159 /*! \brief run the application and free the descriptor once done */
08160 static void *ast_pbx_run_app(void *data)
08161 {
08162    struct app_tmp *tmp = data;
08163    struct ast_app *app;
08164    app = pbx_findapp(tmp->app);
08165    if (app) {
08166       ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
08167       pbx_exec(tmp->chan, app, tmp->data);
08168    } else
08169       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
08170    ast_hangup(tmp->chan);
08171    ast_free(tmp);
08172    return NULL;
08173 }
08174 
08175 int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
08176 {
08177    struct ast_channel *chan;
08178    struct app_tmp *tmp;
08179    int res = -1, cdr_res = -1;
08180    struct outgoing_helper oh;
08181 
08182    memset(&oh, 0, sizeof(oh));
08183    oh.vars = vars;
08184    oh.account = account;
08185 
08186    if (locked_channel)
08187       *locked_channel = NULL;
08188    if (ast_strlen_zero(app)) {
08189       res = -1;
08190       goto outgoing_app_cleanup;
08191    }
08192    if (synchronous) {
08193       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
08194       if (chan) {
08195          ast_set_variables(chan, vars);
08196          if (account)
08197             ast_cdr_setaccount(chan, account);
08198          if (chan->_state == AST_STATE_UP) {
08199             res = 0;
08200             ast_verb(4, "Channel %s was answered.\n", chan->name);
08201             tmp = ast_calloc(1, sizeof(*tmp));
08202             if (!tmp)
08203                res = -1;
08204             else {
08205                ast_copy_string(tmp->app, app, sizeof(tmp->app));
08206                if (appdata)
08207                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
08208                tmp->chan = chan;
08209                if (synchronous > 1) {
08210                   if (locked_channel)
08211                      ast_channel_unlock(chan);
08212                   ast_pbx_run_app(tmp);
08213                } else {
08214                   if (locked_channel)
08215                      ast_channel_lock(chan);
08216                   if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
08217                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
08218                      ast_free(tmp);
08219                      if (locked_channel)
08220                         ast_channel_unlock(chan);
08221                      ast_hangup(chan);
08222                      res = -1;
08223                   } else {
08224                      if (locked_channel)
08225                         *locked_channel = chan;
08226                   }
08227                }
08228             }
08229          } else {
08230             ast_verb(4, "Channel %s was never answered.\n", chan->name);
08231             if (chan->cdr) { /* update the cdr */
08232                /* here we update the status of the call, which sould be busy.
08233                 * if that fails then we set the status to failed */
08234                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
08235                   ast_cdr_failed(chan->cdr);
08236             }
08237             ast_hangup(chan);
08238          }
08239       }
08240 
08241       if (res < 0) { /* the call failed for some reason */
08242          if (*reason == 0) { /* if the call failed (not busy or no answer)
08243                         * update the cdr with the failed message */
08244             cdr_res = ast_pbx_outgoing_cdr_failed();
08245             if (cdr_res != 0) {
08246                res = cdr_res;
08247                goto outgoing_app_cleanup;
08248             }
08249          }
08250       }
08251 
08252    } else {
08253       struct async_stat *as;
08254       if (!(as = ast_calloc(1, sizeof(*as)))) {
08255          res = -1;
08256          goto outgoing_app_cleanup;
08257       }
08258       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
08259       if (!chan) {
08260          ast_free(as);
08261          res = -1;
08262          goto outgoing_app_cleanup;
08263       }
08264       as->chan = chan;
08265       ast_copy_string(as->app, app, sizeof(as->app));
08266       if (appdata)
08267          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
08268       as->timeout = timeout;
08269       ast_set_variables(chan, vars);
08270       if (account)
08271          ast_cdr_setaccount(chan, account);
08272       /* Start a new thread, and get something handling this channel. */
08273       if (locked_channel)
08274          ast_channel_lock(chan);
08275       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
08276          ast_log(LOG_WARNING, "Failed to start async wait\n");
08277          ast_free(as);
08278          if (locked_channel)
08279             ast_channel_unlock(chan);
08280          ast_hangup(chan);
08281          res = -1;
08282          goto outgoing_app_cleanup;
08283       } else {
08284          if (locked_channel)
08285             *locked_channel = chan;
08286       }
08287       res = 0;
08288    }
08289 outgoing_app_cleanup:
08290    ast_variables_destroy(vars);
08291    return res;
08292 }
08293 
08294 /* this is the guts of destroying a context --
08295    freeing up the structure, traversing and destroying the
08296    extensions, switches, ignorepats, includes, etc. etc. */
08297 
08298 static void __ast_internal_context_destroy( struct ast_context *con)
08299 {
08300    struct ast_include *tmpi;
08301    struct ast_sw *sw;
08302    struct ast_exten *e, *el, *en;
08303    struct ast_ignorepat *ipi;
08304    struct ast_context *tmp = con;
08305 
08306    for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
08307       struct ast_include *tmpil = tmpi;
08308       tmpi = tmpi->next;
08309       ast_free(tmpil);
08310    }
08311    for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
08312       struct ast_ignorepat *ipl = ipi;
08313       ipi = ipi->next;
08314       ast_free(ipl);
08315    }
08316    if (tmp->registrar)
08317       ast_free(tmp->registrar);
08318 
08319    /* destroy the hash tabs */
08320    if (tmp->root_table) {
08321       ast_hashtab_destroy(tmp->root_table, 0);
08322    }
08323    /* and destroy the pattern tree */
08324    if (tmp->pattern_tree)
08325       destroy_pattern_tree(tmp->pattern_tree);
08326 
08327    while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
08328       ast_free(sw);
08329    for (e = tmp->root; e;) {
08330       for (en = e->peer; en;) {
08331          el = en;
08332          en = en->peer;
08333          destroy_exten(el);
08334       }
08335       el = e;
08336       e = e->next;
08337       destroy_exten(el);
08338    }
08339    tmp->root = NULL;
08340    ast_rwlock_destroy(&tmp->lock);
08341    ast_free(tmp);
08342 }
08343 
08344 
08345 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
08346 {
08347    struct ast_context *tmp, *tmpl=NULL;
08348    struct ast_exten *exten_item, *prio_item;
08349 
08350    for (tmp = list; tmp; ) {
08351       struct ast_context *next = NULL; /* next starting point */
08352          /* The following code used to skip forward to the next
08353             context with matching registrar, but this didn't
08354             make sense; individual priorities registrar'd to
08355             the matching registrar could occur in any context! */
08356       ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
08357       if (con) {
08358          for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
08359             ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
08360             if ( !strcasecmp(tmp->name, con->name) ) {
08361                break;   /* found it */
08362             }
08363          }
08364       }
08365 
08366       if (!tmp)   /* not found, we are done */
08367          break;
08368       ast_wrlock_context(tmp);
08369 
08370       if (registrar) {
08371          /* then search thru and remove any extens that match registrar. */
08372          struct ast_hashtab_iter *exten_iter;
08373          struct ast_hashtab_iter *prio_iter;
08374          struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
08375          struct ast_include *i, *pi = NULL, *ni = NULL;
08376          struct ast_sw *sw = NULL;
08377 
08378          /* remove any ignorepats whose registrar matches */
08379          for (ip = tmp->ignorepats; ip; ip = ipn) {
08380             ipn = ip->next;
08381             if (!strcmp(ip->registrar, registrar)) {
08382                if (ipl) {
08383                   ipl->next = ip->next;
08384                   ast_free(ip);
08385                   continue; /* don't change ipl */
08386                } else {
08387                   tmp->ignorepats = ip->next;
08388                   ast_free(ip);
08389                   continue; /* don't change ipl */
08390                }
08391             }
08392             ipl = ip;
08393          }
08394          /* remove any includes whose registrar matches */
08395          for (i = tmp->includes; i; i = ni) {
08396             ni = i->next;
08397             if (strcmp(i->registrar, registrar) == 0) {
08398                /* remove from list */
08399                if (pi) {
08400                   pi->next = i->next;
08401                   /* free include */
08402                   ast_free(i);
08403                   continue; /* don't change pi */
08404                } else {
08405                   tmp->includes = i->next;
08406                   /* free include */
08407                   ast_free(i);
08408                   continue; /* don't change pi */
08409                }
08410             }
08411             pi = i;
08412          }
08413          /* remove any switches whose registrar matches */
08414          AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
08415             if (strcmp(sw->registrar,registrar) == 0) {
08416                AST_LIST_REMOVE_CURRENT(list);
08417                ast_free(sw);
08418             }
08419          }
08420          AST_LIST_TRAVERSE_SAFE_END;
08421 
08422          if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
08423             exten_iter = ast_hashtab_start_traversal(tmp->root_table);
08424             while ((exten_item=ast_hashtab_next(exten_iter))) {
08425                prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
08426                while ((prio_item=ast_hashtab_next(prio_iter))) {
08427                   if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
08428                      continue;
08429                   }
08430                   ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
08431                          tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
08432                   /* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */
08433                   ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
08434                }
08435                ast_hashtab_end_traversal(prio_iter);
08436             }
08437             ast_hashtab_end_traversal(exten_iter);
08438          }
08439 
08440          /* delete the context if it's registrar matches, is empty, has refcount of 1, */
08441          /* it's not empty, if it has includes, ignorepats, or switches that are registered from
08442             another registrar. It's not empty if there are any extensions */
08443          if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
08444             ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
08445             ast_hashtab_remove_this_object(contexttab, tmp);
08446 
08447             next = tmp->next;
08448             if (tmpl)
08449                tmpl->next = next;
08450             else
08451                contexts = next;
08452             /* Okay, now we're safe to let it go -- in a sense, we were
08453                ready to let it go as soon as we locked it. */
08454             ast_unlock_context(tmp);
08455             __ast_internal_context_destroy(tmp);
08456          } else {
08457             ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
08458                     tmp->refcount, tmp->root);
08459             ast_unlock_context(tmp);
08460             next = tmp->next;
08461             tmpl = tmp;
08462          }
08463       } else if (con) {
08464          ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
08465          ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
08466          ast_hashtab_remove_this_object(contexttab, tmp);
08467 
08468          next = tmp->next;
08469          if (tmpl)
08470             tmpl->next = next;
08471          else
08472             contexts = next;
08473          /* Okay, now we're safe to let it go -- in a sense, we were
08474             ready to let it go as soon as we locked it. */
08475          ast_unlock_context(tmp);
08476          __ast_internal_context_destroy(tmp);
08477       }
08478 
08479       /* if we have a specific match, we are done, otherwise continue */
08480       tmp = con ? NULL : next;
08481    }
08482 }
08483 
08484 void ast_context_destroy(struct ast_context *con, const char *registrar)
08485 {
08486    ast_wrlock_contexts();
08487    __ast_context_destroy(contexts, contexts_table, con,registrar);
08488    ast_unlock_contexts();
08489 }
08490 
08491 static void wait_for_hangup(struct ast_channel *chan, void *data)
08492 {
08493    int res;
08494    struct ast_frame *f;
08495    double waitsec;
08496    int waittime;
08497 
08498    if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
08499       waitsec = -1;
08500    if (waitsec > -1) {
08501       waittime = waitsec * 1000.0;
08502       ast_safe_sleep(chan, waittime);
08503    } else do {
08504       res = ast_waitfor(chan, -1);
08505       if (res < 0)
08506          return;
08507       f = ast_read(chan);
08508       if (f)
08509          ast_frfree(f);
08510    } while(f);
08511 }
08512 
08513 /*!
08514  * \ingroup applications
08515  */
08516 static int pbx_builtin_proceeding(struct ast_channel *chan, void *data)
08517 {
08518    ast_indicate(chan, AST_CONTROL_PROCEEDING);
08519    return 0;
08520 }
08521 
08522 /*!
08523  * \ingroup applications
08524  */
08525 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
08526 {
08527    ast_indicate(chan, AST_CONTROL_PROGRESS);
08528    return 0;
08529 }
08530 
08531 /*!
08532  * \ingroup applications
08533  */
08534 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
08535 {
08536    ast_indicate(chan, AST_CONTROL_RINGING);
08537    return 0;
08538 }
08539 
08540 /*!
08541  * \ingroup applications
08542  */
08543 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
08544 {
08545    ast_indicate(chan, AST_CONTROL_BUSY);
08546    /* Don't change state of an UP channel, just indicate
08547       busy in audio */
08548    if (chan->_state != AST_STATE_UP) {
08549       ast_setstate(chan, AST_STATE_BUSY);
08550       ast_cdr_busy(chan->cdr);
08551    }
08552    wait_for_hangup(chan, data);
08553    return -1;
08554 }
08555 
08556 /*!
08557  * \ingroup applications
08558  */
08559 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
08560 {
08561    ast_indicate(chan, AST_CONTROL_CONGESTION);
08562    /* Don't change state of an UP channel, just indicate
08563       congestion in audio */
08564    if (chan->_state != AST_STATE_UP)
08565       ast_setstate(chan, AST_STATE_BUSY);
08566    wait_for_hangup(chan, data);
08567    return -1;
08568 }
08569 
08570 /*!
08571  * \ingroup applications
08572  */
08573 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
08574 {
08575    int delay = 0;
08576    int answer_cdr = 1;
08577    char *parse;
08578    AST_DECLARE_APP_ARGS(args,
08579       AST_APP_ARG(delay);
08580       AST_APP_ARG(answer_cdr);
08581    );
08582 
08583    if (ast_strlen_zero(data)) {
08584       return __ast_answer(chan, 0, 1);
08585    }
08586 
08587    parse = ast_strdupa(data);
08588 
08589    AST_STANDARD_APP_ARGS(args, parse);
08590 
08591    if (!ast_strlen_zero(args.delay) && (chan->_state != AST_STATE_UP))
08592       delay = atoi(data);
08593 
08594    if (delay < 0) {
08595       delay = 0;
08596    }
08597 
08598    if (!ast_strlen_zero(args.answer_cdr) && !strcasecmp(args.answer_cdr, "nocdr")) {
08599       answer_cdr = 0;
08600    }
08601 
08602    return __ast_answer(chan, delay, answer_cdr);
08603 }
08604 
08605 static int pbx_builtin_incomplete(struct ast_channel *chan, void *data)
08606 {
08607    char *options = data;
08608    int answer = 1;
08609 
08610    /* Some channels can receive DTMF in unanswered state; some cannot */
08611    if (!ast_strlen_zero(options) && strchr(options, 'n')) {
08612       answer = 0;
08613    }
08614 
08615    /* If the channel is hungup, stop waiting */
08616    if (ast_check_hangup(chan)) {
08617       return -1;
08618    } else if (chan->_state != AST_STATE_UP && answer) {
08619       __ast_answer(chan, 0, 1);
08620    }
08621 
08622    return AST_PBX_INCOMPLETE;
08623 }
08624 
08625 AST_APP_OPTIONS(resetcdr_opts, {
08626    AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
08627    AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
08628    AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
08629    AST_APP_OPTION('e', AST_CDR_FLAG_POST_ENABLE),
08630 });
08631 
08632 /*!
08633  * \ingroup applications
08634  */
08635 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
08636 {
08637    char *args;
08638    struct ast_flags flags = { 0 };
08639 
08640    if (!ast_strlen_zero(data)) {
08641       args = ast_strdupa(data);
08642       ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
08643    }
08644 
08645    ast_cdr_reset(chan->cdr, &flags);
08646 
08647    return 0;
08648 }
08649 
08650 /*!
08651  * \ingroup applications
08652  */
08653 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
08654 {
08655    /* Copy the AMA Flags as specified */
08656    ast_cdr_setamaflags(chan, data ? data : "");
08657    return 0;
08658 }
08659 
08660 /*!
08661  * \ingroup applications
08662  */
08663 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
08664 {
08665    if (!ast_strlen_zero(data)) {
08666       int cause;
08667       char *endptr;
08668 
08669       if ((cause = ast_str2cause(data)) > -1) {
08670          chan->hangupcause = cause;
08671          return -1;
08672       }
08673 
08674       cause = strtol((const char *) data, &endptr, 10);
08675       if (cause != 0 || (data != endptr)) {
08676          chan->hangupcause = cause;
08677          return -1;
08678       }
08679 
08680       ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
08681    }
08682 
08683    if (!chan->hangupcause) {
08684       chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
08685    }
08686 
08687    return -1;
08688 }
08689 
08690 /*!
08691  * \ingroup applications
08692  */
08693 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
08694 {
08695    char *s, *ts, *branch1, *branch2, *branch;
08696    struct ast_timing timing;
08697 
08698    if (ast_strlen_zero(data)) {
08699       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>[,<timezone>]?'labeliftrue':'labeliffalse'\n");
08700       return -1;
08701    }
08702 
08703    ts = s = ast_strdupa(data);
08704 
08705    /* Separate the Goto path */
08706    strsep(&ts, "?");
08707    branch1 = strsep(&ts,":");
08708    branch2 = strsep(&ts,"");
08709 
08710    /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
08711    if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
08712       branch = branch1;
08713    else
08714       branch = branch2;
08715    ast_destroy_timing(&timing);
08716 
08717    if (ast_strlen_zero(branch)) {
08718       ast_debug(1, "Not taking any branch\n");
08719       return 0;
08720    }
08721 
08722    return pbx_builtin_goto(chan, branch);
08723 }
08724 
08725 /*!
08726  * \ingroup applications
08727  */
08728 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
08729 {
08730    char *s, *appname;
08731    struct ast_timing timing;
08732    struct ast_app *app;
08733    static const char *usage = "ExecIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>[,<timezone>]?<appname>[(<appargs>)]";
08734 
08735    if (ast_strlen_zero(data)) {
08736       ast_log(LOG_WARNING, "%s\n", usage);
08737       return -1;
08738    }
08739 
08740    appname = ast_strdupa(data);
08741 
08742    s = strsep(&appname, "?"); /* Separate the timerange and application name/data */
08743    if (!appname) {   /* missing application */
08744       ast_log(LOG_WARNING, "%s\n", usage);
08745       return -1;
08746    }
08747 
08748    if (!ast_build_timing(&timing, s)) {
08749       ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
08750       ast_destroy_timing(&timing);
08751       return -1;
08752    }
08753 
08754    if (!ast_check_timing(&timing))  { /* outside the valid time window, just return */
08755       ast_destroy_timing(&timing);
08756       return 0;
08757    }
08758    ast_destroy_timing(&timing);
08759 
08760    /* now split appname(appargs) */
08761    if ((s = strchr(appname, '('))) {
08762       char *e;
08763       *s++ = '\0';
08764       if ((e = strrchr(s, ')')))
08765          *e = '\0';
08766       else
08767          ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
08768    }
08769 
08770 
08771    if ((app = pbx_findapp(appname))) {
08772       return pbx_exec(chan, app, S_OR(s, ""));
08773    } else {
08774       ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
08775       return -1;
08776    }
08777 }
08778 
08779 /*!
08780  * \ingroup applications
08781  */
08782 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
08783 {
08784    double s;
08785    int ms;
08786 
08787    /* Wait for "n" seconds */
08788    if (data && (s = atof(data)) > 0.0) {
08789       ms = s * 1000.0;
08790       return ast_safe_sleep(chan, ms);
08791    }
08792    return 0;
08793 }
08794 
08795 /*!
08796  * \ingroup applications
08797  */
08798 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
08799 {
08800    int ms, res;
08801    double s;
08802    struct ast_flags flags = {0};
08803    char *opts[1] = { NULL };
08804    char *parse;
08805    AST_DECLARE_APP_ARGS(args,
08806       AST_APP_ARG(timeout);
08807       AST_APP_ARG(options);
08808    );
08809 
08810    if (!ast_strlen_zero(data)) {
08811       parse = ast_strdupa(data);
08812       AST_STANDARD_APP_ARGS(args, parse);
08813    } else
08814       memset(&args, 0, sizeof(args));
08815 
08816    if (args.options)
08817       ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
08818 
08819    if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
08820       ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n"); 
08821    } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
08822       ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL), strlen(opts[0]));
08823    } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
08824       struct ast_tone_zone_sound *ts = ast_get_indication_tone(chan->zone, "dial");
08825       if (ts) {
08826          ast_playtones_start(chan, 0, ts->data, 0);
08827          ts = ast_tone_zone_sound_unref(ts);
08828       } else {
08829          ast_tonepair_start(chan, 350, 440, 0, 0);
08830       }
08831    }
08832    /* Wait for "n" seconds */
08833    if (args.timeout && (s = atof(args.timeout)) > 0)
08834        ms = s * 1000.0;
08835    else if (chan->pbx)
08836       ms = chan->pbx->rtimeoutms;
08837    else
08838       ms = 10000;
08839 
08840    res = ast_waitfordigit(chan, ms);
08841    if (!res) {
08842       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
08843          ast_verb(3, "Timeout on %s, continuing...\n", chan->name);
08844       } else if (chan->_softhangup & AST_SOFTHANGUP_TIMEOUT) {
08845          ast_verb(3, "Call timeout on %s, checking for 'T'\n", chan->name);
08846          res = -1;
08847       } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
08848          ast_verb(3, "Timeout on %s, going to 't'\n", chan->name);
08849          set_ext_pri(chan, "t", 0); /* 0 will become 1, next time through the loop */
08850       } else {
08851          ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
08852          res = -1;
08853       }
08854    }
08855 
08856    if (ast_test_flag(&flags, WAITEXTEN_MOH))
08857       ast_indicate(chan, AST_CONTROL_UNHOLD);
08858    else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
08859       ast_playtones_stop(chan);
08860 
08861    return res;
08862 }
08863 
08864 /*!
08865  * \ingroup applications
08866  */
08867 static int pbx_builtin_background(struct ast_channel *chan, void *data)
08868 {
08869    int res = 0;
08870    int mres = 0;
08871    struct ast_flags flags = {0};
08872    char *parse, exten[2] = "";
08873    AST_DECLARE_APP_ARGS(args,
08874       AST_APP_ARG(filename);
08875       AST_APP_ARG(options);
08876       AST_APP_ARG(lang);
08877       AST_APP_ARG(context);
08878    );
08879 
08880    if (ast_strlen_zero(data)) {
08881       ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
08882       return -1;
08883    }
08884 
08885    parse = ast_strdupa(data);
08886 
08887    AST_STANDARD_APP_ARGS(args, parse);
08888 
08889    if (ast_strlen_zero(args.lang))
08890       args.lang = (char *)chan->language; /* XXX this is const */
08891 
08892    if (ast_strlen_zero(args.context)) {
08893       const char *context;
08894       ast_channel_lock(chan);
08895       if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
08896          args.context = ast_strdupa(context);
08897       } else {
08898          args.context = chan->context;
08899       }
08900       ast_channel_unlock(chan);
08901    }
08902 
08903    if (args.options) {
08904       if (!strcasecmp(args.options, "skip"))
08905          flags.flags = BACKGROUND_SKIP;
08906       else if (!strcasecmp(args.options, "noanswer"))
08907          flags.flags = BACKGROUND_NOANSWER;
08908       else
08909          ast_app_parse_options(background_opts, &flags, NULL, args.options);
08910    }
08911 
08912    /* Answer if need be */
08913    if (chan->_state != AST_STATE_UP) {
08914       if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
08915          goto done;
08916       } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
08917          res = ast_answer(chan);
08918       }
08919    }
08920 
08921    if (!res) {
08922       char *back = args.filename;
08923       char *front;
08924 
08925       ast_stopstream(chan);      /* Stop anything playing */
08926       /* Stream the list of files */
08927       while (!res && (front = strsep(&back, "&")) ) {
08928          if ( (res = ast_streamfile(chan, front, args.lang)) ) {
08929             ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
08930             res = 0;
08931             mres = 1;
08932             break;
08933          }
08934          if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
08935             res = ast_waitstream(chan, "");
08936          } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
08937             res = ast_waitstream_exten(chan, args.context);
08938          } else {
08939             res = ast_waitstream(chan, AST_DIGIT_ANY);
08940          }
08941          ast_stopstream(chan);
08942       }
08943    }
08944 
08945    /*
08946     * If the single digit DTMF is an extension in the specified context, then
08947     * go there and signal no DTMF.  Otherwise, we should exit with that DTMF.
08948     * If we're in Macro, we'll exit and seek that DTMF as the beginning of an
08949     * extension in the Macro's calling context.  If we're not in Macro, then
08950     * we'll simply seek that extension in the calling context.  Previously,
08951     * someone complained about the behavior as it related to the interior of a
08952     * Gosub routine, and the fix (#14011) inadvertently broke FreePBX
08953     * (#14940).  This change should fix both of these situations, but with the
08954     * possible incompatibility that if a single digit extension does not exist
08955     * (but a longer extension COULD have matched), it would have previously
08956     * gone immediately to the "i" extension, but will now need to wait for a
08957     * timeout.
08958     *
08959     * Later, we had to add a flag to disable this workaround, because AGI
08960     * users can EXEC Background and reasonably expect that the DTMF code will
08961     * be returned (see #16434).
08962     */
08963    if (!ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS) &&
08964          (exten[0] = res) &&
08965          ast_canmatch_extension(chan, args.context, exten, 1, chan->cid.cid_num) &&
08966          !ast_matchmore_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
08967       snprintf(chan->exten, sizeof(chan->exten), "%c", res);
08968       ast_copy_string(chan->context, args.context, sizeof(chan->context));
08969       chan->priority = 0;
08970       res = 0;
08971    }
08972 done:
08973    pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
08974    return res;
08975 }
08976 
08977 /*! Goto
08978  * \ingroup applications
08979  */
08980 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
08981 {
08982    int res = ast_parseable_goto(chan, data);
08983    if (!res)
08984       ast_verb(3, "Goto (%s,%s,%d)\n", chan->context, chan->exten, chan->priority + 1);
08985    return res;
08986 }
08987 
08988 
08989 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
08990 {
08991    struct ast_var_t *variables;
08992    const char *var, *val;
08993    int total = 0;
08994 
08995    if (!chan)
08996       return 0;
08997 
08998    ast_str_reset(*buf);
08999 
09000    ast_channel_lock(chan);
09001 
09002    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
09003       if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
09004          /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
09005          ) {
09006          if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
09007             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
09008             break;
09009          } else
09010             total++;
09011       } else
09012          break;
09013    }
09014 
09015    ast_channel_unlock(chan);
09016 
09017    return total;
09018 }
09019 
09020 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
09021 {
09022    struct ast_var_t *variables;
09023    const char *ret = NULL;
09024    int i;
09025    struct varshead *places[2] = { NULL, &globals };
09026 
09027    if (!name)
09028       return NULL;
09029 
09030    if (chan) {
09031       ast_channel_lock(chan);
09032       places[0] = &chan->varshead;
09033    }
09034 
09035    for (i = 0; i < 2; i++) {
09036       if (!places[i])
09037          continue;
09038       if (places[i] == &globals)
09039          ast_rwlock_rdlock(&globalslock);
09040       AST_LIST_TRAVERSE(places[i], variables, entries) {
09041          if (!strcmp(name, ast_var_name(variables))) {
09042             ret = ast_var_value(variables);
09043             break;
09044          }
09045       }
09046       if (places[i] == &globals)
09047          ast_rwlock_unlock(&globalslock);
09048       if (ret)
09049          break;
09050    }
09051 
09052    if (chan)
09053       ast_channel_unlock(chan);
09054 
09055    return ret;
09056 }
09057 
09058 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
09059 {
09060    struct ast_var_t *newvariable;
09061    struct varshead *headp;
09062 
09063    if (name[strlen(name)-1] == ')') {
09064       char *function = ast_strdupa(name);
09065 
09066       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
09067       ast_func_write(chan, function, value);
09068       return;
09069    }
09070 
09071    if (chan) {
09072       ast_channel_lock(chan);
09073       headp = &chan->varshead;
09074    } else {
09075       ast_rwlock_wrlock(&globalslock);
09076       headp = &globals;
09077    }
09078 
09079    if (value) {
09080       if (headp == &globals)
09081          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
09082       newvariable = ast_var_assign(name, value);
09083       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
09084    }
09085 
09086    if (chan)
09087       ast_channel_unlock(chan);
09088    else
09089       ast_rwlock_unlock(&globalslock);
09090 }
09091 
09092 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
09093 {
09094    struct ast_var_t *newvariable;
09095    struct varshead *headp;
09096    const char *nametail = name;
09097 
09098    if (name[strlen(name) - 1] == ')') {
09099       char *function = ast_strdupa(name);
09100 
09101       ast_func_write(chan, function, value);
09102       return;
09103    }
09104 
09105    if (chan) {
09106       ast_channel_lock(chan);
09107       headp = &chan->varshead;
09108    } else {
09109       ast_rwlock_wrlock(&globalslock);
09110       headp = &globals;
09111    }
09112 
09113    /* For comparison purposes, we have to strip leading underscores */
09114    if (*nametail == '_') {
09115       nametail++;
09116       if (*nametail == '_')
09117          nametail++;
09118    }
09119 
09120    AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
09121       if (strcmp(ast_var_name(newvariable), nametail) == 0) {
09122          /* there is already such a variable, delete it */
09123          AST_LIST_REMOVE_CURRENT(entries);
09124          ast_var_delete(newvariable);
09125          break;
09126       }
09127    }
09128    AST_LIST_TRAVERSE_SAFE_END;
09129 
09130    if (value) {
09131       if (headp == &globals)
09132          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
09133       newvariable = ast_var_assign(name, value);
09134       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
09135       manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
09136          "Channel: %s\r\n"
09137          "Variable: %s\r\n"
09138          "Value: %s\r\n"
09139          "Uniqueid: %s\r\n",
09140          chan ? chan->name : "none", name, value,
09141          chan ? chan->uniqueid : "none");
09142    }
09143 
09144    if (chan)
09145       ast_channel_unlock(chan);
09146    else
09147       ast_rwlock_unlock(&globalslock);
09148 }
09149 
09150 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
09151 {
09152    char *name, *value, *mydata;
09153 
09154    if (ast_compat_app_set) {
09155       return pbx_builtin_setvar_multiple(chan, data);
09156    }
09157 
09158    if (ast_strlen_zero(data)) {
09159       ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
09160       return 0;
09161    }
09162 
09163    mydata = ast_strdupa(data);
09164    name = strsep(&mydata, "=");
09165    value = mydata;
09166    if (!value) {
09167       ast_log(LOG_WARNING, "Set requires an '=' to be a valid assignment.\n");
09168       return 0;
09169    }
09170 
09171    if (strchr(name, ' ')) {
09172       ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
09173    }
09174 
09175    pbx_builtin_setvar_helper(chan, name, value);
09176 
09177    return 0;
09178 }
09179 
09180 int pbx_builtin_setvar_multiple(struct ast_channel *chan, void *vdata)
09181 {
09182    char *data;
09183    int x;
09184    AST_DECLARE_APP_ARGS(args,
09185       AST_APP_ARG(pair)[24];
09186    );
09187    AST_DECLARE_APP_ARGS(pair,
09188       AST_APP_ARG(name);
09189       AST_APP_ARG(value);
09190    );
09191 
09192    if (ast_strlen_zero(vdata)) {
09193       ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
09194       return 0;
09195    }
09196 
09197    data = ast_strdupa(vdata);
09198    AST_STANDARD_APP_ARGS(args, data);
09199 
09200    for (x = 0; x < args.argc; x++) {
09201       AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
09202       if (pair.argc == 2) {
09203          pbx_builtin_setvar_helper(chan, pair.name, pair.value);
09204          if (strchr(pair.name, ' '))
09205             ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
09206       } else if (!chan) {
09207          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
09208       } else {
09209          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority);
09210       }
09211    }
09212 
09213    return 0;
09214 }
09215 
09216 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
09217 {
09218    char *name;
09219    char *value;
09220    char *channel;
09221    char tmp[VAR_BUF_SIZE];
09222    static int deprecation_warning = 0;
09223 
09224    if (ast_strlen_zero(data)) {
09225       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
09226       return 0;
09227    }
09228    tmp[0] = 0;
09229    if (!deprecation_warning) {
09230       ast_log(LOG_WARNING, "ImportVar is deprecated.  Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
09231       deprecation_warning = 1;
09232    }
09233 
09234    value = ast_strdupa(data);
09235    name = strsep(&value,"=");
09236    channel = strsep(&value,",");
09237    if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
09238       struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
09239       if (chan2) {
09240          char *s = alloca(strlen(value) + 4);
09241          if (s) {
09242             sprintf(s, "${%s}", value);
09243             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
09244          }
09245          ast_channel_unlock(chan2);
09246       }
09247       pbx_builtin_setvar_helper(chan, name, tmp);
09248    }
09249 
09250    return(0);
09251 }
09252 
09253 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
09254 {
09255    return 0;
09256 }
09257 
09258 void pbx_builtin_clear_globals(void)
09259 {
09260    struct ast_var_t *vardata;
09261 
09262    ast_rwlock_wrlock(&globalslock);
09263    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
09264       ast_var_delete(vardata);
09265    ast_rwlock_unlock(&globalslock);
09266 }
09267 
09268 int pbx_checkcondition(const char *condition)
09269 {
09270    int res;
09271    if (ast_strlen_zero(condition)) {                /* NULL or empty strings are false */
09272       return 0;
09273    } else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
09274       return res;
09275    } else {                                         /* Strings are true */
09276       return 1;
09277    }
09278 }
09279 
09280 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
09281 {
09282    char *condition, *branch1, *branch2, *branch;
09283    char *stringp;
09284 
09285    if (ast_strlen_zero(data)) {
09286       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
09287       return 0;
09288    }
09289 
09290    stringp = ast_strdupa(data);
09291    condition = strsep(&stringp,"?");
09292    branch1 = strsep(&stringp,":");
09293    branch2 = strsep(&stringp,"");
09294    branch = pbx_checkcondition(condition) ? branch1 : branch2;
09295 
09296    if (ast_strlen_zero(branch)) {
09297       ast_debug(1, "Not taking any branch\n");
09298       return 0;
09299    }
09300 
09301    return pbx_builtin_goto(chan, branch);
09302 }
09303 
09304 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
09305 {
09306    char tmp[256];
09307    char *number = tmp;
09308    char *options;
09309 
09310    if (ast_strlen_zero(data)) {
09311       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
09312       return -1;
09313    }
09314    ast_copy_string(tmp, data, sizeof(tmp));
09315    strsep(&number, ",");
09316    options = strsep(&number, ",");
09317    if (options) {
09318       if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
09319          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
09320          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
09321          return -1;
09322       }
09323    }
09324 
09325    if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
09326       ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
09327    }
09328 
09329    return 0;
09330 }
09331 
09332 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
09333 {
09334    int res = 0;
09335 
09336    if (data)
09337       res = ast_say_digit_str(chan, data, "", chan->language);
09338    return res;
09339 }
09340 
09341 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
09342 {
09343    int res = 0;
09344 
09345    if (data)
09346       res = ast_say_character_str(chan, data, "", chan->language);
09347    return res;
09348 }
09349 
09350 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
09351 {
09352    int res = 0;
09353 
09354    if (data)
09355       res = ast_say_phonetic_str(chan, data, "", chan->language);
09356    return res;
09357 }
09358 
09359 static void device_state_cb(const struct ast_event *event, void *unused)
09360 {
09361    const char *device;
09362    struct statechange *sc;
09363 
09364    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
09365    if (ast_strlen_zero(device)) {
09366       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
09367       return;
09368    }
09369 
09370    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
09371       return;
09372    strcpy(sc->dev, device);
09373    if (ast_taskprocessor_push(device_state_tps, handle_statechange, sc) < 0) {
09374       ast_free(sc);
09375    }
09376 }
09377 
09378 int load_pbx(void)
09379 {
09380    int x;
09381 
09382    /* Initialize the PBX */
09383    ast_verb(1, "Asterisk PBX Core Initializing\n");
09384    if (!(device_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
09385       ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
09386    }
09387 
09388    ast_verb(1, "Registering builtin applications:\n");
09389    ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
09390    __ast_custom_function_register(&exception_function, NULL);
09391 
09392    /* Register builtin applications */
09393    for (x = 0; x < ARRAY_LEN(builtins); x++) {
09394       ast_verb(1, "[%s]\n", builtins[x].name);
09395       if (ast_register_application2(builtins[x].name, builtins[x].execute, NULL, NULL, NULL)) {
09396          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
09397          return -1;
09398       }
09399    }
09400 
09401    /* Register manager application */
09402    ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
09403 
09404    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
09405          AST_EVENT_IE_END))) {
09406       return -1;
09407    }
09408 
09409    return 0;
09410 }
09411 
09412 /*
09413  * Lock context list functions ...
09414  */
09415 int ast_wrlock_contexts()
09416 {
09417    return ast_mutex_lock(&conlock);
09418 }
09419 
09420 int ast_rdlock_contexts()
09421 {
09422    return ast_mutex_lock(&conlock);
09423 }
09424 
09425 int ast_unlock_contexts()
09426 {
09427    return ast_mutex_unlock(&conlock);
09428 }
09429 
09430 /*
09431  * Lock context ...
09432  */
09433 int ast_wrlock_context(struct ast_context *con)
09434 {
09435    return ast_rwlock_wrlock(&con->lock);
09436 }
09437 
09438 int ast_rdlock_context(struct ast_context *con)
09439 {
09440    return ast_rwlock_rdlock(&con->lock);
09441 }
09442 
09443 int ast_unlock_context(struct ast_context *con)
09444 {
09445    return ast_rwlock_unlock(&con->lock);
09446 }
09447 
09448 /*
09449  * Name functions ...
09450  */
09451 const char *ast_get_context_name(struct ast_context *con)
09452 {
09453    return con ? con->name : NULL;
09454 }
09455 
09456 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
09457 {
09458    return exten ? exten->parent : NULL;
09459 }
09460 
09461 const char *ast_get_extension_name(struct ast_exten *exten)
09462 {
09463    return exten ? exten->exten : NULL;
09464 }
09465 
09466 const char *ast_get_extension_label(struct ast_exten *exten)
09467 {
09468    return exten ? exten->label : NULL;
09469 }
09470 
09471 const char *ast_get_include_name(struct ast_include *inc)
09472 {
09473    return inc ? inc->name : NULL;
09474 }
09475 
09476 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
09477 {
09478    return ip ? ip->pattern : NULL;
09479 }
09480 
09481 int ast_get_extension_priority(struct ast_exten *exten)
09482 {
09483    return exten ? exten->priority : -1;
09484 }
09485 
09486 /*
09487  * Registrar info functions ...
09488  */
09489 const char *ast_get_context_registrar(struct ast_context *c)
09490 {
09491    return c ? c->registrar : NULL;
09492 }
09493 
09494 const char *ast_get_extension_registrar(struct ast_exten *e)
09495 {
09496    return e ? e->registrar : NULL;
09497 }
09498 
09499 const char *ast_get_include_registrar(struct ast_include *i)
09500 {
09501    return i ? i->registrar : NULL;
09502 }
09503 
09504 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
09505 {
09506    return ip ? ip->registrar : NULL;
09507 }
09508 
09509 int ast_get_extension_matchcid(struct ast_exten *e)
09510 {
09511    return e ? e->matchcid : 0;
09512 }
09513 
09514 const char *ast_get_extension_cidmatch(struct ast_exten *e)
09515 {
09516    return e ? e->cidmatch : NULL;
09517 }
09518 
09519 const char *ast_get_extension_app(struct ast_exten *e)
09520 {
09521    return e ? e->app : NULL;
09522 }
09523 
09524 void *ast_get_extension_app_data(struct ast_exten *e)
09525 {
09526    return e ? e->data : NULL;
09527 }
09528 
09529 const char *ast_get_switch_name(struct ast_sw *sw)
09530 {
09531    return sw ? sw->name : NULL;
09532 }
09533 
09534 const char *ast_get_switch_data(struct ast_sw *sw)
09535 {
09536    return sw ? sw->data : NULL;
09537 }
09538 
09539 int ast_get_switch_eval(struct ast_sw *sw)
09540 {
09541    return sw->eval;
09542 }
09543 
09544 const char *ast_get_switch_registrar(struct ast_sw *sw)
09545 {
09546    return sw ? sw->registrar : NULL;
09547 }
09548 
09549 /*
09550  * Walking functions ...
09551  */
09552 struct ast_context *ast_walk_contexts(struct ast_context *con)
09553 {
09554    return con ? con->next : contexts;
09555 }
09556 
09557 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
09558    struct ast_exten *exten)
09559 {
09560    if (!exten)
09561       return con ? con->root : NULL;
09562    else
09563       return exten->next;
09564 }
09565 
09566 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
09567    struct ast_sw *sw)
09568 {
09569    if (!sw)
09570       return con ? AST_LIST_FIRST(&con->alts) : NULL;
09571    else
09572       return AST_LIST_NEXT(sw, list);
09573 }
09574 
09575 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
09576    struct ast_exten *priority)
09577 {
09578    return priority ? priority->peer : exten;
09579 }
09580 
09581 struct ast_include *ast_walk_context_includes(struct ast_context *con,
09582    struct ast_include *inc)
09583 {
09584    if (!inc)
09585       return con ? con->includes : NULL;
09586    else
09587       return inc->next;
09588 }
09589 
09590 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
09591    struct ast_ignorepat *ip)
09592 {
09593    if (!ip)
09594       return con ? con->ignorepats : NULL;
09595    else
09596       return ip->next;
09597 }
09598 
09599 int ast_context_verify_includes(struct ast_context *con)
09600 {
09601    struct ast_include *inc = NULL;
09602    int res = 0;
09603 
09604    while ( (inc = ast_walk_context_includes(con, inc)) ) {
09605       if (ast_context_find(inc->rname))
09606          continue;
09607 
09608       res = -1;
09609       ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
09610          ast_get_context_name(con), inc->rname);
09611       break;
09612    }
09613 
09614    return res;
09615 }
09616 
09617 
09618 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
09619 {
09620    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
09621 
09622    if (!chan)
09623       return -2;
09624 
09625    if (context == NULL)
09626       context = chan->context;
09627    if (exten == NULL)
09628       exten = chan->exten;
09629 
09630    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
09631    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
09632       return goto_func(chan, context, exten, priority);
09633    else
09634       return -3;
09635 }
09636 
09637 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
09638 {
09639    return __ast_goto_if_exists(chan, context, exten, priority, 0);
09640 }
09641 
09642 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
09643 {
09644    return __ast_goto_if_exists(chan, context, exten, priority, 1);
09645 }
09646 
09647 static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
09648 {
09649    char *exten, *pri, *context;
09650    char *stringp;
09651    int ipri;
09652    int mode = 0;
09653 
09654    if (ast_strlen_zero(goto_string)) {
09655       ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
09656       return -1;
09657    }
09658    stringp = ast_strdupa(goto_string);
09659    context = strsep(&stringp, ","); /* guaranteed non-null */
09660    exten = strsep(&stringp, ",");
09661    pri = strsep(&stringp, ",");
09662    if (!exten) {  /* Only a priority in this one */
09663       pri = context;
09664       exten = NULL;
09665       context = NULL;
09666    } else if (!pri) {   /* Only an extension and priority in this one */
09667       pri = exten;
09668       exten = context;
09669       context = NULL;
09670    }
09671    if (*pri == '+') {
09672       mode = 1;
09673       pri++;
09674    } else if (*pri == '-') {
09675       mode = -1;
09676       pri++;
09677    }
09678    if (sscanf(pri, "%30d", &ipri) != 1) {
09679       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
09680          pri, chan->cid.cid_num)) < 1) {
09681          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
09682          return -1;
09683       } else
09684          mode = 0;
09685    }
09686    /* At this point we have a priority and maybe an extension and a context */
09687 
09688    if (mode)
09689       ipri = chan->priority + (ipri * mode);
09690 
09691    if (async)
09692       ast_async_goto(chan, context, exten, ipri);
09693    else
09694       ast_explicit_goto(chan, context, exten, ipri);
09695 
09696    return 0;
09697 
09698 }
09699 
09700 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
09701 {
09702    return pbx_parseable_goto(chan, goto_string, 0);
09703 }
09704 
09705 int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
09706 {
09707    return pbx_parseable_goto(chan, goto_string, 1);
09708 }
09709 
09710 static int hint_hash(const void *obj, const int flags)
09711 {
09712    const struct ast_hint *hint = obj;
09713 
09714    int res = -1;
09715 
09716    if (ast_get_extension_name(hint->exten)) {
09717       res = ast_str_case_hash(ast_get_extension_name(hint->exten));
09718    }
09719 
09720    return res;
09721 }
09722 
09723 static int hint_cmp(void *obj, void *arg, int flags)
09724 {
09725    const struct ast_hint *hint = obj;
09726    const struct ast_exten *exten = arg;
09727 
09728    return (hint->exten == exten) ? CMP_MATCH | CMP_STOP : 0;
09729 }
09730 
09731 static int statecbs_cmp(void *obj, void *arg, int flags)
09732 {
09733    const struct ast_state_cb *state_cb = obj;
09734    const struct ast_state_cb *callback = arg;
09735 
09736    return (state_cb == callback) ? CMP_MATCH | CMP_STOP : 0;
09737 }
09738 
09739 int ast_pbx_init(void)
09740 {
09741    hints = ao2_container_alloc(HASH_EXTENHINT_SIZE, hint_hash, hint_cmp);
09742    statecbs = ao2_container_alloc(HASH_EXTENHINT_SIZE, NULL, statecbs_cmp);
09743 
09744    return (hints && statecbs) ? 0 : -1;
09745 }