Wed Nov 28 2012 04:18:12

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