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