Mon Mar 31 17:29:54 2014

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

Generated on 31 Mar 2014 for Asterisk - the Open Source PBX by  doxygen 1.6.1