Sat Aug 6 00:39:20 2011

Asterisk developer's documentation


app_queue.c

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

Generated on Sat Aug 6 00:39:21 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7