06aebe72418a1c34b6f55efbfe6a3c037bc9e8fc
[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                                                         o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
1713                                                 }
1714                                                 if (o->chan->cid.cid_rdnis) 
1715                                                         free(o->chan->cid.cid_rdnis);
1716                                                 if (!ast_strlen_zero(in->macroexten))
1717                                                         o->chan->cid.cid_rdnis = strdup(in->macroexten);
1718                                                 else
1719                                                         o->chan->cid.cid_rdnis = strdup(in->exten);
1720                                                 if (ast_call(o->chan, tmpchan, 0)) {
1721                                                         ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1722                                                         o->stillgoing = 0;
1723                                                         ast_hangup(o->chan);
1724                                                         o->chan = NULL;
1725                                                         numnochan++;
1726                                                 }
1727                                         }
1728                                         /* Hangup the original channel now, in case we needed it */
1729                                         ast_hangup(winner);
1730                                         continue;
1731                                 }
1732                                 f = ast_read(winner);
1733                                 if (f) {
1734                                         if (f->frametype == AST_FRAME_CONTROL) {
1735                                                 switch(f->subclass) {
1736                                         case AST_CONTROL_ANSWER:
1737                                                         /* This is our guy if someone answered. */
1738                                                         if (!peer) {
1739                                                                 if (option_verbose > 2)
1740                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1741                                                                 peer = o;
1742                                                         }
1743                                                         break;
1744                                                 case AST_CONTROL_BUSY:
1745                                                         if (option_verbose > 2)
1746                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1747                                                         o->stillgoing = 0;
1748                                                         if (in->cdr)
1749                                                                 ast_cdr_busy(in->cdr);
1750                                                         ast_hangup(o->chan);
1751                                                         o->chan = NULL;
1752                                                         if (qe->parent->strategy) {
1753                                                                 if (qe->parent->timeoutrestart)
1754                                                                         *to = orig;
1755                                                                 ring_one(qe, outgoing, &numbusies);
1756                                                         }
1757                                                         numbusies++;
1758                                                         break;
1759                                                 case AST_CONTROL_CONGESTION:
1760                                                         if (option_verbose > 2)
1761                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1762                                                         o->stillgoing = 0;
1763                                                         if (in->cdr)
1764                                                                 ast_cdr_busy(in->cdr);
1765                                                         ast_hangup(o->chan);
1766                                                         o->chan = NULL;
1767                                                         if (qe->parent->strategy) {
1768                                                                 if (qe->parent->timeoutrestart)
1769                                                                         *to = orig;
1770                                                                 ring_one(qe, outgoing, &numbusies);
1771                                                         }
1772                                                         numbusies++;
1773                                                         break;
1774                                                 case AST_CONTROL_RINGING:
1775                                                         if (option_verbose > 2)
1776                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1777                                                         if (!sentringing) {
1778 #if 0
1779                                                                 ast_indicate(in, AST_CONTROL_RINGING);
1780 #endif                                                          
1781                                                                 sentringing++;
1782                                                         }
1783                                                         break;
1784                                                 case AST_CONTROL_OFFHOOK:
1785                                                         /* Ignore going off hook */
1786                                                         break;
1787                                                 default:
1788                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1789                                                 }
1790                                         }
1791                                         ast_frfree(f);
1792                                 } else {
1793                                         o->stillgoing = 0;
1794                                         ast_hangup(o->chan);
1795                                         o->chan = NULL;
1796                                         if (qe->parent->strategy) {
1797                                                 if (qe->parent->timeoutrestart)
1798                                                         *to = orig;
1799                                                 ring_one(qe, outgoing, &numbusies);
1800                                         }
1801                                 }
1802                         }
1803                         o = o->next;
1804                 }
1805                 if (winner == in) {
1806                         f = ast_read(in);
1807 #if 0
1808                         if (f && (f->frametype != AST_FRAME_VOICE))
1809                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1810                         else if (!f || (f->frametype != AST_FRAME_VOICE))
1811                                 printf("Hangup received on %s\n", in->name);
1812 #endif
1813                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1814                                 /* Got hung up */
1815                                 *to=-1;
1816                                 if (f)
1817                                         ast_frfree(f);
1818                                 return NULL;
1819                         }
1820                         if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1821                                 if (option_verbose > 3)
1822                                         ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1823                                 *to=0;
1824                                 ast_frfree(f);
1825                                 return NULL;
1826                         }
1827                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1828                                 if (option_verbose > 3)
1829                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1830                                 *to=0;
1831                                 *digit=f->subclass;
1832                                 ast_frfree(f);
1833                                 return NULL;
1834                         }
1835                         ast_frfree(f);
1836                 }
1837                 if (!*to) {
1838                         if (option_verbose > 2)
1839                                 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1840                         if (qe->parent->autopause) {
1841                                 if (!set_member_paused(qe->parent->name, on, 1)) {
1842                                         if (option_verbose > 2)
1843                                                 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", on, qe->parent->name);
1844                                 } else {
1845                                         if (option_verbose > 2)
1846                                                 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", on, qe->parent->name);
1847                                 }
1848                         }
1849                 }
1850         }
1851
1852         return peer;
1853         
1854 }
1855
1856 static int is_our_turn(struct queue_ent *qe)
1857 {
1858         struct queue_ent *ch;
1859         int res;
1860
1861         /* Atomically read the parent head -- does not need a lock */
1862         ch = qe->parent->head;
1863         /* If we are now at the top of the head, break out */
1864         if ((ch == qe) || (qe->parent->autofill)) {
1865                 if (option_debug)
1866                         ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1867                 res = 1;
1868         } else {
1869                 if (option_debug)
1870                         ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1871                 res = 0;
1872         }
1873         return res;
1874 }
1875
1876 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1877 {
1878         int res = 0;
1879
1880         /* This is the holding pen for callers 2 through maxlen */
1881         for (;;) {
1882                 enum queue_member_status stat;
1883
1884                 if (is_our_turn(qe))
1885                         break;
1886
1887                 /* If we have timed out, break out */
1888                 if (qe->expire && (time(NULL) > qe->expire)) {
1889                         *reason = QUEUE_TIMEOUT;
1890                         ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
1891                         break;
1892                 }
1893
1894                 stat = get_member_status(qe->parent, qe->max_penalty);
1895
1896                 /* leave the queue if no agents, if enabled */
1897                 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1898                         *reason = QUEUE_LEAVEEMPTY;
1899                         leave_queue(qe);
1900                         break;
1901                 }
1902
1903                 /* leave the queue if no reachable agents, if enabled */
1904                 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1905                         *reason = QUEUE_LEAVEUNAVAIL;
1906                         leave_queue(qe);
1907                         break;
1908                 }
1909
1910                 /* Make a position announcement, if enabled */
1911                 if (qe->parent->announcefrequency && !ringing)
1912                         res = say_position(qe);
1913                 if (res)
1914                         break;
1915
1916                 /* Make a periodic announcement, if enabled */
1917                 if (qe->parent->periodicannouncefrequency && !ringing)
1918                         res = say_periodic_announcement(qe);
1919
1920                 /* Wait a second before checking again */
1921                 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1922                 if (res)
1923                         break;
1924         }
1925         return res;
1926 }
1927
1928 static int update_queue(struct ast_call_queue *q, struct member *member)
1929 {
1930         struct member *cur;
1931
1932         /* Since a reload could have taken place, we have to traverse the list to
1933                 be sure it's still valid */
1934         ast_mutex_lock(&q->lock);
1935         cur = q->members;
1936         while(cur) {
1937                 if (member == cur) {
1938                         time(&cur->lastcall);
1939                         cur->calls++;
1940                         break;
1941                 }
1942                 cur = cur->next;
1943         }
1944         q->callscompleted++;
1945         ast_mutex_unlock(&q->lock);
1946         return 0;
1947 }
1948
1949 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1950 {
1951         if (mem->penalty > qe->max_penalty)
1952                 return -1;
1953
1954         switch (q->strategy) {
1955         case QUEUE_STRATEGY_RINGALL:
1956                 /* Everyone equal, except for penalty */
1957                 tmp->metric = mem->penalty * 1000000;
1958                 break;
1959         case QUEUE_STRATEGY_ROUNDROBIN:
1960                 if (!pos) {
1961                         if (!q->wrapped) {
1962                                 /* No more channels, start over */
1963                                 q->rrpos = 0;
1964                         } else {
1965                                 /* Prioritize next entry */
1966                                 q->rrpos++;
1967                         }
1968                         q->wrapped = 0;
1969                 }
1970                 /* Fall through */
1971         case QUEUE_STRATEGY_RRMEMORY:
1972                 if (pos < q->rrpos) {
1973                         tmp->metric = 1000 + pos;
1974                 } else {
1975                         if (pos > q->rrpos)
1976                                 /* Indicate there is another priority */
1977                                 q->wrapped = 1;
1978                         tmp->metric = pos;
1979                 }
1980                 tmp->metric += mem->penalty * 1000000;
1981                 break;
1982         case QUEUE_STRATEGY_RANDOM:
1983                 tmp->metric = rand() % 1000;
1984                 tmp->metric += mem->penalty * 1000000;
1985                 break;
1986         case QUEUE_STRATEGY_FEWESTCALLS:
1987                 tmp->metric = mem->calls;
1988                 tmp->metric += mem->penalty * 1000000;
1989                 break;
1990         case QUEUE_STRATEGY_LEASTRECENT:
1991                 if (!mem->lastcall)
1992                         tmp->metric = 0;
1993                 else
1994                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1995                 tmp->metric += mem->penalty * 1000000;
1996                 break;
1997         default:
1998                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1999                 break;
2000         }
2001         return 0;
2002 }
2003
2004 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
2005 {
2006         struct member *cur;
2007         struct localuser *outgoing=NULL, *tmp = NULL;
2008         int to;
2009         char restofit[AST_MAX_EXTENSION];
2010         char oldexten[AST_MAX_EXTENSION]="";
2011         char oldcontext[AST_MAX_CONTEXT]="";
2012         char queuename[256]="";
2013         char *newnum;
2014         struct ast_channel *peer;
2015         struct ast_channel *which;
2016         struct localuser *lpeer;
2017         struct member *member;
2018         int res = 0, bridge = 0;
2019         int numbusies = 0;
2020         int x=0;
2021         char *announce = NULL;
2022         char digit = 0;
2023         time_t callstart;
2024         time_t now = time(NULL);
2025         struct ast_bridge_config bridge_config;
2026         char nondataquality = 1;
2027
2028         memset(&bridge_config, 0, sizeof(bridge_config));
2029         time(&now);
2030                 
2031         for (; options && *options; options++)
2032                 switch (*options) {
2033                 case 't':
2034                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2035                         break;
2036                 case 'T':
2037                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2038                         break;
2039                 case 'w':
2040                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2041                         break;
2042                 case 'W':
2043                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2044                         break;
2045                 case 'd':
2046                         nondataquality = 0;
2047                         break;
2048                 case 'h':
2049                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2050                         break;
2051                 case 'H':
2052                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2053                         break;
2054                 case 'n':
2055                         if ((now - qe->start >= qe->parent->timeout))
2056                                 *go_on = 1;
2057                         break;
2058                 }
2059
2060         /* Hold the lock while we setup the outgoing calls */
2061         if (use_weight) 
2062                 ast_mutex_lock(&qlock);
2063         ast_mutex_lock(&qe->parent->lock);
2064         if (option_debug)
2065                 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
2066                                                         qe->chan->name);
2067         ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2068         cur = qe->parent->members;
2069         if (!ast_strlen_zero(qe->announce))
2070                 announce = qe->announce;
2071         if (!ast_strlen_zero(announceoverride))
2072                 announce = announceoverride;
2073
2074         while(cur) {
2075                 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
2076                         ast_mutex_unlock(&qe->parent->lock);
2077                         if (use_weight) 
2078                                 ast_mutex_unlock(&qlock);
2079                         goto out;
2080                 }
2081                 tmp->stillgoing = -1;
2082                 if (option_debug) {
2083                         if (url)
2084                                 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2085                         else 
2086                                 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
2087                 }
2088
2089                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
2090                 tmp->oldstatus = cur->status;
2091                 tmp->lastcall = cur->lastcall;
2092                 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2093                 /* If we're dialing by extension, look at the extension to know what to dial */
2094                 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
2095                         newnum++;
2096                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
2097                         snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
2098                         if (option_debug)
2099                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
2100                 }
2101                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2102                    just calculate their metric for the appropriate strategy */
2103                 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2104                         /* Put them in the list of outgoing thingies...  We're ready now. 
2105                            XXX If we're forcibly removed, these outgoing calls won't get
2106                            hung up XXX */
2107                         tmp->next = outgoing;
2108                         outgoing = tmp;         
2109                         /* If this line is up, don't try anybody else */
2110                         if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2111                                 break;
2112                 } else {
2113                         free(tmp);
2114                 }
2115
2116                 cur = cur->next;
2117         }
2118         if (qe->parent->timeout)
2119                 to = qe->parent->timeout * 1000;
2120         else
2121                 to = -1;
2122         ring_one(qe, outgoing, &numbusies);
2123         ast_mutex_unlock(&qe->parent->lock);
2124         if (use_weight) 
2125                 ast_mutex_unlock(&qlock);
2126         lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
2127         ast_mutex_lock(&qe->parent->lock);
2128         if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2129                 store_next(qe, outgoing);
2130         }
2131         ast_mutex_unlock(&qe->parent->lock);
2132         if (lpeer)
2133                 peer = lpeer->chan;
2134         else
2135                 peer = NULL;
2136         if (!peer) {
2137                 if (to) {
2138                         /* Musta gotten hung up */
2139                         record_abandoned(qe);
2140                         res = -1;
2141                 } else {
2142                         res = digit;
2143                 }
2144                 if (option_debug)
2145                         ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2146                 goto out;
2147         }
2148         if (peer) {
2149                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
2150                    we will always return with -1 so that it is hung up properly after the 
2151                    conversation.  */
2152                 qe->handled++;
2153                 if (!strcmp(qe->chan->type,"Zap"))
2154                         ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2155                 if (!strcmp(peer->type,"Zap"))
2156                         ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2157                 /* Update parameters for the queue */
2158                 recalc_holdtime(qe);
2159                 member = lpeer->member;
2160                 hangupcalls(outgoing, peer);
2161                 outgoing = NULL;
2162                 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2163                         int res2;
2164                         res2 = ast_autoservice_start(qe->chan);
2165                         if (!res2) {
2166                                 if (qe->parent->memberdelay) {
2167                                         ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2168                                         res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2169                                 }
2170                                 if (!res2 && announce) {
2171                                         if (play_file(peer, announce))
2172                                                 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2173                                 }
2174                                 if (!res2 && qe->parent->reportholdtime) {
2175                                         if (!play_file(peer, qe->parent->sound_reporthold)) {
2176                                                 int holdtime;
2177
2178                                                 time(&now);
2179                                                 holdtime = abs((now - qe->start) / 60);
2180                                                 if (holdtime < 2) {
2181                                                         play_file(peer, qe->parent->sound_lessthan);
2182                                                         ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2183                                                 } else 
2184                                                         ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2185                                                 play_file(peer, qe->parent->sound_minutes);
2186                                         }
2187                                 }
2188                         }
2189                         res2 |= ast_autoservice_stop(qe->chan);
2190                         if (peer->_softhangup) {
2191                                 /* Agent must have hung up */
2192                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
2193                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
2194                                 record_abandoned(qe);
2195                                 if (qe->parent->eventwhencalled) {
2196                                         manager_event(EVENT_FLAG_AGENT, "AgentDump",
2197                                                       "Queue: %s\r\n"
2198                                                       "Uniqueid: %s\r\n"
2199                                                       "Channel: %s\r\n"
2200                                                       "Member: %s\r\n",
2201                                                       queuename, qe->chan->uniqueid, peer->name, member->interface);
2202                                 }
2203                                 ast_hangup(peer);
2204                                 goto out;
2205                         } else if (res2) {
2206                                 /* Caller must have hung up just before being connected*/
2207                                 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2208                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2209                                 record_abandoned(qe);
2210                                 ast_hangup(peer);
2211                                 return -1;
2212                         }
2213                 }
2214                 /* Stop music on hold */
2215                 ast_moh_stop(qe->chan);
2216                 /* If appropriate, log that we have a destination channel */
2217                 if (qe->chan->cdr)
2218                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2219                 /* Make sure channels are compatible */
2220                 res = ast_channel_make_compatible(qe->chan, peer);
2221                 if (res < 0) {
2222                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2223                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2224                         record_abandoned(qe);
2225                         ast_hangup(peer);
2226                         return -1;
2227                 }
2228                 /* Begin Monitoring */
2229                 if (qe->parent->monfmt && *qe->parent->monfmt) {
2230                         const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2231                         if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2232                                 which = qe->chan;
2233                         else
2234                                 which = peer;
2235                         if (monitorfilename)
2236                                 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2237                         else if (qe->chan->cdr) 
2238                                 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2239                         else {
2240                                 /* Last ditch effort -- no CDR, make up something */
2241                                 char tmpid[256];
2242                                 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
2243                                 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2244                         }
2245                         if (qe->parent->monjoin)
2246                                 ast_monitor_setjoinfiles(which, 1);
2247                 }
2248                 /* Drop out of the queue at this point, to prepare for next caller */
2249                 leave_queue(qe);                        
2250                 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2251                         if (option_debug)
2252                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2253                         ast_channel_sendurl(peer, url);
2254                 }
2255                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
2256                 if (qe->parent->eventwhencalled)
2257                         manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2258                                       "Queue: %s\r\n"
2259                                       "Uniqueid: %s\r\n"
2260                                       "Channel: %s\r\n"
2261                                       "Member: %s\r\n"
2262                                       "Holdtime: %ld\r\n",
2263                                       queuename, qe->chan->uniqueid, peer->name, member->interface,
2264                                       (long)time(NULL) - qe->start);
2265                 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2266                 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2267                 time(&callstart);
2268
2269                 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2270
2271                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2272                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
2273                 } else if (qe->chan->_softhangup) {
2274                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2275                                       (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2276                         if (qe->parent->eventwhencalled)
2277                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2278                                               "Queue: %s\r\n"
2279                                               "Uniqueid: %s\r\n"
2280                                               "Channel: %s\r\n"
2281                                               "Member: %s\r\n"
2282                                               "HoldTime: %ld\r\n"
2283                                               "TalkTime: %ld\r\n"
2284                                               "Reason: caller\r\n",
2285                                               queuename, qe->chan->uniqueid, peer->name, member->interface,
2286                                               (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2287                 } else {
2288                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2289                         if (qe->parent->eventwhencalled)
2290                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2291                                               "Queue: %s\r\n"
2292                                               "Uniqueid: %s\r\n"
2293                                               "Channel: %s\r\n"
2294                                               "HoldTime: %ld\r\n"
2295                                               "TalkTime: %ld\r\n"
2296                                               "Reason: agent\r\n",
2297                                               queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2298                                               (long)(time(NULL) - callstart));
2299                 }
2300
2301                 if(bridge != AST_PBX_NO_HANGUP_PEER)
2302                         ast_hangup(peer);
2303                 update_queue(qe->parent, member);
2304                 if (bridge == 0) 
2305                         res = 1; /* JDG: bridge successfull, leave app_queue */
2306                 else 
2307                         res = bridge; /* bridge error, stay in the queue */
2308         }       
2309 out:
2310         hangupcalls(outgoing, NULL);
2311         return res;
2312 }
2313
2314 static int wait_a_bit(struct queue_ent *qe)
2315 {
2316         /* Don't need to hold the lock while we setup the outgoing calls */
2317         int retrywait = qe->parent->retry * 1000;
2318
2319         return ast_waitfordigit(qe->chan, retrywait);
2320 }
2321
2322 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2323 {
2324         struct member *mem;
2325
2326         if (q)
2327                 for (mem = q->members; mem; mem = mem->next)
2328                         if (!strcasecmp(interface, mem->interface))
2329                                 return mem;
2330
2331         return NULL;
2332 }
2333
2334
2335 /* Dump all members in a specific queue to the databse
2336  *
2337  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2338  *
2339  */
2340 static void dump_queue_members(struct ast_call_queue *pm_queue)
2341 {
2342         struct member *cur_member;
2343         char value[PM_MAX_LEN];
2344         int value_len = 0;
2345         int res;
2346
2347         memset(value, 0, sizeof(value));
2348
2349         if (!pm_queue)
2350                 return;
2351
2352         for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2353                 if (!cur_member->dynamic)
2354                         continue;
2355
2356                 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2357                                cur_member->interface, cur_member->penalty, cur_member->paused,
2358                                cur_member->next ? "|" : "");
2359                 if (res != strlen(value + value_len)) {
2360                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2361                         break;
2362                 }
2363                 value_len += res;
2364         }
2365         
2366         if (value_len && !cur_member) {
2367                 if (ast_db_put(pm_family, pm_queue->name, value))
2368                         ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2369         } else
2370                 /* Delete the entry if the queue is empty or there is an error */
2371                 ast_db_del(pm_family, pm_queue->name);
2372 }
2373
2374 static int remove_from_queue(char *queuename, char *interface)
2375 {
2376         struct ast_call_queue *q;
2377         struct member *last_member, *look;
2378         int res = RES_NOSUCHQUEUE;
2379
2380         ast_mutex_lock(&qlock);
2381         for (q = queues ; q ; q = q->next) {
2382                 ast_mutex_lock(&q->lock);
2383                 if (!strcmp(q->name, queuename)) {
2384                         if ((last_member = interface_exists(q, interface))) {
2385                                 if ((look = q->members) == last_member) {
2386                                         q->members = last_member->next;
2387                                 } else {
2388                                         while (look != NULL) {
2389                                                 if (look->next == last_member) {
2390                                                         look->next = last_member->next;
2391                                                         break;
2392                                                 } else {
2393                                                          look = look->next;
2394                                                 }
2395                                         }
2396                                 }
2397                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2398                                                 "Queue: %s\r\n"
2399                                                 "Location: %s\r\n",
2400                                         q->name, last_member->interface);
2401                                 free(last_member);
2402
2403                                 if (queue_persistent_members)
2404                                     dump_queue_members(q);
2405
2406                                 res = RES_OKAY;
2407                         } else {
2408                                 res = RES_EXISTS;
2409                         }
2410                         ast_mutex_unlock(&q->lock);
2411                         break;
2412                 }
2413                 ast_mutex_unlock(&q->lock);
2414         }
2415         ast_mutex_unlock(&qlock);
2416         return res;
2417 }
2418
2419 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2420 {
2421         struct ast_call_queue *q;
2422         struct member *new_member;
2423         int res = RES_NOSUCHQUEUE;
2424
2425         ast_mutex_lock(&qlock);
2426         for (q = queues ; q ; q = q->next) {
2427                 ast_mutex_lock(&q->lock);
2428                 if (!strcmp(q->name, queuename)) {
2429                         if (interface_exists(q, interface) == NULL) {
2430                                 new_member = create_queue_member(interface, penalty, paused);
2431
2432                                 if (new_member != NULL) {
2433                                         new_member->dynamic = 1;
2434                                         new_member->next = q->members;
2435                                         q->members = new_member;
2436                                         manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2437                                                 "Queue: %s\r\n"
2438                                                 "Location: %s\r\n"
2439                                                 "Membership: %s\r\n"
2440                                                 "Penalty: %d\r\n"
2441                                                 "CallsTaken: %d\r\n"
2442                                                 "LastCall: %d\r\n"
2443                                                 "Status: %d\r\n"
2444                                                 "Paused: %d\r\n",
2445                                         q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2446                                         new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
2447                                         
2448                                         if (dump)
2449                                                 dump_queue_members(q);
2450
2451                                         res = RES_OKAY;
2452                                 } else {
2453                                         res = RES_OUTOFMEMORY;
2454                                 }
2455                         } else {
2456                                 res = RES_EXISTS;
2457                         }
2458                         ast_mutex_unlock(&q->lock);
2459                         break;
2460                 }
2461                 ast_mutex_unlock(&q->lock);
2462         }
2463         ast_mutex_unlock(&qlock);
2464         return res;
2465 }
2466
2467 static int set_member_paused(char *queuename, char *interface, int paused)
2468 {
2469         int found = 0;
2470         struct ast_call_queue *q;
2471         struct member *mem;
2472
2473         /* Special event for when all queues are paused - individual events still generated */
2474
2475         if (ast_strlen_zero(queuename))
2476                 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2477
2478         ast_mutex_lock(&qlock);
2479         for (q = queues ; q ; q = q->next) {
2480                 ast_mutex_lock(&q->lock);
2481                 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
2482                         if ((mem = interface_exists(q, interface))) {
2483                                 found++;
2484                                 if (mem->paused == paused)
2485                                         ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2486                                 mem->paused = paused;
2487
2488                                 if (queue_persistent_members)
2489                                     dump_queue_members(q);
2490
2491                                 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2492
2493                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2494                                         "Queue: %s\r\n"
2495                                         "Location: %s\r\n"
2496                                         "Paused: %d\r\n",
2497                                                 q->name, mem->interface, paused);
2498                         }
2499                 }
2500                 ast_mutex_unlock(&q->lock);
2501         }
2502         ast_mutex_unlock(&qlock);
2503
2504         if (found)
2505                 return RESULT_SUCCESS;
2506         else
2507                 return RESULT_FAILURE;
2508 }
2509
2510 /* Reload dynamic queue members persisted into the astdb */
2511 static void reload_queue_members(void)
2512 {
2513         char *cur_ptr;  
2514         char *queue_name;
2515         char *member;
2516         char *interface;
2517         char *penalty_tok;
2518         int penalty = 0;
2519         char *paused_tok;
2520         int paused = 0;
2521         struct ast_db_entry *db_tree;
2522         struct ast_db_entry *entry;
2523         struct ast_call_queue *cur_queue;
2524         char queue_data[PM_MAX_LEN];
2525
2526         ast_mutex_lock(&qlock);
2527
2528         /* Each key in 'pm_family' is the name of a queue */
2529         db_tree = ast_db_gettree(pm_family, NULL);
2530         for (entry = db_tree; entry; entry = entry->next) {
2531
2532                 queue_name = entry->key + strlen(pm_family) + 2;
2533
2534                 cur_queue = queues;
2535                 while (cur_queue) {
2536                         ast_mutex_lock(&cur_queue->lock);
2537                         if (!strcmp(queue_name, cur_queue->name))
2538                                 break;
2539                         ast_mutex_unlock(&cur_queue->lock);
2540                         cur_queue = cur_queue->next;
2541                 }
2542
2543                 if (!cur_queue) {
2544                         /* If the queue no longer exists, remove it from the
2545                          * database */
2546                         ast_db_del(pm_family, queue_name);
2547                         continue;
2548                 } else
2549                         ast_mutex_unlock(&cur_queue->lock);
2550
2551                 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2552                         continue;
2553
2554                 cur_ptr = queue_data;
2555                 while ((member = strsep(&cur_ptr, "|"))) {
2556                         if (ast_strlen_zero(member))
2557                                 continue;
2558
2559                         interface = strsep(&member, ";");
2560                         penalty_tok = strsep(&member, ";");
2561                         paused_tok = strsep(&member, ";");
2562
2563                         if (!penalty_tok) {
2564                                 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
2565                                 break;
2566                         }
2567                         penalty = strtol(penalty_tok, NULL, 10);
2568                         if (errno == ERANGE) {
2569                                 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2570                                 break;
2571                         }
2572                         
2573                         if (!paused_tok) {
2574                                 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2575                                 break;
2576                         }
2577                         paused = strtol(paused_tok, NULL, 10);
2578                         if ((errno == ERANGE) || paused < 0 || paused > 1) {
2579                                 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2580                                 break;
2581                         }
2582
2583                         if (option_debug)
2584                                 ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
2585                         
2586                         if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2587                                 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2588                                 break;
2589                         }
2590                 }
2591         }
2592
2593         ast_mutex_unlock(&qlock);
2594         if (db_tree) {
2595                 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2596                 ast_db_freetree(db_tree);
2597         }
2598 }
2599
2600 static int pqm_exec(struct ast_channel *chan, void *data)
2601 {
2602         struct localuser *u;
2603         char *parse;
2604         int priority_jump = 0;
2605         AST_DECLARE_APP_ARGS(args,
2606                 AST_APP_ARG(queuename);
2607                 AST_APP_ARG(interface);
2608                 AST_APP_ARG(options);
2609         );
2610
2611         if (ast_strlen_zero(data)) {
2612                 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2613                 return -1;
2614         }
2615
2616         LOCAL_USER_ADD(u);
2617
2618         if (!(parse = ast_strdupa(data))) {
2619                 ast_log(LOG_WARNING, "Memory Error!\n");
2620                 LOCAL_USER_REMOVE(u);
2621                 return -1;
2622         }
2623
2624         AST_STANDARD_APP_ARGS(args, parse);
2625
2626         if (args.options) {
2627                 if (strchr(args.options, 'j'))
2628                         priority_jump = 1;
2629         }
2630
2631         if (ast_strlen_zero(args.interface)) {
2632                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2633                 LOCAL_USER_REMOVE(u);
2634                 return -1;
2635         }
2636
2637         if (set_member_paused(args.queuename, args.interface, 1)) {
2638                 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
2639                 if (priority_jump || ast_opt_priority_jumping) {
2640                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2641                                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2642                                 LOCAL_USER_REMOVE(u);
2643                                 return 0;
2644                         }
2645                 }
2646                 LOCAL_USER_REMOVE(u);
2647                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2648                 return -1;
2649         }
2650
2651         LOCAL_USER_REMOVE(u);
2652         pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2653         return 0;
2654 }
2655
2656 static int upqm_exec(struct ast_channel *chan, void *data)
2657 {
2658         struct localuser *u;
2659         char *parse;
2660         int priority_jump = 0;
2661         AST_DECLARE_APP_ARGS(args,
2662                 AST_APP_ARG(queuename);
2663                 AST_APP_ARG(interface);
2664                 AST_APP_ARG(options);
2665         );
2666
2667         if (ast_strlen_zero(data)) {
2668                 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2669                 return -1;
2670         }
2671
2672         LOCAL_USER_ADD(u);
2673
2674         if (!(parse = ast_strdupa(data))) {
2675                 ast_log(LOG_WARNING, "Memory Error!\n");
2676                 LOCAL_USER_REMOVE(u);
2677                 return -1;
2678         }
2679
2680         AST_STANDARD_APP_ARGS(args, parse);
2681
2682         if (args.options) {
2683                 if (strchr(args.options, 'j'))
2684                         priority_jump = 1;
2685         }
2686
2687         if (ast_strlen_zero(args.interface)) {
2688                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2689                 LOCAL_USER_REMOVE(u);
2690                 return -1;
2691         }
2692
2693         if (set_member_paused(args.queuename, args.interface, 0)) {
2694                 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
2695                 if (priority_jump || ast_opt_priority_jumping) {
2696                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2697                                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2698                                 LOCAL_USER_REMOVE(u);
2699                                 return 0;
2700                         }
2701                 }
2702                 LOCAL_USER_REMOVE(u);
2703                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2704                 return -1;
2705         }
2706
2707         LOCAL_USER_REMOVE(u);
2708         pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2709         return 0;
2710 }
2711
2712 static int rqm_exec(struct ast_channel *chan, void *data)
2713 {
2714         int res=-1;
2715         struct localuser *u;
2716         char *parse, *temppos = NULL;
2717         int priority_jump = 0;
2718         AST_DECLARE_APP_ARGS(args,
2719                 AST_APP_ARG(queuename);
2720                 AST_APP_ARG(interface);
2721                 AST_APP_ARG(options);
2722         );
2723
2724
2725         if (ast_strlen_zero(data)) {
2726                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2727                 return -1;
2728         }
2729
2730         LOCAL_USER_ADD(u);
2731
2732         if (!(parse = ast_strdupa(data))) {
2733                 ast_log(LOG_WARNING, "Memory Error!\n");
2734                 LOCAL_USER_REMOVE(u);
2735                 return -1;
2736         }
2737
2738         AST_STANDARD_APP_ARGS(args, parse);
2739
2740         if (ast_strlen_zero(args.interface)) {
2741                 args.interface = ast_strdupa(chan->name);
2742                 temppos = strrchr(args.interface, '-');
2743                 if (temppos)
2744                         *temppos = '\0';
2745         }
2746
2747         if (args.options) {
2748                 if (strchr(args.options, 'j'))
2749                         priority_jump = 1;
2750         }
2751
2752         switch (remove_from_queue(args.queuename, args.interface)) {
2753         case RES_OKAY:
2754                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2755                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
2756                 res = 0;
2757                 break;
2758         case RES_EXISTS:
2759                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
2760                 if (priority_jump || ast_opt_priority_jumping) 
2761                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2762                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
2763                 res = 0;
2764                 break;
2765         case RES_NOSUCHQUEUE:
2766                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
2767                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
2768                 res = 0;
2769                 break;
2770         case RES_OUTOFMEMORY:
2771                 ast_log(LOG_ERROR, "Out of memory\n");
2772                 break;
2773         }
2774
2775         LOCAL_USER_REMOVE(u);
2776         return res;
2777 }
2778
2779 static int aqm_exec(struct ast_channel *chan, void *data)
2780 {
2781         int res=-1;
2782         struct localuser *u;
2783         char *parse, *temppos = NULL;
2784         int priority_jump = 0;
2785         AST_DECLARE_APP_ARGS(args,
2786                 AST_APP_ARG(queuename);
2787                 AST_APP_ARG(interface);
2788                 AST_APP_ARG(penalty);
2789                 AST_APP_ARG(options);
2790         );
2791         int penalty = 0;
2792
2793         if (ast_strlen_zero(data)) {
2794                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2795                 return -1;
2796         }
2797
2798         LOCAL_USER_ADD(u);
2799
2800         if (!(parse = ast_strdupa(data))) {
2801                 ast_log(LOG_WARNING, "Memory Error!\n");
2802                 LOCAL_USER_REMOVE(u);
2803                 return -1;
2804         }
2805
2806         AST_STANDARD_APP_ARGS(args, parse);
2807
2808         if (ast_strlen_zero(args.interface)) {
2809                 args.interface = ast_strdupa(chan->name);
2810                 temppos = strrchr(args.interface, '-');
2811                 if (temppos)
2812                         *temppos = '\0';
2813         }
2814
2815         if (!ast_strlen_zero(args.penalty)) {
2816                 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
2817                         ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
2818                         penalty = 0;
2819                 }
2820         }
2821         
2822         if (args.options) {
2823                 if (strchr(args.options, 'j'))
2824                         priority_jump = 1;
2825         }
2826
2827
2828         switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2829         case RES_OKAY:
2830                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2831                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
2832                 res = 0;
2833                 break;
2834         case RES_EXISTS:
2835                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
2836                 if (priority_jump || ast_opt_priority_jumping) 
2837                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2838                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
2839                 res = 0;
2840                 break;
2841         case RES_NOSUCHQUEUE:
2842                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
2843                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
2844                 res = 0;
2845                 break;
2846         case RES_OUTOFMEMORY:
2847                 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2848                 break;
2849         }
2850
2851         LOCAL_USER_REMOVE(u);
2852         return res;
2853 }
2854
2855 static int queue_exec(struct ast_channel *chan, void *data)
2856 {
2857         int res=-1;
2858         int ringing=0;
2859         struct localuser *u;
2860         char *queuename;
2861         char info[512];
2862         char *info_ptr = info;
2863         char *options = NULL;
2864         char *url = NULL;
2865         char *announceoverride = NULL;
2866         const char *user_priority;
2867         const char *max_penalty_str;
2868         int prio;
2869         int max_penalty;
2870         char *queuetimeoutstr = NULL;
2871         enum queue_result reason = QUEUE_UNKNOWN;
2872
2873         /* whether to exit Queue application after the timeout hits */
2874         int go_on = 0;
2875
2876         /* Our queue entry */
2877         struct queue_ent qe;
2878         
2879         if (ast_strlen_zero(data)) {
2880                 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2881                 return -1;
2882         }
2883
2884         LOCAL_USER_ADD(u);
2885
2886         /* Setup our queue entry */
2887         memset(&qe, 0, sizeof(qe));
2888         qe.start = time(NULL);
2889         
2890         /* Parse our arguments XXX Check for failure XXX */
2891         ast_copy_string(info, (char *) data, sizeof(info));
2892         queuename = strsep(&info_ptr, "|");
2893         options = strsep(&info_ptr, "|");
2894         url = strsep(&info_ptr, "|");
2895         announceoverride = strsep(&info_ptr, "|");
2896         queuetimeoutstr = info_ptr;
2897
2898         /* set the expire time based on the supplied timeout; */
2899         if (queuetimeoutstr)
2900                 qe.expire = qe.start + atoi(queuetimeoutstr);
2901         else
2902                 qe.expire = 0;
2903
2904         /* Get the priority from the variable ${QUEUE_PRIO} */
2905         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2906         if (user_priority) {
2907                 if (sscanf(user_priority, "%d", &prio) == 1) {
2908                         if (option_debug)
2909                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2910                                         chan->name, prio);
2911                 } else {
2912                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2913                                 user_priority, chan->name);
2914                         prio = 0;
2915                 }
2916         } else {
2917                 if (option_debug > 2)
2918                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2919                 prio = 0;
2920         }
2921
2922         /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
2923         if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
2924                 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
2925                         if (option_debug)
2926                                 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
2927                                         chan->name, max_penalty);
2928                 } else {
2929                         ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
2930                                 max_penalty_str, chan->name);
2931                         max_penalty = 0;
2932                 }
2933         } else {
2934                 max_penalty = 0;
2935         }
2936
2937         if (options && (strchr(options, 'r')))
2938                 ringing = 1;
2939
2940         if (option_debug)  
2941                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2942                         queuename, options, url, announceoverride, (long)qe.expire, prio);
2943
2944         qe.chan = chan;
2945         qe.prio = prio;
2946         qe.max_penalty = max_penalty;
2947         qe.last_pos_said = 0;
2948         qe.last_pos = 0;
2949         qe.last_periodic_announce_time = time(NULL);
2950         if (!join_queue(queuename, &qe, &reason)) {
2951                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
2952                               chan->cid.cid_num ? chan->cid.cid_num : "");
2953 check_turns:
2954                 if (ringing) {
2955                         ast_indicate(chan, AST_CONTROL_RINGING);
2956                 } else {              
2957                         ast_moh_start(chan, qe.moh);
2958                 }
2959                 for (;;) {
2960                         /* This is the wait loop for callers 2 through maxlen */
2961
2962                         res = wait_our_turn(&qe, ringing, &reason);
2963                         /* If they hungup, return immediately */
2964                         if (res < 0) {
2965                                 /* Record this abandoned call */
2966                                 record_abandoned(&qe);
2967                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2968                                 if (option_verbose > 2) {
2969                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2970                                         res = -1;
2971                                 }
2972                                 break;
2973                         }
2974                         if (!res) 
2975                                 break;
2976                         if (valid_exit(&qe, res)) {
2977                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
2978                                 break;
2979                         }
2980                 }
2981                 if (!res) {
2982                         int makeannouncement = 0;
2983                         for (;;) {
2984                                 /* This is the wait loop for the head caller*/
2985                                 /* To exit, they may get their call answered; */
2986                                 /* they may dial a digit from the queue context; */
2987                                 /* or, they may timeout. */
2988
2989                                 enum queue_member_status stat;
2990
2991                                 /* Leave if we have exceeded our queuetimeout */
2992                                 if (qe.expire && (time(NULL) > qe.expire)) {
2993                                         record_abandoned(&qe);
2994                                         reason = QUEUE_TIMEOUT;
2995                                         res = 0;
2996                                         ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2997                                         break;
2998                                 }
2999
3000                                 if (makeannouncement) {
3001                                         /* Make a position announcement, if enabled */
3002                                         if (qe.parent->announcefrequency && !ringing)
3003                                                 res = say_position(&qe);
3004                                         if (res && valid_exit(&qe, res)) {
3005                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3006                                                 break;
3007                                         }
3008
3009                                 }
3010                                 makeannouncement = 1;
3011
3012                                 /* Make a periodic announcement, if enabled */
3013                                 if (qe.parent->periodicannouncefrequency && !ringing)
3014                                         res = say_periodic_announcement(&qe);
3015
3016                                 if (res && valid_exit(&qe, res)) {
3017                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
3018                                         break;
3019                                 }
3020
3021                                 /* Try calling all queue members for 'timeout' seconds */
3022                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
3023                                 if (res) {
3024                                         if (res < 0) {
3025                                                 if (!qe.handled) {
3026                                                         record_abandoned(&qe);
3027                                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3028                                                 }
3029                                         } else if (res > 0)
3030                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3031                                         break;
3032                                 }
3033
3034                                 stat = get_member_status(qe.parent, qe.max_penalty);
3035
3036                                 /* leave the queue if no agents, if enabled */
3037                                 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
3038                                         record_abandoned(&qe);
3039                                         reason = QUEUE_LEAVEEMPTY;
3040                                         res = 0;
3041                                         break;
3042                                 }
3043
3044                                 /* leave the queue if no reachable agents, if enabled */
3045                                 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
3046                                         record_abandoned(&qe);
3047                                         reason = QUEUE_LEAVEUNAVAIL;
3048                                         res = 0;
3049                                         break;
3050                                 }
3051
3052                                 /* Leave if we have exceeded our queuetimeout */
3053                                 if (qe.expire && (time(NULL) > qe.expire)) {
3054                                         record_abandoned(&qe);
3055                                         reason = QUEUE_TIMEOUT;
3056                                         res = 0;
3057                                         ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);       
3058                                         break;
3059                                 }
3060
3061                                 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3062                                 res = wait_a_bit(&qe);
3063                                 if (res < 0) {
3064                                         record_abandoned(&qe);
3065                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3066                                         if (option_verbose > 2) {
3067                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
3068                                                 res = -1;
3069                                         }
3070                                         break;
3071                                 }
3072                                 if (res && valid_exit(&qe, res)) {
3073                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3074                                         break;
3075                                 }
3076                                 /* exit after 'timeout' cycle if 'n' option enabled */
3077                                 if (go_on) {
3078                                         if (option_verbose > 2) {
3079                                                 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
3080                                                 res = -1;
3081                                         }
3082                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3083                                         record_abandoned(&qe);
3084                                         reason = QUEUE_TIMEOUT;
3085                                         res = 0;
3086                                         break;
3087                                 }
3088                                 /* Since this is a priority queue and 
3089                                  * it is not sure that we are still at the head
3090                                  * of the queue, go and check for our turn again.
3091                                  */
3092                                 if (!is_our_turn(&qe)) {
3093                                         if (option_debug)
3094                                                 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
3095                                                                 qe.chan->name);
3096                                         goto check_turns;
3097                                 }
3098                         }
3099                 }
3100                 /* Don't allow return code > 0 */
3101                 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
3102                         res = 0;        
3103                         if (ringing) {
3104                                 ast_indicate(chan, -1);
3105                         } else {
3106                                 ast_moh_stop(chan);
3107                         }                       
3108                         ast_stopstream(chan);
3109                 }
3110                 leave_queue(&qe);
3111                 if (reason != QUEUE_UNKNOWN)
3112                         set_queue_result(chan, reason);
3113         } else {
3114                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
3115                 set_queue_result(chan, reason);
3116                 res = 0;
3117         }
3118         LOCAL_USER_REMOVE(u);
3119         return res;
3120 }
3121
3122 static char *queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3123 {
3124         int count = 0;
3125         struct ast_call_queue *q;
3126         struct localuser *u;
3127         struct member *m;
3128
3129         LOCAL_USER_ACF_ADD(u);
3130
3131         ast_copy_string(buf, "0", len);
3132         
3133         if (ast_strlen_zero(data)) {
3134                 ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n");
3135                 LOCAL_USER_REMOVE(u);
3136                 return buf;
3137         }
3138
3139         ast_mutex_lock(&qlock);
3140
3141         /* Find the right queue */
3142         for (q = queues; q; q = q->next) {
3143                 if (!strcasecmp(q->name, data)) {
3144                         ast_mutex_lock(&q->lock);
3145                         break;
3146                 }
3147         }
3148
3149         ast_mutex_unlock(&qlock);
3150
3151         if (q) {
3152                 for (m = q->members; m; m = m->next) {
3153                         /* Count the agents who are logged in and presently answering calls */
3154                         if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
3155                                 count++;
3156                         }
3157                 }
3158                 ast_mutex_unlock(&q->lock);
3159         }
3160
3161         snprintf(buf, len, "%d", count);
3162         LOCAL_USER_REMOVE(u);
3163         return buf;
3164 }
3165
3166 static struct ast_custom_function queueagentcount_function = {
3167         .name = "QUEUEAGENTCOUNT",
3168         .synopsis = "Count number of agents answering a queue",
3169         .syntax = "QUEUEAGENTCOUNT(<queuename>)",
3170         .read = queue_function_qac,
3171 };
3172
3173 static void reload_queues(void)
3174 {
3175         struct ast_call_queue *q, *ql, *qn;
3176         struct ast_config *cfg;
3177         char *cat, *tmp;
3178         struct ast_variable *var;
3179         struct member *prev, *cur;
3180         int new;
3181         char *general_val = NULL;
3182         char interface[80];
3183         int penalty;
3184         
3185         cfg = ast_config_load("queues.conf");
3186         if (!cfg) {
3187                 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
3188                 return;
3189         }
3190         memset(interface, 0, sizeof(interface));
3191         ast_mutex_lock(&qlock);
3192         use_weight=0;
3193         /* Mark all queues as dead for the moment */
3194         q = queues;
3195         while(q) {
3196                 q->dead = 1;
3197                 q = q->next;
3198         }
3199         /* Chug through config file */
3200         cat = ast_category_browse(cfg, NULL);
3201         while(cat) {
3202                 if (!strcasecmp(cat, "general")) {      
3203                         /* Initialize global settings */
3204                         queue_persistent_members = 0;
3205                         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
3206                                 queue_persistent_members = ast_true(general_val);
3207                 } else {        /* Define queue */
3208                         /* Look for an existing one */
3209                         q = queues;
3210                         while(q) {
3211                                 if (!strcmp(q->name, cat))
3212                                         break;
3213                                 q = q->next;
3214                         }
3215                         if (!q) {
3216                                 /* Make one then */
3217                                 if (!(q = alloc_queue(cat))) {
3218                                         /* TODO: Handle memory allocation failure */
3219                                 }
3220                                 new = 1;
3221                         } else
3222                                 new = 0;
3223                         if (q) {
3224                                 if (!new)
3225                                         ast_mutex_lock(&q->lock);
3226                                 /* Re-initialize the queue, and clear statistics */
3227                                 init_queue(q);
3228                                 clear_queue(q);
3229                                 free_members(q, 0);
3230                                 prev = q->members;
3231                                 if (prev) {
3232                                         /* find the end of any dynamic members */
3233                                         while(prev->next)
3234                                                 prev = prev->next;
3235                                 }
3236                                 var = ast_variable_browse(cfg, cat);
3237                                 while(var) {
3238                                         if (!strcasecmp(var->name, "member")) {
3239                                                 /* Add a new member */
3240                                                 ast_copy_string(interface, var->value, sizeof(interface));
3241                                                 if ((tmp = strchr(interface, ','))) {
3242                                                         *tmp = '\0';
3243                                                         tmp++;
3244                                                         penalty = atoi(tmp);
3245                                                         if (penalty < 0) {
3246                                                                 penalty = 0;
3247                                                         }
3248                                                 } else
3249                                                         penalty = 0;
3250                                                 cur = create_queue_member(interface, penalty, 0);
3251                                                 if (cur) {
3252                                                         if (prev)
3253                                                                 prev->next = cur;
3254                                                         else
3255                                                                 q->members = cur;
3256                                                         prev = cur;
3257                                                 }
3258                                         } else {
3259                                                 queue_set_param(q, var->name, var->value, var->lineno, 1);
3260                                         }
3261                                         var = var->next;
3262                                 }
3263                                 if (!new) 
3264                                         ast_mutex_unlock(&q->lock);
3265                                 if (new) {
3266                                         q->next = queues;
3267                                         queues = q;
3268                                 }
3269                         }