deb3bcac7142df67995b0115c356bcc0d0ffd2bb
[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 = NULL;
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                 cur_member = pm_queue->members;
1747                 while (cur_member) {
1748                         if (cur_member->dynamic) {
1749                                 value_len = strlen(value);
1750                                 res = snprintf(value+value_len, sizeof(value)-value_len, "%s;%d;%d;", cur_member->interface, cur_member->penalty, cur_member->paused);
1751                                 if (res != strlen(value + value_len)) {
1752                                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
1753                                         break;
1754                                 }
1755                         }                                       
1756                         cur_member = cur_member->next;
1757                 }
1758
1759                 if (!ast_strlen_zero(value) && !cur_member) {
1760                         if (ast_db_put(pm_family, pm_queue->name, value))
1761                             ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
1762                 } else {
1763                         /* Delete the entry if the queue is empty or there is an error */
1764                     ast_db_del(pm_family, pm_queue->name);
1765                 }
1766
1767         }
1768
1769 }
1770
1771 static int remove_from_queue(char *queuename, char *interface)
1772 {
1773         struct ast_call_queue *q;
1774         struct member *last_member, *look;
1775         int res = RES_NOSUCHQUEUE;
1776
1777         ast_mutex_lock(&qlock);
1778         for (q = queues ; q ; q = q->next) {
1779                 ast_mutex_lock(&q->lock);
1780                 if (!strcmp(q->name, queuename)) {
1781                         if ((last_member = interface_exists(q, interface))) {
1782                                 if ((look = q->members) == last_member) {
1783                                         q->members = last_member->next;
1784                                 } else {
1785                                         while (look != NULL) {
1786                                                 if (look->next == last_member) {
1787                                                         look->next = last_member->next;
1788                                                         break;
1789                                                 } else {
1790                                                          look = look->next;
1791                                                 }
1792                                         }
1793                                 }
1794                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
1795                                                 "Queue: %s\r\n"
1796                                                 "Location: %s\r\n",
1797                                         q->name, last_member->interface);
1798                                 free(last_member);
1799
1800                                 if (queue_persistent_members)
1801                                     dump_queue_members(q);
1802
1803                                 res = RES_OKAY;
1804                         } else {
1805                                 res = RES_EXISTS;
1806                         }
1807                         ast_mutex_unlock(&q->lock);
1808                         break;
1809                 }
1810                 ast_mutex_unlock(&q->lock);
1811         }
1812         ast_mutex_unlock(&qlock);
1813         return res;
1814 }
1815
1816 static int add_to_queue(char *queuename, char *interface, int penalty, int paused)
1817 {
1818         struct ast_call_queue *q;
1819         struct member *new_member;
1820         int res = RES_NOSUCHQUEUE;
1821
1822         ast_mutex_lock(&qlock);
1823         for (q = queues ; q ; q = q->next) {
1824                 ast_mutex_lock(&q->lock);
1825                 if (!strcmp(q->name, queuename)) {
1826                         if (interface_exists(q, interface) == NULL) {
1827                                 new_member = create_queue_node(interface, penalty, paused);
1828
1829                                 if (new_member != NULL) {
1830                                         new_member->dynamic = 1;
1831                                         new_member->next = q->members;
1832                                         q->members = new_member;
1833                                         manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
1834                                                 "Queue: %s\r\n"
1835                                                 "Location: %s\r\n"
1836                                                 "Membership: %s\r\n"
1837                                                 "Penalty: %d\r\n"
1838                                                 "CallsTaken: %d\r\n"
1839                                                 "LastCall: %ld\r\n"
1840                                                 "Status: %d\r\n"
1841                                                 "Paused: %d\r\n",
1842                                         q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
1843                                         new_member->penalty, new_member->calls, new_member->lastcall, new_member->status, new_member->paused);
1844                                         
1845                                         if (queue_persistent_members)
1846                                                 dump_queue_members(q);
1847
1848                                         res = RES_OKAY;
1849                                 } else {
1850                                         res = RES_OUTOFMEMORY;
1851                                 }
1852                         } else {
1853                                 res = RES_EXISTS;
1854                         }
1855                         ast_mutex_unlock(&q->lock);
1856                         break;
1857                 }
1858                 ast_mutex_unlock(&q->lock);
1859         }
1860         ast_mutex_unlock(&qlock);
1861         return res;
1862 }
1863
1864 static int set_member_paused(char *queuename, char *interface, int paused)
1865 {
1866         int found = 0;
1867         struct ast_call_queue *q;
1868         struct member *mem;
1869
1870         /* Special event for when all queues are paused - individual events still generated */
1871
1872         if (ast_strlen_zero(queuename))
1873                 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
1874
1875         ast_mutex_lock(&qlock);
1876         for (q = queues ; q ; q = q->next) {
1877                 ast_mutex_lock(&q->lock);
1878                 if (ast_strlen_zero(queuename) || !strcmp(q->name, queuename)) {
1879                         if ((mem = interface_exists(q, interface))) {
1880                                 found++;
1881                                 if (mem->paused == paused)
1882                                         ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
1883                                 mem->paused = paused;
1884
1885                                 if (queue_persistent_members)
1886                                     dump_queue_members(q);
1887
1888                                 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
1889
1890                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
1891                                         "Queue: %s\r\n"
1892                                         "Location: %s\r\n"
1893                                         "Paused: %d\r\n",
1894                                                 q->name, mem->interface, paused);
1895                         }
1896                 }
1897                 ast_mutex_unlock(&q->lock);
1898         }
1899         ast_mutex_unlock(&qlock);
1900
1901         if (found)
1902                 return RESULT_SUCCESS;
1903         else
1904                 return RESULT_FAILURE;
1905 }
1906
1907 /* Add members saved in the queue members DB file saves
1908  * created by dump_queue_members(), back into the queues */
1909 static void reload_queue_members(void)
1910 {
1911         char *cur_pm_ptr;       
1912         char *pm_queue_name;
1913         char *pm_interface;
1914         char *pm_penalty_tok;
1915         int pm_penalty = 0;
1916         char *pm_paused_tok;
1917         int pm_paused = 0;
1918         struct ast_db_entry *pm_db_tree = NULL;
1919         int pm_family_len = 0;
1920         struct ast_call_queue *cur_queue = NULL;
1921         char queue_data[PM_MAX_LEN];
1922
1923         pm_db_tree = ast_db_gettree(pm_family, NULL);
1924
1925         pm_family_len = strlen(pm_family);
1926         ast_mutex_lock(&qlock);
1927         /* Each key in 'pm_family' is the name of a specific queue in which
1928          * we will reload members into. */
1929         while (pm_db_tree) {
1930                 pm_queue_name = pm_db_tree->key+pm_family_len+2;
1931
1932                 cur_queue = queues;
1933                 while (cur_queue) {
1934                         ast_mutex_lock(&cur_queue->lock);
1935                         
1936                         if (strcmp(pm_queue_name, cur_queue->name) == 0)
1937                                 break;
1938                         
1939                         ast_mutex_unlock(&cur_queue->lock);
1940                         
1941                         cur_queue = cur_queue->next;
1942                 }
1943
1944                 if (!cur_queue) {
1945                         /* If the queue no longer exists, remove it from the
1946                          * database */
1947                         ast_db_del(pm_family, pm_queue_name);
1948                         pm_db_tree = pm_db_tree->next;
1949                         continue;
1950                 } else
1951                         ast_mutex_unlock(&cur_queue->lock);
1952
1953                 if (!ast_db_get(pm_family, pm_queue_name, queue_data, PM_MAX_LEN)) {
1954                         cur_pm_ptr = queue_data;
1955                         while ((pm_interface = strsep(&cur_pm_ptr, ";"))) {
1956                                 /* On the last iteration, pm_interface is a pointer to an empty string. Don't report a spurious error. */
1957                                 if (pm_interface[0] == 0)
1958                                         break;
1959                                 if (!(pm_penalty_tok = strsep(&cur_pm_ptr, ";"))) {
1960                                         ast_log(LOG_WARNING, "Error parsing corrupted Queue DB string for '%s' (penalty)\n", pm_queue_name);
1961                                         break;
1962                                 }
1963                                 pm_penalty = strtol(pm_penalty_tok, NULL, 10);
1964                                 if (errno == ERANGE) {
1965                                         ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", pm_penalty_tok);
1966                                         break;
1967                                 }
1968
1969                                 /* If ptr[1] is ';', the string is 1 char long and can't be an interface */
1970
1971                                 if (cur_pm_ptr[1] == ';') {
1972                                         if (!(pm_paused_tok = strsep(&cur_pm_ptr, ";"))) {
1973                                                 ast_log(LOG_WARNING, "Error parsing corrupted Queue DB string for '%s' (paused)\n", pm_queue_name);
1974                                                 break;
1975                                         }
1976                                         pm_paused = strtol(pm_paused_tok, NULL, 10);
1977                                         if ((errno == ERANGE) || (pm_paused < 0 || pm_paused > 1)) {
1978                                                 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", pm_paused_tok);
1979                                                 break;
1980                                         }
1981                                 } else if (option_debug)
1982                                         ast_verbose(VERBOSE_PREFIX_3 "Found old-format queue member %s:%s\n", pm_queue_name, pm_interface);
1983         
1984                                 if (option_debug)
1985                                         ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", pm_queue_name, pm_interface, pm_penalty, pm_paused);
1986         
1987                                 if (add_to_queue(pm_queue_name, pm_interface, pm_penalty, pm_paused) == RES_OUTOFMEMORY) {
1988                                         ast_log(LOG_ERROR, "Out of Memory when loading queue member from astdb\n");
1989                                         break;
1990                                 }
1991                         }
1992                 }
1993                 
1994                 pm_db_tree = pm_db_tree->next;
1995         }
1996
1997         ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
1998         ast_mutex_unlock(&qlock);
1999         if (pm_db_tree) {
2000                 ast_db_freetree(pm_db_tree);
2001                 pm_db_tree = NULL;
2002         }
2003 }
2004
2005 static int pqm_exec(struct ast_channel *chan, void *data)
2006 {
2007         struct localuser *u;
2008         char *queuename, *interface;
2009
2010         if (!data) {
2011                 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface])\n");
2012                 return -1;
2013         }
2014
2015         queuename = ast_strdupa((char *)data);
2016         if (!queuename) {
2017                 ast_log(LOG_ERROR, "Out of memory\n");
2018                 return -1;
2019         }
2020
2021         interface = strchr(queuename, '|');
2022         if (!interface) {
2023                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2024                 return -1;
2025         }
2026
2027         LOCAL_USER_ADD(u);
2028
2029         *interface = '\0';
2030         interface++;
2031
2032         if (set_member_paused(queuename, interface, 1)) {
2033                 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", interface);
2034                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2035                         chan->priority += 100;
2036                         LOCAL_USER_REMOVE(u);
2037                         return 0;
2038                 }
2039                 return -1;
2040         }
2041
2042         LOCAL_USER_REMOVE(u);
2043
2044         return 0;
2045 }
2046
2047 static int upqm_exec(struct ast_channel *chan, void *data)
2048 {
2049         struct localuser *u;
2050         char *queuename, *interface;
2051
2052         if (!data) {
2053                 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface])\n");
2054                 return -1;
2055         }
2056
2057         queuename = ast_strdupa((char *)data);
2058         if (!queuename) {
2059                 ast_log(LOG_ERROR, "Out of memory\n");
2060                 return -1;
2061         }
2062
2063         interface = strchr(queuename, '|');
2064         if (!interface) {
2065                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2066                 return -1;
2067         }
2068
2069         LOCAL_USER_ADD(u);
2070
2071         *interface = '\0';
2072         interface++;
2073
2074         if (set_member_paused(queuename, interface, 0)) {
2075                 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", interface);
2076                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2077                         chan->priority += 100;
2078                         LOCAL_USER_REMOVE(u);
2079                         return 0;
2080                 }
2081                 return -1;
2082         }
2083
2084         LOCAL_USER_REMOVE(u);
2085
2086         return 0;
2087 }
2088
2089 static int rqm_exec(struct ast_channel *chan, void *data)
2090 {
2091         int res=-1;
2092         struct localuser *u;
2093         char *info, *queuename;
2094         char tmpchan[256]="";
2095         char *interface = NULL;
2096
2097         if (!data) {
2098                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
2099                 return -1;
2100         }
2101
2102         info = ast_strdupa((char *)data);
2103         if (!info) {
2104                 ast_log(LOG_ERROR, "Out of memory\n");
2105                 return -1;
2106         }
2107
2108         LOCAL_USER_ADD(u);
2109
2110         queuename = info;
2111         if (queuename) {
2112                 interface = strchr(queuename, '|');
2113                 if (interface) {
2114                         *interface = '\0';
2115                         interface++;
2116                 }
2117                 else {
2118                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2119                         interface = strrchr(tmpchan, '-');
2120                         if (interface)
2121                                 *interface = '\0';
2122                         interface = tmpchan;
2123                 }
2124         }
2125
2126         switch (remove_from_queue(queuename, interface)) {
2127         case RES_OKAY:
2128                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2129                 res = 0;
2130                 break;
2131         case RES_EXISTS:
2132                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2133                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2134                         chan->priority += 100;
2135                 }
2136                 res = 0;
2137                 break;
2138         case RES_NOSUCHQUEUE:
2139                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2140                 res = 0;
2141                 break;
2142         case RES_OUTOFMEMORY:
2143                 ast_log(LOG_ERROR, "Out of memory\n");
2144                 break;
2145         }
2146
2147         LOCAL_USER_REMOVE(u);
2148         return res;
2149 }
2150
2151 static int aqm_exec(struct ast_channel *chan, void *data)
2152 {
2153         int res=-1;
2154         struct localuser *u;
2155         char *queuename;
2156         char *info;
2157         char tmpchan[512]="";
2158         char *interface=NULL;
2159         char *penaltys=NULL;
2160         int penalty = 0;
2161
2162         if (!data) {
2163                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
2164                 return -1;
2165         }
2166
2167         info = ast_strdupa((char *)data);
2168         if (!info) {
2169                 ast_log(LOG_ERROR, "Out of memory\n");
2170                 return -1;
2171         }
2172         LOCAL_USER_ADD(u);
2173
2174         queuename = info;
2175         if (queuename) {
2176                 interface = strchr(queuename, '|');
2177                 if (interface) {
2178                         *interface = '\0';
2179                         interface++;
2180                 }
2181                 if (interface) {
2182                         penaltys = strchr(interface, '|');
2183                         if (penaltys) {
2184                                 *penaltys = '\0';
2185                                 penaltys++;
2186                         }
2187                 }
2188                 if (!interface || ast_strlen_zero(interface)) {
2189                         strncpy(tmpchan, chan->name, sizeof(tmpchan) - 1);
2190                         interface = strrchr(tmpchan, '-');
2191                         if (interface)
2192                                 *interface = '\0';
2193                         interface = tmpchan;
2194                 }
2195                 if (penaltys && !ast_strlen_zero(penaltys)) {
2196                         if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
2197                                 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
2198                                 penalty = 0;
2199                         }
2200                 }
2201         }
2202
2203         switch (add_to_queue(queuename, interface, penalty, 0)) {
2204         case RES_OKAY:
2205                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
2206                 res = 0;
2207                 break;
2208         case RES_EXISTS:
2209                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2210                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2211                         chan->priority += 100;
2212                 }
2213                 res = 0;
2214                 break;
2215         case RES_NOSUCHQUEUE:
2216                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
2217                 res = 0;
2218                 break;
2219         case RES_OUTOFMEMORY:
2220                 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", interface, queuename);
2221                 break;
2222         }
2223
2224         LOCAL_USER_REMOVE(u);
2225         return res;
2226 }
2227
2228 static int queue_exec(struct ast_channel *chan, void *data)
2229 {
2230         int res=-1;
2231         int ringing=0;
2232         struct localuser *u;
2233         char *queuename;
2234         char info[512];
2235         char *info_ptr = info;
2236         char *options = NULL;
2237         char *url = NULL;
2238         char *announceoverride = NULL;
2239         char *user_priority;
2240         int prio;
2241         char *queuetimeoutstr = NULL;
2242
2243         /* whether to exit Queue application after the timeout hits */
2244         int go_on = 0;
2245
2246         /* Our queue entry */
2247         struct queue_ent qe;
2248         
2249         if (!data || ast_strlen_zero(data)) {
2250                 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2251                 return -1;
2252         }
2253         
2254         LOCAL_USER_ADD(u);
2255
2256         /* Setup our queue entry */
2257         memset(&qe, 0, sizeof(qe));
2258         qe.start = time(NULL);
2259         
2260         /* Parse our arguments XXX Check for failure XXX */
2261         strncpy(info, (char *) data, sizeof(info) - 1);
2262         queuename = strsep(&info_ptr, "|");
2263         options = strsep(&info_ptr, "|");
2264         url = strsep(&info_ptr, "|");
2265         announceoverride = strsep(&info_ptr, "|");
2266         queuetimeoutstr = info_ptr;
2267
2268         /* set the expire time based on the supplied timeout; */
2269         if (queuetimeoutstr)
2270                 qe.expire = qe.start + atoi(queuetimeoutstr);
2271         else
2272                 qe.expire = 0;
2273
2274         /* Get the priority from the variable ${QUEUE_PRIO} */
2275         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2276         if (user_priority) {
2277                 if (sscanf(user_priority, "%d", &prio) == 1) {
2278                         if (option_debug)
2279                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2280                                                                 chan->name, prio);
2281                 } else {
2282                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2283                                                         user_priority, chan->name);
2284                         prio = 0;
2285                 }
2286         } else {
2287                 if (option_debug > 2)
2288                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2289                 prio = 0;
2290         }
2291
2292         if (options) {
2293                 if (strchr(options, 'r')) {
2294                         ringing = 1;
2295                 }
2296         }
2297
2298         if (option_debug)  
2299                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2300                                 queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
2301
2302         qe.chan = chan;
2303         qe.prio = (int)prio;
2304         qe.last_pos_said = 0;
2305         qe.last_pos = 0;
2306         if (!join_queue(queuename, &qe)) {
2307                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : "");
2308                 /* Start music on hold */
2309 check_turns:
2310                 if (ringing) {
2311                         ast_indicate(chan, AST_CONTROL_RINGING);
2312                 } else {              
2313                         ast_moh_start(chan, qe.moh);
2314                 }
2315                 for (;;) {
2316                         /* This is the wait loop for callers 2 through maxlen */
2317
2318                         res = wait_our_turn(&qe, ringing);
2319                         /* If they hungup, return immediately */
2320                         if (res < 0) {
2321                                 /* Record this abandoned call */
2322                                 record_abandoned(&qe);
2323                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2324                                 if (option_verbose > 2) {
2325                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2326                                         res = -1;
2327                                 }
2328                                 break;
2329                         }
2330                         if (!res) 
2331                                 break;
2332                         if (valid_exit(&qe, res)) {
2333                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2334                                 break;
2335                         }
2336                 }
2337                 if (!res) {
2338                         int makeannouncement = 0;
2339                         for (;;) {
2340                                 /* This is the wait loop for the head caller*/
2341                                 /* To exit, they may get their call answered; */
2342                                 /* they may dial a digit from the queue context; */
2343                                 /* or, they may timeout. */
2344
2345                                 /* Leave if we have exceeded our queuetimeout */
2346                                 if (qe.expire && (time(NULL) > qe.expire)) {
2347                                         res = 0;
2348                                         break;
2349                                 }
2350
2351                                 if (makeannouncement) {
2352                                         /* Make a position announcement, if enabled */
2353                                         if (qe.parent->announcefrequency && !ringing)
2354                                                 say_position(&qe);
2355                                 }
2356                                 makeannouncement = 1;
2357
2358                                 /* Try calling all queue members for 'timeout' seconds */
2359                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
2360                                 if (res) {
2361                                         if (res < 0) {
2362                                                 if (!qe.handled)
2363                                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2364                                         } else if (res > 0)
2365                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2366                                         break;
2367                                 }
2368
2369                                 /* leave the queue if no agents, if enabled */
2370                                 if (ast_test_flag(qe.parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe.parent)) {
2371                                         res = 0;
2372                                         break;
2373                                 }
2374
2375                                 /* Leave if we have exceeded our queuetimeout */
2376                                 if (qe.expire && (time(NULL) > qe.expire)) {
2377                                         res = 0;
2378                                         break;
2379                                 }
2380
2381                                 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
2382                                 res = wait_a_bit(&qe);
2383                                 if (res < 0) {
2384                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2385                                         if (option_verbose > 2) {
2386                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
2387                                                 res = -1;
2388                                         }
2389                                         break;
2390                                 }
2391                                 if (res && valid_exit(&qe, res)) {
2392                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2393                                         break;
2394                                 }
2395                                 /* exit after 'timeout' cycle if 'n' option enabled */
2396                                 if (go_on) {
2397                                         if (option_verbose > 2) {
2398                                                 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
2399                                                 res = -1;
2400                                         }
2401                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2402                                         res = 0;
2403                                         break;
2404                                 }
2405                                 /* Since this is a priority queue and 
2406                                  * it is not sure that we are still at the head
2407                                  * of the queue, go and check for our turn again.
2408                                  */
2409                                 if (!is_our_turn(&qe)) {
2410                                         if (option_debug)
2411                                                 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
2412                                                                 qe.chan->name);
2413                                         goto check_turns;
2414                                 }
2415                         }
2416                 }
2417                 /* Don't allow return code > 0 */
2418                 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
2419                         res = 0;        
2420                         if (ringing) {
2421                                 ast_indicate(chan, -1);
2422                         } else {
2423                                 ast_moh_stop(chan);
2424                         }                       
2425                         ast_stopstream(chan);
2426                 }
2427                 leave_queue(&qe);
2428         } else {
2429                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
2430                 res =  0;
2431         }
2432         LOCAL_USER_REMOVE(u);
2433         return res;
2434 }
2435
2436 static void reload_queues(void)
2437 {
2438         struct ast_call_queue *q, *ql, *qn;
2439         struct ast_config *cfg;
2440         char *cat, *tmp;
2441         struct ast_variable *var;
2442         struct member *prev, *cur;
2443         int new;
2444         char *general_val = NULL;
2445         
2446         cfg = ast_config_load("queues.conf");
2447         if (!cfg) {
2448                 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
2449                 return;
2450         }
2451         ast_mutex_lock(&qlock);
2452         use_weight=0;
2453         /* Mark all queues as dead for the moment */
2454         q = queues;
2455         while(q) {
2456                 ast_set_flag(q, QUEUE_FLAG_DEAD);
2457                 q = q->next;
2458         }
2459         /* Chug through config file */
2460         cat = ast_category_browse(cfg, NULL);
2461         while(cat) {
2462                 if (strcasecmp(cat, "general")) {       /* Define queue */
2463                         /* Look for an existing one */
2464                         q = queues;
2465                         while(q) {
2466                                 if (!strcmp(q->name, cat))
2467                                         break;
2468                                 q = q->next;
2469                         }
2470                         if (!q) {
2471                                 /* Make one then */
2472                                 q = malloc(sizeof(struct ast_call_queue));
2473                                 if (q) {
2474                                         /* Initialize it */
2475                                         memset(q, 0, sizeof(struct ast_call_queue));
2476                                         ast_mutex_init(&q->lock);
2477                                         strncpy(q->name, cat, sizeof(q->name) - 1);
2478                                         new = 1;
2479                                 } else new = 0;
2480                         } else
2481                                         new = 0;
2482                         if (q) {
2483                                 if (!new) 
2484                                         ast_mutex_lock(&q->lock);
2485                                 /* Re-initialize the queue */
2486                                 ast_clear_flag(q, QUEUE_FLAG_DEAD);
2487                                 q->retry = DEFAULT_RETRY;
2488                                 q->timeout = -1;
2489                                 q->maxlen = 0;
2490                                 q->announcefrequency = 0;
2491                                 q->announceholdtime = 0;
2492                                 q->roundingseconds = 0; /* Default - don't announce seconds */
2493                                 q->holdtime = 0;
2494                                 q->callscompleted = 0;
2495                                 q->callsabandoned = 0;
2496                                 q->callscompletedinsl = 0;
2497                                 q->servicelevel = 0;
2498                                 q->wrapuptime = 0;
2499                                 free_members(q, 0);
2500                                 q->moh[0] = '\0';
2501                                 q->announce[0] = '\0';
2502                                 q->context[0] = '\0';
2503                                 q->monfmt[0] = '\0';
2504                                 strncpy(q->sound_next, "queue-youarenext", sizeof(q->sound_next) - 1);
2505                                 strncpy(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare) - 1);
2506                                 strncpy(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls) - 1);
2507                                 strncpy(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime) - 1);
2508                                 strncpy(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes) - 1);
2509                                 strncpy(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds) - 1);
2510                                 strncpy(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks) - 1);
2511                                 strncpy(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan) - 1);
2512                                 strncpy(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold) - 1);
2513                                 prev = q->members;
2514                                 if (prev) {
2515                                         /* find the end of any dynamic members */
2516                                         while(prev->next)
2517                                                 prev = prev->next;
2518                                 }
2519                                 var = ast_variable_browse(cfg, cat);
2520                                 while(var) {
2521                                         if (!strcasecmp(var->name, "member")) {
2522                                                 /* Add a new member */
2523                                                 cur = malloc(sizeof(struct member));
2524                                                 if (cur) {
2525                                                         memset(cur, 0, sizeof(struct member));
2526                                                         strncpy(cur->interface, var->value, sizeof(cur->interface) - 1);
2527                                                         if ((tmp = strchr(cur->interface, ','))) {
2528                                                                 *tmp = '\0';
2529                                                                 tmp++;
2530                                                                 cur->penalty = atoi(tmp);
2531                                                                 if (cur->penalty < 0)
2532                                                                         cur->penalty = 0;
2533                                                         }
2534                                                         if (!strchr(cur->interface, '/'))
2535                                                                 ast_log(LOG_WARNING, "No location at line %d of queue.conf\n", var->lineno);
2536                                                         if (prev)
2537                                                                 prev->next = cur;
2538                                                         else
2539                                                                 q->members = cur;
2540                                                         prev = cur;
2541                                                 }
2542                                         } else if (!strcasecmp(var->name, "music") || !strcasecmp(var->name, "musiconhold")) {
2543                                                 strncpy(q->moh, var->value, sizeof(q->moh) - 1);
2544                                         } else if (!strcasecmp(var->name, "announce")) {
2545                                                 strncpy(q->announce, var->value, sizeof(q->announce) - 1);
2546                                         } else if (!strcasecmp(var->name, "context")) {
2547                                                 strncpy(q->context, var->value, sizeof(q->context) - 1);
2548                                         } else if (!strcasecmp(var->name, "timeout")) {
2549                                                 q->timeout = atoi(var->value);
2550                                         } else if (!strcasecmp(var->name, "monitor-join")) {
2551                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_MONJOIN);
2552                                         } else if (!strcasecmp(var->name, "monitor-format")) {
2553                                                 strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1);
2554                                         } else if (!strcasecmp(var->name, "queue-youarenext")) {
2555                                                 strncpy(q->sound_next, var->value, sizeof(q->sound_next) - 1);
2556                                         } else if (!strcasecmp(var->name, "queue-thereare")) {
2557                                                 strncpy(q->sound_thereare, var->value, sizeof(q->sound_thereare) - 1);
2558                                         } else if (!strcasecmp(var->name, "queue-callswaiting")) {
2559                                                 strncpy(q->sound_calls, var->value, sizeof(q->sound_calls) - 1);
2560                                         } else if (!strcasecmp(var->name, "queue-holdtime")) {
2561                                                 strncpy(q->sound_holdtime, var->value, sizeof(q->sound_holdtime) - 1);
2562                                         } else if (!strcasecmp(var->name, "queue-minutes")) {
2563                                                 strncpy(q->sound_minutes, var->value, sizeof(q->sound_minutes) - 1);
2564                                         } else if (!strcasecmp(var->name, "queue-seconds")) {
2565                                                 strncpy(q->sound_seconds, var->value, sizeof(q->sound_seconds) - 1);
2566                                         } else if (!strcasecmp(var->name, "queue-lessthan")) {
2567                                                 strncpy(q->sound_lessthan, var->value, sizeof(q->sound_lessthan) - 1);
2568                                         } else if (!strcasecmp(var->name, "queue-thankyou")) {
2569                                                 strncpy(q->sound_thanks, var->value, sizeof(q->sound_thanks) - 1);
2570                                         } else if (!strcasecmp(var->name, "queue-reporthold")) {
2571                                                 strncpy(q->sound_reporthold, var->value, sizeof(q->sound_reporthold) - 1);
2572                                         } else if (!strcasecmp(var->name, "announce-frequency")) {
2573                                                 q->announcefrequency = atoi(var->value);
2574                                         } else if (!strcasecmp(var->name, "announce-round-seconds")) {
2575                                                 q->roundingseconds = atoi(var->value);
2576                                                 if(q->roundingseconds>60 || q->roundingseconds<0) {
2577                                                         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);
2578                                                         q->roundingseconds=0;
2579                                                 }
2580                                         } else if (!strcasecmp(var->name, "announce-holdtime")) {
2581                                                 q->announceholdtime = (!strcasecmp(var->value,"once")) ? 1 : ast_true(var->value);
2582                                         } else if (!strcasecmp(var->name, "retry")) {
2583                                                 q->retry = atoi(var->value);
2584                                         } else if (!strcasecmp(var->name, "wrapuptime")) {
2585                                                 q->wrapuptime = atoi(var->value);
2586                                         } else if (!strcasecmp(var->name, "maxlen")) {
2587                                                 q->maxlen = atoi(var->value);
2588                                         } else if (!strcasecmp(var->name, "servicelevel")) {
2589                                                 q->servicelevel= atoi(var->value);
2590                                         } else if (!strcasecmp(var->name, "strategy")) {
2591                                                 q->strategy = strat2int(var->value);
2592                                                 if (q->strategy < 0) {
2593                                                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy, using ringall instead\n", var->value);
2594                                                         q->strategy = 0;
2595                                                 }
2596                                         } else if (!strcasecmp(var->name, "joinempty")) {
2597                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_JOINEMPTY);
2598                                         } else if (!strcasecmp(var->name, "leavewhenempty")) {
2599                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_LEAVEWHENEMPTY);
2600                                         } else if (!strcasecmp(var->name, "eventwhencalled")) {
2601                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_EVENTWHENCALLED);
2602                                         } else if (!strcasecmp(var->name, "reportholdtime")) {
2603                                                 ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_REPORTHOLDTIME);
2604                                         } else if (!strcasecmp(var->name, "memberdelay")) {
2605                                                 q->memberdelay = atoi(var->value);
2606                                         } else if (!strcasecmp(var->name, "weight")) {
2607                                                 q->weight = atoi(var->value);
2608                                                 if (q->weight)
2609                                                         use_weight++;
2610                                         } else {
2611                                                 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno);
2612                                         }
2613                                         var = var->next;
2614                                 }
2615                                 if (q->retry < 0)
2616                                         q->retry = DEFAULT_RETRY;
2617                                 if (q->timeout < 0)
2618                                         q->timeout = DEFAULT_TIMEOUT;
2619                                 if (q->maxlen < 0)
2620                                         q->maxlen = 0;
2621                                 if (!new) 
2622                                         ast_mutex_unlock(&q->lock);
2623                                 if (new) {
2624                                         q->next = queues;
2625                                         queues = q;
2626                                 }
2627                         }
2628                 } else {        
2629                         /* Initialize global settings */
2630                         queue_persistent_members = 0;
2631                         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
2632                             queue_persistent_members = ast_true(general_val);
2633                 }
2634                 cat = ast_category_browse(cfg, cat);
2635         }
2636         ast_config_destroy(cfg);
2637         q = queues;
2638         ql = NULL;
2639         while(q) {
2640                 qn = q->next;
2641                 if (ast_test_flag(q, QUEUE_FLAG_DEAD)) {
2642                         if (ql)
2643                                 ql->next = q->next;
2644                         else
2645                                 queues = q->next;
2646                         if (!q->count) {
2647                                 free(q);
2648                         } else
2649                                 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
2650                 } else {
2651                         for (cur = q->members; cur; cur = cur->next)
2652                                 cur->status = ast_device_state(cur->interface);
2653                         ql = q;
2654                 }
2655                 q = qn;
2656         }
2657         ast_mutex_unlock(&qlock);
2658 }
2659
2660 static char *status2str(int status, char *buf, int buflen)
2661 {
2662         switch(status) {
2663         case AST_DEVICE_UNKNOWN:
2664                 strncpy(buf, "unknown", buflen - 1);
2665                 break;
2666         case AST_DEVICE_NOT_INUSE:
2667                 strncpy(buf, "notinuse", buflen - 1);
2668                 break;
2669         case AST_DEVICE_INUSE:
2670                 strncpy(buf, "inuse", buflen - 1);
2671                 break;
2672         case AST_DEVICE_BUSY:
2673                 strncpy(buf, "busy", buflen - 1);
2674                 break;
2675         case AST_DEVICE_INVALID:
2676                 strncpy(buf, "invalid", buflen - 1);
2677                 break;
2678         case AST_DEVICE_UNAVAILABLE:
2679                 strncpy(buf, "unavailable", buflen - 1);
2680                 break;
2681         default:
2682                 snprintf(buf, buflen, "unknown status %d", status);
2683         }
2684         return buf;
2685 }
2686
2687 static int __queues_show(int fd, int argc, char **argv, int queue_show)
2688 {
2689         struct ast_call_queue *q;
2690         struct queue_ent *qe;
2691         struct member *mem;
2692         int pos;
2693         time_t now;
2694         char max[80] = "";
2695         char calls[80] = "";
2696         char tmpbuf[80] = "";
2697         float sl = 0;
2698
2699         time(&now);
2700         if ((!queue_show && argc != 2) || (queue_show && argc != 3))
2701                 return RESULT_SHOWUSAGE;
2702         ast_mutex_lock(&qlock);
2703         q = queues;
2704         if (!q) {       
2705                 ast_mutex_unlock(&qlock);
2706                 if (queue_show)
2707                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
2708                 else
2709                         ast_cli(fd, "No queues.\n");
2710                 return RESULT_SUCCESS;
2711         }
2712         while(q) {
2713                 ast_mutex_lock(&q->lock);
2714                 if (queue_show) {
2715                         if (strcasecmp(q->name, argv[2]) != 0) {
2716                                 ast_mutex_unlock(&q->lock);
2717                                 q = q->next;
2718                                 if (!q) {
2719                                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
2720                                         break;
2721                                 }
2722                                 continue;
2723                         }
2724                 }
2725                 if (q->maxlen)
2726                         snprintf(max, sizeof(max), "%d", q->maxlen);
2727                 else
2728                         strncpy(max, "unlimited", sizeof(max) - 1);
2729                 sl = 0;
2730                 if(q->callscompleted > 0)
2731                         sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
2732                 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",
2733                         q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
2734                 if (q->members) {
2735                         ast_cli(fd, "   Members: \n");
2736                         for (mem = q->members; mem; mem = mem->next) {
2737                                 if (mem->penalty)
2738                                         snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
2739                                 else
2740                                         max[0] = '\0';
2741                                 if (mem->dynamic)
2742                                         strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
2743                                 if (mem->paused)
2744                                         strncat(max, " (paused)", sizeof(max) - strlen(max) - 1);
2745                                 if (mem->status)
2746                                         snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
2747                                 if (mem->calls) {
2748                                         snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
2749                                                         mem->calls, (long)(time(NULL) - mem->lastcall));
2750                                 } else
2751                                         strncpy(calls, " has taken no calls yet", sizeof(calls) - 1);
2752                                 ast_cli(fd, "