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