Mon Jun 18 2012 03:55:20

Asterisk developer's documentation


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