Tue Aug 20 16:34:22 2013

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

Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1