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