Make the go_on be non-global.
[asterisk/asterisk.git] / apps / app_queue.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * True call queues with optional send URL on answer
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <asterisk/lock.h>
15 #include <asterisk/file.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/pbx.h>
19 #include <asterisk/options.h>
20 #include <asterisk/module.h>
21 #include <asterisk/translate.h>
22 #include <asterisk/say.h>
23 #include <asterisk/parking.h>
24 #include <asterisk/musiconhold.h>
25 #include <asterisk/cli.h>
26 #include <asterisk/manager.h> /* JDG */
27 #include <asterisk/config.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <sys/time.h>
35 #include <sys/signal.h>
36 #include <netinet/in.h>
37
38 #include <pthread.h>
39
40 #define QUEUE_STRATEGY_RINGALL          0
41 #define QUEUE_STRATEGY_ROUNDROBIN       1
42 #define QUEUE_STRATEGY_LEASTRECENT      2
43 #define QUEUE_STRATEGY_FEWESTCALLS      3
44 #define QUEUE_STRATEGY_RANDOM           4
45
46 static struct strategy {
47         int strategy;
48         char *name;
49 } strategies[] = {
50         { QUEUE_STRATEGY_RINGALL, "ringall" },
51         { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
52         { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
53         { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
54         { QUEUE_STRATEGY_RANDOM, "random" },
55 };
56
57 #define DEFAULT_RETRY           5
58 #define DEFAULT_TIMEOUT         15
59 #define RECHECK                         1               /* Recheck every second to see we we're at the top yet */
60
61 static char *tdesc = "True Call Queueing";
62
63 static char *app = "Queue";
64
65 static char *synopsis = "Queue a call for a call queue";
66
67 static char *descrip =
68 "  Queue(queuename[|options[|URL][|announceoverride]]):\n"
69 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
70 "  This application returns -1 if the originating channel hangs up, or if the\n"
71 "call is bridged and  either of the parties in the bridge terminate the call.\n"
72 "Returns 0 if the queue is full, nonexistant, or has no members.\n"
73 "The option string may contain zero or more of the following characters:\n"
74 "      't' -- allow the called user transfer the calling user\n"
75 "      'T' -- to allow the calling user to transfer the call.\n"
76 "      'd' -- data-quality (modem) call (minimum delay).\n"
77 "      'H' -- allow caller to hang up by hitting *.\n"
78 "      'n' -- no retries on the timeout; will exit this application and go to the next step.\n"
79 "  In addition to transferring the call, a call may be parked and then picked\n"
80 "up by another user.\n"
81 "  The optionnal URL will be sent to the called party if the channel supports\n"
82 "it.\n";
83
84 // [PHM 06/26/03]
85 static char *app_aqm = "AddQueueMember" ;
86 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
87 static char *app_aqm_descrip =
88 "   AddQueueMember(queuename[|interface]):\n"
89 "Dynamically adds interface to an existing queue\n"
90 "Returns -1 if there is an error.\n"
91 "Example: AddQueueMember(techsupport|SIP/3000)\n"
92 "";
93
94 static char *app_rqm = "RemoveQueueMember" ;
95 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
96 static char *app_rqm_descrip =
97 "   RemoveQueueMember(queuename[|interface]):\n"
98 "Dynamically removes interface to an existing queue\n"
99 "Returns -1 if there is an error.\n"
100 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
101 "";
102
103 /* We define a customer "local user" structure because we
104    use it not only for keeping track of what is in use but
105    also for keeping track of who we're dialing. */
106
107 struct localuser {
108         struct ast_channel *chan;
109         char numsubst[256];
110         char tech[40];
111         int stillgoing;
112         int metric;
113         int allowredirect_in;
114         int allowredirect_out;
115         int ringbackonly;
116         int musiconhold;
117         int dataquality;
118         int allowdisconnect;
119         struct member *member;
120         struct localuser *next;
121 };
122
123 LOCAL_USER_DECL;
124
125 struct queue_ent {
126         struct ast_call_queue *parent;  /* What queue is our parent */
127         char moh[80];                           /* Name of musiconhold to be used */
128         char announce[80];              /* Announcement to play */
129         char context[80];               /* Context when user exits queue */
130         int pos;                                        /* Where we are in the queue */
131         time_t start;                           /* When we started holding */
132         struct ast_channel *chan;       /* Our channel */
133         struct queue_ent *next;         /* The next queue entry */
134 };
135
136 struct member {
137         char tech[80];                          /* Technology */
138         char loc[256];                          /* Location */
139         int penalty;                            /* Are we a last resort? */
140         int calls;
141         int dynamic;                            /* Are we dynamically added? */
142         time_t lastcall;        /* When last successful call was hungup */
143         struct member *next;            /* Next member */
144 };
145
146 struct ast_call_queue {
147         ast_mutex_t     lock;   
148         char name[80];                  /* Name of the queue */
149         char moh[80];                   /* Name of musiconhold to be used */
150         char announce[80];              /* Announcement to play */
151         char context[80];               /* Announcement to play */
152         int strategy;                   /* Queueing strategy */
153         int announcetimeout;    /* How often to announce their position */
154         int count;                              /* How many entries are in the queue */
155         int maxlen;                             /* Max number of entries in queue */
156
157         int dead;                               /* Whether this queue is dead or not */
158         int retry;                              /* Retry calling everyone after this amount of time */
159         int timeout;                    /* How long to wait for an answer */
160         
161         /* Queue strategy things */
162         
163         int rrpos;                              /* Round Robin - position */
164         int wrapped;                    /* Round Robin - wrapped around? */
165
166         struct member *members; /* Member channels to be tried */
167         struct queue_ent *head; /* Start of the actual queue */
168         struct ast_call_queue *next;    /* Next call queue */
169 };
170
171 static struct ast_call_queue *queues = NULL;
172 static ast_mutex_t qlock = AST_MUTEX_INITIALIZER;
173
174 static char *int2strat(int strategy)
175 {
176         int x;
177         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
178                 if (strategy == strategies[x].strategy)
179                         return strategies[x].name;
180         }
181         return "<unknown>";
182 }
183
184 static int strat2int(char *strategy)
185 {
186         int x;
187         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
188                 if (!strcasecmp(strategy, strategies[x].name))
189                         return strategies[x].strategy;
190         }
191         return -1;
192 }
193
194 static int join_queue(char *queuename, struct queue_ent *qe)
195 {
196         struct ast_call_queue *q;
197         struct queue_ent *cur, *prev = NULL;
198         int res = -1;
199         int pos = 0;
200         ast_mutex_lock(&qlock);
201         q = queues;
202         while(q) {
203                 if (!strcasecmp(q->name, queuename)) {
204                         /* This is our one */
205                         ast_mutex_lock(&q->lock);
206                         if (q->members && (!q->maxlen || (q->count < q->maxlen))) {
207                                 /* There's space for us, put us at the end */
208                                 prev = NULL;
209                                 cur = q->head;
210                                 while(cur) {
211                                         cur->pos = ++pos;
212                                         prev = cur;
213                                         cur = cur->next;
214                                 }
215                                 if (prev)
216                                         prev->next = qe;
217                                 else
218                                         q->head = qe;
219                                 /* Fix additional pointers and
220                                   information  */
221                                 qe->next = NULL;
222                                 qe->parent = q;
223                                 qe->pos = ++pos;
224                                 strncpy(qe->moh, q->moh, sizeof(qe->moh));
225                                 strncpy(qe->announce, q->announce, sizeof(qe->announce));
226                                 strncpy(qe->context, q->context, sizeof(qe->context));
227                                 q->count++;
228                                 res = 0;
229                                 manager_event(EVENT_FLAG_CALL, "Join", 
230                                                                 "Channel: %s\r\nCallerID: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
231                                                                 qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : "unknown"), q->name, qe->pos, q->count );
232 #if 0
233 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
234 #endif
235                         }
236                         ast_mutex_unlock(&q->lock);
237                         break;
238                 }
239                 q = q->next;
240         }
241         ast_mutex_unlock(&qlock);
242         return res;
243 }
244
245 static void free_members(struct ast_call_queue *q, int all)
246 {
247         /* Free non-dynamic members */
248         struct member *curm, *next, *prev;
249         curm = q->members;
250         prev = NULL;
251         while(curm) {
252                 next = curm->next;
253                 if (all || !curm->dynamic) {
254                         if (prev)
255                                 prev->next = next;
256                         else
257                                 q->members = next;
258                         free(curm);
259                 } else 
260                         prev = curm;
261                 curm = next;
262         }
263 }
264
265 static void destroy_queue(struct ast_call_queue *q)
266 {
267         struct ast_call_queue *cur, *prev = NULL;
268         ast_mutex_lock(&qlock);
269         cur = queues;
270         while(cur) {
271                 if (cur == q) {
272                         if (prev)
273                                 prev->next = cur->next;
274                         else
275                                 queues = cur->next;
276                 } else {
277                         prev = cur;
278                 }
279                 cur = cur->next;
280         }
281         ast_mutex_unlock(&qlock);
282         free_members(q, 1);
283         free(q);
284 }
285
286 static void leave_queue(struct queue_ent *qe)
287 {
288         struct ast_call_queue *q;
289         struct queue_ent *cur, *prev = NULL;
290         int pos = 0;
291         q = qe->parent;
292         if (!q)
293                 return;
294         ast_mutex_lock(&q->lock);
295
296         prev = NULL;
297         cur = q->head;
298         while(cur) {
299                 if (cur == qe) {
300                         q->count--;
301
302                         /* Take us out of the queue */
303                         manager_event(EVENT_FLAG_CALL, "Leave",
304                                  "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
305                                  qe->chan->name, q->name,  q->count);
306 #if 0
307 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
308 #endif
309                         /* Take us out of the queue */
310                         if (prev)
311                                 prev->next = cur->next;
312                         else
313                                 q->head = cur->next;
314                 } else {
315                         cur->pos = ++pos;
316                         prev = cur;
317                 }
318                 cur = cur->next;
319         }
320         ast_mutex_unlock(&q->lock);
321         if (q->dead && !q->count) {     
322                 /* It's dead and nobody is in it, so kill it */
323                 destroy_queue(q);
324         }
325 }
326
327 static void hanguptree(struct localuser *outgoing, struct ast_channel *exception)
328 {
329         /* Hang up a tree of stuff */
330         struct localuser *oo;
331         while(outgoing) {
332                 /* Hangup any existing lines we have open */
333                 if (outgoing->chan && (outgoing->chan != exception))
334                         ast_hangup(outgoing->chan);
335                 oo = outgoing;
336                 outgoing=outgoing->next;
337                 free(oo);
338         }
339 }
340
341 static int ring_entry(struct queue_ent *qe, struct localuser *tmp)
342 {
343         int res;
344         /* Request the peer */
345         tmp->chan = ast_request(tmp->tech, qe->chan->nativeformats, tmp->numsubst);
346         if (!tmp->chan) {                       /* If we can't, just go on to the next call */
347 #if 0
348                 ast_log(LOG_NOTICE, "Unable to create channel of type '%s'\n", cur->tech);
349 #endif                  
350                 if (qe->chan->cdr)
351                         ast_cdr_busy(qe->chan->cdr);
352                 tmp->stillgoing = 0;
353                 return 0;
354         }
355         tmp->chan->appl = "AppQueue";
356         tmp->chan->data = "(Outgoing Line)";
357         tmp->chan->whentohangup = 0;
358         if (tmp->chan->callerid)
359                 free(tmp->chan->callerid);
360         if (tmp->chan->ani)
361                 free(tmp->chan->ani);
362         if (qe->chan->callerid)
363                 tmp->chan->callerid = strdup(qe->chan->callerid);
364         else
365                 tmp->chan->callerid = NULL;
366         if (qe->chan->ani)
367                 tmp->chan->ani = strdup(qe->chan->ani);
368         else
369                 tmp->chan->ani = NULL;
370         /* Presense of ADSI CPE on outgoing channel follows ours */
371         tmp->chan->adsicpe = qe->chan->adsicpe;
372         /* Place the call, but don't wait on the answer */
373         res = ast_call(tmp->chan, tmp->numsubst, 0);
374         if (res) {
375                 /* Again, keep going even if there's an error */
376                 if (option_debug)
377                         ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
378                 else if (option_verbose > 2)
379                         ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->numsubst);
380                 ast_hangup(tmp->chan);
381                 tmp->chan = NULL;
382                 tmp->stillgoing = 0;
383                 return 0;
384         } else
385                 if (option_verbose > 2)
386                         ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->numsubst);
387         return 0;
388 }
389
390 static int ring_one(struct queue_ent *qe, struct localuser *outgoing)
391 {
392         struct localuser *cur;
393         struct localuser *best;
394         int bestmetric=0;
395         do {
396                 best = NULL;
397                 cur = outgoing;
398                 while(cur) {
399                         if (cur->stillgoing &&                                                  /* Not already done */
400                                 !cur->chan &&                                                           /* Isn't already going */
401                                 (!best || (cur->metric < bestmetric))) {        /* We haven't found one yet, or it's better */
402                                         bestmetric = cur->metric;
403                                         best = cur;
404                         }
405                         cur = cur->next;
406                 }
407                 if (best) {
408                         if (!qe->parent->strategy) {
409                                 /* Ring everyone who shares this best metric (for ringall) */
410                                 cur = outgoing;
411                                 while(cur) {
412                                         if (cur->stillgoing && !cur->chan && (cur->metric == bestmetric)) {
413                                                 ast_log(LOG_DEBUG, "(Parallel) Trying '%s/%s' with metric %d\n", cur->tech, cur->numsubst, cur->metric);
414                                                 ring_entry(qe, cur);
415                                         }
416                                         cur = cur->next;
417                                 }
418                         } else {
419                                 /* Ring just the best channel */
420                                 ast_log(LOG_DEBUG, "Trying '%s/%s' with metric %d\n", best->tech, best->numsubst, best->metric);
421                                 ring_entry(qe, best);
422                         }
423                 }
424         } while (best && !best->chan);
425         if (!best) {
426                 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
427                 return 0;
428         }
429         return 1;
430 }
431
432 static int valid_exit(struct queue_ent *qe, char digit)
433 {
434         char tmp[2];
435         if (!strlen(qe->context))
436                 return 0;
437         tmp[0] = digit;
438         tmp[1] = '\0';
439         if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->callerid)) {
440                 strncpy(qe->chan->context, qe->context, sizeof(qe->chan->context) - 1);
441                 strncpy(qe->chan->exten, tmp, sizeof(qe->chan->exten) - 1);
442                 qe->chan->priority = 0;
443                 return 1;
444         }
445         return 0;
446 }
447
448 #define MAX 256
449
450 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, int *allowredir_in, int *allowredir_out, int *allowdisconnect, char *digit)
451 {
452         char *queue = qe->parent->name;
453         struct localuser *o;
454         int found;
455         int numlines;
456         int sentringing = 0;
457         int numbusies = 0;
458         int orig = *to;
459         struct ast_frame *f;
460         struct localuser *peer = NULL;
461         struct ast_channel *watchers[MAX];
462         int pos;
463         struct ast_channel *winner;
464         struct ast_channel *in = qe->chan;
465         
466         while(*to && !peer) {
467                 o = outgoing;
468                 found = -1;
469                 pos = 1;
470                 numlines = 0;
471                 watchers[0] = in;
472                 while(o) {
473                         /* Keep track of important channels */
474                         if (o->stillgoing && o->chan) {
475                                 watchers[pos++] = o->chan;
476                                 found = 1;
477                         }
478                         o = o->next;
479                         numlines++;
480                 }
481                 if (found < 0) {
482                         if (numlines == numbusies) {
483                                 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
484                         } else {
485                                 ast_log(LOG_NOTICE, "No one is answered queue %s\n", queue);
486                         }
487                         *to = 0;
488                         return NULL;
489                 }
490                 winner = ast_waitfor_n(watchers, pos, to);
491                 o = outgoing;
492                 while(o) {
493                         if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
494                                 if (!peer) {
495                                         if (option_verbose > 2)
496                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
497                                         peer = o;
498                                         *allowredir_in = o->allowredirect_in;
499                                         *allowredir_out = o->allowredirect_out;
500                                         *allowdisconnect = o->allowdisconnect;
501                                 }
502                         } else if (o->chan && (o->chan == winner)) {
503                                 f = ast_read(winner);
504                                 if (f) {
505                                         if (f->frametype == AST_FRAME_CONTROL) {
506                                                 switch(f->subclass) {
507                                             case AST_CONTROL_ANSWER:
508                                                         /* This is our guy if someone answered. */
509                                                         if (!peer) {
510                                                                 if (option_verbose > 2)
511                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
512                                                                 peer = o;
513                                                                 *allowredir_in = o->allowredirect_in;
514                                                                 *allowredir_out = o->allowredirect_out;
515                                                                 *allowdisconnect = o->allowdisconnect;
516                                                         }
517                                                         break;
518                                                 case AST_CONTROL_BUSY:
519                                                         if (option_verbose > 2)
520                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
521                                                         o->stillgoing = 0;
522                                                         if (in->cdr)
523                                                                 ast_cdr_busy(in->cdr);
524                                                         ast_hangup(o->chan);
525                                                         o->chan = NULL;
526                                                         if (qe->parent->strategy)
527                                                                 ring_one(qe, outgoing);
528                                                         numbusies++;
529                                                         break;
530                                                 case AST_CONTROL_CONGESTION:
531                                                         if (option_verbose > 2)
532                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
533                                                         o->stillgoing = 0;
534                                                         if (in->cdr)
535                                                                 ast_cdr_busy(in->cdr);
536                                                         ast_hangup(o->chan);
537                                                         o->chan = NULL;
538                                                         if (qe->parent->strategy)
539                                                                 ring_one(qe, outgoing);
540                                                         numbusies++;
541                                                         break;
542                                                 case AST_CONTROL_RINGING:
543                                                         if (option_verbose > 2)
544                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
545                                                         if (!sentringing) {
546 #if 0
547                                                                 ast_indicate(in, AST_CONTROL_RINGING);
548 #endif                                                          
549                                                                 sentringing++;
550                                                         }
551                                                         break;
552                                                 case AST_CONTROL_OFFHOOK:
553                                                         /* Ignore going off hook */
554                                                         break;
555                                                 default:
556                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
557                                                 }
558                                         }
559                                         ast_frfree(f);
560                                 } else {
561                                         o->stillgoing = 0;
562                                         ast_hangup(o->chan);
563                                         o->chan = NULL;
564                                         if (qe->parent->strategy)
565                                                 ring_one(qe, outgoing);
566                                 }
567                         }
568                         o = o->next;
569                 }
570                 if (winner == in) {
571                         f = ast_read(in);
572 #if 0
573                         if (f && (f->frametype != AST_FRAME_VOICE))
574                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
575                         else if (!f || (f->frametype != AST_FRAME_VOICE))
576                                 printf("Hangup received on %s\n", in->name);
577 #endif
578                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
579                                 /* Got hung up */
580                                 *to=-1;
581                                 return NULL;
582                         }
583                         if (f && (f->frametype == AST_FRAME_DTMF) && allowdisconnect && (f->subclass == '*')) {
584                             if (option_verbose > 3)
585                                 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
586                                 *to=0;
587                                 return NULL;
588                         }
589                         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
590                                 if (option_verbose > 3)
591                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
592                                 *to=0;
593                                 *digit=f->subclass;
594                                 return NULL;
595                         }
596                 }
597                 if (!*to && (option_verbose > 2))
598                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
599         }
600
601         return peer;
602         
603 }
604
605 static int wait_our_turn(struct queue_ent *qe)
606 {
607         struct queue_ent *ch;
608         int res = 0;
609         for (;;) {
610                 /* Atomically read the parent head -- does not need a lock */
611                 ch = qe->parent->head;
612                 /* If we are now at the top of the head, break out */
613                 if (qe->parent->head == qe)
614                         break;
615                 /* Wait a second before checking again */
616                 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
617                 if (res)
618                         break;
619         }
620         return res;
621 }
622
623 static int update_queue(struct ast_call_queue *q, struct localuser *user)
624 {
625         struct member *cur;
626         /* Since a reload could have taken place, we have to traverse the list to
627                 be sure it's still valid */
628         ast_mutex_lock(&q->lock);
629         cur = q->members;
630         while(cur) {
631                 if (user->member == cur) {
632                         time(&cur->lastcall);
633                         cur->calls++;
634                         break;
635                 }
636                 cur = cur->next;
637         }
638         ast_mutex_unlock(&q->lock);
639         return 0;
640 }
641
642 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
643 {
644         switch (q->strategy) {
645         case QUEUE_STRATEGY_RINGALL:
646                 /* Everyone equal, except for penalty */
647                 tmp->metric = mem->penalty * 1000000;
648                 break;
649         case QUEUE_STRATEGY_ROUNDROBIN:
650                 if (!pos) {
651                         if (!q->wrapped) {
652                                 /* No more channels, start over */
653                                 q->rrpos = 0;
654                         } else {
655                                 /* Prioritize next entry */
656                                 q->rrpos++;
657                         }
658                         q->wrapped = 0;
659                 }
660                 if (pos < q->rrpos) {
661                         tmp->metric = 1000 + pos;
662                 } else {
663                         if (pos > q->rrpos) {
664                                 /* Indicate there is another priority */
665                                 q->wrapped = 1;
666                         }
667                         tmp->metric = pos;
668                 }
669                 tmp->metric += mem->penalty * 1000000;
670                 break;
671         case QUEUE_STRATEGY_RANDOM:
672                 tmp->metric = rand() % 1000;
673                 tmp->metric += mem->penalty * 1000000;
674                 break;
675         case QUEUE_STRATEGY_FEWESTCALLS:
676                 tmp->metric = mem->calls;
677                 tmp->metric += mem->penalty * 1000000;
678                 break;
679         case QUEUE_STRATEGY_LEASTRECENT:
680                 if (!mem->lastcall)
681                         tmp->metric = 0;
682                 else
683                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
684                 tmp->metric += mem->penalty * 1000000;
685                 break;
686         default:
687                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
688                 break;
689         }
690         return 0;
691 }
692
693 static int try_calling(struct queue_ent *qe, char *options, char *announceoverride, char *url, int *go_on)
694 {
695         struct member *cur;
696         struct localuser *outgoing=NULL, *tmp = NULL;
697         int to;
698         int allowredir_in=0;
699         int allowredir_out=0;
700         int allowdisconnect=0;
701         char restofit[AST_MAX_EXTENSION];
702         char *newnum;
703         struct ast_channel *peer;
704         struct localuser *lpeer;
705         int res = 0, bridge = 0;
706         int zapx = 2;
707         int x=0;
708         char *announce = NULL;
709         char digit = 0;
710         /* Hold the lock while we setup the outgoing calls */
711         ast_mutex_lock(&qe->parent->lock);
712         cur = qe->parent->members;
713         if (strlen(qe->announce))
714                 announce = qe->announce;
715         if (announceoverride && strlen(announceoverride))
716                 announce = announceoverride;
717         while(cur) {
718                 /* Get a technology/[device:]number pair */
719                 tmp = malloc(sizeof(struct localuser));
720                 if (!tmp) {
721                         ast_mutex_unlock(&qe->parent->lock);
722                         ast_log(LOG_WARNING, "Out of memory\n");
723                         goto out;
724                 }
725                 memset(tmp, 0, sizeof(struct localuser));
726                 tmp->stillgoing = -1;
727                 if (options) {
728                         if (strchr(options, 't'))
729                                 tmp->allowredirect_in = 1;
730                         if (strchr(options, 'T'))
731                                 tmp->allowredirect_out = 1;
732                         if (strchr(options, 'r'))
733                                 tmp->ringbackonly = 1;
734                         if (strchr(options, 'm'))
735                                 tmp->musiconhold = 1;
736                         if (strchr(options, 'd'))
737                                 tmp->dataquality = 1;
738                         if (strchr(options, 'H'))
739                                 tmp->allowdisconnect = 1;
740                         if (strchr(options, 'n'))
741                                 *go_on = 1;
742                 }
743                 if (url) {
744                         ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
745                 } else 
746                         ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
747
748                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
749                 strncpy(tmp->tech, cur->tech, sizeof(tmp->tech)-1);
750                 strncpy(tmp->numsubst, cur->loc, sizeof(tmp->numsubst)-1);
751                 /* If we're dialing by extension, look at the extension to know what to dial */
752                 if ((newnum = strstr(tmp->numsubst, "BYEXTENSION"))) {
753                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit)-1);
754                         snprintf(newnum, sizeof(tmp->numsubst) - (newnum - tmp->numsubst), "%s%s", qe->chan->exten,restofit);
755                         if (option_debug)
756                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->numsubst);
757                 }
758                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
759                    just calculate their metric for the appropriate strategy */
760                 calc_metric(qe->parent, cur, x++, qe, tmp);
761                 /* Put them in the list of outgoing thingies...  We're ready now. 
762                    XXX If we're forcibly removed, these outgoing calls won't get
763                    hung up XXX */
764                 tmp->next = outgoing;
765                 outgoing = tmp;         
766                 /* If this line is up, don't try anybody else */
767                 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
768                         break;
769
770                 cur = cur->next;
771         }
772         if (qe->parent->timeout)
773                 to = qe->parent->timeout * 1000;
774         else
775                 to = -1;
776         ring_one(qe, outgoing);
777         ast_mutex_unlock(&qe->parent->lock);
778         lpeer = wait_for_answer(qe, outgoing, &to, &allowredir_in, &allowredir_out, &allowdisconnect, &digit);
779         if (lpeer)
780                 peer = lpeer->chan;
781         else
782                 peer = NULL;
783         if (!peer) {
784                 if (to) {
785                         /* Musta gotten hung up */
786                         res = -1;
787                 } else {
788                         if (digit && valid_exit(qe, digit))
789                                 res=digit;
790                         else
791                                 /* Nobody answered, next please? */
792                                 res=0;
793                 }
794                 goto out;
795         }
796         if (peer) {
797                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
798                    we will always return with -1 so that it is hung up properly after the 
799                    conversation.  */
800                 if (!strcmp(qe->chan->type,"Zap")) {
801                         if (tmp->dataquality) zapx = 0;
802                         ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
803                 }                       
804                 if (!strcmp(peer->type,"Zap")) {
805                         if (tmp->dataquality) zapx = 0;
806                         ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
807                 }
808                 /* Update parameters for the queue */
809                 update_queue(qe->parent, lpeer);
810                 hanguptree(outgoing, peer);
811                 /* Stop music on hold */
812                 ast_moh_stop(qe->chan);
813                 outgoing = NULL;
814                 if (announce) {
815                         int res2;
816                         res2 = ast_autoservice_start(qe->chan);
817                         if (!res2)
818                                 res2 = ast_streamfile(peer, announce, peer->language);
819                         if (!res2)
820                                 res2 = ast_waitstream(peer, "");
821                         res2 |= ast_autoservice_stop(qe->chan);
822                         if (res2) {
823                                 /* Agent must have hung up */
824                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
825                                 ast_hangup(peer);
826                                 return -1;
827                         }
828                 }
829                 /* If appropriate, log that we have a destination channel */
830                 if (qe->chan->cdr)
831                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
832                 /* Make sure channels are compatible */
833                 res = ast_channel_make_compatible(qe->chan, peer);
834                 if (res < 0) {
835                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
836                         ast_hangup(peer);
837                         return -1;
838                 }
839                 /* Drop out of the queue at this point, to prepare for next caller */
840                 leave_queue(qe);                        
841                 /* JDG: sendurl */
842                 if( url && strlen(url) && ast_channel_supports_html(peer) ) {
843                         ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
844                         ast_channel_sendurl( peer, url );
845                 } /* /JDG */
846                 bridge = ast_bridge_call(qe->chan, peer, allowredir_in, allowredir_out, allowdisconnect);
847
848                 if(bridge != AST_PBX_NO_HANGUP_PEER)
849                         ast_hangup(peer);
850
851                 if( bridge == 0 ) res=1; /* JDG: bridge successfull, leave app_queue */
852                 else res = bridge; /* bridge error, stay in the queue */
853         }       
854 out:
855         hanguptree(outgoing, NULL);
856         return res;
857 }
858
859 static int wait_a_bit(struct queue_ent *qe)
860 {
861         /* Don't need to hold the lock while we setup the outgoing calls */
862         int retrywait = qe->parent->retry * 1000;
863         return ast_waitfordigit(qe->chan, retrywait);
864 }
865
866 // [PHM 06/26/03]
867
868 static struct member * interface_exists( struct ast_call_queue * q, char * interface )
869 {
870         struct member * ret = NULL ;
871         struct member *mem;
872         char buf[500] ;
873
874         if( q != NULL )
875         {
876                 mem = q->members ;
877
878                 while( mem != NULL ) {
879                         sprintf( buf, "%s/%s", mem->tech, mem->loc);
880
881                         if( strcmp( buf, interface ) == 0 ) {
882                                 ret = mem ;
883                                 break ;
884                         }
885                         else
886                                 mem = mem->next ;
887                 }
888         }
889
890         return( ret ) ;
891 }
892
893
894 static struct member * create_queue_node( char * interface )
895 {
896         struct member * cur ;
897         char * tmp ;
898         
899         /* Add a new member */
900
901         cur = malloc(sizeof(struct member));
902
903         if (cur) {
904                 memset(cur, 0, sizeof(struct member));
905                 strncpy(cur->tech, interface, sizeof(cur->tech) - 1);
906                 if ((tmp = strchr(cur->tech, '/')))
907                         *tmp = '\0';
908                 if ((tmp = strchr(interface, '/'))) {
909                         tmp++;
910                         strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
911                 } else
912                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
913         }
914
915         return( cur ) ;
916 }
917
918
919 static int rqm_exec(struct ast_channel *chan, void *data)
920 {
921         int res=-1;
922         struct localuser *u;
923         char *queuename;
924         struct member * node ;
925         struct member * look ;
926         char info[512];
927         char tmpchan[256]="";
928         char *interface=NULL;
929         struct ast_call_queue *q;
930         int found=0 ;
931
932         if (!data) {
933                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename|optional interface)\n");
934                 return -1;
935         }
936         
937         LOCAL_USER_ADD(u); // not sure if we need this, but better be safe than sorry ;-)
938         
939         /* Parse our arguments XXX Check for failure XXX */
940         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
941         queuename = info;
942         if (queuename) {
943                 interface = strchr(queuename, '|');
944                 if (interface) {
945                         *interface = '\0';
946                         interface++;
947                 }
948                 else {
949                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
950                         interface = strrchr(tmpchan, '-');
951                         if (interface)
952                                 *interface = '\0';
953                         interface = tmpchan;
954                 }
955         }
956
957         if( ( q = queues) != NULL )
958         {
959                 while( q && ( res != 0 ) && (!found) ) 
960                 {
961                         ast_mutex_lock(&q->lock);
962                         if( strcmp( q->name, queuename) == 0 )
963                         {
964                                 // found queue, try to remove  interface
965                                 found=1 ;
966
967                                 if( ( node = interface_exists( q, interface ) ) != NULL )
968                                 {
969                                         if( ( look = q->members ) == node )
970                                         {
971                                                 // 1st
972                                                 q->members = node->next;
973                                         }
974                                         else
975                                         {
976                                                 while( look != NULL )
977                                                         if( look->next == node )
978                                                         {
979                                                                 look->next = node->next ;
980                                                                 break ;
981                                                         }
982                                                         else
983                                                                 look = look->next ;
984                                         }
985
986                                         free( node ) ;
987
988                                         ast_log(LOG_NOTICE, "Removed interface '%s' to queue '%s'\n", 
989                                                 interface, queuename);
990                                         res = 0 ;
991                                 }
992                                 else
993                                         ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': "
994                                                 "Not there\n", interface, queuename);
995                         }
996
997                         ast_mutex_unlock(&q->lock);
998                         q = q->next;
999                 }
1000         }
1001
1002         if( ! found )
1003                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
1004
1005         LOCAL_USER_REMOVE(u);
1006         return res;
1007 }
1008
1009
1010
1011 static int aqm_exec(struct ast_channel *chan, void *data)
1012 {
1013         int res=-1;
1014         struct localuser *u;
1015         char *queuename;
1016         char info[512];
1017         char tmpchan[512]="";
1018         char *interface=NULL;
1019         struct ast_call_queue *q;
1020         struct member *save;
1021         int found=0 ;
1022
1023         if (!data) {
1024                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename|optional interface)\n");
1025                 return -1;
1026         }
1027         
1028         LOCAL_USER_ADD(u); // not sure if we need this, but better be safe than sorry ;-)
1029         
1030         /* Parse our arguments XXX Check for failure XXX */
1031         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1032         queuename = info;
1033         if (queuename) {
1034                 interface = strchr(queuename, '|');
1035                 if (interface) {
1036                         *interface = '\0';
1037                         interface++;
1038                 }
1039                 else {
1040                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
1041                         interface = strrchr(tmpchan, '-');
1042                         if (interface)
1043                                 *interface = '\0';
1044                         interface = tmpchan;
1045                 }
1046         }
1047
1048         if( ( q = queues) != NULL )
1049         {
1050                 while( q && ( res != 0 ) && (!found) ) 
1051                 {
1052                         ast_mutex_lock(&q->lock);
1053                         if( strcmp( q->name, queuename) == 0 )
1054                         {
1055                                 // found queue, try to enable interface
1056                                 found=1 ;
1057
1058                                 if( interface_exists( q, interface ) == NULL )
1059                                 {
1060                                         save = q->members ;
1061                                         q->members = create_queue_node( interface ) ;
1062
1063                                         if( q->members != NULL ) {
1064                                                 q->members->dynamic = 1;
1065                                                 q->members->next = save ;
1066                                         } else
1067                                                 q->members = save ;
1068
1069                                         ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
1070                                         res = 0 ;
1071                                 }
1072                                 else
1073                                         ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': "
1074                                                 "Already there\n", interface, queuename);
1075                         }
1076
1077                         ast_mutex_unlock(&q->lock);
1078                         q = q->next;
1079                 }
1080         }
1081
1082         if( ! found )
1083                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
1084
1085         LOCAL_USER_REMOVE(u);
1086         return res;
1087 }
1088
1089
1090 static int queue_exec(struct ast_channel *chan, void *data)
1091 {
1092         int res=-1;
1093         struct localuser *u;
1094         char *queuename;
1095         char info[512];
1096         char *options = NULL;
1097         char *url = NULL;
1098         char *announceoverride = NULL;
1099         /* whether to exit Queue application after the timeout hits */
1100         int go_on = 0;
1101
1102
1103
1104         /* Our queue entry */
1105         struct queue_ent qe;
1106         
1107         if (!data) {
1108                 ast_log(LOG_WARNING, "Queue requires an argument (queuename|optional timeout|optional URL)\n");
1109                 return -1;
1110         }
1111         
1112         LOCAL_USER_ADD(u);
1113         
1114         /* Parse our arguments XXX Check for failure XXX */
1115         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1116         queuename = info;
1117         if (queuename) {
1118                 options = strchr(queuename, '|');
1119                 if (options) {
1120                         *options = '\0';
1121                         options++;
1122                         url = strchr(options, '|');
1123                         if (url) {
1124                                 *url = '\0';
1125                                 url++;
1126                                 announceoverride = strchr(url, '|');
1127                                 if (announceoverride) {
1128                                         *announceoverride = '\0';
1129                                         announceoverride++;
1130                                 }
1131                         }
1132                 }
1133         }
1134         if (option_debug)
1135                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s\n",
1136                                         queuename, options, url, announceoverride);
1137         /* Setup our queue entry */
1138         memset(&qe, 0, sizeof(qe));
1139         qe.chan = chan;
1140         qe.start = time(NULL);
1141         if (!join_queue(queuename, &qe)) {
1142                 /* Start music on hold */
1143                 ast_moh_start(chan, qe.moh);
1144                 for (;;) {
1145                         res = wait_our_turn(&qe);
1146                         /* If they hungup, return immediately */
1147                         if (res < 0) {
1148                                 if (option_verbose > 2) {
1149                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected while waiting their turn\n");
1150                                         res = -1;
1151                                 }
1152                                 break;
1153                         }
1154                         if (!res)
1155                                 break;
1156                         if (valid_exit(&qe, res))
1157                                 break;
1158                 }
1159                 if (!res) {
1160                         for (;;) {
1161                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
1162                                 if (res)
1163                                         break;
1164                                 res = wait_a_bit(&qe);
1165                                 if (res < 0) {
1166                                         if (option_verbose > 2) {
1167                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected when they almost made it\n");
1168                                                 res = -1;
1169                                         }
1170                                         break;
1171                                 }
1172                                 if (res && valid_exit(&qe, res))
1173                                         break;
1174
1175                                 /* exit after a timeout if 'n' option enabled */
1176                                 if (go_on) {
1177                                         res = 0;
1178                                         break;
1179                                 }
1180                         }
1181                 }
1182                 /* Don't allow return code > 0 */
1183                 if (res > 0 && res != AST_PBX_KEEPALIVE) {
1184                         res = 0;        
1185                         ast_moh_stop(chan);
1186                 }
1187                 leave_queue(&qe);
1188         } else {
1189                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
1190                 res =  0;
1191         }
1192         LOCAL_USER_REMOVE(u);
1193         return res;
1194 }
1195
1196 static void reload_queues(void)
1197 {
1198         struct ast_call_queue *q, *ql, *qn;
1199         struct ast_config *cfg;
1200         char *cat, *tmp;
1201         struct ast_variable *var;
1202         struct member *prev, *cur;
1203         int new;
1204         cfg = ast_load("queues.conf");
1205         if (!cfg) {
1206                 ast_log(LOG_NOTICE, "No call queueing config file, so no call queues\n");
1207                 return;
1208         }
1209         ast_mutex_lock(&qlock);
1210         /* Mark all queues as dead for the moment */
1211         q = queues;
1212         while(q) {
1213                 q->dead = 1;
1214                 q = q->next;
1215         }
1216         /* Chug through config file */
1217         cat = ast_category_browse(cfg, NULL);
1218         while(cat) {
1219                 if (strcasecmp(cat, "general")) {
1220                         /* Look for an existing one */
1221                         q = queues;
1222                         while(q) {
1223                                 if (!strcmp(q->name, cat))
1224                                         break;
1225                                 q = q->next;
1226                         }
1227                         if (!q) {
1228                                 /* Make one then */
1229                                 q = malloc(sizeof(struct ast_call_queue));
1230                                 if (q) {
1231                                         /* Initialize it */
1232                                         memset(q, 0, sizeof(struct ast_call_queue));
1233                                         ast_mutex_init(&q->lock);
1234                                         strncpy(q->name, cat, sizeof(q->name));
1235                                         new = 1;
1236                                 } else new = 0;
1237                         } else
1238                                         new = 0;
1239                         if (q) {
1240                                 if (!new) 
1241                                         ast_mutex_lock(&q->lock);
1242                                 /* Re-initialize the queue */
1243                                 q->dead = 0;
1244                                 q->retry = 0;
1245                                 q->timeout = -1;
1246                                 q->maxlen = 0;
1247                                 free_members(q, 0);
1248                                 strcpy(q->moh, "");
1249                                 strcpy(q->announce, "");
1250                                 strcpy(q->context, "");
1251                                 prev = q->members;
1252                                 if (prev) {
1253                                         /* find the end of any dynamic members */
1254                                         while(prev->next)
1255                                                 prev = prev->next;
1256                                 }
1257                                 var = ast_variable_browse(cfg, cat);
1258                                 while(var) {
1259                                         if (!strcasecmp(var->name, "member")) {
1260                                                 /* Add a new member */
1261                                                 cur = malloc(sizeof(struct member));
1262                                                 if (cur) {
1263                                                         memset(cur, 0, sizeof(struct member));
1264                                                         strncpy(cur->tech, var->value, sizeof(cur->tech) - 1);
1265                                                         if ((tmp = strchr(cur->tech, ','))) {
1266                                                                 *tmp = '\0';
1267                                                                 tmp++;
1268                                                                 cur->penalty = atoi(tmp);
1269                                                                 if (cur->penalty < 0)
1270                                                                         cur->penalty = 0;
1271                                                         }
1272                                                         if ((tmp = strchr(cur->tech, '/')))
1273                                                                 *tmp = '\0';
1274                                                         if ((tmp = strchr(var->value, '/'))) {
1275                                                                 tmp++;
1276                                                                 strncpy(cur->loc, tmp, sizeof(cur->loc) - 1);
1277                                                                 if ((tmp = strchr(cur->loc, ',')))
1278                                                                         *tmp = '\0';
1279                                                         } else
1280                                                                 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
1281                                                         if (prev)
1282                                                                 prev->next = cur;
1283                                                         else
1284                                                                 q->members = cur;
1285                                                         prev = cur;
1286                                                 }
1287                                         } else if (!strcasecmp(var->name, "music")) {
1288                                                 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
1289                                         } else if (!strcasecmp(var->name, "announce")) {
1290                                                 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
1291                                         } else if (!strcasecmp(var->name, "context")) {
1292                                                 strncpy(q->context, var->value, sizeof(q->context) - 1);
1293                                         } else if (!strcasecmp(var->name, "timeout")) {
1294                                                 q->timeout = atoi(var->value);
1295                                         } else if (!strcasecmp(var->name, "retry")) {
1296                                                 q->retry = atoi(var->value);
1297                                         } else if (!strcasecmp(var->name, "maxlen")) {
1298                                                 q->maxlen = atoi(var->value);
1299                                         } else if (!strcasecmp(var->name, "strategy")) {
1300                                                 q->strategy = strat2int(var->value);
1301                                                 if (q->strategy < 0) {
1302                                                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
1303                                                         q->strategy = 0;
1304                                                 }
1305                                         } else {
1306                                                 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
1307                                         }
1308                                         var = var->next;
1309                                 }
1310                                 if (q->retry < 1)
1311                                         q->retry = DEFAULT_RETRY;
1312                                 if (q->timeout < 0)
1313                                         q->timeout = DEFAULT_TIMEOUT;
1314                                 if (q->maxlen < 0)
1315                                         q->maxlen = 0;
1316                                 if (!new) 
1317                                         ast_mutex_unlock(&q->lock);
1318                                 if (new) {
1319                                         q->next = queues;
1320                                         queues = q;
1321                                 }
1322                         }
1323                 }
1324                 cat = ast_category_browse(cfg, cat);
1325         }
1326         ast_destroy(cfg);
1327         q = queues;
1328         ql = NULL;
1329         while(q) {
1330                 qn = q->next;
1331                 if (q->dead) {
1332                         if (ql)
1333                                 ql->next = q->next;
1334                         else
1335                                 queues = q->next;
1336                         if (!q->count) {
1337                                 free(q);
1338                         } else
1339                                 ast_log(LOG_WARNING, "XXX Leaking a litttle memory :( XXX\n");
1340                 } else
1341                         ql = q;
1342                 q = qn;
1343         }
1344         ast_mutex_unlock(&qlock);
1345 }
1346
1347 static int queues_show(int fd, int argc, char **argv)
1348 {
1349         struct ast_call_queue *q;
1350         struct queue_ent *qe;
1351         struct member *mem;
1352         int pos;
1353         time_t now;
1354         char max[80];
1355         char calls[80];
1356         
1357         time(&now);
1358         if (argc != 2)
1359                 return RESULT_SHOWUSAGE;
1360         ast_mutex_lock(&qlock);
1361         q = queues;
1362         if (!q) {       
1363                 ast_mutex_unlock(&qlock);
1364                 ast_cli(fd, "No queues.\n");
1365                 return RESULT_SUCCESS;
1366         }
1367         while(q) {
1368                 ast_mutex_lock(&q->lock);
1369                 if (q->maxlen)
1370                         snprintf(max, sizeof(max), "%d", q->maxlen);
1371                 else
1372                         strcpy(max, "unlimited");
1373                 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy\n", q->name, q->count, max, int2strat(q->strategy));
1374                 if (q->members) {
1375                         ast_cli(fd, "   Members: \n");
1376                         for (mem = q->members; mem; mem = mem->next) {
1377                                 if (mem->penalty)
1378                                         snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
1379                                 else
1380                                         strcpy(max, "");
1381                                 if (mem->dynamic)
1382                                         strcat(max, " (dynamic)");
1383                                 if (mem->calls) {
1384                                         snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
1385                                                         mem->calls, (long)(time(NULL) - mem->lastcall));
1386                                 } else
1387                                         strcpy(calls, " has taken no calls yet");
1388                                 ast_cli(fd, "      %s/%s%s%s\n", mem->tech, mem->loc, max, calls);
1389                         }
1390                 } else
1391                         ast_cli(fd, "   No Members\n");
1392                 if (q->head) {
1393                         pos = 1;
1394                         ast_cli(fd, "   Callers: \n");
1395                         for (qe = q->head; qe; qe = qe->next) 
1396                                 ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld)\n", pos++, qe->chan->name,
1397                                                                 (long)(now - qe->start) / 60, (long)(now - qe->start) % 60);
1398                 } else
1399                         ast_cli(fd, "   No Callers\n");
1400                 ast_cli(fd, "\n");
1401                 ast_mutex_unlock(&q->lock);
1402                 q = q->next;
1403         }
1404         ast_mutex_unlock(&qlock);
1405         return RESULT_SUCCESS;
1406 }
1407
1408 /* JDG: callback to display queues status in manager */
1409 static int manager_queues_show( struct mansession *s, struct message *m )
1410 {
1411         char *a[] = { "show", "queues" };
1412         return queues_show( s->fd, 2, a );
1413 } /* /JDG */
1414
1415
1416 /* Dump queue status */
1417 static int manager_queues_status( struct mansession *s, struct message *m )
1418 {
1419         time_t now;
1420         int pos;
1421         char *id = astman_get_header(m,"ActionID");
1422         char idText[256] = "";
1423         struct ast_call_queue *q;
1424         struct queue_ent *qe;
1425         astman_send_ack(s, m, "Queue status will follow");
1426         time(&now);
1427         ast_mutex_lock(&qlock);
1428         q = queues;
1429         if (id && &id) {
1430                 snprintf(idText,256,"ActionID: %s\r\n",id);
1431         }
1432         while(q) {
1433                 ast_mutex_lock(&q->lock);
1434                 ast_cli(s->fd, "Event: QueueParams\r\n"
1435                                         "Queue: %s\r\n"
1436                                         "Max: %d\r\n"
1437                                         "Calls: %d\r\n"
1438                                         "%s"
1439                                         "\r\n",
1440                                                 q->name, q->maxlen, q->count,idText);
1441 #if 0
1442                 /* Do we care about queue members? */                                   
1443                 for (mem = q->members; mem; mem = mem->next) 
1444                         ast_cli(fd, "      %s/%s\n", mem->tech, mem->loc);
1445 #endif                  
1446                 pos = 1;
1447                 for (qe = q->head; qe; qe = qe->next) 
1448                         ast_cli(s->fd, "Event: QueueMember\r\n"
1449                                 "Queue: %s\r\n"
1450                                 "Position: %d\r\n"
1451                                 "Channel: %s\r\n"
1452                                 "CallerID: %s\r\n"
1453                                 "Wait: %ld\r\n"
1454                                 "%s"
1455                                 "\r\n", 
1456                                         q->name, pos++, qe->chan->name, (qe->chan->callerid ? qe->chan->callerid : ""), (long)(now - qe->start), idText);
1457                 ast_mutex_unlock(&q->lock);
1458                 q = q->next;
1459         }
1460         ast_mutex_unlock(&qlock);
1461         return RESULT_SUCCESS;
1462 }
1463
1464 static char show_queues_usage[] = 
1465 "Usage: show queues\n"
1466 "       Provides summary information on call queues.\n";
1467
1468 static struct ast_cli_entry cli_show_queues = {
1469         { "show", "queues", NULL }, queues_show, 
1470         "Show status of queues", show_queues_usage, NULL };
1471
1472 int unload_module(void)
1473 {
1474         STANDARD_HANGUP_LOCALUSERS;
1475         ast_cli_unregister(&cli_show_queues);
1476         ast_manager_unregister( "Queues" );
1477         ast_manager_unregister( "QueueStatus" );
1478         return ast_unregister_application(app);
1479 }
1480
1481 int load_module(void)
1482 {
1483         int res;
1484         res = ast_register_application(app, queue_exec, synopsis, descrip);
1485         if (!res) {
1486                 ast_cli_register(&cli_show_queues);
1487                 ast_manager_register( "Queues", 0, manager_queues_show, "Queues" );
1488                 ast_manager_register( "QueueStatus", 0, manager_queues_status, "Queue Status" );
1489
1490                 // [PHM 06/26/03]
1491                 ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip) ;
1492                 ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip) ;
1493         }
1494         reload_queues();
1495         return res;
1496 }
1497
1498
1499 int reload(void)
1500 {
1501         reload_queues();
1502         return 0;
1503 }
1504
1505 char *description(void)
1506 {
1507         return tdesc;
1508 }
1509
1510 int usecount(void)
1511 {
1512         int res;
1513         STANDARD_USECOUNT(res);
1514         return res;
1515 }
1516
1517 char *key()
1518 {
1519         return ASTERISK_GPL_KEY;
1520 }