Sat Jul 12 2014 17:18:24

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