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