Mon Mar 12 2012 21:18:39

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: 350606 $")
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_unlock(q);
01399             ao2_ref(member, -1);
01400             ao2_iterator_destroy(&mem_iter);
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                      ast_channel_update_connected_line(in, &connected_caller, NULL);
03532                      ast_party_connected_line_free(&connected_caller);
03533                   }
03534                }
03535                if (o->aoc_s_rate_list) {
03536                   size_t encoded_size;
03537                   struct ast_aoc_encoded *encoded;
03538                   if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03539                      ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03540                      ast_aoc_destroy_encoded(encoded);
03541                   }
03542                }
03543                peer = o;
03544             }
03545          } else if (o->chan && (o->chan == winner)) {
03546 
03547             ast_copy_string(on, o->member->interface, sizeof(on));
03548             ast_copy_string(membername, o->member->membername, sizeof(membername));
03549 
03550             if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
03551                ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, o->chan->call_forward);
03552                numnochan++;
03553                do_hang(o);
03554                winner = NULL;
03555                continue;
03556             } else if (!ast_strlen_zero(o->chan->call_forward)) {
03557                struct ast_channel *original = o->chan;
03558                char tmpchan[256];
03559                char *stuff;
03560                char *tech;
03561 
03562                ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
03563                if ((stuff = strchr(tmpchan, '/'))) {
03564                   *stuff++ = '\0';
03565                   tech = tmpchan;
03566                } else {
03567                   snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
03568                   stuff = tmpchan;
03569                   tech = "Local";
03570                }
03571 
03572                ast_cel_report_event(in, AST_CEL_FORWARD, NULL, o->chan->call_forward, NULL);
03573 
03574                /* Before processing channel, go ahead and check for forwarding */
03575                ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
03576                /* Setup parameters */
03577                o->chan = ast_request(tech, in->nativeformats, in, stuff, &status);
03578                if (!o->chan) {
03579                   ast_log(LOG_NOTICE,
03580                      "Forwarding failed to create channel to dial '%s/%s'\n",
03581                      tech, stuff);
03582                   o->stillgoing = 0;
03583                   numnochan++;
03584                } else {
03585                   struct ast_party_redirecting redirecting;
03586 
03587                   ast_channel_lock_both(o->chan, in);
03588                   ast_channel_inherit_variables(in, o->chan);
03589                   ast_channel_datastore_inherit(in, o->chan);
03590 
03591                   ast_string_field_set(o->chan, accountcode, in->accountcode);
03592 
03593                   ast_channel_set_redirecting(o->chan, &original->redirecting, NULL);
03594                   if (!o->chan->redirecting.from.number.valid
03595                      || ast_strlen_zero(o->chan->redirecting.from.number.str)) {
03596                      /*
03597                       * The call was not previously redirected so it is
03598                       * now redirected from this number.
03599                       */
03600                      ast_party_number_free(&o->chan->redirecting.from.number);
03601                      ast_party_number_init(&o->chan->redirecting.from.number);
03602                      o->chan->redirecting.from.number.valid = 1;
03603                      o->chan->redirecting.from.number.str =
03604                         ast_strdup(S_OR(in->macroexten, in->exten));
03605                   }
03606 
03607                   o->chan->dialed.transit_network_select = in->dialed.transit_network_select;
03608 
03609                   ast_party_caller_copy(&o->chan->caller, &in->caller);
03610                   ast_party_connected_line_copy(&o->chan->connected, &original->connected);
03611 
03612                   /*
03613                    * We must unlock o->chan before calling
03614                    * ast_channel_redirecting_macro, because we put o->chan into
03615                    * autoservice there.  That is pretty much a guaranteed
03616                    * deadlock.  This is why the handling of o->chan's lock may
03617                    * seem a bit unusual here.
03618                    */
03619                   ast_party_redirecting_init(&redirecting);
03620                   ast_party_redirecting_copy(&redirecting, &o->chan->redirecting);
03621                   ast_channel_unlock(o->chan);
03622                   res = ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0);
03623                   if (res) {
03624                      ast_channel_update_redirecting(in, &redirecting, NULL);
03625                   }
03626                   ast_party_redirecting_free(&redirecting);
03627                   ast_channel_unlock(in);
03628 
03629                   update_connectedline = 1;
03630 
03631                   if (ast_call(o->chan, stuff, 0)) {
03632                      ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
03633                         tech, stuff);
03634                      do_hang(o);
03635                      numnochan++;
03636                   }
03637                }
03638                /* Hangup the original channel now, in case we needed it */
03639                ast_hangup(winner);
03640                continue;
03641             }
03642             f = ast_read(winner);
03643             if (f) {
03644                if (f->frametype == AST_FRAME_CONTROL) {
03645                   switch (f->subclass.integer) {
03646                   case AST_CONTROL_ANSWER:
03647                      /* This is our guy if someone answered. */
03648                      if (!peer) {
03649                         ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
03650                         if (update_connectedline) {
03651                            if (o->pending_connected_update) {
03652                               if (ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
03653                                  ast_channel_update_connected_line(in, &o->connected, NULL);
03654                               }
03655                            } else if (!o->dial_callerid_absent) {
03656                               ast_channel_lock(o->chan);
03657                               ast_connected_line_copy_from_caller(&connected_caller, &o->chan->caller);
03658                               ast_channel_unlock(o->chan);
03659                               connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
03660                               ast_channel_update_connected_line(in, &connected_caller, NULL);
03661                               ast_party_connected_line_free(&connected_caller);
03662                            }
03663                         }
03664                         if (o->aoc_s_rate_list) {
03665                            size_t encoded_size;
03666                            struct ast_aoc_encoded *encoded;
03667                            if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
03668                               ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
03669                               ast_aoc_destroy_encoded(encoded);
03670                            }
03671                         }
03672                         peer = o;
03673                      }
03674                      break;
03675                   case AST_CONTROL_BUSY:
03676                      ast_verb(3, "%s is busy\n", ochan_name);
03677                      if (in->cdr)
03678                         ast_cdr_busy(in->cdr);
03679                      do_hang(o);
03680                      endtime = (long) time(NULL);
03681                      endtime -= starttime;
03682                      rna(endtime * 1000, qe, on, membername, 0);
03683                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03684                         if (qe->parent->timeoutrestart)
03685                            *to = orig;
03686                         /* Have enough time for a queue member to answer? */
03687                         if (*to > 500) {
03688                            ring_one(qe, outgoing, &numbusies);
03689                            starttime = (long) time(NULL);
03690                         }
03691                      }
03692                      numbusies++;
03693                      break;
03694                   case AST_CONTROL_CONGESTION:
03695                      ast_verb(3, "%s is circuit-busy\n", ochan_name);
03696                      if (in->cdr)
03697                         ast_cdr_busy(in->cdr);
03698                      endtime = (long) time(NULL);
03699                      endtime -= starttime;
03700                      rna(endtime * 1000, qe, on, membername, 0);
03701                      do_hang(o);
03702                      if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03703                         if (qe->parent->timeoutrestart)
03704                            *to = orig;
03705                         if (*to > 500) {
03706                            ring_one(qe, outgoing, &numbusies);
03707                            starttime = (long) time(NULL);
03708                         }
03709                      }
03710                      numbusies++;
03711                      break;
03712                   case AST_CONTROL_RINGING:
03713                      ast_verb(3, "%s is ringing\n", ochan_name);
03714 
03715                      /* Start ring indication when the channel is ringing, if specified */
03716                      if (qe->ring_when_ringing) {
03717                         ast_moh_stop(qe->chan);
03718                         ast_indicate(qe->chan, AST_CONTROL_RINGING);
03719                      }
03720                      break;
03721                   case AST_CONTROL_OFFHOOK:
03722                      /* Ignore going off hook */
03723                      break;
03724                   case AST_CONTROL_CONNECTED_LINE:
03725                      if (!update_connectedline) {
03726                         ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
03727                      } else if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
03728                         struct ast_party_connected_line connected;
03729                         ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
03730                         ast_party_connected_line_set_init(&connected, &o->connected);
03731                         ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
03732                         ast_party_connected_line_set(&o->connected, &connected, NULL);
03733                         ast_party_connected_line_free(&connected);
03734                         o->pending_connected_update = 1;
03735                      } else {
03736                         if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
03737                            ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
03738                         }
03739                      }
03740                      break;
03741                   case AST_CONTROL_AOC:
03742                      {
03743                         struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
03744                         if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
03745                            ast_aoc_destroy_decoded(o->aoc_s_rate_list);
03746                            o->aoc_s_rate_list = decoded;
03747                         } else {
03748                            ast_aoc_destroy_decoded(decoded);
03749                         }
03750                      }
03751                      break;
03752                   case AST_CONTROL_REDIRECTING:
03753                      if (!update_connectedline) {
03754                         ast_verb(3, "Redirecting update to %s prevented\n", inchan_name);
03755                      } else if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03756                         ast_verb(3, "%s redirecting info has changed, passing it to %s\n", ochan_name, inchan_name);
03757                         if (ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
03758                            ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
03759                         }
03760                      }
03761                      break;
03762                   default:
03763                      ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
03764                      break;
03765                   }
03766                }
03767                ast_frfree(f);
03768             } else { /* ast_read() returned NULL */
03769                endtime = (long) time(NULL) - starttime;
03770                rna(endtime * 1000, qe, on, membername, 1);
03771                do_hang(o);
03772                if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
03773                   if (qe->parent->timeoutrestart)
03774                      *to = orig;
03775                   if (*to > 500) {
03776                      ring_one(qe, outgoing, &numbusies);
03777                      starttime = (long) time(NULL);
03778                   }
03779                }
03780             }
03781          }
03782       }
03783 
03784       /* If we received an event from the caller, deal with it. */
03785       if (winner == in) {
03786          f = ast_read(in);
03787          if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
03788             /* Got hung up */
03789             *to = -1;
03790             if (f) {
03791                if (f->data.uint32) {
03792                   in->hangupcause = f->data.uint32;
03793                }
03794                ast_frfree(f);
03795             }
03796             return NULL;
03797          }
03798          if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
03799             ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
03800             *to = 0;
03801             ast_frfree(f);
03802             return NULL;
03803          }
03804          if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
03805             ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
03806             *to = 0;
03807             *digit = f->subclass.integer;
03808             ast_frfree(f);
03809             return NULL;
03810          }
03811          ast_frfree(f);
03812       }
03813       if (!*to) {
03814          for (o = start; o; o = o->call_next)
03815             rna(orig, qe, o->interface, o->member->membername, 1);
03816       }
03817    }
03818 
03819 #ifdef HAVE_EPOLL
03820    for (epollo = outgoing; epollo; epollo = epollo->q_next) {
03821       if (epollo->chan)
03822          ast_poll_channel_del(in, epollo->chan);
03823    }
03824 #endif
03825 
03826    return peer;
03827 }
03828 
03829 /*! 
03830  * \brief Check if we should start attempting to call queue members.
03831  *
03832  * A simple process, really. Count the number of members who are available
03833  * to take our call and then see if we are in a position in the queue at
03834  * which a member could accept our call.
03835  *
03836  * \param[in] qe The caller who wants to know if it is his turn
03837  * \retval 0 It is not our turn
03838  * \retval 1 It is our turn
03839  */
03840 static int is_our_turn(struct queue_ent *qe)
03841 {
03842    struct queue_ent *ch;
03843    int res;
03844    int avl;
03845    int idx = 0;
03846    /* This needs a lock. How many members are available to be served? */
03847    ao2_lock(qe->parent);
03848 
03849    avl = num_available_members(qe->parent);
03850 
03851    ch = qe->parent->head;
03852 
03853    ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
03854 
03855    while ((idx < avl) && (ch) && (ch != qe)) {
03856       if (!ch->pending)
03857          idx++;
03858       ch = ch->next;       
03859    }
03860 
03861    ao2_unlock(qe->parent);
03862    /* If the queue entry is within avl [the number of available members] calls from the top ... 
03863     * Autofill and position check added to support autofill=no (as only calls
03864     * from the front of the queue are valid when autofill is disabled)
03865     */
03866    if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
03867       ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
03868       res = 1;
03869    } else {
03870       ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
03871       res = 0;
03872    }
03873 
03874    return res;
03875 }
03876 
03877 /*!
03878  * \brief update rules for queues
03879  *
03880  * Calculate min/max penalties making sure if relative they stay within bounds.
03881  * Update queues penalty and set dialplan vars, goto next list entry.
03882 */
03883 static void update_qe_rule(struct queue_ent *qe)
03884 {
03885    int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
03886    int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
03887    char max_penalty_str[20], min_penalty_str[20]; 
03888    /* a relative change to the penalty could put it below 0 */
03889    if (max_penalty < 0)
03890       max_penalty = 0;
03891    if (min_penalty < 0)
03892       min_penalty = 0;
03893    if (min_penalty > max_penalty)
03894       min_penalty = max_penalty;
03895    snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
03896    snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
03897    pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
03898    pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
03899    qe->max_penalty = max_penalty;
03900    qe->min_penalty = min_penalty;
03901    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);
03902    qe->pr = AST_LIST_NEXT(qe->pr, list);
03903 }
03904 
03905 /*! \brief The waiting areas for callers who are not actively calling members
03906  *
03907  * This function is one large loop. This function will return if a caller
03908  * either exits the queue or it becomes that caller's turn to attempt calling
03909  * queue members. Inside the loop, we service the caller with periodic announcements,
03910  * holdtime announcements, etc. as configured in queues.conf
03911  *
03912  * \retval  0 if the caller's turn has arrived
03913  * \retval -1 if the caller should exit the queue.
03914  */
03915 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
03916 {
03917    int res = 0;
03918 
03919    /* This is the holding pen for callers 2 through maxlen */
03920    for (;;) {
03921 
03922       if (is_our_turn(qe))
03923          break;
03924 
03925       /* If we have timed out, break out */
03926       if (qe->expire && (time(NULL) >= qe->expire)) {
03927          *reason = QUEUE_TIMEOUT;
03928          break;
03929       }
03930 
03931       if (qe->parent->leavewhenempty) {
03932          int status = 0;
03933 
03934          if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty))) {
03935             *reason = QUEUE_LEAVEEMPTY;
03936             ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
03937             leave_queue(qe);
03938             break;
03939          }
03940       }
03941 
03942       /* Make a position announcement, if enabled */
03943       if (qe->parent->announcefrequency &&
03944          (res = say_position(qe,ringing)))
03945          break;
03946 
03947       /* If we have timed out, break out */
03948       if (qe->expire && (time(NULL) >= qe->expire)) {
03949          *reason = QUEUE_TIMEOUT;
03950          break;
03951       }
03952 
03953       /* Make a periodic announcement, if enabled */
03954       if (qe->parent->periodicannouncefrequency &&
03955          (res = say_periodic_announcement(qe,ringing)))
03956          break;
03957       
03958       /* see if we need to move to the next penalty level for this queue */
03959       while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
03960          update_qe_rule(qe);
03961       }
03962 
03963       /* If we have timed out, break out */
03964       if (qe->expire && (time(NULL) >= qe->expire)) {
03965          *reason = QUEUE_TIMEOUT;
03966          break;
03967       }
03968       
03969       /* Wait a second before checking again */
03970       if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
03971          if (res > 0 && !valid_exit(qe, res))
03972             res = 0;
03973          else
03974             break;
03975       }
03976       
03977       /* If we have timed out, break out */
03978       if (qe->expire && (time(NULL) >= qe->expire)) {
03979          *reason = QUEUE_TIMEOUT;
03980          break;
03981       }
03982    }
03983 
03984    return res;
03985 }
03986 
03987 /*!
03988  * \brief update the queue status
03989  * \retval Always 0
03990 */
03991 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
03992 {
03993    int oldtalktime;
03994 
03995    struct member *mem;
03996    struct call_queue *qtmp;
03997    struct ao2_iterator queue_iter;  
03998    
03999    if (shared_lastcall) {
04000       queue_iter = ao2_iterator_init(queues, 0);
04001       while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
04002          ao2_lock(qtmp);
04003          if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
04004             time(&mem->lastcall);
04005             mem->calls++;
04006             mem->lastqueue = q;
04007             ao2_ref(mem, -1);
04008          }
04009          ao2_unlock(qtmp);
04010          queue_t_unref(qtmp, "Done with iterator");
04011       }
04012       ao2_iterator_destroy(&queue_iter);
04013    } else {
04014       ao2_lock(q);
04015       time(&member->lastcall);
04016       member->calls++;
04017       member->lastqueue = q;
04018       ao2_unlock(q);
04019    }  
04020    ao2_lock(q);
04021    q->callscompleted++;
04022    if (callcompletedinsl)
04023       q->callscompletedinsl++;
04024    /* Calculate talktime using the same exponential average as holdtime code*/
04025    oldtalktime = q->talktime;
04026    q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
04027    ao2_unlock(q);
04028    return 0;
04029 }
04030 
04031 /*! \brief Calculate the metric of each member in the outgoing callattempts
04032  *
04033  * A numeric metric is given to each member depending on the ring strategy used
04034  * by the queue. Members with lower metrics will be called before members with
04035  * higher metrics
04036  * \retval -1 if penalties are exceeded
04037  * \retval 0 otherwise
04038  */
04039 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
04040 {
04041    /* disregarding penalty on too few members? */
04042    int membercount = ao2_container_count(q->members);
04043    unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
04044 
04045    if (usepenalty) {
04046       if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) ||
04047          (qe->min_penalty && (mem->penalty < qe->min_penalty))) {
04048          return -1;
04049       }
04050    } else {
04051       ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
04052            membercount, q->penaltymemberslimit);
04053    }
04054 
04055    switch (q->strategy) {
04056    case QUEUE_STRATEGY_RINGALL:
04057       /* Everyone equal, except for penalty */
04058       tmp->metric = mem->penalty * 1000000 * usepenalty;
04059       break;
04060    case QUEUE_STRATEGY_LINEAR:
04061       if (pos < qe->linpos) {
04062          tmp->metric = 1000 + pos;
04063       } else {
04064          if (pos > qe->linpos)
04065             /* Indicate there is another priority */
04066             qe->linwrapped = 1;
04067          tmp->metric = pos;
04068       }
04069       tmp->metric += mem->penalty * 1000000 * usepenalty;
04070       break;
04071    case QUEUE_STRATEGY_RRORDERED:
04072    case QUEUE_STRATEGY_RRMEMORY:
04073       if (pos < q->rrpos) {
04074          tmp->metric = 1000 + pos;
04075       } else {
04076          if (pos > q->rrpos)
04077             /* Indicate there is another priority */
04078             q->wrapped = 1;
04079          tmp->metric = pos;
04080       }
04081       tmp->metric += mem->penalty * 1000000 * usepenalty;
04082       break;
04083    case QUEUE_STRATEGY_RANDOM:
04084       tmp->metric = ast_random() % 1000;
04085       tmp->metric += mem->penalty * 1000000 * usepenalty;
04086       break;
04087    case QUEUE_STRATEGY_WRANDOM:
04088       tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
04089       break;
04090    case QUEUE_STRATEGY_FEWESTCALLS:
04091       tmp->metric = mem->calls;
04092       tmp->metric += mem->penalty * 1000000 * usepenalty;
04093       break;
04094    case QUEUE_STRATEGY_LEASTRECENT:
04095       if (!mem->lastcall)
04096          tmp->metric = 0;
04097       else
04098          tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
04099       tmp->metric += mem->penalty * 1000000 * usepenalty;
04100       break;
04101    default:
04102       ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
04103       break;
04104    }
04105    return 0;
04106 }
04107 
04108 enum agent_complete_reason {
04109    CALLER,
04110    AGENT,
04111    TRANSFER
04112 };
04113 
04114 /*! \brief Send out AMI message with member call completion status information */
04115 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
04116    const struct ast_channel *peer, const struct member *member, time_t callstart,
04117    char *vars, size_t vars_len, enum agent_complete_reason rsn)
04118 {
04119    const char *reason = NULL; /* silence dumb compilers */
04120 
04121    if (!qe->parent->eventwhencalled)
04122       return;
04123 
04124    switch (rsn) {
04125    case CALLER:
04126       reason = "caller";
04127       break;
04128    case AGENT:
04129       reason = "agent";
04130       break;
04131    case TRANSFER:
04132       reason = "transfer";
04133       break;
04134    }
04135 
04136    manager_event(EVENT_FLAG_AGENT, "AgentComplete",
04137       "Queue: %s\r\n"
04138       "Uniqueid: %s\r\n"
04139       "Channel: %s\r\n"
04140       "Member: %s\r\n"
04141       "MemberName: %s\r\n"
04142       "HoldTime: %ld\r\n"
04143       "TalkTime: %ld\r\n"
04144       "Reason: %s\r\n"
04145       "%s",
04146       queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04147       (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
04148       qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
04149 }
04150 
04151 struct queue_transfer_ds {
04152    struct queue_ent *qe;
04153    struct member *member;
04154    time_t starttime;
04155    int callcompletedinsl;
04156 };
04157 
04158 static void queue_transfer_destroy(void *data)
04159 {
04160    struct queue_transfer_ds *qtds = data;
04161    ast_free(qtds);
04162 }
04163 
04164 /*! \brief a datastore used to help correctly log attended transfers of queue callers
04165  */
04166 static const struct ast_datastore_info queue_transfer_info = {
04167    .type = "queue_transfer",
04168    .chan_fixup = queue_transfer_fixup,
04169    .destroy = queue_transfer_destroy,
04170 };
04171 
04172 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
04173  *
04174  * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
04175  * the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
04176  * to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
04177  *
04178  * At the end of this, we want to remove the datastore so that this fixup function is not called on any
04179  * future masquerades of the caller during the current call.
04180  */
04181 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
04182 {
04183    struct queue_transfer_ds *qtds = data;
04184    struct queue_ent *qe = qtds->qe;
04185    struct member *member = qtds->member;
04186    time_t callstart = qtds->starttime;
04187    int callcompletedinsl = qtds->callcompletedinsl;
04188    struct ast_datastore *datastore;
04189 
04190    ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
04191             new_chan->exten, new_chan->context, (long) (callstart - qe->start),
04192             (long) (time(NULL) - callstart), qe->opos);
04193 
04194    update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
04195    
04196    /* No need to lock the channels because they are already locked in ast_do_masquerade */
04197    if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
04198       ast_channel_datastore_remove(old_chan, datastore);
04199    } else {
04200       ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
04201    }
04202 }
04203 
04204 /*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
04205  *
04206  * When a caller is atxferred, then the queue_transfer_info datastore
04207  * is removed from the channel. If it's still there after the bridge is
04208  * broken, then the caller was not atxferred.
04209  *
04210  * \note Only call this with chan locked
04211  */
04212 static int attended_transfer_occurred(struct ast_channel *chan)
04213 {
04214    return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
04215 }
04216 
04217 /*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
04218  */
04219 static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
04220 {
04221    struct ast_datastore *ds;
04222    struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
04223 
04224    if (!qtds) {
04225       ast_log(LOG_WARNING, "Memory allocation error!\n");
04226       return NULL;
04227    }
04228 
04229    ast_channel_lock(qe->chan);
04230    if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
04231       ast_channel_unlock(qe->chan);
04232       ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
04233       return NULL;
04234    }
04235 
04236    qtds->qe = qe;
04237    /* This member is refcounted in try_calling, so no need to add it here, too */
04238    qtds->member = member;
04239    qtds->starttime = starttime;
04240    qtds->callcompletedinsl = callcompletedinsl;
04241    ds->data = qtds;
04242    ast_channel_datastore_add(qe->chan, ds);
04243    ast_channel_unlock(qe->chan);
04244    return ds;
04245 }
04246 
04247 struct queue_end_bridge {
04248    struct call_queue *q;
04249    struct ast_channel *chan;
04250 };
04251 
04252 static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
04253 {
04254    struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
04255    ao2_ref(qeb, +1);
04256    qeb->chan = originator;
04257 }
04258 
04259 static void end_bridge_callback(void *data)
04260 {
04261    struct queue_end_bridge *qeb = data;
04262    struct call_queue *q = qeb->q;
04263    struct ast_channel *chan = qeb->chan;
04264 
04265    if (ao2_ref(qeb, -1) == 1) {
04266       set_queue_variables(q, chan);
04267       /* This unrefs the reference we made in try_calling when we allocated qeb */
04268       queue_t_unref(q, "Expire bridge_config reference");
04269    }
04270 }
04271 
04272 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
04273  * 
04274  * Here is the process of this function
04275  * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
04276  * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
04277  *    iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
04278  *    member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
04279  *    during each iteration, we call calc_metric to determine which members should be rung when.
04280  * 3. Call ring_one to place a call to the appropriate member(s)
04281  * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
04282  * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
04283  * 6. Start the monitor or mixmonitor if the option is set
04284  * 7. Remove the caller from the queue to allow other callers to advance
04285  * 8. Bridge the call.
04286  * 9. Do any post processing after the call has disconnected.
04287  *
04288  * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
04289  * \param[in] options the options passed as the third parameter to the Queue() application
04290  * \param[in] announceoverride filename to play to user when waiting 
04291  * \param[in] url the url passed as the fourth parameter to the Queue() application
04292  * \param[in,out] tries the number of times we have tried calling queue members
04293  * \param[out] noption set if the call to Queue() has the 'n' option set.
04294  * \param[in] agi the agi passed as the fifth parameter to the Queue() application
04295  * \param[in] macro the macro passed as the sixth parameter to the Queue() application
04296  * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
04297  * \param[in] ringing 1 if the 'r' option is set, otherwise 0
04298  */
04299 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)
04300 {
04301    struct member *cur;
04302    struct callattempt *outgoing = NULL; /* the list of calls we are building */
04303    int to, orig;
04304    char oldexten[AST_MAX_EXTENSION]="";
04305    char oldcontext[AST_MAX_CONTEXT]="";
04306    char queuename[256]="";
04307    char interfacevar[256]="";
04308    struct ast_channel *peer;
04309    struct ast_channel *which;
04310    struct callattempt *lpeer;
04311    struct member *member;
04312    struct ast_app *application;
04313    int res = 0, bridge = 0;
04314    int numbusies = 0;
04315    int x=0;
04316    char *announce = NULL;
04317    char digit = 0;
04318    time_t callstart;
04319    time_t now = time(NULL);
04320    struct ast_bridge_config bridge_config;
04321    char nondataquality = 1;
04322    char *agiexec = NULL;
04323    char *macroexec = NULL;
04324    char *gosubexec = NULL;
04325    const char *monitorfilename;
04326    const char *monitor_exec;
04327    const char *monitor_options;
04328    char tmpid[256], tmpid2[256];
04329    char meid[1024], meid2[1024];
04330    char mixmonargs[1512];
04331    struct ast_app *mixmonapp = NULL;
04332    char *p;
04333    char vars[2048];
04334    int forwardsallowed = 1;
04335    int update_connectedline = 1;
04336    int callcompletedinsl;
04337    struct ao2_iterator memi;
04338    struct ast_datastore *datastore, *transfer_ds;
04339    struct queue_end_bridge *queue_end_bridge = NULL;
04340 
04341    ast_channel_lock(qe->chan);
04342    datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
04343    ast_channel_unlock(qe->chan);
04344 
04345    memset(&bridge_config, 0, sizeof(bridge_config));
04346    tmpid[0] = 0;
04347    meid[0] = 0;
04348    time(&now);
04349 
04350    /* If we've already exceeded our timeout, then just stop
04351     * This should be extremely rare. queue_exec will take care
04352     * of removing the caller and reporting the timeout as the reason.
04353     */
04354    if (qe->expire && now >= qe->expire) {
04355       res = 0;
04356       goto out;
04357    }
04358       
04359    for (; options && *options; options++)
04360       switch (*options) {
04361       case 't':
04362          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
04363          break;
04364       case 'T':
04365          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
04366          break;
04367       case 'w':
04368          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
04369          break;
04370       case 'W':
04371          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
04372          break;
04373       case 'c':
04374          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
04375          break;
04376       case 'd':
04377          nondataquality = 0;
04378          break;
04379       case 'h':
04380          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
04381          break;
04382       case 'H':
04383          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
04384          break;
04385       case 'k':
04386          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
04387          break;
04388       case 'K':
04389          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
04390          break;
04391       case 'n':
04392          if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED)
04393             (*tries)++;
04394          else
04395             *tries = ao2_container_count(qe->parent->members);
04396          *noption = 1;
04397          break;
04398       case 'i':
04399          forwardsallowed = 0;
04400          break;
04401       case 'I':
04402          update_connectedline = 0;
04403          break;
04404       case 'x':
04405          ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
04406          break;
04407       case 'X':
04408          ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
04409          break;
04410       case 'C':
04411          qe->cancel_answered_elsewhere = 1;
04412          break;
04413       }
04414 
04415    /* if the calling channel has the ANSWERED_ELSEWHERE flag set, make sure this is inherited. 
04416       (this is mainly to support chan_local)
04417    */
04418    if (ast_test_flag(qe->chan, AST_FLAG_ANSWERED_ELSEWHERE)) {
04419       qe->cancel_answered_elsewhere = 1;
04420    }
04421 
04422    ao2_lock(qe->parent);
04423    ast_debug(1, "%s is trying to call a queue member.\n",
04424                      qe->chan->name);
04425    ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
04426    if (!ast_strlen_zero(qe->announce))
04427       announce = qe->announce;
04428    if (!ast_strlen_zero(announceoverride))
04429       announce = announceoverride;
04430 
04431    memi = ao2_iterator_init(qe->parent->members, 0);
04432    while ((cur = ao2_iterator_next(&memi))) {
04433       struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
04434       struct ast_dialed_interface *di;
04435       AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
04436       if (!tmp) {
04437          ao2_ref(cur, -1);
04438          ao2_unlock(qe->parent);
04439          ao2_iterator_destroy(&memi);
04440          goto out;
04441       }
04442       if (!datastore) {
04443          if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
04444             ao2_ref(cur, -1);
04445             ao2_unlock(qe->parent);
04446             ao2_iterator_destroy(&memi);
04447             callattempt_free(tmp);
04448             goto out;
04449          }
04450          datastore->inheritance = DATASTORE_INHERIT_FOREVER;
04451          if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
04452             ao2_ref(cur, -1);
04453             ao2_unlock(&qe->parent);
04454             ao2_iterator_destroy(&memi);
04455             callattempt_free(tmp);
04456             goto out;
04457          }
04458          datastore->data = dialed_interfaces;
04459          AST_LIST_HEAD_INIT(dialed_interfaces);
04460 
04461          ast_channel_lock(qe->chan);
04462          ast_channel_datastore_add(qe->chan, datastore);
04463          ast_channel_unlock(qe->chan);
04464       } else
04465          dialed_interfaces = datastore->data;
04466 
04467       AST_LIST_LOCK(dialed_interfaces);
04468       AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
04469          if (!strcasecmp(cur->interface, di->interface)) {
04470             ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n", 
04471                di->interface);
04472             break;
04473          }
04474       }
04475       AST_LIST_UNLOCK(dialed_interfaces);
04476 
04477       if (di) {
04478          callattempt_free(tmp);
04479          continue;
04480       }
04481 
04482       /* It is always ok to dial a Local interface.  We only keep track of
04483        * which "real" interfaces have been dialed.  The Local channel will
04484        * inherit this list so that if it ends up dialing a real interface,
04485        * it won't call one that has already been called. */
04486       if (strncasecmp(cur->interface, "Local/", 6)) {
04487          if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
04488             ao2_ref(cur, -1);
04489             ao2_unlock(qe->parent);
04490             ao2_iterator_destroy(&memi);
04491             callattempt_free(tmp);
04492             goto out;
04493          }
04494          strcpy(di->interface, cur->interface);
04495 
04496          AST_LIST_LOCK(dialed_interfaces);
04497          AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
04498          AST_LIST_UNLOCK(dialed_interfaces);
04499       }
04500 
04501       ast_channel_lock(qe->chan);
04502       /*
04503        * Seed the callattempt's connected line information with previously
04504        * acquired connected line info from the queued channel.  The
04505        * previously acquired connected line info could have been set
04506        * through the CONNECTED_LINE dialplan function.
04507        */
04508       ast_party_connected_line_copy(&tmp->connected, &qe->chan->connected);
04509       ast_channel_unlock(qe->chan);
04510 
04511       tmp->stillgoing = -1;
04512       tmp->member = cur;/* Place the reference for cur into callattempt. */
04513       tmp->lastcall = cur->lastcall;
04514       tmp->lastqueue = cur->lastqueue;
04515       ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
04516       /* Special case: If we ring everyone, go ahead and ring them, otherwise
04517          just calculate their metric for the appropriate strategy */
04518       if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
04519          /* Put them in the list of outgoing thingies...  We're ready now.
04520             XXX If we're forcibly removed, these outgoing calls won't get
04521             hung up XXX */
04522          tmp->q_next = outgoing;
04523          outgoing = tmp;      
04524          /* If this line is up, don't try anybody else */
04525          if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
04526             break;
04527       } else {
04528          callattempt_free(tmp);
04529       }
04530    }
04531    ao2_iterator_destroy(&memi);
04532 
04533    if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
04534       /* Application arguments have higher timeout priority (behaviour for <=1.6) */
04535       if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
04536          to = (qe->expire - now) * 1000;
04537       else
04538          to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
04539    } else {
04540       /* Config timeout is higher priority thatn application timeout */
04541       if (qe->expire && qe->expire<=now) {
04542          to = 0;
04543       } else if (qe->parent->timeout) {
04544          to = qe->parent->timeout * 1000;
04545       } else {
04546          to = -1;
04547       }
04548    }
04549    orig = to;
04550    ++qe->pending;
04551    ao2_unlock(qe->parent);
04552    ring_one(qe, outgoing, &numbusies);
04553    lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed, update_connectedline);
04554    /* The ast_channel_datastore_remove() function could fail here if the
04555     * datastore was moved to another channel during a masquerade. If this is
04556     * the case, don't free the datastore here because later, when the channel
04557     * to which the datastore was moved hangs up, it will attempt to free this
04558     * datastore again, causing a crash
04559     */
04560    ast_channel_lock(qe->chan);
04561    if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
04562       ast_datastore_free(datastore);
04563    }
04564    ast_channel_unlock(qe->chan);
04565    ao2_lock(qe->parent);
04566    if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
04567       store_next_rr(qe, outgoing);
04568 
04569    }
04570    if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
04571       store_next_lin(qe, outgoing);
04572    }
04573    ao2_unlock(qe->parent);
04574    peer = lpeer ? lpeer->chan : NULL;
04575    if (!peer) {
04576       qe->pending = 0;
04577       if (to) {
04578          /* Must gotten hung up */
04579          res = -1;
04580       } else {
04581          /* User exited by pressing a digit */
04582          res = digit;
04583       }
04584       if (res == -1)
04585          ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
04586       if (ast_cdr_isset_unanswered()) {
04587          /* channel contains the name of one of the outgoing channels
04588             in its CDR; zero out this CDR to avoid a dual-posting */
04589          struct callattempt *o;
04590          for (o = outgoing; o; o = o->q_next) {
04591             if (!o->chan) {
04592                continue;
04593             }
04594             if (strcmp(o->chan->cdr->dstchannel, qe->chan->cdr->dstchannel) == 0) {
04595                ast_set_flag(o->chan->cdr, AST_CDR_FLAG_POST_DISABLED);
04596                break;
04597             }
04598          }
04599       }
04600    } else { /* peer is valid */
04601       /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
04602          we will always return with -1 so that it is hung up properly after the
04603          conversation.  */
04604       if (!strcmp(qe->chan->tech->type, "DAHDI"))
04605          ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04606       if (!strcmp(peer->tech->type, "DAHDI"))
04607          ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
04608       /* Update parameters for the queue */
04609       time(&now);
04610       recalc_holdtime(qe, (now - qe->start));
04611       ao2_lock(qe->parent);
04612       callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
04613       ao2_unlock(qe->parent);
04614       member = lpeer->member;
04615       /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
04616       ao2_ref(member, 1);
04617       hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
04618       outgoing = NULL;
04619       if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
04620          int res2;
04621 
04622          res2 = ast_autoservice_start(qe->chan);
04623          if (!res2) {
04624             if (qe->parent->memberdelay) {
04625                ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
04626                res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
04627             }
04628             if (!res2 && announce) {
04629                play_file(peer, announce);
04630             }
04631             if (!res2 && qe->parent->reportholdtime) {
04632                if (!play_file(peer, qe->parent->sound_reporthold)) {
04633                   int holdtime, holdtimesecs;
04634 
04635                   time(&now);
04636                   holdtime = abs((now - qe->start) / 60);
04637                   holdtimesecs = abs((now - qe->start) % 60);
04638                   if (holdtime > 0) {
04639                      ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
04640                      play_file(peer, qe->parent->sound_minutes);
04641                   }
04642                   if (holdtimesecs > 1) {
04643                      ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
04644                      play_file(peer, qe->parent->sound_seconds);
04645                   }
04646                }
04647             }
04648          }
04649          res2 |= ast_autoservice_stop(qe->chan);
04650          if (ast_check_hangup(peer)) {
04651             /* Agent must have hung up */
04652             ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
04653             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
04654             if (qe->parent->eventwhencalled)
04655                manager_event(EVENT_FLAG_AGENT, "AgentDump",
04656                      "Queue: %s\r\n"
04657                      "Uniqueid: %s\r\n"
04658                      "Channel: %s\r\n"
04659                      "Member: %s\r\n"
04660                      "MemberName: %s\r\n"
04661                      "%s",
04662                      queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
04663                      qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
04664             ast_hangup(peer);
04665             ao2_ref(member, -1);
04666             goto out;
04667          } else if (res2) {
04668             /* Caller must have hung up just before being connected*/
04669             ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
04670             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
04671             record_abandoned(qe);
04672             ast_hangup(peer);
04673             ao2_ref(member, -1);
04674             return -1;
04675          }
04676       }
04677       /* Stop music on hold */
04678       if (ringing)
04679          ast_indicate(qe->chan,-1);
04680       else
04681          ast_moh_stop(qe->chan);
04682       /* If appropriate, log that we have a destination channel */
04683       if (qe->chan->cdr)
04684          ast_cdr_setdestchan(qe->chan->cdr, peer->name);
04685       /* Make sure channels are compatible */
04686       res = ast_channel_make_compatible(qe->chan, peer);
04687       if (res < 0) {
04688          ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
04689          ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
04690          record_abandoned(qe);
04691          ast_cdr_failed(qe->chan->cdr);
04692          ast_hangup(peer);
04693          ao2_ref(member, -1);
04694          return -1;
04695       }
04696 
04697       /* Play announcement to the caller telling it's his turn if defined */
04698       if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
04699          if (play_file(qe->chan, qe->parent->sound_callerannounce))
04700             ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
04701       }
04702 
04703       ao2_lock(qe->parent);
04704       /* if setinterfacevar is defined, make member variables available to the channel */
04705       /* use  pbx_builtin_setvar to set a load of variables with one call */
04706       if (qe->parent->setinterfacevar) {
04707          snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
04708             member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
04709          pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04710          pbx_builtin_setvar_multiple(peer, interfacevar);
04711       }
04712       
04713       /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
04714       /* use  pbx_builtin_setvar to set a load of variables with one call */
04715       if (qe->parent->setqueueentryvar) {
04716          snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
04717             (long) time(NULL) - qe->start, qe->opos);
04718          pbx_builtin_setvar_multiple(qe->chan, interfacevar);
04719          pbx_builtin_setvar_multiple(peer, interfacevar);
04720       }
04721    
04722       ao2_unlock(qe->parent);
04723 
04724       /* try to set queue variables if configured to do so*/
04725       set_queue_variables(qe->parent, qe->chan);
04726       set_queue_variables(qe->parent, peer);
04727       
04728       ast_channel_lock(qe->chan);
04729       if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
04730             monitorfilename = ast_strdupa(monitorfilename);
04731       }
04732       ast_channel_unlock(qe->chan);
04733       /* Begin Monitoring */
04734       if (qe->parent->monfmt && *qe->parent->monfmt) {
04735          if (!qe->parent->montype) {
04736             const char *monexec, *monargs;
04737             ast_debug(1, "Starting Monitor as requested.\n");
04738             ast_channel_lock(qe->chan);
04739             if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || (monargs = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))) {
04740                which = qe->chan;
04741                monexec = monexec ? ast_strdupa(monexec) : NULL;
04742             }
04743             else
04744                which = peer;
04745             ast_channel_unlock(qe->chan);
04746             if (monitorfilename) {
04747                ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
04748             } else if (qe->chan->cdr) {
04749                ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
04750             } else {
04751                /* Last ditch effort -- no CDR, make up something */
04752                snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04753                ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
04754             }
04755             if (!ast_strlen_zero(monexec)) {
04756                ast_monitor_setjoinfiles(which, 1);
04757             }
04758          } else {
04759             mixmonapp = pbx_findapp("MixMonitor");
04760             
04761             if (mixmonapp) {
04762                ast_debug(1, "Starting MixMonitor as requested.\n");
04763                if (!monitorfilename) {
04764                   if (qe->chan->cdr)
04765                      ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
04766                   else
04767                      snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
04768                } else {
04769                   const char *m = monitorfilename;
04770                   for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
04771                      switch (*m) {
04772                      case '^':
04773                         if (*(m + 1) == '{')
04774                            *p = '$';
04775                         break;
04776                      case ',':
04777                         *p++ = '\\';
04778                         /* Fall through */
04779                      default:
04780                         *p = *m;
04781                      }
04782                      if (*m == '\0')
04783                         break;
04784                   }
04785                   if (p == tmpid2 + sizeof(tmpid2))
04786                      tmpid2[sizeof(tmpid2) - 1] = '\0';
04787 
04788                   pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
04789                }
04790 
04791                ast_channel_lock(qe->chan);
04792                if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
04793                      monitor_exec = ast_strdupa(monitor_exec);
04794                }
04795                if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
04796                      monitor_options = ast_strdupa(monitor_options);
04797                } else {
04798                   monitor_options = "";
04799                }
04800                ast_channel_unlock(qe->chan);
04801 
04802                if (monitor_exec) {
04803                   const char *m = monitor_exec;
04804                   for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
04805                      switch (*m) {
04806                      case '^':
04807                         if (*(m + 1) == '{')
04808                            *p = '$';
04809                         break;
04810                      case ',':
04811                         *p++ = '\\';
04812                         /* Fall through */
04813                      default:
04814                         *p = *m;
04815                      }
04816                      if (*m == '\0')
04817                         break;
04818                   }
04819                   if (p == meid2 + sizeof(meid2))
04820                      meid2[sizeof(meid2) - 1] = '\0';
04821 
04822                   pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
04823                }
04824    
04825                snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
04826 
04827                if (!ast_strlen_zero(monitor_exec))
04828                   snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
04829                else
04830                   snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
04831                
04832                ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
04833                /* We purposely lock the CDR so that pbx_exec does not update the application data */
04834                if (qe->chan->cdr)
04835                   ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04836                pbx_exec(qe->chan, mixmonapp, mixmonargs);
04837                if (qe->chan->cdr)
04838                   ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
04839 
04840             } else {
04841                ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
04842             }
04843          }
04844       }
04845       /* Drop out of the queue at this point, to prepare for next caller */
04846       leave_queue(qe);        
04847       if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
04848          ast_debug(1, "app_queue: sendurl=%s.\n", url);
04849          ast_channel_sendurl(peer, url);
04850       }
04851       
04852       /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
04853       /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
04854       if (!ast_strlen_zero(macro)) {
04855             macroexec = ast_strdupa(macro);
04856       } else {
04857          if (qe->parent->membermacro)
04858             macroexec = ast_strdupa(qe->parent->membermacro);
04859       }
04860 
04861       if (!ast_strlen_zero(macroexec)) {
04862          ast_debug(1, "app_queue: macro=%s.\n", macroexec);
04863          
04864          res = ast_autoservice_start(qe->chan);
04865          if (res) {
04866             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
04867             res = -1;
04868          }
04869          
04870          application = pbx_findapp("Macro");
04871 
04872          if (application) {
04873             res = pbx_exec(peer, application, macroexec);
04874             ast_debug(1, "Macro exited with status %d\n", res);
04875             res = 0;
04876          } else {
04877             ast_log(LOG_ERROR, "Could not find application Macro\n");
04878             res = -1;
04879          }
04880 
04881          if (ast_autoservice_stop(qe->chan) < 0) {
04882             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
04883             res = -1;
04884          }
04885       }
04886 
04887       /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
04888       /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
04889       if (!ast_strlen_zero(gosub)) {
04890             gosubexec = ast_strdupa(gosub);
04891       } else {
04892          if (qe->parent->membergosub)
04893             gosubexec = ast_strdupa(qe->parent->membergosub);
04894       }
04895 
04896       if (!ast_strlen_zero(gosubexec)) {
04897          ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
04898          
04899          res = ast_autoservice_start(qe->chan);
04900          if (res) {
04901             ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
04902             res = -1;
04903          }
04904          
04905          application = pbx_findapp("Gosub");
04906          
04907          if (application) {
04908             char *gosub_args, *gosub_argstart;
04909 
04910             /* Set where we came from */
04911             ast_copy_string(peer->context, "app_queue_gosub_virtual_context", sizeof(peer->context));
04912             ast_copy_string(peer->exten, "s", sizeof(peer->exten));
04913             peer->priority = 0;
04914 
04915             gosub_argstart = strchr(gosubexec, ',');
04916             if (gosub_argstart) {
04917                const char *what_is_s = "s";
04918                *gosub_argstart = 0;
04919                if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
04920                    ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
04921                   what_is_s = "~~s~~";
04922                }
04923                if (asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
04924                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
04925                   gosub_args = NULL;
04926                }
04927                *gosub_argstart = ',';
04928             } else {
04929                const char *what_is_s = "s";
04930                if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL)) &&
04931                    ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(peer->caller.id.number.valid, peer->caller.id.number.str, NULL))) {
04932                   what_is_s = "~~s~~";
04933                }
04934                if (asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
04935                   ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
04936                   gosub_args = NULL;
04937                }
04938             }
04939             if (gosub_args) {
04940                res = pbx_exec(peer, application, gosub_args);
04941                if (!res) {
04942                   struct ast_pbx_args args;
04943                   memset(&args, 0, sizeof(args));
04944                   args.no_hangup_chan = 1;
04945                   ast_pbx_run_args(peer, &args);
04946                }
04947                ast_free(gosub_args);
04948                ast_debug(1, "Gosub exited with status %d\n", res);
04949             } else {
04950                ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
04951             }
04952          } else {
04953             ast_log(LOG_ERROR, "Could not find application Gosub\n");
04954             res = -1;
04955          }
04956       
04957          if (ast_autoservice_stop(qe->chan) < 0) {
04958             ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
04959             res = -1;
04960          }
04961       }
04962 
04963       if (!ast_strlen_zero(agi)) {
04964          ast_debug(1, "app_queue: agi=%s.\n", agi);
04965          application = pbx_findapp("agi");
04966          if (application) {
04967             agiexec = ast_strdupa(agi);
04968             pbx_exec(qe->chan, application, agiexec);
04969          } else
04970             ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
04971       }
04972       qe->handled++;
04973       ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
04974                                        (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
04975 
04976       if (qe->chan->cdr) {
04977          struct ast_cdr *cdr;
04978          struct ast_cdr *newcdr;
04979 
04980          /* Only work with the last CDR in the stack*/
04981          cdr = qe->chan->cdr;
04982          while (cdr->next) {
04983             cdr = cdr->next;
04984          }
04985 
04986          /* If this CDR is not related to us add new one*/
04987          if ((strcasecmp(cdr->uniqueid, qe->chan->uniqueid)) &&
04988              (strcasecmp(cdr->linkedid, qe->chan->uniqueid)) &&
04989              (newcdr = ast_cdr_dup(cdr))) {
04990             ast_channel_lock(qe->chan);
04991             ast_cdr_init(newcdr, qe->chan);
04992             ast_cdr_reset(newcdr, 0);
04993             cdr = ast_cdr_append(cdr, newcdr);
04994             cdr = cdr->next;
04995             ast_channel_unlock(qe->chan);
04996          }
04997 
04998          if (update_cdr) {
04999             ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
05000          }
05001       }
05002 
05003       if (qe->parent->eventwhencalled)
05004          manager_event(EVENT_FLAG_AGENT, "AgentConnect",
05005                "Queue: %s\r\n"
05006                "Uniqueid: %s\r\n"
05007                "Channel: %s\r\n"
05008                "Member: %s\r\n"
05009                "MemberName: %s\r\n"
05010                "Holdtime: %ld\r\n"
05011                "BridgedChannel: %s\r\n"
05012                "Ringtime: %ld\r\n"
05013                "%s",
05014                queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
05015                (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
05016                qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
05017       ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
05018       ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
05019    
05020       if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
05021          queue_end_bridge->q = qe->parent;
05022          queue_end_bridge->chan = qe->chan;
05023          bridge_config.end_bridge_callback = end_bridge_callback;
05024          bridge_config.end_bridge_callback_data = queue_end_bridge;
05025          bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
05026          /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
05027           * to make sure to increase the refcount of this queue so it cannot be freed until we
05028           * are done with it. We remove this reference in end_bridge_callback.
05029           */
05030          queue_t_ref(qe->parent, "For bridge_config reference");
05031       }
05032 
05033       time(&callstart);
05034       transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
05035       bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
05036 
05037       /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
05038        * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for
05039        * the AgentComplete manager event
05040        */
05041       ast_channel_lock(qe->chan);
05042       if (!attended_transfer_occurred(qe->chan)) {
05043          struct ast_datastore *tds;
05044 
05045          /* detect a blind transfer */
05046          if (!(qe->chan->_softhangup | peer->_softhangup) && (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten))) {
05047             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
05048                qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
05049                (long) (time(NULL) - callstart), qe->opos);
05050             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
05051          } else if (ast_check_hangup(qe->chan)) {
05052             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
05053                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05054             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
05055          } else {
05056             ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
05057                (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
05058             send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
05059          }
05060          if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {  
05061             ast_channel_datastore_remove(qe->chan, tds);
05062          }
05063          ast_channel_unlock(qe->chan);
05064          update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
05065       } else {
05066          ast_channel_unlock(qe->chan);
05067 
05068          /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
05069          send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
05070       }
05071 
05072       if (transfer_ds) {
05073          ast_datastore_free(transfer_ds);
05074       }
05075       ast_hangup(peer);
05076       res = bridge ? bridge : 1;
05077       ao2_ref(member, -1);
05078    }
05079 out:
05080    hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
05081 
05082    return res;
05083 }
05084 
05085 static int wait_a_bit(struct queue_ent *qe)
05086 {
05087    /* Don't need to hold the lock while we setup the outgoing calls */
05088    int retrywait = qe->parent->retry * 1000;
05089 
05090    int res = ast_waitfordigit(qe->chan, retrywait);
05091    if (res > 0 && !valid_exit(qe, res))
05092       res = 0;
05093 
05094    return res;
05095 }
05096 
05097 static struct member *interface_exists(struct call_queue *q, const char *interface)
05098 {
05099    struct member *mem;
05100    struct ao2_iterator mem_iter;
05101 
05102    if (!q)
05103       return NULL;
05104 
05105    mem_iter = ao2_iterator_init(q->members, 0);
05106    while ((mem = ao2_iterator_next(&mem_iter))) {
05107       if (!strcasecmp(interface, mem->interface)) {
05108          ao2_iterator_destroy(&mem_iter);
05109          return mem;
05110       }
05111       ao2_ref(mem, -1);
05112    }
05113    ao2_iterator_destroy(&mem_iter);
05114 
05115    return NULL;
05116 }
05117 
05118 
05119 /*! \brief Dump all members in a specific queue to the database
05120  *
05121  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
05122  */
05123 static void dump_queue_members(struct call_queue *pm_queue)
05124 {
05125    struct member *cur_member;
05126    char value[PM_MAX_LEN];
05127    int value_len = 0;
05128    int res;
05129    struct ao2_iterator mem_iter;
05130 
05131    memset(value, 0, sizeof(value));
05132 
05133    if (!pm_queue)
05134       return;
05135 
05136    mem_iter = ao2_iterator_init(pm_queue->members, 0);
05137    while ((cur_member = ao2_iterator_next(&mem_iter))) {
05138       if (!cur_member->dynamic) {
05139          ao2_ref(cur_member, -1);
05140          continue;
05141       }
05142 
05143       res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
05144          value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
05145 
05146       ao2_ref(cur_member, -1);
05147 
05148       if (res != strlen(value + value_len)) {
05149          ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
05150          break;
05151       }
05152       value_len += res;
05153    }
05154    ao2_iterator_destroy(&mem_iter);
05155    
05156    if (value_len && !cur_member) {
05157       if (ast_db_put(pm_family, pm_queue->name, value))
05158          ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
05159    } else
05160       /* Delete the entry if the queue is empty or there is an error */
05161       ast_db_del(pm_family, pm_queue->name);
05162 }
05163 
05164 /*! \brief Remove member from queue 
05165  * \retval RES_NOT_DYNAMIC when they aren't a RT member
05166  * \retval RES_NOSUCHQUEUE queue does not exist
05167  * \retval RES_OKAY removed member from queue
05168  * \retval RES_EXISTS queue exists but no members
05169 */
05170 static int remove_from_queue(const char *queuename, const char *interface)
05171 {
05172    struct call_queue *q, tmpq = {
05173       .name = queuename,   
05174    };
05175    struct member *mem, tmpmem;
05176    int res = RES_NOSUCHQUEUE;
05177 
05178    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
05179    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
05180       ao2_lock(q);
05181       if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
05182          /* XXX future changes should beware of this assumption!! */
05183          if (!mem->dynamic) {
05184             ao2_ref(mem, -1);
05185             ao2_unlock(q);
05186             queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
05187             return RES_NOT_DYNAMIC;
05188          }
05189          manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
05190             "Queue: %s\r\n"
05191             "Location: %s\r\n"
05192             "MemberName: %s\r\n",
05193             q->name, mem->interface, mem->membername);
05194          ao2_unlink(q->members, mem);
05195          ao2_ref(mem, -1);
05196 
05197          if (queue_persistent_members)
05198             dump_queue_members(q);
05199          
05200          res = RES_OKAY;
05201       } else {
05202          res = RES_EXISTS;
05203       }
05204       ao2_unlock(q);
05205       queue_t_unref(q, "Expiring temporary reference");
05206    }
05207 
05208    return res;
05209 }
05210 
05211 /*! \brief Add member to queue 
05212  * \retval RES_NOT_DYNAMIC when they aren't a RT member
05213  * \retval RES_NOSUCHQUEUE queue does not exist
05214  * \retval RES_OKAY added member from queue
05215  * \retval RES_EXISTS queue exists but no members
05216  * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
05217 */
05218 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
05219 {
05220    struct call_queue *q;
05221    struct member *new_member, *old_member;
05222    int res = RES_NOSUCHQUEUE;
05223 
05224    /*! \note Ensure the appropriate realtime queue is loaded.  Note that this
05225     * short-circuits if the queue is already in memory. */
05226    if (!(q = load_realtime_queue(queuename)))
05227       return res;
05228 
05229    ao2_lock(q);
05230    if ((old_member = interface_exists(q, interface)) == NULL) {
05231       if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
05232          new_member->dynamic = 1;
05233          ao2_link(q->members, new_member);
05234          manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
05235             "Queue: %s\r\n"
05236             "Location: %s\r\n"
05237             "MemberName: %s\r\n"
05238             "Membership: %s\r\n"
05239             "Penalty: %d\r\n"
05240             "CallsTaken: %d\r\n"
05241             "LastCall: %d\r\n"
05242             "Status: %d\r\n"
05243             "Paused: %d\r\n",
05244             q->name, new_member->interface, new_member->membername,
05245             "dynamic",
05246             new_member->penalty, new_member->calls, (int) new_member->lastcall,
05247             new_member->status, new_member->paused);
05248          
05249          ao2_ref(new_member, -1);
05250          new_member = NULL;
05251 
05252          if (dump)
05253             dump_queue_members(q);
05254          
05255          res = RES_OKAY;
05256       } else {
05257          res = RES_OUTOFMEMORY;
05258       }
05259    } else {
05260       ao2_ref(old_member, -1);
05261       res = RES_EXISTS;
05262    }
05263    ao2_unlock(q);
05264    queue_t_unref(q, "Expiring temporary reference");
05265 
05266    return res;
05267 }
05268 
05269 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
05270 {
05271    int found = 0;
05272    struct call_queue *q;
05273    struct member *mem;
05274    struct ao2_iterator queue_iter;
05275    int failed;
05276 
05277    /* Special event for when all queues are paused - individual events still generated */
05278    /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
05279    if (ast_strlen_zero(queuename))
05280       ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
05281 
05282    queue_iter = ao2_iterator_init(queues, 0);
05283    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
05284       ao2_lock(q);
05285       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05286          if ((mem = interface_exists(q, interface))) {
05287             if (mem->paused == paused) {
05288                ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
05289             }
05290 
05291             failed = 0;
05292             if (mem->realtime) {
05293                failed = update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
05294             }
05295          
05296             if (failed) {
05297                ast_log(LOG_WARNING, "Failed %spausing realtime queue member %s:%s\n", (paused ? "" : "un"), q->name, interface);
05298                ao2_ref(mem, -1);
05299                ao2_unlock(q);
05300                queue_t_unref(q, "Done with iterator");
05301                continue;
05302             }  
05303             found++;
05304             mem->paused = paused;
05305 
05306             if (queue_persistent_members)
05307                dump_queue_members(q);
05308 
05309             ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
05310             
05311             if (!ast_strlen_zero(reason)) {
05312                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05313                   "Queue: %s\r\n"
05314                   "Location: %s\r\n"
05315                   "MemberName: %s\r\n"
05316                   "Paused: %d\r\n"
05317                   "Reason: %s\r\n",
05318                      q->name, mem->interface, mem->membername, paused, reason);
05319             } else {
05320                manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
05321                   "Queue: %s\r\n"
05322                   "Location: %s\r\n"
05323                   "MemberName: %s\r\n"
05324                   "Paused: %d\r\n",
05325                      q->name, mem->interface, mem->membername, paused);
05326             }
05327             ao2_ref(mem, -1);
05328          }
05329       }
05330       
05331       if (!ast_strlen_zero(queuename) && !strcasecmp(queuename, q->name)) {
05332          ao2_unlock(q);
05333          queue_t_unref(q, "Done with iterator");
05334          break;
05335       }
05336       
05337       ao2_unlock(q);
05338       queue_t_unref(q, "Done with iterator");
05339    }
05340    ao2_iterator_destroy(&queue_iter);
05341 
05342    return found ? RESULT_SUCCESS : RESULT_FAILURE;
05343 }
05344 
05345 /* \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues. */
05346 static int set_member_penalty(const char *queuename, const char *interface, int penalty)
05347 {
05348    int foundinterface = 0, foundqueue = 0;
05349    struct call_queue *q;
05350    struct member *mem;
05351    struct ao2_iterator queue_iter;
05352 
05353    if (penalty < 0) {
05354       ast_log(LOG_ERROR, "Invalid penalty (%d)\n", penalty);
05355       return RESULT_FAILURE;
05356    }
05357 
05358    queue_iter = ao2_iterator_init(queues, 0);
05359    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
05360       ao2_lock(q);
05361       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
05362          foundqueue++;
05363          if ((mem = interface_exists(q, interface))) {
05364             foundinterface++;
05365             mem->penalty = penalty;
05366             
05367             ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
05368             manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
05369                "Queue: %s\r\n"
05370                "Location: %s\r\n"
05371                "Penalty: %d\r\n",
05372                q->name, mem->interface, penalty);
05373             ao2_ref(mem, -1);
05374          }
05375       }
05376       ao2_unlock(q);
05377       queue_t_unref(q, "Done with iterator");
05378    }
05379    ao2_iterator_destroy(&queue_iter);
05380 
05381    if (foundinterface) {
05382       return RESULT_SUCCESS;
05383    } else if (!foundqueue) {
05384       ast_log (LOG_ERROR, "Invalid queuename\n"); 
05385    } else {
05386       ast_log (LOG_ERROR, "Invalid interface\n");
05387    }  
05388 
05389    return RESULT_FAILURE;
05390 }
05391 
05392 /* \brief Gets members penalty. 
05393  * \return Return the members penalty or RESULT_FAILURE on error. 
05394 */
05395 static int get_member_penalty(char *queuename, char *interface)
05396 {
05397    int foundqueue = 0, penalty;
05398    struct call_queue *q, tmpq = {
05399       .name = queuename,   
05400    };
05401    struct member *mem;
05402    
05403    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
05404       foundqueue = 1;
05405       ao2_lock(q);
05406       if ((mem = interface_exists(q, interface))) {
05407          penalty = mem->penalty;
05408          ao2_ref(mem, -1);
05409          ao2_unlock(q);
05410          queue_t_unref(q, "Search complete");
05411          return penalty;
05412       }
05413       ao2_unlock(q);
05414       queue_t_unref(q, "Search complete");
05415    }
05416 
05417    /* some useful debuging */
05418    if (foundqueue) 
05419       ast_log (LOG_ERROR, "Invalid queuename\n");
05420    else 
05421       ast_log (LOG_ERROR, "Invalid interface\n");
05422 
05423    return RESULT_FAILURE;
05424 }
05425 
05426 /*! \brief Reload dynamic queue members persisted into the astdb */
05427 static void reload_queue_members(void)
05428 {
05429    char *cur_ptr;
05430    const char *queue_name;
05431    char *member;
05432    char *interface;
05433    char *membername = NULL;
05434    char *state_interface;
05435    char *penalty_tok;
05436    int penalty = 0;
05437    char *paused_tok;
05438    int paused = 0;
05439    struct ast_db_entry *db_tree;
05440    struct ast_db_entry *entry;
05441    struct call_queue *cur_queue;
05442    char queue_data[PM_MAX_LEN];
05443 
05444    /* Each key in 'pm_family' is the name of a queue */
05445    db_tree = ast_db_gettree(pm_family, NULL);
05446    for (entry = db_tree; entry; entry = entry->next) {
05447 
05448       queue_name = entry->key + strlen(pm_family) + 2;
05449 
05450       {
05451          struct call_queue tmpq = {
05452             .name = queue_name,
05453          };
05454          cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
05455       }  
05456 
05457       if (!cur_queue)
05458          cur_queue = load_realtime_queue(queue_name);
05459 
05460       if (!cur_queue) {
05461          /* If the queue no longer exists, remove it from the
05462           * database */
05463          ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
05464          ast_db_del(pm_family, queue_name);
05465          continue;
05466       } 
05467 
05468       if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN)) {
05469          queue_t_unref(cur_queue, "Expire reload reference");
05470          continue;
05471       }
05472 
05473       cur_ptr = queue_data;
05474       while ((member = strsep(&cur_ptr, ",|"))) {
05475          if (ast_strlen_zero(member))
05476             continue;
05477 
05478          interface = strsep(&member, ";");
05479          penalty_tok = strsep(&member, ";");
05480          paused_tok = strsep(&member, ";");
05481          membername = strsep(&member, ";");
05482          state_interface = strsep(&member, ";");
05483 
05484          if (!penalty_tok) {
05485             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
05486             break;
05487          }
05488          penalty = strtol(penalty_tok, NULL, 10);
05489          if (errno == ERANGE) {
05490             ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
05491             break;
05492          }
05493          
05494          if (!paused_tok) {
05495             ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
05496             break;
05497          }
05498          paused = strtol(paused_tok, NULL, 10);
05499          if ((errno == ERANGE) || paused < 0 || paused > 1) {
05500             ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
05501             break;
05502          }
05503 
05504          ast_debug(1, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
05505          
05506          if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
05507             ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
05508             break;
05509          }
05510       }
05511       queue_t_unref(cur_queue, "Expire reload reference");
05512    }
05513 
05514    if (db_tree) {
05515       ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
05516       ast_db_freetree(db_tree);
05517    }
05518 }
05519 
05520 /*! \brief PauseQueueMember application */
05521 static int pqm_exec(struct ast_channel *chan, const char *data)
05522 {
05523    char *parse;
05524    AST_DECLARE_APP_ARGS(args,
05525       AST_APP_ARG(queuename);
05526       AST_APP_ARG(interface);
05527       AST_APP_ARG(options);
05528       AST_APP_ARG(reason);
05529    );
05530 
05531    if (ast_strlen_zero(data)) {
05532       ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
05533       return -1;
05534    }
05535 
05536    parse = ast_strdupa(data);
05537 
05538    AST_STANDARD_APP_ARGS(args, parse);
05539 
05540    if (ast_strlen_zero(args.interface)) {
05541       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05542       return -1;
05543    }
05544 
05545    if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
05546       ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
05547       pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
05548       return 0;
05549    }
05550 
05551    pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
05552 
05553    return 0;
05554 }
05555 
05556 /*! \brief UnPauseQueueMember application */
05557 static int upqm_exec(struct ast_channel *chan, const char *data)
05558 {
05559    char *parse;
05560    AST_DECLARE_APP_ARGS(args,
05561       AST_APP_ARG(queuename);
05562       AST_APP_ARG(interface);
05563       AST_APP_ARG(options);
05564       AST_APP_ARG(reason);
05565    );
05566 
05567    if (ast_strlen_zero(data)) {
05568       ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
05569       return -1;
05570    }
05571 
05572    parse = ast_strdupa(data);
05573 
05574    AST_STANDARD_APP_ARGS(args, parse);
05575 
05576    if (ast_strlen_zero(args.interface)) {
05577       ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
05578       return -1;
05579    }
05580 
05581    if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
05582       ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
05583       pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
05584       return 0;
05585    }
05586 
05587    pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
05588 
05589    return 0;
05590 }
05591 
05592 /*! \brief RemoveQueueMember application */
05593 static int rqm_exec(struct ast_channel *chan, const char *data)
05594 {
05595    int res=-1;
05596    char *parse, *temppos = NULL;
05597    AST_DECLARE_APP_ARGS(args,
05598       AST_APP_ARG(queuename);
05599       AST_APP_ARG(interface);
05600       AST_APP_ARG(options);
05601    );
05602 
05603 
05604    if (ast_strlen_zero(data)) {
05605       ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface[,options]])\n");
05606       return -1;
05607    }
05608 
05609    parse = ast_strdupa(data);
05610 
05611    AST_STANDARD_APP_ARGS(args, parse);
05612 
05613    if (ast_strlen_zero(args.interface)) {
05614       args.interface = ast_strdupa(chan->name);
05615       temppos = strrchr(args.interface, '-');
05616       if (temppos)
05617          *temppos = '\0';
05618    }
05619 
05620    ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
05621 
05622    switch (remove_from_queue(args.queuename, args.interface)) {
05623    case RES_OKAY:
05624       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
05625       ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
05626       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
05627       res = 0;
05628       break;
05629    case RES_EXISTS:
05630       ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
05631       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
05632       res = 0;
05633       break;
05634    case RES_NOSUCHQUEUE:
05635       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
05636       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
05637       res = 0;
05638       break;
05639    case RES_NOT_DYNAMIC:
05640       ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
05641       pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
05642       res = 0;
05643       break;
05644    }
05645 
05646    return res;
05647 }
05648 
05649 /*! \brief AddQueueMember application */
05650 static int aqm_exec(struct ast_channel *chan, const char *data)
05651 {
05652    int res=-1;
05653    char *parse, *temppos = NULL;
05654    AST_DECLARE_APP_ARGS(args,
05655       AST_APP_ARG(queuename);
05656       AST_APP_ARG(interface);
05657       AST_APP_ARG(penalty);
05658       AST_APP_ARG(options);
05659       AST_APP_ARG(membername);
05660       AST_APP_ARG(state_interface);
05661    );
05662    int penalty = 0;
05663 
05664    if (ast_strlen_zero(data)) {
05665       ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
05666       return -1;
05667    }
05668 
05669    parse = ast_strdupa(data);
05670 
05671    AST_STANDARD_APP_ARGS(args, parse);
05672 
05673    if (ast_strlen_zero(args.interface)) {
05674       args.interface = ast_strdupa(chan->name);
05675       temppos = strrchr(args.interface, '-');
05676       if (temppos)
05677          *temppos = '\0';
05678    }
05679 
05680    if (!ast_strlen_zero(args.penalty)) {
05681       if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
05682          ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
05683          penalty = 0;
05684       }
05685    }
05686 
05687    switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
05688    case RES_OKAY:
05689       ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
05690       ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
05691       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
05692       res = 0;
05693       break;
05694    case RES_EXISTS:
05695       ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
05696       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
05697       res = 0;
05698       break;
05699    case RES_NOSUCHQUEUE:
05700       ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
05701       pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
05702       res = 0;
05703       break;
05704    case RES_OUTOFMEMORY:
05705       ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
05706       break;
05707    }
05708 
05709    return res;
05710 }
05711 
05712 /*! \brief QueueLog application */
05713 static int ql_exec(struct ast_channel *chan, const char *data)
05714 {
05715    char *parse;
05716 
05717    AST_DECLARE_APP_ARGS(args,
05718       AST_APP_ARG(queuename);
05719       AST_APP_ARG(uniqueid);
05720       AST_APP_ARG(membername);
05721       AST_APP_ARG(event);
05722       AST_APP_ARG(params);
05723    );
05724 
05725    if (ast_strlen_zero(data)) {
05726       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
05727       return -1;
05728    }
05729 
05730    parse = ast_strdupa(data);
05731 
05732    AST_STANDARD_APP_ARGS(args, parse);
05733 
05734    if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
05735        || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
05736       ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
05737       return -1;
05738    }
05739 
05740    ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event, 
05741       "%s", args.params ? args.params : "");
05742 
05743    return 0;
05744 }
05745 
05746 /*! \brief Copy rule from global list into specified queue */
05747 static void copy_rules(struct queue_ent *qe, const char *rulename)
05748 {
05749    struct penalty_rule *pr_iter;
05750    struct rule_list *rl_iter;
05751    const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
05752    AST_LIST_LOCK(&rule_lists);
05753    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
05754       if (!strcasecmp(rl_iter->name, tmp))
05755          break;
05756    }
05757    if (rl_iter) {
05758       AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
05759          struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
05760          if (!new_pr) {
05761             ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
05762             break;
05763          }
05764          new_pr->time = pr_iter->time;
05765          new_pr->max_value = pr_iter->max_value;
05766          new_pr->min_value = pr_iter->min_value;
05767          new_pr->max_relative = pr_iter->max_relative;
05768          new_pr->min_relative = pr_iter->min_relative;
05769          AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
05770       }
05771    }
05772    AST_LIST_UNLOCK(&rule_lists);
05773 }
05774 
05775 /*!\brief The starting point for all queue calls
05776  *
05777  * The process involved here is to 
05778  * 1. Parse the options specified in the call to Queue()
05779  * 2. Join the queue
05780  * 3. Wait in a loop until it is our turn to try calling a queue member
05781  * 4. Attempt to call a queue member
05782  * 5. If 4. did not result in a bridged call, then check for between
05783  *    call options such as periodic announcements etc.
05784  * 6. Try 4 again unless some condition (such as an expiration time) causes us to 
05785  *    exit the queue.
05786  */
05787 static int queue_exec(struct ast_channel *chan, const char *data)
05788 {
05789    int res=-1;
05790    int ringing=0;
05791    const char *user_priority;
05792    const char *max_penalty_str;
05793    const char *min_penalty_str;
05794    int prio;
05795    int qcontinue = 0;
05796    int max_penalty, min_penalty;
05797    enum queue_result reason = QUEUE_UNKNOWN;
05798    /* whether to exit Queue application after the timeout hits */
05799    int tries = 0;
05800    int noption = 0;
05801    char *parse;
05802    int makeannouncement = 0;
05803    int position = 0;
05804    AST_DECLARE_APP_ARGS(args,
05805       AST_APP_ARG(queuename);
05806       AST_APP_ARG(options);
05807       AST_APP_ARG(url);
05808       AST_APP_ARG(announceoverride);
05809       AST_APP_ARG(queuetimeoutstr);
05810       AST_APP_ARG(agi);
05811       AST_APP_ARG(macro);
05812       AST_APP_ARG(gosub);
05813       AST_APP_ARG(rule);
05814       AST_APP_ARG(position);
05815    );
05816    /* Our queue entry */
05817    struct queue_ent qe = { 0 };
05818    
05819    if (ast_strlen_zero(data)) {
05820       ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
05821       return -1;
05822    }
05823    
05824    parse = ast_strdupa(data);
05825    AST_STANDARD_APP_ARGS(args, parse);
05826 
05827    /* Setup our queue entry */
05828    qe.start = time(NULL);
05829 
05830    /* set the expire time based on the supplied timeout; */
05831    if (!ast_strlen_zero(args.queuetimeoutstr))
05832       qe.expire = qe.start + atoi(args.queuetimeoutstr);
05833    else
05834       qe.expire = 0;
05835 
05836    /* Get the priority from the variable ${QUEUE_PRIO} */
05837    ast_channel_lock(chan);
05838    user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
05839    if (user_priority) {
05840       if (sscanf(user_priority, "%30d", &prio) == 1) {
05841          ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", chan->name, prio);
05842       } else {
05843          ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
05844             user_priority, chan->name);
05845          prio = 0;
05846       }
05847    } else {
05848       ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
05849       prio = 0;
05850    }
05851 
05852    /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
05853 
05854    if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
05855       if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
05856          ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", chan->name, max_penalty);
05857       } else {
05858          ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
05859             max_penalty_str, chan->name);
05860          max_penalty = 0;
05861       }
05862    } else {
05863       max_penalty = 0;
05864    }
05865 
05866    if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
05867       if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
05868          ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", chan->name, min_penalty);
05869       } else {
05870          ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
05871             min_penalty_str, chan->name);
05872          min_penalty = 0;
05873       }
05874    } else {
05875       min_penalty = 0;
05876    }
05877    ast_channel_unlock(chan);
05878 
05879    if (args.options && (strchr(args.options, 'r')))
05880       ringing = 1;
05881 
05882    if (ringing != 1 && args.options && (strchr(args.options, 'R'))) {
05883       qe.ring_when_ringing = 1;
05884    }
05885 
05886    if (args.options && (strchr(args.options, 'c')))
05887       qcontinue = 1;
05888 
05889    if (args.position) {
05890       position = atoi(args.position);
05891       if (position < 0) {
05892          ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
05893          position = 0;
05894       }
05895    }
05896 
05897    ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
05898       args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
05899 
05900    qe.chan = chan;
05901    qe.prio = prio;
05902    qe.max_penalty = max_penalty;
05903    qe.min_penalty = min_penalty;
05904    qe.last_pos_said = 0;
05905    qe.last_pos = 0;
05906    qe.last_periodic_announce_time = time(NULL);
05907    qe.last_periodic_announce_sound = 0;
05908    qe.valid_digits = 0;
05909    if (join_queue(args.queuename, &qe, &reason, position)) {
05910       ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
05911       set_queue_result(chan, reason);
05912       return 0;
05913    }
05914    ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s|%d",
05915       S_OR(args.url, ""),
05916       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
05917       qe.opos);
05918    copy_rules(&qe, args.rule);
05919    qe.pr = AST_LIST_FIRST(&qe.qe_rules);
05920 check_turns:
05921    if (ringing) {
05922       ast_indicate(chan, AST_CONTROL_RINGING);
05923    } else {
05924       ast_moh_start(chan, qe.moh, NULL);
05925    }
05926 
05927    /* This is the wait loop for callers 2 through maxlen */
05928    res = wait_our_turn(&qe, ringing, &reason);
05929    if (res) {
05930       goto stop;
05931    }
05932 
05933    makeannouncement = 0;
05934 
05935    for (;;) {
05936       /* This is the wait loop for the head caller*/
05937       /* To exit, they may get their call answered; */
05938       /* they may dial a digit from the queue context; */
05939       /* or, they may timeout. */
05940 
05941       /* Leave if we have exceeded our queuetimeout */
05942       if (qe.expire && (time(NULL) >= qe.expire)) {
05943          record_abandoned(&qe);
05944          reason = QUEUE_TIMEOUT;
05945          res = 0;
05946          ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", 
05947             qe.pos, qe.opos, (long) time(NULL) - qe.start);
05948          break;
05949       }
05950 
05951       if (makeannouncement) {
05952          /* Make a position announcement, if enabled */
05953          if (qe.parent->announcefrequency)
05954             if ((res = say_position(&qe,ringing)))
05955                goto stop;
05956       }
05957       makeannouncement = 1;
05958 
05959       /* Make a periodic announcement, if enabled */
05960       if (qe.parent->periodicannouncefrequency)
05961          if ((res = say_periodic_announcement(&qe,ringing)))
05962             goto stop;
05963    
05964       /* Leave if we have exceeded our queuetimeout */
05965       if (qe.expire && (time(NULL) >= qe.expire)) {
05966          record_abandoned(&qe);
05967          reason = QUEUE_TIMEOUT;
05968          res = 0;
05969          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
05970          break;
05971       }
05972 
05973       /* see if we need to move to the next penalty level for this queue */
05974       while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
05975          update_qe_rule(&qe);
05976       }
05977 
05978       /* Try calling all queue members for 'timeout' seconds */
05979       res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
05980       if (res) {
05981          goto stop;
05982       }
05983 
05984       if (qe.parent->leavewhenempty) {
05985          int status = 0;
05986          if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty))) {
05987             record_abandoned(&qe);
05988             reason = QUEUE_LEAVEEMPTY;
05989             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
05990             res = 0;
05991             break;
05992          }
05993       }
05994 
05995       /* exit after 'timeout' cycle if 'n' option enabled */
05996       if (noption && tries >= ao2_container_count(qe.parent->members)) {
05997          ast_verb(3, "Exiting on time-out cycle\n");
05998          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
05999          record_abandoned(&qe);
06000          reason = QUEUE_TIMEOUT;
06001          res = 0;
06002          break;
06003       }
06004 
06005       
06006       /* Leave if we have exceeded our queuetimeout */
06007       if (qe.expire && (time(NULL) >= qe.expire)) {
06008          record_abandoned(&qe);
06009          reason = QUEUE_TIMEOUT;
06010          res = 0;
06011          ast_queue_log(qe.parent->name, qe.chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) time(NULL) - qe.start);
06012          break;
06013       }
06014 
06015       /* If using dynamic realtime members, we should regenerate the member list for this queue */
06016       update_realtime_members(qe.parent);
06017       /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
06018       res = wait_a_bit(&qe);
06019       if (res)
06020          goto stop;
06021 
06022       /* Since this is a priority queue and
06023        * it is not sure that we are still at the head
06024        * of the queue, go and check for our turn again.
06025        */
06026       if (!is_our_turn(&qe)) {
06027          ast_debug(1, "Darn priorities, going back in queue (%s)!\n", qe.chan->name);
06028          goto check_turns;
06029       }
06030    }
06031 
06032 stop:
06033    if (res) {
06034       if (res < 0) {
06035          if (!qe.handled) {
06036             record_abandoned(&qe);
06037             ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
06038                "%d|%d|%ld", qe.pos, qe.opos,
06039                (long) time(NULL) - qe.start);
06040             res = -1;
06041          } else if (qcontinue) {
06042             reason = QUEUE_CONTINUE;
06043             res = 0;
06044          }
06045       } else if (qe.valid_digits) {
06046          ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
06047             "%s|%d", qe.digits, qe.pos);
06048       }
06049    }
06050 
06051    /* Don't allow return code > 0 */
06052    if (res >= 0) {
06053       res = 0; 
06054       if (ringing) {
06055          ast_indicate(chan, -1);
06056       } else {
06057          ast_moh_stop(chan);
06058       }        
06059       ast_stopstream(chan);
06060    }
06061 
06062    set_queue_variables(qe.parent, qe.chan);
06063 
06064    leave_queue(&qe);
06065    if (reason != QUEUE_UNKNOWN)
06066       set_queue_result(chan, reason);
06067 
06068    if (qe.parent) {
06069       /* every queue_ent is given a reference to it's parent call_queue when it joins the queue.
06070        * This ref must be taken away right before the queue_ent is destroyed.  In this case
06071        * the queue_ent is about to be returned on the stack */
06072       qe.parent = queue_unref(qe.parent);
06073    }
06074 
06075    return res;
06076 }
06077 
06078 /*!
06079  * \brief create interface var with all queue details.
06080  * \retval 0 on success
06081  * \retval -1 on error
06082 */
06083 static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06084 {
06085    int res = -1;
06086    struct call_queue *q, tmpq = {
06087       .name = data,  
06088    };
06089 
06090    char interfacevar[256] = "";
06091    float sl = 0;
06092 
06093    if (ast_strlen_zero(data)) {
06094       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06095       return -1;
06096    }
06097 
06098    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) {
06099       ao2_lock(q);
06100       if (q->setqueuevar) {
06101          sl = 0;
06102          res = 0;
06103 
06104          if (q->callscompleted > 0) {
06105             sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
06106          }
06107 
06108          snprintf(interfacevar, sizeof(interfacevar),
06109             "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
06110             q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned,  q->servicelevel, sl);
06111 
06112          pbx_builtin_setvar_multiple(chan, interfacevar);
06113       }
06114 
06115       ao2_unlock(q);
06116       queue_t_unref(q, "Done with QUEUE() function");
06117    } else {
06118       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06119    }
06120 
06121    snprintf(buf, len, "%d", res);
06122 
06123    return 0;
06124 }
06125 
06126 /*!
06127  * \brief Check if a given queue exists
06128  *
06129  */
06130 static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06131 {
06132    struct call_queue *q;
06133 
06134    buf[0] = '\0';
06135 
06136    if (ast_strlen_zero(data)) {
06137       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06138       return -1;
06139    }
06140    q = load_realtime_queue(data);
06141    snprintf(buf, len, "%d", q != NULL? 1 : 0);
06142    if (q) {
06143       queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
06144    }
06145 
06146    return 0;
06147 }
06148 
06149 /*! 
06150  * \brief Get number either busy / free / ready or total members of a specific queue
06151  * \retval number of members (busy / free / ready / total)
06152  * \retval -1 on error
06153 */
06154 static int queue_function_qac(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06155 {
06156    int count = 0;
06157    struct member *m;
06158    struct ao2_iterator mem_iter;
06159    struct call_queue *q;
06160    char *option;
06161 
06162    if (ast_strlen_zero(data)) {
06163       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06164       return -1;
06165    }
06166 
06167    if ((option = strchr(data, ',')))
06168       *option++ = '\0';
06169    else
06170       option = "logged";
06171    if ((q = load_realtime_queue(data))) {
06172       ao2_lock(q);
06173       if (!strcasecmp(option, "logged")) {
06174          mem_iter = ao2_iterator_init(q->members, 0);
06175          while ((m = ao2_iterator_next(&mem_iter))) {
06176             /* Count the agents who are logged in and presently answering calls */
06177             if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06178                count++;
06179             }
06180             ao2_ref(m, -1);
06181          }
06182          ao2_iterator_destroy(&mem_iter);
06183       } else if (!strcasecmp(option, "free")) {
06184          mem_iter = ao2_iterator_init(q->members, 0);
06185          while ((m = ao2_iterator_next(&mem_iter))) {
06186             /* Count the agents who are logged in and presently answering calls */
06187             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
06188                count++;
06189             }
06190             ao2_ref(m, -1);
06191          }
06192          ao2_iterator_destroy(&mem_iter);
06193       } else if (!strcasecmp(option, "ready")) {
06194          time_t now;
06195          time(&now);
06196          mem_iter = ao2_iterator_init(q->members, 0);
06197          while ((m = ao2_iterator_next(&mem_iter))) {
06198             /* Count the agents who are logged in, not paused and not wrapping up */
06199             if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
06200                   !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
06201                count++;
06202             }
06203             ao2_ref(m, -1);
06204          }
06205          ao2_iterator_destroy(&mem_iter);
06206       } else /* must be "count" */
06207          count = ao2_container_count(q->members);
06208       ao2_unlock(q);
06209       queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
06210    } else
06211       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06212 
06213    snprintf(buf, len, "%d", count);
06214 
06215    return 0;
06216 }
06217 
06218 /*! 
06219  * \brief Get the total number of members in a specific queue (Deprecated)
06220  * \retval number of members 
06221  * \retval -1 on error 
06222 */
06223 static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06224 {
06225    int count = 0;
06226    struct member *m;
06227    struct call_queue *q;
06228    struct ao2_iterator mem_iter;
06229    static int depflag = 1;
06230 
06231    if (depflag) {
06232       depflag = 0;
06233       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");
06234    }
06235 
06236    if (ast_strlen_zero(data)) {
06237       ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
06238       return -1;
06239    }
06240    
06241    if ((q = load_realtime_queue(data))) {
06242       ao2_lock(q);
06243       mem_iter = ao2_iterator_init(q->members, 0);
06244       while ((m = ao2_iterator_next(&mem_iter))) {
06245          /* Count the agents who are logged in and presently answering calls */
06246          if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
06247             count++;
06248          }
06249          ao2_ref(m, -1);
06250       }
06251       ao2_iterator_destroy(&mem_iter);
06252       ao2_unlock(q);
06253       queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
06254    } else
06255       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06256 
06257    snprintf(buf, len, "%d", count);
06258 
06259    return 0;
06260 }
06261 
06262 /*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
06263 static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06264 {
06265    int count = 0;
06266    struct call_queue *q, tmpq = {
06267       .name = data,  
06268    };
06269    struct ast_variable *var = NULL;
06270 
06271    buf[0] = '\0';
06272    
06273    if (ast_strlen_zero(data)) {
06274       ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
06275       return -1;
06276    }
06277 
06278    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
06279       ao2_lock(q);
06280       count = q->count;
06281       ao2_unlock(q);
06282       queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
06283    } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
06284       /* if the queue is realtime but was not found in memory, this
06285        * means that the queue had been deleted from memory since it was 
06286        * "dead." This means it has a 0 waiting count
06287        */
06288       count = 0;
06289       ast_variables_destroy(var);
06290    } else
06291       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06292 
06293    snprintf(buf, len, "%d", count);
06294 
06295    return 0;
06296 }
06297 
06298 /*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
06299 static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06300 {
06301    struct call_queue *q, tmpq = {
06302       .name = data,  
06303    };
06304    struct member *m;
06305 
06306    /* Ensure an otherwise empty list doesn't return garbage */
06307    buf[0] = '\0';
06308 
06309    if (ast_strlen_zero(data)) {
06310       ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
06311       return -1;
06312    }
06313 
06314    if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
06315       int buflen = 0, count = 0;
06316       struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
06317 
06318       ao2_lock(q);
06319       while ((m = ao2_iterator_next(&mem_iter))) {
06320          /* strcat() is always faster than printf() */
06321          if (count++) {
06322             strncat(buf + buflen, ",", len - buflen - 1);
06323             buflen++;
06324          }
06325          strncat(buf + buflen, m->interface, len - buflen - 1);
06326          buflen += strlen(m->interface);
06327          /* Safeguard against overflow (negative length) */
06328          if (buflen >= len - 2) {
06329             ao2_ref(m, -1);
06330             ast_log(LOG_WARNING, "Truncating list\n");
06331             break;
06332          }
06333          ao2_ref(m, -1);
06334       }
06335       ao2_iterator_destroy(&mem_iter);
06336       ao2_unlock(q);
06337       queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
06338    } else
06339       ast_log(LOG_WARNING, "queue %s was not found\n", data);
06340 
06341    /* We should already be terminated, but let's make sure. */
06342    buf[len - 1] = '\0';
06343 
06344    return 0;
06345 }
06346 
06347 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
06348 static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
06349 {
06350    int penalty;
06351    AST_DECLARE_APP_ARGS(args,
06352       AST_APP_ARG(queuename);
06353       AST_APP_ARG(interface);
06354    );
06355    /* Make sure the returned value on error is NULL. */
06356    buf[0] = '\0';
06357 
06358    if (ast_strlen_zero(data)) {
06359       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06360       return -1;
06361    }
06362 
06363    AST_STANDARD_APP_ARGS(args, data);
06364 
06365    if (args.argc < 2) {
06366       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06367       return -1;
06368    }
06369 
06370    penalty = get_member_penalty (args.queuename, args.interface);
06371    
06372    if (penalty >= 0) /* remember that buf is already '\0' */
06373       snprintf (buf, len, "%d", penalty);
06374 
06375    return 0;
06376 }
06377 
06378 /*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
06379 static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
06380 {
06381    int penalty;
06382    AST_DECLARE_APP_ARGS(args,
06383       AST_APP_ARG(queuename);
06384       AST_APP_ARG(interface);
06385    );
06386 
06387    if (ast_strlen_zero(data)) {
06388       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06389       return -1;
06390    }
06391 
06392    AST_STANDARD_APP_ARGS(args, data);
06393 
06394    if (args.argc < 2) {
06395       ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
06396       return -1;
06397    }
06398 
06399    penalty = atoi(value);
06400 
06401    if (ast_strlen_zero(args.interface)) {
06402       ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
06403       return -1;
06404    }
06405 
06406    /* if queuename = NULL then penalty will be set for interface in all the queues. */
06407    if (set_member_penalty(args.queuename, args.interface, penalty)) {
06408       ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
06409       return -1;
06410    }
06411 
06412    return 0;
06413 }
06414 
06415 static struct ast_custom_function queueexists_function = {
06416    .name = "QUEUE_EXISTS",
06417    .read = queue_function_exists,
06418 };
06419 
06420 static struct ast_custom_function queuevar_function = {
06421    .name = "QUEUE_VARIABLES",
06422    .read = queue_function_var,
06423 };
06424 
06425 static struct ast_custom_function queuemembercount_function = {
06426    .name = "QUEUE_MEMBER",
06427    .read = queue_function_qac,
06428 };
06429 
06430 static struct ast_custom_function queuemembercount_dep = {
06431    .name = "QUEUE_MEMBER_COUNT",
06432    .read = queue_function_qac_dep,
06433 };
06434 
06435 static struct ast_custom_function queuewaitingcount_function = {
06436    .name = "QUEUE_WAITING_COUNT",
06437    .read = queue_function_queuewaitingcount,
06438 };
06439 
06440 static struct ast_custom_function queuememberlist_function = {
06441    .name = "QUEUE_MEMBER_LIST",
06442    .read = queue_function_queuememberlist,
06443 };
06444 
06445 static struct ast_custom_function queuememberpenalty_function = {
06446    .name = "QUEUE_MEMBER_PENALTY",
06447    .read = queue_function_memberpenalty_read,
06448    .write = queue_function_memberpenalty_write,
06449 };
06450 
06451 /*! \brief Reload the rules defined in queuerules.conf
06452  *
06453  * \param reload If 1, then only process queuerules.conf if the file
06454  * has changed since the last time we inspected it.
06455  * \return Always returns AST_MODULE_LOAD_SUCCESS
06456  */
06457 static int reload_queue_rules(int reload)
06458 {
06459    struct ast_config *cfg;
06460    struct rule_list *rl_iter, *new_rl;
06461    struct penalty_rule *pr_iter;
06462    char *rulecat = NULL;
06463    struct ast_variable *rulevar = NULL;
06464    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06465    
06466    if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
06467       ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
06468       return AST_MODULE_LOAD_SUCCESS;
06469    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06470       ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
06471       return AST_MODULE_LOAD_SUCCESS;
06472    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06473       ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format.  Aborting.\n");
06474       return AST_MODULE_LOAD_SUCCESS;
06475    }
06476 
06477    AST_LIST_LOCK(&rule_lists);
06478    while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
06479       while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
06480          ast_free(pr_iter);
06481       ast_free(rl_iter);
06482    }
06483    while ((rulecat = ast_category_browse(cfg, rulecat))) {
06484       if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
06485          AST_LIST_UNLOCK(&rule_lists);
06486          ast_config_destroy(cfg);
06487          return AST_MODULE_LOAD_FAILURE;
06488       } else {
06489          ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
06490          AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
06491          for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
06492             if(!strcasecmp(rulevar->name, "penaltychange"))
06493                insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
06494             else
06495                ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
06496       }
06497    }
06498    AST_LIST_UNLOCK(&rule_lists);
06499 
06500    ast_config_destroy(cfg);
06501 
06502    return AST_MODULE_LOAD_SUCCESS;
06503 }
06504 
06505 /*! Set the global queue parameters as defined in the "general" section of queues.conf */
06506 static void queue_set_global_params(struct ast_config *cfg)
06507 {
06508    const char *general_val = NULL;
06509    queue_persistent_members = 0;
06510    if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
06511       queue_persistent_members = ast_true(general_val);
06512    autofill_default = 0;
06513    if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
06514       autofill_default = ast_true(general_val);
06515    montype_default = 0;
06516    if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
06517       if (!strcasecmp(general_val, "mixmonitor"))
06518          montype_default = 1;
06519    }
06520    update_cdr = 0;
06521    if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
06522       update_cdr = ast_true(general_val);
06523    shared_lastcall = 0;
06524    if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
06525       shared_lastcall = ast_true(general_val);
06526 }
06527 
06528 /*! \brief reload information pertaining to a single member
06529  *
06530  * This function is called when a member = line is encountered in
06531  * queues.conf.
06532  *
06533  * \param memberdata The part after member = in the config file
06534  * \param q The queue to which this member belongs
06535  */
06536 static void reload_single_member(const char *memberdata, struct call_queue *q)
06537 {
06538    char *membername, *interface, *state_interface, *tmp;
06539    char *parse;
06540    struct member *cur, *newm;
06541    struct member tmpmem;
06542    int penalty;
06543    AST_DECLARE_APP_ARGS(args,
06544       AST_APP_ARG(interface);
06545       AST_APP_ARG(penalty);
06546       AST_APP_ARG(membername);
06547       AST_APP_ARG(state_interface);
06548    );
06549 
06550    if (ast_strlen_zero(memberdata)) {
06551       ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
06552       return;
06553    }
06554 
06555    /* Add a new member */
06556    parse = ast_strdupa(memberdata);
06557             
06558    AST_STANDARD_APP_ARGS(args, parse);
06559 
06560    interface = args.interface;
06561    if (!ast_strlen_zero(args.penalty)) {
06562       tmp = args.penalty;
06563       ast_strip(tmp);
06564       penalty = atoi(tmp);
06565       if (penalty < 0) {
06566          penalty = 0;
06567       }
06568    } else {
06569       penalty = 0;
06570    }
06571 
06572    if (!ast_strlen_zero(args.membername)) {
06573       membername = args.membername;
06574       ast_strip(membername);
06575    } else {
06576       membername = interface;
06577    }
06578 
06579    if (!ast_strlen_zero(args.state_interface)) {
06580       state_interface = args.state_interface;
06581       ast_strip(state_interface);
06582    } else {
06583       state_interface = interface;
06584    }
06585 
06586    /* Find the old position in the list */
06587    ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
06588    cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
06589    if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface))) {
06590       ao2_link(q->members, newm);
06591       ao2_ref(newm, -1);
06592    }
06593    newm = NULL;
06594 
06595    if (cur) {
06596       ao2_ref(cur, -1);
06597    }
06598 }
06599 
06600 static int mark_member_dead(void *obj, void *arg, int flags)
06601 {
06602    struct member *member = obj;
06603    if (!member->dynamic) {
06604       member->delme = 1;
06605    }
06606    return 0;
06607 }
06608 
06609 static int kill_dead_members(void *obj, void *arg, int flags)
06610 {
06611    struct member *member = obj;
06612 
06613    if (!member->delme) {
06614       member->status = get_queue_member_status(member);
06615       return 0;
06616    } else {
06617       return CMP_MATCH;
06618    }
06619 }
06620 
06621 /*! \brief Reload information pertaining to a particular queue
06622  *
06623  * Once we have isolated a queue within reload_queues, we call this. This will either
06624  * reload information for the queue or if we're just reloading member information, we'll just
06625  * reload that without touching other settings within the queue 
06626  *
06627  * \param cfg The configuration which we are reading
06628  * \param mask Tells us what information we need to reload
06629  * \param queuename The name of the queue we are reloading information from
06630  * \retval void
06631  */
06632 static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
06633 {
06634    int new;
06635    struct call_queue *q = NULL;
06636    /*We're defining a queue*/
06637    struct call_queue tmpq = {
06638       .name = queuename,
06639    };
06640    const char *tmpvar;
06641    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06642    const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
06643    int prev_weight = 0;
06644    struct ast_variable *var;
06645    if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
06646       if (queue_reload) {
06647          /* Make one then */
06648          if (!(q = alloc_queue(queuename))) {
06649             return;
06650          }
06651       } else {
06652          /* Since we're not reloading queues, this means that we found a queue
06653           * in the configuration file which we don't know about yet. Just return.
06654           */
06655          return;
06656       }
06657       new = 1;
06658    } else {
06659       new = 0;
06660    }
06661    
06662    if (!new) {
06663       ao2_lock(q);
06664       prev_weight = q->weight ? 1 : 0;
06665    }
06666    /* Check if we already found a queue with this name in the config file */
06667    if (q->found) {
06668       ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
06669       if (!new) {
06670          /* It should be impossible to *not* hit this case*/
06671          ao2_unlock(q);
06672       }
06673       queue_t_unref(q, "We exist! Expiring temporary pointer");
06674       return;
06675    }
06676    /* Due to the fact that the "linear" strategy will have a different allocation
06677     * scheme for queue members, we must devise the queue's strategy before other initializations.
06678     * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
06679     * container used will have only a single bucket instead of the typical number.
06680     */
06681    if (queue_reload) {
06682       if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
06683          q->strategy = strat2int(tmpvar);
06684          if (q->strategy < 0) {
06685             ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
06686             tmpvar, q->name);
06687             q->strategy = QUEUE_STRATEGY_RINGALL;
06688          }
06689       } else {
06690          q->strategy = QUEUE_STRATEGY_RINGALL;
06691       }
06692       init_queue(q);
06693    }
06694    if (member_reload) {
06695       ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
06696    }
06697    for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
06698       if (member_reload && !strcasecmp(var->name, "member")) {
06699          reload_single_member(var->value, q);
06700       } else if (queue_reload) {
06701          queue_set_param(q, var->name, var->value, var->lineno, 1);
06702       }
06703    }
06704    /* At this point, we've determined if the queue has a weight, so update use_weight
06705     * as appropriate
06706     */
06707    if (!q->weight && prev_weight) {
06708       ast_atomic_fetchadd_int(&use_weight, -1);
06709    }
06710    else if (q->weight && !prev_weight) {
06711       ast_atomic_fetchadd_int(&use_weight, +1);
06712    }
06713 
06714    /* Free remaining members marked as delme */
06715    if (member_reload) {
06716       ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
06717    }
06718 
06719    if (new) {
06720       queues_t_link(queues, q, "Add queue to container");
06721    } else {
06722       ao2_unlock(q);
06723    }
06724    queue_t_unref(q, "Expiring creation reference");
06725 }
06726 
06727 static int mark_dead_and_unfound(void *obj, void *arg, int flags)
06728 {
06729    struct call_queue *q = obj;
06730    char *queuename = arg;
06731    if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
06732       q->dead = 1;
06733       q->found = 0;
06734    }
06735    return 0;
06736 }
06737 
06738 static int kill_dead_queues(void *obj, void *arg, int flags)
06739 {
06740    struct call_queue *q = obj;
06741    char *queuename = arg;
06742    if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
06743       return CMP_MATCH;
06744    } else {
06745       return 0;
06746    }
06747 }
06748 
06749 /*! \brief reload the queues.conf file
06750  *
06751  * This function reloads the information in the general section of the queues.conf
06752  * file and potentially more, depending on the value of mask.
06753  *
06754  * \param reload 0 if we are calling this the first time, 1 every other time
06755  * \param mask Gives flags telling us what information to actually reload
06756  * \param queuename If set to a non-zero string, then only reload information from
06757  * that particular queue. Otherwise inspect all queues
06758  * \retval -1 Failure occurred 
06759  * \retval 0 All clear!
06760  */
06761 static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
06762 {
06763    struct ast_config *cfg;
06764    char *cat;
06765    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
06766    const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
06767 
06768    if (!(cfg = ast_config_load("queues.conf", config_flags))) {
06769       ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
06770       return -1;
06771    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
06772       return 0;
06773    } else if (cfg == CONFIG_STATUS_FILEINVALID) {
06774       ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format.  Aborting.\n");
06775       return -1;
06776    }
06777 
06778    /* We've made it here, so it looks like we're doing operations on all queues. */
06779    ao2_lock(queues);
06780 
06781    /* Mark all queues as dead for the moment if we're reloading queues.
06782     * For clarity, we could just be reloading members, in which case we don't want to mess
06783     * with the other queue parameters at all*/
06784    if (queue_reload) {
06785       ao2_callback(queues, OBJ_NODATA, mark_dead_and_unfound, (char *) queuename);
06786    }
06787 
06788    /* Chug through config file */
06789    cat = NULL;
06790    while ((cat = ast_category_browse(cfg, cat)) ) {
06791       if (!strcasecmp(cat, "general") && queue_reload) {
06792          queue_set_global_params(cfg);
06793          continue;
06794       }
06795       if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
06796          reload_single_queue(cfg, mask, cat);
06797    }
06798 
06799    ast_config_destroy(cfg);
06800    /* Unref all the dead queues if we were reloading queues */
06801    if (queue_reload) {
06802       ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_queues, (char *) queuename);
06803    }
06804    ao2_unlock(queues);
06805    return 0;
06806 }
06807 
06808 /*! \brief Facilitates resetting statistics for a queue
06809  *
06810  * This function actually does not reset any statistics, but
06811  * rather finds a call_queue struct which corresponds to the
06812  * passed-in queue name and passes that structure to the
06813  * clear_queue function. If no queuename is passed in, then
06814  * all queues will have their statistics reset.
06815  *
06816  * \param queuename The name of the queue to reset the statistics
06817  * for. If this is NULL or zero-length, then this means to reset
06818  * the statistics for all queues
06819  * \retval void
06820  */
06821 static int clear_stats(const char *queuename)
06822 {
06823    struct call_queue *q;
06824    struct ao2_iterator queue_iter = ao2_iterator_init(queues, 0);
06825    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06826       ao2_lock(q);
06827       if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
06828          clear_queue(q);
06829       ao2_unlock(q);
06830       queue_t_unref(q, "Done with iterator");
06831    }
06832    ao2_iterator_destroy(&queue_iter);
06833    return 0;
06834 }
06835 
06836 /*! \brief The command center for all reload operations
06837  *
06838  * Whenever any piece of queue information is to be reloaded, this function
06839  * is called. It interprets the flags set in the mask parameter and acts
06840  * based on how they are set.
06841  *
06842  * \param reload True if we are reloading information, false if we are loading
06843  * information for the first time.
06844  * \param mask A bitmask which tells the handler what actions to take
06845  * \param queuename The name of the queue on which we wish to take action
06846  * \retval 0 All reloads were successful
06847  * \retval non-zero There was a failure
06848  */
06849 static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
06850 {
06851    int res = 0;
06852 
06853    if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
06854       res |= reload_queue_rules(reload);
06855    }
06856    if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
06857       res |= clear_stats(queuename);
06858    }
06859    if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
06860       res |= reload_queues(reload, mask, queuename);
06861    }
06862    return res;
06863 }
06864 
06865 /*! \brief direct ouput to manager or cli with proper terminator */
06866 static void do_print(struct mansession *s, int fd, const char *str)
06867 {
06868    if (s)
06869       astman_append(s, "%s\r\n", str);
06870    else
06871       ast_cli(fd, "%s\n", str);
06872 }
06873 
06874 /*! 
06875  * \brief Show queue(s) status and statistics 
06876  * 
06877  * List the queues strategy, calls processed, members logged in,
06878  * other queue statistics such as avg hold time.
06879 */
06880 static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
06881 {
06882    struct call_queue *q;
06883    struct ast_str *out = ast_str_alloca(240);
06884    int found = 0;
06885    time_t now = time(NULL);
06886    struct ao2_iterator queue_iter;
06887    struct ao2_iterator mem_iter;
06888 
06889    if (argc != 2 && argc != 3)
06890       return CLI_SHOWUSAGE;
06891 
06892    if (argc == 3) { /* specific queue */
06893       if ((q = load_realtime_queue(argv[2]))) {
06894          queue_t_unref(q, "Done with temporary pointer");
06895       }
06896    } else if (ast_check_realtime("queues")) {
06897       /* This block is to find any queues which are defined in realtime but
06898        * which have not yet been added to the in-core container
06899        */
06900       struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
06901       char *queuename;
06902       if (cfg) {
06903          for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
06904             if ((q = load_realtime_queue(queuename))) {
06905                queue_t_unref(q, "Done with temporary pointer");
06906             }
06907          }
06908          ast_config_destroy(cfg);
06909       }
06910    }
06911 
06912    queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
06913    ao2_lock(queues);
06914    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
06915       float sl;
06916       struct call_queue *realtime_queue = NULL;
06917 
06918       ao2_lock(q);
06919       /* This check is to make sure we don't print information for realtime
06920        * queues which have been deleted from realtime but which have not yet
06921        * been deleted from the in-core container
06922        */
06923       if (q->realtime) {
06924          realtime_queue = load_realtime_queue(q->name);
06925          if (!realtime_queue) {
06926             ao2_unlock(q);
06927             queue_t_unref(q, "Done with iterator");
06928             continue;
06929          }
06930          queue_t_unref(realtime_queue, "Queue is already in memory");
06931       }
06932 
06933       if (argc == 3 && strcasecmp(q->name, argv[2])) {
06934          ao2_unlock(q);
06935          queue_t_unref(q, "Done with iterator");
06936          continue;
06937       }
06938       found = 1;
06939 
06940       ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
06941       if (q->maxlen)
06942          ast_str_append(&out, 0, "%d", q->maxlen);
06943       else
06944          ast_str_append(&out, 0, "unlimited");
06945       sl = 0;
06946       if (q->callscompleted > 0)
06947          sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
06948       ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
06949          int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
06950          q->callscompleted, q->callsabandoned,sl,q->servicelevel);
06951       do_print(s, fd, ast_str_buffer(out));
06952       if (!ao2_container_count(q->members))
06953          do_print(s, fd, "   No Members");
06954       else {
06955          struct member *mem;
06956 
06957          do_print(s, fd, "   Members: ");
06958          mem_iter = ao2_iterator_init(q->members, 0);
06959          while ((mem = ao2_iterator_next(&mem_iter))) {
06960             ast_str_set(&out, 0, "      %s", mem->membername);
06961             if (strcasecmp(mem->membername, mem->interface)) {
06962                ast_str_append(&out, 0, " (%s)", mem->interface);
06963             }
06964             if (mem->penalty)
06965                ast_str_append(&out, 0, " with penalty %d", mem->penalty);
06966             ast_str_append(&out, 0, "%s%s%s (%s)",
06967                mem->dynamic ? " (dynamic)" : "",
06968                mem->realtime ? " (realtime)" : "",
06969                mem->paused ? " (paused)" : "",
06970                ast_devstate2str(mem->status));
06971             if (mem->calls)
06972                ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
06973                   mem->calls, (long) (time(NULL) - mem->lastcall));
06974             else
06975                ast_str_append(&out, 0, " has taken no calls yet");
06976             do_print(s, fd, ast_str_buffer(out));
06977             ao2_ref(mem, -1);
06978          }
06979          ao2_iterator_destroy(&mem_iter);
06980       }
06981       if (!q->head)
06982          do_print(s, fd, "   No Callers");
06983       else {
06984          struct queue_ent *qe;
06985          int pos = 1;
06986 
06987          do_print(s, fd, "   Callers: ");
06988          for (qe = q->head; qe; qe = qe->next) {
06989             ast_str_set(&out, 0, "      %d. %s (wait: %ld:%2.2ld, prio: %d)",
06990                pos++, qe->chan->name, (long) (now - qe->start) / 60,
06991                (long) (now - qe->start) % 60, qe->prio);
06992             do_print(s, fd, ast_str_buffer(out));
06993          }
06994       }
06995       do_print(s, fd, ""); /* blank line between entries */
06996       ao2_unlock(q);
06997       queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
06998    }
06999    ao2_iterator_destroy(&queue_iter);
07000    ao2_unlock(queues);
07001    if (!found) {
07002       if (argc == 3)
07003          ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
07004       else
07005          ast_str_set(&out, 0, "No queues.");
07006       do_print(s, fd, ast_str_buffer(out));
07007    }
07008    return CLI_SUCCESS;
07009 }
07010 
07011 static char *complete_queue(const char *line, const char *word, int pos, int state)
07012 {
07013    struct call_queue *q;
07014    char *ret = NULL;
07015    int which = 0;
07016    int wordlen = strlen(word);
07017    struct ao2_iterator queue_iter;
07018 
07019    queue_iter = ao2_iterator_init(queues, 0);
07020    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07021       if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
07022          ret = ast_strdup(q->name);
07023          queue_t_unref(q, "Done with iterator");
07024          break;
07025       }
07026       queue_t_unref(q, "Done with iterator");
07027    }
07028    ao2_iterator_destroy(&queue_iter);
07029 
07030    return ret;
07031 }
07032 
07033 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
07034 {
07035    if (pos == 2)
07036       return complete_queue(line, word, pos, state);
07037    return NULL;
07038 }
07039 
07040 static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07041 {
07042    switch ( cmd ) {
07043    case CLI_INIT:
07044       e->command = "queue show";
07045       e->usage =
07046          "Usage: queue show\n"
07047          "       Provides summary information on a specified queue.\n";
07048       return NULL;
07049    case CLI_GENERATE:
07050       return complete_queue_show(a->line, a->word, a->pos, a->n); 
07051    }
07052 
07053    return __queues_show(NULL, a->fd, a->argc, a->argv);
07054 }
07055 
07056 /*!\brief callback to display queues status in manager
07057    \addtogroup Group_AMI
07058  */
07059 static int manager_queues_show(struct mansession *s, const struct message *m)
07060 {
07061    static const char * const a[] = { "queue", "show" };
07062 
07063    __queues_show(s, -1, 2, a);
07064    astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
07065 
07066    return RESULT_SUCCESS;
07067 }
07068 
07069 static int manager_queue_rule_show(struct mansession *s, const struct message *m)
07070 {
07071    const char *rule = astman_get_header(m, "Rule");
07072    const char *id = astman_get_header(m, "ActionID");
07073    struct rule_list *rl_iter;
07074    struct penalty_rule *pr_iter;
07075 
07076    astman_append(s, "Response: Success\r\n");
07077    if (!ast_strlen_zero(id)) {
07078       astman_append(s, "ActionID: %s\r\n", id);
07079    }
07080 
07081    AST_LIST_LOCK(&rule_lists);
07082    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07083       if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
07084          astman_append(s, "RuleList: %s\r\n", rl_iter->name);
07085          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07086             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 );
07087          }
07088          if (!ast_strlen_zero(rule))
07089             break;
07090       }
07091    }
07092    AST_LIST_UNLOCK(&rule_lists);
07093 
07094    /*
07095     * Two blank lines instead of one because the Response and
07096     * ActionID headers used to not be present.
07097     */
07098    astman_append(s, "\r\n\r\n");
07099 
07100    return RESULT_SUCCESS;
07101 }
07102 
07103 /*! \brief Summary of queue info via the AMI */
07104 static int manager_queues_summary(struct mansession *s, const struct message *m)
07105 {
07106    time_t now;
07107    int qmemcount = 0;
07108    int qmemavail = 0;
07109    int qchancount = 0;
07110    int qlongestholdtime = 0;
07111    const char *id = astman_get_header(m, "ActionID");
07112    const char *queuefilter = astman_get_header(m, "Queue");
07113    char idText[256] = "";
07114    struct call_queue *q;
07115    struct queue_ent *qe;
07116    struct member *mem;
07117    struct ao2_iterator queue_iter;
07118    struct ao2_iterator mem_iter;
07119 
07120    astman_send_ack(s, m, "Queue summary will follow");
07121    time(&now);
07122    if (!ast_strlen_zero(id))
07123       snprintf(idText, 256, "ActionID: %s\r\n", id);
07124    queue_iter = ao2_iterator_init(queues, 0);
07125    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07126       ao2_lock(q);
07127 
07128       /* List queue properties */
07129       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
07130          /* Reset the necessary local variables if no queuefilter is set*/
07131          qmemcount = 0;
07132          qmemavail = 0;
07133          qchancount = 0;
07134          qlongestholdtime = 0;
07135 
07136          /* List Queue Members */
07137          mem_iter = ao2_iterator_init(q->members, 0);
07138          while ((mem = ao2_iterator_next(&mem_iter))) {
07139             if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
07140                ++qmemcount;
07141                if (((mem->status == AST_DEVICE_NOT_INUSE) || (mem->status == AST_DEVICE_UNKNOWN)) && !(mem->paused)) {
07142                   ++qmemavail;
07143                }
07144             }
07145             ao2_ref(mem, -1);
07146          }
07147          ao2_iterator_destroy(&mem_iter);
07148          for (qe = q->head; qe; qe = qe->next) {
07149             if ((now - qe->start) > qlongestholdtime) {
07150                qlongestholdtime = now - qe->start;
07151             }
07152             ++qchancount;
07153          }
07154          astman_append(s, "Event: QueueSummary\r\n"
07155             "Queue: %s\r\n"
07156             "LoggedIn: %d\r\n"
07157             "Available: %d\r\n"
07158             "Callers: %d\r\n" 
07159             "HoldTime: %d\r\n"
07160             "TalkTime: %d\r\n"
07161             "LongestHoldTime: %d\r\n"
07162             "%s"
07163             "\r\n",
07164             q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
07165       }
07166       ao2_unlock(q);
07167       queue_t_unref(q, "Done with iterator");
07168    }
07169    ao2_iterator_destroy(&queue_iter);
07170    astman_append(s,
07171       "Event: QueueSummaryComplete\r\n"
07172       "%s"
07173       "\r\n", idText);
07174 
07175    return RESULT_SUCCESS;
07176 }
07177 
07178 /*! \brief Queue status info via AMI */
07179 static int manager_queues_status(struct mansession *s, const struct message *m)
07180 {
07181    time_t now;
07182    int pos;
07183    const char *id = astman_get_header(m,"ActionID");
07184    const char *queuefilter = astman_get_header(m,"Queue");
07185    const char *memberfilter = astman_get_header(m,"Member");
07186    char idText[256] = "";
07187    struct call_queue *q;
07188    struct queue_ent *qe;
07189    float sl = 0;
07190    struct member *mem;
07191    struct ao2_iterator queue_iter;
07192    struct ao2_iterator mem_iter;
07193 
07194    astman_send_ack(s, m, "Queue status will follow");
07195    time(&now);
07196    if (!ast_strlen_zero(id))
07197       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
07198 
07199    queue_iter = ao2_iterator_init(queues, 0);
07200    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07201       ao2_lock(q);
07202 
07203       /* List queue properties */
07204       if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
07205          sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
07206          astman_append(s, "Event: QueueParams\r\n"
07207             "Queue: %s\r\n"
07208             "Max: %d\r\n"
07209             "Strategy: %s\r\n"
07210             "Calls: %d\r\n"
07211             "Holdtime: %d\r\n"
07212             "TalkTime: %d\r\n"
07213             "Completed: %d\r\n"
07214             "Abandoned: %d\r\n"
07215             "ServiceLevel: %d\r\n"
07216             "ServicelevelPerf: %2.1f\r\n"
07217             "Weight: %d\r\n"
07218             "%s"
07219             "\r\n",
07220             q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
07221             q->callsabandoned, q->servicelevel, sl, q->weight, idText);
07222          /* List Queue Members */
07223          mem_iter = ao2_iterator_init(q->members, 0);
07224          while ((mem = ao2_iterator_next(&mem_iter))) {
07225             if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
07226                astman_append(s, "Event: QueueMember\r\n"
07227                   "Queue: %s\r\n"
07228                   "Name: %s\r\n"
07229                   "Location: %s\r\n"
07230                   "Membership: %s\r\n"
07231                   "Penalty: %d\r\n"
07232                   "CallsTaken: %d\r\n"
07233                   "LastCall: %d\r\n"
07234                   "Status: %d\r\n"
07235                   "Paused: %d\r\n"
07236                   "%s"
07237                   "\r\n",
07238                   q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
07239                   mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
07240             }
07241             ao2_ref(mem, -1);
07242          }
07243          ao2_iterator_destroy(&mem_iter);
07244          /* List Queue Entries */
07245          pos = 1;
07246          for (qe = q->head; qe; qe = qe->next) {
07247             astman_append(s, "Event: QueueEntry\r\n"
07248                "Queue: %s\r\n"
07249                "Position: %d\r\n"
07250                "Channel: %s\r\n"
07251                "Uniqueid: %s\r\n"
07252                "CallerIDNum: %s\r\n"
07253                "CallerIDName: %s\r\n"
07254                "ConnectedLineNum: %s\r\n"
07255                "ConnectedLineName: %s\r\n"
07256                "Wait: %ld\r\n"
07257                "%s"
07258                "\r\n",
07259                q->name, pos++, qe->chan->name, qe->chan->uniqueid,
07260                S_COR(qe->chan->caller.id.number.valid, qe->chan->caller.id.number.str, "unknown"),
07261                S_COR(qe->chan->caller.id.name.valid, qe->chan->caller.id.name.str, "unknown"),
07262                S_COR(qe->chan->connected.id.number.valid, qe->chan->connected.id.number.str, "unknown"),
07263                S_COR(qe->chan->connected.id.name.valid, qe->chan->connected.id.name.str, "unknown"),
07264                (long) (now - qe->start), idText);
07265          }
07266       }
07267       ao2_unlock(q);
07268       queue_t_unref(q, "Done with iterator");
07269    }
07270    ao2_iterator_destroy(&queue_iter);
07271 
07272    astman_append(s,
07273       "Event: QueueStatusComplete\r\n"
07274       "%s"
07275       "\r\n",idText);
07276 
07277    return RESULT_SUCCESS;
07278 }
07279 
07280 static int manager_add_queue_member(struct mansession *s, const struct message *m)
07281 {
07282    const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
07283    int paused, penalty = 0;
07284 
07285    queuename = astman_get_header(m, "Queue");
07286    interface = astman_get_header(m, "Interface");
07287    penalty_s = astman_get_header(m, "Penalty");
07288    paused_s = astman_get_header(m, "Paused");
07289    membername = astman_get_header(m, "MemberName");
07290    state_interface = astman_get_header(m, "StateInterface");
07291 
07292    if (ast_strlen_zero(queuename)) {
07293       astman_send_error(s, m, "'Queue' not specified.");
07294       return 0;
07295    }
07296 
07297    if (ast_strlen_zero(interface)) {
07298       astman_send_error(s, m, "'Interface' not specified.");
07299       return 0;
07300    }
07301 
07302    if (ast_strlen_zero(penalty_s))
07303       penalty = 0;
07304    else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0)
07305       penalty = 0;
07306 
07307    if (ast_strlen_zero(paused_s))
07308       paused = 0;
07309    else
07310       paused = abs(ast_true(paused_s));
07311 
07312    switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
07313    case RES_OKAY:
07314       ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
07315       astman_send_ack(s, m, "Added interface to queue");
07316       break;
07317    case RES_EXISTS:
07318       astman_send_error(s, m, "Unable to add interface: Already there");
07319       break;
07320    case RES_NOSUCHQUEUE:
07321       astman_send_error(s, m, "Unable to add interface to queue: No such queue");
07322       break;
07323    case RES_OUTOFMEMORY:
07324       astman_send_error(s, m, "Out of memory");
07325       break;
07326    }
07327 
07328    return 0;
07329 }
07330 
07331 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
07332 {
07333    const char *queuename, *interface;
07334 
07335    queuename = astman_get_header(m, "Queue");
07336    interface = astman_get_header(m, "Interface");
07337 
07338    if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
07339       astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
07340       return 0;
07341    }
07342 
07343    switch (remove_from_queue(queuename, interface)) {
07344    case RES_OKAY:
07345       ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
07346       astman_send_ack(s, m, "Removed interface from queue");
07347       break;
07348    case RES_EXISTS:
07349       astman_send_error(s, m, "Unable to remove interface: Not there");
07350       break;
07351    case RES_NOSUCHQUEUE:
07352       astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
07353       break;
07354    case RES_OUTOFMEMORY:
07355       astman_send_error(s, m, "Out of memory");
07356       break;
07357    case RES_NOT_DYNAMIC:
07358       astman_send_error(s, m, "Member not dynamic");
07359       break;
07360    }
07361 
07362    return 0;
07363 }
07364 
07365 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
07366 {
07367    const char *queuename, *interface, *paused_s, *reason;
07368    int paused;
07369 
07370    interface = astman_get_header(m, "Interface");
07371    paused_s = astman_get_header(m, "Paused");
07372    queuename = astman_get_header(m, "Queue");      /* Optional - if not supplied, pause the given Interface in all queues */
07373    reason = astman_get_header(m, "Reason");        /* Optional - Only used for logging purposes */
07374 
07375    if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
07376       astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
07377       return 0;
07378    }
07379 
07380    paused = abs(ast_true(paused_s));
07381 
07382    if (set_member_paused(queuename, interface, reason, paused))
07383       astman_send_error(s, m, "Interface not found");
07384    else
07385       astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
07386    return 0;
07387 }
07388 
07389 static int manager_queue_log_custom(struct mansession *s, const struct message *m)
07390 {
07391    const char *queuename, *event, *message, *interface, *uniqueid;
07392 
07393    queuename = astman_get_header(m, "Queue");
07394    uniqueid = astman_get_header(m, "UniqueId");
07395    interface = astman_get_header(m, "Interface");
07396    event = astman_get_header(m, "Event");
07397    message = astman_get_header(m, "Message");
07398 
07399    if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
07400       astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
07401       return 0;
07402    }
07403 
07404    ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
07405    astman_send_ack(s, m, "Event added successfully");
07406 
07407    return 0;
07408 }
07409 
07410 static int manager_queue_reload(struct mansession *s, const struct message *m)
07411 {
07412    struct ast_flags mask = {0,};
07413    const char *queuename = NULL;
07414    int header_found = 0;
07415 
07416    queuename = astman_get_header(m, "Queue");
07417    if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
07418       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07419       header_found = 1;
07420    }
07421    if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
07422       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07423       header_found = 1;
07424    }
07425    if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
07426       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07427       header_found = 1;
07428    }
07429 
07430    if (!header_found) {
07431       ast_set_flag(&mask, AST_FLAGS_ALL);
07432    }
07433 
07434    if (!reload_handler(1, &mask, queuename)) {
07435       astman_send_ack(s, m, "Queue reloaded successfully");
07436    } else {
07437       astman_send_error(s, m, "Error encountered while reloading queue");
07438    }
07439    return 0;
07440 }
07441 
07442 static int manager_queue_reset(struct mansession *s, const struct message *m)
07443 {
07444    const char *queuename = NULL;
07445    struct ast_flags mask = {QUEUE_RESET_STATS,};
07446    
07447    queuename = astman_get_header(m, "Queue");
07448 
07449    if (!reload_handler(1, &mask, queuename)) {
07450       astman_send_ack(s, m, "Queue stats reset successfully");
07451    } else {
07452       astman_send_error(s, m, "Error encountered while resetting queue stats");
07453    }
07454    return 0;
07455 }
07456 
07457 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
07458 {
07459    /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
07460    switch (pos) {
07461    case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
07462       return NULL;
07463    case 4: /* only one possible match, "to" */
07464       return state == 0 ? ast_strdup("to") : NULL;
07465    case 5: /* <queue> */
07466       return complete_queue(line, word, pos, state);
07467    case 6: /* only one possible match, "penalty" */
07468       return state == 0 ? ast_strdup("penalty") : NULL;
07469    case 7:
07470       if (state < 100) {      /* 0-99 */
07471          char *num;
07472          if ((num = ast_malloc(3))) {
07473             sprintf(num, "%d", state);
07474          }
07475          return num;
07476       } else {
07477          return NULL;
07478       }
07479    case 8: /* only one possible match, "as" */
07480       return state == 0 ? ast_strdup("as") : NULL;
07481    case 9: /* Don't attempt to complete name of member (infinite possibilities) */
07482       return NULL;
07483    default:
07484       return NULL;
07485    }
07486 }
07487 
07488 static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
07489 {
07490    const char *queuename, *interface, *penalty_s;
07491    int penalty;
07492 
07493    interface = astman_get_header(m, "Interface");
07494    penalty_s = astman_get_header(m, "Penalty");
07495    /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
07496    queuename = astman_get_header(m, "Queue");
07497 
07498    if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
07499       astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
07500       return 0;
07501    }
07502  
07503    penalty = atoi(penalty_s);
07504 
07505    if (set_member_penalty((char *)queuename, (char *)interface, penalty))
07506       astman_send_error(s, m, "Invalid interface, queuename or penalty");
07507    else
07508       astman_send_ack(s, m, "Interface penalty set successfully");
07509 
07510    return 0;
07511 }
07512 
07513 static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07514 {
07515    const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
07516    int penalty;
07517 
07518    switch ( cmd ) {
07519    case CLI_INIT:
07520       e->command = "queue add member";
07521       e->usage =
07522          "Usage: queue add member <channel> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
07523          "       Add a channel to a queue with optionally:  a penalty, membername and a state_interface\n";
07524       return NULL;
07525    case CLI_GENERATE:
07526       return complete_queue_add_member(a->line, a->word, a->pos, a->n);
07527    }
07528 
07529    if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
07530       return CLI_SHOWUSAGE;
07531    } else if (strcmp(a->argv[4], "to")) {
07532       return CLI_SHOWUSAGE;
07533    } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
07534       return CLI_SHOWUSAGE;
07535    } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
07536       return CLI_SHOWUSAGE;
07537    } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
07538       return CLI_SHOWUSAGE;
07539    }
07540 
07541    queuename = a->argv[5];
07542    interface = a->argv[3];
07543    if (a->argc >= 8) {
07544       if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
07545          if (penalty < 0) {
07546             ast_cli(a->fd, "Penalty must be >= 0\n");
07547             penalty = 0;
07548          }
07549       } else {
07550          ast_cli(a->fd, "Penalty must be an integer >= 0\n");
07551          penalty = 0;
07552       }
07553    } else {
07554       penalty = 0;
07555    }
07556 
07557    if (a->argc >= 10) {
07558       membername = a->argv[9];
07559    }
07560 
07561    if (a->argc >= 12) {
07562       state_interface = a->argv[11];
07563    }
07564 
07565    switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
07566    case RES_OKAY:
07567       ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
07568       ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
07569       return CLI_SUCCESS;
07570    case RES_EXISTS:
07571       ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
07572       return CLI_FAILURE;
07573    case RES_NOSUCHQUEUE:
07574       ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
07575       return CLI_FAILURE;
07576    case RES_OUTOFMEMORY:
07577       ast_cli(a->fd, "Out of memory\n");
07578       return CLI_FAILURE;
07579    case RES_NOT_DYNAMIC:
07580       ast_cli(a->fd, "Member not dynamic\n");
07581       return CLI_FAILURE;
07582    default:
07583       return CLI_FAILURE;
07584    }
07585 }
07586 
07587 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
07588 {
07589    int which = 0;
07590    struct call_queue *q;
07591    struct member *m;
07592    struct ao2_iterator queue_iter;
07593    struct ao2_iterator mem_iter;
07594    int wordlen = strlen(word);
07595 
07596    /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
07597    if (pos > 5 || pos < 3)
07598       return NULL;
07599    if (pos == 4)   /* only one possible match, 'from' */
07600       return (state == 0 ? ast_strdup("from") : NULL);
07601 
07602    if (pos == 5)   /* No need to duplicate code */
07603       return complete_queue(line, word, pos, state);
07604 
07605    /* here is the case for 3, <member> */
07606    queue_iter = ao2_iterator_init(queues, 0);
07607    while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
07608       ao2_lock(q);
07609       mem_iter = ao2_iterator_init(q->members, 0);
07610       while ((m = ao2_iterator_next(&mem_iter))) {
07611          if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
07612             char *tmp;
07613             ao2_unlock(q);
07614             tmp = ast_strdup(m->interface);
07615             ao2_ref(m, -1);
07616             queue_t_unref(q, "Done with iterator, returning interface name");
07617             ao2_iterator_destroy(&mem_iter);
07618             ao2_iterator_destroy(&queue_iter);
07619             return tmp;
07620          }
07621          ao2_ref(m, -1);
07622       }
07623       ao2_iterator_destroy(&mem_iter);
07624       ao2_unlock(q);
07625       queue_t_unref(q, "Done with iterator");
07626    }
07627    ao2_iterator_destroy(&queue_iter);
07628 
07629    return NULL;
07630 }
07631 
07632 static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07633 {
07634    const char *queuename, *interface;
07635 
07636    switch (cmd) {
07637    case CLI_INIT:
07638       e->command = "queue remove member";
07639       e->usage = 
07640          "Usage: queue remove member <channel> from <queue>\n"
07641          "       Remove a specific channel from a queue.\n";
07642       return NULL;
07643    case CLI_GENERATE:
07644       return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
07645    }
07646 
07647    if (a->argc != 6) {
07648       return CLI_SHOWUSAGE;
07649    } else if (strcmp(a->argv[4], "from")) {
07650       return CLI_SHOWUSAGE;
07651    }
07652 
07653    queuename = a->argv[5];
07654    interface = a->argv[3];
07655 
07656    switch (remove_from_queue(queuename, interface)) {
07657    case RES_OKAY:
07658       ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
07659       ast_cli(a->fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
07660       return CLI_SUCCESS;
07661    case RES_EXISTS:
07662       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
07663       return CLI_FAILURE;
07664    case RES_NOSUCHQUEUE:
07665       ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
07666       return CLI_FAILURE;
07667    case RES_OUTOFMEMORY:
07668       ast_cli(a->fd, "Out of memory\n");
07669       return CLI_FAILURE;
07670    case RES_NOT_DYNAMIC:
07671       ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
07672       return CLI_FAILURE;
07673    default:
07674       return CLI_FAILURE;
07675    }
07676 }
07677 
07678 static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
07679 {
07680    /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
07681    switch (pos) {
07682    case 3:  /* Don't attempt to complete name of interface (infinite possibilities) */
07683       return NULL;
07684    case 4:  /* only one possible match, "queue" */
07685       return state == 0 ? ast_strdup("queue") : NULL;
07686    case 5:  /* <queue> */
07687       return complete_queue(line, word, pos, state);
07688    case 6: /* "reason" */
07689       return state == 0 ? ast_strdup("reason") : NULL;
07690    case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
07691       return NULL;
07692    default:
07693       return NULL;
07694    }
07695 }
07696 
07697 static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07698 {
07699    const char *queuename, *interface, *reason;
07700    int paused;
07701 
07702    switch (cmd) {
07703    case CLI_INIT:
07704       e->command = "queue {pause|unpause} member";
07705       e->usage = 
07706          "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
07707          "  Pause or unpause a queue member. Not specifying a particular queue\n"
07708          "  will pause or unpause a member across all queues to which the member\n"
07709          "  belongs.\n";
07710       return NULL;
07711    case CLI_GENERATE:
07712       return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
07713    }
07714 
07715    if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
07716       return CLI_SHOWUSAGE;
07717    } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
07718       return CLI_SHOWUSAGE;
07719    } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
07720       return CLI_SHOWUSAGE;
07721    }
07722 
07723 
07724    interface = a->argv[3];
07725    queuename = a->argc >= 6 ? a->argv[5] : NULL;
07726    reason = a->argc == 8 ? a->argv[7] : NULL;
07727    paused = !strcasecmp(a->argv[1], "pause");
07728 
07729    if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
07730       ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
07731       if (!ast_strlen_zero(queuename))
07732          ast_cli(a->fd, " in queue '%s'", queuename);
07733       if (!ast_strlen_zero(reason))
07734          ast_cli(a->fd, " for reason '%s'", reason);
07735       ast_cli(a->fd, "\n");
07736       return CLI_SUCCESS;
07737    } else {
07738       ast_cli(a->fd, "Unable to %spause 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_FAILURE;
07745    }
07746 }
07747 
07748 static char *complete_queue_set_member_penalty(const char *line, const char *word, int pos, int state)
07749 {
07750    /* 0 - queue; 1 - set; 2 - penalty; 3 - <penalty>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
07751    switch (pos) {
07752    case 4:
07753       if (state == 0) {
07754          return ast_strdup("on");
07755       } else {
07756          return NULL;
07757       }
07758    case 6:
07759       if (state == 0) {
07760          return ast_strdup("in");
07761       } else {
07762          return NULL;
07763       }
07764    case 7:
07765       return complete_queue(line, word, pos, state);
07766    default:
07767       return NULL;
07768    }
07769 }
07770  
07771 static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07772 {
07773    const char *queuename = NULL, *interface;
07774    int penalty = 0;
07775 
07776    switch (cmd) {
07777    case CLI_INIT:
07778       e->command = "queue set penalty";
07779       e->usage = 
07780       "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
07781       "  Set a member's penalty in the queue specified. If no queue is specified\n"
07782       "  then that interface's penalty is set in all queues to which that interface is a member\n";
07783       return NULL;
07784    case CLI_GENERATE:
07785       return complete_queue_set_member_penalty(a->line, a->word, a->pos, a->n);
07786    }
07787 
07788    if (a->argc != 6 && a->argc != 8) {
07789       return CLI_SHOWUSAGE;
07790    } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
07791       return CLI_SHOWUSAGE;
07792    }
07793 
07794    if (a->argc == 8)
07795       queuename = a->argv[7];
07796    interface = a->argv[5];
07797    penalty = atoi(a->argv[3]);
07798 
07799    switch (set_member_penalty(queuename, interface, penalty)) {
07800    case RESULT_SUCCESS:
07801       ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07802       return CLI_SUCCESS;
07803    case RESULT_FAILURE:
07804       ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
07805       return CLI_FAILURE;
07806    default:
07807       return CLI_FAILURE;
07808    }
07809 }
07810 
07811 static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state) 
07812 {
07813    int which = 0;
07814    struct rule_list *rl_iter;
07815    int wordlen = strlen(word);
07816    char *ret = NULL;
07817    if (pos != 3) /* Wha? */ {
07818       return NULL;
07819    }
07820 
07821    AST_LIST_LOCK(&rule_lists);
07822    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07823       if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
07824          ret = ast_strdup(rl_iter->name);
07825          break;
07826       }
07827    }
07828    AST_LIST_UNLOCK(&rule_lists);
07829 
07830    return ret;
07831 }
07832 
07833 static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07834 {
07835    const char *rule;
07836    struct rule_list *rl_iter;
07837    struct penalty_rule *pr_iter;
07838    switch (cmd) {
07839    case CLI_INIT:
07840       e->command = "queue show rules";
07841       e->usage =
07842       "Usage: queue show rules [rulename]\n"
07843       "  Show the list of rules associated with rulename. If no\n"
07844       "  rulename is specified, list all rules defined in queuerules.conf\n";
07845       return NULL;
07846    case CLI_GENERATE:
07847       return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
07848    }
07849 
07850    if (a->argc != 3 && a->argc != 4)
07851       return CLI_SHOWUSAGE;
07852 
07853    rule = a->argc == 4 ? a->argv[3] : "";
07854    AST_LIST_LOCK(&rule_lists);
07855    AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
07856       if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
07857          ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
07858          AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
07859             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);
07860          }
07861       }
07862    }
07863    AST_LIST_UNLOCK(&rule_lists);
07864    return CLI_SUCCESS; 
07865 }
07866 
07867 static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07868 {
07869    struct ast_flags mask = {QUEUE_RESET_STATS,};
07870    int i;
07871 
07872    switch (cmd) {
07873       case CLI_INIT:
07874          e->command = "queue reset stats";
07875          e->usage =
07876             "Usage: queue reset stats [<queuenames>]\n"
07877             "\n"
07878             "Issuing this command will reset statistics for\n"
07879             "<queuenames>, or for all queues if no queue is\n"
07880             "specified.\n";
07881          return NULL;
07882       case CLI_GENERATE:
07883          if (a->pos >= 3) {
07884             return complete_queue(a->line, a->word, a->pos, a->n);
07885          } else {
07886             return NULL;
07887          }
07888    }
07889 
07890    if (a->argc < 3) {
07891       return CLI_SHOWUSAGE;
07892    }
07893 
07894    if (a->argc == 3) {
07895       reload_handler(1, &mask, NULL);
07896       return CLI_SUCCESS;
07897    }
07898 
07899    for (i = 3; i < a->argc; ++i) {
07900       reload_handler(1, &mask, a->argv[i]);
07901    }
07902 
07903    return CLI_SUCCESS;
07904 }
07905 
07906 static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
07907 {
07908    struct ast_flags mask = {0,};
07909    int i;
07910 
07911    switch (cmd) {
07912       case CLI_INIT:
07913          e->command = "queue reload {parameters|members|rules|all}";
07914          e->usage =
07915             "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
07916             "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
07917             "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
07918             "specified in order to know what information to reload. Below is an explanation\n"
07919             "of each of these qualifiers.\n"
07920             "\n"
07921             "\t'members' - reload queue members from queues.conf\n"
07922             "\t'parameters' - reload all queue options except for queue members\n"
07923             "\t'rules' - reload the queuerules.conf file\n"
07924             "\t'all' - reload queue rules, parameters, and members\n"
07925             "\n"
07926             "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
07927             "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
07928             "one queue is specified when using this command, reloading queue rules may cause\n"
07929             "other queues to be affected\n";
07930          return NULL;
07931       case CLI_GENERATE:
07932          if (a->pos >= 3) {
07933             return complete_queue(a->line, a->word, a->pos, a->n);
07934          } else {
07935             return NULL;
07936          }
07937    }
07938 
07939    if (a->argc < 3)
07940       return CLI_SHOWUSAGE;
07941 
07942    if (!strcasecmp(a->argv[2], "rules")) {
07943       ast_set_flag(&mask, QUEUE_RELOAD_RULES);
07944    } else if (!strcasecmp(a->argv[2], "members")) {
07945       ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
07946    } else if (!strcasecmp(a->argv[2], "parameters")) {
07947       ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
07948    } else if (!strcasecmp(a->argv[2], "all")) {
07949       ast_set_flag(&mask, AST_FLAGS_ALL);
07950    }
07951 
07952    if (a->argc == 3) {
07953       reload_handler(1, &mask, NULL);
07954       return CLI_SUCCESS;
07955    }
07956 
07957    for (i = 3; i < a->argc; ++i) {
07958       reload_handler(1, &mask, a->argv[i]);
07959    }
07960 
07961    return CLI_SUCCESS;
07962 }
07963 
07964 static const char qpm_cmd_usage[] = 
07965 "Usage: queue pause member <channel> in <queue> reason <reason>\n";
07966 
07967 static const char qum_cmd_usage[] =
07968 "Usage: queue unpause member <channel> in <queue> reason <reason>\n";
07969 
07970 static const char qsmp_cmd_usage[] =
07971 "Usage: queue set member penalty <channel> from <queue> <penalty>\n";
07972 
07973 static struct ast_cli_entry cli_queue[] = {
07974    AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
07975    AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
07976    AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
07977    AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
07978    AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
07979    AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
07980    AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
07981    AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
07982 };
07983 
07984 /* struct call_queue astdata mapping. */
07985 #define DATA_EXPORT_CALL_QUEUE(MEMBER)             \
07986    MEMBER(call_queue, name, AST_DATA_STRING)       \
07987    MEMBER(call_queue, moh, AST_DATA_STRING)        \
07988    MEMBER(call_queue, announce, AST_DATA_STRING)         \
07989    MEMBER(call_queue, context, AST_DATA_STRING)       \
07990    MEMBER(call_queue, membermacro, AST_DATA_STRING)      \
07991    MEMBER(call_queue, membergosub, AST_DATA_STRING)      \
07992    MEMBER(call_queue, defaultrule, AST_DATA_STRING)      \
07993    MEMBER(call_queue, sound_next, AST_DATA_STRING)       \
07994    MEMBER(call_queue, sound_thereare, AST_DATA_STRING)      \
07995    MEMBER(call_queue, sound_calls, AST_DATA_STRING)      \
07996    MEMBER(call_queue, queue_quantity1, AST_DATA_STRING)     \
07997    MEMBER(call_queue, queue_quantity2, AST_DATA_STRING)     \
07998    MEMBER(call_queue, sound_holdtime, AST_DATA_STRING)      \
07999    MEMBER(call_queue, sound_minutes, AST_DATA_STRING)    \
08000    MEMBER(call_queue, sound_minute, AST_DATA_STRING)     \
08001    MEMBER(call_queue, sound_seconds, AST_DATA_STRING)    \
08002    MEMBER(call_queue, sound_thanks, AST_DATA_STRING)     \
08003    MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING)   \
08004    MEMBER(call_queue, sound_reporthold, AST_DATA_STRING)    \
08005    MEMBER(call_queue, dead, AST_DATA_BOOLEAN)         \
08006    MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN)    \
08007    MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN)       \
08008    MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN)    \
08009    MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN)     \
08010    MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN)      \
08011    MEMBER(call_queue, reportholdtime, AST_DATA_BOOLEAN)     \
08012    MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN)         \
08013    MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN)     \
08014    MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER)      \
08015    MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN)      \
08016    MEMBER(call_queue, realtime, AST_DATA_BOOLEAN)        \
08017    MEMBER(call_queue, found, AST_DATA_BOOLEAN)        \
08018    MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \
08019    MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS)     \
08020    MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS)  \
08021    MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS)   \
08022    MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER)   \
08023    MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER)   \
08024    MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS)    \
08025    MEMBER(call_queue, holdtime, AST_DATA_SECONDS)        \
08026    MEMBER(call_queue, talktime, AST_DATA_SECONDS)        \
08027    MEMBER(call_queue, callscompleted, AST_DATA_INTEGER)     \
08028    MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER)     \
08029    MEMBER(call_queue, servicelevel, AST_DATA_INTEGER)    \
08030    MEMBER(call_queue, callscompletedinsl, AST_DATA_INTEGER) \
08031    MEMBER(call_queue, monfmt, AST_DATA_STRING)        \
08032    MEMBER(call_queue, montype, AST_DATA_INTEGER)         \
08033    MEMBER(call_queue, count, AST_DATA_INTEGER)        \
08034    MEMBER(call_queue, maxlen, AST_DATA_INTEGER)       \
08035    MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS)      \
08036    MEMBER(call_queue, retry, AST_DATA_SECONDS)        \
08037    MEMBER(call_queue, timeout, AST_DATA_SECONDS)         \
08038    MEMBER(call_queue, weight, AST_DATA_INTEGER)       \
08039    MEMBER(call_queue, autopause, AST_DATA_INTEGER)       \
08040    MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER)    \
08041    MEMBER(call_queue, rrpos, AST_DATA_INTEGER)        \
08042    MEMBER(call_queue, memberdelay, AST_DATA_INTEGER)     \
08043    MEMBER(call_queue, autofill, AST_DATA_INTEGER)        \
08044    MEMBER(call_queue, members, AST_DATA_CONTAINER)
08045 
08046 AST_DATA_STRUCTURE(call_queue, DATA_EXPORT_CALL_QUEUE);
08047 
08048 /* struct member astdata mapping. */
08049 #define DATA_EXPORT_MEMBER(MEMBER)              \
08050    MEMBER(member, interface, AST_DATA_STRING)         \
08051    MEMBER(member, state_interface, AST_DATA_STRING)      \
08052    MEMBER(member, membername, AST_DATA_STRING)        \
08053    MEMBER(member, penalty, AST_DATA_INTEGER)       \
08054    MEMBER(member, calls, AST_DATA_INTEGER)            \
08055    MEMBER(member, dynamic, AST_DATA_INTEGER)       \
08056    MEMBER(member, realtime, AST_DATA_INTEGER)         \
08057    MEMBER(member, status, AST_DATA_INTEGER)        \
08058    MEMBER(member, paused, AST_DATA_BOOLEAN)        \
08059    MEMBER(member, rt_uniqueid, AST_DATA_STRING)
08060 
08061 AST_DATA_STRUCTURE(member, DATA_EXPORT_MEMBER);
08062 
08063 #define DATA_EXPORT_QUEUE_ENT(MEMBER)                 \
08064    MEMBER(queue_ent, moh, AST_DATA_STRING)               \
08065    MEMBER(queue_ent, announce, AST_DATA_STRING)          \
08066    MEMBER(queue_ent, context, AST_DATA_STRING)           \
08067    MEMBER(queue_ent, digits, AST_DATA_STRING)            \
08068    MEMBER(queue_ent, valid_digits, AST_DATA_INTEGER)        \
08069    MEMBER(queue_ent, pos, AST_DATA_INTEGER)           \
08070    MEMBER(queue_ent, prio, AST_DATA_INTEGER)          \
08071    MEMBER(queue_ent, last_pos_said, AST_DATA_INTEGER)       \
08072    MEMBER(queue_ent, last_periodic_announce_time, AST_DATA_INTEGER)  \
08073    MEMBER(queue_ent, last_periodic_announce_sound, AST_DATA_INTEGER) \
08074    MEMBER(queue_ent, last_pos, AST_DATA_INTEGER)            \
08075    MEMBER(queue_ent, opos, AST_DATA_INTEGER)          \
08076    MEMBER(queue_ent, handled, AST_DATA_INTEGER)          \
08077    MEMBER(queue_ent, pending, AST_DATA_INTEGER)          \
08078    MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER)         \
08079    MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER)         \
08080    MEMBER(queue_ent, linpos, AST_DATA_INTEGER)           \
08081    MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER)          \
08082    MEMBER(queue_ent, start, AST_DATA_INTEGER)            \
08083    MEMBER(queue_ent, expire, AST_DATA_INTEGER)           \
08084    MEMBER(queue_ent, cancel_answered_elsewhere, AST_DATA_INTEGER)
08085 
08086 AST_DATA_STRUCTURE(queue_ent, DATA_EXPORT_QUEUE_ENT);
08087 
08088 /*!
08089  * \internal
08090  * \brief Add a queue to the data_root node.
08091  * \param[in] search The search tree.
08092  * \param[in] data_root The main result node.
08093  * \param[in] queue The queue to add.
08094  */
08095 static void queues_data_provider_get_helper(const struct ast_data_search *search,
08096    struct ast_data *data_root, struct call_queue *queue)
08097 {
08098    struct ao2_iterator im;
08099    struct member *member;
08100    struct queue_ent *qe;
08101    struct ast_data *data_queue, *data_members = NULL, *enum_node;
08102    struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
08103 
08104    data_queue = ast_data_add_node(data_root, "queue");
08105    if (!data_queue) {
08106       return;
08107    }
08108 
08109    ast_data_add_structure(call_queue, data_queue, queue);
08110 
08111    ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
08112    ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members));
08113 
08114    /* announce position */
08115    enum_node = ast_data_add_node(data_queue, "announceposition");
08116    if (!enum_node) {
08117       return;
08118    }
08119    switch (queue->announceposition) {
08120    case ANNOUNCEPOSITION_LIMIT:
08121       ast_data_add_str(enum_node, "text", "limit");
08122       break;
08123    case ANNOUNCEPOSITION_MORE_THAN:
08124       ast_data_add_str(enum_node, "text", "more");
08125       break;
08126    case ANNOUNCEPOSITION_YES:
08127       ast_data_add_str(enum_node, "text", "yes");
08128       break;
08129    case ANNOUNCEPOSITION_NO:
08130       ast_data_add_str(enum_node, "text", "no");
08131       break;
08132    default:
08133       ast_data_add_str(enum_node, "text", "unknown");
08134       break;
08135    }
08136    ast_data_add_int(enum_node, "value", queue->announceposition);
08137 
08138    /* add queue members */
08139    im = ao2_iterator_init(queue->members, 0);
08140    while ((member = ao2_iterator_next(&im))) {
08141       if (!data_members) {
08142          data_members = ast_data_add_node(data_queue, "members");
08143          if (!data_members) {
08144             ao2_ref(member, -1);
08145             continue;
08146          }
08147       }
08148 
08149       data_member = ast_data_add_node(data_members, "member");
08150       if (!data_member) {
08151          ao2_ref(member, -1);
08152          continue;
08153       }
08154 
08155       ast_data_add_structure(member, data_member, member);
08156 
08157       ao2_ref(member, -1);
08158    }
08159 
08160    /* include the callers inside the result. */
08161    if (queue->head) {
08162       for (qe = queue->head; qe; qe = qe->next) {
08163          if (!data_callers) {
08164             data_callers = ast_data_add_node(data_queue, "callers");
08165             if (!data_callers) {
08166                continue;
08167             }
08168          }
08169 
08170          data_caller = ast_data_add_node(data_callers, "caller");
08171          if (!data_caller) {
08172             continue;
08173          }
08174 
08175          ast_data_add_structure(queue_ent, data_caller, qe);
08176 
08177          /* add the caller channel. */
08178          data_caller_channel = ast_data_add_node(data_caller, "channel");
08179          if (!data_caller_channel) {
08180             continue;
08181          }
08182 
08183          ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
08184       }
08185    }
08186 
08187    /* if this queue doesn't match remove the added queue. */
08188    if (!ast_data_search_match(search, data_queue)) {
08189       ast_data_remove_node(data_root, data_queue);
08190    }
08191 }
08192 
08193 /*!
08194  * \internal
08195  * \brief Callback used to generate the queues tree.
08196  * \param[in] search The search pattern tree.
08197  * \retval NULL on error.
08198  * \retval non-NULL The generated tree.
08199  */
08200 static int queues_data_provider_get(const struct ast_data_search *search,
08201    struct ast_data *data_root)
08202 {
08203    struct ao2_iterator i;
08204    struct call_queue *queue, *queue_realtime = NULL;
08205    struct ast_config *cfg;
08206    char *queuename;
08207 
08208    /* load realtime queues. */
08209    cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
08210    if (cfg) {
08211       for (queuename = ast_category_browse(cfg, NULL);
08212             !ast_strlen_zero(queuename);
08213             queuename = ast_category_browse(cfg, queuename)) {
08214          if ((queue = load_realtime_queue(queuename))) {
08215             queue_unref(queue);
08216          }
08217       }
08218       ast_config_destroy(cfg);
08219    }
08220 
08221    /* static queues. */
08222    i = ao2_iterator_init(queues, 0);
08223    while ((queue = ao2_iterator_next(&i))) {
08224       ao2_lock(queue);
08225       if (queue->realtime) {
08226          queue_realtime = load_realtime_queue(queue->name);
08227          if (!queue_realtime) {
08228             ao2_unlock(queue);
08229             queue_unref(queue);
08230             continue;
08231          }
08232          queue_unref(queue_realtime);
08233       }
08234 
08235       queues_data_provider_get_helper(search, data_root, queue);
08236       ao2_unlock(queue);
08237       queue_unref(queue);
08238    }
08239    ao2_iterator_destroy(&i);
08240 
08241    return 0;
08242 }
08243 
08244 static const struct ast_data_handler queues_data_provider = {
08245    .version = AST_DATA_HANDLER_VERSION,
08246    .get = queues_data_provider_get
08247 };
08248 
08249 static const struct ast_data_entry queue_data_providers[] = {
08250    AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
08251 };
08252 
08253 static int unload_module(void)
08254 {
08255    int res;
08256    struct ast_context *con;
08257    struct ao2_iterator q_iter;
08258    struct call_queue *q = NULL;
08259 
08260    ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
08261    res = ast_manager_unregister("QueueStatus");
08262    res |= ast_manager_unregister("Queues");
08263    res |= ast_manager_unregister("QueueRule");
08264    res |= ast_manager_unregister("QueueSummary");
08265    res |= ast_manager_unregister("QueueAdd");
08266    res |= ast_manager_unregister("QueueRemove");
08267    res |= ast_manager_unregister("QueuePause");
08268    res |= ast_manager_unregister("QueueLog");
08269    res |= ast_manager_unregister("QueuePenalty");
08270    res |= ast_unregister_application(app_aqm);
08271    res |= ast_unregister_application(app_rqm);
08272    res |= ast_unregister_application(app_pqm);
08273    res |= ast_unregister_application(app_upqm);
08274    res |= ast_unregister_application(app_ql);
08275    res |= ast_unregister_application(app);
08276    res |= ast_custom_function_unregister(&queueexists_function);
08277    res |= ast_custom_function_unregister(&queuevar_function);
08278    res |= ast_custom_function_unregister(&queuemembercount_function);
08279    res |= ast_custom_function_unregister(&queuemembercount_dep);
08280    res |= ast_custom_function_unregister(&queuememberlist_function);
08281    res |= ast_custom_function_unregister(&queuewaitingcount_function);
08282    res |= ast_custom_function_unregister(&queuememberpenalty_function);
08283 
08284    res |= ast_data_unregister(NULL);
08285 
08286    if (device_state_sub)
08287       ast_event_unsubscribe(device_state_sub);
08288 
08289    ast_extension_state_del(0, extension_state_cb);
08290 
08291    if ((con = ast_context_find("app_queue_gosub_virtual_context"))) {
08292       ast_context_remove_extension2(con, "s", 1, NULL, 0);
08293       ast_context_destroy(con, "app_queue"); /* leave no trace */
08294    }
08295 
08296    q_iter = ao2_iterator_init(queues, 0);
08297    while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
08298       queues_t_unlink(queues, q, "Remove queue from container due to unload");
08299       queue_t_unref(q, "Done with iterator");
08300    }
08301    ao2_iterator_destroy(&q_iter);
08302    ao2_ref(queues, -1);
08303    devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
08304    ast_unload_realtime("queue_members");
08305    return res;
08306 }
08307 
08308 static int load_module(void)
08309 {
08310    int res;
08311    struct ast_context *con;
08312    struct ast_flags mask = {AST_FLAGS_ALL, };
08313 
08314    queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
08315 
08316    use_weight = 0;
08317 
08318    if (reload_handler(0, &mask, NULL))
08319       return AST_MODULE_LOAD_DECLINE;
08320 
08321    con = ast_context_find_or_create(NULL, NULL, "app_queue_gosub_virtual_context", "app_queue");
08322    if (!con)
08323       ast_log(LOG_ERROR, "Queue virtual context 'app_queue_gosub_virtual_context' does not exist and unable to create\n");
08324    else
08325       ast_add_extension2(con, 1, "s", 1, NULL, NULL, "NoOp", ast_strdup(""), ast_free_ptr, "app_queue");
08326 
08327    if (queue_persistent_members)
08328       reload_queue_members();
08329 
08330    ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
08331 
08332    ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
08333    res = ast_register_application_xml(app, queue_exec);
08334    res |= ast_register_application_xml(app_aqm, aqm_exec);
08335    res |= ast_register_application_xml(app_rqm, rqm_exec);
08336    res |= ast_register_application_xml(app_pqm, pqm_exec);
08337    res |= ast_register_application_xml(app_upqm, upqm_exec);
08338    res |= ast_register_application_xml(app_ql, ql_exec);
08339    res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
08340    res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
08341    res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
08342    res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
08343    res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
08344    res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
08345    res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
08346    res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
08347    res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
08348    res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
08349    res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
08350    res |= ast_custom_function_register(&queuevar_function);
08351    res |= ast_custom_function_register(&queueexists_function);
08352    res |= ast_custom_function_register(&queuemembercount_function);
08353    res |= ast_custom_function_register(&queuemembercount_dep);
08354    res |= ast_custom_function_register(&queuememberlist_function);
08355    res |= ast_custom_function_register(&queuewaitingcount_function);
08356    res |= ast_custom_function_register(&queuememberpenalty_function);
08357 
08358    if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
08359       ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
08360    }
08361 
08362    /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
08363    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
08364       res = -1;
08365    }
08366 
08367    ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
08368 
08369    ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
08370 
08371    return res ? AST_MODULE_LOAD_DECLINE : 0;
08372 }
08373 
08374 static int reload(void)
08375 {
08376    struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
08377    ast_unload_realtime("queue_members");
08378    reload_handler(1, &mask, NULL);
08379    return 0;
08380 }
08381 
08382 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
08383       .load = load_module,
08384       .unload = unload_module,
08385       .reload = reload,
08386       .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
08387       .nonoptreq = "res_monitor",
08388           );
08389