Add reporting of actual hold time (bug #2564)
[asterisk/asterisk.git] / apps / app_queue.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * True call queues with optional send URL on answer
5  * 
6  * Copyright (C) 1999-2004, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
11  *
12  * These features added by David C. Troy <dave@toad.net>:
13  *    - Per-queue holdtime calculation
14  *    - Estimated holdtime announcement
15  *    - Position announcement
16  *    - Abandoned/completed call counters
17  *    - Failout timer passed as optional app parameter
18  *    - Optional monitoring of calls, started when call is answered
19  *
20  * Patch Version 1.07 2003-12-24 01
21  *
22  * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
23  * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
24  *
25  * Fixed ot work with CVS as of 2004-02-25 and released as 1.07a
26  * by Matthew Enger <m.enger@xi.com.au>
27  *
28  * This program is free software, distributed under the terms of
29  * the GNU General Public License
30  */
31
32 #include <asterisk/lock.h>
33 #include <asterisk/file.h>
34 #include <asterisk/logger.h>
35 #include <asterisk/channel.h>
36 #include <asterisk/pbx.h>
37 #include <asterisk/options.h>
38 #include <asterisk/module.h>
39 #include <asterisk/translate.h>
40 #include <asterisk/say.h>
41 #include <asterisk/features.h>
42 #include <asterisk/musiconhold.h>
43 #include <asterisk/cli.h>
44 #include <asterisk/manager.h>
45 #include <asterisk/config.h>
46 #include <asterisk/monitor.h>
47 #include <asterisk/utils.h>
48 #include <stdlib.h>
49 #include <errno.h>
50 #include <unistd.h>
51 #include <string.h>
52 #include <stdlib.h>
53 #include <stdio.h>
54 #include <sys/time.h>
55 #include <sys/signal.h>
56 #include <netinet/in.h>
57
58 #include "../astconf.h"
59
60 #define QUEUE_STRATEGY_RINGALL          0
61 #define QUEUE_STRATEGY_ROUNDROBIN       1
62 #define QUEUE_STRATEGY_LEASTRECENT      2
63 #define QUEUE_STRATEGY_FEWESTCALLS      3
64 #define QUEUE_STRATEGY_RANDOM           4
65 #define QUEUE_STRATEGY_RRMEMORY         5
66
67 static struct strategy {
68         int strategy;
69         char *name;
70 } strategies[] = {
71         { QUEUE_STRATEGY_RINGALL, "ringall" },
72         { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
73         { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
74         { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
75         { QUEUE_STRATEGY_RANDOM, "random" },
76         { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
77 };
78
79 #define DEFAULT_RETRY           5
80 #define DEFAULT_TIMEOUT         15
81 #define RECHECK                         1               /* Recheck every second to see we we're at the top yet */
82
83 #define RES_OKAY        0                       /* Action completed */
84 #define RES_EXISTS      (-1)            /* Entry already exists */
85 #define RES_OUTOFMEMORY (-2)    /* Out of memory */
86 #define RES_NOSUCHQUEUE (-3)    /* No such queue */
87
88 static char *tdesc = "True Call Queueing";
89
90 static char *app = "Queue";
91
92 static char *synopsis = "Queue a call for a call queue";
93
94 static char *descrip =
95 "  Queue(queuename[|options[|URL][|announceoverride][|timeout]]):\n"
96 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
97 "  This application returns -1 if the originating channel hangs up, or if the\n"
98 "call is bridged and  either of the parties in the bridge terminate the call.\n"
99 "Returns 0 if the queue is full, nonexistant, or has no members.\n"
100 "The option string may contain zero or more of the following characters:\n"
101 "      't' -- allow the called user transfer the calling user\n"
102 "      'T' -- to allow the calling user to transfer the call.\n"
103 "      'd' -- data-quality (modem) call (minimum delay).\n"
104 "      'h' -- allow callee to hang up by hitting *.\n"
105 "      'H' -- allow caller to hang up by hitting *.\n"
106 "      'n' -- no retries on the timeout; will exit this application and go to the next step.\n"
107 "      'r' -- ring instead of playing MOH\n"
108 "  In addition to transferring the call, a call may be parked and then picked\n"
109 "up by another user.\n"
110 "  The optional URL will be sent to the called party if the channel supports\n"
111 "it.\n"
112 "  The timeout will cause the queue to fail out after a specified number of\n"
113 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n";
114
115 // [PHM 06/26/03]
116 static char *app_aqm = "AddQueueMember" ;
117 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
118 static char *app_aqm_descrip =
119 "   AddQueueMember(queuename[|interface[|penalty]]):\n"
120 "Dynamically adds interface to an existing queue.\n"
121 "If the interface is already in the queue and there exists an n+101 priority\n"
122 "then it will then jump to this priority.  Otherwise it will return an error\n"
123 "Returns -1 if there is an error.\n"
124 "Example: AddQueueMember(techsupport|SIP/3000)\n"
125 "";
126
127 static char *app_rqm = "RemoveQueueMember" ;
128 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
129 static char *app_rqm_descrip =
130 "   RemoveQueueMember(queuename[|interface]):\n"
131 "Dynamically removes interface to an existing queue\n"
132 "If the interface is NOT in the queue and there exists an n+101 priority\n"
133 "then it will then jump to this priority.  Otherwise it will return an error\n"
134 "Returns -1 if there is an error.\n"
135 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
136 "";
137
138 /* We define a customer "local user" structure because we
139    use it not only for keeping track of what is in use but
140    also for keeping track of who we're dialing. */
141
142 struct localuser {
143         struct ast_channel *chan;
144         char numsubst[256];
145         char tech[40];
146         int stillgoing;
147         int metric;
148         int allowredirect_in;
149         int allowredirect_out;
150         int ringbackonly;
151         int musiconhold;
152         int dataquality;
153         int allowdisconnect_in;
154         int allowdisconnect_out;
155         time_t lastcall;
156         struct member *member;
157         struct localuser *next;
158 };
159
160 LOCAL_USER_DECL;
161
162 struct queue_ent {
163         struct ast_call_queue *parent;  /* What queue is our parent */
164         char moh[80];                   /* Name of musiconhold to be used */
165         char announce[80];              /* Announcement to play for member when call is answered */
166         char context[80];               /* Context when user exits queue */
167         int pos;                                        /* Where we are in the queue */
168         int prio;                                       /* Our priority */
169         int last_pos_said;              /* Last position we told the user */
170         time_t last_pos;                /* Last time we told the user their position */
171         int opos;                       /* Where we started in the queue */
172         int handled;                    /* Whether our call was handled */
173         time_t start;                   /* When we started holding */
174         int queuetimeout;               /* How many seconds before timing out of queue */
175         struct ast_channel *chan;       /* Our channel */
176         struct queue_ent *next;         /* The next queue entry */
177 };
178
179 struct member {
180         char tech[80];                          /* Technology */
181         char loc[256];                          /* Location */
182         int penalty;                            /* Are we a last resort? */
183         int calls;                                      /* Number of calls serviced by this member */
184         int dynamic;                            /* Are we dynamically added? */
185         time_t lastcall;                        /* When last successful call was hungup */
186         struct member *next;            /* Next member */
187 };
188
189 struct ast_call_queue {
190         ast_mutex_t     lock;   
191         char name[80];                  /* Name of the queue */
192         char moh[80];                   /* Name of musiconhold to be used */
193         char announce[80];              /* Announcement to play when call is answered */
194         char context[80];               /* Context for this queue */
195         int strategy;                   /* Queueing strategy */
196         int announcefrequency;          /* How often to announce their position */
197         int roundingseconds;            /* How many seconds do we round to? */
198         int announceholdtime;           /* When to announce holdtime: 0 = never, -1 = every announcement, 1 = only once */
199         int holdtime;                   /* Current avg holdtime for this queue, based on recursive boxcar filter */
200         int callscompleted;             /* Number of queue calls completed */
201         int callsabandoned;             /* Number of queue calls abandoned */
202         int servicelevel;               /* seconds setting for servicelevel*/
203         int callscompletedinsl;         /* Number of queue calls answererd with servicelevel*/
204         char monfmt[8];                 /* Format to use when recording calls */
205         int monjoin;                    /* Should we join the two files when we are done with the call */
206         char sound_next[80];            /* Sound file: "Your call is now first in line" (def. queue-youarenext) */
207         char sound_thereare[80];        /* Sound file: "There are currently" (def. queue-thereare) */
208         char sound_calls[80];           /* Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
209         char sound_holdtime[80];        /* Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
210         char sound_minutes[80];         /* Sound file: "minutes." (def. queue-minutes) */
211         char sound_lessthan[80];        /* Sound file: "less-than" (def. queue-lessthan) */
212         char sound_seconds[80];         /* Sound file: "seconds." (def. queue-seconds) */
213         char sound_thanks[80];          /* Sound file: "Thank you for your patience." (def. queue-thankyou) */
214         char sound_reporthold[80];      /* Sound file: "Hold time" (def. queue-reporthold) */
215
216         int count;                      /* How many entries are in the queue */
217         int maxlen;                     /* Max number of entries in queue */
218         int wrapuptime;         /* Wrapup Time */
219
220         int dead;                       /* Whether this queue is dead or not */
221         int retry;                      /* Retry calling everyone after this amount of time */
222         int timeout;                    /* How long to wait for an answer */
223         
224         /* Queue strategy things */
225         
226         int rrpos;                      /* Round Robin - position */
227         int wrapped;                    /* Round Robin - wrapped around? */
228         int joinempty;                  /* Do we care if the queue has no members? */
229         int eventwhencalled;                    /* Generate an event when the agent is called (before pickup) */
230         int leavewhenempty;             /* If all agents leave the queue, remove callers from the queue */
231         int reportholdtime;             /* Should we report caller hold time to member? */
232
233         struct member *members;         /* Member channels to be tried */
234         struct queue_ent *head;         /* Start of the actual queue */
235         struct ast_call_queue *next;    /* Next call queue */
236 };
237
238 static struct ast_call_queue *queues = NULL;
239 AST_MUTEX_DEFINE_STATIC(qlock);
240
241 static char *int2strat(int strategy)
242 {
243         int x;
244         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
245                 if (strategy == strategies[x].strategy)
246                         return strategies[x].name;
247         }
248         return "<unknown>";
249 }
250
251 static int strat2int(char *strategy)
252 {
253         int x;
254         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
255                 if (!strcasecmp(strategy, strategies[x].name))
256                         return strategies[x].strategy;
257         }
258         return -1;
259 }
260
261 /* Insert the 'new' entry after the 'prev' entry of queue 'q' */
262 static inline void insert_entry(struct ast_call_queue *q, 
263                                         struct queue_ent *prev, struct queue_ent *new, int *pos)
264 {
265         struct queue_ent *cur;
266
267         if (!q || !new)
268                 return;
269         if (prev) {
270                 cur = prev->next;
271                 prev->next = new;
272         } else {
273                 cur = q->head;
274                 q->head = new;
275         }
276         new->next = cur;
277         new->parent = q;
278         new->pos = ++(*pos);
279         new->opos = *pos;
280 }
281
282 static int join_queue(char *queuename, struct queue_ent *qe)
283 {
284         struct ast_call_queue *q;
285         struct queue_ent *cur, *prev = NULL;
286         int res = -1;
287         int pos = 0;
288         int inserted = 0;
289
290         ast_mutex_lock(&qlock);
291         for (q = queues; q; q = q->next) {
292                 if (!strcasecmp(q->name, queuename)) {
293                         /* This is our one */
294                         ast_mutex_lock(&q->lock);
295                         if ((q->members || q->joinempty) && (!q->maxlen || (q->count < q->maxlen))) {
296                                 /* There's space for us, put us at the right position inside
297                                  * the queue. 
298                                  * Take into account the priority of the calling user */
299                                 inserted = 0;
300                                 prev = NULL;
301                                 cur = q->head;
302                                 while(cur) {
303                                         /* We have higher priority than the current user, enter
304                                          * before him, after all the other users with priority
305                                          * higher or equal to our priority. */
306                                         if ((!inserted) && (qe->prio > cur->prio)) {
307                                                 insert_entry(q, prev, qe, &pos);
308                                                 inserted = 1;
309                                         }
310                                         cur->pos = ++pos;
311                                         prev = cur;
312                                         cur = cur->next;
313                                 }
314                                 /* No luck, join at the end of the queue */
315                                 if (!inserted)
316                                         insert_entry(q, prev, qe, &pos);
317                                 strncpy(qe->moh, q->moh, sizeof(qe->moh) - 1);
318                                 strncpy(qe->announce, q->announce, sizeof(qe->announce) - 1);
319                                 strncpy(qe->context, q->context, sizeof(qe->context) - 1);
320                                 q->count++;
321                                 res = 0;
322                                 manager_event(EVENT_FLAG_CALL, "Join", 
323                                         "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
324                                         qe->chan->name, 
325                                         qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
326                                         qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
327                                         q->name, qe->pos, q->count );
328 #if 0
329 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
330 #endif
331                         }
332                         ast_mutex_unlock(&q->lock);
333                         break;
334                 }
335         }
336         ast_mutex_unlock(&qlock);
337         return res;
338 }
339
340 static void free_members(struct ast_call_queue *q, int all)
341 {
342         /* Free non-dynamic members */
343         struct member *curm, *next, *prev;
344         curm = q->members;
345         prev = NULL;
346         while(curm) {
347                 next = curm->next;
348                 if (all || !curm->dynamic) {
349                         if (prev)
350                                 prev->next = next;
351                         else
352                                 q->members = next;
353                         free(curm);
354                 } else 
355                         prev = curm;
356                 curm = next;
357         }
358 }
359
360 static void destroy_queue(struct ast_call_queue *q)
361 {
362         struct ast_call_queue *cur, *prev = NULL;
363         ast_mutex_lock(&qlock);
364         for (cur = queues; cur; cur = cur->next) {
365                 if (cur == q) {
366                         if (prev)
367                                 prev->next = cur->next;
368                         else
369                                 queues = cur->next;
370                 } else {
371                         prev = cur;
372                 }
373         }
374         ast_mutex_unlock(&qlock);
375         free_members(q, 1);
376         ast_mutex_destroy(&q->lock);
377         free(q);
378 }
379
380 static int play_file(struct ast_channel *chan, char *filename)
381 {
382         int res;
383
384         ast_stopstream(chan);
385         res = ast_streamfile(chan, filename, chan->language);
386
387         if (!res)
388                 res = ast_waitstream(chan, "");
389         else
390                 res = 0;
391
392         if (res) {
393                 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
394                 res = 0;
395         }
396         ast_stopstream(chan);
397
398         return res;
399 }
400
401 static int say_position(struct queue_ent *qe)
402 {
403         int res = 0, avgholdmins, avgholdsecs;
404         time_t now;
405
406         /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
407         time(&now);
408         if ( (now - qe->last_pos) < 15 )
409                 return -1;
410
411         /* If either our position has changed, or we are over the freq timer, say position */
412         if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
413                 return -1;
414
415         ast_moh_stop(qe->chan);
416         /* Say we're next, if we are */
417         if (qe->pos == 1) {
418                 res += play_file(qe->chan, qe->parent->sound_next);
419                 goto posout;
420         } else {
421                 res += play_file(qe->chan, qe->parent->sound_thereare);
422                 res += ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
423                 res += play_file(qe->chan, qe->parent->sound_calls);
424         }
425         /* Round hold time to nearest minute */
426         avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
427
428         /* If they have specified a rounding then round the seconds as well */
429         if(qe->parent->roundingseconds) {
430                 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
431                 avgholdsecs*= qe->parent->roundingseconds;
432         } else {
433                 avgholdsecs=0;
434         }
435
436         if (option_verbose > 2)
437                 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
438
439         /* If the hold time is >1 min, if it's enabled, and if it's not
440            supposed to be only once and we have already said it, say it */
441         if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && (!(qe->parent->announceholdtime==1 && qe->last_pos)) ) {
442                 res += play_file(qe->chan, qe->parent->sound_holdtime);
443                 if(avgholdmins>0) {
444                         if (avgholdmins < 2) {
445                                 res += play_file(qe->chan, qe->parent->sound_lessthan);
446                                 res += ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
447                         } else 
448                                 res += ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
449                         res += play_file(qe->chan, qe->parent->sound_minutes);
450                 }
451                 if(avgholdsecs>0) {
452                         res += ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
453                         res += play_file(qe->chan, qe->parent->sound_seconds);
454                 }
455
456         }
457
458         posout:
459         /* Set our last_pos indicators */
460         qe->last_pos = now;
461         qe->last_pos_said = qe->pos;
462
463         if (option_verbose > 2)
464                 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n", qe->chan->name, qe->parent->name, qe->pos);
465         res += play_file(qe->chan, qe->parent->sound_thanks);
466         ast_moh_start(qe->chan, qe->moh);
467
468         return (res>0);
469 }
470
471 static void record_abandoned(struct queue_ent *qe)
472 {
473         ast_mutex_lock(&qe->parent->lock);
474         qe->parent->callsabandoned++;
475         ast_mutex_unlock(&qe->parent->lock);
476 }
477
478 static void recalc_holdtime(struct queue_ent *qe)
479 {
480         int oldvalue, newvalue;
481
482         /* Calculate holdtime using a recursive boxcar filter */
483         /* Thanks to SRT for this contribution */
484         /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
485
486         newvalue = time(NULL) - qe->start;
487
488         ast_mutex_lock(&qe->parent->lock);
489         if (newvalue <= qe->parent->servicelevel)
490                 qe->parent->callscompletedinsl++;
491         oldvalue = qe->parent->holdtime;
492         qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
493         ast_mutex_unlock(&qe->parent->lock);
494 }
495
496
497 static void leave_queue(struct queue_ent *qe)
498 {
499         struct ast_call_queue *q;
500         struct queue_ent *cur, *prev = NULL;
501         int pos = 0;
502         q = qe->parent;
503         if (!q)
504                 return;
505         ast_mutex_lock(&q->lock);
506
507         prev = NULL;
508         cur = q->head;
509         while(cur) {
510                 if (cur == qe) {
511                         q->count--;
512
513                         /* Take us out of the queue */
514                         manager_event(EVENT_FLAG_CALL, "Leave",
515                                 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
516                                 qe->chan->name, q->name,  q->count);
517 #if 0
518 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
519 #endif
520                         /* Take us out of the queue */
521                         if (prev)
522                                 prev->next = cur->next;
523                         else
524                                 q->head = cur->next;
525                 } else {
526                         /* Renumber the people after us in the queue based on a new count */
527                         cur->pos = ++pos;
528                         prev = cur;
529                 }
530                 cur = cur->next;
531         }
532         ast_mutex_unlock(&q->lock);
533         if (q->dead && !q->count) {     
534                 /* It's dead and nobody is in it, so kill it */
535                 destroy_queue(q);
536         }
537 }
538
539 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
540 {
541         /* Hang up a tree of stuff */
542         struct localuser *oo;
543         while(outgoing) {
544                 /* Hangup any existing lines we have open */
545                 if (outgoing->chan && (outgoing->chan != exception))
546                         ast_hangup(outgoing->chan);
547                 oo = outgoing;
548                 outgoing=outgoing->next;
549                 free(oo);
550         }
551 }
552
553 static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
554 {
555         int res;
556         if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
557                 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s/%s\n", tmp->tech, tmp->numsubst);
558                 if (qe->chan->cdr)
559                         ast_cdr_busy(qe->chan->cdr);
560                 tmp->stillgoing = 0;
561                 return 0;
562         }
563         /* Request the peer */
564         tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst);
565         if (!tmp->chan) {                       /* If we can't, just go on to the next call */
566 #if 0
567                 ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
568 #endif                  
569                 if (qe->chan->cdr)
570                         ast_cdr_busy(qe->chan->cdr);
571                 tmp->stillgoing = 0;
572                 return 0;
573         }
574         tmp->chan->appl = "AppQueue";
575         tmp->chan->data = "(Outgoing Line)";
576         tmp->chan->whentohangup = 0;
577         if (tmp->chan->cid.cid_num)
578                 free(tmp->chan->cid.cid_num);
579         tmp->chan->cid.cid_num = NULL;
580         if (tmp->chan->cid.cid_name)
581                 free(tmp->chan->cid.cid_name);
582         tmp->chan->cid.cid_name = NULL;
583         if (tmp->chan->cid.cid_ani)
584                 free(tmp->chan->cid.cid_ani);
585         tmp->chan->cid.cid_ani = NULL;
586         if (qe->chan->cid.cid_num)
587                 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
588         if (qe->chan->cid.cid_name)
589                 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
590         if (qe->chan->cid.cid_ani)
591                 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
592         /* Presense of ADSI CPE on outgoing channel follows ours */
593         tmp->chan->adsicpe = qe->chan->adsicpe;
594         /* Place the call, but don't wait on the answer */
595         res = ast_call(tmp->chan, tmp->numsubst, 0);
596         if (res) {
597                 /* Again, keep going even if there's an error */
598                 if (option_debug)
599                         ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
600                 else if (option_verbose > 2)
601                         ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->numsubst);
602                 ast_hangup(tmp->chan);
603                 tmp->chan = NULL;
604                 tmp->stillgoing = 0;
605                 return 0;
606         } else {
607                 if (qe->parent->eventwhencalled) {
608                         manager_event(EVENT_FLAG_AGENT, "AgentCalled",
609                                                 "AgentCalled: %s/%s\r\n"
610                                                 "ChannelCalling: %s\r\n"
611                                                 "CallerID: %s\r\n"
612                                                 "CallerIDName: %s\r\n"
613                                                 "Context: %s\r\n"
614                                                 "Extension: %s\r\n"
615                                                 "Priority: %d\r\n",
616                                                 tmp->tech, tmp->numsubst, qe->chan->name,
617                                                 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
618                                                 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
619                                                 qe->chan->context, qe->chan->exten, qe->chan->priority);
620                 }
621                 if (option_verbose > 2)
622                         ast_verbose(VERBOSE_PREFIX_3 "Called %s/%s\n", tmp->tech, tmp->numsubst);
623         }
624         return 0;
625 }
626
627 static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
628 {
629         struct localuser *cur;
630         struct localuser *best;
631         int bestmetric=0;
632         do {
633                 best = NULL;
634                 cur = outgoing;
635                 while(cur) {
636                         if (cur->stillgoing &&                                                  /* Not already done */
637                                 !cur->chan &&                                                           /* Isn't already going */
638                                 (!best || (cur->metric < bestmetric))) {        /* We haven't found one yet, or it's better */
639                                         bestmetric = cur->metric;
640                                         best = cur;
641                         }
642                         cur = cur->next;
643                 }
644                 if (best) {
645                         if (!qe->parent->strategy) {
646                                 /* Ring everyone who shares this best metric (for ringall) */
647                                 cur = outgoing;
648                                 while(cur) {
649                                         if (cur->stillgoing && !cur->chan && (cur->metric == bestmetric)) {
650                                                 ast_log(LOG_DEBUG, "(Parallel) Trying '%s/%s' with metric %d\n", cur->tech, cur->numsubst, cur->metric);
651                                                 ring_entry(qe, cur);
652                                         }
653                                         cur = cur->next;
654                                 }
655                         } else {
656                                 /* Ring just the best channel */
657                                 if (option_debug)
658                                         ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n", 
659                                                                         best->tech, best->numsubst, best->metric);
660                                 ring_entry(qe, best);
661                         }
662                 }
663         } while (best && !best->chan);
664         if (!best) {
665                 if (option_debug)
666                         ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
667                 return 0;
668         }
669         return 1;
670 }
671
672 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
673 {
674         struct localuser *cur;
675         struct localuser *best;
676         int bestmetric=0;
677         best = NULL;
678         cur = outgoing;
679         while(cur) {
680                 if (cur->stillgoing &&                                                  /* Not already done */
681                         !cur->chan &&                                                           /* Isn't already going */
682                         (!best || (cur->metric < bestmetric))) {        /* We haven't found one yet, or it's better */
683                                 bestmetric = cur->metric;
684                                 best = cur;
685                 }
686                 cur = cur->next;
687         }
688         if (best) {
689                 /* Ring just the best channel */
690                 ast_log(LOG_DEBUG, "Next is '%s/%s' with metric %d\n", best->tech, best->numsubst, best->metric);
691                 qe->parent->rrpos = best->metric % 1000;
692         } else {
693                 /* Just increment rrpos */
694                 if (!qe->parent->wrapped) {
695                         /* No more channels, start over */
696                         qe->parent->rrpos = 0;
697                 } else {
698                         /* Prioritize next entry */
699                         qe->parent->rrpos++;
700                 }
701         }
702         qe->parent->wrapped = 0;
703         return 0;
704 }
705
706 static int valid_exit(struct queue_ent *qe, char digit)
707 {
708         char tmp[2];
709         if (ast_strlen_zero(qe->context))
710                 return 0;
711         tmp[0] = digit;
712         tmp[1] = '\0';
713         if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->cid.cid_num)) {
714                 strncpy(qe->chan->context, qe->context, sizeof(qe->chan->context) - 1);
715                 strncpy(qe->chan->exten, tmp, sizeof(qe->chan->exten) - 1);
716                 qe->chan->priority = 0;
717                 return 1;
718         }
719         return 0;
720 }
721
722 #define AST_MAX_WATCHERS 256
723
724 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect_in, int *allowdisconnect_out, char *digit)
725 {
726         char *queue = qe->parent->name;
727         struct localuser *o;
728         int found;
729         int numlines;
730         int sentringing = 0;
731         int numbusies = 0;
732         int orig = *to;
733         struct ast_frame *f;
734         struct localuser *peer = NULL;
735         struct ast_channel *watchers[AST_MAX_WATCHERS];
736         int pos;
737         struct ast_channel *winner;
738         struct ast_channel *in = qe->chan;
739         
740         while(*to && !peer) {
741                 o = outgoing;
742                 found = -1;
743                 pos = 1;
744                 numlines = 0;
745                 watchers[0] = in;
746                 while(o) {
747                         /* Keep track of important channels */
748                         if (o->stillgoing && o->chan) {
749                                 watchers[pos++] = o->chan;
750                                 found = 1;
751                         }
752                         o = o->next;
753                         numlines++;
754                 }
755                 if (found < 0) {
756                         if (numlines == numbusies) {
757                                 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
758                         } else {
759                                 ast_log(LOG_NOTICE, "No one is answering queue '%s'\n", queue);
760                         }
761                         *to = 0;
762                         return NULL;
763                 }
764                 winner = ast_waitfor_n(watchers, pos, to);
765                 o = outgoing;
766                 while(o) {
767                         if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
768                                 if (!peer) {
769                                         if (option_verbose > 2)
770                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
771                                         peer = o;
772                                         *allowredir_in = o->allowredirect_in;
773                                         *allowredir_out = o->allowredirect_out;
774                                         *allowdisconnect_in = o->allowdisconnect_in;
775                                         *allowdisconnect_out = o->allowdisconnect_out;
776                                 }
777                         } else if (o->chan && (o->chan == winner)) {
778                                 f = ast_read(winner);
779                                 if (f) {
780                                         if (f->frametype == AST_FRAME_CONTROL) {
781                                                 switch(f->subclass) {
782                                             case AST_CONTROL_ANSWER:
783                                                         /* This is our guy if someone answered. */
784                                                         if (!peer) {
785                                                                 if (option_verbose > 2)
786                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
787                                                                 peer = o;
788                                                                 *allowredir_in = o->allowredirect_in;
789                                                                 *allowredir_out = o->allowredirect_out;
790                                                                 *allowdisconnect_in = o->allowdisconnect_out;
791                                                                 *allowdisconnect_out = o->allowdisconnect_out;
792                                                         }
793                                                         break;
794                                                 case AST_CONTROL_BUSY:
795                                                         if (option_verbose > 2)
796                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
797                                                         o->stillgoing = 0;
798                                                         if (in->cdr)
799                                                                 ast_cdr_busy(in->cdr);
800                                                         ast_hangup(o->chan);
801                                                         o->chan = NULL;
802                                                         if (qe->parent->strategy)
803                                                                 ring_one(qe, outgoing);
804                                                         numbusies++;
805                                                         break;
806                                                 case AST_CONTROL_CONGESTION:
807                                                         if (option_verbose > 2)
808                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
809                                                         o->stillgoing = 0;
810                                                         if (in->cdr)
811                                                                 ast_cdr_busy(in->cdr);
812                                                         ast_hangup(o->chan);
813                                                         o->chan = NULL;
814                                                         if (qe->parent->strategy)
815                                                                 ring_one(qe, outgoing);
816                                                         numbusies++;
817                                                         break;
818                                                 case AST_CONTROL_RINGING:
819                                                         if (option_verbose > 2)
820                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
821                                                         if (!sentringing) {
822 #if 0
823                                                                 ast_indicate(in, AST_CONTROL_RINGING);
824 #endif                                                          
825                                                                 sentringing++;
826                                                         }
827                                                         break;
828                                                 case AST_CONTROL_OFFHOOK:
829                                                         /* Ignore going off hook */
830                                                         break;
831                                                 default:
832                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
833                                                 }
834                                         }
835                                         ast_frfree(f);
836                                 } else {
837                                         o->stillgoing = 0;
838                                         ast_hangup(o->chan);
839                                         o->chan = NULL;
840                                         if (qe->parent->strategy)
841                                                 ring_one(qe, outgoing);
842                                 }
843                         }
844                         o = o->next;
845                 }
846                 if (winner == in) {
847                         f = ast_read(in);
848 #if 0
849                         if (f && (f->frametype != AST_FRAME_VOICE))
850                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
851                         else if (!f || (f->frametype != AST_FRAME_VOICE))
852                                 printf("Hangup received on %s\n", in->name);
853 #endif
854                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
855                                 /* Got hung up */
856                                 *to=-1;
857                                 return NULL;
858                         }
859                         if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect_out && (f->subclass == '*')) {
860                             if (option_verbose > 3)
861                                         ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
862                                 *to=0;
863                                 return NULL;
864                         }
865                         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
866                                 if (option_verbose > 3)
867                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
868                                 *to=0;
869                                 *digit=f->subclass;
870                                 return NULL;
871                         }
872                 }
873                 if (!*to && (option_verbose > 2))
874                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
875         }
876
877         return peer;
878         
879 }
880
881 static int is_our_turn(struct queue_ent *qe)
882 {
883         struct queue_ent *ch;
884         int res;
885
886         /* Atomically read the parent head -- does not need a lock */
887         ch = qe->parent->head;
888         /* If we are now at the top of the head, break out */
889         if (ch == qe) {
890                 if (option_debug)
891                         ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
892                 res = 1;
893         } else {
894                 if (option_debug)
895                         ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
896                 res = 0;
897         }
898         return res;
899 }
900
901 static int wait_our_turn(struct queue_ent *qe, int ringing)
902 {
903         struct queue_ent *ch;
904         int res = 0;
905         time_t now;
906
907         /* This is the holding pen for callers 2 through maxlen */
908         for (;;) {
909                 /* Atomically read the parent head -- does not need a lock */
910                 ch = qe->parent->head;
911
912                 /* If we are now at the top of the head, break out */
913                 if (ch == qe) {
914                         if (option_debug)
915                                 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
916                         break;
917                 }
918
919                 /* If we have timed out, break out */
920                 if ( qe->queuetimeout ) {
921                         time(&now);
922                         if ( (now - qe->start) >= qe->queuetimeout )
923                         break;
924                 }
925
926                 /* leave the queue if no agents, if enabled */
927                 if (!(qe->parent->members) && qe->parent->leavewhenempty) {
928                         leave_queue(qe);
929                         break;
930                 }
931
932                 /* Make a position announcement, if enabled */
933                 if (qe->parent->announcefrequency && !ringing)
934                         say_position(qe);
935
936                 /* Wait a second before checking again */
937                 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
938                 if (res)
939                         break;
940         }
941         return res;
942 }
943
944 static int update_queue(struct ast_call_queue *q, struct member *member)
945 {
946         struct member *cur;
947         /* Since a reload could have taken place, we have to traverse the list to
948                 be sure it's still valid */
949         ast_mutex_lock(&q->lock);
950         cur = q->members;
951         while(cur) {
952                 if (member == cur) {
953                         time(&cur->lastcall);
954                         cur->calls++;
955                         break;
956                 }
957                 cur = cur->next;
958         }
959         q->callscompleted++;
960         ast_mutex_unlock(&q->lock);
961         return 0;
962 }
963
964 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
965 {
966         switch (q->strategy) {
967         case QUEUE_STRATEGY_RINGALL:
968                 /* Everyone equal, except for penalty */
969                 tmp->metric = mem->penalty * 1000000;
970                 break;
971         case QUEUE_STRATEGY_ROUNDROBIN:
972                 if (!pos) {
973                         if (!q->wrapped) {
974                                 /* No more channels, start over */
975                                 q->rrpos = 0;
976                         } else {
977                                 /* Prioritize next entry */
978                                 q->rrpos++;
979                         }
980                         q->wrapped = 0;
981                 }
982                 /* Fall through */
983         case QUEUE_STRATEGY_RRMEMORY:
984                 if (pos < q->rrpos) {
985                         tmp->metric = 1000 + pos;
986                 } else {
987                         if (pos > q->rrpos) {
988                                 /* Indicate there is another priority */
989                                 q->wrapped = 1;
990                         }
991                         tmp->metric = pos;
992                 }
993                 tmp->metric += mem->penalty * 1000000;
994                 break;
995         case QUEUE_STRATEGY_RANDOM:
996                 tmp->metric = rand() % 1000;
997                 tmp->metric += mem->penalty * 1000000;
998                 break;
999         case QUEUE_STRATEGY_FEWESTCALLS:
1000                 tmp->metric = mem->calls;
1001                 tmp->metric += mem->penalty * 1000000;
1002                 break;
1003         case QUEUE_STRATEGY_LEASTRECENT:
1004                 if (!mem->lastcall)
1005                         tmp->metric = 0;
1006                 else
1007                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1008                 tmp->metric += mem->penalty * 1000000;
1009                 break;
1010         default:
1011                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1012                 break;
1013         }
1014         return 0;
1015 }
1016
1017 static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url, int *go_on)
1018 {
1019         struct member *cur;
1020         struct localuser *outgoing=NULL, *tmp = NULL;
1021         int to;
1022         int allowredir_in=0;
1023         int allowredir_out=0;
1024         int allowdisconnect_in=0;
1025         int allowdisconnect_out=0;
1026         char restofit[AST_MAX_EXTENSION];
1027         char oldexten[AST_MAX_EXTENSION]="";
1028         char oldcontext[AST_MAX_EXTENSION]="";
1029         char queuename[256]="";
1030         char *newnum;
1031         char *monitorfilename;
1032         struct ast_channel *peer;
1033         struct localuser *lpeer;
1034         struct member *member;
1035         int res = 0, bridge = 0;
1036         int zapx = 2;
1037         int x=0;
1038         char *announce = NULL;
1039         char digit = 0;
1040         time_t callstart;
1041         time_t now;
1042         struct ast_bridge_config config;
1043         /* Hold the lock while we setup the outgoing calls */
1044         ast_mutex_lock(&qe->parent->lock);
1045         if (option_debug)
1046                 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
1047                                                         qe->chan->name);
1048         strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
1049         time(&now);
1050         cur = qe->parent->members;
1051         if (!ast_strlen_zero(qe->announce))
1052                 announce = qe->announce;
1053         if (announceoverride && !ast_strlen_zero(announceoverride))
1054                 announce = announceoverride;
1055         while(cur) {
1056                 /* Get a technology/[device:]number pair */
1057                 tmp = malloc(sizeof(struct localuser));
1058                 if (!tmp) {
1059                         ast_mutex_unlock(&qe->parent->lock);
1060                         ast_log(LOG_WARNING, "Out of memory\n");
1061                         goto out;
1062                 }
1063                 memset(tmp, 0, sizeof(struct localuser));
1064                 tmp->stillgoing = -1;
1065                 if (options) {
1066                         if (strchr(options, 't'))
1067                                 tmp->allowredirect_in = 1;
1068                         if (strchr(options, 'T'))
1069                                 tmp->allowredirect_out = 1;
1070                         if (strchr(options, 'r'))
1071                                 tmp->ringbackonly = 1;
1072                         if (strchr(options, 'm'))
1073                                 tmp->musiconhold = 1;
1074                         if (strchr(options, 'd'))
1075                                 tmp->dataquality = 1;
1076                         if (strchr(options, 'h'))
1077                                 tmp->allowdisconnect_in = 1;
1078                         if (strchr(options, 'H'))
1079                                 tmp->allowdisconnect_out = 1;
1080                         if ((strchr(options, 'n')) && (now - qe->start >= qe->parent->timeout))
1081                                 *go_on = 1;
1082                 }
1083                 if (option_debug) {
1084                         if (url)
1085                                 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
1086                         else 
1087                                 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
1088                 }
1089
1090                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
1091                 strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
1092                 strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
1093                 tmp->lastcall = cur->lastcall;
1094                 /* If we're dialing by extension, look at the extension to know what to dial */
1095                 if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
1096                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
1097                         snprintf(newnum, sizeof(tmp->numsubst) - (newnum - tmp->numsubst), "%s%s", qe->chan->exten,restofit);
1098                         if (option_debug)
1099                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->numsubst);
1100                 }
1101                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
1102                    just calculate their metric for the appropriate strategy */
1103                 calc_metric(qe->parent, cur, x++, qe, tmp);
1104                 /* Put them in the list of outgoing thingies...  We're ready now. 
1105                    XXX If we're forcibly removed, these outgoing calls won't get
1106                    hung up XXX */
1107                 tmp->next = outgoing;
1108                 outgoing = tmp;         
1109                 /* If this line is up, don't try anybody else */
1110                 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
1111                         break;
1112
1113                 cur = cur->next;
1114         }
1115         if (qe->parent->timeout)
1116                 to = qe->parent->timeout * 1000;
1117         else
1118                 to = -1;
1119         ring_one(qe, outgoing);
1120         ast_mutex_unlock(&qe->parent->lock);
1121         lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect_in, &allowdisconnect_out, &digit);
1122         ast_mutex_lock(&qe->parent->lock);
1123         if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
1124                 store_next(qe, outgoing);
1125         }
1126         ast_mutex_unlock(&qe->parent->lock);
1127         if (lpeer)
1128                 peer = lpeer->chan;
1129         else
1130                 peer = NULL;
1131         if (!peer) {
1132                 if (to) {
1133                         /* Musta gotten hung up */
1134                         record_abandoned(qe);
1135                         res = -1;
1136                 } else {
1137                         if (digit && valid_exit(qe, digit))
1138                                 res=digit;
1139                         else
1140                                 /* Nobody answered, next please? */
1141                                 res=0;
1142                 }
1143                 if (option_debug)
1144                         ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
1145                 goto out;
1146         }
1147         if (peer) {
1148                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
1149                    we will always return with -1 so that it is hung up properly after the 
1150                    conversation.  */
1151                 qe->handled++;
1152                 if (!strcmp(qe->chan->type,"Zap")) {
1153                         if (tmp->dataquality) zapx = 0;
1154                         ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1155                 }                       
1156                 if (!strcmp(peer->type,"Zap")) {
1157                         if (tmp->dataquality) zapx = 0;
1158                         ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1159                 }
1160                 /* Update parameters for the queue */
1161                 recalc_holdtime(qe);
1162                 member = lpeer->member;
1163                 hanguptree(outgoing, peer);
1164                 outgoing = NULL;
1165                 if (announce || qe->parent->reportholdtime) {
1166                         int res2;
1167                         res2 = ast_autoservice_start(qe->chan);
1168                         if (!res2) {
1169                                 if (announce) {
1170                                         if (play_file(peer, announce))
1171                                                 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
1172                                 }
1173                                 if (qe->parent->reportholdtime) {
1174                                         if (!play_file(peer, qe->parent->sound_reporthold)) {
1175                                                 int holdtime;
1176                                                 time_t now;
1177
1178                                                 time(&now);
1179                                                 holdtime = abs((now - qe->start) / 60);
1180                                                 if (holdtime < 2) {
1181                                                         play_file(peer, qe->parent->sound_lessthan);
1182                                                         ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
1183                                                 } else 
1184                                                         ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
1185                                                 play_file(peer, qe->parent->sound_minutes);
1186                                         }
1187                                 }
1188                         }
1189                         res2 |= ast_autoservice_stop(qe->chan);
1190                         if (res2) {
1191                                 /* Agent must have hung up */
1192                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
1193                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
1194                                 ast_hangup(peer);
1195                                 return -1;
1196                         }
1197                 }
1198                 /* Stop music on hold */
1199                 ast_moh_stop(qe->chan);
1200                 /* If appropriate, log that we have a destination channel */
1201                 if (qe->chan->cdr)
1202                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
1203                 /* Make sure channels are compatible */
1204                 res = ast_channel_make_compatible(qe->chan, peer);
1205                 if (res < 0) {
1206                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
1207                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
1208                         ast_hangup(peer);
1209                         return -1;
1210                 }
1211                 /* Begin Monitoring */
1212                 if (qe->parent->monfmt && *qe->parent->monfmt) {
1213                         monitorfilename = pbx_builtin_getvar_helper( qe->chan, "MONITOR_FILENAME");
1214                         if(monitorfilename) {
1215                                 ast_monitor_start( peer, qe->parent->monfmt, monitorfilename, 1 );
1216                         } else {
1217                                 ast_monitor_start( peer, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
1218                         }
1219                         if(qe->parent->monjoin) {
1220                                 ast_monitor_setjoinfiles( peer, 1);
1221                         }
1222                 }
1223                 /* Drop out of the queue at this point, to prepare for next caller */
1224                 leave_queue(qe);                        
1225                 if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
1226                         if (option_debug)
1227                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
1228                         ast_channel_sendurl( peer, url );
1229                 }
1230                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
1231                 strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1);
1232                 strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1);
1233                 time(&callstart);
1234
1235                 memset(&config,0,sizeof(struct ast_bridge_config));
1236         config.allowredirect_in = allowredir_in;
1237         config.allowredirect_out = allowredir_out;
1238         config.allowdisconnect_in = allowdisconnect_in;
1239         config.allowdisconnect_out = allowdisconnect_out;
1240         bridge = ast_bridge_call(qe->chan,peer,&config);
1241
1242                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
1243                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
1244                 } else if (qe->chan->_softhangup) {
1245                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1246                 } else {
1247                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1248                 }
1249
1250                 if(bridge != AST_PBX_NO_HANGUP_PEER)
1251                         ast_hangup(peer);
1252                 update_queue(qe->parent, member);
1253                 if( bridge == 0 ) res=1; /* JDG: bridge successfull, leave app_queue */
1254                 else res = bridge; /* bridge error, stay in the queue */
1255         }       
1256 out:
1257         hanguptree(outgoing, NULL);
1258         return res;
1259 }
1260
1261 static int wait_a_bit(struct queue_ent *qe)
1262 {
1263         /* Don't need to hold the lock while we setup the outgoing calls */
1264         int retrywait = qe->parent->retry * 1000;
1265         return ast_waitfordigit(qe->chan, retrywait);
1266 }
1267
1268 // [PHM 06/26/03]
1269
1270 static struct member * interface_exists( struct ast_call_queue * q, char * interface )
1271 {
1272         struct member * ret = NULL ;
1273         struct member *mem;
1274         char buf[500] ;
1275
1276         if( q != NULL )
1277         {
1278                 mem = q->members ;
1279
1280                 while( mem != NULL ) {
1281                         snprintf( buf, sizeof(buf), "%s/%s", mem->tech, mem->loc);
1282
1283                         if( strcmp( buf, interface ) == 0 ) {
1284                                 ret = mem ;
1285                                 break ;
1286                         }
1287                         else
1288                                 mem = mem->next ;
1289                 }
1290         }
1291
1292         return( ret ) ;
1293 }
1294
1295
1296 static struct member * create_queue_node( char * interface, int penalty )
1297 {
1298         struct member * cur ;
1299         char * tmp ;
1300         
1301         /* Add a new member */
1302
1303         cur = malloc(sizeof(struct member));
1304
1305         if (cur) {
1306                 memset(cur, 0, sizeof(struct member));
1307                 cur->penalty = penalty;
1308                 strncpy(cur->tech, interface, sizeof(cur->tech) - 1);
1309                 if ((tmp = strchr(cur->tech, '/')))
1310                         *tmp = '\0';
1311                 if ((tmp = strchr(interface, '/'))) {
1312                         tmp++;
1313                         strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
1314                 } else
1315                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1316         }
1317
1318         return( cur ) ;
1319 }
1320
1321 static int remove_from_queue(char *queuename, char *interface)
1322 {
1323         struct ast_call_queue *q;
1324         struct member *last_member, *look;
1325         int res = RES_NOSUCHQUEUE;
1326
1327         ast_mutex_lock(&qlock);
1328         for (q = queues ; q ; q = q->next) {
1329                 ast_mutex_lock(&q->lock);
1330                 if (!strcmp(q->name, queuename)) {
1331                         if ((last_member = interface_exists(q, interface))) {
1332                                 if ((look = q->members) == last_member) {
1333                                         q->members = last_member->next;
1334                                 } else {
1335                                         while (look != NULL) {
1336                                                 if (look->next == last_member) {
1337                                                         look->next = last_member->next;
1338                                                         break;
1339                                                 } else {
1340                                                          look = look->next;
1341                                                 }
1342                                         }
1343                                 }
1344                                 free(last_member);
1345                                 res = RES_OKAY;
1346                         } else {
1347                                 res = RES_EXISTS;
1348                         }
1349                         ast_mutex_unlock(&q->lock);
1350                         break;
1351                 }
1352                 ast_mutex_unlock(&q->lock);
1353         }
1354         ast_mutex_unlock(&qlock);
1355         return res;
1356 }
1357
1358 static int add_to_queue(char *queuename, char *interface, int penalty)
1359 {
1360         struct ast_call_queue *q;
1361         struct member *new_member;
1362         int res = RES_NOSUCHQUEUE;
1363
1364         ast_mutex_lock(&qlock);
1365         for (q = queues ; q ; q = q->next) {
1366                 ast_mutex_lock(&q->lock);
1367                 if (!strcmp(q->name, queuename)) {
1368                         if (interface_exists(q, interface) == NULL) {
1369                                 new_member = create_queue_node(interface, penalty);
1370
1371                                 if (new_member != NULL) {
1372                                         new_member->dynamic = 1;
1373                                         new_member->next = q->members;
1374                                         q->members = new_member;
1375                                         res = RES_OKAY;
1376                                 } else {
1377                                         res = RES_OUTOFMEMORY;
1378                                 }
1379                         } else {
1380                                 res = RES_EXISTS;
1381                         }
1382                         ast_mutex_unlock(&q->lock);
1383                         break;
1384                 }
1385                 ast_mutex_unlock(&q->lock);
1386         }
1387         ast_mutex_unlock(&qlock);
1388         return res;
1389 }
1390
1391 static int rqm_exec(struct ast_channel *chan, void *data)
1392 {
1393         int res=-1;
1394         struct localuser *u;
1395         char *info, *queuename;
1396         char tmpchan[256]="";
1397         char *interface = NULL;
1398
1399         if (!data) {
1400                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
1401                 return -1;
1402         }
1403
1404         info = ast_strdupa((char *)data);
1405         if (!info) {
1406                 ast_log(LOG_ERROR, "Out of memory\n");
1407                 return -1;
1408         }
1409
1410         LOCAL_USER_ADD(u);
1411
1412         queuename = info;
1413         if (queuename) {
1414                 interface = strchr(queuename, '|');
1415                 if (interface) {
1416                         *interface = '\0';
1417                         interface++;
1418                 }
1419                 else {
1420                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
1421                         interface = strrchr(tmpchan, '-');
1422                         if (interface)
1423                                 *interface = '\0';
1424                         interface = tmpchan;
1425                 }
1426         }
1427
1428         switch (remove_from_queue(queuename, interface)) {
1429         case RES_OKAY:
1430                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
1431                 res = 0;
1432                 break;
1433         case RES_EXISTS:
1434                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
1435                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1436                         chan->priority += 100;
1437                 }
1438                 res = 0;
1439                 break;
1440         case RES_NOSUCHQUEUE:
1441                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
1442                 res = 0;
1443                 break;
1444         case RES_OUTOFMEMORY:
1445                 ast_log(LOG_ERROR, "Out of memory\n");
1446                 break;
1447         }
1448
1449         LOCAL_USER_REMOVE(u);
1450         return res;
1451 }
1452
1453 static int aqm_exec(struct ast_channel *chan, void *data)
1454 {
1455         int res=-1;
1456         struct localuser *u;
1457         char *queuename;
1458         char *info;
1459         char tmpchan[512]="";
1460         char *interface=NULL;
1461         char *penaltys=NULL;
1462         int penalty = 0;
1463
1464         if (!data) {
1465                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
1466                 return -1;
1467         }
1468
1469         info = ast_strdupa((char *)data);
1470         if (!info) {
1471                 ast_log(LOG_ERROR, "Out of memory\n");
1472                 return -1;
1473         }
1474         LOCAL_USER_ADD(u);
1475
1476         queuename = info;
1477         if (queuename) {
1478                 interface = strchr(queuename, '|');
1479                 if (interface) {
1480                         *interface = '\0';
1481                         interface++;
1482                 }
1483                 if (interface) {
1484                         penaltys = strchr(interface, '|');
1485                         if (penaltys) {
1486                                 *penaltys = '\0';
1487                                 penaltys++;
1488                         }
1489                 }
1490                 if (!interface || ast_strlen_zero(interface)) {
1491                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
1492                         interface = strrchr(tmpchan, '-');
1493                         if (interface)
1494                                 *interface = '\0';
1495                         interface = tmpchan;
1496                 }
1497                 if (penaltys && strlen(penaltys)) {
1498                         if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
1499                                 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
1500                                 penalty = 0;
1501                         }
1502                 }
1503         }
1504
1505         switch (add_to_queue(queuename, interface, penalty)) {
1506         case RES_OKAY:
1507                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
1508                 res = 0;
1509                 break;
1510         case RES_EXISTS:
1511                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
1512                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1513                         chan->priority += 100;
1514                 }
1515                 res = 0;
1516                 break;
1517         case RES_NOSUCHQUEUE:
1518                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
1519                 res = 0;
1520                 break;
1521         case RES_OUTOFMEMORY:
1522                 ast_log(LOG_ERROR, "Out of memory\n");
1523                 break;
1524         }
1525
1526         LOCAL_USER_REMOVE(u);
1527         return res;
1528 }
1529
1530 static int queue_exec(struct ast_channel *chan, void *data)
1531 {
1532         int res=-1;
1533         int ringing=0;
1534         struct localuser *u;
1535         char *queuename;
1536         char info[512];
1537         char *options = NULL;
1538         char *url = NULL;
1539         char *announceoverride = NULL;
1540         char *user_priority;
1541         int prio;
1542         char *queuetimeoutstr = NULL;
1543
1544         /* whether to exit Queue application after the timeout hits */
1545         int go_on = 0;
1546
1547         /* Our queue entry */
1548         struct queue_ent qe;
1549         
1550         if (!data) {
1551                 ast_log(LOG_WARNING, "Queue requires an argument (queuename[|[timeout][|URL]])\n");
1552                 return -1;
1553         }
1554         
1555         LOCAL_USER_ADD(u);
1556
1557         /* Setup our queue entry */
1558         memset(&qe, 0, sizeof(qe));
1559         
1560         /* Parse our arguments XXX Check for failure XXX */
1561         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1562         queuename = info;
1563         if (queuename) {
1564                 options = strchr(queuename, '|');
1565                 if (options) {
1566                         *options = '\0';
1567                         options++;
1568                         url = strchr(options, '|');
1569                         if (url) {
1570                                 *url = '\0';
1571                                 url++;
1572                                 announceoverride = strchr(url, '|');
1573                                 if (announceoverride) {
1574                                         *announceoverride = '\0';
1575                                         announceoverride++;
1576                                         queuetimeoutstr = strchr(announceoverride, '|');
1577                                         if (queuetimeoutstr) {
1578                                                 *queuetimeoutstr = '\0';
1579                                                 queuetimeoutstr++;
1580                                                 qe.queuetimeout = atoi(queuetimeoutstr);
1581                                         } else {
1582                                                 qe.queuetimeout = 0;
1583                                         }
1584                                 }
1585                         }
1586                 }
1587         }
1588
1589         /* Get the priority from the variable ${QUEUE_PRIO} */
1590         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
1591         if (user_priority) {
1592                 if (sscanf(user_priority, "%d", &prio) == 1) {
1593                         if (option_debug)
1594                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
1595                                                                 chan->name, prio);
1596                 } else {
1597                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
1598                                                         user_priority, chan->name);
1599                         prio = 0;
1600                 }
1601         } else {
1602                 if (option_debug)
1603                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
1604                 prio = 0;
1605         }
1606
1607         if (options) {
1608                 if (strchr(options, 'r')) {
1609                         ringing = 1;
1610                 }
1611         }
1612
1613 //      if (option_debug) 
1614                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, timeout: %d, priority: %d\n",
1615                                 queuename, options, url, announceoverride, qe.queuetimeout, (int)prio);
1616
1617         qe.chan = chan;
1618         qe.start = time(NULL);
1619         qe.prio = (int)prio;
1620         qe.last_pos_said = 0;
1621         qe.last_pos = 0;
1622         if (!join_queue(queuename, &qe)) {
1623                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : "");
1624                 /* Start music on hold */
1625 check_turns:
1626                 if (ringing) {
1627                         ast_indicate(chan, AST_CONTROL_RINGING);
1628                 } else {              
1629                         ast_moh_start(chan, qe.moh);
1630                 }
1631                 for (;;) {
1632                         /* This is the wait loop for callers 2 through maxlen */
1633
1634                         res = wait_our_turn(&qe, ringing);
1635                         /* If they hungup, return immediately */
1636                         if (res < 0) {
1637                                 /* Record this abandoned call */
1638                                 record_abandoned(&qe);
1639                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
1640                                 if (option_verbose > 2) {
1641                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected while waiting their turn\n");
1642                                         res = -1;
1643                                 }
1644                                 break;
1645                         }
1646                         if (!res) 
1647                                 break;
1648                         if (valid_exit(&qe, res)) {
1649                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
1650                                 break;
1651                         }
1652                 }
1653                 if (!res) {
1654                         for (;;) {
1655                                 /* This is the wait loop for the head caller*/
1656                                 /* To exit, they may get their call answered; */
1657                                 /* they may dial a digit from the queue context; */
1658                                 /* or, they may timeout. */
1659
1660                                 /* Leave if we have exceeded our queuetimeout */
1661                                 if (qe.queuetimeout && ( (time(NULL) - qe.start) >= qe.queuetimeout) ) {
1662                                         res = 0;
1663                                         break;
1664                                 }
1665
1666                                 /* leave the queue if no agents, if enabled */
1667                                 if (!((qe.parent)->members) && (qe.parent)->leavewhenempty) {
1668                                         leave_queue(&qe);
1669                                         break;
1670                                 }
1671
1672                                 /* Make a position announcement, if enabled */
1673                                 if (qe.parent->announcefrequency && !ringing)
1674                                         say_position(&qe);
1675
1676                                 /* Try calling all queue members for 'timeout' seconds */
1677                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
1678                                 if (res) {
1679                                         if (res < 0) {
1680                                                 if (!qe.handled)
1681                                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
1682                                         } else if (res > 0)
1683                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
1684                                         break;
1685                                 }
1686
1687                                 /* Leave if we have exceeded our queuetimeout */
1688                                 if (qe.queuetimeout && ( (time(NULL) - qe.start) >= qe.queuetimeout) ) {
1689                                         res = 0;
1690                                         break;
1691                                 }
1692
1693                                 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
1694                                 res = wait_a_bit(&qe);
1695                                 if (res < 0) {
1696                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
1697                                         if (option_verbose > 2) {
1698                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected when they almost made it\n");
1699                                                 res = -1;
1700                                         }
1701                                         break;
1702                                 }
1703                                 if (res && valid_exit(&qe, res)) {
1704                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
1705                                         break;
1706                                 }
1707                                 /* exit after 'timeout' cycle if 'n' option enabled */
1708                                 if (go_on) {
1709                                         if (option_verbose > 2) {
1710                                                 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
1711                                                 res = -1;
1712                                         }
1713                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
1714                                         res = 0;
1715                                         break;
1716                                 }
1717                                 /* Since this is a priority queue and 
1718                                  * it is not sure that we are still at the head
1719                                  * of the queue, go and check for our turn again.
1720                                  */
1721                                 if (!is_our_turn(&qe)) {
1722                                         ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
1723                                                                 qe.chan->name);
1724                                         goto check_turns;
1725                                 }
1726                         }
1727                 }
1728                 /* Don't allow return code > 0 */
1729                 if (res > 0 && res != AST_PBX_KEEPALIVE) {
1730                         res = 0;        
1731                         if (ringing) {
1732                                 ast_indicate(chan, -1);
1733                         } else {
1734                                 ast_moh_stop(chan);
1735                         }                       
1736                         ast_stopstream(chan);
1737                 }
1738                 leave_queue(&qe);
1739         } else {
1740                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
1741                 res =  0;
1742         }
1743         LOCAL_USER_REMOVE(u);
1744         return res;
1745 }
1746
1747 static void reload_queues(void)
1748 {
1749         struct ast_call_queue *q, *ql, *qn;
1750         struct ast_config *cfg;
1751         char *cat, *tmp;
1752         struct ast_variable *var;
1753         struct member *prev, *cur;
1754         int new;
1755         cfg = ast_load("queues.conf");
1756         if (!cfg) {
1757                 ast_log(LOG_NOTICE, "No call queueing config file, so no call queues\n");
1758                 return;
1759         }
1760         ast_mutex_lock(&qlock);
1761         /* Mark all queues as dead for the moment */
1762         q = queues;
1763         while(q) {
1764                 q->dead = 1;
1765                 q = q->next;
1766         }
1767         /* Chug through config file */
1768         cat = ast_category_browse(cfg, NULL);
1769         while(cat) {
1770                 if (strcasecmp(cat, "general")) {
1771                         /* Look for an existing one */
1772                         q = queues;
1773                         while(q) {
1774                                 if (!strcmp(q->name, cat))
1775                                         break;
1776                                 q = q->next;
1777                         }
1778                         if (!q) {
1779                                 /* Make one then */
1780                                 q = malloc(sizeof(struct ast_call_queue));
1781                                 if (q) {
1782                                         /* Initialize it */
1783                                         memset(q, 0, sizeof(struct ast_call_queue));
1784                                         ast_mutex_init(&q->lock);
1785                                         strncpy(q->name, cat, sizeof(q->name) - 1);
1786                                         new = 1;
1787                                 } else new = 0;
1788                         } else
1789                                         new = 0;
1790                         if (q) {
1791                                 if (!new) 
1792                                         ast_mutex_lock(&q->lock);
1793                                 /* Re-initialize the queue */
1794                                 q->dead = 0;
1795                                 q->retry = 0;
1796                                 q->timeout = -1;
1797                                 q->maxlen = 0;
1798                                 q->announcefrequency = 0;
1799                                 q->announceholdtime = 0;
1800                                 q->roundingseconds = 0; /* Default - don't announce seconds */
1801                                 q->holdtime = 0;
1802                                 q->callscompleted = 0;
1803                                 q->callsabandoned = 0;
1804                                 q->callscompletedinsl = 0;
1805                                 q->servicelevel = 0;
1806                                 q->wrapuptime = 0;
1807                                 free_members(q, 0);
1808                                 q->moh[0] = '\0';
1809                                 q->announce[0] = '\0';
1810                                 q->context[0] = '\0';
1811                                 q->monfmt[0] = '\0';
1812                                 strncpy(q->sound_next, "queue-youarenext", sizeof(q->sound_next) - 1);
1813                                 strncpy(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare) - 1);
1814                                 strncpy(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls) - 1);
1815                                 strncpy(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime) - 1);
1816                                 strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
1817                                 strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
1818                                 strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
1819                                 strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
1820                                 strncpy(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold) - 1);
1821                                 prev = q->members;
1822                                 if (prev) {
1823                                         /* find the end of any dynamic members */
1824                                         while(prev->next)
1825                                                 prev = prev->next;
1826                                 }
1827                                 var = ast_variable_browse(cfg, cat);
1828                                 while(var) {
1829                                         if (!strcasecmp(var->name, "member")) {
1830                                                 /* Add a new member */
1831                                                 cur = malloc(sizeof(struct member));
1832                                                 if (cur) {
1833                                                         memset(cur, 0, sizeof(struct member));
1834                                                         strncpy(cur->tech, var->value, sizeof(cur->tech) - 1);
1835                                                         if ((tmp = strchr(cur->tech, ','))) {
1836                                                                 *tmp = '\0';
1837                                                                 tmp++;
1838                                                                 cur->penalty = atoi(tmp);
1839                                                                 if (cur->penalty < 0)
1840                                                                         cur->penalty = 0;
1841                                                         }
1842                                                         if ((tmp = strchr(cur->tech, '/')))
1843                                                                 *tmp = '\0';
1844                                                         if ((tmp = strchr(var->value, '/'))) {
1845                                                                 tmp++;
1846                                                                 strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
1847                                                                 if ((tmp = strchr(cur->loc, ',')))
1848                                                                         *tmp = '\0';
1849                                                         } else
1850                                                                 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
1851                                                         if (prev)
1852                                                                 prev->next = cur;
1853                                                         else
1854                                                                 q->members = cur;
1855                                                         prev = cur;
1856                                                 }
1857                                         } else if (!strcasecmp(var->name, "music")) {
1858                                                 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
1859                                         } else if (!strcasecmp(var->name, "announce")) {
1860                                                 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
1861                                         } else if (!strcasecmp(var->name, "context")) {
1862                                                 strncpy(q->context, var->value, sizeof(q->context) - 1);
1863                                         } else if (!strcasecmp(var->name, "timeout")) {
1864                                                 q->timeout = atoi(var->value);
1865                                         } else if (!strcasecmp(var->name, "monitor-join")) {
1866                                                 q->monjoin = ast_true(var->value);
1867                                         } else if (!strcasecmp(var->name, "monitor-format")) {
1868                                                 strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
1869                                         } else if (!strcasecmp(var->name, "queue-youarenext")) {
1870                                                 strncpy(q->sound_next, var->value, sizeof(q->sound_next) - 1);
1871                                         } else if (!strcasecmp(var->name, "queue-thereare")) {
1872                                                 strncpy(q->sound_thereare, var->value, sizeof(q->sound_thereare) - 1);
1873                                         } else if (!strcasecmp(var->name, "queue-callswaiting")) {
1874                                                 strncpy(q->sound_calls, var->value, sizeof(q->sound_calls) - 1);
1875                                         } else if (!strcasecmp(var->name, "queue-holdtime")) {
1876                                                 strncpy(q->sound_holdtime, var->value, sizeof(q->sound_holdtime) - 1);
1877                                         } else if (!strcasecmp(var->name, "queue-minutes")) {
1878                                                 strncpy(q->sound_minutes, var->value, sizeof(q->sound_minutes) - 1);
1879                                         } else if (!strcasecmp(var->name, "queue-seconds")) {
1880                                                 strncpy(q->sound_seconds, var->value, sizeof(q->sound_seconds) - 1);
1881                                         } else if (!strcasecmp(var->name, "queue-lessthan")) {
1882                                                 strncpy(q->sound_lessthan, var->value, sizeof(q->sound_lessthan) - 1);
1883                                         } else if (!strcasecmp(var->name, "queue-thankyou")) {
1884                                                 strncpy(q->sound_thanks, var->value, sizeof(q->sound_thanks) - 1);
1885                                         } else if (!strcasecmp(var->name, "queue-reporthold")) {
1886                                                 strncpy(q->sound_reporthold, var->value, sizeof(q->sound_reporthold) - 1);
1887                                         } else if (!strcasecmp(var->name, "announce-frequency")) {
1888                                                 q->announcefrequency = atoi(var->value);
1889                                         } else if (!strcasecmp(var->name, "announce-round-seconds")) {
1890                                                 q->roundingseconds = atoi(var->value);
1891                                                 if(q->roundingseconds>60 || q->roundingseconds<0) {
1892                                                         ast_log(LOG_WARNING, "'%s' isn't a valid value for queue-rounding-seconds using 0 instead at line %d of queue.conf\n", var->value, var->lineno);
1893                                                         q->roundingseconds=0;
1894                                                 }
1895                                         } else if (!strcasecmp(var->name, "announce-holdtime")) {
1896                                                 q->announceholdtime = (!strcasecmp(var->value,"once")) ? 1 : ast_true(var->value);
1897                                         } else if (!strcasecmp(var->name, "retry")) {
1898                                                 q->retry = atoi(var->value);
1899                                         } else if (!strcasecmp(var->name, "wrapuptime")) {
1900                                                 q->wrapuptime = atoi(var->value);
1901                                         } else if (!strcasecmp(var->name, "maxlen")) {
1902                                                 q->maxlen = atoi(var->value);
1903                                         } else if (!strcasecmp(var->name, "servicelevel")) {
1904                                                 q->servicelevel= atoi(var->value);
1905                                         } else if (!strcasecmp(var->name, "strategy")) {
1906                                                 q->strategy = strat2int(var->value);
1907                                                 if (q->strategy < 0) {
1908                                                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
1909                                                         q->strategy = 0;
1910                                                 }
1911                                         } else if (!strcasecmp(var->name, "joinempty")) {
1912                                                 q->joinempty = ast_true(var->value);
1913                                         } else if (!strcasecmp(var->name, "leavewhenempty")) {
1914                                                 q->leavewhenempty = ast_true(var->value);
1915                                         } else if (!strcasecmp(var->name, "eventwhencalled")) {
1916                                                 q->eventwhencalled = ast_true(var->value);
1917                                         } else if (!strcasecmp(var->name, "reportholdtime")) {
1918                                                 q->reportholdtime = ast_true(var->value);
1919                                         } else {
1920                                                 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
1921                                         }
1922                                         var = var->next;
1923                                 }
1924                                 if (q->retry < 1)
1925                                         q->retry = DEFAULT_RETRY;
1926                                 if (q->timeout < 0)
1927                                         q->timeout = DEFAULT_TIMEOUT;
1928                                 if (q->maxlen < 0)
1929                                         q->maxlen = 0;
1930                                 if (!new) 
1931                                         ast_mutex_unlock(&q->lock);
1932                                 if (new) {
1933                                         q->next = queues;
1934                                         queues = q;
1935                                 }
1936                         }
1937                 }
1938                 cat = ast_category_browse(cfg, cat);
1939         }
1940         ast_destroy(cfg);
1941         q = queues;
1942         ql = NULL;
1943         while(q) {
1944                 qn = q->next;
1945                 if (q->dead) {
1946                         if (ql)
1947                                 ql->next = q->next;
1948                         else
1949                                 queues = q->next;
1950                         if (!q->count) {
1951                                 free(q);
1952                         } else
1953                                 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
1954                 } else
1955                         ql = q;
1956                 q = qn;
1957         }
1958         ast_mutex_unlock(&qlock);
1959 }
1960
1961 static int __queues_show(int fd, int argc, char **argv, int queue_show)
1962 {
1963         struct ast_call_queue *q;
1964         struct queue_ent *qe;
1965         struct member *mem;
1966         int pos;
1967         time_t now;
1968         char max[80] = "";
1969         char calls[80] = "";
1970         float sl = 0;
1971
1972         time(&now);
1973         if ((!queue_show && argc != 2) || (queue_show && argc != 3))
1974                 return RESULT_SHOWUSAGE;
1975         ast_mutex_lock(&qlock);
1976         q = queues;
1977         if (!q) {       
1978                 ast_mutex_unlock(&qlock);
1979                 if (queue_show)
1980                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
1981                 else
1982                         ast_cli(fd, "No queues.\n");
1983                 return RESULT_SUCCESS;
1984         }
1985         while(q) {
1986                 ast_mutex_lock(&q->lock);
1987                 if (queue_show) {
1988                         if (strcasecmp(q->name, argv[2]) != 0) {
1989                                 ast_mutex_unlock(&q->lock);
1990                                 q = q->next;
1991                                 if (!q) {
1992                                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
1993                                         break;
1994                                 }
1995                                 continue;
1996                         }
1997                 }
1998                 if (q->maxlen)
1999                         snprintf(max, sizeof(max), "%d", q->maxlen);
2000                 else
2001                         strncpy(max, "unlimited", sizeof(max) - 1);
2002                 sl = 0;
2003                 if(q->callscompleted > 0)
2004                         sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
2005                 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), C:%d, A:%d, SL:%2.1f%% within %ds\n",
2006                         q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
2007                 if (q->members) {
2008                         ast_cli(fd, "   Members: \n");
2009                         for (mem = q->members; mem; mem = mem->next) {
2010                                 if (mem->penalty)
2011                                         snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
2012                                 else
2013                                         max[0] = '\0';
2014                                 if (mem->dynamic)
2015                                         strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
2016                                 if (mem->calls) {
2017                                         snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
2018                                                         mem->calls, (long)(time(NULL) - mem->lastcall));
2019                                 } else
2020                                         strncpy(calls, " has taken no calls yet", sizeof(calls) - 1);
2021                                 ast_cli(fd, "      %s/%s%s%s\n", mem->tech, mem->loc, max, calls);
2022                         }
2023                 } else
2024                         ast_cli(fd, "   No Members\n");
2025                 if (q->head) {
2026                         pos = 1;
2027                         ast_cli(fd, "   Callers: \n");
2028                         for (qe = q->head; qe; qe = qe->next) 
2029                                 ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)\n", pos++, qe->chan->name,
2030                                                                 (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio);
2031                 } else
2032                         ast_cli(fd, "   No Callers\n");
2033                 ast_cli(fd, "\n");
2034                 ast_mutex_unlock(&q->lock);
2035                 q = q->next;
2036                 if (queue_show)
2037                         break;
2038         }
2039         ast_mutex_unlock(&qlock);
2040         return RESULT_SUCCESS;
2041 }
2042
2043 static int queues_show(int fd, int argc, char **argv)
2044 {
2045         return __queues_show(fd, argc, argv, 0);
2046 }
2047
2048 static int queue_show(int fd, int argc, char **argv)
2049 {
2050         return __queues_show(fd, argc, argv, 1);
2051 }
2052
2053 static char *complete_queue(char *line, char *word, int pos, int state)
2054 {
2055         struct ast_call_queue *q;
2056         int which=0;
2057         
2058         ast_mutex_lock(&qlock);
2059         for (q = queues; q; q = q->next) {
2060                 if (!strncasecmp(word, q->name, strlen(word))) {
2061                         if (++which > state)
2062                                 break;
2063                 }
2064         }
2065         ast_mutex_unlock(&qlock);
2066         return q ? strdup(q->name) : NULL;
2067 }
2068
2069 /* JDG: callback to display queues status in manager */
2070 static int manager_queues_show( struct mansession *s, struct message *m )
2071 {
2072         char *a[] = { "show", "queues" };
2073         return queues_show( s->fd, 2, a );
2074 } /* /JDG */
2075
2076
2077 /* Dump queue status */
2078 static int manager_queues_status( struct mansession *s, struct message *m )
2079 {
2080         time_t now;
2081         int pos;
2082         char *id = astman_get_header(m,"ActionID");
2083         char idText[256] = "";
2084         struct ast_call_queue *q;
2085         struct queue_ent *qe;
2086         float sl = 0;
2087         struct member *mem;
2088         astman_send_ack(s, m, "Queue status will follow");
2089         time(&now);
2090         ast_mutex_lock(&qlock);
2091         if (!ast_strlen_zero(id)) {
2092                 snprintf(idText,256,"ActionID: %s\r\n",id);
2093         }
2094         for (q = queues; q; q = q->next) {
2095                 ast_mutex_lock(&q->lock);
2096
2097                 /* List queue properties */
2098                 if(q->callscompleted > 0)
2099                         sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
2100                 ast_mutex_lock(&s->lock);
2101                 ast_cli(s->fd, "Event: QueueParams\r\n"
2102                                         "Queue: %s\r\n"
2103                                         "Max: %d\r\n"
2104                                         "Calls: %d\r\n"
2105                                         "Holdtime: %d\r\n"
2106                                         "Completed: %d\r\n"
2107                                         "Abandoned: %d\r\n"
2108                                         "ServiceLevel: %d\r\n"
2109                                         "ServicelevelPerf: %2.1f\r\n"
2110                                         "%s"
2111                                         "\r\n",
2112                                                 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
2113                                                 q->callsabandoned, q->servicelevel, sl, idText);
2114
2115                 /* List Queue Members */
2116                 for (mem = q->members; mem; mem = mem->next) 
2117                         ast_cli(s->fd, "Event: QueueMember\r\n"
2118                                 "Queue: %s\r\n"
2119                                 "Location: %s/%s\r\n"
2120                                 "Membership: %s\r\n"
2121                                 "Penalty: %d\r\n"
2122                                 "CallsTaken: %d\r\n"
2123                                 "LastCall: %ld\r\n"
2124                                 "%s"
2125                                 "\r\n",
2126                                         q->name, mem->tech, mem->loc, mem->dynamic ? "dynamic" : "static",
2127                                         mem->penalty, mem->calls, mem->lastcall, idText);
2128
2129                 /* List Queue Entries */
2130
2131                 pos = 1;
2132                 for (qe = q->head; qe; qe = qe->next) 
2133                         ast_cli(s->fd, "Event: QueueEntry\r\n"
2134                                 "Queue: %s\r\n"
2135                                 "Position: %d\r\n"
2136                                 "Channel: %s\r\n"
2137                                 "CallerID: %s\r\n"
2138                                 "CallerIDName: %s\r\n"
2139                                 "Wait: %ld\r\n"
2140                                 "%s"
2141                                 "\r\n", 
2142                                         q->name, pos++, qe->chan->name, 
2143                                         qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
2144                                         qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
2145                                         (long)(now - qe->start), idText);
2146                 ast_mutex_unlock(&s->lock);
2147                 ast_mutex_unlock(&q->lock);
2148         }
2149         ast_mutex_unlock(&qlock);
2150         return RESULT_SUCCESS;
2151 }
2152
2153 static int manager_add_queue_member(struct mansession *s, struct message *m)
2154 {
2155         char *queuename, *interface, *penalty_s;
2156         int penalty = 0;
2157
2158         queuename = astman_get_header(m, "Queue");
2159         interface = astman_get_header(m, "Interface");
2160         penalty_s = astman_get_header(m, "Penalty");
2161
2162         if (ast_strlen_zero(queuename)) {
2163                 astman_send_error(s, m, "'Queue' not specified.");
2164                 return 0;
2165         }
2166
2167         if (ast_strlen_zero(interface)) {
2168                 astman_send_error(s, m, "'Interface' not specified.");
2169                 return 0;
2170         }
2171
2172         if (ast_strlen_zero(penalty_s))
2173                 penalty = 0;
2174         else if (sscanf(penalty_s, "%d", &penalty) != 1) {
2175                 penalty = 0;
2176         }
2177
2178         switch (add_to_queue(queuename, interface, penalty)) {
2179         case RES_OKAY:
2180                 astman_send_ack(s, m, "Added interface to queue");
2181                 break;
2182         case RES_EXISTS:
2183                 astman_send_error(s, m, "Unable to add interface: Already there");
2184                 break;
2185         case RES_NOSUCHQUEUE:
2186                 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
2187                 break;
2188         case RES_OUTOFMEMORY:
2189                 astman_send_error(s, m, "Out of memory");
2190                 break;
2191         }
2192         return 0;
2193 }
2194
2195 static int manager_remove_queue_member(struct mansession *s, struct message *m)
2196 {
2197         char *queuename, *interface;
2198
2199         queuename = astman_get_header(m, "Queue");
2200         interface = astman_get_header(m, "Interface");
2201
2202         if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
2203                 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
2204                 return 0;
2205         }
2206
2207         switch (remove_from_queue(queuename, interface)) {
2208         case RES_OKAY:
2209                 astman_send_ack(s, m, "Removed interface from queue");
2210                 break;
2211         case RES_EXISTS:
2212                 astman_send_error(s, m, "Unable to remove interface: Not there");
2213                 break;
2214         case RES_NOSUCHQUEUE:
2215                 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
2216                 break;
2217         case RES_OUTOFMEMORY:
2218                 astman_send_error(s, m, "Out of memory");
2219                 break;
2220         }
2221         return 0;
2222 }
2223
2224 static int handle_add_queue_member(int fd, int argc, char *argv[])
2225 {
2226         char *queuename, *interface;
2227         int penalty;
2228
2229         if ((argc != 6) && (argc != 8)) {
2230                 return RESULT_SHOWUSAGE;
2231         } else if (strcmp(argv[4], "to")) {
2232                 return RESULT_SHOWUSAGE;
2233         } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
2234                 return RESULT_SHOWUSAGE;
2235         }
2236
2237         queuename = argv[5];
2238         interface = argv[3];
2239         if (argc == 8) {
2240                 if (sscanf(argv[7], "%d", &penalty) == 1) {
2241                         if (penalty < 0) {
2242                                 ast_cli(fd, "Penalty must be >= 0\n");
2243                                 penalty = 0;
2244                         }
2245                 } else {
2246                         ast_cli(fd, "Penalty must be an integer >= 0\n");
2247                         penalty = 0;
2248                 }
2249         } else {
2250                 penalty = 0;
2251         }
2252
2253         switch (add_to_queue(queuename, interface, penalty)) {
2254         case RES_OKAY:
2255                 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
2256                 return RESULT_SUCCESS;
2257         case RES_EXISTS:
2258                 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2259                 return RESULT_FAILURE;
2260         case RES_NOSUCHQUEUE:
2261                 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
2262                 return RESULT_FAILURE;
2263         case RES_OUTOFMEMORY:
2264                 ast_cli(fd, "Out of memory\n");
2265                 return RESULT_FAILURE;
2266         default:
2267                 return RESULT_FAILURE;
2268         }
2269 }
2270
2271 static char *complete_add_queue_member(char *line, char *word, int pos, int state)
2272 {
2273         /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty> */
2274         switch (pos) {
2275         case 3:
2276                 /* Don't attempt to complete name of member (infinite possibilities) */
2277                 return NULL;
2278         case 4:
2279                 if (state == 0) {
2280                         return strdup("to");
2281                 } else {
2282                         return NULL;
2283                 }
2284         case 5:
2285                 /* No need to duplicate code */
2286                 return complete_queue(line, word, pos, state);
2287         case 6:
2288                 if (state == 0) {
2289                         return strdup("penalty");
2290                 } else {
2291                         return NULL;
2292                 }
2293         case 7:
2294                 if (state < 100) {      /* 0-99 */
2295                         char *num = malloc(3);
2296                         if (num) {
2297                                 sprintf(num, "%d", state);
2298                         }
2299                         return num;
2300                 } else {
2301                         return NULL;
2302                 }
2303         default:
2304                 return NULL;
2305         }
2306 }
2307
2308 static int handle_remove_queue_member(int fd, int argc, char *argv[])
2309 {
2310         char *queuename, *interface;
2311
2312         if (argc != 6) {
2313                 return RESULT_SHOWUSAGE;
2314         } else if (strcmp(argv[4], "from")) {
2315                 return RESULT_SHOWUSAGE;
2316         }
2317
2318         queuename = argv[5];
2319         interface = argv[3];
2320
2321         switch (remove_from_queue(queuename, interface)) {
2322         case RES_OKAY:
2323                 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2324                 return RESULT_SUCCESS;
2325         case RES_EXISTS:
2326                 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2327                 return RESULT_FAILURE;
2328         case RES_NOSUCHQUEUE:
2329                 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2330                 return RESULT_FAILURE;
2331         case RES_OUTOFMEMORY:
2332                 ast_cli(fd, "Out of memory\n");
2333                 return RESULT_FAILURE;
2334         default:
2335                 return RESULT_FAILURE;
2336         }
2337 }
2338
2339 static char *complete_remove_queue_member(char *line, char *word, int pos, int state)
2340 {
2341         int which = 0;
2342         struct ast_call_queue *q;
2343         struct member *m;
2344
2345         /* 0 - add; 1 - queue; 2 - member; 3 - <member>; 4 - to; 5 - <queue> */
2346         if ((pos > 5) || (pos < 3)) {
2347                 return NULL;
2348         }
2349         if (pos == 4) {
2350                 if (state == 0) {
2351                         return strdup("from");
2352                 } else {
2353                         return NULL;
2354                 }
2355         }
2356
2357         if (pos == 5) {
2358                 /* No need to duplicate code */
2359                 return complete_queue(line, word, pos, state);
2360         }
2361
2362         if (queues != NULL) {
2363                 for (q = queues ; q ; q = q->next) {
2364                         ast_mutex_lock(&q->lock);
2365                         for (m = q->members ; m ; m = m->next) {
2366                                 if (++which > state) {
2367                                         char *tmp = malloc(strlen(m->tech) + strlen(m->loc) + 2);
2368                                         if (tmp) {
2369                                                 sprintf(tmp, "%s/%s", m->tech, m->loc);
2370                                         } else {
2371                                                 ast_log(LOG_ERROR, "Out of memory\n");
2372                                         }
2373                                         ast_mutex_unlock(&q->lock);
2374                                         return tmp;
2375                                 }
2376                         }
2377                         ast_mutex_unlock(&q->lock);
2378                 }
2379         }
2380         return NULL;
2381 }
2382
2383 static char show_queues_usage[] = 
2384 "Usage: show queues\n"
2385 "       Provides summary information on call queues.\n";
2386
2387 static struct ast_cli_entry cli_show_queues = {
2388         { "show", "queues", NULL }, queues_show, 
2389         "Show status of queues", show_queues_usage, NULL };
2390
2391 static char show_queue_usage[] = 
2392 "Usage: show queue\n"
2393 "       Provides summary information on a specified queue.\n";
2394
2395 static struct ast_cli_entry cli_show_queue = {
2396         { "show", "queue", NULL }, queue_show, 
2397         "Show status of a specified queue", show_queue_usage, complete_queue };
2398
2399 static char aqm_cmd_usage[] =
2400 "Usage: add queue member <channel> to <queue> [penalty <penalty>]\n";
2401
2402 static struct ast_cli_entry cli_add_queue_member = {
2403         { "add", "queue", "member", NULL }, handle_add_queue_member,
2404         "Add a channel to a specified queue", aqm_cmd_usage, complete_add_queue_member };
2405
2406 static char rqm_cmd_usage[] =
2407 "Usage: remove queue member <channel> from <queue>\n";
2408
2409 static struct ast_cli_entry cli_remove_queue_member = {
2410         { "remove", "queue", "member", NULL }, handle_remove_queue_member,
2411         "Removes a channel from a specified queue", rqm_cmd_usage, complete_remove_queue_member };
2412
2413 int unload_module(void)
2414 {
2415         STANDARD_HANGUP_LOCALUSERS;
2416         ast_cli_unregister(&cli_show_queue);
2417         ast_cli_unregister(&cli_show_queues);
2418         ast_cli_unregister(&cli_add_queue_member);
2419         ast_cli_unregister(&cli_remove_queue_member);
2420         ast_manager_unregister("Queues");
2421         ast_manager_unregister("QueueStatus");
2422         ast_manager_unregister("QueueAdd");
2423         ast_manager_unregister("QueueRemove");
2424         ast_unregister_application(app_aqm);
2425         ast_unregister_application(app_rqm);
2426         return ast_unregister_application(app);
2427 }
2428
2429 int load_module(void)
2430 {
2431         int res;
2432         res = ast_register_application(app, queue_exec, synopsis, descrip);
2433         if (!res) {
2434                 ast_cli_register(&cli_show_queue);
2435                 ast_cli_register(&cli_show_queues);
2436                 ast_cli_register(&cli_add_queue_member);
2437                 ast_cli_register(&cli_remove_queue_member);
2438                 ast_manager_register( "Queues", 0, manager_queues_show, "Queues" );
2439                 ast_manager_register( "QueueStatus", 0, manager_queues_status, "Queue Status" );
2440                 ast_manager_register( "QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue." );
2441                 ast_manager_register( "QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue." );
2442                 ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;
2443                 ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ;
2444         }
2445         reload_queues();
2446         return res;
2447 }
2448
2449
2450 int reload(void)
2451 {
2452         reload_queues();
2453         return 0;
2454 }
2455
2456 char *description(void)
2457 {
2458         return tdesc;
2459 }
2460
2461 int usecount(void)
2462 {
2463         int res;
2464         STANDARD_USECOUNT(res);
2465         return res;
2466 }
2467
2468 char *key()
2469 {
2470         return ASTERISK_GPL_KEY;
2471 }