e3f2026dc9cc1c7baebe152ce18076cf0d088c4a
[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                                                                 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN | QUEUE_FLAG_REDIR_OUT | QUEUE_FLAG_DISCON_IN | QUEUE_FLAG_DISCON_OUT);
1154                                                                 if (option_verbose > 2)
1155                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1156                                                                 peer = o;
1157                                                                 ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN & QUEUE_FLAG_REDIR_OUT & QUEUE_FLAG_DISCON_IN & QUEUE_FLAG_DISCON_OUT);
1158                                                         }
1159                                                         break;
1160                                                 case AST_CONTROL_BUSY:
1161                                                         if (option_verbose > 2)
1162                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1163                                                         o->stillgoing = 0;
1164                                                         if (in->cdr)
1165                                                                 ast_cdr_busy(in->cdr);
1166                                                         ast_hangup(o->chan);
1167                                                         o->chan = NULL;
1168                                                         if (qe->parent->strategy)
1169                                                                 ring_one(qe, outgoing, &numbusies);
1170                                                         numbusies++;
1171                                                         break;
1172                                                 case AST_CONTROL_CONGESTION:
1173                                                         if (option_verbose > 2)
1174                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1175                                                         o->stillgoing = 0;
1176                                                         if (in->cdr)
1177                                                                 ast_cdr_busy(in->cdr);
1178                                                         ast_hangup(o->chan);
1179                                                         o->chan = NULL;
1180                                                         if (qe->parent->strategy)
1181                                                                 ring_one(qe, outgoing, &numbusies);
1182                                                         numbusies++;
1183                                                         break;
1184                                                 case AST_CONTROL_RINGING:
1185                                                         if (option_verbose > 2)
1186                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1187                                                         if (!sentringing) {
1188 #if 0
1189                                                                 ast_indicate(in, AST_CONTROL_RINGING);
1190 #endif                                                          
1191                                                                 sentringing++;
1192                                                         }
1193                                                         break;
1194                                                 case AST_CONTROL_OFFHOOK:
1195                                                         /* Ignore going off hook */
1196                                                         break;
1197                                                 default:
1198                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1199                                                 }
1200                                         }
1201                                         ast_frfree(f);
1202                                 } else {
1203                                         o->stillgoing = 0;
1204                                         ast_hangup(o->chan);
1205                                         o->chan = NULL;
1206                                         if (qe->parent->strategy)
1207                                                 ring_one(qe, outgoing, &numbusies);
1208                                 }
1209                         }
1210                         o = o->next;
1211                 }
1212                 if (winner == in) {
1213                         f = ast_read(in);
1214 #if 0
1215                         if (f && (f->frametype != AST_FRAME_VOICE))
1216                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1217                         else if (!f || (f->frametype != AST_FRAME_VOICE))
1218                                 printf("Hangup received on %s\n", in->name);
1219 #endif
1220                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1221                                 /* Got hung up */
1222                                 *to=-1;
1223                                 return NULL;
1224                         }
1225                         if (f && (f->frametype == AST_FRAME_DTMF) && ast_test_flag(flags, QUEUE_FLAG_DISCON_OUT) && (f->subclass == '*')) {
1226                                 if (option_verbose > 3)
1227                                         ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1228                                 *to=0;
1229                                 return NULL;
1230                         }
1231                         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1232                                 if (option_verbose > 3)
1233                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c", f->subclass);
1234                                 *to=0;
1235                                 *digit=f->subclass;
1236                                 return NULL;
1237                         }
1238                 }
1239                 if (!*to && (option_verbose > 2))
1240                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1241         }
1242
1243         return peer;
1244         
1245 }
1246
1247 static int is_our_turn(struct queue_ent *qe)
1248 {
1249         struct queue_ent *ch;
1250         int res;
1251
1252         /* Atomically read the parent head -- does not need a lock */
1253         ch = qe->parent->head;
1254         /* If we are now at the top of the head, break out */
1255         if (ch == qe) {
1256                 if (option_debug)
1257                         ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1258                 res = 1;
1259         } else {
1260                 if (option_debug)
1261                         ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1262                 res = 0;
1263         }
1264         return res;
1265 }
1266
1267 static int wait_our_turn(struct queue_ent *qe, int ringing)
1268 {
1269         int res = 0;
1270
1271         /* This is the holding pen for callers 2 through maxlen */
1272         for (;;) {
1273                 if (is_our_turn(qe))
1274                         break;
1275
1276                 /* If we have timed out, break out */
1277                 if (qe->expire && (time(NULL) > qe->expire))
1278                         break;
1279
1280                 /* leave the queue if no agents, if enabled */
1281                 if (ast_test_flag(qe->parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe->parent)) {
1282                         leave_queue(qe);
1283                         break;
1284                 }
1285
1286                 /* Make a position announcement, if enabled */
1287                 if (qe->parent->announcefrequency && !ringing)
1288                         say_position(qe);
1289
1290                 /* Wait a second before checking again */
1291                 res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1292                 if (res)
1293                         break;
1294         }
1295         return res;
1296 }
1297
1298 static int update_queue(struct ast_call_queue *q, struct member *member)
1299 {
1300         struct member *cur;
1301         /* Since a reload could have taken place, we have to traverse the list to
1302                 be sure it's still valid */
1303         ast_mutex_lock(&q->lock);
1304         cur = q->members;
1305         while(cur) {
1306                 if (member == cur) {
1307                         time(&cur->lastcall);
1308                         cur->calls++;
1309                         break;
1310                 }
1311                 cur = cur->next;
1312         }
1313         q->callscompleted++;
1314         ast_mutex_unlock(&q->lock);
1315         return 0;
1316 }
1317
1318 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1319 {
1320         switch (q->strategy) {
1321         case QUEUE_STRATEGY_RINGALL:
1322                 /* Everyone equal, except for penalty */
1323                 tmp->metric = mem->penalty * 1000000;
1324                 break;
1325         case QUEUE_STRATEGY_ROUNDROBIN:
1326                 if (!pos) {
1327                         if (!ast_test_flag(q, QUEUE_FLAG_WRAPPED)) {
1328                                 /* No more channels, start over */
1329                                 q->rrpos = 0;
1330                         } else {
1331                                 /* Prioritize next entry */
1332                                 q->rrpos++;
1333                         }
1334                         ast_clear_flag(q, QUEUE_FLAG_WRAPPED);
1335                 }
1336                 /* Fall through */
1337         case QUEUE_STRATEGY_RRMEMORY:
1338                 if (pos < q->rrpos) {
1339                         tmp->metric = 1000 + pos;
1340                 } else {
1341                         if (pos > q->rrpos) {
1342                                 /* Indicate there is another priority */
1343                                 ast_set_flag(q, QUEUE_FLAG_WRAPPED);
1344                         }
1345                         tmp->metric = pos;
1346                 }
1347                 tmp->metric += mem->penalty * 1000000;
1348                 break;
1349         case QUEUE_STRATEGY_RANDOM:
1350                 tmp->metric = rand() % 1000;
1351                 tmp->metric += mem->penalty * 1000000;
1352                 break;
1353         case QUEUE_STRATEGY_FEWESTCALLS:
1354                 tmp->metric = mem->calls;
1355                 tmp->metric += mem->penalty * 1000000;
1356                 break;
1357         case QUEUE_STRATEGY_LEASTRECENT:
1358                 if (!mem->lastcall)
1359                         tmp->metric = 0;
1360                 else
1361                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1362                 tmp->metric += mem->penalty * 1000000;
1363                 break;
1364         default:
1365                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1366                 break;
1367         }
1368         return 0;
1369 }
1370
1371 static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverride, char *url, int *go_on)
1372 {
1373         struct member *cur;
1374         struct localuser *outgoing=NULL, *tmp = NULL;
1375         int to;
1376         struct ast_flags flags;
1377         char restofit[AST_MAX_EXTENSION];
1378         char oldexten[AST_MAX_EXTENSION]="";
1379         char oldcontext[AST_MAX_EXTENSION]="";
1380         char queuename[256]="";
1381         char *newnum;
1382         char *options;
1383         char *monitorfilename;
1384         struct ast_channel *peer;
1385         struct ast_channel *which;
1386         struct localuser *lpeer;
1387         struct member *member;
1388         int res = 0, bridge = 0;
1389         int zapx = 2;
1390         int numbusies = 0;
1391         int x=0;
1392         char *announce = NULL;
1393         char digit = 0;
1394         time_t callstart;
1395         time_t now;
1396         struct ast_bridge_config config;
1397         /* Hold the lock while we setup the outgoing calls */
1398         ast_mutex_lock(&qe->parent->lock);
1399         if (option_debug)
1400                 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
1401                                                         qe->chan->name);
1402         strncpy(queuename, qe->parent->name, sizeof(queuename) - 1);
1403         time(&now);
1404         cur = qe->parent->members;
1405         if (!ast_strlen_zero(qe->announce))
1406                 announce = qe->announce;
1407         if (announceoverride && !ast_strlen_zero(announceoverride))
1408                 announce = announceoverride;
1409         while(cur) {
1410                 /* Get a technology/[device:]number pair */
1411                 tmp = malloc(sizeof(struct localuser));
1412                 if (!tmp) {
1413                         ast_mutex_unlock(&qe->parent->lock);
1414                         ast_log(LOG_WARNING, "Out of memory\n");
1415                         goto out;
1416                 }
1417                 memset(tmp, 0, sizeof(struct localuser));
1418                 tmp->stillgoing = -1;
1419                 options = ooptions;
1420                 for (; options && *options; options++)
1421                         switch (*options) {
1422                         case 't':
1423                                 ast_set_flag(tmp, QUEUE_FLAG_REDIR_IN);
1424                                 break;
1425                         case 'T':
1426                                 ast_set_flag(tmp, QUEUE_FLAG_REDIR_OUT);
1427                                 break;
1428                         case 'r':
1429                                 ast_set_flag(tmp, QUEUE_FLAG_RINGBACKONLY);
1430                                 break;
1431                         case 'm':
1432                                 ast_set_flag(tmp, QUEUE_FLAG_MUSICONHOLD);
1433                                 break;
1434                         case 'd':
1435                                 ast_set_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1436                                 break;
1437                         case 'h':
1438                                 ast_set_flag(tmp, QUEUE_FLAG_DISCON_IN);
1439                                 break;
1440                         case 'H':
1441                                 ast_set_flag(tmp, QUEUE_FLAG_DISCON_OUT);
1442                                 break;
1443                         case 'n':
1444                                 if ((now - qe->start >= qe->parent->timeout))
1445                                         *go_on = 1;
1446                                 break;
1447                         }
1448                 if (option_debug) {
1449                         if (url)
1450                                 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
1451                         else 
1452                                 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
1453                 }
1454
1455                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
1456                 tmp->oldstatus = cur->status;
1457                 tmp->lastcall = cur->lastcall;
1458                 strncpy(tmp->interface, cur->interface, sizeof(tmp->interface)-1);
1459                 /* If we're dialing by extension, look at the extension to know what to dial */
1460                 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
1461                         newnum++;
1462                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
1463                         snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
1464                         if (option_debug)
1465                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
1466                 }
1467                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
1468                    just calculate their metric for the appropriate strategy */
1469                 calc_metric(qe->parent, cur, x++, qe, tmp);
1470                 /* Put them in the list of outgoing thingies...  We're ready now. 
1471                    XXX If we're forcibly removed, these outgoing calls won't get
1472                    hung up XXX */
1473                 tmp->next = outgoing;
1474                 outgoing = tmp;         
1475                 /* If this line is up, don't try anybody else */
1476                 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
1477                         break;
1478
1479                 cur = cur->next;
1480         }
1481         if (qe->parent->timeout)
1482                 to = qe->parent->timeout * 1000;
1483         else
1484                 to = -1;
1485         ring_one(qe, outgoing, &numbusies);
1486         ast_mutex_unlock(&qe->parent->lock);
1487         lpeer = wait_for_answer(qe, outgoing, &to, &flags, &digit, numbusies);
1488         ast_mutex_lock(&qe->parent->lock);
1489         if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
1490                 store_next(qe, outgoing);
1491         }
1492         ast_mutex_unlock(&qe->parent->lock);
1493         if (lpeer)
1494                 peer = lpeer->chan;
1495         else
1496                 peer = NULL;
1497         if (!peer) {
1498                 if (to) {
1499                         /* Musta gotten hung up */
1500                         record_abandoned(qe);
1501                         res = -1;
1502                 } else {
1503                         if (digit && valid_exit(qe, digit))
1504                                 res=digit;
1505                         else
1506                                 /* Nobody answered, next please? */
1507                                 res=0;
1508                 }
1509                 if (option_debug)
1510                         ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
1511                 goto out;
1512         }
1513         if (peer) {
1514                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
1515                    we will always return with -1 so that it is hung up properly after the 
1516                    conversation.  */
1517                 qe->handled++;
1518                 if (!strcmp(qe->chan->type,"Zap")) {
1519                         zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1520                         ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1521                 }                       
1522                 if (!strcmp(peer->type,"Zap")) {
1523                         zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY);
1524                         ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0);
1525                 }
1526                 /* Update parameters for the queue */
1527                 recalc_holdtime(qe);
1528                 member = lpeer->member;
1529                 hanguptree(outgoing, peer);
1530                 outgoing = NULL;
1531                 if (announce || ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME) || qe->parent->memberdelay) {
1532                         int res2;
1533                         res2 = ast_autoservice_start(qe->chan);
1534                         if (!res2) {
1535                                 if (qe->parent->memberdelay) {
1536                                         ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
1537                                         res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
1538                                 }
1539                                 if (!res2 && announce) {
1540                                         if (play_file(peer, announce))
1541                                                 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
1542                                 }
1543                                 if (!res2 && ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME)) {
1544                                         if (!play_file(peer, qe->parent->sound_reporthold)) {
1545                                                 int holdtime;
1546                                                 time_t now;
1547
1548                                                 time(&now);
1549                                                 holdtime = abs((now - qe->start) / 60);
1550                                                 if (holdtime < 2) {
1551                                                         play_file(peer, qe->parent->sound_lessthan);
1552                                                         ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
1553                                                 } else 
1554                                                         ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
1555                                                 play_file(peer, qe->parent->sound_minutes);
1556                                         }
1557                                 }
1558                         }
1559                         res2 |= ast_autoservice_stop(qe->chan);
1560                         if (peer->_softhangup) {
1561                                 /* Agent must have hung up */
1562                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
1563                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
1564                                 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1565                                         manager_event(EVENT_FLAG_AGENT, "AgentDump",
1566                                                         "Queue: %s\r\n"
1567                                                         "Uniqueid: %s\r\n"
1568                                                         "Channel: %s\r\n"
1569                                                         "Member: %s\r\n",
1570                                                 queuename, qe->chan->uniqueid, peer->name, member->interface);
1571                                 }
1572                                 ast_hangup(peer);
1573                                 goto out;
1574                         } else if (res2) {
1575                                 /* Caller must have hung up just before being connected*/
1576                                 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
1577                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
1578                                 record_abandoned(qe);
1579                                 ast_hangup(peer);
1580                                 return -1;
1581                         }
1582                 }
1583                 /* Stop music on hold */
1584                 ast_moh_stop(qe->chan);
1585                 /* If appropriate, log that we have a destination channel */
1586                 if (qe->chan->cdr)
1587                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
1588                 /* Make sure channels are compatible */
1589                 res = ast_channel_make_compatible(qe->chan, peer);
1590                 if (res < 0) {
1591                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
1592                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
1593                         ast_hangup(peer);
1594                         return -1;
1595                 }
1596                 /* Begin Monitoring */
1597                 if (qe->parent->monfmt && *qe->parent->monfmt) {
1598                         monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
1599                         if(pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper( qe->chan, "MONITOR_EXEC_ARGS"))
1600                                 which = qe->chan;
1601                         else
1602                                 which = peer;
1603                         if(monitorfilename) {
1604                                 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
1605                         } else {
1606                                 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
1607                         }
1608                         if(ast_test_flag(qe->parent, QUEUE_FLAG_MONJOIN)) {
1609                                 ast_monitor_setjoinfiles(which, 1);
1610                         }
1611                 }
1612                 /* Drop out of the queue at this point, to prepare for next caller */
1613                 leave_queue(qe);                        
1614                 if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) {
1615                         if (option_debug)
1616                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
1617                         ast_channel_sendurl( peer, url );
1618                 }
1619                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
1620                 if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1621                         manager_event(EVENT_FLAG_AGENT, "AgentConnect",
1622                                         "Queue: %s\r\n"
1623                                         "Uniqueid: %s\r\n"
1624                                         "Channel: %s\r\n"
1625                                         "Member: %s\r\n"
1626                                         "Holdtime: %ld\r\n",
1627                                 queuename, qe->chan->uniqueid, peer->name, member->interface, (long)time(NULL) - qe->start);
1628                 }
1629                 strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1);
1630                 strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1);
1631                 time(&callstart);
1632
1633                 memset(&config,0,sizeof(struct ast_bridge_config));
1634                 
1635                 if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_IN))
1636                         ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
1637                 if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_OUT))
1638                         ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
1639                 if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_IN))
1640                         ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
1641                 if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_OUT))
1642                         ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
1643                 bridge = ast_bridge_call(qe->chan,peer,&config);
1644
1645                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
1646                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
1647                 } else if (qe->chan->_softhangup) {
1648                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1649                         if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1650                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1651                                                 "Queue: %s\r\n"
1652                                                 "Uniqueid: %s\r\n"
1653                                                 "Channel: %s\r\n"
1654                                                 "Member: %s\r\n"
1655                                                 "HoldTime: %ld\r\n"
1656                                                 "TalkTime: %ld\r\n"
1657                                                 "Reason: caller\r\n",
1658                                                 queuename, qe->chan->uniqueid, peer->name, member->interface, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1659                         }
1660                 } else {
1661                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1662                         if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) {
1663                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
1664                                                 "Queue: %s\r\n"
1665                                                 "Uniqueid: %s\r\n"
1666                                                 "Channel: %s\r\n"
1667                                                 "HoldTime: %ld\r\n"
1668                                                 "TalkTime: %ld\r\n"
1669                                                 "Reason: agent\r\n",
1670                                         queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
1671                         }
1672
1673                 }
1674
1675                 if(bridge != AST_PBX_NO_HANGUP_PEER)
1676                         ast_hangup(peer);
1677                 update_queue(qe->parent, member);
1678                 if (bridge == 0) 
1679                         res = 1; /* JDG: bridge successfull, leave app_queue */
1680                 else 
1681                         res = bridge; /* bridge error, stay in the queue */
1682         }       
1683 out:
1684         hanguptree(outgoing, NULL);
1685         return res;
1686 }
1687
1688 static int wait_a_bit(struct queue_ent *qe)
1689 {
1690         /* Don't need to hold the lock while we setup the outgoing calls */
1691         int retrywait = qe->parent->retry * 1000;
1692         return ast_waitfordigit(qe->chan, retrywait);
1693 }
1694
1695 /* [PHM 06/26/03] */
1696
1697 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
1698 {
1699         struct member *mem;
1700
1701         if (q)
1702                 for (mem = q->members; mem; mem = mem->next)
1703                         if (!strcmp(interface, mem->interface))
1704                                 return mem;
1705
1706         return NULL;
1707 }
1708
1709
1710 static struct member *create_queue_node(char *interface, int penalty, int paused)
1711 {
1712         struct member *cur;
1713         
1714         /* Add a new member */
1715
1716         cur = malloc(sizeof(struct member));
1717
1718         if (cur) {
1719                 memset(cur, 0, sizeof(struct member));
1720                 cur->penalty = penalty;
1721                 cur->paused = paused;
1722                 strncpy(cur->interface, interface, sizeof(cur->interface) - 1);
1723                 if (!strchr(cur->interface, '/'))
1724                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
1725                 cur->status = ast_device_state(interface);
1726         }
1727
1728         return cur;
1729 }
1730
1731 /* Dump all members in a specific queue to the databse
1732  *
1733  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
1734  *
1735  */
1736 static void dump_queue_members(struct ast_call_queue *pm_queue)
1737 {
1738         struct member *cur_member;
1739         char value[PM_MAX_LEN];
1740         int value_len = 0;
1741         int res;
1742
1743         memset(value, 0, sizeof(value));
1744
1745         if (!pm_queue)
1746                 return;
1747
1748         for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
1749                 if (!cur_member->dynamic)
1750                         continue;
1751
1752                 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
1753                                cur_member->interface, cur_member->penalty, cur_member->paused,
1754                                cur_member->next ? "|" : "");
1755                 if (res != strlen(value + value_len)) {
1756                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
1757                         break;
1758                 }
1759                 value_len += res;
1760         }
1761         
1762         if (value_len && !cur_member) {
1763                 if (ast_db_put(pm_family, pm_queue->name, value))
1764                         ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
1765         } else
1766                 /* Delete the entry if the queue is empty or there is an error */
1767                 ast_db_del(pm_family, pm_queue->name);
1768 }
1769
1770 static int remove_from_queue(char *queuename, char *interface)
1771 {
1772         struct ast_call_queue *q;
1773         struct member *last_member, *look;
1774         int res = RES_NOSUCHQUEUE;
1775
1776         ast_mutex_lock(&qlock);
1777         for (q = queues ; q ; q = q->next) {
1778                 ast_mutex_lock(&q->lock);
1779                 if (!strcmp(q->name, queuename)) {
1780                         if ((last_member = interface_exists(q, interface))) {
1781                                 if ((look = q->members) == last_member) {
1782                                         q->members = last_member->next;
1783                                 } else {
1784                                         while (look != NULL) {
1785                                                 if (look->next == last_member) {
1786                                                         look->next = last_member->next;
1787                                                         break;
1788                                                 } else {
1789                                                          look = look->next;
1790                                                 }
1791                                         }
1792                                 }
1793                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
1794                                                 "Queue: %s\r\n"
1795                                                 "Location: %s\r\n",
1796                                         q->name, last_member->interface);
1797                                 free(last_member);
1798
1799                                 if (queue_persistent_members)
1800                                     dump_queue_members(q);
1801
1802                                 res = RES_OKAY;
1803                         } else {
1804                                 res = RES_EXISTS;
1805                         }
1806                         ast_mutex_unlock(&q->lock);
1807                         break;
1808                 }
1809                 ast_mutex_unlock(&q->lock);
1810         }
1811         ast_mutex_unlock(&qlock);
1812         return res;
1813 }
1814
1815 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
1816 {
1817         struct ast_call_queue *q;
1818         struct member *new_member;
1819         int res = RES_NOSUCHQUEUE;
1820
1821         ast_mutex_lock(&qlock);
1822         for (q = queues ; q ; q = q->next) {
1823                 ast_mutex_lock(&q->lock);
1824                 if (!strcmp(q->name, queuename)) {
1825                         if (interface_exists(q, interface) == NULL) {
1826                                 new_member = create_queue_node(interface, penalty, paused);
1827
1828                                 if (new_member != NULL) {
1829                                         new_member->dynamic = 1;
1830                                         new_member->next = q->members;
1831                                         q->members = new_member;
1832                                         manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
1833                                                 "Queue: %s\r\n"
1834                                                 "Location: %s\r\n"
1835                                                 "Membership: %s\r\n"
1836                                                 "Penalty: %d\r\n"
1837                                                 "CallsTaken: %d\r\n"
1838                                                 "LastCall: %ld\r\n"
1839                                                 "Status: %d\r\n"
1840                                                 "Paused: %d\r\n",
1841                                         q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
1842                                         new_member->penalty, new_member->calls, new_member->lastcall, new_member->status, new_member->paused);
1843                                         
1844                                         if (dump)
1845                                                 dump_queue_members(q);
1846
1847                                         res = RES_OKAY;
1848                                 } else {
1849                                         res = RES_OUTOFMEMORY;
1850                                 }
1851                         } else {
1852                                 res = RES_EXISTS;
1853                         }
1854                         ast_mutex_unlock(&q->lock);
1855                         break;
1856                 }
1857                 ast_mutex_unlock(&q->lock);
1858         }
1859         ast_mutex_unlock(&qlock);
1860         return res;
1861 }
1862
1863 static int set_member_paused(char *queuename, char *interface, int paused)
1864 {
1865         int found = 0;
1866         struct ast_call_queue *q;
1867         struct member *mem;
1868
1869         /* Special event for when all queues are paused - individual events still generated */
1870
1871         if (ast_strlen_zero(queuename))
1872                 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
1873
1874         ast_mutex_lock(&qlock);
1875         for (q = queues ; q ; q = q->next) {
1876                 ast_mutex_lock(&q->lock);
1877                 if (ast_strlen_zero(queuename) || !strcmp(q->name, queuename)) {
1878                         if ((mem = interface_exists(q, interface))) {
1879                                 found++;
1880                                 if (mem->paused == paused)
1881                                         ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
1882                                 mem->paused = paused;
1883
1884                                 if (queue_persistent_members)
1885                                     dump_queue_members(q);
1886
1887                                 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
1888
1889                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
1890                                         "Queue: %s\r\n"
1891                                         "Location: %s\r\n"
1892                                         "Paused: %d\r\n",
1893                                                 q->name, mem->interface, paused);
1894                         }
1895                 }
1896                 ast_mutex_unlock(&q->lock);
1897         }
1898         ast_mutex_unlock(&qlock);
1899
1900         if (found)
1901                 return RESULT_SUCCESS;
1902         else
1903                 return RESULT_FAILURE;
1904 }
1905
1906 /* Reload dynamic queue members persisted into the astdb */
1907 static void reload_queue_members(void)
1908 {
1909         char *cur_ptr;  
1910         char *queue_name;
1911         char *member;
1912         char *interface;
1913         char *penalty_tok;
1914         int penalty = 0;
1915         char *paused_tok;
1916         int paused = 0;
1917         struct ast_db_entry *db_tree;
1918         struct ast_db_entry *entry;
1919         struct ast_call_queue *cur_queue;
1920         char queue_data[PM_MAX_LEN];
1921
1922         ast_mutex_lock(&qlock);
1923
1924         /* Each key in 'pm_family' is the name of a queue */
1925         db_tree = ast_db_gettree(pm_family, NULL);
1926         for (entry = db_tree; entry; entry = entry->next) {
1927
1928                 queue_name = entry->key + strlen(pm_family) + 2;
1929
1930                 cur_queue = queues;
1931                 while (cur_queue) {
1932                         ast_mutex_lock(&cur_queue->lock);
1933                         if (!strcmp(queue_name, cur_queue->name))
1934                                 break;
1935                         ast_mutex_unlock(&cur_queue->lock);
1936                         cur_queue = cur_queue->next;
1937                 }
1938
1939                 if (!cur_queue) {
1940                         /* If the queue no longer exists, remove it from the
1941                          * database */
1942                         ast_db_del(pm_family, queue_name);
1943                         continue;
1944                 } else
1945                         ast_mutex_unlock(&cur_queue->lock);
1946
1947                 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
1948                         continue;
1949
1950                 cur_ptr = queue_data;
1951                 while ((member = strsep(&cur_ptr, "|"))) {
1952                         if (ast_strlen_zero(member))
1953                                 continue;
1954
1955                         interface = strsep(&member, ";");
1956                         penalty_tok = strsep(&member, ";");
1957                         paused_tok = strsep(&member, ";");
1958
1959                         if (!penalty_tok) {
1960                                 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
1961                                 break;
1962                         }
1963                         penalty = strtol(penalty_tok, NULL, 10);
1964                         if (errno == ERANGE) {
1965                                 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
1966                                 break;
1967                         }
1968                         
1969                         if (!paused_tok) {
1970                                 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
1971                                 break;
1972                         }
1973                         paused = strtol(paused_tok, NULL, 10);
1974                         if ((errno == ERANGE) || paused < 0 || paused > 1) {
1975                                 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
1976                                 break;
1977                         }
1978
1979                         if (option_debug)
1980                                 ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
1981                         
1982                         if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
1983                                 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
1984                                 break;
1985                         }
1986                 }
1987         }
1988
1989         ast_mutex_unlock(&qlock);
1990         if (db_tree) {
1991                 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
1992                 ast_db_freetree(db_tree);
1993         }
1994 }
1995
1996 static int pqm_exec(struct ast_channel *chan, void *data)
1997 {
1998         struct localuser *u;
1999         char *queuename, *interface;
2000
2001         if (!data) {
2002                 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface])\n");
2003                 return -1;
2004         }
2005
2006         queuename = ast_strdupa((char *)data);
2007         if (!queuename) {
2008                 ast_log(LOG_ERROR, "Out of memory\n");
2009                 return -1;
2010         }
2011
2012         interface = strchr(queuename, '|');
2013         if (!interface) {
2014                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2015                 return -1;
2016         }
2017
2018         LOCAL_USER_ADD(u);
2019
2020         *interface = '\0';
2021         interface++;
2022
2023         if (set_member_paused(queuename, interface, 1)) {
2024                 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", interface);
2025                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2026                         chan->priority += 100;
2027                         LOCAL_USER_REMOVE(u);
2028                         return 0;
2029                 }
2030                 return -1;
2031         }
2032
2033         LOCAL_USER_REMOVE(u);
2034
2035         return 0;
2036 }
2037
2038 static int upqm_exec(struct ast_channel *chan, void *data)
2039 {
2040         struct localuser *u;
2041         char *queuename, *interface;
2042
2043         if (!data) {
2044                 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface])\n");
2045                 return -1;
2046         }
2047
2048         queuename = ast_strdupa((char *)data);
2049         if (!queuename) {
2050                 ast_log(LOG_ERROR, "Out of memory\n");
2051                 return -1;
2052         }
2053
2054         interface = strchr(queuename, '|');
2055         if (!interface) {
2056                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2057                 return -1;
2058         }
2059
2060         LOCAL_USER_ADD(u);
2061
2062         *interface = '\0';
2063         interface++;
2064
2065         if (set_member_paused(queuename, interface, 0)) {
2066                 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", interface);
2067                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2068                         chan->priority += 100;
2069                         LOCAL_USER_REMOVE(u);
2070                         return 0;
2071                 }
2072                 return -1;
2073         }
2074
2075         LOCAL_USER_REMOVE(u);
2076
2077         return 0;
2078 }
2079
2080 static int rqm_exec(struct ast_channel *chan, void *data)
2081 {
2082         int res=-1;
2083         struct localuser *u;
2084         char *info, *queuename;
2085         char tmpchan[256]="";
2086         char *interface = NULL;
2087
2088         if (!data) {
2089                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
2090                 return -1;
2091         }
2092
2093         info = ast_strdupa((char *)data);
2094         if (!info) {
2095                 ast_log(LOG_ERROR, "Out of memory\n");
2096                 return -1;
2097         }
2098
2099         LOCAL_USER_ADD(u);
2100
2101         queuename = info;
2102         if (queuename) {
2103                 interface = strchr(queuename, '|');
2104                 if (interface) {
2105                         *interface = '\0';
2106                         interface++;
2107                 }
2108                 else {
2109                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2110                         interface = strrchr(tmpchan, '-');
2111                         if (interface)
2112                                 *interface = '\0';
2113                         interface = tmpchan;
2114                 }
2115         }
2116
2117         switch (remove_from_queue(queuename, interface)) {
2118         case RES_OKAY:
2119                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2120                 res = 0;
2121                 break;
2122         case RES_EXISTS:
2123                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2124                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2125                         chan->priority += 100;
2126                 }
2127                 res = 0;
2128                 break;
2129         case RES_NOSUCHQUEUE:
2130                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2131                 res = 0;
2132                 break;
2133         case RES_OUTOFMEMORY:
2134                 ast_log(LOG_ERROR, "Out of memory\n");
2135                 break;
2136         }
2137
2138         LOCAL_USER_REMOVE(u);
2139         return res;
2140 }
2141
2142 static int aqm_exec(struct ast_channel *chan, void *data)
2143 {
2144         int res=-1;
2145         struct localuser *u;
2146         char *queuename;
2147         char *info;
2148         char tmpchan[512]="";
2149         char *interface=NULL;
2150         char *penaltys=NULL;
2151         int penalty = 0;
2152
2153         if (!data) {
2154                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
2155                 return -1;
2156         }
2157
2158         info = ast_strdupa((char *)data);
2159         if (!info) {
2160                 ast_log(LOG_ERROR, "Out of memory\n");
2161                 return -1;
2162         }
2163         LOCAL_USER_ADD(u);
2164
2165         queuename = info;
2166         if (queuename) {
2167                 interface = strchr(queuename, '|');
2168                 if (interface) {
2169                         *interface = '\0';
2170                         interface++;
2171                 }
2172                 if (interface) {
2173                         penaltys = strchr(interface, '|');
2174                         if (penaltys) {
2175                                 *penaltys = '\0';
2176                                 penaltys++;
2177                         }
2178                 }
2179                 if (!interface || ast_strlen_zero(interface)) {
2180                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2181                         interface = strrchr(tmpchan, '-');
2182                         if (interface)
2183                                 *interface = '\0';
2184                         interface = tmpchan;
2185                 }
2186                 if (penaltys && !ast_strlen_zero(penaltys)) {
2187                         if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
2188                                 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
2189                                 penalty = 0;
2190                         }
2191                 }
2192         }
2193
2194         switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
2195         case RES_OKAY:
2196                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
2197                 res = 0;
2198                 break;
2199         case RES_EXISTS:
2200                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2201                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2202                         chan->priority += 100;
2203                 }
2204                 res = 0;
2205                 break;
2206         case RES_NOSUCHQUEUE:
2207                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
2208                 res = 0;
2209                 break;
2210         case RES_OUTOFMEMORY:
2211                 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", interface, queuename);
2212                 break;
2213         }
2214
2215         LOCAL_USER_REMOVE(u);
2216         return res;
2217 }
2218
2219 static int queue_exec(struct ast_channel *chan, void *data)
2220 {
2221         int res=-1;
2222         int ringing=0;
2223         struct localuser *u;
2224         char *queuename;
2225         char info[512];
2226         char *info_ptr = info;
2227         char *options = NULL;
2228         char *url = NULL;
2229         char *announceoverride = NULL;
2230         char *user_priority;
2231         int prio;
2232         char *queuetimeoutstr = NULL;
2233
2234         /* whether to exit Queue application after the timeout hits */
2235         int go_on = 0;
2236
2237         /* Our queue entry */
2238         struct queue_ent qe;
2239         
2240         if (!data || ast_strlen_zero(data)) {
2241                 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2242                 return -1;
2243         }
2244         
2245         LOCAL_USER_ADD(u);
2246
2247         /* Setup our queue entry */
2248         memset(&qe, 0, sizeof(qe));
2249         qe.start = time(NULL);
2250         
2251         /* Parse our arguments XXX Check for failure XXX */
2252         strncpy(info, (char *) data, sizeof(info) - 1);
2253         queuename = strsep(&info_ptr, "|");
2254         options = strsep(&info_ptr, "|");
2255         url = strsep(&info_ptr, "|");
2256         announceoverride = strsep(&info_ptr, "|");
2257         queuetimeoutstr = info_ptr;
2258
2259         /* set the expire time based on the supplied timeout; */
2260         if (queuetimeoutstr)
2261                 qe.expire = qe.start + atoi(queuetimeoutstr);
2262         else
2263                 qe.expire = 0;
2264
2265         /* Get the priority from the variable ${QUEUE_PRIO} */
2266         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2267         if (user_priority) {
2268                 if (sscanf(user_priority, "%d", &prio) == 1) {
2269                         if (option_debug)
2270                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2271                                                                 chan->name, prio);
2272                 } else {
2273                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2274                                                         user_priority, chan->name);
2275                         prio = 0;
2276                 }
2277         } else {
2278                 if (option_debug > 2)
2279                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2280                 prio = 0;
2281         }
2282
2283         if (options) {
2284                 if (strchr(options, 'r')) {
2285                         ringing = 1;
2286                 }
2287         }
2288
2289         if (option_debug)  
2290                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2291                                 queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
2292
2293         qe.chan = chan;
2294         qe.prio = (int)prio;
2295         qe.last_pos_said = 0;
2296         qe.last_pos = 0;
2297         if (!join_queue(queuename, &qe)) {
2298                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : "");
2299                 /* Start music on hold */
2300 check_turns:
2301                 if (ringing) {
2302                         ast_indicate(chan, AST_CONTROL_RINGING);
2303                 } else {              
2304                         ast_moh_start(chan, qe.moh);
2305                 }
2306                 for (;;) {
2307                         /* This is the wait loop for callers 2 through maxlen */
2308
2309                         res = wait_our_turn(&qe, ringing);
2310                         /* If they hungup, return immediately */
2311                         if (res < 0) {
2312                                 /* Record this abandoned call */
2313                                 record_abandoned(&qe);
2314                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2315                                 if (option_verbose > 2) {
2316                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2317                                         res = -1;
2318                                 }
2319                                 break;
2320                         }
2321                         if (!res) 
2322                                 break;
2323                         if (valid_exit(&qe, res)) {
2324                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2325                                 break;
2326                         }
2327                 }
2328                 if (!res) {
2329                         int makeannouncement = 0;
2330                         for (;;) {
2331                                 /* This is the wait loop for the head caller*/
2332                                 /* To exit, they may get their call answered; */
2333                                 /* they may dial a digit from the queue context; */
2334                                 /* or, they may timeout. */
2335
2336                                 /* Leave if we have exceeded our queuetimeout */
2337                                 if (qe.expire && (time(NULL) > qe.expire)) {
2338                                         res = 0;
2339                                         break;
2340                                 }
2341
2342                                 if (makeannouncement) {
2343                                         /* Make a position announcement, if enabled */
2344                                         if (qe.parent->announcefrequency && !ringing)
2345                                                 say_position(&qe);
2346                                 }
2347                                 makeannouncement = 1;
2348
2349                                 /* Try calling all queue members for 'timeout' seconds */
2350                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
2351                                 if (res) {
2352                                         if (res < 0) {
2353                                                 if (!qe.handled)
2354                                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2355                                         } else if (res > 0)
2356                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2357                                         break;
2358                                 }
2359
2360                                 /* leave the queue if no agents, if enabled */
2361                                 if (ast_test_flag(qe.parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe.parent)) {
2362                                         res = 0;
2363                                         break;
2364                                 }
2365
2366                                 /* Leave if we have exceeded our queuetimeout */
2367                                 if (qe.expire && (time(NULL) > qe.expire)) {
2368                                         res = 0;
2369                                         break;
2370                                 }
2371
2372                                 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
2373                                 res = wait_a_bit(&qe);
2374                                 if (res < 0) {
2375                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2376                                         if (option_verbose > 2) {
2377                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
2378                                                 res = -1;
2379                                         }
2380                                         break;
2381                                 }
2382                                 if (res && valid_exit(&qe, res)) {
2383                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2384                                         break;
2385                                 }
2386                                 /* exit after 'timeout' cycle if 'n' option enabled */
2387                                 if (go_on) {
2388                                         if (option_verbose > 2) {
2389                                                 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
2390                                                 res = -1;
2391                                         }
2392                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2393                                         res = 0;
2394                                         break;
2395                                 }
2396                                 /* Since this is a priority queue and 
2397                                  * it is not sure that we are still at the head
2398                                  * of the queue, go and check for our turn again.
2399                                  */
2400                                 if (!is_our_turn(&qe)) {
2401                                         if (option_debug)
2402                                                 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
2403                                                                 qe.chan->name);
2404                                         goto check_turns;
2405                                 }
2406                         }
2407                 }
2408                 /* Don't allow return code > 0 */
2409                 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
2410                         res = 0;        
2411                         if (ringing) {
2412                                 ast_indicate(chan, -1);
2413                         } else {
2414                                 ast_moh_stop(chan);
2415                         }                       
2416                         ast_stopstream(chan);
2417                 }
2418                 leave_queue(&qe);
2419         } else {
2420                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
2421                 res =  0;
2422         }
2423         LOCAL_USER_REMOVE(u);
2424         return res;
2425 }
2426
2427 static void reload_queues(void)
2428 {
2429         struct ast_call_queue *q, *ql, *qn;
2430         struct ast_config *cfg;
2431         char *cat, *tmp;
2432         struct ast_variable *var;
2433         struct member *prev, *cur;
2434         int new;
2435         char *general_val = NULL;
2436         
2437         cfg = ast_config_load("queues.conf");
2438         if (!cfg) {
2439                 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
2440                 return;
2441         }
2442         ast_mutex_lock(&qlock);
2443         use_weight=0;
2444         /* Mark all queues as dead for the moment */
2445         q = queues;
2446         while(q) {
2447                 ast_set_flag(q, QUEUE_FLAG_DEAD);
2448                 q = q->next;
2449         }
2450         /* Chug through config file */
2451         cat = ast_category_browse(cfg, NULL);
2452         while(cat) {
2453                 if (strcasecmp(cat, "general")) {       /* Define queue */
2454                         /* Look for an existing one */
2455                         q = queues;
2456                         while(q) {
2457                                 if (!strcmp(q->name, cat))
2458                                         break;
2459                                 q = q->next;
2460                         }
2461                         if (!q) {
2462                                 /* Make one then */
2463                                 q = malloc(sizeof(struct ast_call_queue));
2464                                 if (q) {
2465                                         /* Initialize it */
2466                                         memset(q, 0, sizeof(struct ast_call_queue));
2467                                         ast_mutex_init(&q->lock);
2468                                         strncpy(q->name, cat, sizeof(q->name) - 1);
2469                                         new = 1;
2470                                 } else new = 0;
2471                         } else
2472                                         new = 0;
2473                         if (q) {
2474                                 if (!new) 
2475                                         ast_mutex_lock(&q->lock);
2476                                 /* Re-initialize the queue */
2477                                 ast_clear_flag(q, QUEUE_FLAG_DEAD);
2478                                 q->retry = DEFAULT_RETRY;
2479                                 q->timeout = -1;
2480                                 q->maxlen = 0;
2481                                 q->announcefrequency = 0;
2482                                 q->announceholdtime = 0;
2483                                 q->roundingseconds = 0; /* Default - don't announce seconds */
2484                                 q->holdtime = 0;
2485                                 q->callscompleted = 0;
2486                                 q->callsabandoned = 0;
2487                                 q->callscompletedinsl = 0;
2488                                 q->servicelevel = 0;
2489                                 q->wrapuptime = 0;
2490                                 free_members(q, 0);
2491                                 q->moh[0] = '\0';
2492                                 q->announce[0] = '\0';
2493                                 q->context[0] = '\0';
2494                                 q->monfmt[0] = '\0';
2495                                 strncpy(q->sound_next, "queue-youarenext", sizeof(q->sound_next) - 1);
2496                                 strncpy(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare) - 1);
2497                                 strncpy(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls) - 1);
2498                                 strncpy(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime) - 1);
2499                                 strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
2500                                 strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
2501                                 strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
2502                                 strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
2503                                 strncpy(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold) - 1);
2504                                 prev = q->members;
2505                                 if (prev) {
2506                                         /* find the end of any dynamic members */
2507                                         while(prev->next)
2508                                                 prev = prev->next;
2509                                 }
2510                                 var = ast_variable_browse(cfg, cat);
2511                                 while(var) {
2512                                         if (!strcasecmp(var->name, "member")) {
2513                                                 /* Add a new member */
2514                                                 cur = malloc(sizeof(struct member));
2515                                                 if (cur) {
2516                                                         memset(cur, 0, sizeof(struct member));
2517                                                         strncpy(cur->interface, var->value, sizeof(cur->interface) - 1);
2518                                                         if ((tmp = strchr(cur->interface, ','))) {
2519                                                                 *tmp = '\0';
2520                                                                 tmp++;
2521                                                                 cur->penalty = atoi(tmp);
2522                                                                 if (cur->penalty < 0)
2523                                                                         cur->penalty = 0;
2524                                                         }
2525                                                         if (!strchr(cur->interface, '/'))
2526                                                                 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
2527                                                         if (prev)
2528                                                                 prev->next = cur;
2529                                                         else
2530                                                                 q->members = cur;
2531                                                         prev = cur;
2532                                                 }
2533                                         } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
2534                                                 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
2535                                         } else if (!strcasecmp(var->name, "announce")) {
2536                                                 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
2537                                         } else if (!strcasecmp(var->name, "context")) {
2538                                                 strncpy(q->context, var->value, sizeof(q->context) - 1);
2539                                         } else if (!strcasecmp(var->name, "timeout")) {
2540                                                 q->timeout = atoi(var->value);
2541                                         } else if (!strcasecmp(var->name, "monitor-join")) {
2542                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_MONJOIN);
2543                                         } else if (!strcasecmp(var->name, "monitor-format")) {
2544                                                 strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
2545                                         } else if (!strcasecmp(var->name, "queue-youarenext")) {
2546                                                 strncpy(q->sound_next, var->value, sizeof(q->sound_next) - 1);
2547                                         } else if (!strcasecmp(var->name, "queue-thereare")) {
2548                                                 strncpy(q->sound_thereare, var->value, sizeof(q->sound_thereare) - 1);
2549                                         } else if (!strcasecmp(var->name, "queue-callswaiting")) {
2550                                                 strncpy(q->sound_calls, var->value, sizeof(q->sound_calls) - 1);
2551                                         } else if (!strcasecmp(var->name, "queue-holdtime")) {
2552                                                 strncpy(q->sound_holdtime, var->value, sizeof(q->sound_holdtime) - 1);
2553                                         } else if (!strcasecmp(var->name, "queue-minutes")) {
2554                                                 strncpy(q->sound_minutes, var->value, sizeof(q->sound_minutes) - 1);
2555                                         } else if (!strcasecmp(var->name, "queue-seconds")) {
2556                                                 strncpy(q->sound_seconds, var->value, sizeof(q->sound_seconds) - 1);
2557                                         } else if (!strcasecmp(var->name, "queue-lessthan")) {
2558                                                 strncpy(q->sound_lessthan, var->value, sizeof(q->sound_lessthan) - 1);
2559                                         } else if (!strcasecmp(var->name, "queue-thankyou")) {
2560                                                 strncpy(q->sound_thanks, var->value, sizeof(q->sound_thanks) - 1);
2561                                         } else if (!strcasecmp(var->name, "queue-reporthold")) {
2562                                                 strncpy(q->sound_reporthold, var->value, sizeof(q->sound_reporthold) - 1);
2563                                         } else if (!strcasecmp(var->name, "announce-frequency")) {
2564                                                 q->announcefrequency = atoi(var->value);
2565                                         } else if (!strcasecmp(var->name, "announce-round-seconds")) {
2566                                                 q->roundingseconds = atoi(var->value);
2567                                                 if(q->roundingseconds>60 || q->roundingseconds<0) {
2568                                                         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);
2569                                                         q->roundingseconds=0;
2570                                                 }
2571                                         } else if (!strcasecmp(var->name, "announce-holdtime")) {
2572                                                 q->announceholdtime = (!strcasecmp(var->value,"once")) ? 1 : ast_true(var->value);
2573                                         } else if (!strcasecmp(var->name, "retry")) {
2574                                                 q->retry = atoi(var->value);
2575                                         } else if (!strcasecmp(var->name, "wrapuptime")) {
2576                                                 q->wrapuptime = atoi(var->value);
2577                                         } else if (!strcasecmp(var->name, "maxlen")) {
2578                                                 q->maxlen = atoi(var->value);
2579                                         } else if (!strcasecmp(var->name, "servicelevel")) {
2580                                                 q->servicelevel= atoi(var->value);
2581                                         } else if (!strcasecmp(var->name, "strategy")) {
2582                                                 q->strategy = strat2int(var->value);
2583                                                 if (q->strategy < 0) {
2584                                                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
2585                                                         q->strategy = 0;
2586                                                 }
2587                                         } else if (!strcasecmp(var->name, "joinempty")) {
2588                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_JOINEMPTY);
2589                                         } else if (!strcasecmp(var->name, "leavewhenempty")) {
2590                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_LEAVEWHENEMPTY);
2591                                         } else if (!strcasecmp(var->name, "eventwhencalled")) {
2592                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_EVENTWHENCALLED);
2593                                         } else if (!strcasecmp(var->name, "reportholdtime")) {
2594                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_REPORTHOLDTIME);
2595                                         } else if (!strcasecmp(var->name, "memberdelay")) {
2596                                                 q->memberdelay = atoi(var->value);
2597                                         } else if (!strcasecmp(var->name, "weight")) {
2598                                                 q->weight = atoi(var->value);
2599                                                 if (q->weight)
2600                                                         use_weight++;
2601                                         } else {
2602                                                 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
2603                                         }
2604                                         var = var->next;
2605                                 }
2606                                 if (q->retry < 0)
2607                                         q->retry = DEFAULT_RETRY;
2608                                 if (q->timeout < 0)
2609                                         q->timeout = DEFAULT_TIMEOUT;
2610                                 if (q->maxlen < 0)
2611                                         q->maxlen = 0;
2612                                 if (!new) 
2613                                         ast_mutex_unlock(&q->lock);
2614                                 if (new) {
2615                                         q->next = queues;
2616                                         queues = q;
2617                                 }
2618                         }
2619                 } else {        
2620                         /* Initialize global settings */
2621                         queue_persistent_members = 0;
2622                         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
2623                             queue_persistent_members = ast_true(general_val);
2624                 }
2625                 cat = ast_category_browse(cfg, cat);
2626         }
2627         ast_config_destroy(cfg);
2628         q = queues;
2629         ql = NULL;
2630         while(q) {
2631                 qn = q->next;
2632                 if (ast_test_flag(q, QUEUE_FLAG_DEAD)) {
2633                         if (ql)
2634                                 ql->next = q->next;
2635                         else
2636                                 queues = q->next;
2637                         if (!q->count) {
2638                                 free(q);
2639                         } else
2640                                 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
2641                 } else {
2642                         for (cur = q->members; cur; cur = cur->next)
2643                                 cur->status = ast_device_state(cur->interface);
2644                         ql = q;
2645                 }
2646                 q = qn;
2647         }
2648         ast_mutex_unlock(&qlock);
2649 }
2650
2651 static char *status2str(int status, char *buf, int buflen)
2652 {
2653         switch(status) {
2654         case AST_DEVICE_UNKNOWN:
2655                 strncpy(buf, "unknown", buflen - 1);
2656                 break;
2657         case AST_DEVICE_NOT_INUSE:
2658                 strncpy(buf, "notinuse", buflen - 1);
2659                 break;
2660         case AST_DEVICE_INUSE:
2661                 strncpy(buf, "inuse", buflen - 1);
2662                 break;
2663         case AST_DEVICE_BUSY:
2664                 strncpy(buf, "busy", buflen - 1);
2665                 break;
2666         case AST_DEVICE_INVALID:
2667                 strncpy(buf, "invalid", buflen - 1);
2668                 break;
2669         case AST_DEVICE_UNAVAILABLE:
2670                 strncpy(buf, "unavailable", buflen - 1);
2671                 break;
2672         default:
2673                 snprintf(buf, buflen, "unknown status %d", status);
2674         }
2675         return buf;
2676 }
2677
2678 static int __queues_show(int fd, int argc, char **argv, int queue_show)
2679 {
2680         struct ast_call_queue *q;
2681         struct queue_ent *qe;
2682         struct member *mem;
2683         int pos;
2684         time_t now;
2685         char max[80] = "";
2686         char calls[80] = "";
2687         char tmpbuf[80] = "";
2688         float sl = 0;
2689
2690         time(&now);
2691         if ((!queue_show && argc != 2) || (queue_show && argc != 3))
2692                 return RESULT_SHOWUSAGE;
2693         ast_mutex_lock(&qlock);
2694         q = queues;
2695         if (!q) {       
2696                 ast_mutex_unlock(&qlock);
2697                 if (queue_show)
2698                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
2699                 else
2700                         ast_cli(fd, "No queues.\n");
2701                 return RESULT_SUCCESS;
2702         }
2703         while(q) {
2704                 ast_mutex_lock(&q->lock);
2705                 if (queue_show) {
2706                         if (strcasecmp(q->name, argv[2]) != 0) {
2707                                 ast_mutex_unlock(&q->lock);
2708                                 q = q->next;
2709                                 if (!q) {
2710                                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
2711                                         break;
2712                                 }
2713                                 continue;
2714                         }
2715                 }
2716                 if (q->maxlen)
2717                         snprintf(max, sizeof(max), "%d", q->maxlen);
2718                 else
2719                         strncpy(max, "unlimited", sizeof(max) - 1);
2720                 sl = 0;
2721                 if(q->callscompleted > 0)
2722                         sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
2723                 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",
2724                         q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
2725                 if (q->members) {
2726                         ast_cli(fd, "   Members: \n");
2727                         for (mem = q->members; mem; mem = mem->next) {
2728                                 if (mem->penalty)
2729                                         snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
2730                                 else
2731                                         max[0] = '\0';
2732                                 if (mem->dynamic)
2733                                         strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
2734                                 if (mem->paused)
2735                                         strncat(max, " (paused)", sizeof(max) - strlen(max) - 1);
2736                                 if (mem->status)
2737                                         snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
2738                                 if (mem->calls) {
2739                                         snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
2740                                                         mem->calls, (long)(time(NULL) - mem->lastcall));
2741                                 } else
2742                                         strncpy(calls, " has taken no calls yet", sizeof(calls) - 1);
2743                                 ast_cli(fd, "      %s%s%s\n", mem->interface, max, calls);
2744                         }
2745                 } else
2746                         ast_cli(fd, "   No Members\n");
2747                 if (q->head) {
2748                         pos = 1;
2749                         ast_cli(fd, "   Callers: \n");
2750                         for (qe = q->head; qe; qe = qe->next) 
2751                                 ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)\n", pos++, qe->chan->name,
2752                                                                 (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio);
2753                 } else
2754                         ast_cli(fd, "   No Callers\n");
2755                 ast_cli(fd, "\n");
2756                 ast_mutex_unlock(&q->lock);
2757                 q = q->next;
2758                 if (queue_show)
2759                         break;
2760         }