Wed Apr 6 11:29:46 2011

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

Generated on Wed Apr 6 11:29:46 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7