Sun Oct 16 2011 08:41:28

Asterisk developer's documentation


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