Fri Apr 15 20:38:02 2016

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

Generated on 15 Apr 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1