Thu Dec 17 13:33:27 2009

Asterisk developer's documentation


app_queue.c

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

Generated on Thu Dec 17 13:33:27 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7