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

Generated on Mon Oct 8 12:38:56 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7