Tue Mar 2 17:31:42 2010

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

Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1