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