Wed Apr 6 11:29:38 2011

Asterisk developer's documentation


app_queue.c

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

Generated on Wed Apr 6 11:29:38 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7