Sat Feb 11 06:33:19 2012

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

Generated on Sat Feb 11 06:33:19 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6