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