Mon Jun 27 16:50:46 2011

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

Generated on Mon Jun 27 16:50:47 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7