Thu Sep 7 01:02:51 2017

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

Generated on 7 Sep 2017 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1