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