Tue Aug 24 2010 19:41:25

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