Wed Mar 3 22:35:46 2010

Asterisk developer's documentation


app_queue.c

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

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