Mon Apr 28 2014 10:05:34

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