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