Sun Oct 16 2011 08:41:42

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