Sat Mar 10 01:53:58 2012

Asterisk developer's documentation


app_queue.c

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

Generated on Sat Mar 10 01:53:58 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7