Mon Sep 20 2010 00:19:54

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