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