Mon Apr 28 2014 10:05:44

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