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