Mon Nov 24 15:33:59 2008

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

Generated on Mon Nov 24 15:34:01 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7