Wed Oct 28 11:50:53 2009

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