add option to avoid calling members whose channels are 'in use' (issue #6315, plus...
[asterisk/asterisk.git] / apps / app_queue.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief True call queues with optional send URL on answer
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \arg Config in \ref Config_qu queues.conf
26  * 
27  * \par Development notes
28  * \note 2004-11-25: Persistent Dynamic Members added by:
29  *             NetNation Communications (www.netnation.com)
30  *             Kevin Lindsay <kevinl@netnation.com>
31  * 
32  *             Each dynamic agent in each queue is now stored in the astdb.
33  *             When asterisk is restarted, each agent will be automatically
34  *             readded into their recorded queues. This feature can be
35  *             configured with the 'persistent_members=<1|0>' setting in the
36  *             '[general]' category in queues.conf. The default is on.
37  * 
38  * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
39  *
40  * \note These features added by David C. Troy <dave@toad.net>:
41  *    - Per-queue holdtime calculation
42  *    - Estimated holdtime announcement
43  *    - Position announcement
44  *    - Abandoned/completed call counters
45  *    - Failout timer passed as optional app parameter
46  *    - Optional monitoring of calls, started when call is answered
47  *
48  * Patch Version 1.07 2003-12-24 01
49  *
50  * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51  * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
52  *
53  * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54  * by Matthew Enger <m.enger@xi.com.au>
55  *
56  * \ingroup applications
57  */
58
59 #include <stdlib.h>
60 #include <errno.h>
61 #include <unistd.h>
62 #include <string.h>
63 #include <stdlib.h>
64 #include <stdio.h>
65 #include <sys/time.h>
66 #include <sys/signal.h>
67 #include <netinet/in.h>
68
69 #include "asterisk.h"
70
71 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
72
73 #include "asterisk/lock.h"
74 #include "asterisk/file.h"
75 #include "asterisk/logger.h"
76 #include "asterisk/channel.h"
77 #include "asterisk/pbx.h"
78 #include "asterisk/options.h"
79 #include "asterisk/app.h"
80 #include "asterisk/linkedlists.h"
81 #include "asterisk/module.h"
82 #include "asterisk/translate.h"
83 #include "asterisk/say.h"
84 #include "asterisk/features.h"
85 #include "asterisk/musiconhold.h"
86 #include "asterisk/cli.h"
87 #include "asterisk/manager.h"
88 #include "asterisk/config.h"
89 #include "asterisk/monitor.h"
90 #include "asterisk/utils.h"
91 #include "asterisk/causes.h"
92 #include "asterisk/astdb.h"
93 #include "asterisk/devicestate.h"
94 #include "asterisk/stringfields.h"
95
96 #define QUEUE_STRATEGY_RINGALL          0
97 #define QUEUE_STRATEGY_ROUNDROBIN       1
98 #define QUEUE_STRATEGY_LEASTRECENT      2
99 #define QUEUE_STRATEGY_FEWESTCALLS      3
100 #define QUEUE_STRATEGY_RANDOM           4
101 #define QUEUE_STRATEGY_RRMEMORY         5
102
103 static struct strategy {
104         int strategy;
105         char *name;
106 } strategies[] = {
107         { QUEUE_STRATEGY_RINGALL, "ringall" },
108         { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
109         { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
110         { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
111         { QUEUE_STRATEGY_RANDOM, "random" },
112         { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
113 };
114
115 #define DEFAULT_RETRY           5
116 #define DEFAULT_TIMEOUT         15
117 #define RECHECK                 1               /* Recheck every second to see we we're at the top yet */
118 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
119
120 #define RES_OKAY        0               /* Action completed */
121 #define RES_EXISTS      (-1)            /* Entry already exists */
122 #define RES_OUTOFMEMORY (-2)            /* Out of memory */
123 #define RES_NOSUCHQUEUE (-3)            /* No such queue */
124
125 static char *tdesc = "True Call Queueing";
126
127 static char *app = "Queue";
128
129 static char *synopsis = "Queue a call for a call queue";
130
131 static char *descrip =
132 "  Queue(queuename[|options[|URL][|announceoverride][|timeout]]):\n"
133 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
134 "This application will return to the dialplan if the queue does not exist, or\n"
135 "any of the join options cause the caller to not enter the queue.\n"
136 "The option string may contain zero or more of the following characters:\n"
137 "      'd' -- data-quality (modem) call (minimum delay).\n"
138 "      'h' -- allow callee to hang up by hitting *.\n"
139 "      'H' -- allow caller to hang up by hitting *.\n"
140 "      'n' -- no retries on the timeout; will exit this application and \n"
141 "             go to the next step.\n"
142 "      'r' -- ring instead of playing MOH\n"
143 "      't' -- allow the called user transfer the calling user\n"
144 "      'T' -- to allow the calling user to transfer the call.\n"
145 "      'w' -- allow the called user to write the conversation to disk via Monitor\n"
146 "      'W' -- allow the calling user to write the conversation to disk via Monitor\n"
147 "  In addition to transferring the call, a call may be parked and then picked\n"
148 "up by another user.\n"
149 "  The optional URL will be sent to the called party if the channel supports\n"
150 "it.\n"
151 "  The timeout will cause the queue to fail out after a specified number of\n"
152 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
153 "  This application sets the following channel variable upon completion:\n"
154 "      QUEUESTATUS    The status of the call as a text string, one of\n"
155 "             TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
156
157 static char *app_aqm = "AddQueueMember" ;
158 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
159 static char *app_aqm_descrip =
160 "   AddQueueMember(queuename[|interface[|penalty[|options]]]):\n"
161 "Dynamically adds interface to an existing queue.\n"
162 "If the interface is already in the queue and there exists an n+101 priority\n"
163 "then it will then jump to this priority.  Otherwise it will return an error\n"
164 "The option string may contain zero or more of the following characters:\n"
165 "       'j' -- jump to +101 priority when appropriate.\n"
166 "  This application sets the following channel variable upon completion:\n"
167 "     AQMSTATUS    The status of the attempt to add a queue member as a \n"
168 "                     text string, one of\n"
169 "           ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
170 "Example: AddQueueMember(techsupport|SIP/3000)\n"
171 "";
172
173 static char *app_rqm = "RemoveQueueMember" ;
174 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
175 static char *app_rqm_descrip =
176 "   RemoveQueueMember(queuename[|interface[|options]]):\n"
177 "Dynamically removes interface to an existing queue\n"
178 "If the interface is NOT in the queue and there exists an n+101 priority\n"
179 "then it will then jump to this priority.  Otherwise it will return an error\n"
180 "The option string may contain zero or more of the following characters:\n"
181 "       'j' -- jump to +101 priority when appropriate.\n"
182 "  This application sets the following channel variable upon completion:\n"
183 "     RQMSTATUS      The status of the attempt to remove a queue member as a\n"
184 "                     text string, one of\n"
185 "           REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
186 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
187 "";
188
189 static char *app_pqm = "PauseQueueMember" ;
190 static char *app_pqm_synopsis = "Pauses a queue member" ;
191 static char *app_pqm_descrip =
192 "   PauseQueueMember([queuename]|interface[|options]):\n"
193 "Pauses (blocks calls for) a queue member.\n"
194 "The given interface will be paused in the given queue.  This prevents\n"
195 "any calls from being sent from the queue to the interface until it is\n"
196 "unpaused with UnpauseQueueMember or the manager interface.  If no\n"
197 "queuename is given, the interface is paused in every queue it is a\n"
198 "member of.  If the interface is not in the named queue, or if no queue\n"
199 "is given and the interface is not in any queue, it will jump to\n"
200 "priority n+101, if it exists and the appropriate options are set.\n"
201 "The application will fail if the interface is not found and no extension\n"
202 "to jump to exists.\n"
203 "The option string may contain zero or more of the following characters:\n"
204 "       'j' -- jump to +101 priority when appropriate.\n"
205 "  This application sets the following channel variable upon completion:\n"
206 "     PQMSTATUS      The status of the attempt to pause a queue member as a\n"
207 "                     text string, one of\n"
208 "           PAUSED | NOTFOUND\n"
209 "Example: PauseQueueMember(|SIP/3000)\n";
210
211 static char *app_upqm = "UnpauseQueueMember" ;
212 static char *app_upqm_synopsis = "Unpauses a queue member" ;
213 static char *app_upqm_descrip =
214 "   UnpauseQueueMember([queuename]|interface[|options]):\n"
215 "Unpauses (resumes calls to) a queue member.\n"
216 "This is the counterpart to PauseQueueMember and operates exactly the\n"
217 "same way, except it unpauses instead of pausing the given interface.\n"
218 "The option string may contain zero or more of the following characters:\n"
219 "       'j' -- jump to +101 priority when appropriate.\n"
220 "  This application sets the following channel variable upon completion:\n"
221 "     UPQMSTATUS       The status of the attempt to unpause a queue \n"
222 "                      member as a text string, one of\n"
223 "            UNPAUSED | NOTFOUND\n"
224 "Example: UnpauseQueueMember(|SIP/3000)\n";
225
226 /*! \brief Persistent Members astdb family */
227 static const char *pm_family = "/Queue/PersistentMembers";
228 /* The maximum length of each persistent member queue database entry */
229 #define PM_MAX_LEN 2048
230
231 /*! \brief queues.conf [general] option */
232 static int queue_persistent_members = 0;
233
234 /*! \brief queues.conf per-queue weight option */
235 static int use_weight = 0;
236
237 enum queue_result {
238         QUEUE_UNKNOWN = 0,
239         QUEUE_TIMEOUT = 1,
240         QUEUE_JOINEMPTY = 2,
241         QUEUE_LEAVEEMPTY = 3,
242         QUEUE_JOINUNAVAIL = 4,
243         QUEUE_LEAVEUNAVAIL = 5,
244         QUEUE_FULL = 6,
245 };
246
247 const struct { 
248         enum queue_result id;
249         char *text;
250 } queue_results[] = {
251         { QUEUE_UNKNOWN, "UNKNOWN" },
252         { QUEUE_TIMEOUT, "TIMEOUT" },
253         { QUEUE_JOINEMPTY,"JOINEMPTY" },
254         { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
255         { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
256         { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
257         { QUEUE_FULL, "FULL" },
258 };
259
260 /*! \brief We define a custom "local user" structure because we
261    use it not only for keeping track of what is in use but
262    also for keeping track of who we're dialing. */
263
264 struct callattempt {
265         struct callattempt *q_next;
266         struct ast_channel *chan;
267         char interface[256];
268         int stillgoing;
269         int metric;
270         int oldstatus;
271         time_t lastcall;
272         struct member *member;
273 };
274
275 STANDARD_LOCAL_USER;
276
277 LOCAL_USER_DECL;
278
279 struct queue_ent {
280         struct ast_call_queue *parent;  /*!< What queue is our parent */
281         char moh[80];                   /*!< Name of musiconhold to be used */
282         char announce[80];              /*!< Announcement to play for member when call is answered */
283         char context[AST_MAX_CONTEXT];  /*!< Context when user exits queue */
284         char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
285         int pos;                        /*!< Where we are in the queue */
286         int prio;                       /*!< Our priority */
287         int last_pos_said;              /*!< Last position we told the user */
288         time_t last_periodic_announce_time;     /*!< The last time we played a periodic announcement */
289         int last_periodic_announce_sound;       /* The last periodic announcement we made */
290         time_t last_pos;                /*!< Last time we told the user their position */
291         int opos;                       /*!< Where we started in the queue */
292         int handled;                    /*!< Whether our call was handled */
293         int max_penalty;                /*!< Limit the members that can take this call to this penalty or lower */
294         time_t start;                   /*!< When we started holding */
295         time_t expire;                  /*!< When this entry should expire (time out of queue) */
296         struct ast_channel *chan;       /*!< Our channel */
297         struct queue_ent *next;         /*!< The next queue entry */
298 };
299
300 struct member {
301         char interface[80];             /*!< Technology/Location */
302         int penalty;                    /*!< Are we a last resort? */
303         int calls;                      /*!< Number of calls serviced by this member */
304         int dynamic;                    /*!< Are we dynamically added? */
305         int status;                     /*!< Status of queue member */
306         int paused;                     /*!< Are we paused (not accepting calls)? */
307         time_t lastcall;                /*!< When last successful call was hungup */
308         int dead;                       /*!< Used to detect members deleted in realtime */
309         struct member *next;            /*!< Next member */
310 };
311
312 /* values used in multi-bit flags in ast_call_queue */
313 #define QUEUE_EMPTY_NORMAL 1
314 #define QUEUE_EMPTY_STRICT 2
315 #define ANNOUNCEHOLDTIME_ALWAYS 1
316 #define ANNOUNCEHOLDTIME_ONCE 2
317
318 struct ast_call_queue {
319         ast_mutex_t lock;       
320         char name[80];                  /*!< Name */
321         char moh[80];                   /*!< Music On Hold class to be used */
322         char announce[80];              /*!< Announcement to play when call is answered */
323         char context[AST_MAX_CONTEXT];  /*!< Exit context */
324         unsigned int monjoin:1;
325         unsigned int dead:1;
326         unsigned int joinempty:2;
327         unsigned int eventwhencalled:1;
328         unsigned int leavewhenempty:2;
329         unsigned int ringinuse:1;
330         unsigned int reportholdtime:1;
331         unsigned int wrapped:1;
332         unsigned int timeoutrestart:1;
333         unsigned int announceholdtime:2;
334         unsigned int strategy:3;
335         unsigned int maskmemberstatus:1;
336         unsigned int realtime:1;
337         int announcefrequency;          /*!< How often to announce their position */
338         int periodicannouncefrequency;  /*!< How often to play periodic announcement */
339         int roundingseconds;            /*!< How many seconds do we round to? */
340         int holdtime;                   /*!< Current avg holdtime, based on recursive boxcar filter */
341         int callscompleted;             /*!< Number of queue calls completed */
342         int callsabandoned;             /*!< Number of queue calls abandoned */
343         int servicelevel;               /*!< seconds setting for servicelevel*/
344         int callscompletedinsl;         /*!< Number of calls answered with servicelevel*/
345         char monfmt[8];                 /*!< Format to use when recording calls */
346         char sound_next[80];            /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
347         char sound_thereare[80];        /*!< Sound file: "There are currently" (def. queue-thereare) */
348         char sound_calls[80];           /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
349         char sound_holdtime[80];        /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
350         char sound_minutes[80];         /*!< Sound file: "minutes." (def. queue-minutes) */
351         char sound_lessthan[80];        /*!< Sound file: "less-than" (def. queue-lessthan) */
352         char sound_seconds[80];         /*!< Sound file: "seconds." (def. queue-seconds) */
353         char sound_thanks[80];          /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
354         char sound_reporthold[80];      /*!< Sound file: "Hold time" (def. queue-reporthold) */
355         char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/* Sound files: Custom announce, no default */
356
357         int count;                      /*!< How many entries */
358         int maxlen;                     /*!< Max number of entries */
359         int wrapuptime;                 /*!< Wrapup Time */
360
361         int retry;                      /*!< Retry calling everyone after this amount of time */
362         int timeout;                    /*!< How long to wait for an answer */
363         int weight;                     /*!< Respective weight */
364         int autopause;                  /*!< Auto pause queue members if they fail to answer */
365
366         /* Queue strategy things */
367         int rrpos;                      /*!< Round Robin - position */
368         int memberdelay;                /*!< Seconds to delay connecting member to caller */
369         int autofill;                   /*!< Ignore the head call status and ring an available agent */
370         
371         struct member *members;         /*!< Head of the list of members */
372         struct queue_ent *head;         /*!< Head of the list of callers */
373         AST_LIST_ENTRY(ast_call_queue) list;    /*!< Next call queue */
374 };
375
376 static AST_LIST_HEAD_STATIC(queues, ast_call_queue);
377
378 static int set_member_paused(char *queuename, char *interface, int paused);
379
380 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
381 {
382         int i;
383
384         for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
385                 if (queue_results[i].id == res) {
386                         pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
387                         return;
388                 }
389         }
390 }
391
392 static char *int2strat(int strategy)
393 {
394         int x;
395         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
396                 if (strategy == strategies[x].strategy)
397                         return strategies[x].name;
398         }
399         return "<unknown>";
400 }
401
402 static int strat2int(const char *strategy)
403 {
404         int x;
405         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
406                 if (!strcasecmp(strategy, strategies[x].name))
407                         return strategies[x].strategy;
408         }
409         return -1;
410 }
411
412 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
413 static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
414 {
415         struct queue_ent *cur;
416
417         if (!q || !new)
418                 return;
419         if (prev) {
420                 cur = prev->next;
421                 prev->next = new;
422         } else {
423                 cur = q->head;
424                 q->head = new;
425         }
426         new->next = cur;
427         new->parent = q;
428         new->pos = ++(*pos);
429         new->opos = *pos;
430 }
431
432 enum queue_member_status {
433         QUEUE_NO_MEMBERS,
434         QUEUE_NO_REACHABLE_MEMBERS,
435         QUEUE_NORMAL
436 };
437
438 static enum queue_member_status get_member_status(const struct ast_call_queue *q, int max_penalty)
439 {
440         struct member *member;
441         enum queue_member_status result = QUEUE_NO_MEMBERS;
442
443         for (member = q->members; member; member = member->next) {
444                 if (max_penalty && (member->penalty > max_penalty))
445                         continue;
446
447                 switch (member->status) {
448                 case AST_DEVICE_INVALID:
449                         /* nothing to do */
450                         break;
451                 case AST_DEVICE_UNAVAILABLE:
452                         result = QUEUE_NO_REACHABLE_MEMBERS;
453                         break;
454                 default:
455                         return QUEUE_NORMAL;
456                 }
457         }
458         
459         return result;
460 }
461
462 struct statechange {
463         int state;
464         char dev[0];
465 };
466
467 static void *changethread(void *data)
468 {
469         struct ast_call_queue *q;
470         struct statechange *sc = data;
471         struct member *cur;
472         char *loc;
473         char *technology;
474
475         technology = ast_strdupa(sc->dev);
476         loc = strchr(technology, '/');
477         if (loc) {
478                 *loc = '\0';
479                 loc++;
480         } else {
481                 free(sc);
482                 return NULL;
483         }
484         if (option_debug)
485                 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
486         AST_LIST_LOCK(&queues);
487         AST_LIST_TRAVERSE(&queues, q, list) {
488                 ast_mutex_lock(&q->lock);
489                 cur = q->members;
490                 while(cur) {
491                         if (!strcasecmp(sc->dev, cur->interface)) {
492                                 if (cur->status != sc->state) {
493                                         cur->status = sc->state;
494                                         if (!q->maskmemberstatus) {
495                                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
496                                                         "Queue: %s\r\n"
497                                                         "Location: %s\r\n"
498                                                         "Membership: %s\r\n"
499                                                         "Penalty: %d\r\n"
500                                                         "CallsTaken: %d\r\n"
501                                                         "LastCall: %d\r\n"
502                                                         "Status: %d\r\n"
503                                                         "Paused: %d\r\n",
504                                                 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
505                                                 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
506                                         }
507                                 }
508                         }
509                         cur = cur->next;
510                 }
511                 ast_mutex_unlock(&q->lock);
512         }
513         AST_LIST_UNLOCK(&queues);
514         free(sc);
515         return NULL;
516 }
517
518 static int statechange_queue(const char *dev, int state, void *ign)
519 {
520         /* Avoid potential for deadlocks by spawning a new thread to handle
521            the event */
522         struct statechange *sc;
523         pthread_t t;
524         pthread_attr_t attr;
525         
526         if ((sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) {
527                 sc->state = state;
528                 strcpy(sc->dev, dev);
529                 pthread_attr_init(&attr);
530                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
531                 if (ast_pthread_create(&t, &attr, changethread, sc)) {
532                         ast_log(LOG_WARNING, "Failed to create update thread!\n");
533                         free(sc);
534                 }
535         }
536         return 0;
537 }
538
539 static struct member *create_queue_member(char *interface, int penalty, int paused)
540 {
541         struct member *cur;
542         
543         /* Add a new member */
544
545         if ((cur = ast_calloc(1, sizeof(*cur)))) {
546                 cur->penalty = penalty;
547                 cur->paused = paused;
548                 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
549                 if (!strchr(cur->interface, '/'))
550                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
551                 cur->status = ast_device_state(interface);
552         }
553
554         return cur;
555 }
556
557 static struct ast_call_queue *alloc_queue(const char *queuename)
558 {
559         struct ast_call_queue *q;
560
561         if ((q = ast_calloc(1, sizeof(*q)))) {
562                 ast_mutex_init(&q->lock);
563                 ast_copy_string(q->name, queuename, sizeof(q->name));
564         }
565         return q;
566 }
567
568 static void init_queue(struct ast_call_queue *q)
569 {
570         int i;
571         q->dead = 0;
572         q->retry = DEFAULT_RETRY;
573         q->timeout = -1;
574         q->maxlen = 0;
575         q->announcefrequency = 0;
576         q->announceholdtime = 0;
577         q->roundingseconds = 0; /* Default - don't announce seconds */
578         q->servicelevel = 0;
579         q->ringinuse = 1;
580         q->moh[0] = '\0';
581         q->announce[0] = '\0';
582         q->context[0] = '\0';
583         q->monfmt[0] = '\0';
584         q->periodicannouncefrequency = 0;
585         ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
586         ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
587         ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
588         ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
589         ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
590         ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
591         ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
592         ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
593         ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
594         ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
595         for (i=1;i<MAX_PERIODIC_ANNOUNCEMENTS;i++) {
596                 q->sound_periodicannounce[i][0]='\0';
597         }
598 }
599
600 static void clear_queue(struct ast_call_queue *q)
601 {
602         q->holdtime = 0;
603         q->callscompleted = 0;
604         q->callsabandoned = 0;
605         q->callscompletedinsl = 0;
606         q->wrapuptime = 0;
607 }
608
609 /*! \brief Configure a queue parameter.
610 \par
611    For error reporting, line number is passed for .conf static configuration.
612    For Realtime queues, linenum is -1.
613    The failunknown flag is set for config files (and static realtime) to show
614    errors for unknown parameters. It is cleared for dynamic realtime to allow
615    extra fields in the tables. */
616 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
617 {
618         int i = 0;
619         char *c, *lastc;
620         char buff[80];
621         if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
622                 ast_copy_string(q->moh, val, sizeof(q->moh));
623         } else if (!strcasecmp(param, "announce")) {
624                 ast_copy_string(q->announce, val, sizeof(q->announce));
625         } else if (!strcasecmp(param, "context")) {
626                 ast_copy_string(q->context, val, sizeof(q->context));
627         } else if (!strcasecmp(param, "timeout")) {
628                 q->timeout = atoi(val);
629                 if (q->timeout < 0)
630                         q->timeout = DEFAULT_TIMEOUT;
631         } else if (!strcasecmp(param, "ringinuse")) {
632                 q->ringinuse = ast_true(val);
633         } else if (!strcasecmp(param, "monitor-join")) {
634                 q->monjoin = ast_true(val);
635         } else if (!strcasecmp(param, "monitor-format")) {
636                 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
637         } else if (!strcasecmp(param, "queue-youarenext")) {
638                 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
639         } else if (!strcasecmp(param, "queue-thereare")) {
640                 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
641         } else if (!strcasecmp(param, "queue-callswaiting")) {
642                 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
643         } else if (!strcasecmp(param, "queue-holdtime")) {
644                 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
645         } else if (!strcasecmp(param, "queue-minutes")) {
646                 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
647         } else if (!strcasecmp(param, "queue-seconds")) {
648                 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
649         } else if (!strcasecmp(param, "queue-lessthan")) {
650                 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
651         } else if (!strcasecmp(param, "queue-thankyou")) {
652                 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
653         } else if (!strcasecmp(param, "queue-reporthold")) {
654                 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
655         } else if (!strcasecmp(param, "announce-frequency")) {
656                 q->announcefrequency = atoi(val);
657         } else if (!strcasecmp(param, "announce-round-seconds")) {
658                 q->roundingseconds = atoi(val);
659                 if (q->roundingseconds>60 || q->roundingseconds<0) {
660                         if (linenum >= 0) {
661                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
662                                         "using 0 instead for queue '%s' at line %d of queues.conf\n",
663                                         val, param, q->name, linenum);
664                         } else {
665                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
666                                         "using 0 instead for queue '%s'\n", val, param, q->name);
667                         }
668                         q->roundingseconds=0;
669                 }
670         } else if (!strcasecmp(param, "announce-holdtime")) {
671                 if (!strcasecmp(val, "once"))
672                         q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
673                 else if (ast_true(val))
674                         q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
675                 else
676                         q->announceholdtime = 0;
677         } else if (!strcasecmp(param, "periodic-announce")) {
678                 if (strchr(val,'|')) {
679                         lastc = (char *)val;
680                         while ((c = strchr(lastc,'|'))) {
681                                 if (i > MAX_PERIODIC_ANNOUNCEMENTS)
682                                         break;
683                                 strncpy(buff, lastc, abs(lastc - c));
684                                 buff[abs(lastc - c)] = '\0';
685                                 ast_copy_string(q->sound_periodicannounce[i], buff, sizeof(q->sound_periodicannounce[i]));
686                                 lastc = (c + 1);
687                                 i++;
688                         }
689                         if (strlen(lastc)) {
690                                 ast_copy_string(q->sound_periodicannounce[i], lastc, sizeof(q->sound_periodicannounce[i]));
691                         }
692                 } else {
693                         ast_copy_string(q->sound_periodicannounce[i], val, sizeof(q->sound_periodicannounce[i]));
694                 }
695         } else if (!strcasecmp(param, "periodic-announce-frequency")) {
696                 q->periodicannouncefrequency = atoi(val);
697         } else if (!strcasecmp(param, "retry")) {
698                 q->retry = atoi(val);
699                 if (q->retry < 0)
700                         q->retry = DEFAULT_RETRY;
701         } else if (!strcasecmp(param, "wrapuptime")) {
702                 q->wrapuptime = atoi(val);
703         } else if (!strcasecmp(param, "autofill")) {
704                 q->autofill = ast_true(val);
705         } else if (!strcasecmp(param, "autopause")) {
706                 q->autopause = ast_true(val);
707         } else if (!strcasecmp(param, "maxlen")) {
708                 q->maxlen = atoi(val);
709                 if (q->maxlen < 0)
710                         q->maxlen = 0;
711         } else if (!strcasecmp(param, "servicelevel")) {
712                 q->servicelevel= atoi(val);
713         } else if (!strcasecmp(param, "strategy")) {
714                 q->strategy = strat2int(val);
715                 if (q->strategy < 0) {
716                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
717                                 val, q->name);
718                         q->strategy = 0;
719                 }
720         } else if (!strcasecmp(param, "joinempty")) {
721                 if (!strcasecmp(val, "strict"))
722                         q->joinempty = QUEUE_EMPTY_STRICT;
723                 else if (ast_true(val))
724                         q->joinempty = QUEUE_EMPTY_NORMAL;
725                 else
726                         q->joinempty = 0;
727         } else if (!strcasecmp(param, "leavewhenempty")) {
728                 if (!strcasecmp(val, "strict"))
729                         q->leavewhenempty = QUEUE_EMPTY_STRICT;
730                 else if (ast_true(val))
731                         q->leavewhenempty = QUEUE_EMPTY_NORMAL;
732                 else
733                         q->leavewhenempty = 0;
734         } else if (!strcasecmp(param, "eventmemberstatus")) {
735                 q->maskmemberstatus = !ast_true(val);
736         } else if (!strcasecmp(param, "eventwhencalled")) {
737                 q->eventwhencalled = ast_true(val);
738         } else if (!strcasecmp(param, "reportholdtime")) {
739                 q->reportholdtime = ast_true(val);
740         } else if (!strcasecmp(param, "memberdelay")) {
741                 q->memberdelay = atoi(val);
742         } else if (!strcasecmp(param, "weight")) {
743                 q->weight = atoi(val);
744                 if (q->weight)
745                         use_weight++;
746                 /* With Realtime queues, if the last queue using weights is deleted in realtime,
747                    we will not see any effect on use_weight until next reload. */
748         } else if (!strcasecmp(param, "timeoutrestart")) {
749                 q->timeoutrestart = ast_true(val);
750         } else if(failunknown) {
751                 if (linenum >= 0) {
752                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
753                                 q->name, param, linenum);
754                 } else {
755                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
756                 }
757         }
758 }
759
760 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
761 {
762         struct member *m, *prev_m;
763         int penalty = 0;
764
765         if(penalty_str) {
766                 penalty = atoi(penalty_str);
767                 if(penalty < 0)
768                         penalty = 0;
769         }
770
771         /* Find the member, or the place to put a new one. */
772         prev_m = NULL;
773         m = q->members;
774         while (m && strcmp(m->interface, interface)) {
775                 prev_m = m;
776                 m = m->next;
777         }
778
779         /* Create a new one if not found, else update penalty */
780         if (!m) {
781                 m = create_queue_member(interface, penalty, 0);
782                 if (m) {
783                         m->dead = 0;
784                         if (prev_m) {
785                                 prev_m->next = m;
786                         } else {
787                                 q->members = m;
788                         }
789                 }
790         } else {
791                 m->dead = 0;    /* Do not delete this one. */
792                 m->penalty = penalty;
793         }
794 }
795
796 static void free_members(struct ast_call_queue *q, int all)
797 {
798         /* Free non-dynamic members */
799         struct member *curm, *next, *prev = NULL;
800
801         for (curm = q->members; curm; curm = next) {
802                 next = curm->next;
803                 if (all || !curm->dynamic) {
804                         if (prev)
805                                 prev->next = next;
806                         else
807                                 q->members = next;
808                         free(curm);
809                 } else 
810                         prev = curm;
811         }
812 }
813
814 static void destroy_queue(struct ast_call_queue *q)
815 {
816         free_members(q, 1);
817         ast_mutex_destroy(&q->lock);
818         free(q);
819 }
820
821 /*!\brief Reload a single queue via realtime.
822    \return Return the queue, or NULL if it doesn't exist.
823    \note Should be called with the global qlock locked. */
824 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
825 {
826         struct ast_variable *v;
827         struct ast_call_queue *q;
828         struct member *m, *prev_m, *next_m;
829         char *interface;
830         char *tmp, *tmp_name;
831         char tmpbuf[64];        /* Must be longer than the longest queue param name. */
832
833         /* Find the queue in the in-core list (we will create a new one if not found). */
834         AST_LIST_TRAVERSE(&queues, q, list) {
835                 if (!strcasecmp(q->name, queuename)) {
836                         break;
837                 }
838         }
839
840         /* Static queues override realtime. */
841         if (q) {
842                 ast_mutex_lock(&q->lock);
843                 if (!q->realtime) {
844                         if (q->dead) {
845                                 ast_mutex_unlock(&q->lock);
846                                 return NULL;
847                         } else {
848                                 ast_mutex_unlock(&q->lock);
849                                 return q;
850                         }
851                 }
852         } else if (!member_config)
853                 /* Not found in the list, and it's not realtime ... */
854                 return NULL;
855
856         /* Check if queue is defined in realtime. */
857         if (!queue_vars) {
858                 /* Delete queue from in-core list if it has been deleted in realtime. */
859                 if (q) {
860                         /*! \note Hmm, can't seem to distinguish a DB failure from a not
861                            found condition... So we might delete an in-core queue
862                            in case of DB failure. */
863                         ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
864
865                         q->dead = 1;
866                         /* Delete if unused (else will be deleted when last caller leaves). */
867                         if (!q->count) {
868                                 /* Delete. */
869                                 AST_LIST_REMOVE(&queues, q, list);
870                                 ast_mutex_unlock(&q->lock);
871                                 destroy_queue(q);
872                         } else
873                                 ast_mutex_unlock(&q->lock);
874                 }
875                 return NULL;
876         }
877
878         /* Create a new queue if an in-core entry does not exist yet. */
879         if (!q) {
880                 if (!(q = alloc_queue(queuename)))
881                         return NULL;
882                 ast_mutex_lock(&q->lock);
883                 clear_queue(q);
884                 q->realtime = 1;
885                 AST_LIST_INSERT_HEAD(&queues, q, list);
886         }
887         init_queue(q);          /* Ensure defaults for all parameters not set explicitly. */
888
889         v = queue_vars;
890         memset(tmpbuf, 0, sizeof(tmpbuf));
891         while(v) {
892                 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
893                 if((tmp = strchr(v->name, '_')) != NULL) {
894                         ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
895                         tmp_name = tmpbuf;
896                         tmp = tmp_name;
897                         while((tmp = strchr(tmp, '_')) != NULL)
898                                 *tmp++ = '-';
899                 } else
900                         tmp_name = v->name;
901                 queue_set_param(q, tmp_name, v->value, -1, 0);
902                 v = v->next;
903         }
904
905         /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
906         m = q->members;
907         while (m) {
908                 if (!m->dynamic)
909                         m->dead = 1;
910                 m = m->next;
911         }
912
913         interface = ast_category_browse(member_config, NULL);
914         while (interface) {
915                 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
916                 interface = ast_category_browse(member_config, interface);
917         }
918
919         /* Delete all realtime members that have been deleted in DB. */
920         m = q->members;
921         prev_m = NULL;
922         while (m) {
923                 next_m = m->next;
924                 if (m->dead) {
925                         if (prev_m) {
926                                 prev_m->next = next_m;
927                         } else {
928                                 q->members = next_m;
929                         }
930                         free(m);
931                 } else {
932                         prev_m = m;
933                 }
934                 m = next_m;
935         }
936
937         ast_mutex_unlock(&q->lock);
938
939         return q;
940 }
941
942 static struct ast_call_queue *load_realtime_queue(char *queuename)
943 {
944         struct ast_variable *queue_vars = NULL;
945         struct ast_config *member_config = NULL;
946         struct ast_call_queue *q;
947
948         /* Find the queue in the in-core list first. */
949         AST_LIST_LOCK(&queues);
950         AST_LIST_TRAVERSE(&queues, q, list) {
951                 if (!strcasecmp(q->name, queuename)) {
952                         break;
953                 }
954         }
955         AST_LIST_UNLOCK(&queues);
956
957         if (!q) {
958                 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
959                    queue operations while waiting for the DB.
960
961                    This will be two separate database transactions, so we might
962                    see queue parameters as they were before another process
963                    changed the queue and member list as it was after the change.
964                    Thus we might see an empty member list when a queue is
965                    deleted. In practise, this is unlikely to cause a problem. */
966
967                 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
968                 if (queue_vars) {
969                         member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
970                         if (!member_config) {
971                                 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
972                                 return NULL;
973                         }
974                 }
975
976                 AST_LIST_LOCK(&queues);
977
978                 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
979                 if (member_config)
980                         ast_config_destroy(member_config);
981                 if (queue_vars)
982                         ast_variables_destroy(queue_vars);
983
984                 AST_LIST_UNLOCK(&queues);
985         }
986         return q;
987 }
988
989 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
990 {
991         struct ast_call_queue *q;
992         struct queue_ent *cur, *prev = NULL;
993         int res = -1;
994         int pos = 0;
995         int inserted = 0;
996         enum queue_member_status stat;
997
998         q = load_realtime_queue(queuename);
999         if (!q)
1000                 return res;
1001
1002         AST_LIST_LOCK(&queues);
1003         ast_mutex_lock(&q->lock);
1004
1005         /* This is our one */
1006         stat = get_member_status(q, qe->max_penalty);
1007         if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1008                 *reason = QUEUE_JOINEMPTY;
1009         else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1010                 *reason = QUEUE_JOINUNAVAIL;
1011         else if (q->maxlen && (q->count >= q->maxlen))
1012                 *reason = QUEUE_FULL;
1013         else {
1014                 /* There's space for us, put us at the right position inside
1015                  * the queue. 
1016                  * Take into account the priority of the calling user */
1017                 inserted = 0;
1018                 prev = NULL;
1019                 cur = q->head;
1020                 while(cur) {
1021                         /* We have higher priority than the current user, enter
1022                          * before him, after all the other users with priority
1023                          * higher or equal to our priority. */
1024                         if ((!inserted) && (qe->prio > cur->prio)) {
1025                                 insert_entry(q, prev, qe, &pos);
1026                                 inserted = 1;
1027                         }
1028                         cur->pos = ++pos;
1029                         prev = cur;
1030                         cur = cur->next;
1031                 }
1032                 /* No luck, join at the end of the queue */
1033                 if (!inserted)
1034                         insert_entry(q, prev, qe, &pos);
1035                 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1036                 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1037                 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1038                 q->count++;
1039                 res = 0;
1040                 manager_event(EVENT_FLAG_CALL, "Join", 
1041                               "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1042                               qe->chan->name, 
1043                               qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
1044                               qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
1045                               q->name, qe->pos, q->count, qe->chan->uniqueid );
1046 #if 0
1047 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1048 #endif
1049         }
1050         ast_mutex_unlock(&q->lock);
1051         AST_LIST_UNLOCK(&queues);
1052         return res;
1053 }
1054
1055 static int play_file(struct ast_channel *chan, char *filename)
1056 {
1057         int res;
1058
1059         ast_stopstream(chan);
1060         res = ast_streamfile(chan, filename, chan->language);
1061
1062         if (!res)
1063                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1064         else
1065                 res = 0;
1066
1067         ast_stopstream(chan);
1068
1069         return res;
1070 }
1071
1072 static int valid_exit(struct queue_ent *qe, char digit)
1073 {
1074         int digitlen = strlen(qe->digits);
1075
1076         /* Prevent possible buffer overflow */
1077         if (digitlen < sizeof(qe->digits) - 2) {
1078                 qe->digits[digitlen] = digit;
1079                 qe->digits[digitlen + 1] = '\0';
1080         } else {
1081                 qe->digits[0] = '\0';
1082                 return 0;
1083         }
1084
1085         /* If there's no context to goto, short-circuit */
1086         if (ast_strlen_zero(qe->context))
1087                 return 0;
1088
1089         /* If the extension is bad, then reset the digits to blank */
1090         if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1091                 qe->digits[0] = '\0';
1092                 return 0;
1093         }
1094
1095         /* We have an exact match */
1096         if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1097                 /* Return 1 on a successful goto */
1098                 return 1;
1099         }
1100         return 0;
1101 }
1102
1103 static int say_position(struct queue_ent *qe)
1104 {
1105         int res = 0, avgholdmins, avgholdsecs;
1106         time_t now;
1107
1108         /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1109         time(&now);
1110         if ( (now - qe->last_pos) < 15 )
1111                 return 0;
1112
1113         /* If either our position has changed, or we are over the freq timer, say position */
1114         if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
1115                 return 0;
1116
1117         ast_moh_stop(qe->chan);
1118         /* Say we're next, if we are */
1119         if (qe->pos == 1) {
1120                 res = play_file(qe->chan, qe->parent->sound_next);
1121                 if (res && valid_exit(qe, res))
1122                         goto playout;
1123                 else
1124                         goto posout;
1125         } else {
1126                 res = play_file(qe->chan, qe->parent->sound_thereare);
1127                 if (res && valid_exit(qe, res))
1128                         goto playout;
1129                 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1130                 if (res && valid_exit(qe, res))
1131                         goto playout;
1132                 res = play_file(qe->chan, qe->parent->sound_calls);
1133                 if (res && valid_exit(qe, res))
1134                         goto playout;
1135         }
1136         /* Round hold time to nearest minute */
1137         avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
1138
1139         /* If they have specified a rounding then round the seconds as well */
1140         if(qe->parent->roundingseconds) {
1141                 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
1142                 avgholdsecs*= qe->parent->roundingseconds;
1143         } else {
1144                 avgholdsecs=0;
1145         }
1146
1147         if (option_verbose > 2)
1148                 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1149
1150         /* If the hold time is >1 min, if it's enabled, and if it's not
1151            supposed to be only once and we have already said it, say it */
1152         if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1153             (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1154                 res = play_file(qe->chan, qe->parent->sound_holdtime);
1155                 if (res && valid_exit(qe, res))
1156                         goto playout;
1157
1158                 if (avgholdmins>0) {
1159                         if (avgholdmins < 2) {
1160                                 res = play_file(qe->chan, qe->parent->sound_lessthan);
1161                                 if (res && valid_exit(qe, res))
1162                                         goto playout;
1163
1164                                 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1165                                 if (res && valid_exit(qe, res))
1166                                         goto playout;
1167                         } else {
1168                                 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1169                                 if (res && valid_exit(qe, res))
1170                                         goto playout;
1171                         }
1172                         
1173                         res = play_file(qe->chan, qe->parent->sound_minutes);
1174                         if (res && valid_exit(qe, res))
1175                                 goto playout;
1176                 }
1177                 if (avgholdsecs>0) {
1178                         res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1179                         if (res && valid_exit(qe, res))
1180                                 goto playout;
1181
1182                         res = play_file(qe->chan, qe->parent->sound_seconds);
1183                         if (res && valid_exit(qe, res))
1184                                 goto playout;
1185                 }
1186
1187         }
1188
1189  posout:
1190         if (option_verbose > 2)
1191                 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1192                             qe->chan->name, qe->parent->name, qe->pos);
1193         res = play_file(qe->chan, qe->parent->sound_thanks);
1194
1195  playout:
1196         /* Set our last_pos indicators */
1197         qe->last_pos = now;
1198         qe->last_pos_said = qe->pos;
1199         ast_moh_start(qe->chan, qe->moh);
1200
1201         return res;
1202 }
1203
1204 static void recalc_holdtime(struct queue_ent *qe)
1205 {
1206         int oldvalue, newvalue;
1207
1208         /* Calculate holdtime using a recursive boxcar filter */
1209         /* Thanks to SRT for this contribution */
1210         /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1211
1212         newvalue = time(NULL) - qe->start;
1213
1214         ast_mutex_lock(&qe->parent->lock);
1215         if (newvalue <= qe->parent->servicelevel)
1216                 qe->parent->callscompletedinsl++;
1217         oldvalue = qe->parent->holdtime;
1218         qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1219         ast_mutex_unlock(&qe->parent->lock);
1220 }
1221
1222
1223 static void leave_queue(struct queue_ent *qe)
1224 {
1225         struct ast_call_queue *q;
1226         struct queue_ent *cur, *prev = NULL;
1227         int pos = 0;
1228
1229         q = qe->parent;
1230         if (!q)
1231                 return;
1232         ast_mutex_lock(&q->lock);
1233
1234         prev = NULL;
1235         cur = q->head;
1236         while(cur) {
1237                 if (cur == qe) {
1238                         q->count--;
1239
1240                         /* Take us out of the queue */
1241                         manager_event(EVENT_FLAG_CALL, "Leave",
1242                                 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
1243                                 qe->chan->name, q->name,  q->count);
1244 #if 0
1245 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1246 #endif
1247                         /* Take us out of the queue */
1248                         if (prev)
1249                                 prev->next = cur->next;
1250                         else
1251                                 q->head = cur->next;
1252                 } else {
1253                         /* Renumber the people after us in the queue based on a new count */
1254                         cur->pos = ++pos;
1255                         prev = cur;
1256                 }
1257                 cur = cur->next;
1258         }
1259         ast_mutex_unlock(&q->lock);
1260         if (q->dead && !q->count) {     
1261                 /* It's dead and nobody is in it, so kill it */
1262                 AST_LIST_LOCK(&queues);
1263                 AST_LIST_REMOVE(&queues, q, list);
1264                 AST_LIST_UNLOCK(&queues);
1265                 destroy_queue(q);
1266         }
1267 }
1268
1269 /* Hang up a list of outgoing calls */
1270 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1271 {
1272         struct callattempt *oo;
1273
1274         while(outgoing) {
1275                 /* Hangup any existing lines we have open */
1276                 if (outgoing->chan && (outgoing->chan != exception))
1277                         ast_hangup(outgoing->chan);
1278                 oo = outgoing;
1279                 outgoing=outgoing->q_next;
1280                 free(oo);
1281         }
1282 }
1283
1284 static int update_status(struct ast_call_queue *q, struct member *member, int status)
1285 {
1286         struct member *cur;
1287
1288         /* Since a reload could have taken place, we have to traverse the list to
1289                 be sure it's still valid */
1290         ast_mutex_lock(&q->lock);
1291         for (cur = q->members; cur; cur = cur->next) {
1292                 if (member == cur) {
1293                         cur->status = status;
1294                         if (!q->maskmemberstatus) {
1295                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1296                                         "Queue: %s\r\n"
1297                                         "Location: %s\r\n"
1298                                         "Membership: %s\r\n"
1299                                         "Penalty: %d\r\n"
1300                                         "CallsTaken: %d\r\n"
1301                                         "LastCall: %d\r\n"
1302                                         "Status: %d\r\n"
1303                                         "Paused: %d\r\n",
1304                                 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1305                                 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1306                         }
1307                         break;
1308                 }
1309         }
1310         ast_mutex_unlock(&q->lock);
1311         return 0;
1312 }
1313
1314 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
1315 {
1316         if (status == AST_CAUSE_BUSY)
1317                 status = AST_DEVICE_BUSY;
1318         else if (status == AST_CAUSE_UNREGISTERED)
1319                 status = AST_DEVICE_UNAVAILABLE;
1320         else if (status == AST_CAUSE_NOSUCHDRIVER)
1321                 status = AST_DEVICE_INVALID;
1322         else
1323                 status = AST_DEVICE_UNKNOWN;
1324         return update_status(q, member, status);
1325 }
1326
1327 /* traverse all defined queues which have calls waiting and contain this member
1328    return 0 if no other queue has precedence (higher weight) or 1 if found  */
1329 static int compare_weight(struct ast_call_queue *rq, struct member *member)
1330 {
1331         struct ast_call_queue *q;
1332         struct member *mem;
1333         int found = 0;
1334         
1335         /* &qlock and &rq->lock already set by try_calling()
1336          * to solve deadlock */
1337         AST_LIST_TRAVERSE(&queues, q, list) {
1338                 if (q == rq) /* don't check myself, could deadlock */
1339                         continue; 
1340                 ast_mutex_lock(&q->lock);
1341                 if (q->count && q->members) {
1342                         for (mem = q->members; mem; mem = mem->next) {
1343                                 if (!strcmp(mem->interface, member->interface)) {
1344                                         ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1345                                         if (q->weight > rq->weight) {
1346                                                 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);
1347                                                 found = 1;
1348                                                 break;
1349                                         }
1350                                 }
1351                         }
1352                 }
1353                 ast_mutex_unlock(&q->lock);
1354                 if (found) 
1355                         break;
1356         }
1357         return found;
1358 }
1359
1360 /*! \brief common hangup actions */
1361 static void do_hang(struct callattempt *o)
1362 {
1363         o->stillgoing = 0;
1364         ast_hangup(o->chan);
1365         o->chan = NULL;
1366 }
1367
1368 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1369 {
1370         int res;
1371         int status;
1372         char tech[256];
1373         char *location;
1374
1375         /* on entry here, we know that tmp->chan == NULL */
1376         if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1377                 if (option_debug)
1378                         ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1379                 if (qe->chan->cdr)
1380                         ast_cdr_busy(qe->chan->cdr);
1381                 tmp->stillgoing = 0;
1382                 (*busies)++;
1383                 return 0;
1384         }
1385
1386         if (!qe->parent->ringinuse && (tmp->member->status == AST_DEVICE_INUSE)) {
1387                 if (option_debug)
1388                         ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1389                 if (qe->chan->cdr)
1390                         ast_cdr_busy(qe->chan->cdr);
1391                 tmp->stillgoing = 0;
1392                 return 0;
1393         }
1394
1395         if (tmp->member->paused) {
1396                 if (option_debug)
1397                         ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1398                 if (qe->chan->cdr)
1399                         ast_cdr_busy(qe->chan->cdr);
1400                 tmp->stillgoing = 0;
1401                 return 0;
1402         }
1403         if (use_weight && compare_weight(qe->parent,tmp->member)) {
1404                 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1405                 if (qe->chan->cdr)
1406                         ast_cdr_busy(qe->chan->cdr);
1407                 tmp->stillgoing = 0;
1408                 (*busies)++;
1409                 return 0;
1410         }
1411
1412         ast_copy_string(tech, tmp->interface, sizeof(tech));
1413         if ((location = strchr(tech, '/')))
1414                 *location++ = '\0';
1415         else
1416                 location = "";
1417
1418         /* Request the peer */
1419         tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1420         if (!tmp->chan) {                       /* If we can't, just go on to the next call */
1421 #if 0
1422                 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
1423 #endif                  
1424                 if (qe->chan->cdr)
1425                         ast_cdr_busy(qe->chan->cdr);
1426                 tmp->stillgoing = 0;
1427                 update_dial_status(qe->parent, tmp->member, status);
1428                 (*busies)++;
1429                 return 0;
1430         } else if (status != tmp->oldstatus) 
1431                 update_dial_status(qe->parent, tmp->member, status);
1432         
1433         tmp->chan->appl = "AppQueue";
1434         tmp->chan->data = "(Outgoing Line)";
1435         tmp->chan->whentohangup = 0;
1436         if (tmp->chan->cid.cid_num)
1437                 free(tmp->chan->cid.cid_num);
1438         tmp->chan->cid.cid_num = NULL;
1439         if (tmp->chan->cid.cid_name)
1440                 free(tmp->chan->cid.cid_name);
1441         tmp->chan->cid.cid_name = NULL;
1442         if (tmp->chan->cid.cid_ani)
1443                 free(tmp->chan->cid.cid_ani);
1444         tmp->chan->cid.cid_ani = NULL;
1445         if (qe->chan->cid.cid_num)
1446                 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
1447         if (qe->chan->cid.cid_name)
1448                 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
1449         if (qe->chan->cid.cid_ani)
1450                 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
1451
1452         /* Inherit specially named variables from parent channel */
1453         ast_channel_inherit_variables(qe->chan, tmp->chan);
1454
1455         /* Presense of ADSI CPE on outgoing channel follows ours */
1456         tmp->chan->adsicpe = qe->chan->adsicpe;
1457
1458         /* Place the call, but don't wait on the answer */
1459         res = ast_call(tmp->chan, location, 0);
1460         if (res) {
1461                 /* Again, keep going even if there's an error */
1462                 if (option_debug)
1463                         ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1464                 else if (option_verbose > 2)
1465                         ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1466                 do_hang(tmp);
1467                 (*busies)++;
1468                 return 0;
1469         } else {
1470                 if (qe->parent->eventwhencalled) {
1471                         manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1472                                                 "AgentCalled: %s\r\n"
1473                                                 "ChannelCalling: %s\r\n"
1474                                                 "CallerID: %s\r\n"
1475                                                 "CallerIDName: %s\r\n"
1476                                                 "Context: %s\r\n"
1477                                                 "Extension: %s\r\n"
1478                                                 "Priority: %d\r\n",
1479                                                 tmp->interface, qe->chan->name,
1480                                                 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1481                                                 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1482                                                 qe->chan->context, qe->chan->exten, qe->chan->priority);
1483                 }
1484                 if (option_verbose > 2)
1485                         ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1486         }
1487         return 1;
1488 }
1489
1490 /*! \brief find the entry with the best metric, or NULL */
1491 static struct callattempt *find_best(struct callattempt *outgoing)
1492 {
1493         struct callattempt *best = NULL, *cur;
1494
1495         for (cur = outgoing; cur; cur = cur->q_next) {
1496                 if (cur->stillgoing &&                                  /* Not already done */
1497                         !cur->chan &&                                   /* Isn't already going */
1498                         (!best || cur->metric < best->metric)) {        /* We haven't found one yet, or it's better */
1499                                 best = cur;
1500                 }
1501         }
1502         return best;
1503 }
1504
1505 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1506 {
1507         int ret = 0;
1508
1509         while (ret == 0) {
1510                 struct callattempt *best = find_best(outgoing);
1511                 if (!best) {
1512                         if (option_debug)
1513                                 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1514                         break;
1515                 }
1516                 if (!qe->parent->strategy) {
1517                         struct callattempt *cur;
1518                         /* Ring everyone who shares this best metric (for ringall) */
1519                         for (cur = outgoing; cur; cur = cur->q_next) {
1520                                 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1521                                         if (option_debug)
1522                                                 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1523                                         ring_entry(qe, cur, busies);
1524                                 }
1525                         }
1526                 } else {
1527                         /* Ring just the best channel */
1528                         if (option_debug)
1529                                 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1530                         ring_entry(qe, best, busies);
1531                 }
1532                 if (best->chan) /* break out with result = 1 */
1533                         ret = 1;
1534         }
1535         return ret;
1536 }
1537
1538 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1539 {
1540         struct callattempt *best = find_best(outgoing);
1541
1542         if (best) {
1543                 /* Ring just the best channel */
1544                 if (option_debug)
1545                         ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1546                 qe->parent->rrpos = best->metric % 1000;
1547         } else {
1548                 /* Just increment rrpos */
1549                 if (qe->parent->wrapped) {
1550                         /* No more channels, start over */
1551                         qe->parent->rrpos = 0;
1552                 } else {
1553                         /* Prioritize next entry */
1554                         qe->parent->rrpos++;
1555                 }
1556         }
1557         qe->parent->wrapped = 0;
1558         return 0;
1559 }
1560
1561 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1562 {
1563         int res;
1564
1565         ast_stopstream(chan);
1566         res = ast_streamfile(chan, filename, chan->language);
1567
1568         if (!res) {
1569                 /* Wait for a keypress */
1570                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1571                 if (res <= 0 || !valid_exit(qe, res))
1572                         res = 0;
1573
1574                 /* Stop playback */
1575                 ast_stopstream(chan);
1576         } else {
1577                 res = 0;
1578         }
1579         
1580         /*if (res) {
1581                 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
1582                 res = 0;
1583         }*/
1584
1585         return res;
1586 }
1587
1588 static int say_periodic_announcement(struct queue_ent *qe)
1589 {
1590         int res = 0;
1591         time_t now;
1592
1593         /* Get the current time */
1594         time(&now);
1595
1596         /* Check to see if it is time to announce */
1597         if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1598                 return 0;
1599
1600         /* Stop the music on hold so we can play our own file */
1601         ast_moh_stop(qe->chan);
1602
1603         if (option_verbose > 2)
1604                 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1605
1606         /* Check to make sure we have a sound file. If not, reset to the first sound file */
1607         if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
1608                 qe->last_periodic_announce_sound = 0;
1609         }
1610         
1611         /* play the announcement */
1612         res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
1613
1614         /* Resume Music on Hold */
1615         ast_moh_start(qe->chan, qe->moh);
1616
1617         /* update last_periodic_announce_time */
1618         qe->last_periodic_announce_time = now;
1619
1620         /* Update the current periodic announcement to the next announcement */
1621         qe->last_periodic_announce_sound++;
1622         
1623         return res;
1624 }
1625
1626 static void record_abandoned(struct queue_ent *qe)
1627 {
1628         ast_mutex_lock(&qe->parent->lock);
1629         qe->parent->callsabandoned++;
1630         ast_mutex_unlock(&qe->parent->lock);
1631 }
1632
1633
1634 #define AST_MAX_WATCHERS 256
1635
1636 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1637 {
1638         char *queue = qe->parent->name;
1639         struct callattempt *o;
1640         int status;
1641         int sentringing = 0;
1642         int numbusies = prebusies;
1643         int numnochan = 0;
1644         int stillgoing = 0;
1645         int orig = *to;
1646         struct ast_frame *f;
1647         struct callattempt *peer = NULL;
1648         struct ast_channel *winner;
1649         struct ast_channel *in = qe->chan;
1650         char on[256] = "";
1651         
1652         while(*to && !peer) {
1653                 int numlines, retry, pos = 1;
1654                 struct ast_channel *watchers[AST_MAX_WATCHERS];
1655                 watchers[0] = in;
1656
1657                 for (retry = 0; retry < 2; retry++) {
1658                         numlines = 0;
1659                         for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
1660                                 if (o->stillgoing) {    /* Keep track of important channels */
1661                                         stillgoing = 1;
1662                                         if (o->chan)
1663                                                 watchers[pos++] = o->chan;
1664                                 }
1665                                 numlines++;
1666                         }
1667                         if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
1668                                          qe->parent->strategy /* ring would not be delivered */)
1669                                 break;
1670                         /* On "ringall" strategy we only move to the next penalty level
1671                            when *all* ringing phones are done in the current penalty level */
1672                         ring_one(qe, outgoing, &numbusies);
1673                         /* and retry... */
1674                 }
1675                 if (pos == 1 /* not found */) {
1676                         if (numlines == (numbusies + numnochan)) {
1677                                 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1678                         } else {
1679                                 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1680                         }
1681                         *to = 0;
1682                         return NULL;
1683                 }
1684                 winner = ast_waitfor_n(watchers, pos, to);
1685                 for (o = outgoing; o; o = o->q_next) {
1686                         if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
1687                                 if (!peer) {
1688                                         if (option_verbose > 2)
1689                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1690                                         peer = o;
1691                                 }
1692                         } else if (o->chan && (o->chan == winner)) {
1693                                 ast_copy_string(on, o->member->interface, sizeof(on));
1694                                 if (!ast_strlen_zero(o->chan->call_forward)) {
1695                                         char tmpchan[256]="";
1696                                         char *stuff;
1697                                         char *tech;
1698                                         ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1699                                         if ((stuff = strchr(tmpchan, '/'))) {
1700                                                 *stuff++ = '\0';
1701                                                 tech = tmpchan;
1702                                         } else {
1703                                                 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1704                                                 stuff = tmpchan;
1705                                                 tech = "Local";
1706                                         }
1707                                         /* Before processing channel, go ahead and check for forwarding */
1708                                         if (option_verbose > 2)
1709                                                 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1710                                         /* Setup parameters */
1711                                         o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1712                                         if (status != o->oldstatus) 
1713                                                 update_dial_status(qe->parent, o->member, status);                                              
1714                                         if (!o->chan) {
1715                                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1716                                                 o->stillgoing = 0;
1717                                                 numnochan++;
1718                                         } else {
1719                                                 if (o->chan->cid.cid_num)
1720                                                         free(o->chan->cid.cid_num);
1721                                                 o->chan->cid.cid_num = NULL;
1722                                                 if (o->chan->cid.cid_name)
1723                                                         free(o->chan->cid.cid_name);
1724                                                 o->chan->cid.cid_name = NULL;
1725
1726                                                 if (in->cid.cid_num) {
1727                                                         o->chan->cid.cid_num = strdup(in->cid.cid_num);
1728                                                         if (!o->chan->cid.cid_num)
1729                                                                 ast_log(LOG_WARNING, "Out of memory\n");        
1730                                                 }
1731                                                 if (in->cid.cid_name) {
1732                                                         o->chan->cid.cid_name = strdup(in->cid.cid_name);
1733                                                         if (!o->chan->cid.cid_name)
1734                                                                 ast_log(LOG_WARNING, "Out of memory\n");        
1735                                                 }
1736                                                 ast_string_field_set(o->chan, accountcode, in->accountcode);
1737                                                 o->chan->cdrflags = in->cdrflags;
1738
1739                                                 if (in->cid.cid_ani) {
1740                                                         if (o->chan->cid.cid_ani)
1741                                                                 free(o->chan->cid.cid_ani);
1742                                                         o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
1743                                                 }
1744                                                 if (o->chan->cid.cid_rdnis) 
1745                                                         free(o->chan->cid.cid_rdnis);
1746                                                 if (!ast_strlen_zero(in->macroexten))
1747                                                         o->chan->cid.cid_rdnis = strdup(in->macroexten);
1748                                                 else
1749                                                         o->chan->cid.cid_rdnis = strdup(in->exten);
1750                                                 if (ast_call(o->chan, tmpchan, 0)) {
1751                                                         ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1752                                                         do_hang(o);
1753                                                         numnochan++;
1754                                                 }
1755                                         }
1756                                         /* Hangup the original channel now, in case we needed it */
1757                                         ast_hangup(winner);
1758                                         continue;
1759                                 }
1760                                 f = ast_read(winner);
1761                                 if (f) {
1762                                         if (f->frametype == AST_FRAME_CONTROL) {
1763                                                 switch(f->subclass) {
1764                                         case AST_CONTROL_ANSWER:
1765                                                         /* This is our guy if someone answered. */
1766                                                         if (!peer) {
1767                                                                 if (option_verbose > 2)
1768                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1769                                                                 peer = o;
1770                                                         }
1771                                                         break;
1772                                                 case AST_CONTROL_BUSY:
1773                                                         if (option_verbose > 2)
1774                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1775                                                         if (in->cdr)
1776                                                                 ast_cdr_busy(in->cdr);
1777                                                         do_hang(o);
1778                                                         if (qe->parent->strategy) {
1779                                                                 if (qe->parent->timeoutrestart)
1780                                                                         *to = orig;
1781                                                                 ring_one(qe, outgoing, &numbusies);
1782                                                         }
1783                                                         numbusies++;
1784                                                         break;
1785                                                 case AST_CONTROL_CONGESTION:
1786                                                         if (option_verbose > 2)
1787                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1788                                                         if (in->cdr)
1789                                                                 ast_cdr_busy(in->cdr);
1790                                                         do_hang(o);
1791                                                         if (qe->parent->strategy) {
1792                                                                 if (qe->parent->timeoutrestart)
1793                                                                         *to = orig;
1794                                                                 ring_one(qe, outgoing, &numbusies);
1795                                                         }
1796                                                         numbusies++;
1797                                                         break;
1798                                                 case AST_CONTROL_RINGING:
1799                                                         if (option_verbose > 2)
1800                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1801                                                         if (!sentringing) {
1802 #if 0
1803                                                                 ast_indicate(in, AST_CONTROL_RINGING);
1804 #endif                                                          
1805                                                                 sentringing++;
1806                                                         }
1807                                                         break;
1808                                                 case AST_CONTROL_OFFHOOK:
1809                                                         /* Ignore going off hook */
1810                                                         break;
1811                                                 default:
1812                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1813                                                 }
1814                                         }
1815                                         ast_frfree(f);
1816                                 } else {
1817                                         do_hang(o);
1818                                         if (qe->parent->strategy) {
1819                                                 if (qe->parent->timeoutrestart)
1820                                                         *to = orig;
1821                                                 ring_one(qe, outgoing, &numbusies);
1822                                         }
1823                                 }
1824                         }
1825                 }
1826                 if (winner == in) {
1827                         f = ast_read(in);
1828 #if 0
1829                         if (f && (f->frametype != AST_FRAME_VOICE))
1830                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1831                         else if (!f || (f->frametype != AST_FRAME_VOICE))
1832                                 printf("Hangup received on %s\n", in->name);
1833 #endif
1834                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1835                                 /* Got hung up */
1836                                 *to=-1;
1837                                 if (f)
1838                                         ast_frfree(f);
1839                                 return NULL;
1840                         }
1841                         if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1842                                 if (option_verbose > 3)
1843                                         ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1844                                 *to=0;
1845                                 ast_frfree(f);
1846                                 return NULL;
1847                         }
1848                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1849                                 if (option_verbose > 3)
1850                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1851                                 *to=0;
1852                                 *digit=f->subclass;
1853                                 ast_frfree(f);
1854                                 return NULL;
1855                         }
1856                         ast_frfree(f);
1857                 }
1858                 if (!*to) {
1859                         if (option_verbose > 2)
1860                                 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1861                         if (qe->parent->autopause) {
1862                                 if (!set_member_paused(qe->parent->name, on, 1)) {
1863                                         if (option_verbose > 2)
1864                                                 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", on, qe->parent->name);
1865                                 } else {
1866                                         if (option_verbose > 2)
1867                                                 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", on, qe->parent->name);
1868                                 }
1869                         }
1870                 }
1871         }
1872
1873         return peer;
1874 }
1875
1876 static int is_our_turn(struct queue_ent *qe)
1877 {
1878         struct queue_ent *ch;
1879         int res;
1880
1881         /* Atomically read the parent head -- does not need a lock */
1882         ch = qe->parent->head;
1883         /* If we are now at the top of the head, break out */
1884         if ((ch == qe) || (qe->parent->autofill)) {
1885                 if (option_debug)
1886                         ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1887                 res = 1;
1888         } else {
1889                 if (option_debug)
1890                         ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1891                 res = 0;
1892         }
1893         return res;
1894 }
1895
1896 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1897 {
1898         int res = 0;
1899
1900         /* This is the holding pen for callers 2 through maxlen */
1901         for (;;) {
1902                 enum queue_member_status stat;
1903
1904                 if (is_our_turn(qe))
1905                         break;
1906
1907                 /* If we have timed out, break out */
1908                 if (qe->expire && (time(NULL) > qe->expire)) {
1909                         *reason = QUEUE_TIMEOUT;
1910                         ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
1911                         break;
1912                 }
1913
1914                 stat = get_member_status(qe->parent, qe->max_penalty);
1915
1916                 /* leave the queue if no agents, if enabled */
1917                 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1918                         *reason = QUEUE_LEAVEEMPTY;
1919                         leave_queue(qe);
1920                         break;
1921                 }
1922
1923                 /* leave the queue if no reachable agents, if enabled */
1924                 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1925                         *reason = QUEUE_LEAVEUNAVAIL;
1926                         leave_queue(qe);
1927                         break;
1928                 }
1929
1930                 /* Make a position announcement, if enabled */
1931                 if (qe->parent->announcefrequency && !ringing)
1932                         res = say_position(qe);
1933                 if (res)
1934                         break;
1935
1936                 /* Make a periodic announcement, if enabled */
1937                 if (qe->parent->periodicannouncefrequency && !ringing)
1938                         res = say_periodic_announcement(qe);
1939
1940                 /* Wait a second before checking again */
1941                 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1942                 if (res)
1943                         break;
1944         }
1945         return res;
1946 }
1947
1948 static int update_queue(struct ast_call_queue *q, struct member *member)
1949 {
1950         struct member *cur;
1951
1952         /* Since a reload could have taken place, we have to traverse the list to
1953                 be sure it's still valid */
1954         ast_mutex_lock(&q->lock);
1955         cur = q->members;
1956         while(cur) {
1957                 if (member == cur) {
1958                         time(&cur->lastcall);
1959                         cur->calls++;
1960                         break;
1961                 }
1962                 cur = cur->next;
1963         }
1964         q->callscompleted++;
1965         ast_mutex_unlock(&q->lock);
1966         return 0;
1967 }
1968
1969 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
1970 {
1971         if (mem->penalty > qe->max_penalty)
1972                 return -1;
1973
1974         switch (q->strategy) {
1975         case QUEUE_STRATEGY_RINGALL:
1976                 /* Everyone equal, except for penalty */
1977                 tmp->metric = mem->penalty * 1000000;
1978                 break;
1979         case QUEUE_STRATEGY_ROUNDROBIN:
1980                 if (!pos) {
1981                         if (!q->wrapped) {
1982                                 /* No more channels, start over */
1983                                 q->rrpos = 0;
1984                         } else {
1985                                 /* Prioritize next entry */
1986                                 q->rrpos++;
1987                         }
1988                         q->wrapped = 0;
1989                 }
1990                 /* Fall through */
1991         case QUEUE_STRATEGY_RRMEMORY:
1992                 if (pos < q->rrpos) {
1993                         tmp->metric = 1000 + pos;
1994                 } else {
1995                         if (pos > q->rrpos)
1996                                 /* Indicate there is another priority */
1997                                 q->wrapped = 1;
1998                         tmp->metric = pos;
1999                 }
2000                 tmp->metric += mem->penalty * 1000000;
2001                 break;
2002         case QUEUE_STRATEGY_RANDOM:
2003                 tmp->metric = rand() % 1000;
2004                 tmp->metric += mem->penalty * 1000000;
2005                 break;
2006         case QUEUE_STRATEGY_FEWESTCALLS:
2007                 tmp->metric = mem->calls;
2008                 tmp->metric += mem->penalty * 1000000;
2009                 break;
2010         case QUEUE_STRATEGY_LEASTRECENT:
2011                 if (!mem->lastcall)
2012                         tmp->metric = 0;
2013                 else
2014                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2015                 tmp->metric += mem->penalty * 1000000;
2016                 break;
2017         default:
2018                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2019                 break;
2020         }
2021         return 0;
2022 }
2023
2024 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
2025 {
2026         struct member *cur;
2027         struct callattempt *outgoing=NULL; /* the queue we are building */
2028         int to;
2029         char restofit[AST_MAX_EXTENSION];
2030         char oldexten[AST_MAX_EXTENSION]="";
2031         char oldcontext[AST_MAX_CONTEXT]="";
2032         char queuename[256]="";
2033         char *newnum;
2034         struct ast_channel *peer;
2035         struct ast_channel *which;
2036         struct callattempt *lpeer;
2037         struct member *member;
2038         int res = 0, bridge = 0;
2039         int numbusies = 0;
2040         int x=0;
2041         char *announce = NULL;
2042         char digit = 0;
2043         time_t callstart;
2044         time_t now = time(NULL);
2045         struct ast_bridge_config bridge_config;
2046         char nondataquality = 1;
2047
2048         memset(&bridge_config, 0, sizeof(bridge_config));
2049         time(&now);
2050                 
2051         for (; options && *options; options++)
2052                 switch (*options) {
2053                 case 't':
2054                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2055                         break;
2056                 case 'T':
2057                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2058                         break;
2059                 case 'w':
2060                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2061                         break;
2062                 case 'W':
2063                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2064                         break;
2065                 case 'd':
2066                         nondataquality = 0;
2067                         break;
2068                 case 'h':
2069                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2070                         break;
2071                 case 'H':
2072                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2073                         break;
2074                 case 'n':
2075                         if ((now - qe->start >= qe->parent->timeout))
2076                                 *go_on = 1;
2077                         break;
2078                 }
2079
2080         /* Hold the lock while we setup the outgoing calls */
2081         if (use_weight) 
2082                 AST_LIST_LOCK(&queues);
2083         ast_mutex_lock(&qe->parent->lock);
2084         if (option_debug)
2085                 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
2086                                                         qe->chan->name);
2087         ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2088         cur = qe->parent->members;
2089         if (!ast_strlen_zero(qe->announce))
2090                 announce = qe->announce;
2091         if (!ast_strlen_zero(announceoverride))
2092                 announce = announceoverride;
2093
2094         for (;cur; cur = cur->next) {
2095                 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2096                 if (!tmp) {
2097                         ast_mutex_unlock(&qe->parent->lock);
2098                         if (use_weight) 
2099                                 AST_LIST_UNLOCK(&queues);
2100                         goto out;
2101                 }
2102                 tmp->stillgoing = -1;
2103                 if (option_debug) {
2104                         if (url)
2105                                 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2106                         else 
2107                                 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
2108                 }
2109
2110                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
2111                 tmp->oldstatus = cur->status;
2112                 tmp->lastcall = cur->lastcall;
2113                 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2114                 /* If we're dialing by extension, look at the extension to know what to dial */
2115                 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
2116                         newnum++;
2117                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
2118                         snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
2119                         if (option_debug)
2120                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
2121                 }
2122                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2123                    just calculate their metric for the appropriate strategy */
2124                 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2125                         /* Put them in the list of outgoing thingies...  We're ready now. 
2126                            XXX If we're forcibly removed, these outgoing calls won't get
2127                            hung up XXX */
2128                         tmp->q_next = outgoing;
2129                         outgoing = tmp;         
2130                         /* If this line is up, don't try anybody else */
2131                         if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2132                                 break;
2133                 } else {
2134                         free(tmp);
2135                 }
2136         }
2137         to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2138         ring_one(qe, outgoing, &numbusies);
2139         ast_mutex_unlock(&qe->parent->lock);
2140         if (use_weight) 
2141                 AST_LIST_UNLOCK(&queues);
2142         lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
2143         ast_mutex_lock(&qe->parent->lock);
2144         if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2145                 store_next(qe, outgoing);
2146         }
2147         ast_mutex_unlock(&qe->parent->lock);
2148         peer = lpeer ? lpeer->chan : NULL;
2149         if (!peer) {
2150                 if (to) {
2151                         /* Must gotten hung up */
2152                         res = -1;
2153                 } else {
2154                         res = digit;
2155                 }
2156                 if (option_debug)
2157                         ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2158         } else { /* peer is valid */
2159                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
2160                    we will always return with -1 so that it is hung up properly after the 
2161                    conversation.  */
2162                 qe->handled++;
2163                 if (!strcmp(qe->chan->tech->type, "Zap"))
2164                         ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2165                 if (!strcmp(peer->tech->type, "Zap"))
2166                         ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2167                 /* Update parameters for the queue */
2168                 recalc_holdtime(qe);
2169                 member = lpeer->member;
2170                 hangupcalls(outgoing, peer);
2171                 outgoing = NULL;
2172                 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2173                         int res2;
2174                         res2 = ast_autoservice_start(qe->chan);
2175                         if (!res2) {
2176                                 if (qe->parent->memberdelay) {
2177                                         ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2178                                         res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2179                                 }
2180                                 if (!res2 && announce) {
2181                                         if (play_file(peer, announce))
2182                                                 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2183                                 }
2184                                 if (!res2 && qe->parent->reportholdtime) {
2185                                         if (!play_file(peer, qe->parent->sound_reporthold)) {
2186                                                 int holdtime;
2187
2188                                                 time(&now);
2189                                                 holdtime = abs((now - qe->start) / 60);
2190                                                 if (holdtime < 2) {
2191                                                         play_file(peer, qe->parent->sound_lessthan);
2192                                                         ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2193                                                 } else 
2194                                                         ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2195                                                 play_file(peer, qe->parent->sound_minutes);
2196                                         }
2197                                 }
2198                         }
2199                         res2 |= ast_autoservice_stop(qe->chan);
2200                         if (peer->_softhangup) {
2201                                 /* Agent must have hung up */
2202                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
2203                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
2204                                 record_abandoned(qe);
2205                                 if (qe->parent->eventwhencalled) {
2206                                         manager_event(EVENT_FLAG_AGENT, "AgentDump",
2207                                                       "Queue: %s\r\n"
2208                                                       "Uniqueid: %s\r\n"
2209                                                       "Channel: %s\r\n"
2210                                                       "Member: %s\r\n",
2211                                                       queuename, qe->chan->uniqueid, peer->name, member->interface);
2212                                 }
2213                                 ast_hangup(peer);
2214                                 goto out;
2215                         } else if (res2) {
2216                                 /* Caller must have hung up just before being connected*/
2217                                 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2218                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2219                                 record_abandoned(qe);
2220                                 ast_hangup(peer);
2221                                 return -1;
2222                         }
2223                 }
2224                 /* Stop music on hold */
2225                 ast_moh_stop(qe->chan);
2226                 /* If appropriate, log that we have a destination channel */
2227                 if (qe->chan->cdr)
2228                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2229                 /* Make sure channels are compatible */
2230                 res = ast_channel_make_compatible(qe->chan, peer);
2231                 if (res < 0) {
2232                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2233                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2234                         record_abandoned(qe);
2235                         ast_hangup(peer);
2236                         return -1;
2237                 }
2238                 /* Begin Monitoring */
2239                 if (qe->parent->monfmt && *qe->parent->monfmt) {
2240                         const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2241                         if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2242                                 which = qe->chan;
2243                         else
2244                                 which = peer;
2245                         if (monitorfilename)
2246                                 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2247                         else if (qe->chan->cdr) 
2248                                 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2249                         else {
2250                                 /* Last ditch effort -- no CDR, make up something */
2251                                 char tmpid[256];
2252                                 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
2253                                 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2254                         }
2255                         if (qe->parent->monjoin)
2256                                 ast_monitor_setjoinfiles(which, 1);
2257                 }
2258                 /* Drop out of the queue at this point, to prepare for next caller */
2259                 leave_queue(qe);                        
2260                 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2261                         if (option_debug)
2262                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2263                         ast_channel_sendurl(peer, url);
2264                 }
2265                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
2266                 if (qe->parent->eventwhencalled)
2267                         manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2268                                       "Queue: %s\r\n"
2269                                       "Uniqueid: %s\r\n"
2270                                       "Channel: %s\r\n"
2271                                       "Member: %s\r\n"
2272                                       "Holdtime: %ld\r\n",
2273                                       queuename, qe->chan->uniqueid, peer->name, member->interface,
2274                                       (long)time(NULL) - qe->start);
2275                 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2276                 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2277                 time(&callstart);
2278
2279                 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2280
2281                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2282                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
2283                 } else if (qe->chan->_softhangup) {
2284                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2285                                       (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2286                         if (qe->parent->eventwhencalled)
2287                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2288                                               "Queue: %s\r\n"
2289                                               "Uniqueid: %s\r\n"
2290                                               "Channel: %s\r\n"
2291                                               "Member: %s\r\n"
2292                                               "HoldTime: %ld\r\n"
2293                                               "TalkTime: %ld\r\n"
2294                                               "Reason: caller\r\n",
2295                                               queuename, qe->chan->uniqueid, peer->name, member->interface,
2296                                               (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2297                 } else {
2298                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2299                         if (qe->parent->eventwhencalled)
2300                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2301                                               "Queue: %s\r\n"
2302                                               "Uniqueid: %s\r\n"
2303                                               "Channel: %s\r\n"
2304                                               "HoldTime: %ld\r\n"
2305                                               "TalkTime: %ld\r\n"
2306                                               "Reason: agent\r\n",
2307                                               queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2308                                               (long)(time(NULL) - callstart));
2309                 }
2310
2311                 if(bridge != AST_PBX_NO_HANGUP_PEER)
2312                         ast_hangup(peer);
2313                 update_queue(qe->parent, member);
2314                 if (bridge == 0) 
2315                         res = 1; /* JDG: bridge successfully, leave app_queue */
2316                 else 
2317                         res = bridge; /* bridge error, stay in the queue */
2318         }
2319 out:
2320         hangupcalls(outgoing, NULL);
2321         return res;
2322 }
2323
2324 static int wait_a_bit(struct queue_ent *qe)
2325 {
2326         /* Don't need to hold the lock while we setup the outgoing calls */
2327         int retrywait = qe->parent->retry * 1000;
2328
2329         return ast_waitfordigit(qe->chan, retrywait);
2330 }
2331
2332 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2333 {
2334         struct member *mem;
2335
2336         if (q)
2337                 for (mem = q->members; mem; mem = mem->next)
2338                         if (!strcasecmp(interface, mem->interface))
2339                                 return mem;
2340
2341         return NULL;
2342 }
2343
2344
2345 /* Dump all members in a specific queue to the database
2346  *
2347  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2348  *
2349  */
2350 static void dump_queue_members(struct ast_call_queue *pm_queue)
2351 {
2352         struct member *cur_member;
2353         char value[PM_MAX_LEN];
2354         int value_len = 0;
2355         int res;
2356
2357         memset(value, 0, sizeof(value));
2358
2359         if (!pm_queue)
2360                 return;
2361
2362         for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2363                 if (!cur_member->dynamic)
2364                         continue;
2365
2366                 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2367                                cur_member->interface, cur_member->penalty, cur_member->paused,
2368                                cur_member->next ? "|" : "");
2369                 if (res != strlen(value + value_len)) {
2370                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2371                         break;
2372                 }
2373                 value_len += res;
2374         }
2375         
2376         if (value_len && !cur_member) {
2377                 if (ast_db_put(pm_family, pm_queue->name, value))
2378                         ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2379         } else
2380                 /* Delete the entry if the queue is empty or there is an error */
2381                 ast_db_del(pm_family, pm_queue->name);
2382 }
2383
2384 static int remove_from_queue(char *queuename, char *interface)
2385 {
2386         struct ast_call_queue *q;
2387         struct member *last_member, *look;
2388         int res = RES_NOSUCHQUEUE;
2389
2390         AST_LIST_LOCK(&queues);
2391         AST_LIST_TRAVERSE(&queues, q, list) {
2392                 ast_mutex_lock(&q->lock);
2393                 if (!strcmp(q->name, queuename)) {
2394                         if ((last_member = interface_exists(q, interface))) {
2395                                 if ((look = q->members) == last_member) {
2396                                         q->members = last_member->next;
2397                                 } else {
2398                                         while (look != NULL) {
2399                                                 if (look->next == last_member) {
2400                                                         look->next = last_member->next;
2401                                                         break;
2402                                                 } else {
2403                                                          look = look->next;
2404                                                 }
2405                                         }
2406                                 }
2407                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2408                                                 "Queue: %s\r\n"
2409                                                 "Location: %s\r\n",
2410                                         q->name, last_member->interface);
2411                                 free(last_member);
2412
2413                                 if (queue_persistent_members)
2414                                     dump_queue_members(q);
2415
2416                                 res = RES_OKAY;
2417                         } else {
2418                                 res = RES_EXISTS;
2419                         }
2420                         ast_mutex_unlock(&q->lock);
2421                         break;
2422                 }
2423                 ast_mutex_unlock(&q->lock);
2424         }
2425         AST_LIST_UNLOCK(&queues);
2426         return res;
2427 }
2428
2429 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2430 {
2431         struct ast_call_queue *q;
2432         struct member *new_member;
2433         int res = RES_NOSUCHQUEUE;
2434
2435         /* \note Ensure the appropriate realtime queue is loaded.  Note that this
2436          * short-circuits if the queue is already in memory. */
2437         q = load_realtime_queue(queuename);
2438
2439         AST_LIST_LOCK(&queues);
2440
2441         if (q) {
2442                 ast_mutex_lock(&q->lock);
2443                 if (interface_exists(q, interface) == NULL) {
2444                         new_member = create_queue_member(interface, penalty, paused);
2445
2446                         if (new_member != NULL) {
2447                                 new_member->dynamic = 1;
2448                                 new_member->next = q->members;
2449                                 q->members = new_member;
2450                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2451                                         "Queue: %s\r\n"
2452                                         "Location: %s\r\n"
2453                                         "Membership: %s\r\n"
2454                                         "Penalty: %d\r\n"
2455                                         "CallsTaken: %d\r\n"
2456                                         "LastCall: %d\r\n"
2457                                         "Status: %d\r\n"
2458                                         "Paused: %d\r\n",
2459                                 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2460                                 new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
2461                                         
2462                                 if (dump)
2463                                         dump_queue_members(q);
2464
2465                                 res = RES_OKAY;
2466                         } else {
2467                                 res = RES_OUTOFMEMORY;
2468                         }
2469                 } else {
2470                         res = RES_EXISTS;
2471                 }
2472                 ast_mutex_unlock(&q->lock);
2473         }
2474         AST_LIST_UNLOCK(&queues);
2475         return res;
2476 }
2477
2478 static int set_member_paused(char *queuename, char *interface, int paused)
2479 {
2480         int found = 0;
2481         struct ast_call_queue *q;
2482         struct member *mem;
2483
2484         /* Special event for when all queues are paused - individual events still generated */
2485
2486         if (ast_strlen_zero(queuename))
2487                 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2488
2489         AST_LIST_LOCK(&queues);
2490         AST_LIST_TRAVERSE(&queues, q, list) {
2491                 ast_mutex_lock(&q->lock);
2492                 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
2493                         if ((mem = interface_exists(q, interface))) {
2494                                 found++;
2495                                 if (mem->paused == paused)
2496                                         ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2497                                 mem->paused = paused;
2498
2499                                 if (queue_persistent_members)
2500                                     dump_queue_members(q);
2501
2502                                 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2503
2504                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2505                                         "Queue: %s\r\n"
2506                                         "Location: %s\r\n"
2507                                         "Paused: %d\r\n",
2508                                                 q->name, mem->interface, paused);
2509                         }
2510                 }
2511                 ast_mutex_unlock(&q->lock);
2512         }
2513         AST_LIST_UNLOCK(&queues);
2514
2515         if (found)
2516                 return RESULT_SUCCESS;
2517         else
2518                 return RESULT_FAILURE;
2519 }
2520
2521 /* Reload dynamic queue members persisted into the astdb */
2522 static void reload_queue_members(void)
2523 {
2524         char *cur_ptr;  
2525         char *queue_name;
2526         char *member;
2527         char *interface;
2528         char *penalty_tok;
2529         int penalty = 0;
2530         char *paused_tok;
2531         int paused = 0;
2532         struct ast_db_entry *db_tree;
2533         struct ast_db_entry *entry;
2534         struct ast_call_queue *cur_queue;
2535         char queue_data[PM_MAX_LEN];
2536
2537         AST_LIST_LOCK(&queues);
2538
2539         /* Each key in 'pm_family' is the name of a queue */
2540         db_tree = ast_db_gettree(pm_family, NULL);
2541         for (entry = db_tree; entry; entry = entry->next) {
2542
2543                 queue_name = entry->key + strlen(pm_family) + 2;
2544
2545                 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
2546                         ast_mutex_lock(&cur_queue->lock);
2547                         if (!strcmp(queue_name, cur_queue->name))
2548                                 break;
2549                         ast_mutex_unlock(&cur_queue->lock);
2550                 }
2551
2552                 if (!cur_queue) {
2553                         /* If the queue no longer exists, remove it from the
2554                          * database */
2555                         ast_db_del(pm_family, queue_name);
2556                         continue;
2557                 } else
2558                         ast_mutex_unlock(&cur_queue->lock);
2559
2560                 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2561                         continue;
2562
2563                 cur_ptr = queue_data;
2564                 while ((member = strsep(&cur_ptr, "|"))) {
2565                         if (ast_strlen_zero(member))
2566                                 continue;
2567
2568                         interface = strsep(&member, ";");
2569                         penalty_tok = strsep(&member, ";");
2570                         paused_tok = strsep(&member, ";");
2571
2572                         if (!penalty_tok) {
2573                                 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
2574                                 break;
2575                         }
2576                         penalty = strtol(penalty_tok, NULL, 10);
2577                         if (errno == ERANGE) {
2578                                 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2579                                 break;
2580                         }
2581                         
2582                         if (!paused_tok) {
2583                                 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2584                                 break;
2585                         }
2586                         paused = strtol(paused_tok, NULL, 10);
2587                         if ((errno == ERANGE) || paused < 0 || paused > 1) {
2588                                 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2589                                 break;
2590                         }
2591
2592                         if (option_debug)
2593                                 ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
2594                         
2595                         if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2596                                 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2597                                 break;
2598                         }
2599                 }
2600         }
2601
2602         AST_LIST_UNLOCK(&queues);
2603         if (db_tree) {
2604                 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
2605                 ast_db_freetree(db_tree);
2606         }
2607 }
2608
2609 static int pqm_exec(struct ast_channel *chan, void *data)
2610 {
2611         struct localuser *lu;
2612         char *parse;
2613         int priority_jump = 0;
2614         AST_DECLARE_APP_ARGS(args,
2615                 AST_APP_ARG(queuename);
2616                 AST_APP_ARG(interface);
2617                 AST_APP_ARG(options);
2618         );
2619
2620         if (ast_strlen_zero(data)) {
2621                 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2622                 return -1;
2623         }
2624
2625         if (!(parse = ast_strdupa(data)))
2626                 return -1;
2627
2628         AST_STANDARD_APP_ARGS(args, parse);
2629
2630         LOCAL_USER_ADD(lu);
2631
2632         if (args.options) {
2633                 if (strchr(args.options, 'j'))
2634                         priority_jump = 1;
2635         }
2636
2637         if (ast_strlen_zero(args.interface)) {
2638                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2639                 LOCAL_USER_REMOVE(lu);
2640                 return -1;
2641         }
2642
2643         if (set_member_paused(args.queuename, args.interface, 1)) {
2644                 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
2645                 if (priority_jump || ast_opt_priority_jumping) {
2646                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2647                                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2648                                 LOCAL_USER_REMOVE(lu);
2649                                 return 0;
2650                         }
2651                 }
2652                 LOCAL_USER_REMOVE(lu);
2653                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2654                 return -1;
2655         }
2656
2657         LOCAL_USER_REMOVE(lu);
2658         pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2659         return 0;
2660 }
2661
2662 static int upqm_exec(struct ast_channel *chan, void *data)
2663 {
2664         struct localuser *lu;
2665         char *parse;
2666         int priority_jump = 0;
2667         AST_DECLARE_APP_ARGS(args,
2668                 AST_APP_ARG(queuename);
2669                 AST_APP_ARG(interface);
2670                 AST_APP_ARG(options);
2671         );
2672
2673         if (ast_strlen_zero(data)) {
2674                 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2675                 return -1;
2676         }
2677
2678         if (!(parse = ast_strdupa(data))) 
2679                 return -1;      
2680
2681         AST_STANDARD_APP_ARGS(args, parse);
2682
2683         LOCAL_USER_ADD(lu);
2684
2685         if (args.options) {
2686                 if (strchr(args.options, 'j'))
2687                         priority_jump = 1;
2688         }
2689
2690         if (ast_strlen_zero(args.interface)) {
2691                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2692                 LOCAL_USER_REMOVE(lu);
2693                 return -1;
2694         }
2695
2696         if (set_member_paused(args.queuename, args.interface, 0)) {
2697                 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
2698                 if (priority_jump || ast_opt_priority_jumping) {
2699                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2700                                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2701                                 LOCAL_USER_REMOVE(lu);
2702                                 return 0;
2703                         }
2704                 }
2705                 LOCAL_USER_REMOVE(lu);
2706                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2707                 return -1;
2708         }
2709
2710         LOCAL_USER_REMOVE(lu);
2711         pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2712         return 0;
2713 }
2714
2715 static int rqm_exec(struct ast_channel *chan, void *data)
2716 {
2717         int res=-1;
2718         struct localuser *lu;
2719         char *parse, *temppos = NULL;
2720         int priority_jump = 0;
2721         AST_DECLARE_APP_ARGS(args,
2722                 AST_APP_ARG(queuename);
2723                 AST_APP_ARG(interface);
2724                 AST_APP_ARG(options);
2725         );
2726
2727
2728         if (ast_strlen_zero(data)) {
2729                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2730                 return -1;
2731         }
2732
2733         if (!(parse = ast_strdupa(data)))
2734                 return -1;
2735
2736         AST_STANDARD_APP_ARGS(args, parse);
2737
2738         LOCAL_USER_ADD(lu);
2739
2740         if (ast_strlen_zero(args.interface)) {
2741                 args.interface = ast_strdupa(chan->name);
2742                 temppos = strrchr(args.interface, '-');
2743                 if (temppos)
2744                         *temppos = '\0';
2745         }
2746
2747         if (args.options) {
2748                 if (strchr(args.options, 'j'))
2749                         priority_jump = 1;
2750         }
2751
2752         switch (remove_from_queue(args.queuename, args.interface)) {
2753         case RES_OKAY:
2754                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2755                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
2756                 res = 0;
2757                 break;
2758         case RES_EXISTS:
2759                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
2760                 if (priority_jump || ast_opt_priority_jumping) 
2761                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2762                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
2763                 res = 0;
2764                 break;
2765         case RES_NOSUCHQUEUE:
2766                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
2767                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
2768                 res = 0;
2769                 break;
2770         case RES_OUTOFMEMORY:
2771                 ast_log(LOG_ERROR, "Out of memory\n");
2772                 break;
2773         }
2774
2775         LOCAL_USER_REMOVE(lu);
2776         return res;
2777 }
2778
2779 static int aqm_exec(struct ast_channel *chan, void *data)
2780 {
2781         int res=-1;
2782         struct localuser *lu;
2783         char *parse, *temppos = NULL;
2784         int priority_jump = 0;
2785         AST_DECLARE_APP_ARGS(args,
2786                 AST_APP_ARG(queuename);
2787                 AST_APP_ARG(interface);
2788                 AST_APP_ARG(penalty);
2789                 AST_APP_ARG(options);
2790         );
2791         int penalty = 0;
2792
2793         if (ast_strlen_zero(data)) {
2794                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2795                 return -1;
2796         }
2797
2798         if (!(parse = ast_strdupa(data)))
2799                 return -1;
2800
2801         AST_STANDARD_APP_ARGS(args, parse);
2802
2803         LOCAL_USER_ADD(lu);
2804
2805         if (ast_strlen_zero(args.interface)) {
2806                 args.interface = ast_strdupa(chan->name);
2807                 temppos = strrchr(args.interface, '-');
2808                 if (temppos)
2809                         *temppos = '\0';
2810         }
2811
2812         if (!ast_strlen_zero(args.penalty)) {
2813                 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
2814                         ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
2815                         penalty = 0;
2816                 }
2817         }
2818         
2819         if (args.options) {
2820                 if (strchr(args.options, 'j'))
2821                         priority_jump = 1;
2822         }
2823
2824
2825         switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2826         case RES_OKAY:
2827                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2828                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
2829                 res = 0;
2830                 break;
2831         case RES_EXISTS:
2832                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
2833                 if (priority_jump || ast_opt_priority_jumping) 
2834                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2835                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
2836                 res = 0;
2837                 break;
2838         case RES_NOSUCHQUEUE:
2839                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
2840                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
2841                 res = 0;
2842                 break;
2843         case RES_OUTOFMEMORY:
2844                 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2845                 break;
2846         }
2847
2848         LOCAL_USER_REMOVE(lu);
2849         return res;
2850 }
2851
2852 static int queue_exec(struct ast_channel *chan, void *data)
2853 {
2854         int res=-1;
2855         int ringing=0;
2856         struct localuser *lu;
2857         const char *user_priority;
2858         const char *max_penalty_str;
2859         int prio;
2860         int max_penalty;
2861         enum queue_result reason = QUEUE_UNKNOWN;
2862
2863         /* whether to exit Queue application after the timeout hits */
2864         int go_on = 0;
2865
2866         char *parse;
2867         AST_DECLARE_APP_ARGS(args,
2868                  AST_APP_ARG(queuename);
2869                  AST_APP_ARG(options);
2870                  AST_APP_ARG(url);
2871                  AST_APP_ARG(announceoverride);
2872                  AST_APP_ARG(queuetimeoutstr);
2873         );
2874         
2875         /* Our queue entry */
2876         struct queue_ent qe;
2877         
2878         if (ast_strlen_zero(data)) {
2879                 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2880                 return -1;
2881         }
2882         
2883         parse = ast_strdupa(data);
2884         if (!parse) {
2885                 ast_log(LOG_ERROR, "Out of memory!\n");
2886                 return -1;
2887         }
2888         AST_STANDARD_APP_ARGS(args, parse);
2889
2890         LOCAL_USER_ADD(lu);
2891
2892         /* Setup our queue entry */
2893         memset(&qe, 0, sizeof(qe));
2894         qe.start = time(NULL);
2895
2896         /* set the expire time based on the supplied timeout; */
2897         if (args.queuetimeoutstr)
2898                 qe.expire = qe.start + atoi(args.queuetimeoutstr);
2899         else
2900                 qe.expire = 0;
2901
2902         /* Get the priority from the variable ${QUEUE_PRIO} */
2903         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2904         if (user_priority) {
2905                 if (sscanf(user_priority, "%d", &prio) == 1) {
2906                         if (option_debug)
2907                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2908                                         chan->name, prio);
2909                 } else {
2910                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2911                                 user_priority, chan->name);
2912                         prio = 0;
2913                 }
2914         } else {
2915                 if (option_debug > 2)
2916                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2917                 prio = 0;
2918         }
2919
2920         /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
2921         if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
2922                 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
2923                         if (option_debug)
2924                                 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
2925                                         chan->name, max_penalty);
2926                 } else {
2927      &n