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