Wed Nov 28 2012 04:18:01

Asterisk developer's documentation


app_queue.c
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, 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 True call queues with optional send URL on answer
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  *
00025  * \arg Config in \ref Config_qu queues.conf
00026  *
00027  * \par Development notes
00028  * \note 2004-11-25: Persistent Dynamic Members added by:
00029  *             NetNation Communications (www.netnation.com)
00030  *             Kevin Lindsay <kevinl@netnation.com>
00031  *
00032  *             Each dynamic agent in each queue is now stored in the astdb.
00033  *             When asterisk is restarted, each agent will be automatically
00034  *             readded into their recorded queues. This feature can be
00035  *             configured with the 'persistent_members=<1|0>' setting in the
00036  *             '[general]' category in queues.conf. The default is on.
00037  *
00038  * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
00039  *
00040  * \note These features added by David C. Troy <dave@toad.net>:
00041  *    - Per-queue holdtime calculation
00042  *    - Estimated holdtime announcement
00043  *    - Position announcement
00044  *    - Abandoned/completed call counters
00045  *    - Failout timer passed as optional app parameter
00046  *    - Optional monitoring of calls, started when call is answered
00047  *
00048  * Patch Version 1.07 2003-12-24 01
00049  *
00050  * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
00051  * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
00052  *
00053  * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
00054  * by Matthew Enger <m.enger@xi.com.au>
00055  *
00056  * \ingroup applications
00057  */
00058 
00059 /*** MODULEINFO
00060    <use>res_monitor</use>
00061    <support_level>core</support_level>
00062  ***/
00063 
00064 #include "asterisk.h"
00065 
00066 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 374108 $")
00067 
00068 #include <sys/time.h>
00069 #include <sys/signal.h>
00070 #include <netinet/in.h>
00071 #include <ctype.h>
00072 
00073 #include "asterisk/lock.h"
00074 #include "asterisk/file.h"
00075 #include "asterisk/channel.h"
00076 #include "asterisk/pbx.h"
00077 #include "asterisk/app.h"
00078 #include "asterisk/linkedlists.h"
00079 #include "asterisk/module.h"
00080 #include "asterisk/translate.h"
00081 #include "asterisk/say.h"
00082 #include "asterisk/features.h"
00083 #include "asterisk/musiconhold.h"
00084 #include "asterisk/cli.h"
00085 #include "asterisk/manager.h"
00086 #include "asterisk/config.h"
00087 #include "asterisk/monitor.h"
00088 #include "asterisk/utils.h"
00089 #include "asterisk/causes.h"
00090 #include "asterisk/astdb.h"
00091 #include "asterisk/devicestate.h"
00092 #include "asterisk/stringfields.h"
00093 #include "asterisk/event.h"
00094 #include "asterisk/astobj2.h"
00095 #include "asterisk/strings.h"
00096 #include "asterisk/global_datastores.h"
00097 #include "asterisk/taskprocessor.h"
00098 #include "asterisk/aoc.h"
00099 #include "asterisk/callerid.h"
00100 #include "asterisk/cel.h"
00101 #include "asterisk/data.h"
00102 
00103 /* Define, to debug reference counts on queues, without debugging reference counts on queue members */
00104 /* #define REF_DEBUG_ONLY_QUEUES */
00105 
00106 /*!
00107  * \par Please read before modifying this file.
00108  * There are three locks which are regularly used
00109  * throughout this file, the queue list lock, the lock
00110  * for each individual queue, and the interface list lock.
00111  * Please be extra careful to always lock in the following order
00112  * 1) queue list lock
00113  * 2) individual queue lock
00114  * 3) interface list lock
00115  * This order has sort of "evolved" over the lifetime of this
00116  * application, but it is now in place this way, so please adhere
00117  * to this order!
00118  */
00119 
00120 /*** DOCUMENTATION
00121    <application name="Queue" language="en_US">
00122       <synopsis>
00123          Queue a call for a call queue.
00124       </synopsis>
00125       <syntax>
00126          <parameter name="queuename" required="true" />
00127          <parameter name="options">
00128             <optionlist>
00129                <option name="C">
00130                   <para>Mark all calls as "answered elsewhere" when cancelled.</para>
00131                </option>
00132                <option name="c">
00133                   <para>Continue in the dialplan if the callee hangs up.</para>
00134                </option>
00135                <option name="d">
00136                   <para>data-quality (modem) call (minimum delay).</para>
00137                </option>
00138                <option name="h">
00139                   <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
00140                </option>
00141                <option name="H">
00142                   <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
00143                </option>
00144                <option name="n">
00145                   <para>No retries on the timeout; will exit this application and
00146                   go to the next step.</para>
00147                </option>
00148                <option name="i">
00149                   <para>Ignore call forward requests from queue members and do nothing
00150                   when they are requested.</para>
00151                </option>
00152                <option name="I">
00153                   <para>Asterisk will ignore any connected line update requests or any redirecting party
00154                   update requests it may receive on this dial attempt.</para>
00155                </option>
00156                <option name="r">
00157                   <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
00158                </option>
00159                <option name="R">
00160                   <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
00161                </option>
00162                <option name="t">
00163                   <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
00164                </option>
00165                <option name="T">
00166                   <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
00167                </option>
00168                <option name="w">
00169                   <para>Allow the <emphasis>called</emphasis> user to write the conversation to
00170                   disk via Monitor.</para>
00171                </option>
00172                <option name="W">
00173                   <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
00174                   disk via Monitor.</para>
00175                </option>
00176                <option name="k">
00177                   <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
00178                   the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
00179                </option>
00180                <option name="K">
00181                   <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
00182                   the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
00183                </option>
00184                <option name="x">
00185                   <para>Allow the <emphasis>called</emphasis> user to write the conversation
00186                   to disk via MixMonitor.</para>
00187                </option>
00188                <option name="X">
00189                   <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
00190                   disk via MixMonitor.</para>
00191                </option>
00192             </optionlist>
00193          </parameter>
00194          <parameter name="URL">
00195             <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
00196          </parameter>
00197          <parameter name="announceoverride" />
00198          <parameter name="timeout">
00199             <para>Will cause the queue to fail out after a specified number of
00200             seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
00201             <replaceable>retry</replaceable> cycle.</para>
00202          </parameter>
00203          <parameter name="AGI">
00204             <para>Will setup an AGI script to be executed on the calling party's channel once they are
00205             connected to a queue member.</para>
00206          </parameter>
00207          <parameter name="macro">
00208             <para>Will run a macro on the calling party's channel once they are connected to a queue member.</para>
00209          </parameter>
00210          <parameter name="gosub">
00211             <para>Will run a gosub on the calling party's channel once they are connected to a queue member.</para>
00212          </parameter>
00213          <parameter name="rule">
00214             <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
00215          </parameter>
00216          <parameter name="position">
00217             <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
00218             would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
00219             the caller third in the queue.</para>
00220          </parameter>
00221       </syntax>
00222       <description>
00223          <para>In addition to transferring the call, a call may be parked and then picked
00224          up by another user.</para>
00225          <para>This application will return to the dialplan if the queue does not exist, or
00226          any of the join options cause the caller to not enter the queue.</para>
00227          <para>This application does not automatically answer and should be preceeded
00228          by an application such as Answer(), Progress(), or Ringing().</para>
00229          <para>This application sets the following channel variable upon completion:</para>
00230          <variablelist>
00231             <variable name="QUEUESTATUS">
00232                <para>The status of the call as a text string.</para>
00233                <value name="TIMEOUT" />
00234                <value name="FULL" />
00235                <value name="JOINEMPTY" />
00236                <value name="LEAVEEMPTY" />
00237                <value name="JOINUNAVAIL" />
00238                <value name="LEAVEUNAVAIL" />
00239                <value name="CONTINUE" />
00240             </variable>
00241          </variablelist>
00242       </description>
00243       <see-also>
00244          <ref type="application">Queue</ref>
00245          <ref type="application">QueueLog</ref>
00246          <ref type="application">AddQueueMember</ref>
00247          <ref type="application">RemoveQueueMember</ref>
00248          <ref type="application">PauseQueueMember</ref>
00249          <ref type="application">UnpauseQueueMember</ref>
00250          <ref type="function">QUEUE_VARIABLES</ref>
00251          <ref type="function">QUEUE_MEMBER</ref>
00252          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00253          <ref type="function">QUEUE_EXISTS</ref>
00254          <ref type="function">QUEUE_WAITING_COUNT</ref>
00255          <ref type="function">QUEUE_MEMBER_LIST</ref>
00256          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00257       </see-also>
00258    </application>
00259    <application name="AddQueueMember" language="en_US">
00260       <synopsis>
00261          Dynamically adds queue members.
00262       </synopsis>
00263       <syntax>
00264          <parameter name="queuename" required="true" />
00265          <parameter name="interface" />
00266          <parameter name="penalty" />
00267          <parameter name="options" />
00268          <parameter name="membername" />
00269          <parameter name="stateinterface" />
00270       </syntax>
00271       <description>
00272          <para>Dynamically adds interface to an existing queue. If the interface is
00273          already in the queue it will return an error.</para>
00274          <para>This application sets the following channel variable upon completion:</para>
00275          <variablelist>
00276             <variable name="AQMSTATUS">
00277                <para>The status of the attempt to add a queue member as a text string.</para>
00278                <value name="ADDED" />
00279                <value name="MEMBERALREADY" />
00280                <value name="NOSUCHQUEUE" />
00281             </variable>
00282          </variablelist>
00283       </description>
00284       <see-also>
00285          <ref type="application">Queue</ref>
00286          <ref type="application">QueueLog</ref>
00287          <ref type="application">AddQueueMember</ref>
00288          <ref type="application">RemoveQueueMember</ref>
00289          <ref type="application">PauseQueueMember</ref>
00290          <ref type="application">UnpauseQueueMember</ref>
00291          <ref type="function">QUEUE_VARIABLES</ref>
00292          <ref type="function">QUEUE_MEMBER</ref>
00293          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00294          <ref type="function">QUEUE_EXISTS</ref>
00295          <ref type="function">QUEUE_WAITING_COUNT</ref>
00296          <ref type="function">QUEUE_MEMBER_LIST</ref>
00297          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00298       </see-also>
00299    </application>
00300    <application name="RemoveQueueMember" language="en_US">
00301       <synopsis>
00302          Dynamically removes queue members.
00303       </synopsis>
00304       <syntax>
00305          <parameter name="queuename" required="true" />
00306          <parameter name="interface" />
00307       </syntax>
00308       <description>
00309          <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
00310          <para>This application sets the following channel variable upon completion:</para>
00311          <variablelist>
00312             <variable name="RQMSTATUS">
00313                <value name="REMOVED" />
00314                <value name="NOTINQUEUE" />
00315                <value name="NOSUCHQUEUE" />
00316                <value name="NOTDYNAMIC" />
00317             </variable>
00318          </variablelist>
00319          <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
00320       </description>
00321       <see-also>
00322          <ref type="application">Queue</ref>
00323          <ref type="application">QueueLog</ref>
00324          <ref type="application">AddQueueMember</ref>
00325          <ref type="application">RemoveQueueMember</ref>
00326          <ref type="application">PauseQueueMember</ref>
00327          <ref type="application">UnpauseQueueMember</ref>
00328          <ref type="function">QUEUE_VARIABLES</ref>
00329          <ref type="function">QUEUE_MEMBER</ref>
00330          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00331          <ref type="function">QUEUE_EXISTS</ref>
00332          <ref type="function">QUEUE_WAITING_COUNT</ref>
00333          <ref type="function">QUEUE_MEMBER_LIST</ref>
00334          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00335       </see-also>
00336    </application>
00337    <application name="PauseQueueMember" language="en_US">
00338       <synopsis>
00339          Pauses a queue member.
00340       </synopsis>
00341       <syntax>
00342          <parameter name="queuename" />
00343          <parameter name="interface" required="true" />
00344          <parameter name="options" />
00345          <parameter name="reason">
00346             <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
00347          </parameter>
00348       </syntax>
00349       <description>
00350          <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
00351          This prevents any calls from being sent from the queue to the interface until it is
00352          unpaused with UnpauseQueueMember or the manager interface.  If no queuename is given,
00353          the interface is paused in every queue it is a member of. The application will fail if the
00354          interface is not found.</para>
00355          <para>This application sets the following channel variable upon completion:</para>
00356          <variablelist>
00357             <variable name="PQMSTATUS">
00358                <para>The status of the attempt to pause a queue member as a text string.</para>
00359                <value name="PAUSED" />
00360                <value name="NOTFOUND" />
00361             </variable>
00362          </variablelist>
00363          <para>Example: PauseQueueMember(,SIP/3000)</para>
00364       </description>
00365       <see-also>
00366          <ref type="application">Queue</ref>
00367          <ref type="application">QueueLog</ref>
00368          <ref type="application">AddQueueMember</ref>
00369          <ref type="application">RemoveQueueMember</ref>
00370          <ref type="application">PauseQueueMember</ref>
00371          <ref type="application">UnpauseQueueMember</ref>
00372          <ref type="function">QUEUE_VARIABLES</ref>
00373          <ref type="function">QUEUE_MEMBER</ref>
00374          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00375          <ref type="function">QUEUE_EXISTS</ref>
00376          <ref type="function">QUEUE_WAITING_COUNT</ref>
00377          <ref type="function">QUEUE_MEMBER_LIST</ref>
00378          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00379       </see-also>
00380    </application>
00381    <application name="UnpauseQueueMember" language="en_US">
00382       <synopsis>
00383          Unpauses a queue member.      
00384       </synopsis>
00385       <syntax>
00386          <parameter name="queuename" />
00387          <parameter name="interface" required="true" />
00388          <parameter name="options" />
00389          <parameter name="reason">
00390             <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
00391          </parameter>
00392       </syntax>
00393       <description>
00394          <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
00395          and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
00396          <para>This application sets the following channel variable upon completion:</para>
00397          <variablelist>
00398             <variable name="UPQMSTATUS">
00399                <para>The status of the attempt to unpause a queue member as a text string.</para>
00400                <value name="UNPAUSED" />
00401                <value name="NOTFOUND" />
00402             </variable>
00403          </variablelist>
00404          <para>Example: UnpauseQueueMember(,SIP/3000)</para>
00405       </description>
00406       <see-also>
00407          <ref type="application">Queue</ref>
00408          <ref type="application">QueueLog</ref>
00409          <ref type="application">AddQueueMember</ref>
00410          <ref type="application">RemoveQueueMember</ref>
00411          <ref type="application">PauseQueueMember</ref>
00412          <ref type="application">UnpauseQueueMember</ref>
00413          <ref type="function">QUEUE_VARIABLES</ref>
00414          <ref type="function">QUEUE_MEMBER</ref>
00415          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00416          <ref type="function">QUEUE_EXISTS</ref>
00417          <ref type="function">QUEUE_WAITING_COUNT</ref>
00418          <ref type="function">QUEUE_MEMBER_LIST</ref>
00419          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00420       </see-also>
00421    </application>
00422    <application name="QueueLog" language="en_US">
00423       <synopsis>
00424          Writes to the queue_log file.
00425       </synopsis>
00426       <syntax>
00427          <parameter name="queuename" required="true" />
00428          <parameter name="uniqueid" required="true" />
00429          <parameter name="agent" required="true" />
00430          <parameter name="event" required="true" />
00431          <parameter name="additionalinfo" />
00432       </syntax>
00433       <description>
00434          <para>Allows you to write your own events into the queue log.</para>
00435          <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
00436       </description>
00437       <see-also>
00438          <ref type="application">Queue</ref>
00439          <ref type="application">QueueLog</ref>
00440          <ref type="application">AddQueueMember</ref>
00441          <ref type="application">RemoveQueueMember</ref>
00442          <ref type="application">PauseQueueMember</ref>
00443          <ref type="application">UnpauseQueueMember</ref>
00444          <ref type="function">QUEUE_VARIABLES</ref>
00445          <ref type="function">QUEUE_MEMBER</ref>
00446          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00447          <ref type="function">QUEUE_EXISTS</ref>
00448          <ref type="function">QUEUE_WAITING_COUNT</ref>
00449          <ref type="function">QUEUE_MEMBER_LIST</ref>
00450          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00451       </see-also>
00452    </application>
00453    <function name="QUEUE_VARIABLES" language="en_US">
00454       <synopsis>
00455          Return Queue information in variables.
00456       </synopsis>
00457       <syntax>
00458          <parameter name="queuename" required="true">
00459             <enumlist>
00460                <enum name="QUEUEMAX">
00461                   <para>Maxmimum number of calls allowed.</para>
00462                </enum>
00463                <enum name="QUEUESTRATEGY">
00464                   <para>The strategy of the queue.</para>
00465                </enum>
00466                <enum name="QUEUECALLS">
00467                   <para>Number of calls currently in the queue.</para>
00468                </enum>
00469                <enum name="QUEUEHOLDTIME">
00470                   <para>Current average hold time.</para>
00471                </enum>
00472                <enum name="QUEUECOMPLETED">
00473                   <para>Number of completed calls for the queue.</para>
00474                </enum>
00475                <enum name="QUEUEABANDONED">
00476                   <para>Number of abandoned calls.</para>
00477                </enum>
00478                <enum name="QUEUESRVLEVEL">
00479                   <para>Queue service level.</para>
00480                </enum>
00481                <enum name="QUEUESRVLEVELPERF">
00482                   <para>Current service level performance.</para>
00483                </enum>
00484             </enumlist>
00485          </parameter>
00486       </syntax>
00487       <description>
00488          <para>Makes the following queue variables available.</para>
00489          <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
00490       </description>
00491       <see-also>
00492          <ref type="application">Queue</ref>
00493          <ref type="application">QueueLog</ref>
00494          <ref type="application">AddQueueMember</ref>
00495          <ref type="application">RemoveQueueMember</ref>
00496          <ref type="application">PauseQueueMember</ref>
00497          <ref type="application">UnpauseQueueMember</ref>
00498          <ref type="function">QUEUE_VARIABLES</ref>
00499          <ref type="function">QUEUE_MEMBER</ref>
00500          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00501          <ref type="function">QUEUE_EXISTS</ref>
00502          <ref type="function">QUEUE_WAITING_COUNT</ref>
00503          <ref type="function">QUEUE_MEMBER_LIST</ref>
00504          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00505       </see-also>
00506    </function>
00507    <function name="QUEUE_MEMBER" language="en_US">
00508       <synopsis>
00509          Count number of members answering a queue.
00510       </synopsis>
00511       <syntax>
00512          <parameter name="queuename" required="true" />
00513          <parameter name="option" required="true">
00514             <enumlist>
00515                <enum name="logged">
00516                   <para>Returns the number of logged-in members for the specified queue.</para>
00517                </enum>
00518                <enum name="free">
00519                   <para>Returns the number of logged-in members for the specified queue that either can take calls or are currently wrapping up after a previous call.</para>
00520                </enum>
00521                <enum name="ready">
00522                   <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
00523                </enum>
00524                <enum name="count">
00525                   <para>Returns the total number of members for the specified queue.</para>
00526                </enum>
00527             </enumlist>
00528          </parameter>
00529       </syntax>
00530       <description>
00531          <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
00532       </description>
00533       <see-also>
00534          <ref type="application">Queue</ref>
00535          <ref type="application">QueueLog</ref>
00536          <ref type="application">AddQueueMember</ref>
00537          <ref type="application">RemoveQueueMember</ref>
00538          <ref type="application">PauseQueueMember</ref>
00539          <ref type="application">UnpauseQueueMember</ref>
00540          <ref type="function">QUEUE_VARIABLES</ref>
00541          <ref type="function">QUEUE_MEMBER</ref>
00542          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00543          <ref type="function">QUEUE_EXISTS</ref>
00544          <ref type="function">QUEUE_WAITING_COUNT</ref>
00545          <ref type="function">QUEUE_MEMBER_LIST</ref>
00546          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00547       </see-also>
00548    </function>
00549    <function name="QUEUE_MEMBER_COUNT" language="en_US">
00550       <synopsis>
00551          Count number of members answering a queue.
00552       </synopsis>
00553       <syntax>
00554          <parameter name="queuename" required="true" />
00555       </syntax>
00556       <description>
00557          <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
00558          <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
00559       </description>
00560       <see-also>
00561          <ref type="application">Queue</ref>
00562          <ref type="application">QueueLog</ref>
00563          <ref type="application">AddQueueMember</ref>
00564          <ref type="application">RemoveQueueMember</ref>
00565          <ref type="application">PauseQueueMember</ref>
00566          <ref type="application">UnpauseQueueMember</ref>
00567          <ref type="function">QUEUE_VARIABLES</ref>
00568          <ref type="function">QUEUE_MEMBER</ref>
00569          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00570          <ref type="function">QUEUE_EXISTS</ref>
00571          <ref type="function">QUEUE_WAITING_COUNT</ref>
00572          <ref type="function">QUEUE_MEMBER_LIST</ref>
00573          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00574       </see-also>
00575    </function>
00576    <function name="QUEUE_EXISTS" language="en_US">
00577       <synopsis>
00578          Check if a named queue exists on this server
00579       </synopsis>
00580       <syntax>
00581          <parameter name="queuename" />
00582       </syntax>
00583       <description>
00584          <para>Returns 1 if the specified queue exists, 0 if it does not</para>
00585       </description>
00586       <see-also>
00587          <ref type="application">Queue</ref>
00588          <ref type="application">QueueLog</ref>
00589          <ref type="application">AddQueueMember</ref>
00590          <ref type="application">RemoveQueueMember</ref>
00591          <ref type="application">PauseQueueMember</ref>
00592          <ref type="application">UnpauseQueueMember</ref>
00593          <ref type="function">QUEUE_VARIABLES</ref>
00594          <ref type="function">QUEUE_MEMBER</ref>
00595          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00596          <ref type="function">QUEUE_EXISTS</ref>
00597          <ref type="function">QUEUE_WAITING_COUNT</ref>
00598          <ref type="function">QUEUE_MEMBER_LIST</ref>
00599          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00600       </see-also>
00601    </function>
00602    <function name="QUEUE_WAITING_COUNT" language="en_US">
00603       <synopsis>
00604          Count number of calls currently waiting in a queue.
00605       </synopsis>
00606       <syntax>
00607          <parameter name="queuename" />
00608       </syntax>
00609       <description>
00610          <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
00611       </description>
00612       <see-also>
00613          <ref type="application">Queue</ref>
00614          <ref type="application">QueueLog</ref>
00615          <ref type="application">AddQueueMember</ref>
00616          <ref type="application">RemoveQueueMember</ref>
00617          <ref type="application">PauseQueueMember</ref>
00618          <ref type="application">UnpauseQueueMember</ref>
00619          <ref type="function">QUEUE_VARIABLES</ref>
00620          <ref type="function">QUEUE_MEMBER</ref>
00621          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00622          <ref type="function">QUEUE_EXISTS</ref>
00623          <ref type="function">QUEUE_WAITING_COUNT</ref>
00624          <ref type="function">QUEUE_MEMBER_LIST</ref>
00625          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00626       </see-also>
00627    </function>
00628    <function name="QUEUE_MEMBER_LIST" language="en_US">
00629       <synopsis>
00630          Returns a list of interfaces on a queue.
00631       </synopsis>
00632       <syntax>
00633          <parameter name="queuename" required="true" />
00634       </syntax>
00635       <description>
00636          <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
00637       </description>
00638       <see-also>
00639          <ref type="application">Queue</ref>
00640          <ref type="application">QueueLog</ref>
00641          <ref type="application">AddQueueMember</ref>
00642          <ref type="application">RemoveQueueMember</ref>
00643          <ref type="application">PauseQueueMember</ref>
00644          <ref type="application">UnpauseQueueMember</ref>
00645          <ref type="function">QUEUE_VARIABLES</ref>
00646          <ref type="function">QUEUE_MEMBER</ref>
00647          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00648          <ref type="function">QUEUE_EXISTS</ref>
00649          <ref type="function">QUEUE_WAITING_COUNT</ref>
00650          <ref type="function">QUEUE_MEMBER_LIST</ref>
00651          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00652       </see-also>
00653    </function>
00654    <function name="QUEUE_MEMBER_PENALTY" language="en_US">
00655       <synopsis>
00656          Gets or sets queue members penalty.
00657       </synopsis>
00658       <syntax>
00659          <parameter name="queuename" required="true" />
00660          <parameter name="interface" required="true" />
00661       </syntax>
00662       <description>
00663          <para>Gets or sets queue members penalty.</para>
00664       </description>
00665       <see-also>
00666          <ref type="application">Queue</ref>
00667          <ref type="application">QueueLog</ref>
00668          <ref type="application">AddQueueMember</ref>
00669          <ref type="application">RemoveQueueMember</ref>
00670          <ref type="application">PauseQueueMember</ref>
00671          <ref type="application">UnpauseQueueMember</ref>
00672          <ref type="function">QUEUE_VARIABLES</ref>
00673          <ref type="function">QUEUE_MEMBER</ref>
00674          <ref type="function">QUEUE_MEMBER_COUNT</ref>
00675          <ref type="function">QUEUE_EXISTS</ref>
00676          <ref type="function">QUEUE_WAITING_COUNT</ref>
00677          <ref type="function">QUEUE_MEMBER_LIST</ref>
00678          <ref type="function">QUEUE_MEMBER_PENALTY</ref>
00679       </see-also>
00680    </function>
00681    <manager name="Queues" language="en_US">
00682       <synopsis>
00683          Queues.
00684       </synopsis>
00685       <syntax>
00686       </syntax>
00687       <description>
00688       </description>
00689    </manager>
00690    <manager name="QueueStatus" language="en_US">
00691       <synopsis>
00692          Show queue status.
00693       </synopsis>
00694       <syntax>
00695          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00696          <parameter name="Queue" />
00697          <parameter name="Member" />
00698       </syntax>
00699       <description>
00700       </description>
00701    </manager>
00702    <manager name="QueueSummary" language="en_US">
00703       <synopsis>
00704          Show queue summary.
00705       </synopsis>
00706       <syntax>
00707          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00708          <parameter name="Queue" />
00709       </syntax>
00710       <description>
00711       </description>
00712    </manager>
00713    <manager name="QueueAdd" language="en_US">
00714       <synopsis>
00715          Add interface to queue.
00716       </synopsis>
00717       <syntax>
00718          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00719          <parameter name="Queue" required="true" />
00720          <parameter name="Interface" required="true" />
00721          <parameter name="Penalty" />
00722          <parameter name="Paused" />
00723          <parameter name="MemberName" />
00724          <parameter name="StateInterface" />
00725       </syntax>
00726       <description>
00727       </description>
00728    </manager>
00729    <manager name="QueueRemove" language="en_US">
00730       <synopsis>
00731          Remove interface from queue.
00732       </synopsis>
00733       <syntax>
00734          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00735          <parameter name="Queue" required="true" />
00736          <parameter name="Interface" required="true" />
00737       </syntax>
00738       <description>
00739       </description>
00740    </manager>
00741    <manager name="QueuePause" language="en_US">
00742       <synopsis>
00743          Makes a queue member temporarily unavailable.
00744       </synopsis>
00745       <syntax>
00746          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00747          <parameter name="Interface" required="true" />
00748          <parameter name="Paused" required="true" />
00749          <parameter name="Queue" />
00750          <parameter name="Reason" />
00751       </syntax>
00752       <description>
00753       </description>
00754    </manager>
00755    <manager name="QueueLog" language="en_US">
00756       <synopsis>
00757          Adds custom entry in queue_log.
00758       </synopsis>
00759       <syntax>
00760          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00761          <parameter name="Queue" required="true" />
00762          <parameter name="Event" required="true" />
00763          <parameter name="Uniqueid" />
00764          <parameter name="Interface" />
00765          <parameter name="Message" />
00766       </syntax>
00767       <description>
00768       </description>
00769    </manager>
00770    <manager name="QueuePenalty" language="en_US">
00771       <synopsis>
00772          Set the penalty for a queue member.
00773       </synopsis>
00774       <syntax>
00775          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00776          <parameter name="Interface" required="true" />
00777          <parameter name="Penalty" required="true" />
00778          <parameter name="Queue" />
00779       </syntax>
00780       <description>
00781       </description>
00782    </manager>
00783    <manager name="QueueRule" language="en_US">
00784       <synopsis>
00785          Queue Rules.
00786       </synopsis>
00787       <syntax>
00788          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00789          <parameter name="Rule" />
00790       </syntax>
00791       <description>
00792       </description>
00793    </manager>
00794    <manager name="QueueReload" language="en_US">
00795       <synopsis>
00796          Reload a queue, queues, or any sub-section of a queue or queues.
00797       </synopsis>
00798       <syntax>
00799          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00800          <parameter name="Queue" />
00801          <parameter name="Members">
00802             <enumlist>
00803                <enum name="yes" />
00804                <enum name="no" />
00805             </enumlist>
00806          </parameter>
00807          <parameter name="Rules">
00808             <enumlist>
00809                <enum name="yes" />
00810                <enum name="no" />
00811             </enumlist>
00812          </parameter>
00813          <parameter name="Parameters">
00814             <enumlist>
00815                <enum name="yes" />
00816                <enum name="no" />
00817             </enumlist>
00818          </parameter>
00819       </syntax>
00820       <description>
00821       </description>
00822    </manager>
00823    <manager name="QueueReset" language="en_US">
00824       <synopsis>
00825          Reset queue statistics.
00826       </synopsis>
00827       <syntax>
00828          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00829          <parameter name="Queue" />
00830       </syntax>
00831       <description>
00832       </description>
00833    </manager>
00834  ***/
00835 
00836 enum {
00837    QUEUE_STRATEGY_RINGALL = 0,
00838    QUEUE_STRATEGY_LEASTRECENT,
00839    QUEUE_STRATEGY_FEWESTCALLS,
00840    QUEUE_STRATEGY_RANDOM,
00841    QUEUE_STRATEGY_RRMEMORY,
00842    QUEUE_STRATEGY_LINEAR,
00843    QUEUE_STRATEGY_WRANDOM,
00844    QUEUE_STRATEGY_RRORDERED,
00845 };
00846 
00847 enum {
00848      QUEUE_AUTOPAUSE_OFF = 0,
00849      QUEUE_AUTOPAUSE_ON,
00850      QUEUE_AUTOPAUSE_ALL
00851 };
00852 
00853 enum queue_reload_mask {
00854    QUEUE_RELOAD_PARAMETERS = (1 << 0),
00855    QUEUE_RELOAD_MEMBER = (1 << 1),
00856    QUEUE_RELOAD_RULES = (1 << 2),
00857    QUEUE_RESET_STATS = (1 << 3),
00858 };
00859 
00860 static const struct strategy {
00861    int strategy;
00862    const char *name;
00863 } strategies[] = {
00864    { QUEUE_STRATEGY_RINGALL, "ringall" },
00865    { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
00866    { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
00867    { QUEUE_STRATEGY_RANDOM, "random" },
00868    { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
00869    { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
00870    { QUEUE_STRATEGY_LINEAR, "linear" },
00871    { QUEUE_STRATEGY_WRANDOM, "wrandom"},
00872    { QUEUE_STRATEGY_RRORDERED, "rrordered"},
00873 };
00874 
00875 static const struct autopause {
00876    int autopause;
00877    const char *name;
00878 } autopausesmodes [] = {
00879    { QUEUE_AUTOPAUSE_OFF,"no" },
00880    { QUEUE_AUTOPAUSE_ON, "yes" },
00881    { QUEUE_AUTOPAUSE_ALL,"all" },
00882 };
00883 
00884 
00885 static struct ast_taskprocessor *devicestate_tps;
00886 
00887 #define DEFAULT_RETRY      5
00888 #define DEFAULT_TIMEOUT    15
00889 #define RECHECK         1     /*!< Recheck every second to see we we're at the top yet */
00890 #define MAX_PERIODIC_ANNOUNCEMENTS 10           /*!< The maximum periodic announcements we can have */
00891 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15       /*!< The minimum number of seconds between position announcements \
00892                                                      The default value of 15 provides backwards compatibility */
00893 #define MAX_QUEUE_BUCKETS 53
00894 
00895 #define  RES_OKAY 0     /*!< Action completed */
00896 #define  RES_EXISTS  (-1)     /*!< Entry already exists */
00897 #define  RES_OUTOFMEMORY   (-2)     /*!< Out of memory */
00898 #define  RES_NOSUCHQUEUE   (-3)     /*!< No such queue */
00899 #define RES_NOT_DYNAMIC (-4)     /*!< Member is not dynamic */
00900 
00901 static char *app = "Queue";
00902 
00903 static char *app_aqm = "AddQueueMember" ;
00904 
00905 static char *app_rqm = "RemoveQueueMember" ;
00906 
00907 static char *app_pqm = "PauseQueueMember" ;
00908 
00909 static char *app_upqm = "UnpauseQueueMember" ;
00910 
00911 static char *app_ql = "QueueLog" ;
00912 
00913 /*! \brief Persistent Members astdb family */
00914 static const char * const pm_family = "Queue/PersistentMembers";
00915 
00916 /*! \brief queues.conf [general] option */
00917 static int queue_persistent_members = 0;
00918 
00919 /*! \brief queues.conf per-queue weight option */
00920 static int use_weight = 0;
00921 
00922 /*! \brief queues.conf [general] option */
00923 static int autofill_default = 1;
00924 
00925 /*! \brief queues.conf [general] option */
00926 static int montype_default = 0;
00927 
00928 /*! \brief queues.conf [general] option */
00929 static int shared_lastcall = 1;
00930 
00931 /*! \brief Subscription to device state change events */
00932 static struct ast_event_sub *device_state_sub;
00933 
00934 /*! \brief queues.conf [general] option */
00935 static int update_cdr = 0;
00936 
00937 enum queue_result {
00938    QUEUE_UNKNOWN = 0,
00939    QUEUE_TIMEOUT = 1,
00940    QUEUE_JOINEMPTY = 2,
00941    QUEUE_LEAVEEMPTY = 3,
00942    QUEUE_JOINUNAVAIL = 4,
00943    QUEUE_LEAVEUNAVAIL = 5,
00944    QUEUE_FULL = 6,
00945    QUEUE_CONTINUE = 7,
00946 };
00947 
00948 static const struct {
00949    enum queue_result id;
00950    char *text;
00951 } queue_results[] = {
00952    { QUEUE_UNKNOWN, "UNKNOWN" },
00953    { QUEUE_TIMEOUT, "TIMEOUT" },
00954    { QUEUE_JOINEMPTY,"JOINEMPTY" },
00955    { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
00956    { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
00957    { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
00958    { QUEUE_FULL, "FULL" },
00959    { QUEUE_CONTINUE, "CONTINUE" },
00960 };
00961 
00962 enum queue_timeout_priority {
00963    TIMEOUT_PRIORITY_APP,
00964    TIMEOUT_PRIORITY_CONF,
00965 };
00966 
00967 /*! \brief We define a custom "local user" structure because we
00968  *  use it not only for keeping track of what is in use but
00969  *  also for keeping track of who we're dialing.
00970  *
00971  *  There are two "links" defined in this structure, q_next and call_next.
00972  *  q_next links ALL defined callattempt structures into a linked list. call_next is
00973  *  a link which allows for a subset of the callattempts to be traversed. This subset
00974  *  is used in wait_for_answer so that irrelevant callattempts are not traversed. This
00975  *  also is helpful so that queue logs are always accurate in the case where a call to 
00976  *  a member times out, especially if using the ringall strategy. 
00977 */
00978 
00979 struct callattempt {
00980    struct callattempt *q_next;
00981    struct callattempt *call_next;
00982    struct ast_channel *chan;
00983    char interface[256];
00984    int metric;
00985    time_t lastcall;
00986    struct call_queue *lastqueue;
00987    struct member *member;
00988    /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
00989    struct ast_party_connected_line connected;
00990    /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
00991    unsigned int pending_connected_update:1;
00992    /*! TRUE if the connected line update is blocked. */
00993    unsigned int block_connected_update:1;
00994    /*! TRUE if caller id is not available for connected line */
00995    unsigned int dial_callerid_absent:1;
00996    /*! TRUE if the call is still active */
00997    unsigned int stillgoing:1;
00998    struct ast_aoc_decoded *aoc_s_rate_list;
00999 };
01000 
01001 
01002 struct queue_ent {
01003    struct call_queue *parent;             /*!< What queue is our parent */
01004    char moh[80];                          /*!< Name of musiconhold to be used */
01005    char announce[PATH_MAX];               /*!< Announcement to play for member when call is answered */
01006    char context[AST_MAX_CONTEXT];         /*!< Context when user exits queue */
01007    char digits[AST_MAX_EXTENSION];        /*!< Digits entered while in queue */
01008    int valid_digits;                      /*!< Digits entered correspond to valid extension. Exited */
01009    int pos;                               /*!< Where we are in the queue */
01010    int prio;                              /*!< Our priority */
01011    int last_pos_said;                     /*!< Last position we told the user */
01012    int ring_when_ringing;                 /*!< Should we only use ring indication when a channel is ringing? */
01013    time_t last_periodic_announce_time;    /*!< The last time we played a periodic announcement */
01014    int last_periodic_announce_sound;      /*!< The last periodic announcement we made */
01015    time_t last_pos;                       /*!< Last time we told the user their position */
01016    int opos;                              /*!< Where we started in the queue */
01017    int handled;                           /*!< Whether our call was handled */
01018    int pending;                           /*!< Non-zero if we are attempting to call a member */
01019    int max_penalty;                       /*!< Limit the members that can take this call to this penalty or lower */
01020    int min_penalty;                       /*!< Limit the members that can take this call to this penalty or higher */
01021    int linpos;                            /*!< If using linear strategy, what position are we at? */
01022    int linwrapped;                        /*!< Is the linpos wrapped? */
01023    time_t start;                          /*!< When we started holding */
01024    time_t expire;                         /*!< When this entry should expire (time out of queue) */
01025    int cancel_answered_elsewhere;          /*!< Whether we should force the CAE flag on this call (C) option*/
01026    struct ast_channel *chan;              /*!< Our channel */
01027    AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
01028    struct penalty_rule *pr;               /*!< Pointer to the next penalty rule to implement */
01029    struct queue_ent *next;                /*!< The next queue entry */
01030 };
01031 
01032 struct member {
01033    char interface[80];                  /*!< Technology/Location to dial to reach this member*/
01034    char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
01035    char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
01036    char state_interface[80];            /*!< Technology/Location from which to read devicestate changes */
01037    char membername[80];                 /*!< Member name to use in queue logs */
01038    int penalty;                         /*!< Are we a last resort? */
01039    int calls;                           /*!< Number of calls serviced by this member */
01040    int dynamic;                         /*!< Are we dynamically added? */
01041    int realtime;                        /*!< Is this member realtime? */
01042    int status;                          /*!< Status of queue member */
01043    int paused;                          /*!< Are we paused (not accepting calls)? */
01044    time_t lastcall;                     /*!< When last successful call was hungup */
01045    struct call_queue *lastqueue;      /*!< Last queue we received a call */
01046    unsigned int dead:1;                 /*!< Used to detect members deleted in realtime */
01047    unsigned int delme:1;                /*!< Flag to delete entry on reload */
01048    char rt_uniqueid[80];                /*!< Unique id of realtime member entry */
01049 };
01050 
01051 enum empty_conditions {
01052    QUEUE_EMPTY_PENALTY = (1 << 0),
01053    QUEUE_EMPTY_PAUSED = (1 << 1),
01054    QUEUE_EMPTY_INUSE = (1 << 2),
01055    QUEUE_EMPTY_RINGING = (1 << 3),
01056    QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
01057    QUEUE_EMPTY_INVALID = (1 << 5),
01058    QUEUE_EMPTY_UNKNOWN = (1 << 6),
01059    QUEUE_EMPTY_WRAPUP = (1 << 7),
01060 };
01061 
01062 /* values used in multi-bit flags in call_queue */
01063 #define ANNOUNCEHOLDTIME_ALWAYS 1
01064 #define ANNOUNCEHOLDTIME_ONCE 2
01065 #define QUEUE_EVENT_VARIABLES 3
01066 
01067 struct penalty_rule {
01068    int time;                           /*!< Number of seconds that need to pass before applying this rule */
01069    int max_value;                      /*!< The amount specified in the penalty rule for max penalty */
01070    int min_value;                      /*!< The amount specified in the penalty rule for min penalty */
01071    int max_relative;                   /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
01072    int min_relative;                   /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
01073    AST_LIST_ENTRY(penalty_rule) list;  /*!< Next penalty_rule */
01074 };
01075 
01076 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
01077 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
01078 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
01079 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
01080 
01081 struct call_queue {
01082    AST_DECLARE_STRING_FIELDS(
01083       /*! Queue name */
01084       AST_STRING_FIELD(name);
01085       /*! Music on Hold class */
01086       AST_STRING_FIELD(moh);
01087       /*! Announcement to play when call is answered */
01088       AST_STRING_FIELD(announce);
01089       /*! Exit context */
01090       AST_STRING_FIELD(context);
01091       /*! Macro to run upon member connection */
01092       AST_STRING_FIELD(membermacro);
01093       /*! Gosub to run upon member connection */
01094       AST_STRING_FIELD(membergosub);
01095       /*! Default rule to use if none specified in call to Queue() */
01096       AST_STRING_FIELD(defaultrule);
01097       /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
01098       AST_STRING_FIELD(sound_next);
01099       /*! Sound file: "There are currently" (def. queue-thereare) */
01100       AST_STRING_FIELD(sound_thereare);
01101       /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
01102       AST_STRING_FIELD(sound_calls);
01103       /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
01104       AST_STRING_FIELD(queue_quantity1);
01105       /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
01106       AST_STRING_FIELD(queue_quantity2);
01107       /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
01108       AST_STRING_FIELD(sound_holdtime);
01109       /*! Sound file: "minutes." (def. queue-minutes) */
01110       AST_STRING_FIELD(sound_minutes);
01111       /*! Sound file: "minute." (def. queue-minute) */
01112       AST_STRING_FIELD(sound_minute);
01113       /*! Sound file: "seconds." (def. queue-seconds) */
01114       AST_STRING_FIELD(sound_seconds);
01115       /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
01116       AST_STRING_FIELD(sound_thanks);
01117       /*! Sound file: Custom announce for caller, no default */
01118       AST_STRING_FIELD(sound_callerannounce);
01119       /*! Sound file: "Hold time" (def. queue-reporthold) */
01120       AST_STRING_FIELD(sound_reporthold);
01121    );
01122    /*! Sound files: Custom announce, no default */
01123    struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
01124    unsigned int dead:1;
01125    unsigned int eventwhencalled:2;
01126    unsigned int ringinuse:1;
01127    unsigned int setinterfacevar:1;
01128    unsigned int setqueuevar:1;
01129    unsigned int setqueueentryvar:1;
01130    unsigned int reportholdtime:1;
01131    unsigned int wrapped:1;
01132    unsigned int timeoutrestart:1;
01133    unsigned int announceholdtime:2;
01134    unsigned int announceposition:3;
01135    int strategy:4;
01136    unsigned int maskmemberstatus:1;
01137    unsigned int realtime:1;
01138    unsigned int found:1;
01139    unsigned int relativeperiodicannounce:1;
01140    enum empty_conditions joinempty;
01141    enum empty_conditions leavewhenempty;
01142    int announcepositionlimit;          /*!< How many positions we announce? */
01143    int announcefrequency;              /*!< How often to announce their position */
01144    int minannouncefrequency;           /*!< The minimum number of seconds between position announcements (def. 15) */
01145    int periodicannouncefrequency;      /*!< How often to play periodic announcement */
01146    int numperiodicannounce;            /*!< The number of periodic announcements configured */
01147    int randomperiodicannounce;         /*!< Are periodic announcments randomly chosen */
01148    int roundingseconds;                /*!< How many seconds do we round to? */
01149    int holdtime;                       /*!< Current avg holdtime, based on an exponential average */
01150    int talktime;                       /*!< Current avg talktime, based on the same exponential average */
01151    int callscompleted;                 /*!< Number of queue calls completed */
01152    int callsabandoned;                 /*!< Number of queue calls abandoned */
01153    int servicelevel;                   /*!< seconds setting for servicelevel*/
01154    int callscompletedinsl;             /*!< Number of calls answered with servicelevel*/
01155    char monfmt[8];                     /*!< Format to use when recording calls */
01156    int montype;                        /*!< Monitor type  Monitor vs. MixMonitor */
01157    int count;                          /*!< How many entries */
01158    int maxlen;                         /*!< Max number of entries */
01159    int wrapuptime;                     /*!< Wrapup Time */
01160    int penaltymemberslimit;            /*!< Disregard penalty when queue has fewer than this many members */
01161 
01162    int retry;                          /*!< Retry calling everyone after this amount of time */
01163    int timeout;                        /*!< How long to wait for an answer */
01164    int weight;                         /*!< Respective weight */
01165    int autopause;                      /*!< Auto pause queue members if they fail to answer */
01166    int timeoutpriority;                /*!< Do we allow a fraction of the timeout to occur for a ring? */
01167 
01168    /* Queue strategy things */
01169    int rrpos;                          /*!< Round Robin - position */
01170    int memberdelay;                    /*!< Seconds to delay connecting member to caller */
01171    int autofill;                       /*!< Ignore the head call status and ring an available agent */
01172    
01173    struct ao2_container *members;             /*!< Head of the list of members */
01174    struct queue_ent *head;             /*!< Head of the list of callers */
01175    AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
01176    AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
01177 };
01178 
01179 struct rule_list {
01180    char name[80];
01181    AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
01182    AST_LIST_ENTRY(rule_list) list;
01183 };
01184 
01185 static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
01186 
01187 static struct ao2_container *queues;
01188 
01189 static void update_realtime_members(struct call_queue *q);
01190 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
01191 
01192 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); 
01193 /*! \brief sets the QUEUESTATUS channel variable */
01194 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
01195 {
01196    int i;
01197 
01198    for (i = 0; i < ARRAY_LEN(queue_results); i++) {
01199       if (queue_results[i].id == res) {
01200          pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
01201          return;
01202       }
01203    }
01204 }
01205 
01206 static const char *int2strat(int strategy)
01207 {
01208    int x;
01209 
01210    for (x = 0; x < ARRAY_LEN(strategies); x++) {
01211       if (strategy == strategies[x].strategy)
01212          return strategies[x].name;
01213    }
01214 
01215    return "<unknown>";
01216 }
01217 
01218 static int strat2int(const char *strategy)
01219 {
01220    int x;
01221 
01222    for (x = 0; x < ARRAY_LEN(strategies); x++) {
01223       if (!strcasecmp(strategy, strategies[x].name))
01224          return strategies[x].strategy;
01225    }
01226 
01227    return -1;
01228 }
01229 
01230 static int autopause2int(const char *autopause)
01231 {
01232    int x;
01233    /*This 'double check' that default value is OFF */
01234    if (ast_strlen_zero(autopause))
01235       return QUEUE_AUTOPAUSE_OFF;
01236 
01237    /*This 'double check' is to ensure old values works */
01238    if(ast_true(autopause))
01239       return QUEUE_AUTOPAUSE_ON;
01240 
01241    for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
01242       if (!strcasecmp(autopause, autopausesmodes[x].name))
01243          return autopausesmodes[x].autopause;
01244    }
01245 
01246    /*This 'double check' that default value is OFF */
01247    return QUEUE_AUTOPAUSE_OFF;
01248 }
01249 
01250 static int queue_hash_cb(const void *obj, const int flags)
01251 {
01252    const struct call_queue *q = obj;
01253 
01254    return ast_str_case_hash(q->name);
01255 }
01256 
01257 static int queue_cmp_cb(void *obj, void *arg, int flags)
01258 {
01259    struct call_queue *q = obj, *q2 = arg;
01260    return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
01261 }
01262 
01263 #ifdef REF_DEBUG_ONLY_QUEUES
01264 #define queue_ref(a) __ao2_ref_debug(a,1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
01265 #define queue_unref(a)  __ao2_ref_debug(a,-1,"",__FILE__,__LINE__,__PRETTY_FUNCTION__)
01266 #define queue_t_ref(a,b)   __ao2_ref_debug(a,1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01267 #define queue_t_unref(a,b) __ao2_ref_debug(a,-1,b,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01268 #define queues_t_link(c,q,tag)   __ao2_link_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01269 #define queues_t_unlink(c,q,tag) __ao2_unlink_debug(c,q,tag,__FILE__,__LINE__,__PRETTY_FUNCTION__)
01270 #else
01271 #define queue_t_ref(a,b)   queue_ref(a)
01272 #define queue_t_unref(a,b) queue_unref(a)
01273 #define queues_t_link(c,q,tag)   ao2_t_link(c,q,tag)
01274 #define queues_t_unlink(c,q,tag) ao2_t_unlink(c,q,tag)
01275 static inline struct call_queue *queue_ref(struct call_queue *q)
01276 {
01277    ao2_ref(q, 1);
01278    return q;
01279 }
01280 
01281 static inline struct call_queue *queue_unref(struct call_queue *q)
01282 {
01283    ao2_ref(q, -1);
01284    return NULL;
01285 }
01286 #endif
01287 
01288 /*! \brief Set variables of queue */
01289 static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
01290 {
01291    char interfacevar[256]="";
01292    float sl = 0;
01293 
01294    ao2_lock(q);
01295 
01296    if (q->setqueuevar) {
01297       sl = 0;
01298       if (q->callscompleted > 0) 
01299          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
01300 
01301       snprintf(interfacevar, sizeof(interfacevar),
01302          "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
01303          q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
01304 
01305       ao2_unlock(q);
01306    
01307       pbx_builtin_setvar_multiple(chan, interfacevar); 
01308    } else {
01309       ao2_unlock(q);
01310    }
01311 }
01312 
01313 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
01314 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
01315 {
01316    struct queue_ent *cur;
01317 
01318    if (!q || !new)
01319       return;
01320    if (prev) {
01321       cur = prev->next;
01322       prev->next = new;
01323    } else {
01324       cur = q->head;
01325       q->head = new;
01326    }
01327    new->next = cur;
01328 
01329    /* every queue_ent must have a reference to it's parent call_queue, this
01330     * reference does not go away until the end of the queue_ent's life, meaning
01331     * that even when the queue_ent leaves the call_queue this ref must remain. */
01332    queue_ref(q);
01333    new->parent = q;
01334    new->pos = ++(*pos);
01335    new->opos = *pos;
01336 }
01337 
01338 /*! \brief Check if members are available
01339  *
01340  * This function checks to see if members are available to be called. If any member
01341  * is available, the function immediately returns 0. If no members are available,
01342  * then -1 is returned.
01343  */
01344 static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions)
01345 {
01346    struct member *member;
01347    struct ao2_iterator mem_iter;
01348 
01349    ao2_lock(q);
01350    mem_iter = ao2_iterator_init(q->members, 0);
01351    for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
01352       if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty))) {
01353          if (conditions & QUEUE_EMPTY_PENALTY) {
01354             ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
01355             continue;
01356          }
01357       }
01358 
01359       switch (member->status) {
01360       case AST_DEVICE_INVALID:
01361          if (conditions & QUEUE_EMPTY_INVALID) {
01362             ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
01363             break;
01364          }
01365          goto default_case;
01366       case AST_DEVICE_UNAVAILABLE:
01367          if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
01368             ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
01369             break;
01370          }
01371          goto default_case;
01372       case AST_DEVICE_INUSE:
01373          if (conditions & QUEUE_EMPTY_INUSE) {
01374             ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
01375             break;
01376          }
01377          goto default_case;
01378       case AST_DEVICE_RINGING:
01379          if (conditions & QUEUE_EMPTY_RINGING) {
01380             ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
01381             break;
01382          }
01383          goto default_case;
01384       case AST_DEVICE_UNKNOWN:
01385          if (conditions & QUEUE_EMPTY_UNKNOWN) {
01386             ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
01387             break;
01388          }
01389          /* Fall-through */
01390       default:
01391       default_case:
01392          if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
01393             ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
01394             break;
01395          } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
01396             ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
01397             break;
01398          } else {
01399             ao2_ref(member, -1);
01400             ao2_iterator_destroy(&mem_iter);
01401             ao2_unlock(q);
01402             ast_debug(4, "%s is available.\n", member->membername);
01403             return 0;
01404          }
01405          break;
01406       }
01407    }
01408    ao2_iterator_destroy(&mem_iter);
01409 
01410    ao2_unlock(q);
01411    return -1;
01412 }
01413 
01414 struct statechange {
01415    AST_LIST_ENTRY(statechange) entry;
01416    int state;
01417    char dev[0];
01418 };
01419 
01420 /*! \brief set a member's status based on device state of that member's state_interface.
01421  *  
01422  * Lock interface list find sc, iterate through each queues queue_member list for member to
01423  * update state inside queues
01424 */
01425 static int update_status(struct call_queue *q, struct member *m, const int status)
01426 {
01427    m->status = status;
01428 
01429    if (q->maskmemberstatus)
01430       return 0;
01431 
01432    manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
01433       "Queue: %s\r\n"
01434       "Location: %s\r\n"
01435       "MemberName: %s\r\n"
01436       "Membership: %s\r\n"
01437       "Penalty: %d\r\n"
01438       "CallsTaken: %d\r\n"
01439       "LastCall: %d\r\n"
01440       "Status: %d\r\n"
01441       "Paused: %d\r\n",
01442       q->name, m->interface, m->membername, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
01443       m->penalty, m->calls, (int)m->lastcall, m->status, m->paused
01444    );
01445 
01446    return 0;
01447 }
01448 
01449 /*! \brief set a member's status based on device state of that member's interface*/
01450 static int handle_statechange(void *datap)
01451 {
01452    struct statechange *sc = datap;
01453    struct ao2_iterator miter, qiter;
01454    struct member *m;
01455    struct call_queue *q;
01456    char interface[80], *slash_pos;
01457    int found = 0;
01458 
01459    qiter = ao2_iterator_init(queues, 0);
01460    while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
01461       ao2_lock(q);
01462 
01463       miter = ao2_iterator_init(q->members, 0);
01464       for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01465          ast_copy_string(interface, m->state_interface, sizeof(interface));
01466 
01467          if ((slash_pos = strchr(interface, '/')))
01468             if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/')))
01469                *slash_pos = '\0';
01470 
01471          if (!strcasecmp(interface, sc->dev)) {
01472             found = 1;
01473             update_status(q, m, sc->state);
01474             ao2_ref(m, -1);
01475             break;
01476          }
01477       }
01478       ao2_iterator_destroy(&miter);
01479 
01480       ao2_unlock(q);
01481       queue_t_unref(q, "Done with iterator");
01482    }
01483    ao2_iterator_destroy(&qiter);
01484 
01485    if (found)
01486       ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
01487    else
01488       ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state));
01489 
01490    ast_free(sc);
01491    return 0;
01492 }
01493 
01494 static void device_state_cb(const struct ast_event *event, void *unused)
01495 {
01496    enum ast_device_state state;
01497    const char *device;
01498    struct statechange *sc;
01499    size_t datapsize;
01500 
01501    state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
01502    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
01503 
01504    if (ast_strlen_zero(device)) {
01505       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
01506       return;
01507    }
01508    datapsize = sizeof(*sc) + strlen(device) + 1;
01509    if (!(sc = ast_calloc(1, datapsize))) {
01510       ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
01511       return;
01512    }
01513    sc->state = state;
01514    strcpy(sc->dev, device);
01515    if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
01516       ast_free(sc);
01517    }
01518 }
01519 
01520 /*! \brief Helper function which converts from extension state to device state values */
01521 static int extensionstate2devicestate(int state)
01522 {
01523    switch (state) {
01524    case AST_EXTENSION_NOT_INUSE:
01525       state = AST_DEVICE_NOT_INUSE;
01526       break;
01527    case AST_EXTENSION_INUSE:
01528       state = AST_DEVICE_INUSE;
01529       break;
01530    case AST_EXTENSION_BUSY:
01531       state = AST_DEVICE_BUSY;
01532       break;
01533    case AST_EXTENSION_RINGING:
01534       state = AST_DEVICE_RINGING;
01535       break;
01536    case AST_EXTENSION_ONHOLD:
01537       state = AST_DEVICE_ONHOLD;
01538       break;
01539    case AST_EXTENSION_UNAVAILABLE:
01540       state = AST_DEVICE_UNAVAILABLE;
01541       break;
01542    case AST_EXTENSION_REMOVED:
01543    case AST_EXTENSION_DEACTIVATED:
01544    default:
01545       state = AST_DEVICE_INVALID;
01546       break;
01547    }
01548 
01549    return state;
01550 }
01551 
01552 static int extension_state_cb(char *context, char *exten, enum ast_extension_states state, void *data)
01553 {
01554    struct ao2_iterator miter, qiter;
01555    struct member *m;
01556    struct call_queue *q;
01557    int found = 0, device_state = extensionstate2devicestate(state);
01558 
01559    qiter = ao2_iterator_init(queues, 0);
01560    while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
01561       ao2_lock(q);
01562 
01563       miter = ao2_iterator_init(q->members, 0);
01564       for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
01565          if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
01566             update_status(q, m, device_state);
01567             ao2_ref(m, -1);
01568             found = 1;
01569             break;
01570          }
01571       }
01572       ao2_iterator_destroy(&miter);
01573 
01574       ao2_unlock(q);
01575       queue_t_unref(q, "Done with iterator");
01576    }
01577    ao2_iterator_destroy(&qiter);
01578 
01579         if (found) {
01580       ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
01581    } else {
01582       ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
01583            exten, context, device_state, ast_devstate2str(device_state));
01584    }
01585 
01586    return 0;
01587 }
01588 
01589 /*! \brief Return the current state of a member */
01590 static int get_queue_member_status(struct member *cur)
01591 {
01592    return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
01593 }
01594 
01595 /*! \brief allocate space for new queue member and set fields based on parameters passed */
01596 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
01597 {
01598    struct member *cur;
01599    
01600    if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
01601       cur->penalty = penalty;
01602       cur->paused = paused;
01603       ast_copy_string(cur->interface, interface, sizeof(cur->interface));
01604       if (!ast_strlen_zero(state_interface))
01605          ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
01606       else
01607          ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
01608       if (!ast_strlen_zero(membername))
01609          ast_copy_string(cur->membername, membername, sizeof(cur->membername));
01610       else
01611          ast_copy_string(cur->membername, interface, sizeof(cur->membername));
01612       if (!strchr(cur->interface, '/'))
01613          ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
01614       if (!strncmp(cur->state_interface, "hint:", 5)) {
01615          char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
01616          char *exten = strsep(&context, "@") + 5;
01617 
01618          ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
01619          ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
01620       }
01621       cur->status = get_queue_member_status(cur);
01622    }
01623 
01624    return cur;
01625 }
01626 
01627 
01628 static int compress_char(const char c)
01629 {
01630    if (c < 32)
01631       return 0;
01632    else if (c > 96)
01633       return c - 64;
01634    else
01635       return c - 32;
01636 }
01637 
01638 static int member_hash_fn(const void *obj, const int flags)
01639 {
01640    const struct member *mem = obj;
01641    const char *chname = strchr(mem->interface, '/');
01642    int ret = 0, i;
01643    if (!chname)
01644       chname = mem->interface;
01645    for (i = 0; i < 5 && chname[i]; i++)
01646       ret += compress_char(chname[i]) << (i * 6);
01647    return ret;
01648 }
01649 
01650 static int member_cmp_fn(void *obj1, void *obj2, int flags)
01651 {
01652    struct member *mem1 = obj1, *mem2 = obj2;
01653    return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
01654 }
01655 
01656 /*! 
01657  * \brief Initialize Queue default values.
01658  * \note the queue's lock  must be held before executing this function
01659 */
01660 static void init_queue(struct call_queue *q)
01661 {
01662    int i;
01663    struct penalty_rule *pr_iter;
01664 
01665    q->dead = 0;
01666    q->retry = DEFAULT_RETRY;
01667    q->timeout = DEFAULT_TIMEOUT;
01668    q->maxlen = 0;
01669    q->announcefrequency = 0;
01670    q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
01671    q->announceholdtime = 1;
01672    q->announcepositionlimit = 10; /* Default 10 positions */
01673    q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
01674    q->roundingseconds = 0; /* Default - don't announce seconds */
01675    q->servicelevel = 0;
01676    q->ringinuse = 1;
01677    q->setinterfacevar = 0;
01678    q->setqueuevar = 0;
01679    q->setqueueentryvar = 0;
01680    q->autofill = autofill_default;
01681    q->montype = montype_default;
01682    q->monfmt[0] = '\0';
01683    q->reportholdtime = 0;
01684    q->wrapuptime = 0;
01685    q->penaltymemberslimit = 0;
01686    q->joinempty = 0;
01687    q->leavewhenempty = 0;
01688    q->memberdelay = 0;
01689    q->maskmemberstatus = 0;
01690    q->eventwhencalled = 0;
01691    q->weight = 0;
01692    q->timeoutrestart = 0;
01693    q->periodicannouncefrequency = 0;
01694    q->randomperiodicannounce = 0;
01695    q->numperiodicannounce = 0;
01696    q->autopause = QUEUE_AUTOPAUSE_OFF;
01697    q->timeoutpriority = TIMEOUT_PRIORITY_APP;
01698    if (!q->members) {
01699       if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED)
01700          /* linear strategy depends on order, so we have to place all members in a single bucket */
01701          q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
01702       else
01703          q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
01704    }
01705    q->found = 1;
01706 
01707    ast_string_field_set(q, sound_next, "queue-youarenext");
01708    ast_string_field_set(q, sound_thereare, "queue-thereare");
01709    ast_string_field_set(q, sound_calls, "queue-callswaiting");
01710    ast_string_field_set(q, queue_quantity1, "queue-quantity1");
01711    ast_string_field_set(q, queue_quantity2, "queue-quantity2");
01712    ast_string_field_set(q, sound_holdtime, "queue-holdtime");
01713    ast_string_field_set(q, sound_minutes, "queue-minutes");
01714    ast_string_field_set(q, sound_minute, "queue-minute");
01715    ast_string_field_set(q, sound_seconds, "queue-seconds");
01716    ast_string_field_set(q, sound_thanks, "queue-thankyou");
01717    ast_string_field_set(q, sound_reporthold, "queue-reporthold");
01718 
01719    if (!q->sound_periodicannounce[0]) {
01720       q->sound_periodicannounce[0] = ast_str_create(32);
01721    }
01722 
01723    if (q->sound_periodicannounce[0]) {
01724       ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
01725    }
01726 
01727    for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
01728       if (q->sound_periodicannounce[i])
01729          ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
01730    }
01731 
01732    while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
01733       ast_free(pr_iter);
01734 }
01735 
01736 static void clear_queue(struct call_queue *q)
01737 {
01738    q->holdtime = 0;
01739    q->callscompleted = 0;
01740    q->callsabandoned = 0;
01741    q->callscompletedinsl = 0;
01742    q->talktime = 0;
01743 
01744    if (q->members) {
01745       struct member *mem;
01746       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01747       while ((mem = ao2_iterator_next(&mem_iter))) {
01748          mem->calls = 0;
01749          mem->lastcall = 0;
01750          ao2_ref(mem, -1);
01751       }
01752       ao2_iterator_destroy(&mem_iter);
01753    }
01754 }
01755 
01756 /*! 
01757  * \brief Change queue penalty by adding rule.
01758  *
01759  * Check rule for errors with time or fomatting, see if rule is relative to rest 
01760  * of queue, iterate list of rules to find correct insertion point, insert and return.
01761  * \retval -1 on failure
01762  * \retval 0 on success 
01763  * \note Call this with the rule_lists locked 
01764 */
01765 static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
01766 {
01767    char *timestr, *maxstr, *minstr, *contentdup;
01768    struct penalty_rule *rule = NULL, *rule_iter;
01769    struct rule_list *rl_iter;
01770    int penaltychangetime, inserted = 0;
01771 
01772    if (!(rule = ast_calloc(1, sizeof(*rule)))) {
01773       return -1;
01774    }
01775 
01776    contentdup = ast_strdupa(content);
01777    
01778    if (!(maxstr = strchr(contentdup, ','))) {
01779       ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
01780       ast_free(rule);
01781       return -1;
01782    }
01783 
01784    *maxstr++ = '\0';
01785    timestr = contentdup;
01786 
01787    if ((penaltychangetime = atoi(timestr)) < 0) {
01788       ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
01789       ast_free(rule);
01790       return -1;
01791    }
01792 
01793    rule->time = penaltychangetime;
01794 
01795    if ((minstr = strchr(maxstr,',')))
01796       *minstr++ = '\0';
01797    
01798    /* The last check will evaluate true if either no penalty change is indicated for a given rule
01799     * OR if a min penalty change is indicated but no max penalty change is */
01800    if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
01801       rule->max_relative = 1;
01802    }
01803 
01804    rule->max_value = atoi(maxstr);
01805 
01806    if (!ast_strlen_zero(minstr)) {
01807       if (*minstr == '+' || *minstr == '-')
01808          rule->min_relative = 1;
01809       rule->min_value = atoi(minstr);
01810    } else /*there was no minimum specified, so assume this means no change*/
01811       rule->min_relative = 1;
01812 
01813    /*We have the rule made, now we need to insert it where it belongs*/
01814    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
01815       if (strcasecmp(rl_iter->name, list_name))
01816          continue;
01817 
01818       AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
01819          if (rule->time < rule_iter->time) {
01820             AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
01821             inserted = 1;
01822             break;
01823          }
01824       }
01825       AST_LIST_TRAVERSE_SAFE_END;
01826    
01827       if (!inserted) {
01828          AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
01829          inserted = 1;
01830       }
01831 
01832       break;
01833    }
01834 
01835    if (!inserted) {
01836       ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
01837       ast_free(rule);
01838       return -1;
01839    }
01840    return 0;
01841 }
01842 
01843 static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
01844 {
01845    char *value_copy = ast_strdupa(value);
01846    char *option = NULL;
01847    while ((option = strsep(&value_copy, ","))) {
01848       if (!strcasecmp(option, "paused")) {
01849          *empty |= QUEUE_EMPTY_PAUSED;
01850       } else if (!strcasecmp(option, "penalty")) {
01851          *empty |= QUEUE_EMPTY_PENALTY;
01852       } else if (!strcasecmp(option, "inuse")) {
01853          *empty |= QUEUE_EMPTY_INUSE;
01854       } else if (!strcasecmp(option, "ringing")) {
01855          *empty |= QUEUE_EMPTY_RINGING;
01856       } else if (!strcasecmp(option, "invalid")) {
01857          *empty |= QUEUE_EMPTY_INVALID;
01858       } else if (!strcasecmp(option, "wrapup")) {
01859          *empty |= QUEUE_EMPTY_WRAPUP;
01860       } else if (!strcasecmp(option, "unavailable")) {
01861          *empty |= QUEUE_EMPTY_UNAVAILABLE;
01862       } else if (!strcasecmp(option, "unknown")) {
01863          *empty |= QUEUE_EMPTY_UNKNOWN;
01864       } else if (!strcasecmp(option, "loose")) {
01865          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
01866       } else if (!strcasecmp(option, "strict")) {
01867          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
01868       } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
01869          *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
01870       } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
01871          *empty = 0;
01872       } else {
01873          ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
01874       }
01875    }
01876 }
01877 
01878 /*! \brief Configure a queue parameter.
01879  * 
01880  * The failunknown flag is set for config files (and static realtime) to show
01881  * errors for unknown parameters. It is cleared for dynamic realtime to allow
01882  *  extra fields in the tables.
01883  * \note For error reporting, line number is passed for .conf static configuration,
01884  * for Realtime queues, linenum is -1.
01885 */
01886 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
01887 {
01888    if (!strcasecmp(param, "musicclass") || 
01889       !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
01890       ast_string_field_set(q, moh, val);
01891    } else if (!strcasecmp(param, "announce")) {
01892       ast_string_field_set(q, announce, val);
01893    } else if (!strcasecmp(param, "context")) {
01894       ast_string_field_set(q, context, val);
01895    } else if (!strcasecmp(param, "timeout")) {
01896       q->timeout = atoi(val);
01897       if (q->timeout < 0)
01898          q->timeout = DEFAULT_TIMEOUT;
01899    } else if (!strcasecmp(param, "ringinuse")) {
01900       q->ringinuse = ast_true(val);
01901    } else if (!strcasecmp(param, "setinterfacevar")) {
01902       q->setinterfacevar = ast_true(val);
01903    } else if (!strcasecmp(param, "setqueuevar")) {
01904       q->setqueuevar = ast_true(val);
01905    } else if (!strcasecmp(param, "setqueueentryvar")) {
01906       q->setqueueentryvar = ast_true(val);
01907    } else if (!strcasecmp(param, "monitor-format")) {
01908       ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
01909    } else if (!strcasecmp(param, "membermacro")) {
01910       ast_string_field_set(q, membermacro, val);
01911    } else if (!strcasecmp(param, "membergosub")) {
01912       ast_string_field_set(q, membergosub, val);
01913    } else if (!strcasecmp(param, "queue-youarenext")) {
01914       ast_string_field_set(q, sound_next, val);
01915    } else if (!strcasecmp(param, "queue-thereare")) {
01916       ast_string_field_set(q, sound_thereare, val);
01917    } else if (!strcasecmp(param, "queue-callswaiting")) {
01918       ast_string_field_set(q, sound_calls, val);
01919    } else if (!strcasecmp(param, "queue-quantity1")) {
01920       ast_string_field_set(q, queue_quantity1, val);
01921    } else if (!strcasecmp(param, "queue-quantity2")) {
01922       ast_string_field_set(q, queue_quantity2, val);
01923    } else if (!strcasecmp(param, "queue-holdtime")) {
01924       ast_string_field_set(q, sound_holdtime, val);
01925    } else if (!strcasecmp(param, "queue-minutes")) {
01926       ast_string_field_set(q, sound_minutes, val);
01927    } else if (!strcasecmp(param, "queue-minute")) {
01928       ast_string_field_set(q, sound_minute, val);
01929    } else if (!strcasecmp(param, "queue-seconds")) {
01930       ast_string_field_set(q, sound_seconds, val);
01931    } else if (!strcasecmp(param, "queue-thankyou")) {
01932       ast_string_field_set(q, sound_thanks, val);
01933    } else if (!strcasecmp(param, "queue-callerannounce")) {
01934       ast_string_field_set(q, sound_callerannounce, val);
01935    } else if (!strcasecmp(param, "queue-reporthold")) {
01936       ast_string_field_set(q, sound_reporthold, val);
01937    } else if (!strcasecmp(param, "announce-frequency")) {
01938       q->announcefrequency = atoi(val);
01939    } else if (!strcasecmp(param, "min-announce-frequency")) {
01940       q->minannouncefrequency = atoi(val);
01941       ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
01942    } else if (!strcasecmp(param, "announce-round-seconds")) {
01943       q->roundingseconds = atoi(val);
01944       /* Rounding to any other values just doesn't make sense... */
01945       if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
01946          || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
01947          if (linenum >= 0) {
01948             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01949                "using 0 instead for queue '%s' at line %d of queues.conf\n",
01950                val, param, q->name, linenum);
01951          } else {
01952             ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01953                "using 0 instead for queue '%s'\n", val, param, q->name);
01954          }
01955          q->roundingseconds=0;
01956       }
01957    } else if (!strcasecmp(param, "announce-holdtime")) {
01958       if (!strcasecmp(val, "once"))
01959          q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01960       else if (ast_true(val))
01961          q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01962       else
01963          q->announceholdtime = 0;
01964    } else if (!strcasecmp(param, "announce-position")) {
01965       if (!strcasecmp(val, "limit"))
01966          q->announceposition = ANNOUNCEPOSITION_LIMIT;
01967       else if (!strcasecmp(val, "more"))
01968          q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
01969       else if (ast_true(val))
01970          q->announceposition = ANNOUNCEPOSITION_YES;
01971       else
01972          q->announceposition = ANNOUNCEPOSITION_NO;
01973    } else if (!strcasecmp(param, "announce-position-limit")) {
01974       q->announcepositionlimit = atoi(val);
01975    } else if (!strcasecmp(param, "periodic-announce")) {
01976       if (strchr(val, ',')) {
01977          char *s, *buf = ast_strdupa(val);
01978          unsigned int i = 0;
01979 
01980          while ((s = strsep(&buf, ",|"))) {
01981             if (!q->sound_periodicannounce[i])
01982                q->sound_periodicannounce[i] = ast_str_create(16);
01983             ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
01984             i++;
01985             if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01986                break;
01987          }
01988          q->numperiodicannounce = i;
01989       } else {
01990          ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
01991          q->numperiodicannounce = 1;
01992       }
01993    } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01994       q->periodicannouncefrequency = atoi(val);
01995    } else if (!strcasecmp(param, "relative-periodic-announce")) {
01996       q->relativeperiodicannounce = ast_true(val);
01997    } else if (!strcasecmp(param, "random-periodic-announce")) {
01998       q->randomperiodicannounce = ast_true(val);
01999    } else if (!strcasecmp(param, "retry")) {
02000       q->retry = atoi(val);
02001       if (q->retry <= 0)
02002          q->retry = DEFAULT_RETRY;
02003    } else if (!strcasecmp(param, "wrapuptime")) {
02004       q->wrapuptime = atoi(val);
02005    } else if (!strcasecmp(param, "penaltymemberslimit")) {
02006       if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
02007          q->penaltymemberslimit = 0;
02008       }
02009    } else if (!strcasecmp(param, "autofill")) {
02010       q->autofill = ast_true(val);
02011    } else if (!strcasecmp(param, "monitor-type")) {
02012       if (!strcasecmp(val, "mixmonitor"))
02013          q->montype = 1;
02014    } else if (!strcasecmp(param, "autopause")) {
02015       q->autopause = autopause2int(val);
02016    } else if (!strcasecmp(param, "maxlen")) {
02017       q->maxlen = atoi(val);
02018       if (q->maxlen < 0)
02019          q->maxlen = 0;
02020    } else if (!strcasecmp(param, "servicelevel")) {
02021       q->servicelevel= atoi(val);
02022    } else if (!strcasecmp(param, "strategy")) {
02023       int strategy;
02024 
02025       /* We are a static queue and already have set this, no need to do it again */
02026       if (failunknown) {
02027          return;
02028       }
02029       strategy = strat2int(val);
02030       if (strategy < 0) {
02031          ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
02032             val, q->name);
02033          q->strategy = QUEUE_STRATEGY_RINGALL;
02034       }
02035       if (strategy == q->strategy) {
02036          return;
02037       }
02038       if (strategy == QUEUE_STRATEGY_LINEAR) {
02039          ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
02040          return;
02041       }
02042       q->strategy = strategy;
02043    } else if (!strcasecmp(param, "joinempty")) {
02044       parse_empty_options(val, &q->joinempty, 1);
02045    } else if (!strcasecmp(param, "leavewhenempty")) {
02046       parse_empty_options(val, &q->leavewhenempty, 0);
02047    } else if (!strcasecmp(param, "eventmemberstatus")) {
02048       q->maskmemberstatus = !ast_true(val);
02049    } else if (!strcasecmp(param, "eventwhencalled")) {
02050       if (!strcasecmp(val, "vars")) {
02051          q->eventwhencalled = QUEUE_EVENT_VARIABLES;
02052       } else {
02053          q->eventwhencalled = ast_true(val) ? 1 : 0;
02054       }
02055    } else if (!strcasecmp(param, "reportholdtime")) {
02056       q->reportholdtime = ast_true(val);
02057    } else if (!strcasecmp(param, "memberdelay")) {
02058       q->memberdelay = atoi(val);
02059    } else if (!strcasecmp(param, "weight")) {
02060       q->weight = atoi(val);
02061    } else if (!strcasecmp(param, "timeoutrestart")) {
02062       q->timeoutrestart = ast_true(val);
02063    } else if (!strcasecmp(param, "defaultrule")) {
02064       ast_string_field_set(q, defaultrule, val);
02065    } else if (!strcasecmp(param, "timeoutpriority")) {
02066       if (!strcasecmp(val, "conf")) {
02067          q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
02068       } else {
02069          q->timeoutpriority = TIMEOUT_PRIORITY_APP;
02070       }
02071    } else if (failunknown) {
02072       if (linenum >= 0) {
02073          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
02074             q->name, param, linenum);
02075       } else {
02076          ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
02077       }
02078    }
02079 }
02080 
02081 /*!
02082  * \brief Find rt member record to update otherwise create one.
02083  *
02084  * Search for member in queue, if found update penalty/paused state,
02085  * if no member exists create one flag it as a RT member and add to queue member list. 
02086 */
02087 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
02088 {
02089    struct member *m;
02090    struct ao2_iterator mem_iter;
02091    int penalty = 0;
02092    int paused  = 0;
02093    int found = 0;
02094 
02095    if (ast_strlen_zero(rt_uniqueid)) {
02096       ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
02097       return;
02098    }
02099 
02100    if (penalty_str) {
02101       penalty = atoi(penalty_str);
02102       if (penalty < 0)
02103          penalty = 0;
02104    }
02105 
02106    if (paused_str) {
02107       paused = atoi(paused_str);
02108       if (paused < 0)
02109          paused = 0;
02110    }
02111 
02112    /* Find member by realtime uniqueid and update */
02113    mem_iter = ao2_iterator_init(q->members, 0);
02114    while ((m = ao2_iterator_next(&mem_iter))) {
02115       if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
02116          m->dead = 0;   /* Do not delete this one. */
02117          ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
02118          if (paused_str)
02119             m->paused = paused;
02120          if (strcasecmp(state_interface, m->state_interface)) {
02121             ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
02122          }     
02123          m->penalty = penalty;
02124          found = 1;
02125          ao2_ref(m, -1);
02126          break;
02127       }
02128       ao2_ref(m, -1);
02129    }
02130    ao2_iterator_destroy(&mem_iter);
02131 
02132    /* Create a new member */
02133    if (!found) {
02134       if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
02135          m->dead = 0;
02136          m->realtime = 1;
02137          ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
02138          ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
02139          ao2_link(q->members, m);
02140          ao2_ref(m, -1);
02141          m = NULL;
02142       }
02143    }
02144 }
02145 
02146 /*! \brief Iterate through queue's member list and delete them */
02147 static void free_members(struct call_queue *q, int all)
02148 {
02149    /* Free non-dynamic members */
02150    struct member *cur;
02151    struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
02152 
02153    while ((cur = ao2_iterator_next(&mem_iter))) {
02154       if (all || !cur->dynamic) {
02155          ao2_unlink(q->members, cur);
02156       }
02157       ao2_ref(cur, -1);
02158    }
02159    ao2_iterator_destroy(&mem_iter);
02160 }
02161 
02162 /*! \brief Free queue's member list then its string fields */
02163 static void destroy_queue(void *obj)
02164 {
02165    struct call_queue *q = obj;
02166    int i;
02167 
02168    free_members(q, 1);
02169    ast_string_field_free_memory(q);
02170    for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
02171       if (q->sound_periodicannounce[i])
02172          free(q->sound_periodicannounce[i]);
02173    }
02174    ao2_ref(q->members, -1);
02175 }
02176 
02177 static struct call_queue *alloc_queue(const char *queuename)
02178 {
02179    struct call_queue *q;
02180 
02181    if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
02182       if (ast_string_field_init(q, 64)) {
02183          queue_t_unref(q, "String field allocation failed");
02184          return NULL;
02185       }
02186       ast_string_field_set(q, name, queuename);
02187    }
02188    return q;
02189 }
02190 
02191 /*!
02192  * \brief Reload a single queue via realtime.
02193  *
02194  * Check for statically defined queue first, check if deleted RT queue,
02195  * check for new RT queue, if queue vars are not defined init them with defaults.
02196  * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
02197  * \retval the queue, 
02198  * \retval NULL if it doesn't exist.
02199  * \note Should be called with the "queues" container locked. 
02200 */
02201 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
02202 {
02203    struct ast_variable *v;
02204    struct call_queue *q, tmpq = {
02205       .name = queuename,   
02206    };
02207    struct member *m;
02208    struct ao2_iterator mem_iter;
02209    char *interface = NULL;
02210    const char *tmp_name;
02211    char *tmp;
02212    char tmpbuf[64];  /* Must be longer than the longest queue param name. */
02213 
02214    /* Static queues override realtime. */
02215    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
02216       ao2_lock(q);
02217       if (!q->realtime) {
02218          if (q->dead) {
02219             ao2_unlock(q);
02220             queue_t_unref(q, "Queue is dead; can't return it");
02221             return NULL;
02222          } else {
02223             ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
02224             ao2_unlock(q);
02225             return q;
02226          }
02227       }
02228    } else if (!member_config)
02229       /* Not found in the list, and it's not realtime ... */
02230       return NULL;
02231 
02232    /* Check if queue is defined in realtime. */
02233    if (!queue_vars) {
02234       /* Delete queue from in-core list if it has been deleted in realtime. */
02235       if (q) {
02236          /*! \note Hmm, can't seem to distinguish a DB failure from a not
02237             found condition... So we might delete an in-core queue
02238             in case of DB failure. */
02239          ast_debug(1, "Queue %s not found in realtime.\n", queuename);
02240 
02241          q->dead = 1;
02242          /* Delete if unused (else will be deleted when last caller leaves). */
02243          queues_t_unlink(queues, q, "Unused; removing from container");
02244          ao2_unlock(q);
02245          queue_t_unref(q, "Queue is dead; can't return it");
02246       }
02247       return NULL;
02248    }
02249 
02250    /* Create a new queue if an in-core entry does not exist yet. */
02251    if (!q) {
02252       struct ast_variable *tmpvar = NULL;
02253       if (!(q = alloc_queue(queuename)))
02254          return NULL;
02255       ao2_lock(q);
02256       clear_queue(q);
02257       q->realtime = 1;
02258       /*Before we initialize the queue, we need to set the strategy, so that linear strategy
02259        * will allocate the members properly
02260        */
02261       for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
02262          if (!strcasecmp(tmpvar->name, "strategy")) {
02263             q->strategy = strat2int(tmpvar->value);
02264             if (q->strategy < 0) {
02265                ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
02266                tmpvar->value, q->name);
02267                q->strategy = QUEUE_STRATEGY_RINGALL;
02268             }
02269             break;
02270          }
02271       }
02272       /* We traversed all variables and didn't find a strategy */
02273       if (!tmpvar)
02274          q->strategy = QUEUE_STRATEGY_RINGALL;
02275       queues_t_link(queues, q, "Add queue to container");
02276    }
02277    init_queue(q);    /* Ensure defaults for all parameters not set explicitly. */
02278 
02279    memset(tmpbuf, 0, sizeof(tmpbuf));
02280    for (v = queue_vars; v; v = v->next) {
02281       /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
02282       if (strchr(v->name, '_')) {
02283          ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
02284          tmp_name = tmpbuf;
02285          tmp = tmpbuf;
02286          while ((tmp = strchr(tmp, '_')))
02287             *tmp++ = '-';
02288       } else
02289          tmp_name = v->name;
02290 
02291       /* NULL values don't get returned from realtime; blank values should
02292        * still get set.  If someone doesn't want a value to be set, they
02293        * should set the realtime column to NULL, not blank. */
02294       queue_set_param(q, tmp_name, v->value, -1, 0);
02295    }
02296 
02297    /* Temporarily set realtime members dead so we can detect deleted ones. */
02298    mem_iter = ao2_iterator_init(q->members, 0);
02299    while ((m = ao2_iterator_next(&mem_iter))) {
02300       if (m->realtime)
02301          m->dead = 1;
02302       ao2_ref(m, -1);
02303    }
02304    ao2_iterator_destroy(&mem_iter);
02305 
02306    while ((interface = ast_category_browse(member_config, interface))) {
02307       rt_handle_member_record(q, interface,
02308          ast_variable_retrieve(member_config, interface, "uniqueid"),
02309          S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
02310          ast_variable_retrieve(member_config, interface, "penalty"),
02311          ast_variable_retrieve(member_config, interface, "paused"),
02312          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
02313    }
02314 
02315    /* Delete all realtime members that have been deleted in DB. */
02316    mem_iter = ao2_iterator_init(q->members, 0);
02317    while ((m = ao2_iterator_next(&mem_iter))) {
02318       if (m->dead) {
02319          ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02320          ao2_unlink(q->members, m);
02321       }
02322       ao2_ref(m, -1);
02323    }
02324    ao2_iterator_destroy(&mem_iter);
02325 
02326    ao2_unlock(q);
02327 
02328    return q;
02329 }
02330 
02331 /*! \note Returns a reference to the loaded realtime queue. */
02332 static struct call_queue *load_realtime_queue(const char *queuename)
02333 {
02334    struct ast_variable *queue_vars;
02335    struct ast_config *member_config = NULL;
02336    struct call_queue *q = NULL, tmpq = {
02337       .name = queuename,   
02338    };
02339    int prev_weight = 0;
02340 
02341    /* Find the queue in the in-core list first. */
02342    q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
02343 
02344    if (!q || q->realtime) {
02345       /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
02346          queue operations while waiting for the DB.
02347 
02348          This will be two separate database transactions, so we might
02349          see queue parameters as they were before another process
02350          changed the queue and member list as it was after the change.
02351          Thus we might see an empty member list when a queue is
02352          deleted. In practise, this is unlikely to cause a problem. */
02353 
02354       queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
02355       if (queue_vars) {
02356          member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
02357          if (!member_config) {
02358             ast_debug(1, "No queue_members defined in config extconfig.conf\n");
02359             member_config = ast_config_new();
02360          }
02361       }
02362       if (q) {
02363          prev_weight = q->weight ? 1 : 0;
02364          queue_t_unref(q, "Need to find realtime queue");
02365       }
02366 
02367       q = find_queue_by_name_rt(queuename, queue_vars, member_config);
02368       ast_config_destroy(member_config);
02369       ast_variables_destroy(queue_vars);
02370 
02371       /* update the use_weight value if the queue's has gained or lost a weight */
02372       if (q) {
02373          if (!q->weight && prev_weight) {
02374             ast_atomic_fetchadd_int(&use_weight, -1);
02375          }
02376          if (q->weight && !prev_weight) {
02377             ast_atomic_fetchadd_int(&use_weight, +1);
02378          }
02379       }
02380       /* Other cases will end up with the proper value for use_weight */
02381    } else {
02382       update_realtime_members(q);
02383    }
02384    return q;
02385 }
02386 
02387 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
02388 {
02389    int ret = -1;
02390 
02391    if (ast_strlen_zero(mem->rt_uniqueid))
02392       return ret;
02393 
02394    if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0)
02395       ret = 0;
02396 
02397    return ret;
02398 }
02399 
02400 
02401 static void update_realtime_members(struct call_queue *q)
02402 {
02403    struct ast_config *member_config = NULL;
02404    struct member *m;
02405    char *interface = NULL;
02406    struct ao2_iterator mem_iter;
02407 
02408    if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
02409       /* This queue doesn't have realtime members. If the queue still has any realtime
02410        * members in memory, they need to be removed.
02411        */
02412       ao2_lock(q);
02413       mem_iter = ao2_iterator_init(q->members, 0);
02414       while ((m = ao2_iterator_next(&mem_iter))) {
02415          if (m->realtime) {
02416             ao2_unlink(q->members, m);
02417          }
02418          ao2_ref(m, -1);
02419       }
02420       ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
02421       ao2_unlock(q);
02422       return;
02423    }
02424 
02425    ao2_lock(q);
02426 
02427    /* Temporarily set realtime  members dead so we can detect deleted ones.*/
02428    mem_iter = ao2_iterator_init(q->members, 0);
02429    while ((m = ao2_iterator_next(&mem_iter))) {
02430       if (m->realtime)
02431          m->dead = 1;
02432       ao2_ref(m, -1);
02433    }
02434    ao2_iterator_destroy(&mem_iter);
02435 
02436    while ((interface = ast_category_browse(member_config, interface))) {
02437       rt_handle_member_record(q, interface,
02438          ast_variable_retrieve(member_config, interface, "uniqueid"),
02439          S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
02440          ast_variable_retrieve(member_config, interface, "penalty"),
02441          ast_variable_retrieve(member_config, interface, "paused"),
02442          S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
02443    }
02444 
02445    /* Delete all realtime members that have been deleted in DB. */
02446    mem_iter = ao2_iterator_init(q->members, 0);
02447    while ((m = ao2_iterator_next(&mem_iter))) {
02448       if (m->dead) {
02449          ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
02450          ao2_unlink(q->members, m);
02451       }
02452       ao2_ref(m, -1);
02453    }
02454    ao2_iterator_destroy(&mem_iter);
02455    ao2_unlock(q);
02456    ast_config_destroy(member_config);
02457 }
02458 
02459 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
02460 {
02461    struct call_queue *q;
02462    struct queue_ent *cur, *prev = NULL;
02463    int res = -1;
02464    int pos = 0;
02465    int inserted = 0;
02466 
02467    if (!(q = load_realtime_queue(queuename)))
02468       return res;
02469 
02470    ao2_lock(q);
02471 
02472    /* This is our one */
02473    if (q->joinempty) {
02474       int status = 0;
02475       if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty))) {
02476          *reason = QUEUE_JOINEMPTY;
02477          ao2_unlock(q);
02478          queue_t_unref(q, "Done with realtime queue");
02479          return res;
02480       }
02481    }
02482    if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen))
02483       *reason = QUEUE_FULL;
02484    else if (*reason == QUEUE_UNKNOWN) {
02485       /* There's space for us, put us at the right position inside
02486        * the queue.
02487        * Take into account the priority of the calling user */
02488       inserted = 0;
02489       prev = NULL;
02490       cur = q->head;
02491       while (cur) {
02492          /* We have higher priority than the current user, enter
02493           * before him, after all the other users with priority
02494           * higher or equal to our priority. */
02495          if ((!inserted) && (qe->prio > cur->prio)) {
02496             insert_entry(q, prev, qe, &pos);
02497             inserted = 1;
02498          }
02499          /* <= is necessary for the position comparison because it may not be possible to enter
02500           * at our desired position since higher-priority callers may have taken the position we want
02501           */
02502          if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
02503             insert_entry(q, prev, qe, &pos);
02504             inserted = 1;
02505             /*pos is incremented inside insert_entry, so don't need to add 1 here*/
02506             if (position < pos) {
02507                ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
02508             }
02509          }
02510          cur->pos = ++pos;
02511          prev = cur;
02512          cur = cur->next;
02513       }
02514       /* No luck, join at the end of the queue */
02515       if (!inserted)
02516          insert_entry(q, prev, qe, &pos);
02517       ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
02518       ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
02519       ast_copy_string(qe->context, q->context, sizeof(qe->context));
02520       q->count++;
02521       res = 0;
02522       ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
02523          "Channel: %s\r\n"
02524          "CallerIDNum: %s\r\n"
02525          "CallerIDName: %s\r\n"
02526          "ConnectedLineNum: %s\r\n"
02527          "ConnectedLineName: %s\r\n"
02528          "Queue: %s\r\n"
02529          "Position: %d\r\n"
02530          "Count: %d\r\n"
02531          "Uniqueid: %s\r\n",
02532          qe->chan->name,
02533          S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
02534          S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
02535          S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
02536          S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
02537          q->name, qe->pos, q->count, qe->chan->uniqueid );
02538       ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
02539    }
02540    ao2_unlock(q);
02541    queue_t_unref(q, "Done with realtime queue");
02542 
02543    return res;
02544 }
02545 
02546 static int play_file(struct ast_channel *chan, const char *filename)
02547 {
02548    int res;
02549 
02550    if (ast_strlen_zero(filename)) {
02551       return 0;
02552    }
02553 
02554    if (!ast_fileexists(filename, NULL, chan->language)) {
02555       return 0;
02556    }
02557 
02558    ast_stopstream(chan);
02559 
02560    res = ast_streamfile(chan, filename, chan->language);
02561    if (!res)
02562       res = ast_waitstream(chan, AST_DIGIT_ANY);
02563 
02564    ast_stopstream(chan);
02565 
02566    return res;
02567 }
02568 
02569 /*!
02570  * \brief Check for valid exit from queue via goto
02571  * \retval 0 if failure
02572  * \retval 1 if successful
02573 */
02574 static int valid_exit(struct queue_ent *qe, char digit)
02575 {
02576    int digitlen = strlen(qe->digits);
02577 
02578    /* Prevent possible buffer overflow */
02579    if (digitlen < sizeof(qe->digits) - 2) {
02580       qe->digits[digitlen] = digit;
02581       qe->digits[digitlen + 1] = '\0';
02582    } else {
02583       qe->digits[0] = '\0';
02584       return 0;
02585    }
02586 
02587    /* If there's no context to goto, short-circuit */
02588    if (ast_strlen_zero(qe->context))
02589       return 0;
02590 
02591    /* If the extension is bad, then reset the digits to blank */
02592    if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
02593       S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, NULL))) {
02594       qe->digits[0] = '\0';
02595       return 0;
02596    }
02597 
02598    /* We have an exact match */
02599    if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
02600       qe->valid_digits = 1;
02601       /* Return 1 on a successful goto */
02602       return 1;
02603    }
02604 
02605    return 0;
02606 }
02607 
02608 static int say_position(struct queue_ent *qe, int ringing)
02609 {
02610    int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
02611    int say_thanks = 1;
02612    time_t now;
02613 
02614    /* Let minannouncefrequency seconds pass between the start of each position announcement */
02615    time(&now);
02616    if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
02617       return 0;
02618 
02619    /* If either our position has changed, or we are over the freq timer, say position */
02620    if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
02621       return 0;
02622 
02623    if (ringing) {
02624       ast_indicate(qe->chan,-1);
02625    } else {
02626       ast_moh_stop(qe->chan);
02627    }
02628 
02629    if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
02630       qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
02631       (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
02632       qe->pos <= qe->parent->announcepositionlimit))
02633          announceposition = 1;
02634 
02635 
02636    if (announceposition == 1) {
02637       /* Say we're next, if we are */
02638       if (qe->pos == 1) {
02639          res = play_file(qe->chan, qe->parent->sound_next);
02640          if (res)
02641             goto playout;
02642          else
02643             goto posout;
02644       } else {
02645          if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
02646             /* More than Case*/
02647             res = play_file(qe->chan, qe->parent->queue_quantity1);
02648             if (res)
02649                goto playout;
02650             res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
02651             if (res)
02652                goto playout;
02653          } else {
02654             /* Normal Case */
02655             res = play_file(qe->chan, qe->parent->sound_thereare);
02656             if (res)
02657                goto playout;
02658             res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
02659             if (res)
02660                goto playout;
02661          }
02662          if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
02663             /* More than Case*/
02664             res = play_file(qe->chan, qe->parent->queue_quantity2);
02665             if (res)
02666                goto playout;
02667          } else {
02668             res = play_file(qe->chan, qe->parent->sound_calls);
02669             if (res)
02670                goto playout;
02671          }
02672       }
02673    }
02674    /* Round hold time to nearest minute */
02675    avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
02676 
02677    /* If they have specified a rounding then round the seconds as well */
02678    if (qe->parent->roundingseconds) {
02679       avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
02680       avgholdsecs *= qe->parent->roundingseconds;
02681    } else {
02682       avgholdsecs = 0;
02683    }
02684 
02685    ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
02686 
02687    /* If the hold time is >1 min, if it's enabled, and if it's not
02688       supposed to be only once and we have already said it, say it */
02689     if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
02690         ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
02691         !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
02692       res = play_file(qe->chan, qe->parent->sound_holdtime);
02693       if (res)
02694          goto playout;
02695 
02696       if (avgholdmins >= 1) {
02697          res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
02698          if (res)
02699             goto playout;
02700 
02701          if (avgholdmins == 1) {
02702             res = play_file(qe->chan, qe->parent->sound_minute);
02703             if (res)
02704                goto playout;
02705          } else {
02706             res = play_file(qe->chan, qe->parent->sound_minutes);
02707             if (res)
02708                goto playout;
02709          }
02710       }
02711       if (avgholdsecs >= 1) {
02712          res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
02713          if (res)
02714             goto playout;
02715 
02716          res = play_file(qe->chan, qe->parent->sound_seconds);
02717          if (res)
02718             goto playout;
02719       }
02720    } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
02721       say_thanks = 0;
02722    }
02723 
02724 posout:
02725    if (qe->parent->announceposition) {
02726       ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
02727          qe->chan->name, qe->parent->name, qe->pos);
02728    }
02729    if (say_thanks) {
02730       res = play_file(qe->chan, qe->parent->sound_thanks);
02731    }
02732 playout:
02733 
02734    if ((res > 0 && !valid_exit(qe, res)))
02735       res = 0;
02736 
02737    /* Set our last_pos indicators */
02738    qe->last_pos = now;
02739    qe->last_pos_said = qe->pos;
02740 
02741    /* Don't restart music on hold if we're about to exit the caller from the queue */
02742    if (!res) {
02743       if (ringing) {
02744          ast_indicate(qe->chan, AST_CONTROL_RINGING);
02745       } else {
02746          ast_moh_start(qe->chan, qe->moh, NULL);
02747       }
02748    }
02749    return res;
02750 }
02751 
02752 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
02753 {
02754    int oldvalue;
02755 
02756    /* Calculate holdtime using an exponential average */
02757    /* Thanks to SRT for this contribution */
02758    /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
02759 
02760    ao2_lock(qe->parent);
02761    oldvalue = qe->parent->holdtime;
02762    qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
02763    ao2_unlock(qe->parent);
02764 }
02765 
02766 /*! \brief Caller leaving queue.
02767  * 
02768  * Search the queue to find the leaving client, if found remove from queue
02769  * create manager event, move others up the queue.
02770 */
02771 static void leave_queue(struct queue_ent *qe)
02772 {
02773    struct call_queue *q;
02774    struct queue_ent *current, *prev = NULL;
02775    struct penalty_rule *pr_iter;
02776    int pos = 0;
02777 
02778    if (!(q = qe->parent))
02779       return;
02780    queue_t_ref(q, "Copy queue pointer from queue entry");
02781    ao2_lock(q);
02782 
02783    prev = NULL;
02784    for (current = q->head; current; current = current->next) {
02785       if (current == qe) {
02786          char posstr[20];
02787          q->count--;
02788 
02789          /* Take us out of the queue */
02790          ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
02791             "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
02792             qe->chan->name, q->name,  q->count, qe->pos, qe->chan->uniqueid);
02793          ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
02794          /* Take us out of the queue */
02795          if (prev)
02796             prev->next = current->next;
02797          else
02798             q->head = current->next;
02799          /* Free penalty rules */
02800          while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
02801             ast_free(pr_iter);
02802          snprintf(posstr, sizeof(posstr), "%d", qe->pos);
02803          pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
02804       } else {
02805          /* Renumber the people after us in the queue based on a new count */
02806          current->pos = ++pos;
02807          prev = current;
02808       }
02809    }
02810    ao2_unlock(q);
02811 
02812    /*If the queue is a realtime queue, check to see if it's still defined in real time*/
02813    if (q->realtime) {
02814       struct ast_variable *var;
02815       if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
02816          q->dead = 1;
02817       } else {
02818          ast_variables_destroy(var);
02819       }
02820    }
02821 
02822    if (q->dead) { 
02823       /* It's dead and nobody is in it, so kill it */
02824       queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
02825    }
02826    /* unref the explicit ref earlier in the function */
02827    queue_t_unref(q, "Expire copied reference");
02828 }
02829 
02830 /*!
02831  * \internal
02832  * \brief Destroy the given callattempt structure and free it.
02833  * \since 1.8
02834  *
02835  * \param doomed callattempt structure to destroy.
02836  *
02837  * \return Nothing
02838  */
02839 static void callattempt_free(struct callattempt *doomed)
02840 {
02841    if (doomed->member) {
02842       ao2_ref(doomed->member, -1);
02843    }
02844    ast_party_connected_line_free(&doomed->connected);
02845    ast_free(doomed);
02846 }
02847 
02848 /*! \brief Hang up a list of outgoing calls */
02849 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
02850 {
02851    struct callattempt *oo;
02852 
02853    while (outgoing) {
02854       /* If someone else answered the call we should indicate this in the CANCEL */
02855       /* Hangup any existing lines we have open */
02856       if (outgoing->chan && (outgoing->chan != exception)) {
02857          if (exception || cancel_answered_elsewhere)
02858             ast_set_flag(outgoing->chan, AST_FLAG_ANSWERED_ELSEWHERE);
02859          ast_hangup(outgoing->chan);
02860       }
02861       oo = outgoing;
02862       outgoing = outgoing->q_next;
02863       ast_aoc_destroy_decoded(oo->aoc_s_rate_list);
02864       callattempt_free(oo);
02865    }
02866 }
02867 
02868 /*!
02869  * \brief Get the number of members available to accept a call.
02870  *
02871  * \note The queue passed in should be locked prior to this function call
02872  *
02873  * \param[in] q The queue for which we are couting the number of available members
02874  * \return Return the number of available members in queue q
02875  */
02876 static int num_available_members(struct call_queue *q)
02877 {
02878    struct member *mem;
02879    int avl = 0;
02880    struct ao2_iterator mem_iter;
02881 
02882    mem_iter = ao2_iterator_init(q->members, 0);
02883    while ((mem = ao2_iterator_next(&mem_iter))) {
02884       switch (mem->status) {
02885       case AST_DEVICE_INUSE:
02886          if (!q->ringinuse)
02887             break;
02888          /* else fall through */
02889       case AST_DEVICE_NOT_INUSE:
02890       case AST_DEVICE_UNKNOWN:
02891          if (!mem->paused) {
02892             avl++;
02893          }
02894          break;
02895       }
02896       ao2_ref(mem, -1);
02897 
02898       /* If autofill is not enabled or if the queue's strategy is ringall, then
02899        * we really don't care about the number of available members so much as we
02900        * do that there is at least one available.
02901        *
02902        * In fact, we purposely will return from this function stating that only
02903        * one member is available if either of those conditions hold. That way,
02904        * functions which determine what action to take based on the number of available
02905        * members will operate properly. The reasoning is that even if multiple
02906        * members are available, only the head caller can actually be serviced.
02907        */
02908       if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
02909          break;
02910       }
02911    }
02912    ao2_iterator_destroy(&mem_iter);
02913 
02914    return avl;
02915 }
02916 
02917 /* traverse all defined queues which have calls waiting and contain this member
02918    return 0 if no other queue has precedence (higher weight) or 1 if found  */
02919 static int compare_weight(struct call_queue *rq, struct member *member)
02920 {
02921    struct call_queue *q;
02922    struct member *mem;
02923    int found = 0;
02924    struct ao2_iterator queue_iter;
02925 
02926    queue_iter = ao2_iterator_init(queues, 0);
02927    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
02928       if (q == rq) { /* don't check myself, could deadlock */
02929          queue_t_unref(q, "Done with iterator");
02930          continue;
02931       }
02932       ao2_lock(q);
02933       if (q->count && q->members) {
02934          if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
02935             ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
02936             if (q->weight > rq->weight && q->count >= num_available_members(q)) {
02937                ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
02938                found = 1;
02939             }
02940             ao2_ref(mem, -1);
02941          }
02942       }
02943       ao2_unlock(q);
02944       queue_t_unref(q, "Done with iterator");
02945       if (found) {
02946          break;
02947       }
02948    }
02949    ao2_iterator_destroy(&queue_iter);
02950    return found;
02951 }
02952 
02953 /*! \brief common hangup actions */
02954 static void do_hang(struct callattempt *o)
02955 {
02956    o->stillgoing = 0;
02957    ast_hangup(o->chan);
02958    o->chan = NULL;
02959 }
02960 
02961 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
02962 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
02963 {
02964    struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
02965    const char *tmp;
02966 
02967    if (pbx_builtin_serialize_variables(chan, &buf)) {
02968       int i, j;
02969 
02970       /* convert "\n" to "\nVariable: " */
02971       strcpy(vars, "Variable: ");
02972       tmp = ast_str_buffer(buf);
02973 
02974       for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
02975          vars[j] = tmp[i];
02976 
02977          if (tmp[i + 1] == '\0')
02978             break;
02979          if (tmp[i] == '\n') {
02980             vars[j++] = '\r';
02981             vars[j++] = '\n';
02982 
02983             ast_copy_string(&(vars[j]), "Variable: ", len - j);
02984             j += 9;
02985          }
02986       }
02987       if (j > len - 3)
02988          j = len - 3;
02989       vars[j++] = '\r';
02990       vars[j++] = '\n';
02991       vars[j] = '\0';
02992    } else {
02993       /* there are no channel variables; leave it blank */
02994       *vars = '\0';
02995    }
02996    return vars;
02997 }
02998 
02999 /*! 
03000  * \brief Part 2 of ring_one
03001  *
03002  * Does error checking before attempting to request a channel and call a member. 
03003  * This function is only called from ring_one(). 
03004  * Failure can occur if:
03005  * - Agent on call
03006  * - Agent is paused
03007  * - Wrapup time not expired
03008  * - Priority by another queue
03009  *
03010  * \retval 1 on success to reach a free agent
03011  * \retval 0 on failure to get agent.
03012  */
03013 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
03014 {
03015    int res;
03016    int status;
03017    char tech[256];
03018    char *location;
03019    const char *macrocontext, *macroexten;
03020 
03021    /* on entry here, we know that tmp->chan == NULL */
03022    if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
03023       (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
03024       ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n", 
03025             (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
03026       if (qe->chan->cdr)
03027          ast_cdr_busy(qe->chan->cdr);
03028       tmp->stillgoing = 0;
03029       (*busies)++;
03030       return 0;
03031    }
03032 
03033    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
03034       ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
03035       if (qe->chan->cdr)
03036          ast_cdr_busy(qe->chan->cdr);
03037       tmp->stillgoing = 0;
03038       return 0;
03039    }
03040 
03041    if (tmp->member->paused) {
03042       ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
03043       if (qe->chan->cdr)
03044          ast_cdr_busy(qe->chan->cdr);
03045       tmp->stillgoing = 0;
03046       return 0;
03047    }
03048    if (use_weight && compare_weight(qe->parent,tmp->member)) {
03049       ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
03050       if (qe->chan->cdr)
03051          ast_cdr_busy(qe->chan->cdr);
03052       tmp->stillgoing = 0;
03053       (*busies)++;
03054       return 0;
03055    }
03056 
03057    ast_copy_string(tech, tmp->interface, sizeof(tech));
03058    if ((location = strchr(tech, '/')))
03059       *location++ = '\0';
03060    else
03061       location = "";
03062 
03063    /* Request the peer */
03064    tmp->chan = ast_request(tech, qe->chan->nativeformats, qe->chan, location, &status);
03065    if (!tmp->chan) {       /* If we can't, just go on to the next call */
03066       if (qe->chan->cdr)
03067          ast_cdr_busy(qe->chan->cdr);
03068       tmp->stillgoing = 0; 
03069 
03070       ao2_lock(qe->parent);
03071       update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03072       qe->parent->rrpos++;
03073       qe->linpos++;
03074       ao2_unlock(qe->parent);
03075 
03076       (*busies)++;
03077       return 0;
03078    }
03079 
03080    ast_channel_lock_both(tmp->chan, qe->chan);
03081 
03082    if (qe->cancel_answered_elsewhere) {
03083       ast_set_flag(tmp->chan, AST_FLAG_ANSWERED_ELSEWHERE);
03084    }
03085    tmp->chan->appl = "AppQueue";
03086    tmp->chan->data = "(Outgoing Line)";
03087    memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
03088 
03089    /* If the new channel has no callerid, try to guess what it should be */
03090    if (!tmp->chan->caller.id.number.valid) {
03091       if (qe->chan->connected.id.number.valid) {
03092          struct ast_party_caller caller;
03093 
03094          ast_party_caller_set_init(&caller, &tmp->chan->caller);
03095          caller.id = qe->chan->connected.id;
03096          caller.ani = qe->chan->connected.ani;
03097          ast_channel_set_caller_event(tmp->chan, &caller, NULL);
03098       } else if (!ast_strlen_zero(qe->chan->dialed.number.str)) {
03099          ast_set_callerid(tmp->chan, qe->chan->dialed.number.str, NULL, NULL);
03100       } else if (!ast_strlen_zero(S_OR(qe->chan->macroexten, qe->chan->exten))) {
03101          ast_set_callerid(tmp->chan, S_OR(qe->chan->macroexten, qe->chan->exten), NULL, NULL); 
03102       }
03103       tmp->dial_callerid_absent = 1;
03104    }
03105 
03106    ast_party_redirecting_copy(&tmp->chan->redirecting, &qe->chan->redirecting);
03107 
03108    tmp->chan->dialed.transit_network_select = qe->chan->dialed.transit_network_select;
03109 
03110    ast_connected_line_copy_from_caller(&tmp->chan->connected, &qe->chan->caller);
03111 
03112    /* Inherit specially named variables from parent channel */
03113    ast_channel_inherit_variables(qe->chan, tmp->chan);
03114    ast_channel_datastore_inherit(qe->chan, tmp->chan);
03115 
03116    /* Presense of ADSI CPE on outgoing channel follows ours */
03117    tmp->chan->adsicpe = qe->chan->adsicpe;
03118 
03119    /* Inherit context and extension */
03120    macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
03121    ast_string_field_set(tmp->chan, dialcontext, ast_strlen_zero(macrocontext) ? qe->chan->context : macrocontext);
03122    macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
03123    if (!ast_strlen_zero(macroexten))
03124       ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
03125    else
03126       ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
03127    if (ast_cdr_isset_unanswered()) {
03128       /* they want to see the unanswered dial attempts! */
03129       /* set up the CDR fields on all the CDRs to give sensical information */
03130       ast_cdr_setdestchan(tmp->chan->cdr, tmp->chan->name);
03131       strcpy(tmp->chan->cdr->clid, qe->chan->cdr->clid);
03132       strcpy(tmp->chan->cdr->channel, qe->chan->cdr->channel);
03133       strcpy(tmp->chan->cdr->src, qe->chan->cdr->src);
03134       strcpy(tmp->chan->cdr->dst, qe->chan->exten);
03135       strcpy(tmp->chan->cdr->dcontext, qe->chan->context);
03136       strcpy(tmp->chan->cdr->lastapp, qe->chan->cdr->lastapp);
03137       strcpy(tmp->chan->cdr->lastdata, qe->chan->cdr->lastdata);
03138       tmp->chan->cdr->amaflags = qe->chan->cdr->amaflags;
03139       strcpy(tmp->chan->cdr->accountcode, qe->chan->cdr->accountcode);
03140       strcpy(tmp->chan->cdr->userfield, qe->chan->cdr->userfield);
03141    }
03142 
03143    ast_channel_unlock(tmp->chan);
03144    ast_channel_unlock(qe->chan);
03145 
03146    ao2_lock(tmp->member);
03147    update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03148    if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
03149       ast_verb(1, "Member %s is busy, cannot dial", tmp->member->interface);
03150       res = -1;
03151    }
03152    else {
03153       /* Place the call, but don't wait on the answer */
03154       res = ast_call(tmp->chan, location, 0);
03155    }
03156    ao2_unlock(tmp->member);
03157    if (res) {
03158       /* Again, keep going even if there's an error */
03159       ast_verb(3, "Couldn't call %s\n", tmp->interface);
03160       do_hang(tmp);
03161       (*busies)++;
03162       update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03163       return 0;
03164    } else if (qe->parent->eventwhencalled) {
03165       char vars[2048];
03166 
03167       ast_channel_lock_both(tmp->chan, qe->chan);
03168 
03169       manager_event(EVENT_FLAG_AGENT, "AgentCalled",
03170          "Queue: %s\r\n"
03171          "AgentCalled: %s\r\n"
03172          "AgentName: %s\r\n"
03173          "ChannelCalling: %s\r\n"
03174          "DestinationChannel: %s\r\n"
03175          "CallerIDNum: %s\r\n"
03176          "CallerIDName: %s\r\n"
03177          "ConnectedLineNum: %s\r\n"
03178          "ConnectedLineName: %s\r\n"
03179          "Context: %s\r\n"
03180          "Extension: %s\r\n"
03181          "Priority: %d\r\n"
03182          "Uniqueid: %s\r\n"
03183          "%s",
03184          qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
03185          S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
03186          S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
03187          S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
03188          S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
03189          qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
03190          qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03191 
03192       ast_channel_unlock(tmp->chan);
03193       ast_channel_unlock(qe->chan);
03194 
03195       ast_verb(3, "Called %s\n", tmp->interface);
03196    }
03197 
03198    update_status(qe->parent, tmp->member, get_queue_member_status(tmp->member));
03199    return 1;
03200 }
03201 
03202 /*! \brief find the entry with the best metric, or NULL */
03203 static struct callattempt *find_best(struct callattempt *outgoing)
03204 {
03205    struct callattempt *best = NULL, *cur;
03206 
03207    for (cur = outgoing; cur; cur = cur->q_next) {
03208       if (cur->stillgoing &&              /* Not already done */
03209          !cur->chan &&              /* Isn't already going */
03210          (!best || cur->metric < best->metric)) {     /* We haven't found one yet, or it's better */
03211          best = cur;
03212       }
03213    }
03214 
03215    return best;
03216 }
03217 
03218 /*! 
03219  * \brief Place a call to a queue member.
03220  *
03221  * Once metrics have been calculated for each member, this function is used
03222  * to place a call to the appropriate member (or members). The low-level
03223  * channel-handling and error detection is handled in ring_entry
03224  *
03225  * \retval 1 if a member was called successfully
03226  * \retval 0 otherwise
03227  */
03228 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
03229 {
03230    int ret = 0;
03231 
03232    while (ret == 0) {
03233       struct callattempt *best = find_best(outgoing);
03234       if (!best) {
03235          ast_debug(1, "Nobody left to try ringing in queue\n");
03236          break;
03237       }
03238       if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03239          struct callattempt *cur;
03240          /* Ring everyone who shares this best metric (for ringall) */
03241          for (cur = outgoing; cur; cur = cur->q_next) {
03242             if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
03243                ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
03244                ret |= ring_entry(qe, cur, busies);
03245             }
03246          }
03247       } else {
03248          /* Ring just the best channel */
03249          ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
03250          ret = ring_entry(qe, best, busies);
03251       }
03252       
03253       /* If we have timed out, break out */
03254       if (qe->expire && (time(NULL) >= qe->expire)) {
03255          ast_debug(1, "Queue timed out while ringing members.\n");
03256          ret = 0;
03257          break;
03258       }
03259    }
03260 
03261    return ret;
03262 }
03263 
03264 /*! \brief Search for best metric and add to Round Robbin queue */
03265 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
03266 {
03267    struct callattempt *best = find_best(outgoing);
03268 
03269    if (best) {
03270       /* Ring just the best channel */
03271       ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03272       qe->parent->rrpos = best->metric % 1000;
03273    } else {
03274       /* Just increment rrpos */
03275       if (qe->parent->wrapped) {
03276          /* No more channels, start over */
03277          qe->parent->rrpos = 0;
03278       } else {
03279          /* Prioritize next entry */
03280          qe->parent->rrpos++;
03281       }
03282    }
03283    qe->parent->wrapped = 0;
03284 
03285    return 0;
03286 }
03287 
03288 /*! \brief Search for best metric and add to Linear queue */
03289 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
03290 {
03291    struct callattempt *best = find_best(outgoing);
03292 
03293    if (best) {
03294       /* Ring just the best channel */
03295       ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
03296       qe->linpos = best->metric % 1000;
03297    } else {
03298       /* Just increment rrpos */
03299       if (qe->linwrapped) {
03300          /* No more channels, start over */
03301          qe->linpos = 0;
03302       } else {
03303          /* Prioritize next entry */
03304          qe->linpos++;
03305       }
03306    }
03307    qe->linwrapped = 0;
03308 
03309    return 0;
03310 }
03311 
03312 /*! \brief Playback announcement to queued members if period has elapsed */
03313 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
03314 {
03315    int res = 0;
03316    time_t now;
03317 
03318    /* Get the current time */
03319    time(&now);
03320 
03321    /* Check to see if it is time to announce */
03322    if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
03323       return 0;
03324 
03325    /* Stop the music on hold so we can play our own file */
03326    if (ringing)
03327       ast_indicate(qe->chan,-1);
03328    else
03329       ast_moh_stop(qe->chan);
03330 
03331    ast_verb(3, "Playing periodic announcement\n");
03332    
03333    if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) {
03334       qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
03335    } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce || 
03336       ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
03337       qe->last_periodic_announce_sound = 0;
03338    }
03339    
03340    /* play the announcement */
03341    res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
03342 
03343    if (res > 0 && !valid_exit(qe, res))
03344       res = 0;
03345 
03346    /* Resume Music on Hold if the caller is going to stay in the queue */
03347    if (!res) {
03348       if (ringing)
03349          ast_indicate(qe->chan, AST_CONTROL_RINGING);
03350       else
03351          ast_moh_start(qe->chan, qe->moh, NULL);
03352    }
03353 
03354    /* update last_periodic_announce_time */
03355    if (qe->parent->relativeperiodicannounce)
03356       time(&qe->last_periodic_announce_time);
03357    else
03358       qe->last_periodic_announce_time = now;
03359 
03360    /* Update the current periodic announcement to the next announcement */
03361    if (!qe->parent->randomperiodicannounce) {
03362       qe->last_periodic_announce_sound++;
03363    }
03364    
03365    return res;
03366 }
03367 
03368 /*! \brief Record that a caller gave up on waiting in queue */
03369 static void record_abandoned(struct queue_ent *qe)
03370 {
03371    set_queue_variables(qe->parent, qe->chan);
03372    ao2_lock(qe->parent);
03373    manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
03374       "Queue: %s\r\n"
03375       "Uniqueid: %s\r\n"
03376       "Position: %d\r\n"
03377       "OriginalPosition: %d\r\n"
03378       "HoldTime: %d\r\n",
03379       qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
03380 
03381    qe->parent->callsabandoned++;
03382    ao2_unlock(qe->parent);
03383 }
03384 
03385 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
03386 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
03387 {
03388    ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
03389 
03390    /* Stop ringing, and resume MOH if specified */
03391    if (qe->ring_when_ringing) {
03392       ast_indicate(qe->chan, -1);
03393       ast_moh_start(qe->chan, qe->moh, NULL);
03394    }
03395 
03396    if (qe->parent->eventwhencalled) {
03397       char vars[2048];
03398 
03399       manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
03400                   "Queue: %s\r\n"
03401                   "Uniqueid: %s\r\n"
03402                   "Channel: %s\r\n"
03403                   "Member: %s\r\n"
03404                   "MemberName: %s\r\n"
03405                   "Ringtime: %d\r\n"
03406                   "%s",
03407                   qe->parent->name,
03408                   qe->chan->uniqueid,
03409                   qe->chan->name,
03410                   interface,
03411                   membername,
03412                   rnatime,
03413                   qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03414    }
03415    ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
03416    if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && pause) {
03417       if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
03418          if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
03419             ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
03420                interface, qe->parent->name);
03421          } else {
03422             ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
03423          }
03424       } else {
03425          /* If queue autopause is mode all, just don't send any queue to stop.
03426          * the function will stop in all queues */
03427          if (!set_member_paused("", interface, "Auto-Pause", 1)) {
03428             ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
03429                   interface, qe->parent->name);
03430          } else {
03431                ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
03432          }
03433       }
03434    }
03435    return;
03436 }
03437 
03438 #define AST_MAX_WATCHERS 256
03439 /*!
03440  * \brief Wait for a member to answer the call
03441  *
03442  * \param[in] qe the queue_ent corresponding to the caller in the queue
03443  * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
03444  * \param[in] to the amount of time (in milliseconds) to wait for a response
03445  * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
03446  * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
03447  * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
03448  * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
03449  *
03450  * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
03451  */
03452 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
03453 {
03454    const char *queue = qe->parent->name;
03455    struct callattempt *o, *start = NULL, *prev = NULL;
03456    int status;
03457    int numbusies = prebusies;
03458    int numnochan = 0;
03459    int stillgoing = 0;
03460    int orig = *to;
03461    struct ast_frame *f;
03462    struct callattempt *peer = NULL;
03463    struct ast_channel *winner;
03464    struct ast_channel *in = qe->chan;
03465    char on[80] = "";
03466    char membername[80] = "";
03467    long starttime = 0;
03468    long endtime = 0;
03469 #ifdef HAVE_EPOLL
03470    struct callattempt *epollo;
03471 #endif
03472    struct ast_party_connected_line connected_caller;
03473    char *inchan_name;
03474 
03475    ast_party_connected_line_init(&connected_caller);
03476 
03477    ast_channel_lock(qe->chan);
03478    inchan_name = ast_strdupa(qe->chan->name);
03479    ast_channel_unlock(qe->chan);
03480 
03481    starttime = (long) time(NULL);
03482 #ifdef HAVE_EPOLL
03483    for (epollo = outgoing; epollo; epollo = epollo->q_next) {
03484       if (epollo->chan)
03485          ast_poll_channel_add(in, epollo->chan);
03486    }
03487 #endif
03488    
03489    while (*to && !peer) {
03490       int numlines, retry, pos = 1;
03491       struct ast_channel *watchers[AST_MAX_WATCHERS];
03492       watchers[0] = in;
03493       start = NULL;
03494 
03495       for (retry = 0; retry < 2; retry++) {
03496          numlines = 0;
03497          for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
03498             if (o->stillgoing) { /* Keep track of important channels */
03499                stillgoing = 1;
03500                if (o->chan) {
03501                   if (pos < AST_MAX_WATCHERS) {
03502                      watchers[pos++] = o->chan;
03503                   }
03504                   if (!start)
03505                      start = o;
03506                   else
03507                      prev->call_next = o;
03508                   prev = o;
03509                }
03510             }
03511             numlines++;
03512          }
03513          if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
03514             (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
03515             break;
03516          /* On "ringall" strategy we only move to the next penalty level
03517             when *all* ringing phones are done in the current penalty level */
03518          ring_one(qe, outgoing, &numbusies);
03519          /* and retry... */
03520       }
03521       if (pos == 1 /* not found */) {
03522          if (numlines == (numbusies + numnochan)) {
03523             ast_debug(1, "Everyone is busy at this time\n");
03524          } else {
03525             ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
03526          }
03527          *to = 0;
03528          return NULL;
03529       }
03530 
03531       /* Poll for events from both the incoming channel as well as any outgoing channels */
03532       winner = ast_waitfor_n(watchers, pos, to);
03533 
03534       /* Service all of the outgoing channels */
03535       for (o = start; o; o = o->call_next) {
03536          /* We go with a fixed buffer here instead of using ast_strdupa. Using
03537           * ast_strdupa in a loop like this one can cause a stack overflow
03538           */
03539          char ochan_name[AST_CHANNEL_NAME];
03540 
03541          if (o->chan) {
03542             ast_channel_lock(o->chan);
03543             ast_copy_string(ochan_name, o->chan->name, sizeof(ochan_name));
03544             ast_channel_unlock(o->chan);
03545          }
03546          if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
03547             if (!peer) {
03548                ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
03549                if (!o->block_connected_update) {
03550                   if (o->pending_connected_update) {
03551                      if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
03552                         ast_channel_update_connected_line(in, &o->connected, NULL);
03553                      }
03554                   } else if (!o->dial_callerid_absent) {
03555                      ast_channel_lock(o->chan);
03556                      ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
03557                      ast_channel_unlock(o->chan);
03558                      connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
03559                      if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
03560                         ast_channel_update_connected_line(in, &connected_caller, NULL);
03561                      }
03562                      ast_party_connected_line_free(&connected_caller);
03563                   }
03564                }
03565                if (o->aoc_s_rate_list) {
03566                   size_t encoded_size;
03567                   struct ast_aoc_encoded *encoded;
03568                   if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03569                      ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03570                      ast_aoc_destroy_encoded(encoded);
03571                   }
03572                }
03573                peer = o;
03574             }
03575          } else if (o->chan && (o->chan == winner)) {
03576 
03577             ast_copy_string(on, o->member->interface, sizeof(on));
03578             ast_copy_string(membername, o->member->membername, sizeof(membername));
03579 
03580             /* Before processing channel, go ahead and check for forwarding */
03581             if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
03582                ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
03583                numnochan++;
03584                do_hang(o);
03585                winner = NULL;
03586                continue;
03587             } else if (!ast_strlen_zero(o->chan->call_forward)) {
03588                struct ast_channel *original = o->chan;
03589                char tmpchan[256];
03590                char *stuff;
03591                char *tech;
03592 
03593                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
03594                if ((stuff = strchr(tmpchan, '/'))) {
03595                   *stuff++ = '\0';
03596                   tech = tmpchan;
03597                } else {
03598                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
03599                   stuff = tmpchan;
03600                   tech = "Local";
03601                }
03602                if (!strcasecmp(tech, "Local")) {
03603                   /*
03604                    * Drop the connected line update block for local channels since
03605                    * this is going to run dialplan and the user can change his
03606                    * mind about what connected line information he wants to send.
03607                    */
03608                   o->block_connected_update = 0;
03609                }
03610 
03611                ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
03612 
03613                ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
03614                /* Setup parameters */
03615                o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
03616                if (!o->chan) {
03617                   ast_log(LOG_NOTICE,
03618                      "Forwarding failed to create channel to dial '%s/%s'\n",
03619                      tech, stuff);
03620                   o->stillgoing = 0;
03621                   numnochan++;
03622                } else {
03623                   ast_channel_lock_both(o->chan, original);
03624                   ast_party_redirecting_copy(&o->chan->redirecting, &original->redirecting);
03625                   ast_channel_unlock(o->chan);
03626                   ast_channel_unlock(original);
03627 
03628                   ast_channel_lock_both(o->chan, in);
03629                   ast_channel_inherit_variables(in, o->chan);
03630                   ast_channel_datastore_inherit(in, o->chan);
03631 
03632                   if (o->pending_connected_update) {
03633                      /*
03634                       * Re-seed the callattempt's connected line information with
03635                       * previously acquired connected line info from the queued
03636                       * channel.  The previously acquired connected line info could
03637                       * have been set through the CONNECTED_LINE dialplan function.
03638                       */
03639                      o->pending_connected_update = 0;
03640                      ast_party_connected_line_copy(&o->connected, &in->connected);
03641                   }
03642 
03643                   ast_string_field_set(o->chan, accountcode, in->accountcode);
03644 
03645                   if (!o->chan->redirecting.from.number.valid
03646                      || ast_strlen_zero(o->chan->redirecting.from.number.str)) {
03647                      /*
03648                       * The call was not previously redirected so it is
03649                       * now redirected from this number.
03650                       */
03651                      ast_party_number_free(&o->chan->redirecting.from.number);
03652                      ast_party_number_init(&o->chan->redirecting.from.number);
03653                      o->chan->redirecting.from.number.valid = 1;
03654                      o->chan->redirecting.from.number.str =
03655                         ast_strdup(S_OR(in->macroexten, in->exten));
03656                   }
03657 
03658                   o->chan->dialed.transit_network_select = in->dialed.transit_network_select;
03659 
03660                   o->dial_callerid_absent = !o->chan->caller.id.number.valid
03661                      || ast_strlen_zero(o->chan->caller.id.number.str);
03662                   ast_connected_line_copy_from_caller(&o->chan->connected, &in->caller);
03663 
03664                   ast_channel_unlock(in);
03665                   if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL
03666                      && !o->block_connected_update) {
03667                      struct ast_party_redirecting redirecting;
03668 
03669                      /*
03670                       * Redirecting updates to the caller make sense only on single
03671                       * call at a time strategies.
03672                       *
03673                       * We must unlock o->chan before calling
03674                       * ast_channel_redirecting_macro, because we put o->chan into
03675                       * autoservice there.  That is pretty much a guaranteed
03676                       * deadlock.  This is why the handling of o->chan's lock may
03677                       * seem a bit unusual here.
03678                       */
03679                      ast_party_redirecting_init(&redirecting);
03680                      ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
03681                      ast_channel_unlock(o->chan);
03682                      if (ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
03683                         ast_channel_update_redirecting(in, &redirecting, NULL);
03684                      }
03685                      ast_party_redirecting_free(&redirecting);
03686                   } else {
03687                      ast_channel_unlock(o->chan);
03688                   }
03689 
03690                   if (ast_call(o->chan, stuff, 0)) {
03691                      ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
03692                         tech, stuff);
03693                      do_hang(o);
03694                      numnochan++;
03695                   }
03696                }
03697                /* Hangup the original channel now, in case we needed it */
03698                ast_hangup(winner);
03699                continue;
03700             }
03701             f = ast_read(winner);
03702             if (f) {
03703                if (f->frametype == AST_FRAME_CONTROL) {
03704                   switch (f->subclass.integer) {
03705                   case AST_CONTROL_ANSWER:
03706                      /* This is our guy if someone answered. */
03707                      if (!peer) {
03708                         ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
03709                         if (!o->block_connected_update) {
03710                            if (o->pending_connected_update) {
03711                               if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
03712                                  ast_channel_update_connected_line(in, &o->connected, NULL);
03713                               }
03714                            } else if (!o->dial_callerid_absent) {
03715                               ast_channel_lock(o->chan);
03716                               ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
03717                               ast_channel_unlock(o->chan);
03718                               connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
03719                               if (ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
03720                                  ast_channel_update_connected_line(in, &connected_caller, NULL);
03721                               }
03722                               ast_party_connected_line_free(&connected_caller);
03723                            }
03724                         }
03725                         if (o->aoc_s_rate_list) {
03726                            size_t encoded_size;
03727                            struct ast_aoc_encoded *encoded;
03728                            if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03729                               ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03730                               ast_aoc_destroy_encoded(encoded);
03731                            }
03732                         }
03733                         peer = o;
03734                      }
03735                      break;
03736                   case AST_CONTROL_BUSY:
03737                      ast_verb(3, "%s is busy\n", ochan_name);
03738                      if (in->cdr)
03739                         ast_cdr_busy(in->cdr);
03740                      do_hang(o);
03741                      endtime = (long) time(NULL);
03742                      endtime -= starttime;
03743                      rna(endtime * 1000, qe, on, membername, 0);
03744                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03745                         if (qe->parent->timeoutrestart)
03746                            *to = orig;
03747                         /* Have enough time for a queue member to answer? */
03748                         if (*to > 500) {
03749                            ring_one(qe, outgoing, &numbusies);
03750                            starttime = (long) time(NULL);
03751                         }
03752                      }
03753                      numbusies++;
03754                      break;
03755                   case AST_CONTROL_CONGESTION:
03756                      ast_verb(3, "%s is circuit-busy\n", ochan_name);
03757                      if (in->cdr)
03758                         ast_cdr_busy(in->cdr);
03759                      endtime = (long) time(NULL);
03760                      endtime -= starttime;
03761                      rna(endtime * 1000, qe, on, membername, 0);
03762                      do_hang(o);
03763                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03764                         if (qe->parent->timeoutrestart)
03765                            *to = orig;
03766                         if (*to > 500) {
03767                            ring_one(qe, outgoing, &numbusies);
03768                            starttime = (long) time(NULL);
03769                         }
03770                      }
03771                      numbusies++;
03772                      break;
03773                   case AST_CONTROL_RINGING:
03774                      ast_verb(3, "%s is ringing\n", ochan_name);
03775 
03776                      /* Start ring indication when the channel is ringing, if specified */
03777                      if (qe->ring_when_ringing) {
03778                         ast_moh_stop(qe->chan);
03779                         ast_indicate(qe->chan, AST_CONTROL_RINGING);
03780                      }
03781                      break;
03782                   case AST_CONTROL_OFFHOOK:
03783                      /* Ignore going off hook */
03784                      break;
03785                   case AST_CONTROL_CONNECTED_LINE:
03786                      if (o->block_connected_update) {
03787                         ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
03788                         break;
03789                      }
03790                      if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03791                         struct ast_party_connected_line connected;
03792 
03793                         ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
03794                         ast_party_connected_line_set_init(&connected, &o->connected);
03795                         ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
03796                         ast_party_connected_line_set(&o->connected, &connected, NULL);
03797                         ast_party_connected_line_free(&connected);
03798                         o->pending_connected_update = 1;
03799                         break;
03800                      }
03801 
03802                      /*
03803                       * Prevent using the CallerID from the outgoing channel since we
03804                       * got a connected line update from it.
03805                       */
03806                      o->dial_callerid_absent = 1;
03807 
03808                      if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
03809                         ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
03810                      }
03811                      break;
03812                   case AST_CONTROL_AOC:
03813                      {
03814                         struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
03815                         if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
03816                            ast_aoc_destroy_decoded(o->aoc_s_rate_list);
03817                            o->aoc_s_rate_list = decoded;
03818                         } else {
03819                            ast_aoc_destroy_decoded(decoded);
03820                         }
03821                      }
03822                      break;
03823                   case AST_CONTROL_REDIRECTING:
03824                      if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03825                         /*
03826                          * Redirecting updates to the caller make sense only on single
03827                          * call at a time strategies.
03828                          */
03829                         break;
03830                      }
03831                      if (o->block_connected_update) {
03832                         ast_verb(3, "Redirecting update to %s prevented\n",
03833                            inchan_name);
03834                         break;
03835                      }
03836                      ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
03837                         ochan_name, inchan_name);
03838                      if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
03839                         ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
03840                      }
03841                      break;
03842                   default:
03843                      ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
03844                      break;
03845                   }
03846                }
03847                ast_frfree(f);
03848             } else { /* ast_read() returned NULL */
03849                endtime = (long) time(NULL) - starttime;
03850                rna(endtime * 1000, qe, on, membername, 1);
03851                do_hang(o);
03852                if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03853                   if (qe->parent->timeoutrestart)
03854                      *to = orig;
03855                   if (*to > 500) {
03856                      ring_one(qe, outgoing, &numbusies);
03857                      starttime = (long) time(NULL);
03858                   }
03859                }
03860             }
03861          }
03862       }
03863 
03864       /* If we received an event from the caller, deal with it. */
03865       if (winner == in) {
03866          f = ast_read(in);
03867          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
03868             /* Got hung up */
03869             *to = -1;
03870             if (f) {
03871                if (f->data.uint32) {
03872                   in->hangupcause = f->data.uint32;
03873                }
03874                ast_frfree(f);
03875             }
03876             return NULL;
03877          }
03878 
03879          /*!
03880           * \todo
03881           * XXX Queue like Dial really should send any connected line
03882           * updates (AST_CONTROL_CONNECTED_LINE) from the caller to each
03883           * ringing queue member.
03884           */
03885 
03886          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
03887             ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
03888             *to = 0;
03889             ast_frfree(f);
03890             return NULL;
03891          }
03892          if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
03893             ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
03894             *to = 0;
03895             *digit = f->subclass.integer;
03896             ast_frfree(f);
03897             return NULL;
03898          }
03899          ast_frfree(f);
03900       }
03901       if (!*to) {
03902          for (o = start; o; o = o->call_next)
03903             rna(orig, qe, o->interface, o->member->membername, 1);
03904       }
03905    }
03906 
03907 #ifdef HAVE_EPOLL
03908    for (epollo = outgoing; epollo; epollo = epollo->q_next) {
03909       if (epollo->chan)
03910          ast_poll_channel_del(in, epollo->chan);
03911    }
03912 #endif
03913 
03914    return peer;
03915 }
03916 
03917 /*! 
03918  * \brief Check if we should start attempting to call queue members.
03919  *
03920  * A simple process, really. Count the number of members who are available
03921  * to take our call and then see if we are in a position in the queue at
03922  * which a member could accept our call.
03923  *
03924  * \param[in] qe The caller who wants to know if it is his turn
03925  * \retval 0 It is not our turn
03926  * \retval 1 It is our turn
03927  */
03928 static int is_our_turn(struct queue_ent *qe)
03929 {
03930    struct queue_ent *ch;
03931    int res;
03932    int avl;
03933    int idx = 0;
03934    /* This needs a lock. How many members are available to be served? */
03935    ao2_lock(qe->parent);
03936 
03937    avl = num_available_members(qe->parent);
03938 
03939    ch = qe->parent->head;
03940 
03941    ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
03942 
03943    while ((idx < avl) && (ch) && (ch != qe)) {
03944       if (!ch->pending)
03945          idx++;
03946       ch = ch->next;       
03947    }
03948 
03949    ao2_unlock(qe->parent);
03950    /* If the queue entry is within avl [the number of available members] calls from the top ... 
03951     * Autofill and position check added to support autofill=no (as only calls
03952     * from the front of the queue are valid when autofill is disabled)
03953     */
03954    if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
03955       ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
03956       res = 1;
03957    } else {
03958       ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
03959       res = 0;
03960    }
03961 
03962    return res;
03963 }
03964 
03965 /*!
03966  * \brief update rules for queues
03967  *
03968  * Calculate min/max penalties making sure if relative they stay within bounds.
03969  * Update queues penalty and set dialplan vars, goto next list entry.
03970 */
03971 static void update_qe_rule(struct queue_ent *qe)
03972 {
03973    int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
03974    int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
03975    char max_penalty_str[20], min_penalty_str[20]; 
03976    /* a relative change to the penalty could put it below 0 */
03977    if (max_penalty < 0)
03978       max_penalty = 0;
03979    if (min_penalty < 0)
03980       min_penalty = 0;
03981    if (min_penalty > max_penalty)
03982       min_penalty = max_penalty;
03983    snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
03984    snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
03985    pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
03986    pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
03987    qe->max_penalty = max_penalty;
03988    qe->min_penalty = min_penalty;
03989    ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, qe->chan->name, qe->pr->time);
03990    qe->pr = AST_LIST_NEXT(qe->pr, list);
03991 }
03992 
03993 /*! \brief The waiting areas for callers who are not actively calling members
03994  *
03995  * This function is one large loop. This function will return if a caller
03996  * either exits the queue or it becomes that caller's turn to attempt calling
03997  * queue members. Inside the loop, we service the caller with periodic announcements,
03998  * holdtime announcements, etc. as configured in queues.conf
03999  *
04000  * \retval  0 if the caller's turn has arrived
04001  * \retval -1 if the caller should exit the queue.
04002  */
04003 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
04004 {
04005    int res = 0;
04006 
04007    /* This is the holding pen for callers 2 through maxlen */
04008    for (;;) {
04009 
04010       if (is_our_turn(qe))
04011          break;
04012 
04013       /* If we have timed out, break out */
04014       if (qe->expire && (time(NULL) >= qe->expire)) {
04015          *reason = QUEUE_TIMEOUT;
04016          break;
04017       }
04018 
04019       if (qe->parent->leavewhenempty) {
04020          int status = 0;
04021 
04022          if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) {
04023             *reason = QUEUE_LEAVEEMPTY;
04024             ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
04025             leave_queue(qe);
04026             break;
04027          }
04028       }
04029 
04030       /* Make a position announcement, if enabled */
04031       if (qe->parent->announcefrequency &&
04032          (res = say_position(qe,ringing)))
04033          break;
04034 
04035       /* If we have timed out, break out */
04036       if (qe->expire && (time(NULL) >= qe->expire)) {
04037          *reason = QUEUE_TIMEOUT;
04038          break;
04039       }
04040 
04041       /* Make a periodic announcement, if enabled */
04042       if (qe->parent->periodicannouncefrequency &&
04043          (res = say_periodic_announcement(qe,ringing)))
04044          break;
04045       
04046       /* see if we need to move to the next penalty level for this queue */
04047       while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
04048          update_qe_rule(qe);
04049       }
04050 
04051       /* If we have timed out, break out */
04052       if (qe->expire && (time(NULL) >= qe->expire)) {
04053          *reason = QUEUE_TIMEOUT;
04054          break;
04055       }
04056       
04057       /* Wait a second before checking again */
04058       if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
04059          if (res > 0 && !valid_exit(qe, res))
04060             res = 0;
04061          else
04062             break;
04063       }
04064       
04065       /* If we have timed out, break out */
04066       if (qe->expire && (time(NULL) >= qe->expire)) {
04067          *reason = QUEUE_TIMEOUT;
04068          break;
04069       }
04070    }
04071 
04072    return res;
04073 }
04074 
04075 /*!
04076  * \brief update the queue status
04077  * \retval Always 0
04078 */
04079 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
04080 {
04081    int oldtalktime;
04082 
04083    struct member *mem;
04084    struct call_queue *qtmp;
04085    struct ao2_iterator queue_iter;  
04086    
04087    if (shared_lastcall) {
04088       queue_iter = ao2_iterator_init(queues, 0);
04089       while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
04090          ao2_lock(qtmp);
04091          if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
04092             time(&mem->lastcall);
04093             mem->calls++;
04094             mem->lastqueue = q;
04095             ao2_ref(mem, -1);
04096          }
04097          ao2_unlock(qtmp);
04098          queue_t_unref(qtmp, "Done with iterator");
04099       }
04100       ao2_iterator_destroy(&queue_iter);
04101    } else {
04102       ao2_lock(q);
04103       time(&member->lastcall);
04104       member->calls++;
04105       member->lastqueue = q;
04106       ao2_unlock(q);
04107    }  
04108    ao2_lock(q);
04109    q->callscompleted++;
04110    if (callcompletedinsl)
04111       q->callscompletedinsl++;
04112    /* Calculate talktime using the same exponential average as holdtime code*/
04113    oldtalktime = q->talktime;
04114    q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
04115    ao2_unlock(q);
04116    return 0;
04117 }
04118 
04119 /*! \brief Calculate the metric of each member in the outgoing callattempts
04120  *
04121  * A numeric metric is given to each member depending on the ring strategy used
04122  * by the queue. Members with lower metrics will be called before members with
04123  * higher metrics
04124  * \retval -1 if penalties are exceeded
04125  * \retval 0 otherwise
04126  */
04127 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
04128 {
04129    /* disregarding penalty on too few members? */
04130    int membercount = ao2_container_count(q->members);
04131    unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
04132 
04133    if (usepenalty) {
04134       if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) ||
04135          (qe->min_penalty && (mem->penalty < qe->min_penalty))) {
04136          return -1;
04137       }
04138    } else {
04139       ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
04140            membercount, q->penaltymemberslimit);
04141    }
04142 
04143    switch (q->strategy) {
04144    case QUEUE_STRATEGY_RINGALL:
04145       /* Everyone equal, except for penalty */
04146       tmp->metric = mem->penalty * 1000000 * usepenalty;
04147       break;
04148    case QUEUE_STRATEGY_LINEAR:
04149       if (pos < qe->linpos) {
04150          tmp->metric = 1000 + pos;
04151       } else {
04152          if (pos > qe->linpos)
04153             /* Indicate there is another priority */
04154             qe->linwrapped = 1;
04155          tmp->metric = pos;
04156       }
04157       tmp->metric += mem->penalty * 1000000 * usepenalty;
04158       break;
04159    case QUEUE_STRATEGY_RRORDERED:
04160    case QUEUE_STRATEGY_RRMEMORY:
04161       if (pos < q->rrpos) {
04162          tmp->metric = 1000 + pos;
04163       } else {
04164          if (pos > q->rrpos)
04165             /* Indicate there is another priority */
04166             q->wrapped = 1;
04167          tmp->metric = pos;
04168       }
04169       tmp->metric += mem->penalty * 1000000 * usepenalty;
04170       break;
04171    case QUEUE_STRATEGY_RANDOM:
04172       tmp->metric = ast_random() % 1000;
04173       tmp->metric += mem->penalty * 1000000 * usepenalty;
04174       break;
04175    case QUEUE_STRATEGY_WRANDOM:
04176       tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
04177       break;
04178    case QUEUE_STRATEGY_FEWESTCALLS:
04179       tmp->metric = mem->calls;
04180       tmp->metric += mem->penalty * 1000000 * usepenalty;
04181       break;
04182    case QUEUE_STRATEGY_LEASTRECENT:
04183       if (!mem->lastcall)
04184          tmp->metric = 0;
04185       else
04186          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
04187       tmp->metric += mem->penalty * 1000000 * usepenalty;
04188       break;
04189    default:
04190       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
04191       break;
04192    }
04193    return 0;
04194 }
04195 
04196 enum agent_complete_reason {
04197    CALLER,
04198    AGENT,
04199    TRANSFER
04200 };
04201 
04202 /*! \brief Send out AMI message with member call completion status information */
04203 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
04204    const struct ast_channel *peer, const struct member *member, time_t callstart,
04205    char *vars, size_t vars_len, enum agent_complete_reason rsn)
04206 {
04207    const char *reason = NULL; /* silence dumb compilers */
04208 
04209    if (!qe->parent->eventwhencalled)
04210       return;
04211 
04212    switch (rsn) {
04213    case CALLER:
04214       reason = "caller";
04215       break;
04216    case AGENT:
04217       reason = "agent";
04218       break;
04219    case TRANSFER:
04220       reason = "transfer";
04221       break;
04222    }
04223 
04224    manager_event(EVENT_FLAG_AGENT, "AgentComplete",
04225       "Queue: %s\r\n"
04226       "Uniqueid: %s\r\n"
04227       "Channel: %s\r\n"
04228       "Member: %s\r\n"
04229       "MemberName: %s\r\n"
04230       "HoldTime: %ld\r\n"
04231       "TalkTime: %ld\r\n"
04232       "Reason: %s\r\n"
04233       "%s",
04234       queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04235       (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
04236       qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
04237 }
04238 
04239 struct queue_transfer_ds {
04240    struct queue_ent *qe;
04241    struct member *member;
04242    time_t starttime;
04243    int callcompletedinsl;
04244 };
04245 
04246 static void queue_transfer_destroy(void *data)
04247 {
04248    struct queue_transfer_ds *qtds = data;
04249    ast_free(qtds);
04250 }
04251 
04252 /*! \brief a datastore used to help correctly log attended transfers of queue callers
04253  */
04254 static const struct ast_datastore_info queue_transfer_info = {
04255    .type = "queue_transfer",
04256    .chan_fixup = queue_transfer_fixup,
04257    .destroy = queue_transfer_destroy,
04258 };
04259 
04260 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
04261  *
04262  * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
04263  * the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
04264  * to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
04265  *
04266  * At the end of this, we want to remove the datastore so that this fixup function is not called on any
04267  * future masquerades of the caller during the current call.
04268  */
04269 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
04270 {
04271    struct queue_transfer_ds *qtds = data;
04272    struct queue_ent *qe = qtds->qe;
04273    struct member *member = qtds->member;
04274    time_t callstart = qtds->starttime;
04275    int callcompletedinsl = qtds->callcompletedinsl;
04276    struct ast_datastore *datastore;
04277 
04278    ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
04279             new_chan->exten, new_chan->context, (long) (callstart - qe->start),
04280             (long) (time(NULL) - callstart), qe->opos);
04281 
04282    update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
04283    
04284    /* No need to lock the channels because they are already locked in ast_do_masquerade */
04285    if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
04286       ast_channel_datastore_remove(old_chan, datastore);
04287    } else {
04288       ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
04289    }
04290 }
04291 
04292 /*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
04293  *
04294  * When a caller is atxferred, then the queue_transfer_info datastore
04295  * is removed from the channel. If it's still there after the bridge is
04296  * broken, then the caller was not atxferred.
04297  *
04298  * \note Only call this with chan locked
04299  */
04300 static int attended_transfer_occurred(struct ast_channel *chan)
04301 {
04302    return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
04303 }
04304 
04305 /*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
04306  */
04307 static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
04308 {
04309    struct ast_datastore *ds;
04310    struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
04311 
04312    if (!qtds) {
04313       ast_log(LOG_WARNING, "Memory allocation error!\n");
04314       return NULL;
04315    }
04316 
04317    ast_channel_lock(qe->chan);
04318    if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
04319       ast_channel_unlock(qe->chan);
04320       ast_free(qtds);
04321       ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
04322       return NULL;
04323    }
04324 
04325    qtds->qe = qe;
04326    /* This member is refcounted in try_calling, so no need to add it here, too */
04327    qtds->member = member;
04328    qtds->starttime = starttime;
04329    qtds->callcompletedinsl = callcompletedinsl;
04330    ds->data = qtds;
04331    ast_channel_datastore_add(qe->chan, ds);
04332    ast_channel_unlock(qe->chan);
04333    return ds;
04334 }
04335 
04336 struct queue_end_bridge {
04337    struct call_queue *q;
04338    struct ast_channel *chan;
04339 };
04340 
04341 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
04342 {
04343    struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
04344    ao2_ref(qeb, +1);
04345    qeb->chan = originator;
04346 }
04347 
04348 static void end_bridge_callback(void *data)
04349 {
04350    struct queue_end_bridge *qeb = data;
04351    struct call_queue *q = qeb->q;
04352    struct ast_channel *chan = qeb->chan;
04353 
04354    if (ao2_ref(qeb, -1) == 1) {
04355       set_queue_variables(q, chan);
04356       /* This unrefs the reference we made in try_calling when we allocated qeb */
04357       queue_t_unref(q, "Expire bridge_config reference");
04358    }
04359 }
04360 
04361 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
04362  * 
04363  * Here is the process of this function
04364  * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
04365  * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
04366  *    iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
04367  *    member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
04368  *    during each iteration, we call calc_metric to determine which members should be rung when.
04369  * 3. Call ring_one to place a call to the appropriate member(s)
04370  * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
04371  * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
04372  * 6. Start the monitor or mixmonitor if the option is set
04373  * 7. Remove the caller from the queue to allow other callers to advance
04374  * 8. Bridge the call.
04375  * 9. Do any post processing after the call has disconnected.
04376  *
04377  * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
04378  * \param[in] options the options passed as the third parameter to the Queue() application
04379  * \param[in] announceoverride filename to play to user when waiting 
04380  * \param[in] url the url passed as the fourth parameter to the Queue() application
04381  * \param[in,out] tries the number of times we have tried calling queue members
04382  * \param[out] noption set if the call to Queue() has the 'n' option set.
04383  * \param[in] agi the agi passed as the fifth parameter to the Queue() application
04384  * \param[in] macro the macro passed as the sixth parameter to the Queue() application
04385  * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
04386  * \param[in] ringing 1 if the 'r' option is set, otherwise 0
04387  */
04388 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
04389 {
04390    struct member *cur;
04391    struct callattempt *outgoing = NULL; /* the list of calls we are building */
04392    int to, orig;
04393    char oldexten[AST_MAX_EXTENSION]="";
04394    char oldcontext[AST_MAX_CONTEXT]="";
04395    char queuename[256]="";
04396    char interfacevar[256]="";
04397    struct ast_channel *peer;
04398    struct ast_channel *which;
04399    struct callattempt *lpeer;
04400    struct member *member;
04401    struct ast_app *application;
04402    int res = 0, bridge = 0;
04403    int numbusies = 0;
04404    int x=0;
04405    char *announce = NULL;
04406    char digit = 0;
04407    time_t callstart;
04408    time_t now = time(NULL);
04409    struct ast_bridge_config bridge_config;
04410    char nondataquality = 1;
04411    char *agiexec = NULL;
04412    char *macroexec = NULL;
04413    char *gosubexec = NULL;
04414    const char *monitorfilename;
04415    const char *monitor_exec;
04416    const char *monitor_options;
04417    char tmpid[256], tmpid2[256];
04418    char meid[1024], meid2[1024];
04419    char mixmonargs[1512];
04420    struct ast_app *mixmonapp = NULL;
04421    char *p;
04422    char vars[2048];
04423    int forwardsallowed = 1;
04424    int block_connected_line = 0;
04425    int callcompletedinsl;
04426    struct ao2_iterator memi;
04427    struct ast_datastore *datastore, *transfer_ds;
04428    struct queue_end_bridge *queue_end_bridge = NULL;
04429 
04430    ast_channel_lock(qe->chan);
04431    datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
04432    ast_channel_unlock(qe->chan);
04433 
04434    memset(&bridge_config, 0, sizeof(bridge_config));
04435    tmpid[0] = 0;
04436    meid[0] = 0;
04437    time(&now);
04438 
04439    /* If we've already exceeded our timeout, then just stop
04440     * This should be extremely rare. queue_exec will take care
04441     * of removing the caller and reporting the timeout as the reason.
04442     */
04443    if (qe->expire && now >= qe->expire) {
04444       res = 0;
04445       goto out;
04446    }
04447       
04448    for (; options && *options; options++)
04449       switch (*options) {
04450       case 't':
04451          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
04452          break;
04453       case 'T':
04454          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
04455          break;
04456       case 'w':
04457          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
04458          break;
04459       case 'W':
04460          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
04461          break;
04462       case 'c':
04463          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
04464          break;
04465       case 'd':
04466          nondataquality = 0;
04467          break;
04468       case 'h':
04469          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
04470          break;
04471       case 'H':
04472          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
04473          break;
04474       case 'k':
04475          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
04476          break;
04477       case 'K':
04478          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
04479          break;
04480       case 'n':
04481          if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED)
04482             (*tries)++;
04483          else
04484             *tries = ao2_container_count(qe->parent->members);
04485          *noption = 1;
04486          break;
04487       case 'i':
04488          forwardsallowed = 0;
04489          break;
04490       case 'I':
04491          block_connected_line = 1;
04492          break;
04493       case 'x':
04494          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
04495          break;
04496       case 'X':
04497          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
04498          break;
04499       case 'C':
04500          qe->cancel_answered_elsewhere = 1;
04501          break;
04502       }
04503 
04504    /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 
04505       (this is mainly to support chan_local)
04506    */
04507    if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) {
04508       qe->cancel_answered_elsewhere = 1;
04509    }
04510 
04511    ao2_lock(qe->parent);
04512    ast_debug(1, "%s is trying to call a queue member.\n",
04513                      qe->chan->name);
04514    ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
04515    if (!ast_strlen_zero(qe->announce))
04516       announce = qe->announce;
04517    if (!ast_strlen_zero(announceoverride))
04518       announce = announceoverride;
04519 
04520    memi = ao2_iterator_init(qe->parent->members, 0);
04521    while ((cur = ao2_iterator_next(&memi))) {
04522       struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
04523       struct ast_dialed_interface *di;
04524       AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
04525       if (!tmp) {
04526          ao2_ref(cur, -1);
04527          ao2_iterator_destroy(&memi);
04528          ao2_unlock(qe->parent);
04529          goto out;
04530       }
04531       if (!datastore) {
04532          if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
04533             callattempt_free(tmp);
04534             ao2_ref(cur, -1);
04535             ao2_iterator_destroy(&memi);
04536             ao2_unlock(qe->parent);
04537             goto out;
04538          }
04539          datastore->inheritance = DATASTORE_INHERIT_FOREVER;
04540          if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
04541             callattempt_free(tmp);
04542             ao2_ref(cur, -1);
04543             ao2_iterator_destroy(&memi);
04544             ao2_unlock(qe->parent);
04545             goto out;
04546          }
04547          datastore->data = dialed_interfaces;
04548          AST_LIST_HEAD_INIT(dialed_interfaces);
04549 
04550          ast_channel_lock(qe->chan);
04551          ast_channel_datastore_add(qe->chan, datastore);
04552          ast_channel_unlock(qe->chan);
04553       } else
04554          dialed_interfaces = datastore->data;
04555 
04556       AST_LIST_LOCK(dialed_interfaces);
04557       AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
04558          if (!strcasecmp(cur->interface, di->interface)) {
04559             ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 
04560                di->interface);
04561             break;
04562          }
04563       }
04564       AST_LIST_UNLOCK(dialed_interfaces);
04565 
04566       if (di) {
04567          callattempt_free(tmp);
04568          ao2_ref(cur, -1);
04569          continue;
04570       }
04571 
04572       /* It is always ok to dial a Local interface.  We only keep track of
04573        * which "real" interfaces have been dialed.  The Local channel will
04574        * inherit this list so that if it ends up dialing a real interface,
04575        * it won't call one that has already been called. */
04576       if (strncasecmp(cur->interface, "Local/", 6)) {
04577          if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
04578             callattempt_free(tmp);
04579             ao2_ref(cur, -1);
04580             ao2_iterator_destroy(&memi);
04581             ao2_unlock(qe->parent);
04582             goto out;
04583          }
04584          strcpy(di->interface, cur->interface);
04585 
04586          AST_LIST_LOCK(dialed_interfaces);
04587          AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
04588          AST_LIST_UNLOCK(dialed_interfaces);
04589       }
04590 
04591       /*
04592        * Seed the callattempt's connected line information with previously
04593        * acquired connected line info from the queued channel.  The
04594        * previously acquired connected line info could have been set
04595        * through the CONNECTED_LINE dialplan function.
04596        */
04597       ast_channel_lock(qe->chan);
04598       ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
04599       ast_channel_unlock(qe->chan);
04600 
04601       tmp->block_connected_update = block_connected_line;
04602       tmp->stillgoing = 1;
04603       tmp->member = cur;/* Place the reference for cur into callattempt. */
04604       tmp->lastcall = cur->lastcall;
04605       tmp->lastqueue = cur->lastqueue;
04606       ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
04607       /* Special case: If we ring everyone, go ahead and ring them, otherwise
04608          just calculate their metric for the appropriate strategy */
04609       if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
04610          /* Put them in the list of outgoing thingies...  We're ready now.
04611             XXX If we're forcibly removed, these outgoing calls won't get
04612             hung up XXX */
04613          tmp->q_next = outgoing;
04614          outgoing = tmp;      
04615          /* If this line is up, don't try anybody else */
04616          if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
04617             break;
04618       } else {
04619          callattempt_free(tmp);
04620       }
04621    }
04622    ao2_iterator_destroy(&memi);
04623 
04624    if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
04625       /* Application arguments have higher timeout priority (behaviour for <=1.6) */
04626       if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
04627          to = (qe->expire - now) * 1000;
04628       else
04629          to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
04630    } else {
04631       /* Config timeout is higher priority thatn application timeout */
04632       if (qe->expire && qe->expire<=now) {
04633          to = 0;
04634       } else if (qe->parent->timeout) {
04635          to = qe->parent->timeout * 1000;
04636       } else {
04637          to = -1;
04638       }
04639    }
04640    orig = to;
04641    ++qe->pending;
04642    ao2_unlock(qe->parent);
04643    ring_one(qe, outgoing, &numbusies);
04644    lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
04645       ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
04646       forwardsallowed);
04647    /* The ast_channel_datastore_remove() function could fail here if the
04648     * datastore was moved to another channel during a masquerade. If this is
04649     * the case, don't free the datastore here because later, when the channel
04650     * to which the datastore was moved hangs up, it will attempt to free this
04651     * datastore again, causing a crash
04652     */
04653    ast_channel_lock(qe->chan);
04654    if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
04655       ast_datastore_free(datastore);
04656    }
04657    ast_channel_unlock(qe->chan);
04658    ao2_lock(qe->parent);
04659    if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
04660       store_next_rr(qe, outgoing);
04661 
04662    }
04663    if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
04664       store_next_lin(qe, outgoing);
04665    }
04666    ao2_unlock(qe->parent);
04667    peer = lpeer ? lpeer->chan : NULL;
04668    if (!peer) {
04669       qe->pending = 0;
04670       if (to) {
04671          /* Must gotten hung up */
04672          res = -1;
04673       } else {
04674          /* User exited by pressing a digit */
04675          res = digit;
04676       }
04677       if (res == -1)
04678          ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
04679       if (ast_cdr_isset_unanswered()) {
04680          /* channel contains the name of one of the outgoing channels
04681             in its CDR; zero out this CDR to avoid a dual-posting */
04682          struct callattempt *o;
04683          for (o = outgoing; o; o = o->q_next) {
04684             if (!o->chan) {
04685                continue;
04686             }
04687             if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) {
04688                ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED);
04689                break;
04690             }
04691          }
04692       }
04693    } else { /* peer is valid */
04694       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
04695          we will always return with -1 so that it is hung up properly after the
04696          conversation.  */
04697       if (!strcmp(qe->chan->tech->type, "DAHDI"))
04698          ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04699       if (!strcmp(peer->tech->type, "DAHDI"))
04700          ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04701       /* Update parameters for the queue */
04702       time(&now);
04703       recalc_holdtime(qe, (now - qe->start));
04704       ao2_lock(qe->parent);
04705       callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
04706       ao2_unlock(qe->parent);
04707       member = lpeer->member;
04708       /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
04709       ao2_ref(member, 1);
04710       hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
04711       outgoing = NULL;
04712       if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
04713          int res2;
04714 
04715          res2 = ast_autoservice_start(qe->chan);
04716          if (!res2) {
04717             if (qe->parent->memberdelay) {
04718                ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
04719                res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
04720             }
04721             if (!res2 && announce) {
04722                if (play_file(peer, announce) < 0) {
04723                   ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name);
04724                }
04725             }
04726             if (!res2 && qe->parent->reportholdtime) {
04727                if (!play_file(peer, qe->parent->sound_reporthold)) {
04728                   int holdtime, holdtimesecs;
04729 
04730                   time(&now);
04731                   holdtime = abs((now - qe->start) / 60);
04732                   holdtimesecs = abs((now - qe->start) % 60);
04733                   if (holdtime > 0) {
04734                      ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
04735                      if (play_file(peer, qe->parent->sound_minutes) < 0) {
04736                         ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name);
04737                      }
04738                   }
04739                   if (holdtimesecs > 1) {
04740                      ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
04741                      if (play_file(peer, qe->parent->sound_seconds) < 0) {
04742                         ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name);
04743                      }
04744                   }
04745                }
04746             }
04747             ast_autoservice_stop(qe->chan);
04748          }
04749          if (ast_check_hangup(peer)) {
04750             /* Agent must have hung up */
04751             ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
04752             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
04753             if (qe->parent->eventwhencalled)
04754                manager_event(EVENT_FLAG_AGENT, "AgentDump",
04755                      "Queue: %s\r\n"
04756                      "Uniqueid: %s\r\n"
04757                      "Channel: %s\r\n"
04758                      "Member: %s\r\n"
04759                      "MemberName: %s\r\n"
04760                      "%s",
04761                      queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04762                      qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
04763             ast_hangup(peer);
04764             ao2_ref(member, -1);
04765             goto out;
04766          } else if (ast_check_hangup(qe->chan)) {
04767             /* Caller must have hung up just before being connected */
04768             ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
04769             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
04770             record_abandoned(qe);
04771             ast_hangup(peer);
04772             ao2_ref(member, -1);
04773             return -1;
04774          }
04775       }
04776       /* Stop music on hold */
04777       if (ringing)
04778          ast_indicate(qe->chan,-1);
04779       else
04780          ast_moh_stop(qe->chan);
04781       /* If appropriate, log that we have a destination channel */
04782       if (qe->chan->cdr)
04783          ast_cdr_setdestchan(qe->chan->cdr, peer->name);
04784       /* Make sure channels are compatible */
04785       res = ast_channel_make_compatible(qe->chan, peer);
04786       if (res < 0) {
04787          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
04788          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
04789          record_abandoned(qe);
04790          ast_cdr_failed(qe->chan->cdr);
04791          ast_hangup(peer);
04792          ao2_ref(member, -1);
04793          return -1;
04794       }
04795 
04796       /* Play announcement to the caller telling it's his turn if defined */
04797       if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
04798          if (play_file(qe->chan, qe->parent->sound_callerannounce))
04799             ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
04800       }
04801 
04802       ao2_lock(qe->parent);
04803       /* if setinterfacevar is defined, make member variables available to the channel */
04804       /* use  pbx_builtin_setvar to set a load of variables with one call */
04805       if (qe->parent->setinterfacevar) {
04806          snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
04807             member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
04808          pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04809          pbx_builtin_setvar_multiple(peer, interfacevar);
04810       }
04811       
04812       /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
04813       /* use  pbx_builtin_setvar to set a load of variables with one call */
04814       if (qe->parent->setqueueentryvar) {
04815          snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
04816             (long) time(NULL) - qe->start, qe->opos);
04817          pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04818          pbx_builtin_setvar_multiple(peer, interfacevar);
04819       }
04820    
04821       ao2_unlock(qe->parent);
04822 
04823       /* try to set queue variables if configured to do so*/
04824       set_queue_variables(qe->parent, qe->chan);
04825       set_queue_variables(qe->parent, peer);
04826       
04827       ast_channel_lock(qe->chan);
04828       if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
04829             monitorfilename = ast_strdupa(monitorfilename);
04830       }
04831       ast_channel_unlock(qe->chan);
04832       /* Begin Monitoring */
04833       if (qe->parent->monfmt && *qe->parent->monfmt) {
04834          if (!qe->parent->montype) {
04835             const char *monexec;
04836             ast_debug(1, "Starting Monitor as requested.\n");
04837             ast_channel_lock(qe->chan);
04838             if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
04839                which = qe->chan;
04840                monexec = monexec ? ast_strdupa(monexec) : NULL;
04841             }
04842             else
04843                which = peer;
04844             ast_channel_unlock(qe->chan);
04845             if (monitorfilename) {
04846                ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
04847             } else if (qe->chan->cdr) {
04848                ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
04849             } else {
04850                /* Last ditch effort -- no CDR, make up something */
04851                snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04852                ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
04853             }
04854             if (!ast_strlen_zero(monexec)) {
04855                ast_monitor_setjoinfiles(which, 1);
04856             }
04857          } else {
04858             mixmonapp = pbx_findapp("MixMonitor");
04859             
04860             if (mixmonapp) {
04861                ast_debug(1, "Starting MixMonitor as requested.\n");
04862                if (!monitorfilename) {
04863                   if (qe->chan->cdr)
04864                      ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
04865                   else
04866                      snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04867                } else {
04868                   const char *m = monitorfilename;
04869                   for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
04870                      switch (*m) {
04871                      case '^':
04872                         if (*(m + 1) == '{')
04873                            *p = '$';
04874                         break;
04875                      case ',':
04876                         *p++ = '\\';
04877                         /* Fall through */
04878                      default:
04879                         *p = *m;
04880                      }
04881                      if (*m == '\0')
04882                         break;
04883                   }
04884                   if (p == tmpid2 + sizeof(tmpid2))
04885                      tmpid2[sizeof(tmpid2) - 1] = '\0';
04886 
04887                   pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
04888                }
04889 
04890                ast_channel_lock(qe->chan);
04891                if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
04892                      monitor_exec = ast_strdupa(monitor_exec);
04893                }
04894                if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
04895                      monitor_options = ast_strdupa(monitor_options);
04896                } else {
04897                   monitor_options = "";
04898                }
04899                ast_channel_unlock(qe->chan);
04900 
04901                if (monitor_exec) {
04902                   const char *m = monitor_exec;
04903                   for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
04904                      switch (*m) {
04905                      case '^':
04906                         if (*(m + 1) == '{')
04907                            *p = '$';
04908                         break;
04909                      case ',':
04910                         *p++ = '\\';
04911                         /* Fall through */
04912                      default:
04913                         *p = *m;
04914                      }
04915                      if (*m == '\0')
04916                         break;
04917                   }
04918                   if (p == meid2 + sizeof(meid2))
04919                      meid2[sizeof(meid2) - 1] = '\0';
04920 
04921                   pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
04922                }
04923    
04924                snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
04925 
04926                if (!ast_strlen_zero(monitor_exec))
04927                   snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
04928                else
04929                   snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
04930                
04931                ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
04932                /* We purposely lock the CDR so that pbx_exec does not update the application data */
04933                if (qe->chan->cdr)
04934                   ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04935                pbx_exec(qe->chan, mixmonapp, mixmonargs);
04936                if (qe->chan->cdr)
04937                   ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04938 
04939             } else {
04940                ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
04941             }
04942          }
04943       }
04944       /* Drop out of the queue at this point, to prepare for next caller */
04945       leave_queue(qe);        
04946       if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
04947          ast_debug(1, "app_queue: sendurl=%s.\n", url);
04948          ast_channel_sendurl(peer, url);
04949       }
04950       
04951       /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
04952       /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
04953       if (!ast_strlen_zero(macro)) {
04954             macroexec = ast_strdupa(macro);
04955       } else {
04956          if (qe->parent->membermacro)
04957             macroexec = ast_strdupa(qe->parent->membermacro);
04958       }
04959 
04960       if (!ast_strlen_zero(macroexec)) {
04961          ast_debug(1, "app_queue: macro=%s.\n", macroexec);
04962          
04963          res = ast_autoservice_start(qe->chan);
04964          if (res) {
04965             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
04966             res = -1;
04967          }
04968          
04969          application = pbx_findapp("Macro");
04970 
04971          if (application) {
04972             res = pbx_exec(peer, application, macroexec);
04973             ast_debug(1, "Macro exited with status %d\n", res);
04974             res = 0;
04975          } else {
04976             ast_log(LOG_ERROR, "Could not find application Macro\n");
04977             res = -1;
04978          }
04979 
04980          if (ast_autoservice_stop(qe->chan) < 0) {
04981             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
04982             res = -1;
04983          }
04984       }
04985 
04986       /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
04987       /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
04988       if (!ast_strlen_zero(gosub)) {
04989             gosubexec = ast_strdupa(gosub);
04990       } else {
04991          if (qe->parent->membergosub)
04992             gosubexec = ast_strdupa(qe->parent->membergosub);
04993       }
04994 
04995       if (!ast_strlen_zero(gosubexec)) {
04996          ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
04997          
04998          res = ast_autoservice_start(qe->chan);
04999          if (res) {
05000             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
05001             res = -1;
05002          }
05003          
05004          application = pbx_findapp("Gosub");
05005          
05006          if (application) {
05007             char *gosub_args, *gosub_argstart;
05008 
05009             /* Set where we came from */
05010             ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context));
05011             ast_copy_string(peer->exten, "s", sizeof(peer->exten));
05012             peer->priority = 0;
05013 
05014             gosub_argstart = strchr(gosubexec, ',');
05015             if (gosub_argstart) {
05016                const char *what_is_s = "s";
05017                *gosub_argstart = 0;
05018                if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
05019                    ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
05020                   what_is_s = "~~s~~";
05021                }
05022                if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
05023                   gosub_args = NULL;
05024                }
05025                *gosub_argstart = ',';
05026             } else {
05027                const char *what_is_s = "s";
05028                if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
05029                    ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
05030                   what_is_s = "~~s~~";
05031                }
05032                if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
05033                   gosub_args = NULL;
05034                }
05035             }
05036             if (gosub_args) {
05037                res = pbx_exec(peer, application, gosub_args);
05038                if (!res) {
05039                   struct ast_pbx_args args;
05040                   memset(&args, 0, sizeof(args));
05041                   args.no_hangup_chan = 1;
05042                   ast_pbx_run_args(peer, &args);
05043                }
05044                ast_free(gosub_args);
05045                ast_debug(1, "Gosub exited with status %d\n", res);
05046             } else {
05047                ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
05048             }
05049          } else {
05050             ast_log(LOG_ERROR, "Could not find application Gosub\n");
05051             res = -1;
05052          }
05053       
05054          if (ast_autoservice_stop(qe->chan) < 0) {
05055             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
05056             res = -1;
05057          }
05058       }
05059 
05060       if (!ast_strlen_zero(agi)) {
05061          ast_debug(1, "app_queue: agi=%s.\n", agi);
05062          application = pbx_findapp("agi");
05063          if (application) {
05064             agiexec = ast_strdupa(agi);
05065             pbx_exec(qe->chan, application, agiexec);
05066          } else
05067             ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
05068       }
05069       qe->handled++;
05070       ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
05071                                        (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
05072 
05073       if (qe->chan->cdr) {
05074          struct ast_cdr *cdr;
05075          struct ast_cdr *newcdr;
05076 
05077          /* Only work with the last CDR in the stack*/
05078          cdr = qe->chan->cdr;
05079          while (cdr->next) {
05080             cdr = cdr->next;
05081          }
05082 
05083          /* If this CDR is not related to us add new one*/
05084          if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) &&
05085              (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) &&
05086              (newcdr = ast_cdr_dup(cdr))) {
05087             ast_channel_lock(qe->chan);
05088             ast_cdr_init(newcdr, qe->chan);
05089             ast_cdr_reset(newcdr, 0);
05090             cdr = ast_cdr_append(cdr, newcdr);
05091             cdr = cdr->next;
05092             ast_channel_unlock(qe->chan);
05093          }
05094 
05095          if (update_cdr) {
05096             ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
05097          }
05098       }
05099 
05100       if (qe->parent->eventwhencalled)
05101          manager_event(EVENT_FLAG_AGENT, "AgentConnect",
05102                "Queue: %s\r\n"
05103                "Uniqueid: %s\r\n"
05104                "Channel: %s\r\n"
05105                "Member: %s\r\n"
05106                "MemberName: %s\r\n"
05107                "Holdtime: %ld\r\n"
05108                "BridgedChannel: %s\r\n"
05109                "Ringtime: %ld\r\n"
05110                "%s",
05111                queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
05112                (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
05113                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
05114       ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
05115       ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
05116    
05117       if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
05118          queue_end_bridge->q = qe->parent;
05119          queue_end_bridge->chan = qe->chan;
05120          bridge_config.end_bridge_callback = end_bridge_callback;
05121          bridge_config.end_bridge_callback_data = queue_end_bridge;
05122          bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
05123          /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
05124           * to make sure to increase the refcount of this queue so it cannot be freed until we
05125           * are done with it. We remove this reference in end_bridge_callback.
05126           */
05127          queue_t_ref(qe->parent, "For bridge_config reference");
05128       }
05129 
05130       time(&callstart);
05131       transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
05132       bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
05133 
05134       /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
05135        * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for
05136        * the AgentComplete manager event
05137        */
05138       ast_channel_lock(qe->chan);
05139       if (!attended_transfer_occurred(qe->chan)) {
05140          struct ast_datastore *tds;
05141 
05142          /* detect a blind transfer */
05143          if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) {
05144             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
05145                qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
05146                (long) (time(NULL) - callstart), qe->opos);
05147             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
05148          } else if (ast_check_hangup(qe->chan)) {
05149             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
05150                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05151             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
05152          } else {
05153             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
05154                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05155             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
05156          }
05157          if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {  
05158             ast_channel_datastore_remove(qe->chan, tds);
05159          }
05160          ast_channel_unlock(qe->chan);
05161          update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
05162       } else {
05163          ast_channel_unlock(qe->chan);
05164 
05165          /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
05166          send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
05167       }
05168 
05169       if (transfer_ds) {
05170          ast_datastore_free(transfer_ds);
05171       }
05172       ast_hangup(peer);
05173       res = bridge ? bridge : 1;
05174       ao2_ref(member, -1);
05175    }
05176 out:
05177    hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
05178 
05179    return res;
05180 }
05181 
05182 static int wait_a_bit(struct queue_ent *qe)
05183 {
05184    /* Don't need to hold the lock while we setup the outgoing calls */
05185    int retrywait = qe->parent->retry * 1000;
05186 
05187    int res = ast_waitfordigit(qe->chan, retrywait);
05188    if (res > 0 && !valid_exit(qe, res))
05189       res = 0;
05190 
05191    return res;
05192 }
05193 
05194 static struct member *interface_exists(struct call_queue *q, const char *interface)
05195 {
05196    struct member *mem;
05197    struct ao2_iterator mem_iter;
05198 
05199    if (!q)
05200       return NULL;
05201 
05202    mem_iter = ao2_iterator_init(q->members, 0);
05203    while ((mem = ao2_iterator_next(&mem_iter))) {
05204       if (!strcasecmp(interface, mem->interface)) {
05205          ao2_iterator_destroy(&mem_iter);
05206          return mem;
05207       }
05208       ao2_ref(mem, -1);
05209    }
05210    ao2_iterator_destroy(&mem_iter);
05211 
05212    return NULL;
05213 }
05214 
05215 
05216 /*! \brief Dump all members in a specific queue to the database
05217  *
05218  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
05219  */
05220 static void dump_queue_members(struct call_queue *pm_queue)
05221 {
05222    struct member *cur_member;
05223    struct ast_str *value;
05224    struct ao2_iterator mem_iter;
05225 
05226    if (!pm_queue) {
05227       return;
05228    }
05229 
05230    /* 4K is a reasonable default for most applications, but we grow to
05231     * accommodate more if necessary. */
05232    if (!(value = ast_str_create(4096))) {
05233       return;
05234    }
05235 
05236    mem_iter = ao2_iterator_init(pm_queue->members, 0);
05237    while ((cur_member = ao2_iterator_next(&mem_iter))) {
05238       if (!cur_member->dynamic) {
05239          ao2_ref(cur_member, -1);
05240          continue;
05241       }
05242 
05243       ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s",
05244          ast_str_strlen(value) ? "|" : "",
05245          cur_member->interface,
05246          cur_member->penalty,
05247          cur_member->paused,
05248          cur_member->membername,
05249          cur_member->state_interface);
05250 
05251       ao2_ref(cur_member, -1);
05252    }
05253    ao2_iterator_destroy(&mem_iter);
05254 
05255    if (ast_str_strlen(value) && !cur_member) {
05256       if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value)))
05257          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
05258    } else {
05259       /* Delete the entry if the queue is empty or there is an error */
05260       ast_db_del(pm_family, pm_queue->name);
05261    }
05262 
05263    ast_free(value);
05264 }
05265 
05266 /*! \brief Remove member from queue 
05267  * \retval RES_NOT_DYNAMIC when they aren't a RT member
05268  * \retval RES_NOSUCHQUEUE queue does not exist
05269  * \retval RES_OKAY removed member from queue
05270  * \retval RES_EXISTS queue exists but no members
05271 */
05272 static int remove_from_queue(const char *queuename, const char *interface)
05273 {
05274    struct call_queue *q, tmpq = {
05275       .name = queuename,   
05276    };
05277    struct member *mem, tmpmem;
05278    int res = RES_NOSUCHQUEUE;
05279 
05280    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
05281    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
05282       ao2_lock(q);
05283       if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
05284          /* XXX future changes should beware of this assumption!! */
05285          if (!mem->dynamic) {
05286             ao2_ref(mem, -1);
05287             ao2_unlock(q);
05288             queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
05289             return RES_NOT_DYNAMIC;
05290          }
05291          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
05292             "Queue: %s\r\n"
05293             "Location: %s\r\n"
05294             "MemberName: %s\r\n",
05295             q->name, mem->interface, mem->membername);
05296          ao2_unlink(q->members, mem);
05297          ao2_ref(mem, -1);
05298 
05299          if (queue_persistent_members)
05300             dump_queue_members(q);
05301          
05302          res = RES_OKAY;
05303       } else {
05304          res = RES_EXISTS;
05305       }
05306       ao2_unlock(q);
05307       queue_t_unref(q, "Expiring temporary reference");
05308    }
05309 
05310    return res;
05311 }
05312 
05313 /*! \brief Add member to queue 
05314  * \retval RES_NOT_DYNAMIC when they aren't a RT member
05315  * \retval RES_NOSUCHQUEUE queue does not exist
05316  * \retval RES_OKAY added member from queue
05317  * \retval RES_EXISTS queue exists but no members
05318  * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
05319 */
05320 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
05321 {
05322    struct call_queue *q;
05323    struct member *new_member, *old_member;
05324    int res = RES_NOSUCHQUEUE;
05325 
05326    /*! \note Ensure the appropriate realtime queue is loaded.  Note that this
05327     * short-circuits if the queue is already in memory. */
05328    if (!(q = load_realtime_queue(queuename)))
05329       return res;
05330 
05331    ao2_lock(q);
05332    if ((old_member = interface_exists(q, interface)) == NULL) {
05333       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
05334          new_member->dynamic = 1;
05335          ao2_link(q->members, new_member);
05336          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
05337             "Queue: %s\r\n"
05338             "Location: %s\r\n"
05339             "MemberName: %s\r\n"
05340             "Membership: %s\r\n"
05341             "Penalty: %d\r\n"
05342             "CallsTaken: %d\r\n"
05343             "LastCall: %d\r\n"
05344             "Status: %d\r\n"
05345             "Paused: %d\r\n",
05346             q->name, new_member->interface, new_member->membername,
05347             "dynamic",
05348             new_member->penalty, new_member->calls, (int) new_member->lastcall,
05349             new_member->status, new_member->paused);
05350          
05351          ao2_ref(new_member, -1);
05352          new_member = NULL;
05353 
05354          if (dump)
05355             dump_queue_members(q);
05356          
05357          res = RES_OKAY;
05358       } else {
05359          res = RES_OUTOFMEMORY;
05360       }
05361    } else {
05362       ao2_ref(old_member, -1);
05363       res = RES_EXISTS;
05364    }
05365    ao2_unlock(q);
05366    queue_t_unref(q, "Expiring temporary reference");
05367 
05368    return res;
05369 }
05370 
05371 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
05372 {
05373    int found = 0;
05374    struct call_queue *q;
05375    struct member *mem;
05376    struct ao2_iterator queue_iter;
05377    int failed;
05378 
05379    /* Special event for when all queues are paused - individual events still generated */
05380    /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
05381    if (ast_strlen_zero(queuename))
05382       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
05383 
05384    queue_iter = ao2_iterator_init(queues, 0);
05385    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
05386       ao2_lock(q);
05387       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05388          if ((mem = interface_exists(q, interface))) {
05389             if (mem->paused == paused) {
05390                ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
05391             }
05392 
05393             failed = 0;
05394             if (mem->realtime) {
05395                failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
05396             }
05397          
05398             if (failed) {
05399                ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
05400                ao2_ref(mem, -1);
05401                ao2_unlock(q);
05402                queue_t_unref(q, "Done with iterator");
05403                continue;
05404             }  
05405             found++;
05406             mem->paused = paused;
05407 
05408             if (queue_persistent_members)
05409                dump_queue_members(q);
05410 
05411             ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
05412             
05413             if (!ast_strlen_zero(reason)) {
05414                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05415                   "Queue: %s\r\n"
05416                   "Location: %s\r\n"
05417                   "MemberName: %s\r\n"
05418                   "Paused: %d\r\n"
05419                   "Reason: %s\r\n",
05420                      q->name, mem->interface, mem->membername, paused, reason);
05421             } else {
05422                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05423                   "Queue: %s\r\n"
05424                   "Location: %s\r\n"
05425                   "MemberName: %s\r\n"
05426                   "Paused: %d\r\n",
05427                      q->name, mem->interface, mem->membername, paused);
05428             }
05429             ao2_ref(mem, -1);
05430          }
05431       }
05432       
05433       if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
05434          ao2_unlock(q);
05435          queue_t_unref(q, "Done with iterator");
05436          break;
05437       }
05438       
05439       ao2_unlock(q);
05440       queue_t_unref(q, "Done with iterator");
05441    }
05442    ao2_iterator_destroy(&queue_iter);
05443 
05444    return found ? RESULT_SUCCESS : RESULT_FAILURE;
05445 }
05446 
05447 /* \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. */
05448 static int set_member_penalty(const char *queuename, const char *interface, int penalty)
05449 {
05450    int foundinterface = 0, foundqueue = 0;
05451    struct call_queue *q;
05452    struct member *mem;
05453    struct ao2_iterator queue_iter;
05454 
05455    if (penalty < 0) {
05456       ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
05457       return RESULT_FAILURE;
05458    }
05459 
05460    queue_iter = ao2_iterator_init(queues, 0);
05461    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
05462       ao2_lock(q);
05463       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05464          foundqueue++;
05465          if ((mem = interface_exists(q, interface))) {
05466             foundinterface++;
05467             mem->penalty = penalty;
05468             
05469             ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
05470             manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
05471                "Queue: %s\r\n"
05472                "Location: %s\r\n"
05473                "Penalty: %d\r\n",
05474                q->name, mem->interface, penalty);
05475             ao2_ref(mem, -1);
05476          }
05477       }
05478       ao2_unlock(q);
05479       queue_t_unref(q, "Done with iterator");
05480    }
05481    ao2_iterator_destroy(&queue_iter);
05482 
05483    if (foundinterface) {
05484       return RESULT_SUCCESS;
05485    } else if (!foundqueue) {
05486       ast_log (LOG_ERROR, "Invalid queuename\n"); 
05487    } else {
05488       ast_log (LOG_ERROR, "Invalid interface\n");
05489    }  
05490 
05491    return RESULT_FAILURE;
05492 }
05493 
05494 /* \brief Gets members penalty. 
05495  * \return Return the members penalty or RESULT_FAILURE on error. 
05496 */
05497 static int get_member_penalty(char *queuename, char *interface)
05498 {
05499    int foundqueue = 0, penalty;
05500    struct call_queue *q, tmpq = {
05501       .name = queuename,   
05502    };
05503    struct member *mem;
05504    
05505    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
05506       foundqueue = 1;
05507       ao2_lock(q);
05508       if ((mem = interface_exists(q, interface))) {
05509          penalty = mem->penalty;
05510          ao2_ref(mem, -1);
05511          ao2_unlock(q);
05512          queue_t_unref(q, "Search complete");
05513          return penalty;
05514       }
05515       ao2_unlock(q);
05516       queue_t_unref(q, "Search complete");
05517    }
05518 
05519    /* some useful debuging */
05520    if (foundqueue) 
05521       ast_log (LOG_ERROR, "Invalid queuename\n");
05522    else 
05523       ast_log (LOG_ERROR, "Invalid interface\n");
05524 
05525    return RESULT_FAILURE;
05526 }
05527 
05528 /*! \brief Reload dynamic queue members persisted into the astdb */
05529 static void reload_queue_members(void)
05530 {
05531    char *cur_ptr;
05532    const char *queue_name;
05533    char *member;
05534    char *interface;
05535    char *membername = NULL;
05536    char *state_interface;
05537    char *penalty_tok;
05538    int penalty = 0;
05539    char *paused_tok;
05540    int paused = 0;
05541    struct ast_db_entry *db_tree;
05542    struct ast_db_entry *entry;
05543    struct call_queue *cur_queue;
05544    char *queue_data;
05545 
05546    /* Each key in 'pm_family' is the name of a queue */
05547    db_tree = ast_db_gettree(pm_family, NULL);
05548    for (entry = db_tree; entry; entry = entry->next) {
05549 
05550       queue_name = entry->key + strlen(pm_family) + 2;
05551 
05552       {
05553          struct call_queue tmpq = {
05554             .name = queue_name,
05555          };
05556          cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
05557       }  
05558 
05559       if (!cur_queue)
05560          cur_queue = load_realtime_queue(queue_name);
05561 
05562       if (!cur_queue) {
05563          /* If the queue no longer exists, remove it from the
05564           * database */
05565          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
05566          ast_db_del(pm_family, queue_name);
05567          continue;
05568       } 
05569 
05570       if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
05571          queue_t_unref(cur_queue, "Expire reload reference");
05572          continue;
05573       }
05574 
05575       cur_ptr = queue_data;
05576       while ((member = strsep(&cur_ptr, ",|"))) {
05577          if (ast_strlen_zero(member))
05578             continue;
05579 
05580          interface = strsep(&member, ";");
05581          penalty_tok = strsep(&member, ";");
05582          paused_tok = strsep(&member, ";");
05583          membername = strsep(&member, ";");
05584          state_interface = strsep(&member, ";");
05585 
05586          if (!penalty_tok) {
05587             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
05588             break;
05589          }
05590          penalty = strtol(penalty_tok, NULL, 10);
05591          if (errno == ERANGE) {
05592             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
05593             break;
05594          }
05595          
05596          if (!paused_tok) {
05597             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
05598             break;
05599          }
05600          paused = strtol(paused_tok, NULL, 10);
05601          if ((errno == ERANGE) || paused < 0 || paused > 1) {
05602             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
05603             break;
05604          }
05605 
05606          ast_debug(1, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
05607          
05608          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
05609             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
05610             break;
05611          }
05612       }
05613       queue_t_unref(cur_queue, "Expire reload reference");
05614       ast_free(queue_data);
05615    }
05616 
05617    if (db_tree) {
05618       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
05619       ast_db_freetree(db_tree);
05620    }
05621 }
05622 
05623 /*! \brief PauseQueueMember application */
05624 static int pqm_exec(struct ast_channel *chan, const char *data)
05625 {
05626    char *parse;
05627    AST_DECLARE_APP_ARGS(args,
05628       AST_APP_ARG(queuename);
05629       AST_APP_ARG(interface);
05630       AST_APP_ARG(options);
05631       AST_APP_ARG(reason);
05632    );
05633 
05634    if (ast_strlen_zero(data)) {
05635       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
05636       return -1;
05637    }
05638 
05639    parse = ast_strdupa(data);
05640 
05641    AST_STANDARD_APP_ARGS(args, parse);
05642 
05643    if (ast_strlen_zero(args.interface)) {
05644       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05645       return -1;
05646    }
05647 
05648    if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
05649       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
05650       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
05651       return 0;
05652    }
05653 
05654    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
05655 
05656    return 0;
05657 }
05658 
05659 /*! \brief UnPauseQueueMember application */
05660 static int upqm_exec(struct ast_channel *chan, const char *data)
05661 {
05662    char *parse;
05663    AST_DECLARE_APP_ARGS(args,
05664       AST_APP_ARG(queuename);
05665       AST_APP_ARG(interface);
05666       AST_APP_ARG(options);
05667       AST_APP_ARG(reason);
05668    );
05669 
05670    if (ast_strlen_zero(data)) {
05671       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
05672       return -1;
05673    }
05674 
05675    parse = ast_strdupa(data);
05676 
05677    AST_STANDARD_APP_ARGS(args, parse);
05678 
05679    if (ast_strlen_zero(args.interface)) {
05680       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05681       return -1;
05682    }
05683 
05684    if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
05685       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
05686       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
05687       return 0;
05688    }
05689 
05690    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
05691 
05692    return 0;
05693 }
05694 
05695 /*! \brief RemoveQueueMember application */
05696 static int rqm_exec(struct ast_channel *chan, const char *data)
05697 {
05698    int res=-1;
05699    char *parse, *temppos = NULL;
05700    AST_DECLARE_APP_ARGS(args,
05701       AST_APP_ARG(queuename);
05702       AST_APP_ARG(interface);
05703    );
05704 
05705 
05706    if (ast_strlen_zero(data)) {
05707       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
05708       return -1;
05709    }
05710 
05711    parse = ast_strdupa(data);
05712 
05713    AST_STANDARD_APP_ARGS(args, parse);
05714 
05715    if (ast_strlen_zero(args.interface)) {
05716       args.interface = ast_strdupa(chan->name);
05717       temppos = strrchr(args.interface, '-');
05718       if (temppos)
05719          *temppos = '\0';
05720    }
05721 
05722    ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
05723 
05724    switch (remove_from_queue(args.queuename, args.interface)) {
05725    case RES_OKAY:
05726       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
05727       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
05728       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
05729       res = 0;
05730       break;
05731    case RES_EXISTS:
05732       ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
05733       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
05734       res = 0;
05735       break;
05736    case RES_NOSUCHQUEUE:
05737       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
05738       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
05739       res = 0;
05740       break;
05741    case RES_NOT_DYNAMIC:
05742       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
05743       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
05744       res = 0;
05745       break;
05746    }
05747 
05748    return res;
05749 }
05750 
05751 /*! \brief AddQueueMember application */
05752 static int aqm_exec(struct ast_channel *chan, const char *data)
05753 {
05754    int res=-1;
05755    char *parse, *temppos = NULL;
05756    AST_DECLARE_APP_ARGS(args,
05757       AST_APP_ARG(queuename);
05758       AST_APP_ARG(interface);
05759       AST_APP_ARG(penalty);
05760       AST_APP_ARG(options);
05761       AST_APP_ARG(membername);
05762       AST_APP_ARG(state_interface);
05763    );
05764    int penalty = 0;
05765 
05766    if (ast_strlen_zero(data)) {
05767       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
05768       return -1;
05769    }
05770 
05771    parse = ast_strdupa(data);
05772 
05773    AST_STANDARD_APP_ARGS(args, parse);
05774 
05775    if (ast_strlen_zero(args.interface)) {
05776       args.interface = ast_strdupa(chan->name);
05777       temppos = strrchr(args.interface, '-');
05778       if (temppos)
05779          *temppos = '\0';
05780    }
05781 
05782    if (!ast_strlen_zero(args.penalty)) {
05783       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
05784          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
05785          penalty = 0;
05786       }
05787    }
05788 
05789    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
05790    case RES_OKAY:
05791       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
05792       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
05793       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
05794       res = 0;
05795       break;
05796    case RES_EXISTS:
05797       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
05798       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
05799       res = 0;
05800       break;
05801    case RES_NOSUCHQUEUE:
05802       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
05803       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
05804       res = 0;
05805       break;
05806    case RES_OUTOFMEMORY:
05807       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
05808       break;
05809    }
05810 
05811    return res;
05812 }
05813 
05814 /*! \brief QueueLog application */
05815 static int ql_exec(struct ast_channel *chan, const char *data)
05816 {
05817    char *parse;
05818 
05819    AST_DECLARE_APP_ARGS(args,
05820       AST_APP_ARG(queuename);
05821       AST_APP_ARG(uniqueid);
05822       AST_APP_ARG(membername);
05823       AST_APP_ARG(event);
05824       AST_APP_ARG(params);
05825    );
05826 
05827    if (ast_strlen_zero(data)) {
05828       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
05829       return -1;
05830    }
05831 
05832    parse = ast_strdupa(data);
05833 
05834    AST_STANDARD_APP_ARGS(args, parse);
05835 
05836    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
05837        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
05838       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
05839       return -1;
05840    }
05841 
05842    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
05843       "%s", args.params ? args.params : "");
05844 
05845    return 0;
05846 }
05847 
05848 /*! \brief Copy rule from global list into specified queue */
05849 static void copy_rules(struct queue_ent *qe, const char *rulename)
05850 {
05851    struct penalty_rule *pr_iter;
05852    struct rule_list *rl_iter;
05853    const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
05854    AST_LIST_LOCK(&rule_lists);
05855    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
05856       if (!strcasecmp(rl_iter->name, tmp))
05857          break;
05858    }
05859    if (rl_iter) {
05860       AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
05861          struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
05862          if (!new_pr) {
05863             ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
05864             break;
05865          }
05866          new_pr->time = pr_iter->time;
05867          new_pr->max_value = pr_iter->max_value;
05868          new_pr->min_value = pr_iter->min_value;
05869          new_pr->max_relative = pr_iter->max_relative;
05870          new_pr->min_relative = pr_iter->min_relative;
05871          AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
05872       }
05873    }
05874    AST_LIST_UNLOCK(&rule_lists);
05875 }
05876 
05877 /*!\brief The starting point for all queue calls
05878  *
05879  * The process involved here is to 
05880  * 1. Parse the options specified in the call to Queue()
05881  * 2. Join the queue
05882  * 3. Wait in a loop until it is our turn to try calling a queue member
05883  * 4. Attempt to call a queue member
05884  * 5. If 4. did not result in a bridged call, then check for between
05885  *    call options such as periodic announcements etc.
05886  * 6. Try 4 again unless some condition (such as an expiration time) causes us to 
05887  *    exit the queue.
05888  */
05889 static int queue_exec(struct ast_channel *chan, const char *data)
05890 {
05891    int res=-1;
05892    int ringing=0;
05893    const char *user_priority;
05894    const char *max_penalty_str;
05895    const char *min_penalty_str;
05896    int prio;
05897    int qcontinue = 0;
05898    int max_penalty, min_penalty;
05899    enum queue_result reason = QUEUE_UNKNOWN;
05900    /* whether to exit Queue application after the timeout hits */
05901    int tries = 0;
05902    int noption = 0;
05903    char *parse;
05904    int makeannouncement = 0;
05905    int position = 0;
05906    AST_DECLARE_APP_ARGS(args,
05907       AST_APP_ARG(queuename);
05908       AST_APP_ARG(options);
05909       AST_APP_ARG(url);
05910       AST_APP_ARG(announceoverride);
05911       AST_APP_ARG(queuetimeoutstr);
05912       AST_APP_ARG(agi);
05913       AST_APP_ARG(macro);
05914       AST_APP_ARG(gosub);
05915       AST_APP_ARG(rule);
05916       AST_APP_ARG(position);
05917    );
05918    /* Our queue entry */
05919    struct queue_ent qe = { 0 };
05920    
05921    if (ast_strlen_zero(data)) {
05922       ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
05923       return -1;
05924    }
05925    
05926    parse = ast_strdupa(data);
05927    AST_STANDARD_APP_ARGS(args, parse);
05928 
05929    /* Setup our queue entry */
05930    qe.start = time(NULL);
05931 
05932    /* set the expire time based on the supplied timeout; */
05933    if (!ast_strlen_zero(args.queuetimeoutstr))
05934       qe.expire = qe.start + atoi(args.queuetimeoutstr);
05935    else
05936       qe.expire = 0;
05937 
05938    /* Get the priority from the variable ${QUEUE_PRIO} */
05939    ast_channel_lock(chan);
05940    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
05941    if (user_priority) {
05942       if (sscanf(user_priority, "%30d", &prio) == 1) {
05943          ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
05944       } else {
05945          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
05946             user_priority, chan->name);
05947          prio = 0;
05948       }
05949    } else {
05950       ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
05951       prio = 0;
05952    }
05953 
05954    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
05955 
05956    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
05957       if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
05958          ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
05959       } else {
05960          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
05961             max_penalty_str, chan->name);
05962          max_penalty = 0;
05963       }
05964    } else {
05965       max_penalty = 0;
05966    }
05967 
05968    if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
05969       if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
05970          ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
05971       } else {
05972          ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
05973             min_penalty_str, chan->name);
05974          min_penalty = 0;
05975       }
05976    } else {
05977       min_penalty = 0;
05978    }
05979    ast_channel_unlock(chan);
05980 
05981    if (args.options && (strchr(args.options, 'r')))
05982       ringing = 1;
05983 
05984    if (ringing != 1 && args.options && (strchr(args.options, 'R'))) {
05985       qe.ring_when_ringing = 1;
05986    }
05987 
05988    if (args.options && (strchr(args.options, 'c')))
05989       qcontinue = 1;
05990 
05991    if (args.position) {
05992       position = atoi(args.position);
05993       if (position < 0) {
05994          ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
05995          position = 0;
05996       }
05997    }
05998 
05999    ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
06000       args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
06001 
06002    qe.chan = chan;
06003    qe.prio = prio;
06004    qe.max_penalty = max_penalty;
06005    qe.min_penalty = min_penalty;
06006    qe.last_pos_said = 0;
06007    qe.last_pos = 0;
06008    qe.last_periodic_announce_time = time(NULL);
06009    qe.last_periodic_announce_sound = 0;
06010    qe.valid_digits = 0;
06011    if (join_queue(args.queuename, &qe, &reason, position)) {
06012       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
06013       set_queue_result(chan, reason);
06014       return 0;
06015    }
06016    ast_assert(qe.parent != NULL);
06017 
06018    ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d",
06019       S_OR(args.url, ""),
06020       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
06021       qe.opos);
06022    copy_rules(&qe, args.rule);
06023    qe.pr = AST_LIST_FIRST(&qe.qe_rules);
06024 check_turns:
06025    if (ringing) {
06026       ast_indicate(chan, AST_CONTROL_RINGING);
06027    } else {
06028       ast_moh_start(chan, qe.moh, NULL);
06029    }
06030 
06031    /* This is the wait loop for callers 2 through maxlen */
06032    res = wait_our_turn(&qe, ringing, &reason);
06033    if (res) {
06034       goto stop;
06035    }
06036 
06037    makeannouncement = 0;
06038 
06039    for (;;) {
06040       /* This is the wait loop for the head caller*/
06041       /* To exit, they may get their call answered; */
06042       /* they may dial a digit from the queue context; */
06043       /* or, they may timeout. */
06044 
06045       /* Leave if we have exceeded our queuetimeout */
06046       if (qe.expire && (time(NULL) >= qe.expire)) {
06047          record_abandoned(&qe);
06048          reason = QUEUE_TIMEOUT;
06049          res = 0;
06050          ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 
06051             qe.pos, qe.opos, (long) time(NULL) - qe.start);
06052          break;
06053       }
06054 
06055       if (makeannouncement) {
06056          /* Make a position announcement, if enabled */
06057          if (qe.parent->announcefrequency)
06058             if ((res = say_position(&qe,ringing)))
06059                goto stop;
06060       }
06061       makeannouncement = 1;
06062 
06063       /* Make a periodic announcement, if enabled */
06064       if (qe.parent->periodicannouncefrequency)
06065          if ((res = say_periodic_announcement(&qe,ringing)))
06066             goto stop;
06067    
06068       /* Leave if we have exceeded our queuetimeout */
06069       if (qe.expire && (time(NULL) >= qe.expire)) {
06070          record_abandoned(&qe);
06071          reason = QUEUE_TIMEOUT;
06072          res = 0;
06073          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
06074          break;
06075       }
06076 
06077       /* see if we need to move to the next penalty level for this queue */
06078       while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
06079          update_qe_rule(&qe);
06080       }
06081 
06082       /* Try calling all queue members for 'timeout' seconds */
06083       res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
06084       if (res) {
06085          goto stop;
06086       }
06087 
06088       if (qe.parent->leavewhenempty) {
06089          int status = 0;
06090          if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) {
06091             record_abandoned(&qe);
06092             reason = QUEUE_LEAVEEMPTY;
06093             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
06094             res = 0;
06095             break;
06096          }
06097       }
06098 
06099       /* exit after 'timeout' cycle if 'n' option enabled */
06100       if (noption && tries >= ao2_container_count(qe.parent->members)) {
06101          ast_verb(3, "Exiting on time-out cycle\n");
06102          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
06103          record_abandoned(&qe);
06104          reason = QUEUE_TIMEOUT;
06105          res = 0;
06106          break;
06107       }
06108 
06109       
06110       /* Leave if we have exceeded our queuetimeout */
06111       if (qe.expire && (time(NULL) >= qe.expire)) {
06112          record_abandoned(&qe);
06113          reason = QUEUE_TIMEOUT;
06114          res = 0;
06115          ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
06116          break;
06117       }
06118 
06119       /* If using dynamic realtime members, we should regenerate the member list for this queue */
06120       update_realtime_members(qe.parent);
06121       /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
06122       res = wait_a_bit(&qe);
06123       if (res)
06124          goto stop;
06125 
06126       /* Since this is a priority queue and
06127        * it is not sure that we are still at the head
06128        * of the queue, go and check for our turn again.
06129        */
06130       if (!is_our_turn(&qe)) {
06131          ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
06132          goto check_turns;
06133       }
06134    }
06135 
06136 stop:
06137    if (res) {
06138       if (res < 0) {
06139          if (!qe.handled) {
06140             record_abandoned(&qe);
06141             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
06142                "%d|%d|%ld", qe.pos, qe.opos,
06143                (long) time(NULL) - qe.start);
06144             res = -1;
06145          } else if (qcontinue) {
06146             reason = QUEUE_CONTINUE;
06147             res = 0;
06148          }
06149       } else if (qe.valid_digits) {
06150          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
06151             "%s|%d", qe.digits, qe.pos);
06152       }
06153    }
06154 
06155    /* Don't allow return code > 0 */
06156    if (res >= 0) {
06157       res = 0; 
06158       if (ringing) {
06159          ast_indicate(chan, -1);
06160       } else {
06161          ast_moh_stop(chan);
06162       }        
06163       ast_stopstream(chan);
06164    }
06165 
06166    set_queue_variables(qe.parent, qe.chan);
06167 
06168    leave_queue(&qe);
06169    if (reason != QUEUE_UNKNOWN)
06170       set_queue_result(chan, reason);
06171 
06172    /*
06173     * every queue_ent is given a reference to it's parent
06174     * call_queue when it joins the queue.  This ref must be taken
06175     * away right before the queue_ent is destroyed.  In this case
06176     * the queue_ent is about to be returned on the stack
06177     */
06178    qe.parent = queue_unref(qe.parent);
06179 
06180    return res;
06181 }
06182 
06183 /*!
06184  * \brief create interface var with all queue details.
06185  * \retval 0 on success
06186  * \retval -1 on error
06187 */
06188 static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06189 {
06190    int res = -1;
06191    struct call_queue *q, tmpq = {
06192       .name = data,  
06193    };
06194 
06195    char interfacevar[256] = "";
06196    float sl = 0;
06197 
06198    if (ast_strlen_zero(data)) {
06199       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06200       return -1;
06201    }
06202 
06203    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) {
06204       ao2_lock(q);
06205       if (q->setqueuevar) {
06206          sl = 0;
06207          res = 0;
06208 
06209          if (q->callscompleted > 0) {
06210             sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
06211          }
06212 
06213          snprintf(interfacevar, sizeof(interfacevar),
06214             "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
06215             q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
06216 
06217          pbx_builtin_setvar_multiple(chan, interfacevar);
06218       }
06219 
06220       ao2_unlock(q);
06221       queue_t_unref(q, "Done with QUEUE() function");
06222    } else {
06223       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06224    }
06225 
06226    snprintf(buf, len, "%d", res);
06227 
06228    return 0;
06229 }
06230 
06231 /*!
06232  * \brief Check if a given queue exists
06233  *
06234  */
06235 static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06236 {
06237    struct call_queue *q;
06238 
06239    buf[0] = '\0';
06240 
06241    if (ast_strlen_zero(data)) {
06242       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06243       return -1;
06244    }
06245    q = load_realtime_queue(data);
06246    snprintf(buf, len, "%d", q != NULL? 1 : 0);
06247    if (q) {
06248       queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
06249    }
06250 
06251    return 0;
06252 }
06253 
06254 /*! 
06255  * \brief Get number either busy / free / ready or total members of a specific queue
06256  * \retval number of members (busy / free / ready / total)
06257  * \retval -1 on error
06258 */
06259 static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06260 {
06261    int count = 0;
06262    struct member *m;
06263    struct ao2_iterator mem_iter;
06264    struct call_queue *q;
06265    char *option;
06266 
06267    if (ast_strlen_zero(data)) {
06268       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06269       return -1;
06270    }
06271 
06272    if ((option = strchr(data, ',')))
06273       *option++ = '\0';
06274    else
06275       option = "logged";
06276    if ((q = load_realtime_queue(data))) {
06277       ao2_lock(q);
06278       if (!strcasecmp(option, "logged")) {
06279          mem_iter = ao2_iterator_init(q->members, 0);
06280          while ((m = ao2_iterator_next(&mem_iter))) {
06281             /* Count the agents who are logged in and presently answering calls */
06282             if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06283                count++;
06284             }
06285             ao2_ref(m, -1);
06286          }
06287          ao2_iterator_destroy(&mem_iter);
06288       } else if (!strcasecmp(option, "free")) {
06289          mem_iter = ao2_iterator_init(q->members, 0);
06290          while ((m = ao2_iterator_next(&mem_iter))) {
06291             /* Count the agents who are logged in and presently answering calls */
06292             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
06293                count++;
06294             }
06295             ao2_ref(m, -1);
06296          }
06297          ao2_iterator_destroy(&mem_iter);
06298       } else if (!strcasecmp(option, "ready")) {
06299          time_t now;
06300          time(&now);
06301          mem_iter = ao2_iterator_init(q->members, 0);
06302          while ((m = ao2_iterator_next(&mem_iter))) {
06303             /* Count the agents who are logged in, not paused and not wrapping up */
06304             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
06305                   !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
06306                count++;
06307             }
06308             ao2_ref(m, -1);
06309          }
06310          ao2_iterator_destroy(&mem_iter);
06311       } else /* must be "count" */
06312          count = ao2_container_count(q->members);
06313       ao2_unlock(q);
06314       queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
06315    } else
06316       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06317 
06318    snprintf(buf, len, "%d", count);
06319 
06320    return 0;
06321 }
06322 
06323 /*! 
06324  * \brief Get the total number of members in a specific queue (Deprecated)
06325  * \retval number of members 
06326  * \retval -1 on error 
06327 */
06328 static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06329 {
06330    int count = 0;
06331    struct member *m;
06332    struct call_queue *q;
06333    struct ao2_iterator mem_iter;
06334    static int depflag = 1;
06335 
06336    if (depflag) {
06337       depflag = 0;
06338       ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
06339    }
06340 
06341    if (ast_strlen_zero(data)) {
06342       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06343       return -1;
06344    }
06345    
06346    if ((q = load_realtime_queue(data))) {
06347       ao2_lock(q);
06348       mem_iter = ao2_iterator_init(q->members, 0);
06349       while ((m = ao2_iterator_next(&mem_iter))) {
06350          /* Count the agents who are logged in and presently answering calls */
06351          if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06352             count++;
06353          }
06354          ao2_ref(m, -1);
06355       }
06356       ao2_iterator_destroy(&mem_iter);
06357       ao2_unlock(q);
06358       queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
06359    } else
06360       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06361 
06362    snprintf(buf, len, "%d", count);
06363 
06364    return 0;
06365 }
06366 
06367 /*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
06368 static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06369 {
06370    int count = 0;
06371    struct call_queue *q, tmpq = {
06372       .name = data,  
06373    };
06374    struct ast_variable *var = NULL;
06375 
06376    buf[0] = '\0';
06377    
06378    if (ast_strlen_zero(data)) {
06379       ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
06380       return -1;
06381    }
06382 
06383    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
06384       ao2_lock(q);
06385       count = q->count;
06386       ao2_unlock(q);
06387       queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
06388    } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
06389       /* if the queue is realtime but was not found in memory, this
06390        * means that the queue had been deleted from memory since it was 
06391        * "dead." This means it has a 0 waiting count
06392        */
06393       count = 0;
06394       ast_variables_destroy(var);
06395    } else
06396       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06397 
06398    snprintf(buf, len, "%d", count);
06399 
06400    return 0;
06401 }
06402 
06403 /*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
06404 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06405 {
06406    struct call_queue *q, tmpq = {
06407       .name = data,  
06408    };
06409    struct member *m;
06410 
06411    /* Ensure an otherwise empty list doesn't return garbage */
06412    buf[0] = '\0';
06413 
06414    if (ast_strlen_zero(data)) {
06415       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
06416       return -1;
06417    }
06418 
06419    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
06420       int buflen = 0, count = 0;
06421       struct ao2_iterator mem_iter;
06422 
06423       ao2_lock(q);
06424       mem_iter = ao2_iterator_init(q->members, 0);
06425       while ((m = ao2_iterator_next(&mem_iter))) {
06426          /* strcat() is always faster than printf() */
06427          if (count++) {
06428             strncat(buf + buflen, ",", len - buflen - 1);
06429             buflen++;
06430          }
06431          strncat(buf + buflen, m->interface, len - buflen - 1);
06432          buflen += strlen(m->interface);
06433          /* Safeguard against overflow (negative length) */
06434          if (buflen >= len - 2) {
06435             ao2_ref(m, -1);
06436             ast_log(LOG_WARNING, "Truncating list\n");
06437             break;
06438          }
06439          ao2_ref(m, -1);
06440       }
06441       ao2_iterator_destroy(&mem_iter);
06442       ao2_unlock(q);
06443       queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
06444    } else
06445       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06446 
06447    /* We should already be terminated, but let's make sure. */
06448    buf[len - 1] = '\0';
06449 
06450    return 0;
06451 }
06452 
06453 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
06454 static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06455 {
06456    int penalty;
06457    AST_DECLARE_APP_ARGS(args,
06458       AST_APP_ARG(queuename);
06459       AST_APP_ARG(interface);
06460    );
06461    /* Make sure the returned value on error is NULL. */
06462    buf[0] = '\0';
06463 
06464    if (ast_strlen_zero(data)) {
06465       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06466       return -1;
06467    }
06468 
06469    AST_STANDARD_APP_ARGS(args, data);
06470 
06471    if (args.argc < 2) {
06472       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06473       return -1;
06474    }
06475 
06476    penalty = get_member_penalty (args.queuename, args.interface);
06477    
06478    if (penalty >= 0) /* remember that buf is already '\0' */
06479       snprintf (buf, len, "%d", penalty);
06480 
06481    return 0;
06482 }
06483 
06484 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
06485 static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
06486 {
06487    int penalty;
06488    AST_DECLARE_APP_ARGS(args,
06489       AST_APP_ARG(queuename);
06490       AST_APP_ARG(interface);
06491    );
06492 
06493    if (ast_strlen_zero(data)) {
06494       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06495       return -1;
06496    }
06497 
06498    AST_STANDARD_APP_ARGS(args, data);
06499 
06500    if (args.argc < 2) {
06501       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06502       return -1;
06503    }
06504 
06505    penalty = atoi(value);
06506 
06507    if (ast_strlen_zero(args.interface)) {
06508       ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
06509       return -1;
06510    }
06511 
06512    /* if queuename = NULL then penalty will be set for interface in all the queues. */
06513    if (set_member_penalty(args.queuename, args.interface, penalty)) {
06514       ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
06515       return -1;
06516    }
06517 
06518    return 0;
06519 }
06520 
06521 static struct ast_custom_function queueexists_function = {
06522    .name = "QUEUE_EXISTS",
06523    .read = queue_function_exists,
06524 };
06525 
06526 static struct ast_custom_function queuevar_function = {
06527    .name = "QUEUE_VARIABLES",
06528    .read = queue_function_var,
06529 };
06530 
06531 static struct ast_custom_function queuemembercount_function = {
06532    .name = "QUEUE_MEMBER",
06533    .read = queue_function_qac,
06534 };
06535 
06536 static struct ast_custom_function queuemembercount_dep = {
06537    .name = "QUEUE_MEMBER_COUNT",
06538    .read = queue_function_qac_dep,
06539 };
06540 
06541 static struct ast_custom_function queuewaitingcount_function = {
06542    .name = "QUEUE_WAITING_COUNT",
06543    .read = queue_function_queuewaitingcount,
06544 };
06545 
06546 static struct ast_custom_function queuememberlist_function = {
06547    .name = "QUEUE_MEMBER_LIST",
06548    .read = queue_function_queuememberlist,
06549 };
06550 
06551 static struct ast_custom_function queuememberpenalty_function = {
06552    .name = "QUEUE_MEMBER_PENALTY",
06553    .read = queue_function_memberpenalty_read,
06554    .write = queue_function_memberpenalty_write,
06555 };
06556 
06557 /*! \brief Reload the rules defined in queuerules.conf
06558  *
06559  * \param reload If 1, then only process queuerules.conf if the file
06560  * has changed since the last time we inspected it.
06561  * \return Always returns AST_MODULE_LOAD_SUCCESS
06562  */
06563 static int reload_queue_rules(int reload)
06564 {
06565    struct ast_config *cfg;
06566    struct rule_list *rl_iter, *new_rl;
06567    struct penalty_rule *pr_iter;
06568    char *rulecat = NULL;
06569    struct ast_variable *rulevar = NULL;
06570    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06571    
06572    if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
06573       ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
06574       return AST_MODULE_LOAD_SUCCESS;
06575    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06576       ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
06577       return AST_MODULE_LOAD_SUCCESS;
06578    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06579       ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format.  Aborting.\n");
06580       return AST_MODULE_LOAD_SUCCESS;
06581    }
06582 
06583    AST_LIST_LOCK(&rule_lists);
06584    while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
06585       while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
06586          ast_free(pr_iter);
06587       ast_free(rl_iter);
06588    }
06589    while ((rulecat = ast_category_browse(cfg, rulecat))) {
06590       if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
06591          AST_LIST_UNLOCK(&rule_lists);
06592          ast_config_destroy(cfg);
06593          return AST_MODULE_LOAD_FAILURE;
06594       } else {
06595          ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
06596          AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
06597          for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
06598             if(!strcasecmp(rulevar->name, "penaltychange"))
06599                insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
06600             else
06601                ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
06602       }
06603    }
06604    AST_LIST_UNLOCK(&rule_lists);
06605 
06606    ast_config_destroy(cfg);
06607 
06608    return AST_MODULE_LOAD_SUCCESS;
06609 }
06610 
06611 /*! Set the global queue parameters as defined in the "general" section of queues.conf */
06612 static void queue_set_global_params(struct ast_config *cfg)
06613 {
06614    const char *general_val = NULL;
06615    queue_persistent_members = 0;
06616    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
06617       queue_persistent_members = ast_true(general_val);
06618    autofill_default = 0;
06619    if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
06620       autofill_default = ast_true(general_val);
06621    montype_default = 0;
06622    if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
06623       if (!strcasecmp(general_val, "mixmonitor"))
06624          montype_default = 1;
06625    }
06626    update_cdr = 0;
06627    if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
06628       update_cdr = ast_true(general_val);
06629    shared_lastcall = 0;
06630    if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
06631       shared_lastcall = ast_true(general_val);
06632 }
06633 
06634 /*! \brief reload information pertaining to a single member
06635  *
06636  * This function is called when a member = line is encountered in
06637  * queues.conf.
06638  *
06639  * \param memberdata The part after member = in the config file
06640  * \param q The queue to which this member belongs
06641  */
06642 static void reload_single_member(const char *memberdata, struct call_queue *q)
06643 {
06644    char *membername, *interface, *state_interface, *tmp;
06645    char *parse;
06646    struct member *cur, *newm;
06647    struct member tmpmem;
06648    int penalty;
06649    AST_DECLARE_APP_ARGS(args,
06650       AST_APP_ARG(interface);
06651       AST_APP_ARG(penalty);
06652       AST_APP_ARG(membername);
06653       AST_APP_ARG(state_interface);
06654    );
06655 
06656    if (ast_strlen_zero(memberdata)) {
06657       ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
06658       return;
06659    }
06660 
06661    /* Add a new member */
06662    parse = ast_strdupa(memberdata);
06663             
06664    AST_STANDARD_APP_ARGS(args, parse);
06665 
06666    interface = args.interface;
06667    if (!ast_strlen_zero(args.penalty)) {
06668       tmp = args.penalty;
06669       ast_strip(tmp);
06670       penalty = atoi(tmp);
06671       if (penalty < 0) {
06672          penalty = 0;
06673       }
06674    } else {
06675       penalty = 0;
06676    }
06677 
06678    if (!ast_strlen_zero(args.membername)) {
06679       membername = args.membername;
06680       ast_strip(membername);
06681    } else {
06682       membername = interface;
06683    }
06684 
06685    if (!ast_strlen_zero(args.state_interface)) {
06686       state_interface = args.state_interface;
06687       ast_strip(state_interface);
06688    } else {
06689       state_interface = interface;
06690    }
06691 
06692    /* Find the old position in the list */
06693    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
06694    cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
06695    if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
06696       ao2_link(q->members, newm);
06697       ao2_ref(newm, -1);
06698    }
06699    newm = NULL;
06700 
06701    if (cur) {
06702       ao2_ref(cur, -1);
06703    }
06704 }
06705 
06706 static int mark_member_dead(void *obj, void *arg, int flags)
06707 {
06708    struct member *member = obj;
06709    if (!member->dynamic) {
06710       member->delme = 1;
06711    }
06712    return 0;
06713 }
06714 
06715 static int kill_dead_members(void *obj, void *arg, int flags)
06716 {
06717    struct member *member = obj;
06718 
06719    if (!member->delme) {
06720       member->status = get_queue_member_status(member);
06721       return 0;
06722    } else {
06723       return CMP_MATCH;
06724    }
06725 }
06726 
06727 /*! \brief Reload information pertaining to a particular queue
06728  *
06729  * Once we have isolated a queue within reload_queues, we call this. This will either
06730  * reload information for the queue or if we're just reloading member information, we'll just
06731  * reload that without touching other settings within the queue 
06732  *
06733  * \param cfg The configuration which we are reading
06734  * \param mask Tells us what information we need to reload
06735  * \param queuename The name of the queue we are reloading information from
06736  * \retval void
06737  */
06738 static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
06739 {
06740    int new;
06741    struct call_queue *q = NULL;
06742    /*We're defining a queue*/
06743    struct call_queue tmpq = {
06744       .name = queuename,
06745    };
06746    const char *tmpvar;
06747    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06748    const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
06749    int prev_weight = 0;
06750    struct ast_variable *var;
06751    if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
06752       if (queue_reload) {
06753          /* Make one then */
06754          if (!(q = alloc_queue(queuename))) {
06755             return;
06756          }
06757       } else {
06758          /* Since we're not reloading queues, this means that we found a queue
06759           * in the configuration file which we don't know about yet. Just return.
06760           */
06761          return;
06762       }
06763       new = 1;
06764    } else {
06765       new = 0;
06766    }
06767    
06768    if (!new) {
06769       ao2_lock(q);
06770       prev_weight = q->weight ? 1 : 0;
06771    }
06772    /* Check if we already found a queue with this name in the config file */
06773    if (q->found) {
06774       ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
06775       if (!new) {
06776          /* It should be impossible to *not* hit this case*/
06777          ao2_unlock(q);
06778       }
06779       queue_t_unref(q, "We exist! Expiring temporary pointer");
06780       return;
06781    }
06782    /* Due to the fact that the "linear" strategy will have a different allocation
06783     * scheme for queue members, we must devise the queue's strategy before other initializations.
06784     * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
06785     * container used will have only a single bucket instead of the typical number.
06786     */
06787    if (queue_reload) {
06788       if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
06789          q->strategy = strat2int(tmpvar);
06790          if (q->strategy < 0) {
06791             ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
06792             tmpvar, q->name);
06793             q->strategy = QUEUE_STRATEGY_RINGALL;
06794          }
06795       } else {
06796          q->strategy = QUEUE_STRATEGY_RINGALL;
06797       }
06798       init_queue(q);
06799    }
06800    if (member_reload) {
06801       ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
06802       q->found = 1;
06803    }
06804    for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
06805       if (member_reload && !strcasecmp(var->name, "member")) {
06806          reload_single_member(var->value, q);
06807       } else if (queue_reload) {
06808          queue_set_param(q, var->name, var->value, var->lineno, 1);
06809       }
06810    }
06811    /* At this point, we've determined if the queue has a weight, so update use_weight
06812     * as appropriate
06813     */
06814    if (!q->weight && prev_weight) {
06815       ast_atomic_fetchadd_int(&use_weight, -1);
06816    }
06817    else if (q->weight && !prev_weight) {
06818       ast_atomic_fetchadd_int(&use_weight, +1);
06819    }
06820 
06821    /* Free remaining members marked as delme */
06822    if (member_reload) {
06823       ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
06824    }
06825 
06826    if (new) {
06827       queues_t_link(queues, q, "Add queue to container");
06828    } else {
06829       ao2_unlock(q);
06830    }
06831    queue_t_unref(q, "Expiring creation reference");
06832 }
06833 
06834 static int remove_members_and_mark_unfound(void *obj, void *arg, int flags)
06835 {
06836    struct call_queue *q = obj;
06837    char *queuename = arg;
06838    if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
06839       q->found = 0;
06840 
06841    }
06842    return 0;
06843 }
06844 
06845 static int mark_dead_and_unfound(void *obj, void *arg, int flags)
06846 {
06847    struct call_queue *q = obj;
06848    char *queuename = arg;
06849    if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
06850       q->dead = 1;
06851       q->found = 0;
06852    }
06853    return 0;
06854 }
06855 
06856 static int kill_dead_queues(void *obj, void *arg, int flags)
06857 {
06858    struct call_queue *q = obj;
06859    char *queuename = arg;
06860    if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
06861       return CMP_MATCH;
06862    } else {
06863       return 0;
06864    }
06865 }
06866 
06867 /*! \brief reload the queues.conf file
06868  *
06869  * This function reloads the information in the general section of the queues.conf
06870  * file and potentially more, depending on the value of mask.
06871  *
06872  * \param reload 0 if we are calling this the first time, 1 every other time
06873  * \param mask Gives flags telling us what information to actually reload
06874  * \param queuename If set to a non-zero string, then only reload information from
06875  * that particular queue. Otherwise inspect all queues
06876  * \retval -1 Failure occurred 
06877  * \retval 0 All clear!
06878  */
06879 static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
06880 {
06881    struct ast_config *cfg;
06882    char *cat;
06883    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06884    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06885    const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
06886 
06887    if (!(cfg = ast_config_load("queues.conf", config_flags))) {
06888       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
06889       return -1;
06890    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06891       return 0;
06892    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06893       ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format.  Aborting.\n");
06894       return -1;
06895    }
06896 
06897    /* We've made it here, so it looks like we're doing operations on all queues. */
06898    ao2_lock(queues);
06899 
06900    /* Mark all queues as dead for the moment if we're reloading queues.
06901     * For clarity, we could just be reloading members, in which case we don't want to mess
06902     * with the other queue parameters at all*/
06903    if (queue_reload) {
06904       ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
06905    }
06906 
06907    if (member_reload) {
06908       ao2_callback(queues, OBJ_NODATA, remove_members_and_mark_unfound, (char *) queuename);
06909    }
06910 
06911    /* Chug through config file */
06912    cat = NULL;
06913    while ((cat = ast_category_browse(cfg, cat)) ) {
06914       if (!strcasecmp(cat, "general") && queue_reload) {
06915          queue_set_global_params(cfg);
06916          continue;
06917       }
06918       if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
06919          reload_single_queue(cfg, mask, cat);
06920    }
06921 
06922    ast_config_destroy(cfg);
06923    /* Unref all the dead queues if we were reloading queues */
06924    if (queue_reload) {
06925       ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
06926    }
06927    ao2_unlock(queues);
06928    return 0;
06929 }
06930 
06931 /*! \brief Facilitates resetting statistics for a queue
06932  *
06933  * This function actually does not reset any statistics, but
06934  * rather finds a call_queue struct which corresponds to the
06935  * passed-in queue name and passes that structure to the
06936  * clear_queue function. If no queuename is passed in, then
06937  * all queues will have their statistics reset.
06938  *
06939  * \param queuename The name of the queue to reset the statistics
06940  * for. If this is NULL or zero-length, then this means to reset
06941  * the statistics for all queues
06942  * \retval void
06943  */
06944 static int clear_stats(const char *queuename)
06945 {
06946    struct call_queue *q;
06947    struct ao2_iterator queue_iter;
06948 
06949    queue_iter = ao2_iterator_init(queues, 0);
06950    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06951       ao2_lock(q);
06952       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
06953          clear_queue(q);
06954       ao2_unlock(q);
06955       queue_t_unref(q, "Done with iterator");
06956    }
06957    ao2_iterator_destroy(&queue_iter);
06958    return 0;
06959 }
06960 
06961 /*! \brief The command center for all reload operations
06962  *
06963  * Whenever any piece of queue information is to be reloaded, this function
06964  * is called. It interprets the flags set in the mask parameter and acts
06965  * based on how they are set.
06966  *
06967  * \param reload True if we are reloading information, false if we are loading
06968  * information for the first time.
06969  * \param mask A bitmask which tells the handler what actions to take
06970  * \param queuename The name of the queue on which we wish to take action
06971  * \retval 0 All reloads were successful
06972  * \retval non-zero There was a failure
06973  */
06974 static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
06975 {
06976    int res = 0;
06977 
06978    if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
06979       res |= reload_queue_rules(reload);
06980    }
06981    if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
06982       res |= clear_stats(queuename);
06983    }
06984    if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
06985       res |= reload_queues(reload, mask, queuename);
06986    }
06987    return res;
06988 }
06989 
06990 /*! \brief direct ouput to manager or cli with proper terminator */
06991 static void do_print(struct mansession *s, int fd, const char *str)
06992 {
06993    if (s)
06994       astman_append(s, "%s\r\n", str);
06995    else
06996       ast_cli(fd, "%s\n", str);
06997 }
06998 
06999 /*! 
07000  * \brief Show queue(s) status and statistics 
07001  * 
07002  * List the queues strategy, calls processed, members logged in,
07003  * other queue statistics such as avg hold time.
07004 */
07005 static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
07006 {
07007    struct call_queue *q;
07008    struct ast_str *out = ast_str_alloca(240);
07009    int found = 0;
07010    time_t now = time(NULL);
07011    struct ao2_iterator queue_iter;
07012    struct ao2_iterator mem_iter;
07013 
07014    if (argc != 2 && argc != 3)
07015       return CLI_SHOWUSAGE;
07016 
07017    if (argc == 3) { /* specific queue */
07018       if ((q = load_realtime_queue(argv[2]))) {
07019          queue_t_unref(q, "Done with temporary pointer");
07020       }
07021    } else if (ast_check_realtime("queues")) {
07022       /* This block is to find any queues which are defined in realtime but
07023        * which have not yet been added to the in-core container
07024        */
07025       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
07026       char *queuename;
07027       if (cfg) {
07028          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
07029             if ((q = load_realtime_queue(queuename))) {
07030                queue_t_unref(q, "Done with temporary pointer");
07031             }
07032          }
07033          ast_config_destroy(cfg);
07034       }
07035    }
07036 
07037    ao2_lock(queues);
07038    queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
07039    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07040       float sl;
07041       struct call_queue *realtime_queue = NULL;
07042 
07043       ao2_lock(q);
07044       /* This check is to make sure we don't print information for realtime
07045        * queues which have been deleted from realtime but which have not yet
07046        * been deleted from the in-core container
07047        */
07048       if (q->realtime) {
07049          realtime_queue = load_realtime_queue(q->name);
07050          if (!realtime_queue) {
07051             ao2_unlock(q);
07052             queue_t_unref(q, "Done with iterator");
07053             continue;
07054          }
07055          queue_t_unref(realtime_queue, "Queue is already in memory");
07056       }
07057 
07058       if (argc == 3 && strcasecmp(q->name, argv[2])) {
07059          ao2_unlock(q);
07060          queue_t_unref(q, "Done with iterator");
07061          continue;
07062       }
07063       found = 1;
07064 
07065       ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
07066       if (q->maxlen)
07067          ast_str_append(&out, 0, "%d", q->maxlen);
07068       else
07069          ast_str_append(&out, 0, "unlimited");
07070       sl = 0;
07071       if (q->callscompleted > 0)
07072          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
07073       ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
07074          int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
07075          q->callscompleted, q->callsabandoned,sl,q->servicelevel);
07076       do_print(s, fd, ast_str_buffer(out));
07077       if (!ao2_container_count(q->members))
07078          do_print(s, fd, "   No Members");
07079       else {
07080          struct member *mem;
07081 
07082          do_print(s, fd, "   Members: ");
07083          mem_iter = ao2_iterator_init(q->members, 0);
07084          while ((mem = ao2_iterator_next(&mem_iter))) {
07085             ast_str_set(&out, 0, "      %s", mem->membername);
07086             if (strcasecmp(mem->membername, mem->interface)) {
07087                ast_str_append(&out, 0, " (%s)", mem->interface);
07088             }
07089             if (mem->penalty)
07090                ast_str_append(&out, 0, " with penalty %d", mem->penalty);
07091             ast_str_append(&out, 0, "%s%s%s (%s)",
07092                mem->dynamic ? " (dynamic)" : "",
07093                mem->realtime ? " (realtime)" : "",
07094                mem->paused ? " (paused)" : "",
07095                ast_devstate2str(mem->status));
07096             if (mem->calls)
07097                ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
07098                   mem->calls, (long) (time(NULL) - mem->lastcall));
07099             else
07100                ast_str_append(&out, 0, " has taken no calls yet");
07101             do_print(s, fd, ast_str_buffer(out));
07102             ao2_ref(mem, -1);
07103          }
07104          ao2_iterator_destroy(&mem_iter);
07105       }
07106       if (!q->head)
07107          do_print(s, fd, "   No Callers");
07108       else {
07109          struct queue_ent *qe;
07110          int pos = 1;
07111 
07112          do_print(s, fd, "   Callers: ");
07113          for (qe = q->head; qe; qe = qe->next) {
07114             ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
07115                pos++, qe->chan->name, (long) (now - qe->start) / 60,
07116                (long) (now - qe->start) % 60, qe->prio);
07117             do_print(s, fd, ast_str_buffer(out));
07118          }
07119       }
07120       do_print(s, fd, ""); /* blank line between entries */
07121       ao2_unlock(q);
07122       queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
07123    }
07124    ao2_iterator_destroy(&queue_iter);
07125    ao2_unlock(queues);
07126    if (!found) {
07127       if (argc == 3)
07128          ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
07129       else
07130          ast_str_set(&out, 0, "No queues.");
07131       do_print(s, fd, ast_str_buffer(out));
07132    }
07133    return CLI_SUCCESS;
07134 }
07135 
07136 /*! 
07137  * \brief Check if a given word is in a space-delimited list
07138  *
07139  * \param list Space delimited list of words
07140  * \param word The word used to search the list
07141  *
07142  * \note This function will not return 1 if the word is at the very end of the
07143  * list (followed immediately by a \0, not a space) since it is used for
07144  * checking tab-completion and a word at the end is still being tab-completed.
07145  *
07146  * \return Returns 1 if the word is found
07147  * \return Returns 0 if the word is not found
07148 */
07149 static int word_in_list(const char *list, const char *word) {
07150    int list_len, word_len = strlen(word);
07151    const char *find, *end_find, *end_list;
07152 
07153    /* strip whitespace from front */
07154    while (isspace(*list)) {
07155       list++;
07156    }
07157 
07158    while ((find = strstr(list, word))) {
07159       /* beginning of find starts inside another word? */
07160       if (find != list && *(find - 1) != ' ') {
07161          list = find;
07162          /* strip word from front */
07163          while (!isspace(*list) && *list != '\0') {
07164             list++;
07165          }
07166          /* strip whitespace from front */
07167          while (isspace(*list)) {
07168             list++;
07169          }
07170          continue;
07171       }
07172 
07173       /* end of find ends inside another word or at very end of list? */
07174       list_len = strlen(list);
07175       end_find = find + word_len;
07176       end_list = list + list_len;
07177       if (end_find == end_list || *end_find != ' ') {
07178          list = find;
07179          /* strip word from front */
07180          while (!isspace(*list) && *list != '\0') {
07181             list++;
07182          }
07183          /* strip whitespace from front */
07184          while (isspace(*list)) {
07185             list++;
07186          }
07187          continue;
07188       }
07189 
07190       /* terminating conditions satisfied, word at beginning or separated by ' ' */
07191       return 1;
07192    }
07193    
07194    return 0;
07195 }
07196 
07197 /*! 
07198  * \brief Check if a given word is in a space-delimited list
07199  *
07200  * \param line The line as typed not including the current word being completed
07201  * \param word The word currently being completed
07202  * \param pos The number of completed words in line
07203  * \param state The nth desired completion option
07204  * \param word_list_offset Offset into the line where the list of queues begins.  If non-zero, queues in the list will not be offered for further completion.
07205  *
07206  * \return Returns the queue tab-completion for the given word and state
07207 */
07208 static char *complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
07209 {
07210    struct call_queue *q;
07211    char *ret = NULL;
07212    int which = 0;
07213    int wordlen = strlen(word);
07214    struct ao2_iterator queue_iter;
07215    const char *word_list = NULL;
07216 
07217    /* for certain commands, already completed items should be left out of
07218     * the list */
07219    if (word_list_offset && strlen(line) >= word_list_offset) {
07220       word_list = line + word_list_offset;
07221    }
07222 
07223    queue_iter = ao2_iterator_init(queues, 0);
07224    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07225       if (!strncasecmp(word, q->name, wordlen) && ++which > state
07226          && (!word_list_offset || !word_in_list(word_list, q->name))) {
07227          ret = ast_strdup(q->name);
07228          queue_t_unref(q, "Done with iterator");
07229          break;
07230       }
07231       queue_t_unref(q, "Done with iterator");
07232    }
07233    ao2_iterator_destroy(&queue_iter);
07234 
07235    /* Pretend "rules" is at the end of the queues list in certain
07236     * circumstances since it is an alternate command that should be
07237     * tab-completable for "queue show" */
07238    if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
07239       ret = ast_strdup("rules");
07240    }
07241 
07242    return ret;
07243 }
07244 
07245 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
07246 {
07247    if (pos == 2) {
07248       return complete_queue(line, word, pos, state, 0);
07249    }
07250    return NULL;
07251 }
07252 
07253 static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07254 {
07255    switch ( cmd ) {
07256    case CLI_INIT:
07257       e->command = "queue show";
07258       e->usage =
07259          "Usage: queue show\n"
07260          "       Provides summary information on a specified queue.\n";
07261       return NULL;
07262    case CLI_GENERATE:
07263       return complete_queue_show(a->line, a->word, a->pos, a->n); 
07264    }
07265 
07266    return __queues_show(NULL, a->fd, a->argc, a->argv);
07267 }
07268 
07269 /*!\brief callback to display queues status in manager
07270    \addtogroup Group_AMI
07271  */
07272 static int manager_queues_show(struct mansession *s, const struct message *m)
07273 {
07274    static const char * const a[] = { "queue", "show" };
07275 
07276    __queues_show(s, -1, 2, a);
07277    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
07278 
07279    return RESULT_SUCCESS;
07280 }
07281 
07282 static int manager_queue_rule_show(struct mansession *s, const struct message *m)
07283 {
07284    const char *rule = astman_get_header(m, "Rule");
07285    const char *id = astman_get_header(m, "ActionID");
07286    struct rule_list *rl_iter;
07287    struct penalty_rule *pr_iter;
07288 
07289    astman_append(s, "Response: Success\r\n");
07290    if (!ast_strlen_zero(id)) {
07291       astman_append(s, "ActionID: %s\r\n", id);
07292    }
07293 
07294    AST_LIST_LOCK(&rule_lists);
07295    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07296       if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
07297          astman_append(s, "RuleList: %s\r\n", rl_iter->name);
07298          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07299             astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
07300          }
07301          if (!ast_strlen_zero(rule))
07302             break;
07303       }
07304    }
07305    AST_LIST_UNLOCK(&rule_lists);
07306 
07307    /*
07308     * Two blank lines instead of one because the Response and
07309     * ActionID headers used to not be present.
07310     */
07311    astman_append(s, "\r\n\r\n");
07312 
07313    return RESULT_SUCCESS;
07314 }
07315 
07316 /*! \brief Summary of queue info via the AMI */
07317 static int manager_queues_summary(struct mansession *s, const struct message *m)
07318 {
07319    time_t now;
07320    int qmemcount = 0;
07321    int qmemavail = 0;
07322    int qchancount = 0;
07323    int qlongestholdtime = 0;
07324    const char *id = astman_get_header(m, "ActionID");
07325    const char *queuefilter = astman_get_header(m, "Queue");
07326    char idText[256] = "";
07327    struct call_queue *q;
07328    struct queue_ent *qe;
07329    struct member *mem;
07330    struct ao2_iterator queue_iter;
07331    struct ao2_iterator mem_iter;
07332 
07333    astman_send_ack(s, m, "Queue summary will follow");
07334    time(&now);
07335    if (!ast_strlen_zero(id))
07336       snprintf(idText, 256, "ActionID: %s\r\n", id);
07337    queue_iter = ao2_iterator_init(queues, 0);
07338    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07339       ao2_lock(q);
07340 
07341       /* List queue properties */
07342       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
07343          /* Reset the necessary local variables if no queuefilter is set*/
07344          qmemcount = 0;
07345          qmemavail = 0;
07346          qchancount = 0;
07347          qlongestholdtime = 0;
07348 
07349          /* List Queue Members */
07350          mem_iter = ao2_iterator_init(q->members, 0);
07351          while ((mem = ao2_iterator_next(&mem_iter))) {
07352             if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
07353                ++qmemcount;
07354                if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
07355                   ++qmemavail;
07356                }
07357             }
07358             ao2_ref(mem, -1);
07359          }
07360          ao2_iterator_destroy(&mem_iter);
07361          for (qe = q->head; qe; qe = qe->next) {
07362             if ((now - qe->start) > qlongestholdtime) {
07363                qlongestholdtime = now - qe->start;
07364             }
07365             ++qchancount;
07366          }
07367          astman_append(s, "Event: QueueSummary\r\n"
07368             "Queue: %s\r\n"
07369             "LoggedIn: %d\r\n"
07370             "Available: %d\r\n"
07371             "Callers: %d\r\n" 
07372             "HoldTime: %d\r\n"
07373             "TalkTime: %d\r\n"
07374             "LongestHoldTime: %d\r\n"
07375             "%s"
07376             "\r\n",
07377             q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
07378       }
07379       ao2_unlock(q);
07380       queue_t_unref(q, "Done with iterator");
07381    }
07382    ao2_iterator_destroy(&queue_iter);
07383    astman_append(s,
07384       "Event: QueueSummaryComplete\r\n"
07385       "%s"
07386       "\r\n", idText);
07387 
07388    return RESULT_SUCCESS;
07389 }
07390 
07391 /*! \brief Queue status info via AMI */
07392 static int manager_queues_status(struct mansession *s, const struct message *m)
07393 {
07394    time_t now;
07395    int pos;
07396    const char *id = astman_get_header(m,"ActionID");
07397    const char *queuefilter = astman_get_header(m,"Queue");
07398    const char *memberfilter = astman_get_header(m,"Member");
07399    char idText[256] = "";
07400    struct call_queue *q;
07401    struct queue_ent *qe;
07402    float sl = 0;
07403    struct member *mem;
07404    struct ao2_iterator queue_iter;
07405    struct ao2_iterator mem_iter;
07406 
07407    astman_send_ack(s, m, "Queue status will follow");
07408    time(&now);
07409    if (!ast_strlen_zero(id))
07410       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07411 
07412    queue_iter = ao2_iterator_init(queues, 0);
07413    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07414       ao2_lock(q);
07415 
07416       /* List queue properties */
07417       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
07418          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
07419          astman_append(s, "Event: QueueParams\r\n"
07420             "Queue: %s\r\n"
07421             "Max: %d\r\n"
07422             "Strategy: %s\r\n"
07423             "Calls: %d\r\n"
07424             "Holdtime: %d\r\n"
07425             "TalkTime: %d\r\n"
07426             "Completed: %d\r\n"
07427             "Abandoned: %d\r\n"
07428             "ServiceLevel: %d\r\n"
07429             "ServicelevelPerf: %2.1f\r\n"
07430             "Weight: %d\r\n"
07431             "%s"
07432             "\r\n",
07433             q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
07434             q->callsabandoned, q->servicelevel, sl, q->weight, idText);
07435          /* List Queue Members */
07436          mem_iter = ao2_iterator_init(q->members, 0);
07437          while ((mem = ao2_iterator_next(&mem_iter))) {
07438             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
07439                astman_append(s, "Event: QueueMember\r\n"
07440                   "Queue: %s\r\n"
07441                   "Name: %s\r\n"
07442                   "Location: %s\r\n"
07443                   "Membership: %s\r\n"
07444                   "Penalty: %d\r\n"
07445                   "CallsTaken: %d\r\n"
07446                   "LastCall: %d\r\n"
07447                   "Status: %d\r\n"
07448                   "Paused: %d\r\n"
07449                   "%s"
07450                   "\r\n",
07451                   q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
07452                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
07453             }
07454             ao2_ref(mem, -1);
07455          }
07456          ao2_iterator_destroy(&mem_iter);
07457          /* List Queue Entries */
07458          pos = 1;
07459          for (qe = q->head; qe; qe = qe->next) {
07460             astman_append(s, "Event: QueueEntry\r\n"
07461                "Queue: %s\r\n"
07462                "Position: %d\r\n"
07463                "Channel: %s\r\n"
07464                "Uniqueid: %s\r\n"
07465                "CallerIDNum: %s\r\n"
07466                "CallerIDName: %s\r\n"
07467                "ConnectedLineNum: %s\r\n"
07468                "ConnectedLineName: %s\r\n"
07469                "Wait: %ld\r\n"
07470                "%s"
07471                "\r\n",
07472                q->name, pos++, qe->chan->name, qe->chan->uniqueid,
07473                S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
07474                S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
07475                S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
07476                S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
07477                (long) (now - qe->start), idText);
07478          }
07479       }
07480       ao2_unlock(q);
07481       queue_t_unref(q, "Done with iterator");
07482    }
07483    ao2_iterator_destroy(&queue_iter);
07484 
07485    astman_append(s,
07486       "Event: QueueStatusComplete\r\n"
07487       "%s"
07488       "\r\n",idText);
07489 
07490    return RESULT_SUCCESS;
07491 }
07492 
07493 static int manager_add_queue_member(struct mansession *s, const struct message *m)
07494 {
07495    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
07496    int paused, penalty = 0;
07497 
07498    queuename = astman_get_header(m, "Queue");
07499    interface = astman_get_header(m, "Interface");
07500    penalty_s = astman_get_header(m, "Penalty");
07501    paused_s = astman_get_header(m, "Paused");
07502    membername = astman_get_header(m, "MemberName");
07503    state_interface = astman_get_header(m, "StateInterface");
07504 
07505    if (ast_strlen_zero(queuename)) {
07506       astman_send_error(s, m, "'Queue' not specified.");
07507       return 0;
07508    }
07509 
07510    if (ast_strlen_zero(interface)) {
07511       astman_send_error(s, m, "'Interface' not specified.");
07512       return 0;
07513    }
07514 
07515    if (ast_strlen_zero(penalty_s))
07516       penalty = 0;
07517    else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
07518       penalty = 0;
07519 
07520    if (ast_strlen_zero(paused_s))
07521       paused = 0;
07522    else
07523       paused = abs(ast_true(paused_s));
07524 
07525    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
07526    case RES_OKAY:
07527       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
07528       astman_send_ack(s, m, "Added interface to queue");
07529       break;
07530    case RES_EXISTS:
07531       astman_send_error(s, m, "Unable to add interface: Already there");
07532       break;
07533    case RES_NOSUCHQUEUE:
07534       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
07535       break;
07536    case RES_OUTOFMEMORY:
07537       astman_send_error(s, m, "Out of memory");
07538       break;
07539    }
07540 
07541    return 0;
07542 }
07543 
07544 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
07545 {
07546    const char *queuename, *interface;
07547 
07548    queuename = astman_get_header(m, "Queue");
07549    interface = astman_get_header(m, "Interface");
07550 
07551    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
07552       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
07553       return 0;
07554    }
07555 
07556    switch (remove_from_queue(queuename, interface)) {
07557    case RES_OKAY:
07558       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
07559       astman_send_ack(s, m, "Removed interface from queue");
07560       break;
07561    case RES_EXISTS:
07562       astman_send_error(s, m, "Unable to remove interface: Not there");
07563       break;
07564    case RES_NOSUCHQUEUE:
07565       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
07566       break;
07567    case RES_OUTOFMEMORY:
07568       astman_send_error(s, m, "Out of memory");
07569       break;
07570    case RES_NOT_DYNAMIC:
07571       astman_send_error(s, m, "Member not dynamic");
07572       break;
07573    }
07574 
07575    return 0;
07576 }
07577 
07578 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
07579 {
07580    const char *queuename, *interface, *paused_s, *reason;
07581    int paused;
07582 
07583    interface = astman_get_header(m, "Interface");
07584    paused_s = astman_get_header(m, "Paused");
07585    queuename = astman_get_header(m, "Queue");      /* Optional - if not supplied, pause the given Interface in all queues */
07586    reason = astman_get_header(m, "Reason");        /* Optional - Only used for logging purposes */
07587 
07588    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
07589       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
07590       return 0;
07591    }
07592 
07593    paused = abs(ast_true(paused_s));
07594 
07595    if (set_member_paused(queuename, interface, reason, paused))
07596       astman_send_error(s, m, "Interface not found");
07597    else
07598       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
07599    return 0;
07600 }
07601 
07602 static int manager_queue_log_custom(struct mansession *s, const struct message *m)
07603 {
07604    const char *queuename, *event, *message, *interface, *uniqueid;
07605 
07606    queuename = astman_get_header(m, "Queue");
07607    uniqueid = astman_get_header(m, "UniqueId");
07608    interface = astman_get_header(m, "Interface");
07609    event = astman_get_header(m, "Event");
07610    message = astman_get_header(m, "Message");
07611 
07612    if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
07613       astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
07614       return 0;
07615    }
07616 
07617    ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
07618    astman_send_ack(s, m, "Event added successfully");
07619 
07620    return 0;
07621 }
07622 
07623 static int manager_queue_reload(struct mansession *s, const struct message *m)
07624 {
07625    struct ast_flags mask = {0,};
07626    const char *queuename = NULL;
07627    int header_found = 0;
07628 
07629    queuename = astman_get_header(m, "Queue");
07630    if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
07631       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07632       header_found = 1;
07633    }
07634    if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
07635       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07636       header_found = 1;
07637    }
07638    if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
07639       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07640       header_found = 1;
07641    }
07642 
07643    if (!header_found) {
07644       ast_set_flag(&mask, AST_FLAGS_ALL);
07645    }
07646 
07647    if (!reload_handler(1, &mask, queuename)) {
07648       astman_send_ack(s, m, "Queue reloaded successfully");
07649    } else {
07650       astman_send_error(s, m, "Error encountered while reloading queue");
07651    }
07652    return 0;
07653 }
07654 
07655 static int manager_queue_reset(struct mansession *s, const struct message *m)
07656 {
07657    const char *queuename = NULL;
07658    struct ast_flags mask = {QUEUE_RESET_STATS,};
07659    
07660    queuename = astman_get_header(m, "Queue");
07661 
07662    if (!reload_handler(1, &mask, queuename)) {
07663       astman_send_ack(s, m, "Queue stats reset successfully");
07664    } else {
07665       astman_send_error(s, m, "Error encountered while resetting queue stats");
07666    }
07667    return 0;
07668 }
07669 
07670 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
07671 {
07672    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
07673    switch (pos) {
07674    case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
07675       return NULL;
07676    case 4: /* only one possible match, "to" */
07677       return state == 0 ? ast_strdup("to") : NULL;
07678    case 5: /* <queue> */
07679       return complete_queue(line, word, pos, state, 0);
07680    case 6: /* only one possible match, "penalty" */
07681       return state == 0 ? ast_strdup("penalty") : NULL;
07682    case 7:
07683       if (state < 100) {      /* 0-99 */
07684          char *num;
07685          if ((num = ast_malloc(3))) {
07686             sprintf(num, "%d", state);
07687          }
07688          return num;
07689       } else {
07690          return NULL;
07691       }
07692    case 8: /* only one possible match, "as" */
07693       return state == 0 ? ast_strdup("as") : NULL;
07694    case 9: /* Don't attempt to complete name of member (infinite possibilities) */
07695       return NULL;
07696    default:
07697       return NULL;
07698    }
07699 }
07700 
07701 static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
07702 {
07703    const char *queuename, *interface, *penalty_s;
07704    int penalty;
07705 
07706    interface = astman_get_header(m, "Interface");
07707    penalty_s = astman_get_header(m, "Penalty");
07708    /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
07709    queuename = astman_get_header(m, "Queue");
07710 
07711    if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
07712       astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
07713       return 0;
07714    }
07715  
07716    penalty = atoi(penalty_s);
07717 
07718    if (set_member_penalty((char *)queuename, (char *)interface, penalty))
07719       astman_send_error(s, m, "Invalid interface, queuename or penalty");
07720    else
07721       astman_send_ack(s, m, "Interface penalty set successfully");
07722 
07723    return 0;
07724 }
07725 
07726 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07727 {
07728    const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
07729    int penalty;
07730 
07731    switch ( cmd ) {
07732    case CLI_INIT:
07733       e->command = "queue add member";
07734       e->usage =
07735          "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
07736          "       Add a channel to a queue with optionally:  a penalty, membername and a state_interface\n";
07737       return NULL;
07738    case CLI_GENERATE:
07739       return complete_queue_add_member(a->line, a->word, a->pos, a->n);
07740    }
07741 
07742    if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
07743       return CLI_SHOWUSAGE;
07744    } else if (strcmp(a->argv[4], "to")) {
07745       return CLI_SHOWUSAGE;
07746    } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
07747       return CLI_SHOWUSAGE;
07748    } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
07749       return CLI_SHOWUSAGE;
07750    } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
07751       return CLI_SHOWUSAGE;
07752    }
07753 
07754    queuename = a->argv[5];
07755    interface = a->argv[3];
07756    if (a->argc >= 8) {
07757       if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
07758          if (penalty < 0) {
07759             ast_cli(a->fd, "Penalty must be >= 0\n");
07760             penalty = 0;
07761          }
07762       } else {
07763          ast_cli(a->fd, "Penalty must be an integer >= 0\n");
07764          penalty = 0;
07765       }
07766    } else {
07767       penalty = 0;
07768    }
07769 
07770    if (a->argc >= 10) {
07771       membername = a->argv[9];
07772    }
07773 
07774    if (a->argc >= 12) {
07775       state_interface = a->argv[11];
07776    }
07777 
07778    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
07779    case RES_OKAY:
07780       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
07781       ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
07782       return CLI_SUCCESS;
07783    case RES_EXISTS:
07784       ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
07785       return CLI_FAILURE;
07786    case RES_NOSUCHQUEUE:
07787       ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
07788       return CLI_FAILURE;
07789    case RES_OUTOFMEMORY:
07790       ast_cli(a->fd, "Out of memory\n");
07791       return CLI_FAILURE;
07792    case RES_NOT_DYNAMIC:
07793       ast_cli(a->fd, "Member not dynamic\n");
07794       return CLI_FAILURE;
07795    default:
07796       return CLI_FAILURE;
07797    }
07798 }
07799 
07800 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
07801 {
07802    int which = 0;
07803    struct call_queue *q;
07804    struct member *m;
07805    struct ao2_iterator queue_iter;
07806    struct ao2_iterator mem_iter;
07807    int wordlen = strlen(word);
07808 
07809    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
07810    if (pos > 5 || pos < 3)
07811       return NULL;
07812    if (pos == 4)   /* only one possible match, 'from' */
07813       return (state == 0 ? ast_strdup("from") : NULL);
07814 
07815    if (pos == 5) {  /* No need to duplicate code */
07816       return complete_queue(line, word, pos, state, 0);
07817    }
07818 
07819    /* here is the case for 3, <member> */
07820    queue_iter = ao2_iterator_init(queues, 0);
07821    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07822       ao2_lock(q);
07823       mem_iter = ao2_iterator_init(q->members, 0);
07824       while ((m = ao2_iterator_next(&mem_iter))) {
07825          if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
07826             char *tmp;
07827             tmp = ast_strdup(m->interface);
07828             ao2_ref(m, -1);
07829             ao2_iterator_destroy(&mem_iter);
07830             ao2_unlock(q);
07831             queue_t_unref(q, "Done with iterator, returning interface name");
07832             ao2_iterator_destroy(&queue_iter);
07833             return tmp;
07834          }
07835          ao2_ref(m, -1);
07836       }
07837       ao2_iterator_destroy(&mem_iter);
07838       ao2_unlock(q);
07839       queue_t_unref(q, "Done with iterator");
07840    }
07841    ao2_iterator_destroy(&queue_iter);
07842 
07843    return NULL;
07844 }
07845 
07846 static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07847 {
07848    const char *queuename, *interface;
07849 
07850    switch (cmd) {
07851    case CLI_INIT:
07852       e->command = "queue remove member";
07853       e->usage = 
07854          "Usage: queue remove member <channel> from <queue>\n"
07855          "       Remove a specific channel from a queue.\n";
07856       return NULL;
07857    case CLI_GENERATE:
07858       return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
07859    }
07860 
07861    if (a->argc != 6) {
07862       return CLI_SHOWUSAGE;
07863    } else if (strcmp(a->argv[4], "from")) {
07864       return CLI_SHOWUSAGE;
07865    }
07866 
07867    queuename = a->argv[5];
07868    interface = a->argv[3];
07869 
07870    switch (remove_from_queue(queuename, interface)) {
07871    case RES_OKAY:
07872       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
07873       ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
07874       return CLI_SUCCESS;
07875    case RES_EXISTS:
07876       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
07877       return CLI_FAILURE;
07878    case RES_NOSUCHQUEUE:
07879       ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
07880       return CLI_FAILURE;
07881    case RES_OUTOFMEMORY:
07882       ast_cli(a->fd, "Out of memory\n");
07883       return CLI_FAILURE;
07884    case RES_NOT_DYNAMIC:
07885       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
07886       return CLI_FAILURE;
07887    default:
07888       return CLI_FAILURE;
07889    }
07890 }
07891 
07892 static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
07893 {
07894    /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
07895    switch (pos) {
07896    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
07897       return NULL;
07898    case 4:  /* only one possible match, "queue" */
07899       return state == 0 ? ast_strdup("queue") : NULL;
07900    case 5:  /* <queue> */
07901       return complete_queue(line, word, pos, state, 0);
07902    case 6: /* "reason" */
07903       return state == 0 ? ast_strdup("reason") : NULL;
07904    case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
07905       return NULL;
07906    default:
07907       return NULL;
07908    }
07909 }
07910 
07911 static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07912 {
07913    const char *queuename, *interface, *reason;
07914    int paused;
07915 
07916    switch (cmd) {
07917    case CLI_INIT:
07918       e->command = "queue {pause|unpause} member";
07919       e->usage = 
07920          "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
07921          "  Pause or unpause a queue member. Not specifying a particular queue\n"
07922          "  will pause or unpause a member across all queues to which the member\n"
07923          "  belongs.\n";
07924       return NULL;
07925    case CLI_GENERATE:
07926       return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
07927    }
07928 
07929    if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
07930       return CLI_SHOWUSAGE;
07931    } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
07932       return CLI_SHOWUSAGE;
07933    } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
07934       return CLI_SHOWUSAGE;
07935    }
07936 
07937 
07938    interface = a->argv[3];
07939    queuename = a->argc >= 6 ? a->argv[5] : NULL;
07940    reason = a->argc == 8 ? a->argv[7] : NULL;
07941    paused = !strcasecmp(a->argv[1], "pause");
07942 
07943    if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
07944       ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
07945       if (!ast_strlen_zero(queuename))
07946          ast_cli(a->fd, " in queue '%s'", queuename);
07947       if (!ast_strlen_zero(reason))
07948          ast_cli(a->fd, " for reason '%s'", reason);
07949       ast_cli(a->fd, "\n");
07950       return CLI_SUCCESS;
07951    } else {
07952       ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
07953       if (!ast_strlen_zero(queuename))
07954          ast_cli(a->fd, " in queue '%s'", queuename);
07955       if (!ast_strlen_zero(reason))
07956          ast_cli(a->fd, " for reason '%s'", reason);
07957       ast_cli(a->fd, "\n");
07958       return CLI_FAILURE;
07959    }
07960 }
07961 
07962 static char *complete_queue_set_member_penalty(const char *line, const char *word, int pos, int state)
07963 {
07964    /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
07965    switch (pos) {
07966    case 4:
07967       if (state == 0) {
07968          return ast_strdup("on");
07969       } else {
07970          return NULL;
07971       }
07972    case 6:
07973       if (state == 0) {
07974          return ast_strdup("in");
07975       } else {
07976          return NULL;
07977       }
07978    case 7:
07979       return complete_queue(line, word, pos, state, 0);
07980    default:
07981       return NULL;
07982    }
07983 }
07984  
07985 static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07986 {
07987    const char *queuename = NULL, *interface;
07988    int penalty = 0;
07989 
07990    switch (cmd) {
07991    case CLI_INIT:
07992       e->command = "queue set penalty";
07993       e->usage = 
07994       "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
07995       "  Set a member's penalty in the queue specified. If no queue is specified\n"
07996       "  then that interface's penalty is set in all queues to which that interface is a member\n";
07997       return NULL;
07998    case CLI_GENERATE:
07999       return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
08000    }
08001 
08002    if (a->argc != 6 && a->argc != 8) {
08003       return CLI_SHOWUSAGE;
08004    } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
08005       return CLI_SHOWUSAGE;
08006    }
08007 
08008    if (a->argc == 8)
08009       queuename = a->argv[7];
08010    interface = a->argv[5];
08011    penalty = atoi(a->argv[3]);
08012 
08013    switch (set_member_penalty(queuename, interface, penalty)) {
08014    case RESULT_SUCCESS:
08015       ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
08016       return CLI_SUCCESS;
08017    case RESULT_FAILURE:
08018       ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
08019       return CLI_FAILURE;
08020    default:
08021       return CLI_FAILURE;
08022    }
08023 }
08024 
08025 static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state) 
08026 {
08027    int which = 0;
08028    struct rule_list *rl_iter;
08029    int wordlen = strlen(word);
08030    char *ret = NULL;
08031    if (pos != 3) /* Wha? */ {
08032       return NULL;
08033    }
08034 
08035    AST_LIST_LOCK(&rule_lists);
08036    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
08037       if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
08038          ret = ast_strdup(rl_iter->name);
08039          break;
08040       }
08041    }
08042    AST_LIST_UNLOCK(&rule_lists);
08043 
08044    return ret;
08045 }
08046 
08047 static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08048 {
08049    const char *rule;
08050    struct rule_list *rl_iter;
08051    struct penalty_rule *pr_iter;
08052    switch (cmd) {
08053    case CLI_INIT:
08054       e->command = "queue show rules";
08055       e->usage =
08056       "Usage: queue show rules [rulename]\n"
08057       "  Show the list of rules associated with rulename. If no\n"
08058       "  rulename is specified, list all rules defined in queuerules.conf\n";
08059       return NULL;
08060    case CLI_GENERATE:
08061       return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
08062    }
08063 
08064    if (a->argc != 3 && a->argc != 4)
08065       return CLI_SHOWUSAGE;
08066 
08067    rule = a->argc == 4 ? a->argv[3] : "";
08068    AST_LIST_LOCK(&rule_lists);
08069    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
08070       if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
08071          ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
08072          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
08073             ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value);
08074          }
08075       }
08076    }
08077    AST_LIST_UNLOCK(&rule_lists);
08078    return CLI_SUCCESS; 
08079 }
08080 
08081 static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08082 {
08083    struct ast_flags mask = {QUEUE_RESET_STATS,};
08084    int i;
08085 
08086    switch (cmd) {
08087       case CLI_INIT:
08088          e->command = "queue reset stats";
08089          e->usage =
08090             "Usage: queue reset stats [<queuenames>]\n"
08091             "\n"
08092             "Issuing this command will reset statistics for\n"
08093             "<queuenames>, or for all queues if no queue is\n"
08094             "specified.\n";
08095          return NULL;
08096       case CLI_GENERATE:
08097          if (a->pos >= 3) {
08098             return complete_queue(a->line, a->word, a->pos, a->n, 17);
08099          } else {
08100             return NULL;
08101          }
08102    }
08103 
08104    if (a->argc < 3) {
08105       return CLI_SHOWUSAGE;
08106    }
08107 
08108    if (a->argc == 3) {
08109       reload_handler(1, &mask, NULL);
08110       return CLI_SUCCESS;
08111    }
08112 
08113    for (i = 3; i < a->argc; ++i) {
08114       reload_handler(1, &mask, a->argv[i]);
08115    }
08116 
08117    return CLI_SUCCESS;
08118 }
08119 
08120 static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
08121 {
08122    struct ast_flags mask = {0,};
08123    int i;
08124 
08125    switch (cmd) {
08126       case CLI_INIT:
08127          e->command = "queue reload {parameters|members|rules|all}";
08128          e->usage =
08129             "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
08130             "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
08131             "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
08132             "specified in order to know what information to reload. Below is an explanation\n"
08133             "of each of these qualifiers.\n"
08134             "\n"
08135             "\t'members' - reload queue members from queues.conf\n"
08136             "\t'parameters' - reload all queue options except for queue members\n"
08137             "\t'rules' - reload the queuerules.conf file\n"
08138             "\t'all' - reload queue rules, parameters, and members\n"
08139             "\n"
08140             "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
08141             "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
08142             "one queue is specified when using this command, reloading queue rules may cause\n"
08143             "other queues to be affected\n";
08144          return NULL;
08145       case CLI_GENERATE:
08146          if (a->pos >= 3) {
08147             /* find the point at which the list of queue names starts */
08148             const char *command_end = a->line + strlen("queue reload ");
08149             command_end = strchr(command_end, ' ');
08150             if (!command_end) {
08151                command_end = a->line + strlen(a->line);
08152             }
08153             return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
08154          } else {
08155             return NULL;
08156          }
08157    }
08158 
08159    if (a->argc < 3)
08160       return CLI_SHOWUSAGE;
08161 
08162    if (!strcasecmp(a->argv[2], "rules")) {
08163       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
08164    } else if (!strcasecmp(a->argv[2], "members")) {
08165       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
08166    } else if (!strcasecmp(a->argv[2], "parameters")) {
08167       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
08168    } else if (!strcasecmp(a->argv[2], "all")) {
08169       ast_set_flag(&mask, AST_FLAGS_ALL);
08170    }
08171 
08172    if (a->argc == 3) {
08173       reload_handler(1, &mask, NULL);
08174       return CLI_SUCCESS;
08175    }
08176 
08177    for (i = 3; i < a->argc; ++i) {
08178       reload_handler(1, &mask, a->argv[i]);
08179    }
08180 
08181    return CLI_SUCCESS;
08182 }
08183 
08184 static const char qpm_cmd_usage[] = 
08185 "Usage: queue pause member <channel> in <queue> reason <reason>\n";
08186 
08187 static const char qum_cmd_usage[] =
08188 "Usage: queue unpause member <channel> in <queue> reason <reason>\n";
08189 
08190 static const char qsmp_cmd_usage[] =
08191 "Usage: queue set member penalty <channel> from <queue> <penalty>\n";
08192 
08193 static struct ast_cli_entry cli_queue[] = {
08194    AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
08195    AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
08196    AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
08197    AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
08198    AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
08199    AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
08200    AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
08201    AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
08202 };
08203 
08204 /* struct call_queue astdata mapping. */
08205 #define DATA_EXPORT_CALL_QUEUE(MEMBER)             \
08206    MEMBER(call_queue, name, AST_DATA_STRING)       \
08207    MEMBER(call_queue, moh, AST_DATA_STRING)        \
08208    MEMBER(call_queue, announce, AST_DATA_STRING)         \
08209    MEMBER(call_queue, context, AST_DATA_STRING)       \
08210    MEMBER(call_queue, membermacro, AST_DATA_STRING)      \
08211    MEMBER(call_queue, membergosub, AST_DATA_STRING)      \
08212    MEMBER(call_queue, defaultrule, AST_DATA_STRING)      \
08213    MEMBER(call_queue, sound_next, AST_DATA_STRING)       \
08214    MEMBER(call_queue, sound_thereare, AST_DATA_STRING)      \
08215    MEMBER(call_queue, sound_calls, AST_DATA_STRING)      \
08216    MEMBER(call_queue, queue_quantity1, AST_DATA_STRING)     \
08217    MEMBER(call_queue, queue_quantity2, AST_DATA_STRING)     \
08218    MEMBER(call_queue, sound_holdtime, AST_DATA_STRING)      \
08219    MEMBER(call_queue, sound_minutes, AST_DATA_STRING)    \
08220    MEMBER(call_queue, sound_minute, AST_DATA_STRING)     \
08221    MEMBER(call_queue, sound_seconds, AST_DATA_STRING)    \
08222    MEMBER(call_queue, sound_thanks, AST_DATA_STRING)     \
08223    MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING)   \
08224    MEMBER(call_queue, sound_reporthold, AST_DATA_STRING)    \
08225    MEMBER(call_queue, dead, AST_DATA_BOOLEAN)         \
08226    MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN)    \
08227    MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN)       \
08228    MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN)    \
08229    MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN)     \
08230    MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN)      \
08231    MEMBER(call_queue, reportholdtime, AST_DATA_BOOLEAN)     \
08232    MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN)         \
08233    MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN)     \
08234    MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER)      \
08235    MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN)      \
08236    MEMBER(call_queue, realtime, AST_DATA_BOOLEAN)        \
08237    MEMBER(call_queue, found, AST_DATA_BOOLEAN)        \
08238    MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \
08239    MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS)     \
08240    MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS)  \
08241    MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS)   \
08242    MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER)   \
08243    MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER)   \
08244    MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS)    \
08245    MEMBER(call_queue, holdtime, AST_DATA_SECONDS)        \
08246    MEMBER(call_queue, talktime, AST_DATA_SECONDS)        \
08247    MEMBER(call_queue, callscompleted, AST_DATA_INTEGER)     \
08248    MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER)     \
08249    MEMBER(call_queue, servicelevel, AST_DATA_INTEGER)    \
08250    MEMBER(call_queue, callscompletedinsl, AST_DATA_INTEGER) \
08251    MEMBER(call_queue, monfmt, AST_DATA_STRING)        \
08252    MEMBER(call_queue, montype, AST_DATA_INTEGER)         \
08253    MEMBER(call_queue, count, AST_DATA_INTEGER)        \
08254    MEMBER(call_queue, maxlen, AST_DATA_INTEGER)       \
08255    MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS)      \
08256    MEMBER(call_queue, retry, AST_DATA_SECONDS)        \
08257    MEMBER(call_queue, timeout, AST_DATA_SECONDS)         \
08258    MEMBER(call_queue, weight, AST_DATA_INTEGER)       \
08259    MEMBER(call_queue, autopause, AST_DATA_INTEGER)       \
08260    MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER)    \
08261    MEMBER(call_queue, rrpos, AST_DATA_INTEGER)        \
08262    MEMBER(call_queue, memberdelay, AST_DATA_INTEGER)     \
08263    MEMBER(call_queue, autofill, AST_DATA_INTEGER)        \
08264    MEMBER(call_queue, members, AST_DATA_CONTAINER)
08265 
08266 AST_DATA_STRUCTURE(call_queue, DATA_EXPORT_CALL_QUEUE);
08267 
08268 /* struct member astdata mapping. */
08269 #define DATA_EXPORT_MEMBER(MEMBER)              \
08270    MEMBER(member, interface, AST_DATA_STRING)         \
08271    MEMBER(member, state_interface, AST_DATA_STRING)      \
08272    MEMBER(member, membername, AST_DATA_STRING)        \
08273    MEMBER(member, penalty, AST_DATA_INTEGER)       \
08274    MEMBER(member, calls, AST_DATA_INTEGER)            \
08275    MEMBER(member, dynamic, AST_DATA_INTEGER)       \
08276    MEMBER(member, realtime, AST_DATA_INTEGER)         \
08277    MEMBER(member, status, AST_DATA_INTEGER)        \
08278    MEMBER(member, paused, AST_DATA_BOOLEAN)        \
08279    MEMBER(member, rt_uniqueid, AST_DATA_STRING)
08280 
08281 AST_DATA_STRUCTURE(member, DATA_EXPORT_MEMBER);
08282 
08283 #define DATA_EXPORT_QUEUE_ENT(MEMBER)                 \
08284    MEMBER(queue_ent, moh, AST_DATA_STRING)               \
08285    MEMBER(queue_ent, announce, AST_DATA_STRING)          \
08286    MEMBER(queue_ent, context, AST_DATA_STRING)           \
08287    MEMBER(queue_ent, digits, AST_DATA_STRING)            \
08288    MEMBER(queue_ent, valid_digits, AST_DATA_INTEGER)        \
08289    MEMBER(queue_ent, pos, AST_DATA_INTEGER)           \
08290    MEMBER(queue_ent, prio, AST_DATA_INTEGER)          \
08291    MEMBER(queue_ent, last_pos_said, AST_DATA_INTEGER)       \
08292    MEMBER(queue_ent, last_periodic_announce_time, AST_DATA_INTEGER)  \
08293    MEMBER(queue_ent, last_periodic_announce_sound, AST_DATA_INTEGER) \
08294    MEMBER(queue_ent, last_pos, AST_DATA_INTEGER)            \
08295    MEMBER(queue_ent, opos, AST_DATA_INTEGER)          \
08296    MEMBER(queue_ent, handled, AST_DATA_INTEGER)          \
08297    MEMBER(queue_ent, pending, AST_DATA_INTEGER)          \
08298    MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER)         \
08299    MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER)         \
08300    MEMBER(queue_ent, linpos, AST_DATA_INTEGER)           \
08301    MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER)          \
08302    MEMBER(queue_ent, start, AST_DATA_INTEGER)            \
08303    MEMBER(queue_ent, expire, AST_DATA_INTEGER)           \
08304    MEMBER(queue_ent, cancel_answered_elsewhere, AST_DATA_INTEGER)
08305 
08306 AST_DATA_STRUCTURE(queue_ent, DATA_EXPORT_QUEUE_ENT);
08307 
08308 /*!
08309  * \internal
08310  * \brief Add a queue to the data_root node.
08311  * \param[in] search The search tree.
08312  * \param[in] data_root The main result node.
08313  * \param[in] queue The queue to add.
08314  */
08315 static void queues_data_provider_get_helper(const struct ast_data_search *search,
08316    struct ast_data *data_root, struct call_queue *queue)
08317 {
08318    struct ao2_iterator im;
08319    struct member *member;
08320    struct queue_ent *qe;
08321    struct ast_data *data_queue, *data_members = NULL, *enum_node;
08322    struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
08323 
08324    data_queue = ast_data_add_node(data_root, "queue");
08325    if (!data_queue) {
08326       return;
08327    }
08328 
08329    ast_data_add_structure(call_queue, data_queue, queue);
08330 
08331    ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
08332    ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members));
08333 
08334    /* announce position */
08335    enum_node = ast_data_add_node(data_queue, "announceposition");
08336    if (!enum_node) {
08337       return;
08338    }
08339    switch (queue->announceposition) {
08340    case ANNOUNCEPOSITION_LIMIT:
08341       ast_data_add_str(enum_node, "text", "limit");
08342       break;
08343    case ANNOUNCEPOSITION_MORE_THAN:
08344       ast_data_add_str(enum_node, "text", "more");
08345       break;
08346    case ANNOUNCEPOSITION_YES:
08347       ast_data_add_str(enum_node, "text", "yes");
08348       break;
08349    case ANNOUNCEPOSITION_NO:
08350       ast_data_add_str(enum_node, "text", "no");
08351       break;
08352    default:
08353       ast_data_add_str(enum_node, "text", "unknown");
08354       break;
08355    }
08356    ast_data_add_int(enum_node, "value", queue->announceposition);
08357 
08358    /* add queue members */
08359    im = ao2_iterator_init(queue->members, 0);
08360    while ((member = ao2_iterator_next(&im))) {
08361       if (!data_members) {
08362          data_members = ast_data_add_node(data_queue, "members");
08363          if (!data_members) {
08364             ao2_ref(member, -1);
08365             continue;
08366          }
08367       }
08368 
08369       data_member = ast_data_add_node(data_members, "member");
08370       if (!data_member) {
08371          ao2_ref(member, -1);
08372          continue;
08373       }
08374 
08375       ast_data_add_structure(member, data_member, member);
08376 
08377       ao2_ref(member, -1);
08378    }
08379    ao2_iterator_destroy(&im);
08380 
08381    /* include the callers inside the result. */
08382    if (queue->head) {
08383       for (qe = queue->head; qe; qe = qe->next) {
08384          if (!data_callers) {
08385             data_callers = ast_data_add_node(data_queue, "callers");
08386             if (!data_callers) {
08387                continue;
08388             }
08389          }
08390 
08391          data_caller = ast_data_add_node(data_callers, "caller");
08392          if (!data_caller) {
08393             continue;
08394          }
08395 
08396          ast_data_add_structure(queue_ent, data_caller, qe);
08397 
08398          /* add the caller channel. */
08399          data_caller_channel = ast_data_add_node(data_caller, "channel");
08400          if (!data_caller_channel) {
08401             continue;
08402          }
08403 
08404          ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
08405       }
08406    }
08407 
08408    /* if this queue doesn't match remove the added queue. */
08409    if (!ast_data_search_match(search, data_queue)) {
08410       ast_data_remove_node(data_root, data_queue);
08411    }
08412 }
08413 
08414 /*!
08415  * \internal
08416  * \brief Callback used to generate the queues tree.
08417  * \param[in] search The search pattern tree.
08418  * \retval NULL on error.
08419  * \retval non-NULL The generated tree.
08420  */
08421 static int queues_data_provider_get(const struct ast_data_search *search,
08422    struct ast_data *data_root)
08423 {
08424    struct ao2_iterator i;
08425    struct call_queue *queue, *queue_realtime = NULL;
08426    struct ast_config *cfg;
08427    char *queuename;
08428 
08429    /* load realtime queues. */
08430    cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
08431    if (cfg) {
08432       for (queuename = ast_category_browse(cfg, NULL);
08433             !ast_strlen_zero(queuename);
08434             queuename = ast_category_browse(cfg, queuename)) {
08435          if ((queue = load_realtime_queue(queuename))) {
08436             queue_unref(queue);
08437          }
08438       }
08439       ast_config_destroy(cfg);
08440    }
08441 
08442    /* static queues. */
08443    i = ao2_iterator_init(queues, 0);
08444    while ((queue = ao2_iterator_next(&i))) {
08445       ao2_lock(queue);
08446       if (queue->realtime) {
08447          queue_realtime = load_realtime_queue(queue->name);
08448          if (!queue_realtime) {
08449             ao2_unlock(queue);
08450             queue_unref(queue);
08451             continue;
08452          }
08453          queue_unref(queue_realtime);
08454       }
08455 
08456       queues_data_provider_get_helper(search, data_root, queue);
08457       ao2_unlock(queue);
08458       queue_unref(queue);
08459    }
08460    ao2_iterator_destroy(&i);
08461 
08462    return 0;
08463 }
08464 
08465 static const struct ast_data_handler queues_data_provider = {
08466    .version = AST_DATA_HANDLER_VERSION,
08467    .get = queues_data_provider_get
08468 };
08469 
08470 static const struct ast_data_entry queue_data_providers[] = {
08471    AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
08472 };
08473 
08474 static int unload_module(void)
08475 {
08476    int res;
08477    struct ast_context *con;
08478    struct ao2_iterator q_iter;
08479    struct call_queue *q = NULL;
08480 
08481    ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
08482    res = ast_manager_unregister("QueueStatus");
08483    res |= ast_manager_unregister("Queues");
08484    res |= ast_manager_unregister("QueueRule");
08485    res |= ast_manager_unregister("QueueSummary");
08486    res |= ast_manager_unregister("QueueAdd");
08487    res |= ast_manager_unregister("QueueRemove");
08488    res |= ast_manager_unregister("QueuePause");
08489    res |= ast_manager_unregister("QueueLog");
08490    res |= ast_manager_unregister("QueuePenalty");
08491    res |= ast_unregister_application(app_aqm);
08492    res |= ast_unregister_application(app_rqm);
08493    res |= ast_unregister_application(app_pqm);
08494    res |= ast_unregister_application(app_upqm);
08495    res |= ast_unregister_application(app_ql);
08496    res |= ast_unregister_application(app);
08497    res |= ast_custom_function_unregister(&queueexists_function);
08498    res |= ast_custom_function_unregister(&queuevar_function);
08499    res |= ast_custom_function_unregister(&queuemembercount_function);
08500    res |= ast_custom_function_unregister(&queuemembercount_dep);
08501    res |= ast_custom_function_unregister(&queuememberlist_function);
08502    res |= ast_custom_function_unregister(&queuewaitingcount_function);
08503    res |= ast_custom_function_unregister(&queuememberpenalty_function);
08504 
08505    res |= ast_data_unregister(NULL);
08506 
08507    if (device_state_sub)
08508       ast_event_unsubscribe(device_state_sub);
08509 
08510    ast_extension_state_del(0, extension_state_cb);
08511 
08512    if ((con = ast_context_find("app_queue_gosub_virtual_context"))) {
08513       ast_context_remove_extension2(con, "s", 1, NULL, 0);
08514       ast_context_destroy(con, "app_queue"); /* leave no trace */
08515    }
08516 
08517    q_iter = ao2_iterator_init(queues, 0);
08518    while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
08519       queues_t_unlink(queues, q, "Remove queue from container due to unload");
08520       queue_t_unref(q, "Done with iterator");
08521    }
08522    ao2_iterator_destroy(&q_iter);
08523    devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
08524    ao2_ref(queues, -1);
08525    ast_unload_realtime("queue_members");
08526    return res;
08527 }
08528 
08529 static int load_module(void)
08530 {
08531    int res;
08532    struct ast_context *con;
08533    struct ast_flags mask = {AST_FLAGS_ALL, };
08534 
08535    queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
08536 
08537    use_weight = 0;
08538 
08539    if (reload_handler(0, &mask, NULL))
08540       return AST_MODULE_LOAD_DECLINE;
08541 
08542    con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
08543    if (!con)
08544       ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
08545    else
08546       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue");
08547 
08548    if (queue_persistent_members)
08549       reload_queue_members();
08550 
08551    ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
08552 
08553    ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
08554    res = ast_register_application_xml(app, queue_exec);
08555    res |= ast_register_application_xml(app_aqm, aqm_exec);
08556    res |= ast_register_application_xml(app_rqm, rqm_exec);
08557    res |= ast_register_application_xml(app_pqm, pqm_exec);
08558    res |= ast_register_application_xml(app_upqm, upqm_exec);
08559    res |= ast_register_application_xml(app_ql, ql_exec);
08560    res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
08561    res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
08562    res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
08563    res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
08564    res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
08565    res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
08566    res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
08567    res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
08568    res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
08569    res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
08570    res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
08571    res |= ast_custom_function_register(&queuevar_function);
08572    res |= ast_custom_function_register(&queueexists_function);
08573    res |= ast_custom_function_register(&queuemembercount_function);
08574    res |= ast_custom_function_register(&queuemembercount_dep);
08575    res |= ast_custom_function_register(&queuememberlist_function);
08576    res |= ast_custom_function_register(&queuewaitingcount_function);
08577    res |= ast_custom_function_register(&queuememberpenalty_function);
08578 
08579    if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
08580       ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
08581    }
08582 
08583    /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
08584    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
08585       res = -1;
08586    }
08587 
08588    ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
08589 
08590    ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
08591 
08592    return res ? AST_MODULE_LOAD_DECLINE : 0;
08593 }
08594 
08595 static int reload(void)
08596 {
08597    struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
08598    ast_unload_realtime("queue_members");
08599    reload_handler(1, &mask, NULL);
08600    return 0;
08601 }
08602 
08603 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
08604       .load = load_module,
08605       .unload = unload_module,
08606       .reload = reload,
08607       .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
08608       .nonoptreq = "res_monitor",
08609           );
08610