Thu Apr 28 2011 17:13:28

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