Fri Mar 8 17:29:54 2019

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

Generated on 8 Mar 2019 for Asterisk - the Open Source PBX by  doxygen 1.6.1