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