Mon Sep 20 2010 00:23:14

Asterisk developer's documentation


pbx.c

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