Sat Feb 11 06:33:02 2012

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

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