Tue Apr 6 15:45:24 2010

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

Generated on Tue Apr 6 15:45:24 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7