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