Thu Oct 11 06:41:59 2012

Asterisk developer's documentation


app_queue.c

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

Generated on Thu Oct 11 06:41:59 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6