669e25d867cefb2ab3c21b5bea38577e21c69c82
[asterisk/asterisk.git] / apps / app_queue.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief True call queues with optional send URL on answer
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \arg Config in \ref Config_qu queues.conf
26  * 
27  * \par Development notes
28  * \note 2004-11-25: Persistent Dynamic Members added by:
29  *             NetNation Communications (www.netnation.com)
30  *             Kevin Lindsay <kevinl@netnation.com>
31  * 
32  *             Each dynamic agent in each queue is now stored in the astdb.
33  *             When asterisk is restarted, each agent will be automatically
34  *             readded into their recorded queues. This feature can be
35  *             configured with the 'persistent_members=<1|0>' setting in the
36  *             '[general]' category in queues.conf. The default is on.
37  * 
38  * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
39  *
40  * \note These features added by David C. Troy <dave@toad.net>:
41  *    - Per-queue holdtime calculation
42  *    - Estimated holdtime announcement
43  *    - Position announcement
44  *    - Abandoned/completed call counters
45  *    - Failout timer passed as optional app parameter
46  *    - Optional monitoring of calls, started when call is answered
47  *
48  * Patch Version 1.07 2003-12-24 01
49  *
50  * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51  * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
52  *
53  * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54  * by Matthew Enger <m.enger@xi.com.au>
55  *
56  * \ingroup applications
57  */
58
59 #include <stdlib.h>
60 #include <errno.h>
61 #include <unistd.h>
62 #include <string.h>
63 #include <stdlib.h>
64 #include <stdio.h>
65 #include <sys/time.h>
66 #include <sys/signal.h>
67 #include <netinet/in.h>
68
69 #include "asterisk.h"
70
71 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
72
73 #include "asterisk/lock.h"
74 #include "asterisk/file.h"
75 #include "asterisk/logger.h"
76 #include "asterisk/channel.h"
77 #include "asterisk/pbx.h"
78 #include "asterisk/options.h"
79 #include "asterisk/app.h"
80 #include "asterisk/linkedlists.h"
81 #include "asterisk/module.h"
82 #include "asterisk/translate.h"
83 #include "asterisk/say.h"
84 #include "asterisk/features.h"
85 #include "asterisk/musiconhold.h"
86 #include "asterisk/cli.h"
87 #include "asterisk/manager.h"
88 #include "asterisk/config.h"
89 #include "asterisk/monitor.h"
90 #include "asterisk/utils.h"
91 #include "asterisk/causes.h"
92 #include "asterisk/astdb.h"
93 #include "asterisk/devicestate.h"
94
95 #define QUEUE_STRATEGY_RINGALL          0
96 #define QUEUE_STRATEGY_ROUNDROBIN       1
97 #define QUEUE_STRATEGY_LEASTRECENT      2
98 #define QUEUE_STRATEGY_FEWESTCALLS      3
99 #define QUEUE_STRATEGY_RANDOM           4
100 #define QUEUE_STRATEGY_RRMEMORY         5
101
102 static struct strategy {
103         int strategy;
104         char *name;
105 } strategies[] = {
106         { QUEUE_STRATEGY_RINGALL, "ringall" },
107         { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
108         { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
109         { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
110         { QUEUE_STRATEGY_RANDOM, "random" },
111         { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
112 };
113
114 #define DEFAULT_RETRY           5
115 #define DEFAULT_TIMEOUT         15
116 #define RECHECK                 1               /* Recheck every second to see we we're at the top yet */
117
118 #define RES_OKAY        0               /* Action completed */
119 #define RES_EXISTS      (-1)            /* Entry already exists */
120 #define RES_OUTOFMEMORY (-2)            /* Out of memory */
121 #define RES_NOSUCHQUEUE (-3)            /* No such queue */
122
123 static char *tdesc = "True Call Queueing";
124
125 static char *app = "Queue";
126
127 static char *synopsis = "Queue a call for a call queue";
128
129 static char *descrip =
130 "  Queue(queuename[|options[|URL][|announceoverride][|timeout]]):\n"
131 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
132 "This application will return to the dialplan if the queue does not exist, or\n"
133 "any of the join options cause the caller to not enter the queue.\n"
134 "The option string may contain zero or more of the following characters:\n"
135 "      'd' -- data-quality (modem) call (minimum delay).\n"
136 "      'h' -- allow callee to hang up by hitting *.\n"
137 "      'H' -- allow caller to hang up by hitting *.\n"
138 "      'n' -- no retries on the timeout; will exit this application and \n"
139 "             go to the next step.\n"
140 "      'r' -- ring instead of playing MOH\n"
141 "      't' -- allow the called user transfer the calling user\n"
142 "      'T' -- to allow the calling user to transfer the call.\n"
143 "      'w' -- allow the called user to write the conversation to disk via Monitor\n"
144 "      'W' -- allow the calling user to write the conversation to disk via Monitor\n"
145 "  In addition to transferring the call, a call may be parked and then picked\n"
146 "up by another user.\n"
147 "  The optional URL will be sent to the called party if the channel supports\n"
148 "it.\n"
149 "  The timeout will cause the queue to fail out after a specified number of\n"
150 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
151 "  This application sets the following channel variable upon completion:\n"
152 "      QUEUESTATUS    The status of the call as a text string, one of\n"
153 "             TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
154
155 static char *app_aqm = "AddQueueMember" ;
156 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
157 static char *app_aqm_descrip =
158 "   AddQueueMember(queuename[|interface[|penalty[|options]]]):\n"
159 "Dynamically adds interface to an existing queue.\n"
160 "If the interface is already in the queue and there exists an n+101 priority\n"
161 "then it will then jump to this priority.  Otherwise it will return an error\n"
162 "The option string may contain zero or more of the following characters:\n"
163 "       'j' -- jump to +101 priority when appropriate.\n"
164 "  This application sets the following channel variable upon completion:\n"
165 "     AQMSTATUS    The status of the attempt to add a queue member as a \n"
166 "                     text string, one of\n"
167 "           ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
168 "Example: AddQueueMember(techsupport|SIP/3000)\n"
169 "";
170
171 static char *app_rqm = "RemoveQueueMember" ;
172 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
173 static char *app_rqm_descrip =
174 "   RemoveQueueMember(queuename[|interface[|options]]):\n"
175 "Dynamically removes interface to an existing queue\n"
176 "If the interface is NOT in the queue and there exists an n+101 priority\n"
177 "then it will then jump to this priority.  Otherwise it will return an error\n"
178 "The option string may contain zero or more of the following characters:\n"
179 "       'j' -- jump to +101 priority when appropriate.\n"
180 "  This application sets the following channel variable upon completion:\n"
181 "     RQMSTATUS      The status of the attempt to remove a queue member as a\n"
182 "                     text string, one of\n"
183 "           REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
184 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
185 "";
186
187 static char *app_pqm = "PauseQueueMember" ;
188 static char *app_pqm_synopsis = "Pauses a queue member" ;
189 static char *app_pqm_descrip =
190 "   PauseQueueMember([queuename]|interface[|options]):\n"
191 "Pauses (blocks calls for) a queue member.\n"
192 "The given interface will be paused in the given queue.  This prevents\n"
193 "any calls from being sent from the queue to the interface until it is\n"
194 "unpaused with UnpauseQueueMember or the manager interface.  If no\n"
195 "queuename is given, the interface is paused in every queue it is a\n"
196 "member of.  If the interface is not in the named queue, or if no queue\n"
197 "is given and the interface is not in any queue, it will jump to\n"
198 "priority n+101, if it exists and the appropriate options are set.\n"
199 "The application will fail if the interface is not found and no extension\n"
200 "to jump to exists.\n"
201 "The option string may contain zero or more of the following characters:\n"
202 "       'j' -- jump to +101 priority when appropriate.\n"
203 "  This application sets the following channel variable upon completion:\n"
204 "     PQMSTATUS      The status of the attempt to pause a queue member as a\n"
205 "                     text string, one of\n"
206 "           PAUSED | NOTFOUND\n"
207 "Example: PauseQueueMember(|SIP/3000)\n";
208
209 static char *app_upqm = "UnpauseQueueMember" ;
210 static char *app_upqm_synopsis = "Unpauses a queue member" ;
211 static char *app_upqm_descrip =
212 "   UnpauseQueueMember([queuename]|interface[|options]):\n"
213 "Unpauses (resumes calls to) a queue member.\n"
214 "This is the counterpart to PauseQueueMember and operates exactly the\n"
215 "same way, except it unpauses instead of pausing the given interface.\n"
216 "The option string may contain zero or more of the following characters:\n"
217 "       'j' -- jump to +101 priority when appropriate.\n"
218 "  This application sets the following channel variable upon completion:\n"
219 "     UPQMSTATUS       The status of the attempt to unpause a queue \n"
220 "                      member as a text string, one of\n"
221 "            UNPAUSED | NOTFOUND\n"
222 "Example: UnpauseQueueMember(|SIP/3000)\n";
223
224 /*! \brief Persistent Members astdb family */
225 static const char *pm_family = "/Queue/PersistentMembers";
226 /* The maximum lengh of each persistent member queue database entry */
227 #define PM_MAX_LEN 2048
228
229 /*! \brief queues.conf [general] option */
230 static int queue_persistent_members = 0;
231
232 /*! \brief queues.conf per-queue weight option */
233 static int use_weight = 0;
234
235 enum queue_result {
236         QUEUE_UNKNOWN = 0,
237         QUEUE_TIMEOUT = 1,
238         QUEUE_JOINEMPTY = 2,
239         QUEUE_LEAVEEMPTY = 3,
240         QUEUE_JOINUNAVAIL = 4,
241         QUEUE_LEAVEUNAVAIL = 5,
242         QUEUE_FULL = 6,
243 };
244
245 const struct { 
246         enum queue_result id;
247         char *text;
248 } queue_results[] = {
249         { QUEUE_UNKNOWN, "UNKNOWN" },
250         { QUEUE_TIMEOUT, "TIMEOUT" },
251         { QUEUE_JOINEMPTY,"JOINEMPTY" },
252         { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
253         { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
254         { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
255         { QUEUE_FULL, "FULL" },
256 };
257
258 /*! \brief We define a custom "local user" structure because we
259    use it not only for keeping track of what is in use but
260    also for keeping track of who we're dialing. */
261
262 struct localuser {
263         struct ast_channel *chan;
264         char interface[256];
265         int stillgoing;
266         int metric;
267         int oldstatus;
268         time_t lastcall;
269         struct member *member;
270         struct localuser *next;
271 };
272
273 LOCAL_USER_DECL;
274
275
276 struct queue_ent {
277         struct ast_call_queue *parent;  /*!< What queue is our parent */
278         char moh[80];                   /*!< Name of musiconhold to be used */
279         char announce[80];              /*!< Announcement to play for member when call is answered */
280         char context[AST_MAX_CONTEXT];  /*!< Context when user exits queue */
281         char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
282         int pos;                        /*!< Where we are in the queue */
283         int prio;                       /*!< Our priority */
284         int last_pos_said;              /*!< Last position we told the user */
285         time_t last_periodic_announce_time;     /*!< The last time we played a periodic anouncement */
286         time_t last_pos;                /*!< Last time we told the user their position */
287         int opos;                       /*!< Where we started in the queue */
288         int handled;                    /*!< Whether our call was handled */
289         int max_penalty;                /*!< Limit the members that can take this call to this penalty or lower */
290         time_t start;                   /*!< When we started holding */
291         time_t expire;                  /*!< When this entry should expire (time out of queue) */
292         struct ast_channel *chan;       /*!< Our channel */
293         struct queue_ent *next;         /*!< The next queue entry */
294 };
295
296 struct member {
297         char interface[80];             /*!< Technology/Location */
298         int penalty;                    /*!< Are we a last resort? */
299         int calls;                      /*!< Number of calls serviced by this member */
300         int dynamic;                    /*!< Are we dynamically added? */
301         int status;                     /*!< Status of queue member */
302         int paused;                     /*!< Are we paused (not accepting calls)? */
303         time_t lastcall;                /*!< When last successful call was hungup */
304         int dead;                       /*!< Used to detect members deleted in realtime */
305         struct member *next;            /*!< Next member */
306 };
307
308 /* values used in multi-bit flags in ast_call_queue */
309 #define QUEUE_EMPTY_NORMAL 1
310 #define QUEUE_EMPTY_STRICT 2
311 #define ANNOUNCEHOLDTIME_ALWAYS 1
312 #define ANNOUNCEHOLDTIME_ONCE 2
313
314 struct ast_call_queue {
315         ast_mutex_t lock;       
316         char name[80];                  /*!< Name */
317         char moh[80];                   /*!< Music On Hold class to be used */
318         char announce[80];              /*!< Announcement to play when call is answered */
319         char context[AST_MAX_CONTEXT];  /*!< Exit context */
320         unsigned int monjoin:1;
321         unsigned int dead:1;
322         unsigned int joinempty:2;
323         unsigned int eventwhencalled:1;
324         unsigned int leavewhenempty:2;
325         unsigned int reportholdtime:1;
326         unsigned int wrapped:1;
327         unsigned int timeoutrestart:1;
328         unsigned int announceholdtime:2;
329         unsigned int strategy:3;
330         unsigned int maskmemberstatus:1;
331         unsigned int realtime:1;
332         int announcefrequency;          /*!< How often to announce their position */
333         int periodicannouncefrequency;  /*!< How often to play periodic announcement */
334         int roundingseconds;            /*!< How many seconds do we round to? */
335         int holdtime;                   /*!< Current avg holdtime, based on recursive boxcar filter */
336         int callscompleted;             /*!< Number of queue calls completed */
337         int callsabandoned;             /*!< Number of queue calls abandoned */
338         int servicelevel;               /*!< seconds setting for servicelevel*/
339         int callscompletedinsl;         /*!< Number of calls answered with servicelevel*/
340         char monfmt[8];                 /*!< Format to use when recording calls */
341         char sound_next[80];            /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
342         char sound_thereare[80];        /*!< Sound file: "There are currently" (def. queue-thereare) */
343         char sound_calls[80];           /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
344         char sound_holdtime[80];        /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
345         char sound_minutes[80];         /*!< Sound file: "minutes." (def. queue-minutes) */
346         char sound_lessthan[80];        /*!< Sound file: "less-than" (def. queue-lessthan) */
347         char sound_seconds[80];         /*!< Sound file: "seconds." (def. queue-seconds) */
348         char sound_thanks[80];          /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
349         char sound_reporthold[80];      /*!< Sound file: "Hold time" (def. queue-reporthold) */
350         char sound_periodicannounce[80];/*!< Sound file: Custom announce, no default */
351
352         int count;                      /*!< How many entries */
353         int maxlen;                     /*!< Max number of entries */
354         int wrapuptime;                 /*!< Wrapup Time */
355
356         int retry;                      /*!< Retry calling everyone after this amount of time */
357         int timeout;                    /*!< How long to wait for an answer */
358         int weight;                     /*!< Respective weight */
359         int autopause;                  /*!< Auto pause queue members if they fail to answer */
360
361         /* Queue strategy things */
362         int rrpos;                      /*!< Round Robin - position */
363         int memberdelay;                /*!< Seconds to delay connecting member to caller */
364         int autofill;                   /*!< Ignore the head call status and ring an available agent */
365         
366         struct member *members;         /*!< Head of the list of members */
367         struct queue_ent *head;         /*!< Head of the list of callers */
368         struct ast_call_queue *next;    /*!< Next call queue */
369 };
370
371 static struct ast_call_queue *queues = NULL;
372 AST_MUTEX_DEFINE_STATIC(qlock);
373
374 static int set_member_paused(char *queuename, char *interface, int paused);
375
376 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
377 {
378         int i;
379
380         for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
381                 if (queue_results[i].id == res) {
382                         pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
383                         return;
384                 }
385         }
386 }
387
388 static char *int2strat(int strategy)
389 {
390         int x;
391         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
392                 if (strategy == strategies[x].strategy)
393                         return strategies[x].name;
394         }
395         return "<unknown>";
396 }
397
398 static int strat2int(const char *strategy)
399 {
400         int x;
401         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
402                 if (!strcasecmp(strategy, strategies[x].name))
403                         return strategies[x].strategy;
404         }
405         return -1;
406 }
407
408 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
409 static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
410 {
411         struct queue_ent *cur;
412
413         if (!q || !new)
414                 return;
415         if (prev) {
416                 cur = prev->next;
417                 prev->next = new;
418         } else {
419                 cur = q->head;
420                 q->head = new;
421         }
422         new->next = cur;
423         new->parent = q;
424         new->pos = ++(*pos);
425         new->opos = *pos;
426 }
427
428 enum queue_member_status {
429         QUEUE_NO_MEMBERS,
430         QUEUE_NO_REACHABLE_MEMBERS,
431         QUEUE_NORMAL
432 };
433
434 static enum queue_member_status get_member_status(const struct ast_call_queue *q, int max_penalty)
435 {
436         struct member *member;
437         enum queue_member_status result = QUEUE_NO_MEMBERS;
438
439         for (member = q->members; member; member = member->next) {
440                 if (max_penalty && (member->penalty > max_penalty))
441                         continue;
442
443                 switch (member->status) {
444                 case AST_DEVICE_INVALID:
445                         /* nothing to do */
446                         break;
447                 case AST_DEVICE_UNAVAILABLE:
448                         result = QUEUE_NO_REACHABLE_MEMBERS;
449                         break;
450                 default:
451                         return QUEUE_NORMAL;
452                 }
453         }
454         
455         return result;
456 }
457
458 struct statechange {
459         int state;
460         char dev[0];
461 };
462
463 static void *changethread(void *data)
464 {
465         struct ast_call_queue *q;
466         struct statechange *sc = data;
467         struct member *cur;
468         char *loc;
469         char *technology;
470
471         technology = ast_strdupa(sc->dev);
472         loc = strchr(technology, '/');
473         if (loc) {
474                 *loc = '\0';
475                 loc++;
476         } else {
477                 free(sc);
478                 return NULL;
479         }
480         if (option_debug)
481                 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
482         ast_mutex_lock(&qlock);
483         for (q = queues; q; q = q->next) {
484                 ast_mutex_lock(&q->lock);
485                 cur = q->members;
486                 while(cur) {
487                         if (!strcasecmp(sc->dev, cur->interface)) {
488                                 if (cur->status != sc->state) {
489                                         cur->status = sc->state;
490                                         if (!q->maskmemberstatus) {
491                                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
492                                                         "Queue: %s\r\n"
493                                                         "Location: %s\r\n"
494                                                         "Membership: %s\r\n"
495                                                         "Penalty: %d\r\n"
496                                                         "CallsTaken: %d\r\n"
497                                                         "LastCall: %d\r\n"
498                                                         "Status: %d\r\n"
499                                                         "Paused: %d\r\n",
500                                                 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
501                                                 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
502                                         }
503                                 }
504                         }
505                         cur = cur->next;
506                 }
507                 ast_mutex_unlock(&q->lock);
508         }
509         ast_mutex_unlock(&qlock);
510         free(sc);
511         return NULL;
512 }
513
514 static int statechange_queue(const char *dev, int state, void *ign)
515 {
516         /* Avoid potential for deadlocks by spawning a new thread to handle
517            the event */
518         struct statechange *sc;
519         pthread_t t;
520         pthread_attr_t attr;
521         
522         if ((sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) {
523                 sc->state = state;
524                 strcpy(sc->dev, dev);
525                 pthread_attr_init(&attr);
526                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
527                 if (ast_pthread_create(&t, &attr, changethread, sc)) {
528                         ast_log(LOG_WARNING, "Failed to create update thread!\n");
529                         free(sc);
530                 }
531         }
532         return 0;
533 }
534
535 static struct member *create_queue_member(char *interface, int penalty, int paused)
536 {
537         struct member *cur;
538         
539         /* Add a new member */
540
541         if ((cur = ast_calloc(1, sizeof(*cur)))) {
542                 cur->penalty = penalty;
543                 cur->paused = paused;
544                 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
545                 if (!strchr(cur->interface, '/'))
546                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
547                 cur->status = ast_device_state(interface);
548         }
549
550         return cur;
551 }
552
553 static struct ast_call_queue *alloc_queue(const char *queuename)
554 {
555         struct ast_call_queue *q;
556
557         if ((q = ast_calloc(1, sizeof(*q)))) {
558                 ast_mutex_init(&q->lock);
559                 ast_copy_string(q->name, queuename, sizeof(q->name));
560         }
561         return q;
562 }
563
564 static void init_queue(struct ast_call_queue *q)
565 {
566         q->dead = 0;
567         q->retry = DEFAULT_RETRY;
568         q->timeout = -1;
569         q->maxlen = 0;
570         q->announcefrequency = 0;
571         q->announceholdtime = 0;
572         q->roundingseconds = 0; /* Default - don't announce seconds */
573         q->servicelevel = 0;
574         q->moh[0] = '\0';
575         q->announce[0] = '\0';
576         q->context[0] = '\0';
577         q->monfmt[0] = '\0';
578         q->periodicannouncefrequency = 0;
579         ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
580         ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
581         ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
582         ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
583         ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
584         ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
585         ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
586         ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
587         ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
588         ast_copy_string(q->sound_periodicannounce, "queue-periodic-announce", sizeof(q->sound_periodicannounce));
589 }
590
591 static void clear_queue(struct ast_call_queue *q)
592 {
593         q->holdtime = 0;
594         q->callscompleted = 0;
595         q->callsabandoned = 0;
596         q->callscompletedinsl = 0;
597         q->wrapuptime = 0;
598 }
599
600 /*! \brief Configure a queue parameter.
601 \par
602    For error reporting, line number is passed for .conf static configuration.
603    For Realtime queues, linenum is -1.
604    The failunknown flag is set for config files (and static realtime) to show
605    errors for unknown parameters. It is cleared for dynamic realtime to allow
606    extra fields in the tables. */
607 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
608 {
609         if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
610                 ast_copy_string(q->moh, val, sizeof(q->moh));
611         } else if (!strcasecmp(param, "announce")) {
612                 ast_copy_string(q->announce, val, sizeof(q->announce));
613         } else if (!strcasecmp(param, "context")) {
614                 ast_copy_string(q->context, val, sizeof(q->context));
615         } else if (!strcasecmp(param, "timeout")) {
616                 q->timeout = atoi(val);
617                 if (q->timeout < 0)
618                         q->timeout = DEFAULT_TIMEOUT;
619         } else if (!strcasecmp(param, "monitor-join")) {
620                 q->monjoin = ast_true(val);
621         } else if (!strcasecmp(param, "monitor-format")) {
622                 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
623         } else if (!strcasecmp(param, "queue-youarenext")) {
624                 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
625         } else if (!strcasecmp(param, "queue-thereare")) {
626                 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
627         } else if (!strcasecmp(param, "queue-callswaiting")) {
628                 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
629         } else if (!strcasecmp(param, "queue-holdtime")) {
630                 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
631         } else if (!strcasecmp(param, "queue-minutes")) {
632                 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
633         } else if (!strcasecmp(param, "queue-seconds")) {
634                 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
635         } else if (!strcasecmp(param, "queue-lessthan")) {
636                 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
637         } else if (!strcasecmp(param, "queue-thankyou")) {
638                 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
639         } else if (!strcasecmp(param, "queue-reporthold")) {
640                 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
641         } else if (!strcasecmp(param, "announce-frequency")) {
642                 q->announcefrequency = atoi(val);
643         } else if (!strcasecmp(param, "announce-round-seconds")) {
644                 q->roundingseconds = atoi(val);
645                 if (q->roundingseconds>60 || q->roundingseconds<0) {
646                         if (linenum >= 0) {
647                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
648                                         "using 0 instead for queue '%s' at line %d of queues.conf\n",
649                                         val, param, q->name, linenum);
650                         } else {
651                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
652                                         "using 0 instead for queue '%s'\n", val, param, q->name);
653                         }
654                         q->roundingseconds=0;
655                 }
656         } else if (!strcasecmp(param, "announce-holdtime")) {
657                 if (!strcasecmp(val, "once"))
658                         q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
659                 else if (ast_true(val))
660                         q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
661                 else
662                         q->announceholdtime = 0;
663          } else if (!strcasecmp(param, "periodic-announce")) {
664                 ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce));
665         } else if (!strcasecmp(param, "periodic-announce-frequency")) {
666                 q->periodicannouncefrequency = atoi(val);
667         } else if (!strcasecmp(param, "retry")) {
668                 q->retry = atoi(val);
669                 if (q->retry < 0)
670                         q->retry = DEFAULT_RETRY;
671         } else if (!strcasecmp(param, "wrapuptime")) {
672                 q->wrapuptime = atoi(val);
673         } else if (!strcasecmp(param, "autofill")) {
674                 q->autofill = ast_true(val);
675         } else if (!strcasecmp(param, "autopause")) {
676                 q->autopause = ast_true(val);
677         } else if (!strcasecmp(param, "maxlen")) {
678                 q->maxlen = atoi(val);
679                 if (q->maxlen < 0)
680                         q->maxlen = 0;
681         } else if (!strcasecmp(param, "servicelevel")) {
682                 q->servicelevel= atoi(val);
683         } else if (!strcasecmp(param, "strategy")) {
684                 q->strategy = strat2int(val);
685                 if (q->strategy < 0) {
686                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
687                                 val, q->name);
688                         q->strategy = 0;
689                 }
690         } else if (!strcasecmp(param, "joinempty")) {
691                 if (!strcasecmp(val, "strict"))
692                         q->joinempty = QUEUE_EMPTY_STRICT;
693                 else if (ast_true(val))
694                         q->joinempty = QUEUE_EMPTY_NORMAL;
695                 else
696                         q->joinempty = 0;
697         } else if (!strcasecmp(param, "leavewhenempty")) {
698                 if (!strcasecmp(val, "strict"))
699                         q->leavewhenempty = QUEUE_EMPTY_STRICT;
700                 else if (ast_true(val))
701                         q->leavewhenempty = QUEUE_EMPTY_NORMAL;
702                 else
703                         q->leavewhenempty = 0;
704         } else if (!strcasecmp(param, "eventmemberstatus")) {
705                 q->maskmemberstatus = !ast_true(val);
706         } else if (!strcasecmp(param, "eventwhencalled")) {
707                 q->eventwhencalled = ast_true(val);
708         } else if (!strcasecmp(param, "reportholdtime")) {
709                 q->reportholdtime = ast_true(val);
710         } else if (!strcasecmp(param, "memberdelay")) {
711                 q->memberdelay = atoi(val);
712         } else if (!strcasecmp(param, "weight")) {
713                 q->weight = atoi(val);
714                 if (q->weight)
715                         use_weight++;
716                 /* With Realtime queues, if the last queue using weights is deleted in realtime,
717                    we will not see any effect on use_weight until next reload. */
718         } else if (!strcasecmp(param, "timeoutrestart")) {
719                 q->timeoutrestart = ast_true(val);
720         } else if(failunknown) {
721                 if (linenum >= 0) {
722                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
723                                 q->name, param, linenum);
724                 } else {
725                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
726                 }
727         }
728 }
729
730 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
731 {
732         struct member *m, *prev_m;
733         int penalty = 0;
734
735         if(penalty_str) {
736                 penalty = atoi(penalty_str);
737                 if(penalty < 0)
738                         penalty = 0;
739         }
740
741         /* Find the member, or the place to put a new one. */
742         prev_m = NULL;
743         m = q->members;
744         while (m && strcmp(m->interface, interface)) {
745                 prev_m = m;
746                 m = m->next;
747         }
748
749         /* Create a new one if not found, else update penalty */
750         if (!m) {
751                 m = create_queue_member(interface, penalty, 0);
752                 if (m) {
753                         m->dead = 0;
754                         if (prev_m) {
755                                 prev_m->next = m;
756                         } else {
757                                 q->members = m;
758                         }
759                 }
760         } else {
761                 m->dead = 0;    /* Do not delete this one. */
762                 m->penalty = penalty;
763         }
764 }
765
766
767 /*!\brief Reload a single queue via realtime.
768    \return Return the queue, or NULL if it doesn't exist.
769    \note Should be called with the global qlock locked.
770    When found, the queue is returned with q->lock locked. */
771 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
772 {
773         struct ast_variable *v;
774         struct ast_call_queue *q, *prev_q;
775         struct member *m, *prev_m, *next_m;
776         char *interface;
777         char *tmp, *tmp_name;
778         char tmpbuf[64];        /* Must be longer than the longest queue param name. */
779
780         /* Find the queue in the in-core list (we will create a new one if not found). */
781         q = queues;
782         prev_q = NULL;
783         while (q) {
784                 if (!strcasecmp(q->name, queuename)) {
785                         break;
786                 }
787                 q = q->next;
788                 prev_q = q;
789         }
790
791         /* Static queues override realtime. */
792         if (q) {
793                 ast_mutex_lock(&q->lock);
794                 if (!q->realtime) {
795                         if (q->dead) {
796                                 ast_mutex_unlock(&q->lock);
797                                 return NULL;
798                         } else {
799                                 return q;
800                         }
801                 }
802         } else if (!member_config)
803                 /* Not found in the list, and it's not realtime ... */
804                 return NULL;
805
806         /* Check if queue is defined in realtime. */
807         if (!queue_vars) {
808                 /* Delete queue from in-core list if it has been deleted in realtime. */
809                 if (q) {
810                         /*! \note Hmm, can't seem to distinguish a DB failure from a not
811                            found condition... So we might delete an in-core queue
812                            in case of DB failure. */
813                         ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
814
815                         q->dead = 1;
816                         /* Delete if unused (else will be deleted when last caller leaves). */
817                         if (!q->count) {
818                                 /* Delete. */
819                                 if (!prev_q) {
820                                         queues = q->next;
821                                 } else {
822                                         prev_q->next = q->next;
823                                 }
824                                 ast_mutex_unlock(&q->lock);
825                                 free(q);
826                         } else
827                                 ast_mutex_unlock(&q->lock);
828                 }
829                 return NULL;
830         }
831
832         /* Create a new queue if an in-core entry does not exist yet. */
833         if (!q) {
834                 if (!(q = alloc_queue(queuename)))
835                         return NULL;
836                 ast_mutex_lock(&q->lock);
837                 clear_queue(q);
838                 q->realtime = 1;
839                 q->next = queues;
840                 queues = q;
841         }
842         init_queue(q);          /* Ensure defaults for all parameters not set explicitly. */
843
844         v = queue_vars;
845         memset(tmpbuf, 0, sizeof(tmpbuf));
846         while(v) {
847                 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
848                 if((tmp = strchr(v->name, '_')) != NULL) {
849                         ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
850                         tmp_name = tmpbuf;
851                         tmp = tmp_name;
852                         while((tmp = strchr(tmp, '_')) != NULL)
853                                 *tmp++ = '-';
854                 } else
855                         tmp_name = v->name;
856                 queue_set_param(q, tmp_name, v->value, -1, 0);
857                 v = v->next;
858         }
859
860         /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
861         m = q->members;
862         while (m) {
863                 if (!m->dynamic)
864                         m->dead = 1;
865                 m = m->next;
866         }
867
868         interface = ast_category_browse(member_config, NULL);
869         while (interface) {
870                 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
871                 interface = ast_category_browse(member_config, interface);
872         }
873
874         /* Delete all realtime members that have been deleted in DB. */
875         m = q->members;
876         prev_m = NULL;
877         while (m) {
878                 next_m = m->next;
879                 if (m->dead) {
880                         if (prev_m) {
881                                 prev_m->next = next_m;
882                         } else {
883                                 q->members = next_m;
884                         }
885                         free(m);
886                 } else {
887                         prev_m = m;
888                 }
889                 m = next_m;
890         }
891
892         return q;
893 }
894
895 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
896 {
897         struct ast_variable *queue_vars = NULL;
898         struct ast_config *member_config = NULL;
899         struct ast_call_queue *q;
900         struct queue_ent *cur, *prev = NULL;
901         int res = -1;
902         int pos = 0;
903         int inserted = 0;
904         enum queue_member_status stat;
905
906         /*! \note Load from realtime before taking the global qlock, to avoid blocking all
907            queue operations while waiting for the DB.
908
909            This will be two separate database transactions, so we might
910            see queue parameters as they were before another process
911            changed the queue and member list as it was after the change.
912            Thus we might see an empty member list when a queue is
913            deleted. In practise, this is unlikely to cause a problem. */
914         queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
915         if (queue_vars) {
916                 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
917                 if (!member_config) {
918                         ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
919                         return res;
920                 }
921         }
922
923         ast_mutex_lock(&qlock);
924         q = find_queue_by_name_rt(queuename, queue_vars, member_config);
925         /* Note: If found, find_queue_by_name_rt() returns with q->lock locked. */
926         if(member_config)
927                 ast_config_destroy(member_config);
928         if(queue_vars)
929                 ast_variables_destroy(queue_vars);
930
931         if (!q) {
932                 ast_mutex_unlock(&qlock);
933                 return res;
934         }
935
936         /* This is our one */
937         stat = get_member_status(q, qe->max_penalty);
938         if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
939                 *reason = QUEUE_JOINEMPTY;
940         else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
941                 *reason = QUEUE_JOINUNAVAIL;
942         else if (q->maxlen && (q->count >= q->maxlen))
943                 *reason = QUEUE_FULL;
944         else {
945                 /* There's space for us, put us at the right position inside
946                  * the queue. 
947                  * Take into account the priority of the calling user */
948                 inserted = 0;
949                 prev = NULL;
950                 cur = q->head;
951                 while(cur) {
952                         /* We have higher priority than the current user, enter
953                          * before him, after all the other users with priority
954                          * higher or equal to our priority. */
955                         if ((!inserted) && (qe->prio > cur->prio)) {
956                                 insert_entry(q, prev, qe, &pos);
957                                 inserted = 1;
958                         }
959                         cur->pos = ++pos;
960                         prev = cur;
961                         cur = cur->next;
962                 }
963                 /* No luck, join at the end of the queue */
964                 if (!inserted)
965                         insert_entry(q, prev, qe, &pos);
966                 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
967                 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
968                 ast_copy_string(qe->context, q->context, sizeof(qe->context));
969                 q->count++;
970                 res = 0;
971                 manager_event(EVENT_FLAG_CALL, "Join", 
972                               "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
973                               qe->chan->name, 
974                               qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
975                               qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
976                               q->name, qe->pos, q->count );
977 #if 0
978 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
979 #endif
980         }
981         ast_mutex_unlock(&q->lock);
982         ast_mutex_unlock(&qlock);
983         return res;
984 }
985
986 static void free_members(struct ast_call_queue *q, int all)
987 {
988         /* Free non-dynamic members */
989         struct member *curm, *next, *prev;
990
991         curm = q->members;
992         prev = NULL;
993         while(curm) {
994                 next = curm->next;
995                 if (all || !curm->dynamic) {
996                         if (prev)
997                                 prev->next = next;
998                         else
999                                 q->members = next;
1000                         free(curm);
1001                 } else 
1002                         prev = curm;
1003                 curm = next;
1004         }
1005 }
1006
1007 static void destroy_queue(struct ast_call_queue *q)
1008 {
1009         struct ast_call_queue *cur, *prev = NULL;
1010
1011         ast_mutex_lock(&qlock);
1012         for (cur = queues; cur; cur = cur->next) {
1013                 if (cur == q) {
1014                         if (prev)
1015                                 prev->next = cur->next;
1016                         else
1017                                 queues = cur->next;
1018                 } else {
1019                         prev = cur;
1020                 }
1021         }
1022         ast_mutex_unlock(&qlock);
1023         free_members(q, 1);
1024         ast_mutex_destroy(&q->lock);
1025         free(q);
1026 }
1027
1028 static int play_file(struct ast_channel *chan, char *filename)
1029 {
1030         int res;
1031
1032         ast_stopstream(chan);
1033         res = ast_streamfile(chan, filename, chan->language);
1034
1035         if (!res)
1036                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1037         else
1038                 res = 0;
1039
1040         ast_stopstream(chan);
1041
1042         return res;
1043 }
1044
1045 static int valid_exit(struct queue_ent *qe, char digit)
1046 {
1047         int digitlen = strlen(qe->digits);
1048
1049         /* Prevent possible buffer overflow */
1050         if (digitlen < sizeof(qe->digits) - 2) {
1051                 qe->digits[digitlen] = digit;
1052                 qe->digits[digitlen + 1] = '\0';
1053         } else {
1054                 qe->digits[0] = '\0';
1055                 return 0;
1056         }
1057
1058         /* If there's no context to goto, short-circuit */
1059         if (ast_strlen_zero(qe->context))
1060                 return 0;
1061
1062         /* If the extension is bad, then reset the digits to blank */
1063         if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1064                 qe->digits[0] = '\0';
1065                 return 0;
1066         }
1067
1068         /* We have an exact match */
1069         if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1070                 /* Return 1 on a successful goto */
1071                 return 1;
1072         }
1073         return 0;
1074 }
1075
1076 static int say_position(struct queue_ent *qe)
1077 {
1078         int res = 0, avgholdmins, avgholdsecs;
1079         time_t now;
1080
1081         /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1082         time(&now);
1083         if ( (now - qe->last_pos) < 15 )
1084                 return 0;
1085
1086         /* If either our position has changed, or we are over the freq timer, say position */
1087         if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
1088                 return 0;
1089
1090         ast_moh_stop(qe->chan);
1091         /* Say we're next, if we are */
1092         if (qe->pos == 1) {
1093                 res = play_file(qe->chan, qe->parent->sound_next);
1094                 if (res && valid_exit(qe, res))
1095                         goto playout;
1096                 else
1097                         goto posout;
1098         } else {
1099                 res = play_file(qe->chan, qe->parent->sound_thereare);
1100                 if (res && valid_exit(qe, res))
1101                         goto playout;
1102                 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1103                 if (res && valid_exit(qe, res))
1104                         goto playout;
1105                 res = play_file(qe->chan, qe->parent->sound_calls);
1106                 if (res && valid_exit(qe, res))
1107                         goto playout;
1108         }
1109         /* Round hold time to nearest minute */
1110         avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
1111
1112         /* If they have specified a rounding then round the seconds as well */
1113         if(qe->parent->roundingseconds) {
1114                 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
1115                 avgholdsecs*= qe->parent->roundingseconds;
1116         } else {
1117                 avgholdsecs=0;
1118         }
1119
1120         if (option_verbose > 2)
1121                 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1122
1123         /* If the hold time is >1 min, if it's enabled, and if it's not
1124            supposed to be only once and we have already said it, say it */
1125         if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1126             (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1127                 res = play_file(qe->chan, qe->parent->sound_holdtime);
1128                 if (res && valid_exit(qe, res))
1129                         goto playout;
1130
1131                 if (avgholdmins>0) {
1132                         if (avgholdmins < 2) {
1133                                 res = play_file(qe->chan, qe->parent->sound_lessthan);
1134                                 if (res && valid_exit(qe, res))
1135                                         goto playout;
1136
1137                                 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1138                                 if (res && valid_exit(qe, res))
1139                                         goto playout;
1140                         } else {
1141                                 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1142                                 if (res && valid_exit(qe, res))
1143                                         goto playout;
1144                         }
1145                         
1146                         res = play_file(qe->chan, qe->parent->sound_minutes);
1147                         if (res && valid_exit(qe, res))
1148                                 goto playout;
1149                 }
1150                 if (avgholdsecs>0) {
1151                         res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1152                         if (res && valid_exit(qe, res))
1153                                 goto playout;
1154
1155                         res = play_file(qe->chan, qe->parent->sound_seconds);
1156                         if (res && valid_exit(qe, res))
1157                                 goto playout;
1158                 }
1159
1160         }
1161
1162  posout:
1163         if (option_verbose > 2)
1164                 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1165                             qe->chan->name, qe->parent->name, qe->pos);
1166         res = play_file(qe->chan, qe->parent->sound_thanks);
1167
1168  playout:
1169         /* Set our last_pos indicators */
1170         qe->last_pos = now;
1171         qe->last_pos_said = qe->pos;
1172         ast_moh_start(qe->chan, qe->moh);
1173
1174         return res;
1175 }
1176
1177 static void recalc_holdtime(struct queue_ent *qe)
1178 {
1179         int oldvalue, newvalue;
1180
1181         /* Calculate holdtime using a recursive boxcar filter */
1182         /* Thanks to SRT for this contribution */
1183         /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1184
1185         newvalue = time(NULL) - qe->start;
1186
1187         ast_mutex_lock(&qe->parent->lock);
1188         if (newvalue <= qe->parent->servicelevel)
1189                 qe->parent->callscompletedinsl++;
1190         oldvalue = qe->parent->holdtime;
1191         qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1192         ast_mutex_unlock(&qe->parent->lock);
1193 }
1194
1195
1196 static void leave_queue(struct queue_ent *qe)
1197 {
1198         struct ast_call_queue *q;
1199         struct queue_ent *cur, *prev = NULL;
1200         int pos = 0;
1201
1202         q = qe->parent;
1203         if (!q)
1204                 return;
1205         ast_mutex_lock(&q->lock);
1206
1207         prev = NULL;
1208         cur = q->head;
1209         while(cur) {
1210                 if (cur == qe) {
1211                         q->count--;
1212
1213                         /* Take us out of the queue */
1214                         manager_event(EVENT_FLAG_CALL, "Leave",
1215                                 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
1216                                 qe->chan->name, q->name,  q->count);
1217 #if 0
1218 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1219 #endif
1220                         /* Take us out of the queue */
1221                         if (prev)
1222                                 prev->next = cur->next;
1223                         else
1224                                 q->head = cur->next;
1225                 } else {
1226                         /* Renumber the people after us in the queue based on a new count */
1227                         cur->pos = ++pos;
1228                         prev = cur;
1229                 }
1230                 cur = cur->next;
1231         }
1232         ast_mutex_unlock(&q->lock);
1233         if (q->dead && !q->count) {     
1234                 /* It's dead and nobody is in it, so kill it */
1235                 destroy_queue(q);
1236         }
1237 }
1238
1239 /* Hang up a list of outgoing calls */
1240 static void hangupcalls(struct localuser *outgoing, struct ast_channel *exception)
1241 {
1242         struct localuser *oo;
1243
1244         while(outgoing) {
1245                 /* Hangup any existing lines we have open */
1246                 if (outgoing->chan && (outgoing->chan != exception))
1247                         ast_hangup(outgoing->chan);
1248                 oo = outgoing;
1249                 outgoing=outgoing->next;
1250                 free(oo);
1251         }
1252 }
1253
1254 static int update_status(struct ast_call_queue *q, struct member *member, int status)
1255 {
1256         struct member *cur;
1257
1258         /* Since a reload could have taken place, we have to traverse the list to
1259                 be sure it's still valid */
1260         ast_mutex_lock(&q->lock);
1261         cur = q->members;
1262         while(cur) {
1263                 if (member == cur) {
1264                         cur->status = status;
1265                         if (!q->maskmemberstatus) {
1266                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1267                                         "Queue: %s\r\n"
1268                                         "Location: %s\r\n"
1269                                         "Membership: %s\r\n"
1270                                         "Penalty: %d\r\n"
1271                                         "CallsTaken: %d\r\n"
1272                                         "LastCall: %d\r\n"
1273                                         "Status: %d\r\n"
1274                                         "Paused: %d\r\n",
1275                                 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1276                                 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1277                         }
1278                         break;
1279                 }
1280                 cur = cur->next;
1281         }
1282         ast_mutex_unlock(&q->lock);
1283         return 0;
1284 }
1285
1286 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
1287 {
1288         if (status == AST_CAUSE_BUSY)
1289                 status = AST_DEVICE_BUSY;
1290         else if (status == AST_CAUSE_UNREGISTERED)
1291                 status = AST_DEVICE_UNAVAILABLE;
1292         else if (status == AST_CAUSE_NOSUCHDRIVER)
1293                 status = AST_DEVICE_INVALID;
1294         else
1295                 status = AST_DEVICE_UNKNOWN;
1296         return update_status(q, member, status);
1297 }
1298
1299 /* traverse all defined queues which have calls waiting and contain this member
1300    return 0 if no other queue has precedence (higher weight) or 1 if found  */
1301 static int compare_weight(struct ast_call_queue *rq, struct member *member)
1302 {
1303         struct ast_call_queue *q;
1304         struct member *mem;
1305         int found = 0;
1306         
1307         /* &qlock and &rq->lock already set by try_calling()
1308          * to solve deadlock */
1309         for (q = queues; q; q = q->next) {
1310                 if (q == rq) /* don't check myself, could deadlock */
1311                         continue; 
1312                 ast_mutex_lock(&q->lock);
1313                 if (q->count && q->members) {
1314                         for (mem = q->members; mem; mem = mem->next) {
1315                                 if (!strcmp(mem->interface, member->interface)) {
1316                                         ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1317                                         if (q->weight > rq->weight) {
1318                                                 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, rq->name, rq->weight, rq->count);
1319                                                 found = 1;
1320                                                 break;
1321                                         }
1322                                 }
1323                         }
1324                 }
1325                 ast_mutex_unlock(&q->lock);
1326                 if (found) 
1327                         break;
1328         }
1329         return found;
1330 }
1331
1332 static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
1333 {
1334         int res;
1335         int status;
1336         char tech[256];
1337         char *location;
1338
1339         if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1340                 if (option_debug)
1341                         ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1342                 if (qe->chan->cdr)
1343                         ast_cdr_busy(qe->chan->cdr);
1344                 tmp->stillgoing = 0;
1345                 (*busies)++;
1346                 return 0;
1347         }
1348         
1349         if (tmp->member->paused) {
1350                 if (option_debug)
1351                         ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1352                 if (qe->chan->cdr)
1353                         ast_cdr_busy(qe->chan->cdr);
1354                 tmp->stillgoing = 0;
1355                 return 0;
1356         }
1357         if (use_weight && compare_weight(qe->parent,tmp->member)) {
1358                 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1359                 if (qe->chan->cdr)
1360                         ast_cdr_busy(qe->chan->cdr);
1361                 tmp->stillgoing = 0;
1362                 (*busies)++;
1363                 return 0;
1364         }
1365
1366         ast_copy_string(tech, tmp->interface, sizeof(tech));
1367         if ((location = strchr(tech, '/')))
1368                 *location++ = '\0';
1369         else
1370                 location = "";
1371
1372         /* Request the peer */
1373         tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1374         if (!tmp->chan) {                       /* If we can't, just go on to the next call */
1375 #if 0
1376                 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
1377 #endif                  
1378                 if (qe->chan->cdr)
1379                         ast_cdr_busy(qe->chan->cdr);
1380                 tmp->stillgoing = 0;
1381                 update_dial_status(qe->parent, tmp->member, status);
1382                 (*busies)++;
1383                 return 0;
1384         } else if (status != tmp->oldstatus) 
1385                 update_dial_status(qe->parent, tmp->member, status);
1386         
1387         tmp->chan->appl = "AppQueue";
1388         tmp->chan->data = "(Outgoing Line)";
1389         tmp->chan->whentohangup = 0;
1390         if (tmp->chan->cid.cid_num)
1391                 free(tmp->chan->cid.cid_num);
1392         tmp->chan->cid.cid_num = NULL;
1393         if (tmp->chan->cid.cid_name)
1394                 free(tmp->chan->cid.cid_name);
1395         tmp->chan->cid.cid_name = NULL;
1396         if (tmp->chan->cid.cid_ani)
1397                 free(tmp->chan->cid.cid_ani);
1398         tmp->chan->cid.cid_ani = NULL;
1399         if (qe->chan->cid.cid_num)
1400                 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
1401         if (qe->chan->cid.cid_name)
1402                 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
1403         if (qe->chan->cid.cid_ani)
1404                 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
1405
1406         /* Inherit specially named variables from parent channel */
1407         ast_channel_inherit_variables(qe->chan, tmp->chan);
1408
1409         /* Presense of ADSI CPE on outgoing channel follows ours */
1410         tmp->chan->adsicpe = qe->chan->adsicpe;
1411
1412         /* Place the call, but don't wait on the answer */
1413         res = ast_call(tmp->chan, location, 0);
1414         if (res) {
1415                 /* Again, keep going even if there's an error */
1416                 if (option_debug)
1417                         ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1418                 else if (option_verbose > 2)
1419                         ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1420                 ast_hangup(tmp->chan);
1421                 tmp->chan = NULL;
1422                 tmp->stillgoing = 0;
1423                 (*busies)++;
1424                 return 0;
1425         } else {
1426                 if (qe->parent->eventwhencalled) {
1427                         manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1428                                                 "AgentCalled: %s\r\n"
1429                                                 "ChannelCalling: %s\r\n"
1430                                                 "CallerID: %s\r\n"
1431                                                 "CallerIDName: %s\r\n"
1432                                                 "Context: %s\r\n"
1433                                                 "Extension: %s\r\n"
1434                                                 "Priority: %d\r\n",
1435                                                 tmp->interface, qe->chan->name,
1436                                                 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1437                                                 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1438                                                 qe->chan->context, qe->chan->exten, qe->chan->priority);
1439                 }
1440                 if (option_verbose > 2)
1441                         ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1442         }
1443         return 1;
1444 }
1445
1446 static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
1447 {
1448         struct localuser *cur;
1449         struct localuser *best;
1450         int bestmetric=0;
1451
1452         do {
1453                 best = NULL;
1454                 cur = outgoing;
1455                 while(cur) {
1456                         if (cur->stillgoing &&                                  /* Not already done */
1457                                 !cur->chan &&                                   /* Isn't already going */
1458                                 (!best || (cur->metric < bestmetric))) {        /* We haven't found one yet, or it's better */
1459                                         bestmetric = cur->metric;
1460                                         best = cur;
1461                         }
1462                         cur = cur->next;
1463                 }
1464                 if (best) {
1465                         if (!qe->parent->strategy) {
1466                                 /* Ring everyone who shares this best metric (for ringall) */
1467                                 cur = outgoing;
1468                                 while(cur) {
1469                                         if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
1470                                                 if (option_debug)
1471                                                         ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1472                                                 ring_entry(qe, cur, busies);
1473                                         }
1474                                         cur = cur->next;
1475                                 }
1476                         } else {
1477                                 /* Ring just the best channel */
1478                                 if (option_debug)
1479                                         ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1480                                 ring_entry(qe, best, busies);
1481                         }
1482                 }
1483         } while (best && !best->chan);
1484         if (!best) {
1485                 if (option_debug)
1486                         ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1487                 return 0;
1488         }
1489         return 1;
1490 }
1491
1492 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
1493 {
1494         struct localuser *cur;
1495         struct localuser *best;
1496         int bestmetric=0;
1497
1498         best = NULL;
1499         cur = outgoing;
1500         while(cur) {
1501                 if (cur->stillgoing &&                                  /* Not already done */
1502                         !cur->chan &&                                   /* Isn't already going */
1503                         (!best || (cur->metric < bestmetric))) {        /* We haven't found one yet, or it's better */
1504                                 bestmetric = cur->metric;
1505                                 best = cur;
1506                 }
1507                 cur = cur->next;
1508         }
1509         if (best) {
1510                 /* Ring just the best channel */
1511                 if (option_debug)
1512                         ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1513                 qe->parent->rrpos = best->metric % 1000;
1514         } else {
1515                 /* Just increment rrpos */
1516                 if (qe->parent->wrapped) {
1517                         /* No more channels, start over */
1518                         qe->parent->rrpos = 0;
1519                 } else {
1520                         /* Prioritize next entry */
1521                         qe->parent->rrpos++;
1522                 }
1523         }
1524         qe->parent->wrapped = 0;
1525         return 0;
1526 }
1527
1528 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1529 {
1530         int res;
1531
1532         ast_stopstream(chan);
1533         res = ast_streamfile(chan, filename, chan->language);
1534
1535         if (!res) {
1536                 /* Wait for a keypress */
1537                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1538                 if (res <= 0 || !valid_exit(qe, res))
1539                         res = 0;
1540
1541                 /* Stop playback */
1542                 ast_stopstream(chan);
1543         } else {
1544                 res = 0;
1545         }
1546         
1547         /*if (res) {
1548                 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
1549                 res = 0;
1550         }*/
1551
1552         return res;
1553 }
1554
1555 static int say_periodic_announcement(struct queue_ent *qe)
1556 {
1557         int res = 0;
1558         time_t now;
1559
1560         /* Get the current time */
1561         time(&now);
1562
1563         /* Check to see if it is time to announce */
1564         if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1565                 return 0;
1566
1567         /* Stop the music on hold so we can play our own file */
1568         ast_moh_stop(qe->chan);
1569
1570         if (option_verbose > 2)
1571                 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1572
1573         /* play the announcement */
1574         res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce);
1575
1576         /* Resume Music on Hold */
1577         ast_moh_start(qe->chan, qe->moh);
1578
1579         /* update last_periodic_announce_time */
1580         qe->last_periodic_announce_time = now;
1581
1582         return res;
1583 }
1584
1585 static void record_abandoned(struct queue_ent *qe)
1586 {
1587         ast_mutex_lock(&qe->parent->lock);
1588         qe->parent->callsabandoned++;
1589         ast_mutex_unlock(&qe->parent->lock);
1590 }
1591
1592
1593 #define AST_MAX_WATCHERS 256
1594
1595 #define BUILD_WATCHERS do { \
1596                 o = outgoing; \
1597                 found = -1; \
1598                 pos = 1; \
1599                 numlines = 0; \
1600                 watchers[0] = in; \
1601                 while(o) { \
1602                         /* Keep track of important channels */ \
1603                         if (o->stillgoing) { \
1604                                 stillgoing = 1; \
1605                                 if (o->chan) { \
1606                                         watchers[pos++] = o->chan; \
1607                                         found = 1; \
1608                                 } \
1609                         } \
1610                         o = o->next; \
1611                         numlines++; \
1612                 } \
1613         } while(0)
1614         
1615 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1616 {
1617         char *queue = qe->parent->name;
1618         char on[256] = "";
1619         struct localuser *o;
1620         int found;
1621         int numlines;
1622         int status;
1623         int sentringing = 0;
1624         int numbusies = prebusies;
1625         int numnochan = 0;
1626         int stillgoing = 0;
1627         int orig = *to;
1628         struct ast_frame *f;
1629         struct localuser *peer = NULL;
1630         struct ast_channel *watchers[AST_MAX_WATCHERS];
1631         int pos;
1632         struct ast_channel *winner;
1633         struct ast_channel *in = qe->chan;
1634         
1635         while(*to && !peer) {
1636                 BUILD_WATCHERS;
1637                 if ((found < 0) && stillgoing && !qe->parent->strategy) {
1638                         /* On "ringall" strategy we only move to the next penalty level
1639                            when *all* ringing phones are done in the current penalty level */
1640                         ring_one(qe, outgoing, &numbusies);
1641                         BUILD_WATCHERS;
1642                 }
1643                 if (found < 0) {
1644                         if (numlines == (numbusies + numnochan)) {
1645                                 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1646                         } else {
1647                                 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1648                         }
1649                         *to = 0;
1650                         return NULL;
1651                 }
1652                 winner = ast_waitfor_n(watchers, pos, to);
1653                 o = outgoing;
1654                 while(o) {
1655                         if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
1656                                 if (!peer) {
1657                                         if (option_verbose > 2)
1658                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1659                                         peer = o;
1660                                 }
1661                         } else if (o->chan && (o->chan == winner)) {
1662                                 ast_copy_string(on, o->member->interface, sizeof(on));
1663                                 if (!ast_strlen_zero(o->chan->call_forward)) {
1664                                         char tmpchan[256]="";
1665                                         char *stuff;
1666                                         char *tech;
1667                                         ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1668                                         if ((stuff = strchr(tmpchan, '/'))) {
1669                                                 *stuff = '\0';
1670                                                 stuff++;
1671                                                 tech = tmpchan;
1672                                         } else {
1673                                                 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1674                                                 stuff = tmpchan;
1675                                                 tech = "Local";
1676                                         }
1677                                         /* Before processing channel, go ahead and check for forwarding */
1678                                         if (option_verbose > 2)
1679                                                 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1680                                         /* Setup parameters */
1681                                         o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1682                                         if (status != o->oldstatus) 
1683                                                 update_dial_status(qe->parent, o->member, status);                                              
1684                                         if (!o->chan) {
1685                                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1686                                                 o->stillgoing = 0;
1687                                                 numnochan++;
1688                                         } else {
1689                                                 if (o->chan->cid.cid_num)
1690                                                         free(o->chan->cid.cid_num);
1691                                                 o->chan->cid.cid_num = NULL;
1692                                                 if (o->chan->cid.cid_name)
1693                                                         free(o->chan->cid.cid_name);
1694                                                 o->chan->cid.cid_name = NULL;
1695
1696                                                 if (in->cid.cid_num) {
1697                                                         o->chan->cid.cid_num = strdup(in->cid.cid_num);
1698                                                         if (!o->chan->cid.cid_num)
1699                                                                 ast_log(LOG_WARNING, "Out of memory\n");        
1700                                                 }
1701                                                 if (in->cid.cid_name) {
1702                                                         o->chan->cid.cid_name = strdup(in->cid.cid_name);
1703                                                         if (!o->chan->cid.cid_name)
1704                                                                 ast_log(LOG_WARNING, "Out of memory\n");        
1705                                                 }
1706                                                 ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
1707                                                 o->chan->cdrflags = in->cdrflags;
1708
1709                                                 if (in->cid.cid_ani) {
1710                                                         if (o->chan->cid.cid_ani)
1711                                                                 free(o->chan->cid.cid_ani);
1712                                                         if ((o->chan->cid.cid_ani = ast_calloc(1, strlen(in->cid.cid_ani) + 1)))
1713                                                                 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
1714                                                 }
1715                                                 if (o->chan->cid.cid_rdnis) 
1716                                                         free(o->chan->cid.cid_rdnis);
1717                                                 if (!ast_strlen_zero(in->macroexten))
1718                                                         o->chan->cid.cid_rdnis = strdup(in->macroexten);
1719                                                 else
1720                                                         o->chan->cid.cid_rdnis = strdup(in->exten);
1721                                                 if (ast_call(o->chan, tmpchan, 0)) {
1722                                                         ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1723                                                         o->stillgoing = 0;
1724                                                         ast_hangup(o->chan);
1725                                                         o->chan = NULL;
1726                                                         numnochan++;
1727                                                 }
1728                                         }
1729                                         /* Hangup the original channel now, in case we needed it */
1730                                         ast_hangup(winner);
1731                                         continue;
1732                                 }
1733                                 f = ast_read(winner);
1734                                 if (f) {
1735                                         if (f->frametype == AST_FRAME_CONTROL) {
1736                                                 switch(f->subclass) {
1737                                         case AST_CONTROL_ANSWER:
1738                                                         /* This is our guy if someone answered. */
1739                                                         if (!peer) {
1740                                                                 if (option_verbose > 2)
1741                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1742                                                                 peer = o;
1743                                                         }
1744                                                         break;
1745                                                 case AST_CONTROL_BUSY:
1746                                                         if (option_verbose > 2)
1747                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1748                                                         o->stillgoing = 0;
1749                                                         if (in->cdr)
1750                                                                 ast_cdr_busy(in->cdr);
1751                                                         ast_hangup(o->chan);
1752                                                         o->chan = NULL;
1753                                                         if (qe->parent->strategy) {
1754                                                                 if (qe->parent->timeoutrestart)
1755                                                                         *to = orig;
1756                                                                 ring_one(qe, outgoing, &numbusies);
1757                                                         }
1758                                                         numbusies++;
1759                                                         break;
1760                                                 case AST_CONTROL_CONGESTION:
1761                                                         if (option_verbose > 2)
1762                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1763                                                         o->stillgoing = 0;
1764                                                         if (in->cdr)
1765                                                                 ast_cdr_busy(in->cdr);
1766                                                         ast_hangup(o->chan);
1767                                                         o->chan = NULL;
1768                                                         if (qe->parent->strategy) {
1769                                                                 if (qe->parent->timeoutrestart)
1770                                                                         *to = orig;
1771                                                                 ring_one(qe, outgoing, &numbusies);
1772                                                         }
1773                                                         numbusies++;
1774                                                         break;
1775                                                 case AST_CONTROL_RINGING:
1776                                                         if (option_verbose > 2)
1777                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1778                                                         if (!sentringing) {
1779 #if 0
1780                                                                 ast_indicate(in, AST_CONTROL_RINGING);
1781 #endif                                                          
1782                                                                 sentringing++;
1783                                                         }
1784                                                         break;
1785                                                 case AST_CONTROL_OFFHOOK:
1786                                                         /* Ignore going off hook */
1787                                                         break;
1788                                                 default:
1789                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1790                                                 }
1791                                         }
1792                                         ast_frfree(f);
1793                                 } else {
1794                                         o->stillgoing = 0;
1795                                         ast_hangup(o->chan);
1796                                         o->chan = NULL;
1797                                         if (qe->parent->strategy) {
1798                                                 if (qe->parent->timeoutrestart)
1799                                                         *to = orig;
1800                                                 ring_one(qe, outgoing, &numbusies);
1801                                         }
1802                                 }
1803                         }
1804                         o = o->next;
1805                 }
1806                 if (winner == in) {
1807                         f = ast_read(in);
1808 #if 0
1809                         if (f && (f->frametype != AST_FRAME_VOICE))
1810                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1811                         else if (!f || (f->frametype != AST_FRAME_VOICE))
1812                                 printf("Hangup received on %s\n", in->name);
1813 #endif
1814                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1815                                 /* Got hung up */
1816                                 *to=-1;
1817                                 if (f)
1818                                         ast_frfree(f);
1819                                 return NULL;
1820                         }
1821                         if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1822                                 if (option_verbose > 3)
1823                                         ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1824                                 *to=0;
1825                                 ast_frfree(f);
1826                                 return NULL;
1827                         }
1828                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1829                                 if (option_verbose > 3)
1830                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1831                                 *to=0;
1832                                 *digit=f->subclass;
1833                                 ast_frfree(f);
1834                                 return NULL;
1835                         }
1836                         ast_frfree(f);
1837                 }
1838                 if (!*to) {
1839                         if (option_verbose > 2)
1840                                 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1841                         if (qe->parent->autopause) {
1842                                 if (!set_member_paused(qe->parent->name, on, 1)) {
1843                                         if (option_verbose > 2)
1844                                                 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", on, qe->parent->name);
1845                                 } else {
1846                                         if (option_verbose > 2)
1847                                                 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", on, qe->parent->name);
1848                                 }
1849                         }
1850                 }
1851         }
1852
1853         return peer;
1854         
1855 }
1856
1857 static int is_our_turn(struct queue_ent *qe)
1858 {
1859         struct queue_ent *ch;
1860         int res;
1861
1862         /* Atomically read the parent head -- does not need a lock */
1863         ch = qe->parent->head;
1864         /* If we are now at the top of the head, break out */
1865         if ((ch == qe) || (qe->parent->autofill)) {
1866                 if (option_debug)
1867                         ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1868                 res = 1;
1869         } else {
1870                 if (option_debug)
1871                         ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1872                 res = 0;
1873         }
1874         return res;
1875 }
1876
1877 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1878 {
1879         int res = 0;
1880
1881         /* This is the holding pen for callers 2 through maxlen */
1882         for (;;) {
1883                 enum queue_member_status stat;
1884
1885                 if (is_our_turn(qe))
1886                         break;
1887
1888                 /* If we have timed out, break out */
1889                 if (qe->expire && (time(NULL) > qe->expire)) {
1890                         *reason = QUEUE_TIMEOUT;
1891                         ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
1892                         break;
1893                 }
1894
1895                 stat = get_member_status(qe->parent, qe->max_penalty);
1896
1897                 /* leave the queue if no agents, if enabled */
1898                 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1899                         *reason = QUEUE_LEAVEEMPTY;
1900                         leave_queue(qe);
1901                         break;
1902                 }
1903
1904                 /* leave the queue if no reachable agents, if enabled */
1905                 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1906                         *reason = QUEUE_LEAVEUNAVAIL;
1907                         leave_queue(qe);
1908                         break;
1909                 }
1910
1911                 /* Make a position announcement, if enabled */
1912                 if (qe->parent->announcefrequency && !ringing)
1913                         res = say_position(qe);
1914                 if (res)
1915                         break;
1916
1917                 /* Make a periodic announcement, if enabled */
1918                 if (qe->parent->periodicannouncefrequency && !ringing)
1919                         res = say_periodic_announcement(qe);
1920
1921                 /* Wait a second before checking again */
1922                 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1923                 if (res)
1924                         break;
1925         }
1926         return res;
1927 }
1928
1929 static int update_queue(struct ast_call_queue *q, struct member *member)
1930 {
1931         struct member *cur;
1932
1933         /* Since a reload could have taken place, we have to traverse the list to
1934                 be sure it's still valid */
1935         ast_mutex_lock(&q->lock);
1936         cur = q->members;
1937         while(cur) {
1938                 if (member == cur) {
1939                         time(&cur->lastcall);
1940                         cur->calls++;
1941                         break;
1942                 }
1943                 cur = cur->next;
1944         }
1945         q->callscompleted++;
1946         ast_mutex_unlock(&q->lock);
1947         return 0;
1948 }
1949
1950 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1951 {
1952         if (mem->penalty > qe->max_penalty)
1953                 return -1;
1954
1955         switch (q->strategy) {
1956         case QUEUE_STRATEGY_RINGALL:
1957                 /* Everyone equal, except for penalty */
1958                 tmp->metric = mem->penalty * 1000000;
1959                 break;
1960         case QUEUE_STRATEGY_ROUNDROBIN:
1961                 if (!pos) {
1962                         if (!q->wrapped) {
1963                                 /* No more channels, start over */
1964                                 q->rrpos = 0;
1965                         } else {
1966                                 /* Prioritize next entry */
1967                                 q->rrpos++;
1968                         }
1969                         q->wrapped = 0;
1970                 }
1971                 /* Fall through */
1972         case QUEUE_STRATEGY_RRMEMORY:
1973                 if (pos < q->rrpos) {
1974                         tmp->metric = 1000 + pos;
1975                 } else {
1976                         if (pos > q->rrpos)
1977                                 /* Indicate there is another priority */
1978                                 q->wrapped = 1;
1979                         tmp->metric = pos;
1980                 }
1981                 tmp->metric += mem->penalty * 1000000;
1982                 break;
1983         case QUEUE_STRATEGY_RANDOM:
1984                 tmp->metric = rand() % 1000;
1985                 tmp->metric += mem->penalty * 1000000;
1986                 break;
1987         case QUEUE_STRATEGY_FEWESTCALLS:
1988                 tmp->metric = mem->calls;
1989                 tmp->metric += mem->penalty * 1000000;
1990                 break;
1991         case QUEUE_STRATEGY_LEASTRECENT:
1992                 if (!mem->lastcall)
1993                         tmp->metric = 0;
1994                 else
1995                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1996                 tmp->metric += mem->penalty * 1000000;
1997                 break;
1998         default:
1999                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2000                 break;
2001         }
2002         return 0;
2003 }
2004
2005 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
2006 {
2007         struct member *cur;
2008         struct localuser *outgoing=NULL, *tmp = NULL;
2009         int to;
2010         char restofit[AST_MAX_EXTENSION];
2011         char oldexten[AST_MAX_EXTENSION]="";
2012         char oldcontext[AST_MAX_CONTEXT]="";
2013         char queuename[256]="";
2014         char *newnum;
2015         struct ast_channel *peer;
2016         struct ast_channel *which;
2017         struct localuser *lpeer;
2018         struct member *member;
2019         int res = 0, bridge = 0;
2020         int numbusies = 0;
2021         int x=0;
2022         char *announce = NULL;
2023         char digit = 0;
2024         time_t callstart;
2025         time_t now = time(NULL);
2026         struct ast_bridge_config bridge_config;
2027         char nondataquality = 1;
2028
2029         memset(&bridge_config, 0, sizeof(bridge_config));
2030         time(&now);
2031                 
2032         for (; options && *options; options++)
2033                 switch (*options) {
2034                 case 't':
2035                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2036                         break;
2037                 case 'T':
2038                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2039                         break;
2040                 case 'w':
2041                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2042                         break;
2043                 case 'W':
2044                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2045                         break;
2046                 case 'd':
2047                         nondataquality = 0;
2048                         break;
2049                 case 'h':
2050                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2051                         break;
2052                 case 'H':
2053                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2054                         break;
2055                 case 'n':
2056                         if ((now - qe->start >= qe->parent->timeout))
2057                                 *go_on = 1;
2058                         break;
2059                 }
2060
2061         /* Hold the lock while we setup the outgoing calls */
2062         if (use_weight) 
2063                 ast_mutex_lock(&qlock);
2064         ast_mutex_lock(&qe->parent->lock);
2065         if (option_debug)
2066                 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
2067                                                         qe->chan->name);
2068         ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2069         cur = qe->parent->members;
2070         if (!ast_strlen_zero(qe->announce))
2071                 announce = qe->announce;
2072         if (!ast_strlen_zero(announceoverride))
2073                 announce = announceoverride;
2074
2075         while(cur) {
2076                 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
2077                         ast_mutex_unlock(&qe->parent->lock);
2078                         if (use_weight) 
2079                                 ast_mutex_unlock(&qlock);
2080                         goto out;
2081                 }
2082                 tmp->stillgoing = -1;
2083                 if (option_debug) {
2084                         if (url)
2085                                 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2086                         else 
2087                                 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
2088                 }
2089
2090                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
2091                 tmp->oldstatus = cur->status;
2092                 tmp->lastcall = cur->lastcall;
2093                 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2094                 /* If we're dialing by extension, look at the extension to know what to dial */
2095                 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
2096                         newnum++;
2097                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
2098                         snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
2099                         if (option_debug)
2100                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
2101                 }
2102                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2103                    just calculate their metric for the appropriate strategy */
2104                 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2105                         /* Put them in the list of outgoing thingies...  We're ready now. 
2106                            XXX If we're forcibly removed, these outgoing calls won't get
2107                            hung up XXX */
2108                         tmp->next = outgoing;
2109                         outgoing = tmp;         
2110                         /* If this line is up, don't try anybody else */
2111                         if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2112                                 break;
2113                 } else {
2114                         free(tmp);
2115                 }
2116
2117                 cur = cur->next;
2118         }
2119         if (qe->parent->timeout)
2120                 to = qe->parent->timeout * 1000;
2121         else
2122                 to = -1;
2123         ring_one(qe, outgoing, &numbusies);
2124         ast_mutex_unlock(&qe->parent->lock);
2125         if (use_weight) 
2126                 ast_mutex_unlock(&qlock);
2127         lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
2128         ast_mutex_lock(&qe->parent->lock);
2129         if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2130                 store_next(qe, outgoing);
2131         }
2132         ast_mutex_unlock(&qe->parent->lock);
2133         if (lpeer)
2134                 peer = lpeer->chan;
2135         else
2136                 peer = NULL;
2137         if (!peer) {
2138                 if (to) {
2139                         /* Musta gotten hung up */
2140                         record_abandoned(qe);
2141                         res = -1;
2142                 } else {
2143                         res = digit;
2144                 }
2145                 if (option_debug)
2146                         ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2147                 goto out;
2148         }
2149         if (peer) {
2150                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
2151                    we will always return with -1 so that it is hung up properly after the 
2152                    conversation.  */
2153                 qe->handled++;
2154                 if (!strcmp(qe->chan->type,"Zap"))
2155                         ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2156                 if (!strcmp(peer->type,"Zap"))
2157                         ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2158                 /* Update parameters for the queue */
2159                 recalc_holdtime(qe);
2160                 member = lpeer->member;
2161                 hangupcalls(outgoing, peer);
2162                 outgoing = NULL;
2163                 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2164                         int res2;
2165                         res2 = ast_autoservice_start(qe->chan);
2166                         if (!res2) {
2167                                 if (qe->parent->memberdelay) {
2168                                         ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2169                                         res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2170                                 }
2171                                 if (!res2 && announce) {
2172                                         if (play_file(peer, announce))
2173                                                 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2174                                 }
2175                                 if (!res2 && qe->parent->reportholdtime) {
2176                                         if (!play_file(peer, qe->parent->sound_reporthold)) {
2177                                                 int holdtime;
2178
2179                                                 time(&now);
2180                                                 holdtime = abs((now - qe->start) / 60);
2181                                                 if (holdtime < 2) {
2182                                                         play_file(peer, qe->parent->sound_lessthan);
2183                                                         ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2184                                                 } else 
2185                                                         ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2186                                                 play_file(peer, qe->parent->sound_minutes);
2187                                         }
2188                                 }
2189                         }
2190                         res2 |= ast_autoservice_stop(qe->chan);
2191                         if (peer->_softhangup) {
2192                                 /* Agent must have hung up */
2193                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
2194                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
2195                                 record_abandoned(qe);
2196                                 if (qe->parent->eventwhencalled) {
2197                                         manager_event(EVENT_FLAG_AGENT, "AgentDump",
2198                                                       "Queue: %s\r\n"
2199                                                       "Uniqueid: %s\r\n"
2200                                                       "Channel: %s\r\n"
2201                                                       "Member: %s\r\n",
2202                                                       queuename, qe->chan->uniqueid, peer->name, member->interface);
2203                                 }
2204                                 ast_hangup(peer);
2205                                 goto out;
2206                         } else if (res2) {
2207                                 /* Caller must have hung up just before being connected*/
2208                                 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2209                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2210                                 record_abandoned(qe);
2211                                 ast_hangup(peer);
2212                                 return -1;
2213                         }
2214                 }
2215                 /* Stop music on hold */
2216                 ast_moh_stop(qe->chan);
2217                 /* If appropriate, log that we have a destination channel */
2218                 if (qe->chan->cdr)
2219                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2220                 /* Make sure channels are compatible */
2221                 res = ast_channel_make_compatible(qe->chan, peer);
2222                 if (res < 0) {
2223                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2224                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2225                         record_abandoned(qe);
2226                         ast_hangup(peer);
2227                         return -1;
2228                 }
2229                 /* Begin Monitoring */
2230                 if (qe->parent->monfmt && *qe->parent->monfmt) {
2231                         const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2232                         if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2233                                 which = qe->chan;
2234                         else
2235                                 which = peer;
2236                         if (monitorfilename)
2237                                 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2238                         else if (qe->chan->cdr) 
2239                                 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2240                         else {
2241                                 /* Last ditch effort -- no CDR, make up something */
2242                                 char tmpid[256];
2243                                 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
2244                                 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2245                         }
2246                         if (qe->parent->monjoin)
2247                                 ast_monitor_setjoinfiles(which, 1);
2248                 }
2249                 /* Drop out of the queue at this point, to prepare for next caller */
2250                 leave_queue(qe);                        
2251                 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2252                         if (option_debug)
2253                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2254                         ast_channel_sendurl(peer, url);
2255                 }
2256                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
2257                 if (qe->parent->eventwhencalled)
2258                         manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2259                                       "Queue: %s\r\n"
2260                                       "Uniqueid: %s\r\n"
2261                                       "Channel: %s\r\n"
2262                                       "Member: %s\r\n"
2263                                       "Holdtime: %ld\r\n",
2264                                       queuename, qe->chan->uniqueid, peer->name, member->interface,
2265                                       (long)time(NULL) - qe->start);
2266                 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2267                 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2268                 time(&callstart);
2269
2270                 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2271
2272                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2273                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
2274                 } else if (qe->chan->_softhangup) {
2275                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2276                                       (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2277                         if (qe->parent->eventwhencalled)
2278                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2279                                               "Queue: %s\r\n"
2280                                               "Uniqueid: %s\r\n"
2281                                               "Channel: %s\r\n"
2282                                               "Member: %s\r\n"
2283                                               "HoldTime: %ld\r\n"
2284                                               "TalkTime: %ld\r\n"
2285                                               "Reason: caller\r\n",
2286                                               queuename, qe->chan->uniqueid, peer->name, member->interface,
2287                                               (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2288                 } else {
2289                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2290                         if (qe->parent->eventwhencalled)
2291                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2292                                               "Queue: %s\r\n"
2293                                               "Uniqueid: %s\r\n"
2294                                               "Channel: %s\r\n"
2295                                               "HoldTime: %ld\r\n"
2296                                               "TalkTime: %ld\r\n"
2297                                               "Reason: agent\r\n",
2298                                               queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2299                                               (long)(time(NULL) - callstart));
2300                 }
2301
2302                 if(bridge != AST_PBX_NO_HANGUP_PEER)
2303                         ast_hangup(peer);
2304                 update_queue(qe->parent, member);
2305                 if (bridge == 0) 
2306                         res = 1; /* JDG: bridge successfull, leave app_queue */
2307                 else 
2308                         res = bridge; /* bridge error, stay in the queue */
2309         }       
2310 out:
2311         hangupcalls(outgoing, NULL);
2312         return res;
2313 }
2314
2315 static int wait_a_bit(struct queue_ent *qe)
2316 {
2317         /* Don't need to hold the lock while we setup the outgoing calls */
2318         int retrywait = qe->parent->retry * 1000;
2319
2320         return ast_waitfordigit(qe->chan, retrywait);
2321 }
2322
2323 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2324 {
2325         struct member *mem;
2326
2327         if (q)
2328                 for (mem = q->members; mem; mem = mem->next)
2329                         if (!strcasecmp(interface, mem->interface))
2330                                 return mem;
2331
2332         return NULL;
2333 }
2334
2335
2336 /* Dump all members in a specific queue to the databse
2337  *
2338  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2339  *
2340  */
2341 static void dump_queue_members(struct ast_call_queue *pm_queue)
2342 {
2343         struct member *cur_member;
2344         char value[PM_MAX_LEN];
2345         int value_len = 0;
2346         int res;
2347
2348         memset(value, 0, sizeof(value));
2349
2350         if (!pm_queue)
2351                 return;
2352
2353         for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2354                 if (!cur_member->dynamic)
2355                         continue;
2356
2357                 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2358                                cur_member->interface, cur_member->penalty, cur_member->paused,
2359                                cur_member->next ? "|" : "");
2360                 if (res != strlen(value + value_len)) {
2361                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2362                         break;
2363                 }
2364                 value_len += res;
2365         }
2366         
2367         if (value_len && !cur_member) {
2368                 if (ast_db_put(pm_family, pm_queue->name, value))
2369                         ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2370         } else
2371                 /* Delete the entry if the queue is empty or there is an error */
2372                 ast_db_del(pm_family, pm_queue->name);
2373 }
2374
2375 static int remove_from_queue(char *queuename, char *interface)
2376 {
2377         struct ast_call_queue *q;
2378         struct member *last_member, *look;
2379         int res = RES_NOSUCHQUEUE;
2380
2381         ast_mutex_lock(&qlock);
2382         for (q = queues ; q ; q = q->next) {
2383                 ast_mutex_lock(&q->lock);
2384                 if (!strcmp(q->name, queuename)) {
2385                         if ((last_member = interface_exists(q, interface))) {
2386                                 if ((look = q->members) == last_member) {
2387                                         q->members = last_member->next;
2388                                 } else {
2389                                         while (look != NULL) {
2390                                                 if (look->next == last_member) {
2391                                                         look->next = last_member->next;
2392                                                         break;
2393                                                 } else {
2394                                                          look = look->next;
2395                                                 }
2396                                         }
2397                                 }
2398                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2399                                                 "Queue: %s\r\n"
2400                                                 "Location: %s\r\n",
2401                                         q->name, last_member->interface);
2402                                 free(last_member);
2403
2404                                 if (queue_persistent_members)
2405                                     dump_queue_members(q);
2406
2407                                 res = RES_OKAY;
2408                         } else {
2409                                 res = RES_EXISTS;
2410                         }
2411                         ast_mutex_unlock(&q->lock);
2412                         break;
2413                 }
2414                 ast_mutex_unlock(&q->lock);
2415         }
2416         ast_mutex_unlock(&qlock);
2417         return res;
2418 }
2419
2420 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2421 {
2422         struct ast_call_queue *q;
2423         struct member *new_member;
2424         int res = RES_NOSUCHQUEUE;
2425
2426         ast_mutex_lock(&qlock);
2427         for (q = queues ; q ; q = q->next) {
2428                 ast_mutex_lock(&q->lock);
2429                 if (!strcmp(q->name, queuename)) {
2430                         if (interface_exists(q, interface) == NULL) {
2431                                 new_member = create_queue_member(interface, penalty, paused);
2432
2433                                 if (new_member != NULL) {
2434                                         new_member->dynamic = 1;
2435                                         new_member->next = q->members;
2436                                         q->members = new_member;
2437                                         manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2438                                                 "Queue: %s\r\n"
2439                                                 "Location: %s\r\n"
2440                                                 "Membership: %s\r\n"
2441                                                 "Penalty: %d\r\n"
2442                                                 "CallsTaken: %d\r\n"
2443                                                 "LastCall: %d\r\n"
2444                                                 "Status: %d\r\n"
2445                                                 "Paused: %d\r\n",
2446                                         q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2447                                         new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
2448                                         
2449                                         if (dump)
2450                                                 dump_queue_members(q);
2451
2452                                         res = RES_OKAY;
2453                                 } else {
2454                                         res = RES_OUTOFMEMORY;
2455                                 }
2456                         } else {
2457                                 res = RES_EXISTS;
2458                         }
2459                         ast_mutex_unlock(&q->lock);
2460                         break;
2461                 }
2462                 ast_mutex_unlock(&q->lock);
2463         }
2464         ast_mutex_unlock(&qlock);
2465         return res;
2466 }
2467
2468 static int set_member_paused(char *queuename, char *interface, int paused)
2469 {
2470         int found = 0;
2471         struct ast_call_queue *q;
2472         struct member *mem;
2473
2474         /* Special event for when all queues are paused - individual events still generated */
2475
2476         if (ast_strlen_zero(queuename))
2477                 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2478
2479         ast_mutex_lock(&qlock);
2480         for (q = queues ; q ; q = q->next) {
2481                 ast_mutex_lock(&q->lock);
2482                 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
2483                         if ((mem = interface_exists(q, interface))) {
2484                                 found++;
2485                                 if (mem->paused == paused)
2486                                         ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2487                                 mem->paused = paused;
2488
2489                                 if (queue_persistent_members)
2490                                     dump_queue_members(q);
2491
2492                                 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2493
2494                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2495                                         "Queue: %s\r\n"
2496                                         "Location: %s\r\n"
2497                                         "Paused: %d\r\n",
2498                                                 q->name, mem->interface, paused);
2499                         }
2500                 }
2501                 ast_mutex_unlock(&q->lock);
2502         }
2503         ast_mutex_unlock(&qlock);
2504
2505         if (found)
2506                 return RESULT_SUCCESS;
2507         else
2508                 return RESULT_FAILURE;
2509 }
2510
2511 /* Reload dynamic queue members persisted into the astdb */
2512 static void reload_queue_members(void)
2513 {
2514         char *cur_ptr;  
2515         char *queue_name;
2516         char *member;
2517         char *interface;
2518         char *penalty_tok;
2519         int penalty = 0;
2520         char *paused_tok;
2521         int paused = 0;
2522         struct ast_db_entry *db_tree;
2523         struct ast_db_entry *entry;
2524         struct ast_call_queue *cur_queue;
2525         char queue_data[PM_MAX_LEN];
2526
2527         ast_mutex_lock(&qlock);
2528
2529         /* Each key in 'pm_family' is the name of a queue */
2530         db_tree = ast_db_gettree(pm_family, NULL);
2531         for (entry = db_tree; entry; entry = entry->next) {
2532
2533                 queue_name = entry->key + strlen(pm_family) + 2;
2534
2535                 cur_queue = queues;
2536                 while (cur_queue) {
2537                         ast_mutex_lock(&cur_queue->lock);
2538                         if (!strcmp(queue_name, cur_queue->name))
2539                                 break;
2540                         ast_mutex_unlock(&cur_queue->lock);
2541                         cur_queue = cur_queue->next;
2542                 }
2543
2544                 if (!cur_queue) {
2545                         /* If the queue no longer exists, remove it from the
2546                          * database */
2547                         ast_db_del(pm_family, queue_name);
2548                         continue;
2549                 } else
2550                         ast_mutex_unlock(&cur_queue->lock);
2551
2552                 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2553                         continue;
2554
2555                 cur_ptr = queue_data;
2556                 while ((member = strsep(&cur_ptr, "|"))) {
2557                         if (ast_strlen_zero(member))
2558                                 continue;
2559
2560                         interface = strsep(&member, ";");
2561                         penalty_tok = strsep(&member, ";");
2562                         paused_tok = strsep(&member, ";");
2563
2564                         if (!penalty_tok) {
2565                                 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
2566                                 break;
2567                         }
2568                         penalty = strtol(penalty_tok, NULL, 10);
2569                         if (errno == ERANGE) {
2570                                 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2571                                 break;
2572                         }
2573                         
2574                         if (!paused_tok) {
2575                                 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2576                                 break;
2577                         }
2578                         paused = strtol(paused_tok, NULL, 10);
2579                         if ((errno == ERANGE) || paused < 0 || paused > 1) {
2580                                 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2581                                 break;
2582                         }
2583
2584                         if (option_debug)
2585                                 ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
2586                         
2587                         if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2588                                 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2589                                 break;
2590                         }
2591                 }
2592         }
2593
2594         ast_mutex_unlock(&qlock);
2595         if (db_tree) {
2596                 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2597                 ast_db_freetree(db_tree);
2598         }
2599 }
2600
2601 static int pqm_exec(struct ast_channel *chan, void *data)
2602 {
2603         struct localuser *u;
2604         char *parse;
2605         int priority_jump = 0;
2606         AST_DECLARE_APP_ARGS(args,
2607                 AST_APP_ARG(queuename);
2608                 AST_APP_ARG(interface);
2609                 AST_APP_ARG(options);
2610         );
2611
2612         if (ast_strlen_zero(data)) {
2613                 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2614                 return -1;
2615         }
2616
2617         LOCAL_USER_ADD(u);
2618
2619         if (!(parse = ast_strdupa(data))) {
2620                 ast_log(LOG_WARNING, "Memory Error!\n");
2621                 LOCAL_USER_REMOVE(u);
2622                 return -1;
2623         }
2624
2625         AST_STANDARD_APP_ARGS(args, parse);
2626
2627         if (args.options) {
2628                 if (strchr(args.options, 'j'))
2629                         priority_jump = 1;
2630         }
2631
2632         if (ast_strlen_zero(args.interface)) {
2633                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2634                 LOCAL_USER_REMOVE(u);
2635                 return -1;
2636         }
2637
2638         if (set_member_paused(args.queuename, args.interface, 1)) {
2639                 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
2640                 if (priority_jump || ast_opt_priority_jumping) {
2641                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2642                                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2643                                 LOCAL_USER_REMOVE(u);
2644                                 return 0;
2645                         }
2646                 }
2647                 LOCAL_USER_REMOVE(u);
2648                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2649                 return -1;
2650         }
2651
2652         LOCAL_USER_REMOVE(u);
2653         pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2654         return 0;
2655 }
2656
2657 static int upqm_exec(struct ast_channel *chan, void *data)
2658 {
2659         struct localuser *u;
2660         char *parse;
2661         int priority_jump = 0;
2662         AST_DECLARE_APP_ARGS(args,
2663                 AST_APP_ARG(queuename);
2664                 AST_APP_ARG(interface);
2665                 AST_APP_ARG(options);
2666         );
2667
2668         if (ast_strlen_zero(data)) {
2669                 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2670                 return -1;
2671         }
2672
2673         LOCAL_USER_ADD(u);
2674
2675         if (!(parse = ast_strdupa(data))) {
2676                 ast_log(LOG_WARNING, "Memory Error!\n");
2677                 LOCAL_USER_REMOVE(u);
2678                 return -1;
2679         }
2680
2681         AST_STANDARD_APP_ARGS(args, parse);
2682
2683         if (args.options) {
2684                 if (strchr(args.options, 'j'))
2685                         priority_jump = 1;
2686         }
2687
2688         if (ast_strlen_zero(args.interface)) {
2689                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2690                 LOCAL_USER_REMOVE(u);
2691                 return -1;
2692         }
2693
2694         if (set_member_paused(args.queuename, args.interface, 0)) {
2695                 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
2696                 if (priority_jump || ast_opt_priority_jumping) {
2697                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2698                                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2699                                 LOCAL_USER_REMOVE(u);
2700                                 return 0;
2701                         }
2702                 }
2703                 LOCAL_USER_REMOVE(u);
2704                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2705                 return -1;
2706         }
2707
2708         LOCAL_USER_REMOVE(u);
2709         pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2710         return 0;
2711 }
2712
2713 static int rqm_exec(struct ast_channel *chan, void *data)
2714 {
2715         int res=-1;
2716         struct localuser *u;
2717         char *parse, *temppos = NULL;
2718         int priority_jump = 0;
2719         AST_DECLARE_APP_ARGS(args,
2720                 AST_APP_ARG(queuename);
2721                 AST_APP_ARG(interface);
2722                 AST_APP_ARG(options);
2723         );
2724
2725
2726         if (ast_strlen_zero(data)) {
2727                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2728                 return -1;
2729         }
2730
2731         LOCAL_USER_ADD(u);
2732
2733         if (!(parse = ast_strdupa(data))) {
2734                 ast_log(LOG_WARNING, "Memory Error!\n");
2735                 LOCAL_USER_REMOVE(u);
2736                 return -1;
2737         }
2738
2739         AST_STANDARD_APP_ARGS(args, parse);
2740
2741         if (ast_strlen_zero(args.interface)) {
2742                 args.interface = ast_strdupa(chan->name);
2743                 temppos = strrchr(args.interface, '-');
2744                 if (temppos)
2745                         *temppos = '\0';
2746         }
2747
2748         if (args.options) {
2749                 if (strchr(args.options, 'j'))
2750                         priority_jump = 1;
2751         }
2752
2753         switch (remove_from_queue(args.queuename, args.interface)) {
2754         case RES_OKAY:
2755                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2756                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
2757                 res = 0;
2758                 break;
2759         case RES_EXISTS:
2760                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
2761                 if (priority_jump || ast_opt_priority_jumping) 
2762                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2763                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
2764                 res = 0;
2765                 break;
2766         case RES_NOSUCHQUEUE:
2767                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
2768                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
2769                 res = 0;
2770                 break;
2771         case RES_OUTOFMEMORY:
2772                 ast_log(LOG_ERROR, "Out of memory\n");
2773                 break;
2774         }
2775
2776         LOCAL_USER_REMOVE(u);
2777         return res;
2778 }
2779
2780 static int aqm_exec(struct ast_channel *chan, void *data)
2781 {
2782         int res=-1;
2783         struct localuser *u;
2784         char *parse, *temppos = NULL;
2785         int priority_jump = 0;
2786         AST_DECLARE_APP_ARGS(args,
2787                 AST_APP_ARG(queuename);
2788                 AST_APP_ARG(interface);
2789                 AST_APP_ARG(penalty);
2790                 AST_APP_ARG(options);
2791         );
2792         int penalty = 0;
2793
2794         if (ast_strlen_zero(data)) {
2795                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2796                 return -1;
2797         }
2798
2799         LOCAL_USER_ADD(u);
2800
2801         if (!(parse = ast_strdupa(data))) {
2802                 ast_log(LOG_WARNING, "Memory Error!\n");
2803                 LOCAL_USER_REMOVE(u);
2804                 return -1;
2805         }
2806
2807         AST_STANDARD_APP_ARGS(args, parse);
2808
2809         if (ast_strlen_zero(args.interface)) {
2810                 args.interface = ast_strdupa(chan->name);
2811                 temppos = strrchr(args.interface, '-');
2812                 if (temppos)
2813                         *temppos = '\0';
2814         }
2815
2816         if (!ast_strlen_zero(args.penalty)) {
2817                 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
2818                         ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
2819                         penalty = 0;
2820                 }
2821         }
2822         
2823         if (args.options) {
2824                 if (strchr(args.options, 'j'))
2825                         priority_jump = 1;
2826         }
2827
2828
2829         switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2830         case RES_OKAY:
2831                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2832                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
2833                 res = 0;
2834                 break;
2835         case RES_EXISTS:
2836                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
2837                 if (priority_jump || ast_opt_priority_jumping) 
2838                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2839                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
2840                 res = 0;
2841                 break;
2842         case RES_NOSUCHQUEUE:
2843                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
2844                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
2845                 res = 0;
2846                 break;
2847         case RES_OUTOFMEMORY:
2848                 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2849                 break;
2850         }
2851
2852         LOCAL_USER_REMOVE(u);
2853         return res;
2854 }
2855
2856 static int queue_exec(struct ast_channel *chan, void *data)
2857 {
2858         int res=-1;
2859         int ringing=0;
2860         struct localuser *u;
2861         char *queuename;
2862         char info[512];
2863         char *info_ptr = info;
2864         char *options = NULL;
2865         char *url = NULL;
2866         char *announceoverride = NULL;
2867         const char *user_priority;
2868         const char *max_penalty_str;
2869         int prio;
2870         int max_penalty;
2871         char *queuetimeoutstr = NULL;
2872         enum queue_result reason = QUEUE_UNKNOWN;
2873
2874         /* whether to exit Queue application after the timeout hits */
2875         int go_on = 0;
2876
2877         /* Our queue entry */
2878         struct queue_ent qe;
2879         
2880         if (ast_strlen_zero(data)) {
2881                 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2882                 return -1;
2883         }
2884
2885         LOCAL_USER_ADD(u);
2886
2887         /* Setup our queue entry */
2888         memset(&qe, 0, sizeof(qe));
2889         qe.start = time(NULL);
2890         
2891         /* Parse our arguments XXX Check for failure XXX */
2892         ast_copy_string(info, (char *) data, sizeof(info));
2893         queuename = strsep(&info_ptr, "|");
2894         options = strsep(&info_ptr, "|");
2895         url = strsep(&info_ptr, "|");
2896         announceoverride = strsep(&info_ptr, "|");
2897         queuetimeoutstr = info_ptr;
2898
2899         /* set the expire time based on the supplied timeout; */
2900         if (queuetimeoutstr)
2901                 qe.expire = qe.start + atoi(queuetimeoutstr);
2902         else
2903                 qe.expire = 0;
2904
2905         /* Get the priority from the variable ${QUEUE_PRIO} */
2906         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2907         if (user_priority) {
2908                 if (sscanf(user_priority, "%d", &prio) == 1) {
2909                         if (option_debug)
2910                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2911                                         chan->name, prio);
2912                 } else {
2913                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2914                                 user_priority, chan->name);
2915                         prio = 0;
2916                 }
2917         } else {
2918                 if (option_debug > 2)
2919                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2920                 prio = 0;
2921         }
2922
2923         /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
2924         if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
2925                 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
2926                         if (option_debug)
2927                                 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
2928                                         chan->name, max_penalty);
2929                 } else {
2930                         ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
2931                                 max_penalty_str, chan->name);
2932                         max_penalty = 0;
2933                 }
2934         } else {
2935                 max_penalty = 0;
2936         }
2937
2938         if (options && (strchr(options, 'r')))
2939                 ringing = 1;
2940
2941         if (option_debug)  
2942                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2943                         queuename, options, url, announceoverride, (long)qe.expire, prio);
2944
2945         qe.chan = chan;
2946         qe.prio = prio;
2947         qe.max_penalty = max_penalty;
2948         qe.last_pos_said = 0;
2949         qe.last_pos = 0;
2950         qe.last_periodic_announce_time = time(NULL);
2951         if (!join_queue(queuename, &qe, &reason)) {
2952                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
2953                               chan->cid.cid_num ? chan->cid.cid_num : "");
2954 check_turns:
2955                 if (ringing) {
2956                         ast_indicate(chan, AST_CONTROL_RINGING);
2957                 } else {              
2958                         ast_moh_start(chan, qe.moh);
2959                 }
2960                 for (;;) {
2961                         /* This is the wait loop for callers 2 through maxlen */
2962
2963                         res = wait_our_turn(&qe, ringing, &reason);
2964                         /* If they hungup, return immediately */
2965                         if (res < 0) {
2966                                 /* Record this abandoned call */
2967                                 record_abandoned(&qe);
2968                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2969                                 if (option_verbose > 2) {
2970                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2971                                         res = -1;
2972                                 }
2973                                 break;
2974                         }
2975                         if (!res) 
2976                                 break;
2977                         if (valid_exit(&qe, res)) {
2978                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
2979                                 break;
2980                         }
2981                 }
2982                 if (!res) {
2983                         int makeannouncement = 0;
2984                         for (;;) {
2985                                 /* This is the wait loop for the head caller*/
2986                                 /* To exit, they may get their call answered; */
2987                                 /* they may dial a digit from the queue context; */
2988                                 /* or, they may timeout. */
2989
2990                                 enum queue_member_status stat;
2991
2992                                 /* Leave if we have exceeded our queuetimeout */
2993                                 if (qe.expire && (time(NULL) > qe.expire)) {
2994                                         record_abandoned(&qe);
2995                                         reason = QUEUE_TIMEOUT;
2996                                         res = 0;
2997                                         ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2998                                         break;
2999                                 }
3000
3001                                 if (makeannouncement) {
3002                                         /* Make a position announcement, if enabled */
3003                                         if (qe.parent->announcefrequency && !ringing)
3004                                                 res = say_position(&qe);
3005                                         if (res && valid_exit(&qe, res)) {
3006                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3007                                                 break;
3008                                         }
3009
3010                                 }
3011                                 makeannouncement = 1;
3012
3013                                 /* Make a periodic announcement, if enabled */
3014                                 if (qe.parent->periodicannouncefrequency && !ringing)
3015                                         res = say_periodic_announcement(&qe);
3016
3017                                 if (res && valid_exit(&qe, res)) {
3018                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
3019                                         break;
3020                                 }
3021
3022                                 /* Try calling all queue members for 'timeout' seconds */
3023                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
3024                                 if (res) {
3025                                         if (res < 0) {
3026                                                 if (!qe.handled) {
3027                                                         record_abandoned(&qe);
3028                                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3029                                                 }
3030                                         } else if (res > 0)
3031                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3032                                         break;
3033                                 }
3034
3035                                 stat = get_member_status(qe.parent, qe.max_penalty);
3036
3037                                 /* leave the queue if no agents, if enabled */
3038                                 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
3039                                         record_abandoned(&qe);
3040                                         reason = QUEUE_LEAVEEMPTY;
3041                                         res = 0;
3042                                         break;
3043                                 }
3044
3045                                 /* leave the queue if no reachable agents, if enabled */
3046                                 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
3047                                         record_abandoned(&qe);
3048                                         reason = QUEUE_LEAVEUNAVAIL;
3049                                         res = 0;
3050                                         break;
3051                                 }
3052
3053                                 /* Leave if we have exceeded our queuetimeout */
3054                                 if (qe.expire && (time(NULL) > qe.expire)) {
3055                                         record_abandoned(&qe);
3056                                         reason = QUEUE_TIMEOUT;
3057                                         res = 0;
3058                                         ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);       
3059                                         break;
3060                                 }
3061
3062                                 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3063                                 res = wait_a_bit(&qe);
3064                                 if (res < 0) {
3065                                         record_abandoned(&qe);
3066                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3067                                         if (option_verbose > 2) {
3068                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
3069                                                 res = -1;
3070                                         }
3071                                         break;
3072                                 }
3073                                 if (res && valid_exit(&qe, res)) {
3074                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3075                                         break;
3076                                 }
3077                                 /* exit after 'timeout' cycle if 'n' option enabled */
3078                                 if (go_on) {
3079                                         if (option_verbose > 2) {
3080                                                 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
3081                                                 res = -1;
3082                                         }
3083                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3084                                         record_abandoned(&qe);
3085                                         reason = QUEUE_TIMEOUT;
3086                                         res = 0;
3087                                         break;
3088                                 }
3089                                 /* Since this is a priority queue and 
3090                                  * it is not sure that we are still at the head
3091                                  * of the queue, go and check for our turn again.
3092                                  */
3093                                 if (!is_our_turn(&qe)) {
3094                                         if (option_debug)
3095                                                 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
3096                                                                 qe.chan->name);
3097                                         goto check_turns;
3098                                 }
3099                         }
3100                 }
3101                 /* Don't allow return code > 0 */
3102                 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
3103                         res = 0;        
3104                         if (ringing) {
3105                                 ast_indicate(chan, -1);
3106                         } else {
3107                                 ast_moh_stop(chan);
3108                         }                       
3109                         ast_stopstream(chan);
3110                 }
3111                 leave_queue(&qe);
3112                 if (reason != QUEUE_UNKNOWN)
3113                         set_queue_result(chan, reason);
3114         } else {
3115                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
3116                 set_queue_result(chan, reason);
3117                 res = 0;
3118         }
3119         LOCAL_USER_REMOVE(u);
3120         return res;
3121 }
3122
3123 static char *queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3124 {
3125         int count = 0;
3126         struct ast_call_queue *q;
3127         struct localuser *u;
3128         struct member *m;
3129
3130         LOCAL_USER_ACF_ADD(u);
3131
3132         ast_copy_string(buf, "0", len);
3133         
3134         if (ast_strlen_zero(data)) {
3135                 ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n");
3136                 LOCAL_USER_REMOVE(u);
3137                 return buf;
3138         }
3139
3140         ast_mutex_lock(&qlock);
3141
3142         /* Find the right queue */
3143         for (q = queues; q; q = q->next) {
3144                 if (!strcasecmp(q->name, data)) {
3145                         ast_mutex_lock(&q->lock);
3146                         break;
3147                 }
3148         }
3149
3150         ast_mutex_unlock(&qlock);
3151
3152         if (q) {
3153                 for (m = q->members; m; m = m->next) {
3154                         /* Count the agents who are logged in and presently answering calls */
3155                         if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
3156                                 count++;
3157                         }
3158                 }
3159                 ast_mutex_unlock(&q->lock);
3160         }
3161
3162         snprintf(buf, len, "%d", count);
3163         LOCAL_USER_REMOVE(u);
3164         return buf;
3165 }
3166
3167 static struct ast_custom_function queueagentcount_function = {
3168         .name = "QUEUEAGENTCOUNT",
3169         .synopsis = "Count number of agents answering a queue",
3170         .syntax = "QUEUEAGENTCOUNT(<queuename>)",
3171         .read = queue_function_qac,
3172 };
3173
3174 static void reload_queues(void)
3175 {
3176         struct ast_call_queue *q, *ql, *qn;
3177         struct ast_config *cfg;
3178         char *cat, *tmp;
3179         struct ast_variable *var;
3180         struct member *prev, *cur;
3181         int new;
3182         char *general_val = NULL;
3183         char interface[80];
3184         int penalty;
3185         
3186         cfg = ast_config_load("queues.conf");
3187         if (!cfg) {
3188                 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
3189                 return;
3190         }
3191         memset(interface, 0, sizeof(interface));
3192         ast_mutex_lock(&qlock);
3193         use_weight=0;
3194         /* Mark all queues as dead for the moment */
3195         q = queues;
3196         while(q) {
3197                 q->dead = 1;
3198                 q = q->next;
3199         }
3200         /* Chug through config file */
3201         cat = ast_category_browse(cfg, NULL);
3202         while(cat) {
3203                 if (!strcasecmp(cat, "general")) {      
3204                         /* Initialize global settings */
3205                         queue_persistent_members = 0;
3206                         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
3207                                 queue_persistent_members = ast_true(general_val);
3208                 } else {        /* Define queue */
3209                         /* Look for an existing one */
3210                         q = queues;
3211                         while(q) {
3212                                 if (!strcmp(q->name, cat))
3213                                         break;
3214                                 q = q->next;
3215                         }
3216                         if (!q) {
3217                                 /* Make one then */
3218                                 if (!(q = alloc_queue(cat))) {
3219                                         /* TODO: Handle memory allocation failure */
3220                                 }
3221                                 new = 1;
3222                         } else
3223                                 new = 0;
3224                         if (q) {
3225                                 if (!new)
3226                                         ast_mutex_lock(&q->lock);
3227                                 /* Re-initialize the queue, and clear statistics */
3228                                 init_queue(q);
3229                                 clear_queue(q);
3230                                 free_members(q, 0);
3231                                 prev = q->members;
3232                                 if (prev) {
3233                                         /* find the end of any dynamic members */
3234                                         while(prev->next)
3235                                                 prev = prev->next;
3236                                 }
3237                                 var = ast_variable_browse(cfg, cat);
3238                                 while(var) {
3239                                         if (!strcasecmp(var->name, "member")) {
3240                                                 /* Add a new member */
3241                                                 ast_copy_string(interface, var->value, sizeof(interface));
3242                                                 if ((tmp = strchr(interface, ','))) {
3243                                                         *tmp = '\0';
3244                                                         tmp++;
3245                                                         penalty = atoi(tmp);
3246                                                         if (penalty < 0) {
3247                                                                 penalty = 0;
3248                                                         }
3249                                                 } else
3250                                                         penalty = 0;
3251                                                 cur = create_queue_member(interface, penalty, 0);
3252                                                 if (cur) {
3253                                                         if (prev)
3254                                                                 prev->next = cur;
3255                                                         else
3256                                                                 q->members = cur;
3257                                                         prev = cur;
3258                                                 }
3259                                         } else {
3260                                                 queue_set_param(q, var->name, var->value, var->lineno, 1);
3261                                         }
3262                                         var = var->next;
3263                                 }
3264                                 if (!new) 
3265                                         ast_mutex_unlock(&q->lock);
3266                                 if (new) {
3267                                         q->next = queues;
3268                                         queues = q;