Tue Aug 24 2010 19:41:31

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