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