cae7e5ef636bc98b0ee41ce48adf73062b135143
[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 #include "asterisk/devicestate.h"
75
76 #define QUEUE_STRATEGY_RINGALL          0
77 #define QUEUE_STRATEGY_ROUNDROBIN       1
78 #define QUEUE_STRATEGY_LEASTRECENT      2
79 #define QUEUE_STRATEGY_FEWESTCALLS      3
80 #define QUEUE_STRATEGY_RANDOM           4
81 #define QUEUE_STRATEGY_RRMEMORY         5
82
83 static struct strategy {
84         int strategy;
85         char *name;
86 } strategies[] = {
87         { QUEUE_STRATEGY_RINGALL, "ringall" },
88         { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
89         { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
90         { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
91         { QUEUE_STRATEGY_RANDOM, "random" },
92         { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
93 };
94
95 #define DEFAULT_RETRY           5
96 #define DEFAULT_TIMEOUT         15
97 #define RECHECK                 1               /* Recheck every second to see we we're at the top yet */
98
99 #define RES_OKAY        0               /* Action completed */
100 #define RES_EXISTS      (-1)            /* Entry already exists */
101 #define RES_OUTOFMEMORY (-2)            /* Out of memory */
102 #define RES_NOSUCHQUEUE (-3)            /* No such queue */
103
104 static char *tdesc = "True Call Queueing";
105
106 static char *app = "Queue";
107
108 static char *synopsis = "Queue a call for a call queue";
109
110 static char *descrip =
111 "  Queue(queuename[|options[|URL][|announceoverride][|timeout]]):\n"
112 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
113 "  This application returns -1 if the originating channel hangs up, or if the\n"
114 "call is bridged and  either of the parties in the bridge terminate the call.\n"
115 "Returns 0 if the queue is full, nonexistent, or has no members.\n"
116 "The option string may contain zero or more of the following characters:\n"
117 "      't' -- allow the called user transfer the calling user\n"
118 "      'T' -- to allow the calling user to transfer the call.\n"
119 "      'd' -- data-quality (modem) call (minimum delay).\n"
120 "      'h' -- allow callee to hang up by hitting *.\n"
121 "      'H' -- allow caller to hang up by hitting *.\n"
122 "      'n' -- no retries on the timeout; will exit this application and \n"
123 "             go to the next step.\n"
124 "      'r' -- ring instead of playing MOH\n"
125 "  In addition to transferring the call, a call may be parked and then picked\n"
126 "up by another user.\n"
127 "  The optional URL will be sent to the called party if the channel supports\n"
128 "it.\n"
129 "  The timeout will cause the queue to fail out after a specified number of\n"
130 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
131 "  This application sets the following channel variable upon completion:\n"
132 "      QUEUESTATUS    The status of the call as a text string, one of\n"
133 "             TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
134
135 static char *app_aqm = "AddQueueMember" ;
136 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
137 static char *app_aqm_descrip =
138 "   AddQueueMember(queuename[|interface[|penalty]]):\n"
139 "Dynamically adds interface to an existing queue.\n"
140 "If the interface is already in the queue and there exists an n+101 priority\n"
141 "then it will then jump to this priority.  Otherwise it will return an error\n"
142 "Returns -1 if there is an error.\n"
143 "Example: AddQueueMember(techsupport|SIP/3000)\n"
144 "";
145
146 static char *app_rqm = "RemoveQueueMember" ;
147 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
148 static char *app_rqm_descrip =
149 "   RemoveQueueMember(queuename[|interface]):\n"
150 "Dynamically removes interface to an existing queue\n"
151 "If the interface is NOT in the queue and there exists an n+101 priority\n"
152 "then it will then jump to this priority.  Otherwise it will return an error\n"
153 "Returns -1 if there is an error.\n"
154 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
155 "";
156
157 static char *app_pqm = "PauseQueueMember" ;
158 static char *app_pqm_synopsis = "Pauses a queue member" ;
159 static char *app_pqm_descrip =
160 "   PauseQueueMember([queuename]|interface):\n"
161 "Pauses (blocks calls for) a queue member.\n"
162 "The given interface will be paused in the given queue.  This prevents\n"
163 "any calls from being sent from the queue to the interface until it is\n"
164 "unpaused with UnpauseQueueMember or the manager interface.  If no\n"
165 "queuename is given, the interface is paused in every queue it is a\n"
166 "member of.  If the interface is not in the named queue, or if no queue\n"
167 "is given and the interface is not in any queue, it will jump to\n"
168 " priority n+101, if it exists.  Returns -1 if the interface is not\n"
169 "found and no extension to jump to exists, 0 otherwise.\n"
170 "Example: PauseQueueMember(|SIP/3000)\n";
171
172 static char *app_upqm = "UnpauseQueueMember" ;
173 static char *app_upqm_synopsis = "Unpauses a queue member" ;
174 static char *app_upqm_descrip =
175 "   UnpauseQueueMember([queuename]|interface):\n"
176 "Unpauses (resumes calls to) a queue member.\n"
177 "This is the counterpart to PauseQueueMember and operates exactly the\n"
178 "same way, except it unpauses instead of pausing the given interface.\n"
179 "Example: UnpauseQueueMember(|SIP/3000)\n";
180
181 /* Persistent Members astdb family */
182 static const char *pm_family = "/Queue/PersistentMembers";
183 /* The maximum lengh of each persistent member queue database entry */
184 #define PM_MAX_LEN 2048
185
186 /* queues.conf [general] option */
187 static int queue_persistent_members = 0;
188
189 /* queues.conf per-queue weight option */
190 static int use_weight = 0;
191
192 enum queue_result {
193         QUEUE_UNKNOWN = 0,
194         QUEUE_TIMEOUT = 1,
195         QUEUE_JOINEMPTY = 2,
196         QUEUE_LEAVEEMPTY = 3,
197         QUEUE_JOINUNAVAIL = 4,
198         QUEUE_LEAVEUNAVAIL = 5,
199         QUEUE_FULL = 6,
200 };
201
202 const struct { 
203         enum queue_result id;
204         char *text;
205 } queue_results[] = {
206         { QUEUE_UNKNOWN, "UNKNOWN" },
207         { QUEUE_TIMEOUT, "TIMEOUT" },
208         { QUEUE_JOINEMPTY,"JOINEMPTY" },
209         { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
210         { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
211         { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
212         { QUEUE_FULL, "FULL" },
213 };
214
215 /* We define a custom "local user" structure because we
216    use it not only for keeping track of what is in use but
217    also for keeping track of who we're dialing. */
218
219 struct localuser {
220         struct ast_channel *chan;
221         char interface[256];
222         int stillgoing;
223         int metric;
224         int oldstatus;
225         time_t lastcall;
226         struct member *member;
227         struct localuser *next;
228 };
229
230 LOCAL_USER_DECL;
231
232 struct queue_ent {
233         struct ast_call_queue *parent;  /* What queue is our parent */
234         char moh[80];                   /* Name of musiconhold to be used */
235         char announce[80];              /* Announcement to play for member when call is answered */
236         char context[80];               /* Context when user exits queue */
237         int pos;                        /* Where we are in the queue */
238         int prio;                       /* Our priority */
239         int last_pos_said;              /* Last position we told the user */
240         time_t last_pos;                /* Last time we told the user their position */
241         int opos;                       /* Where we started in the queue */
242         int handled;                    /* Whether our call was handled */
243         time_t start;                   /* When we started holding */
244         time_t expire;                  /* When this entry should expire (time out of queue) */
245         struct ast_channel *chan;       /* Our channel */
246         struct queue_ent *next;         /* The next queue entry */
247 };
248
249 struct member {
250         char interface[80];             /* Technology/Location */
251         int penalty;                    /* Are we a last resort? */
252         int calls;                      /* Number of calls serviced by this member */
253         int dynamic;                    /* Are we dynamically added? */
254         int status;                     /* Status of queue member */
255         int paused;                     /* Are we paused (not accepting calls)? */
256         time_t lastcall;                /* When last successful call was hungup */
257         int dead;                       /* Used to detect members deleted in realtime */
258         struct member *next;            /* Next member */
259 };
260
261 /* values used in multi-bit flags in ast_call_queue */
262 #define QUEUE_EMPTY_NORMAL 1
263 #define QUEUE_EMPTY_STRICT 2
264 #define ANNOUNCEHOLDTIME_ALWAYS 1
265 #define ANNOUNCEHOLDTIME_ONCE 2
266
267 struct ast_call_queue {
268         ast_mutex_t lock;       
269         char name[80];                  /* Name */
270         char moh[80];                   /* Music On Hold class to be used */
271         char announce[80];              /* Announcement to play when call is answered */
272         char context[80];               /* Exit context */
273                 unsigned int monjoin:1;
274                 unsigned int dead:1;
275                 unsigned int joinempty:2;
276                 unsigned int eventwhencalled:1;
277                 unsigned int leavewhenempty:2;
278                 unsigned int reportholdtime:1;
279                 unsigned int wrapped:1;
280                 unsigned int timeoutrestart:1;
281                 unsigned int announceholdtime:2;
282                 unsigned int strategy:3;
283                 unsigned int maskmemberstatus:1;
284                 unsigned int realtime:1;
285         int announcefrequency;          /* How often to announce their position */
286         int roundingseconds;            /* How many seconds do we round to? */
287         int holdtime;                   /* Current avg holdtime, based on recursive boxcar filter */
288         int callscompleted;             /* Number of queue calls completed */
289         int callsabandoned;             /* Number of queue calls abandoned */
290         int servicelevel;               /* seconds setting for servicelevel*/
291         int callscompletedinsl;         /* Number of calls answered with servicelevel*/
292         char monfmt[8];                 /* Format to use when recording calls */
293         char sound_next[80];            /* Sound file: "Your call is now first in line" (def. queue-youarenext) */
294         char sound_thereare[80];        /* Sound file: "There are currently" (def. queue-thereare) */
295         char sound_calls[80];           /* Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
296         char sound_holdtime[80];        /* Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
297         char sound_minutes[80];         /* Sound file: "minutes." (def. queue-minutes) */
298         char sound_lessthan[80];        /* Sound file: "less-than" (def. queue-lessthan) */
299         char sound_seconds[80];         /* Sound file: "seconds." (def. queue-seconds) */
300         char sound_thanks[80];          /* Sound file: "Thank you for your patience." (def. queue-thankyou) */
301         char sound_reporthold[80];      /* Sound file: "Hold time" (def. queue-reporthold) */
302
303         int count;                      /* How many entries */
304         int maxlen;                     /* Max number of entries */
305         int wrapuptime;                 /* Wrapup Time */
306
307         int retry;                      /* Retry calling everyone after this amount of time */
308         int timeout;                    /* How long to wait for an answer */
309         int weight;                     /* Respective weight */
310         
311         /* Queue strategy things */
312         int rrpos;                      /* Round Robin - position */
313         int memberdelay;                /* Seconds to delay connecting member to caller */
314
315         struct member *members;         /* Head of the list of members */
316         struct queue_ent *head;         /* Head of the list of callers */
317         struct ast_call_queue *next;    /* Next call queue */
318 };
319
320 static struct ast_call_queue *queues = NULL;
321 AST_MUTEX_DEFINE_STATIC(qlock);
322
323 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
324 {
325         int i;
326
327         for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
328                 if (queue_results[i].id == res) {
329                         pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
330                         return;
331                 }
332         }
333 }
334
335 static char *int2strat(int strategy)
336 {
337         int x;
338         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
339                 if (strategy == strategies[x].strategy)
340                         return strategies[x].name;
341         }
342         return "<unknown>";
343 }
344
345 static int strat2int(const char *strategy)
346 {
347         int x;
348         for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
349                 if (!strcasecmp(strategy, strategies[x].name))
350                         return strategies[x].strategy;
351         }
352         return -1;
353 }
354
355 /* Insert the 'new' entry after the 'prev' entry of queue 'q' */
356 static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
357 {
358         struct queue_ent *cur;
359
360         if (!q || !new)
361                 return;
362         if (prev) {
363                 cur = prev->next;
364                 prev->next = new;
365         } else {
366                 cur = q->head;
367                 q->head = new;
368         }
369         new->next = cur;
370         new->parent = q;
371         new->pos = ++(*pos);
372         new->opos = *pos;
373 }
374
375 enum queue_member_status {
376         QUEUE_NO_MEMBERS,
377         QUEUE_NO_REACHABLE_MEMBERS,
378         QUEUE_NORMAL
379 };
380
381 static enum queue_member_status get_member_status(const struct ast_call_queue *q)
382 {
383         struct member *member;
384         enum queue_member_status result = QUEUE_NO_MEMBERS;
385
386         for (member = q->members; member; member = member->next) {
387                 switch (member->status) {
388                 case AST_DEVICE_INVALID:
389                         /* nothing to do */
390                         break;
391                 case AST_DEVICE_UNAVAILABLE:
392                         result = QUEUE_NO_REACHABLE_MEMBERS;
393                         break;
394                 default:
395                         return QUEUE_NORMAL;
396                 }
397         }
398         
399         return result;
400 }
401
402 struct statechange {
403         int state;
404         char dev[0];
405 };
406
407 static void *changethread(void *data)
408 {
409         struct ast_call_queue *q;
410         struct statechange *sc = data;
411         struct member *cur;
412         char *loc;
413         char *technology;
414
415         technology = ast_strdupa(sc->dev);
416         loc = strchr(technology, '/');
417         if (loc) {
418                 *loc = '\0';
419                 loc++;
420         } else {
421                 free(sc);
422                 return NULL;
423         }
424         if (option_debug)
425                 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
426         ast_mutex_lock(&qlock);
427         for (q = queues; q; q = q->next) {
428                 ast_mutex_lock(&q->lock);
429                 cur = q->members;
430                 while(cur) {
431                         if (!strcasecmp(sc->dev, cur->interface)) {
432                                 if (cur->status != sc->state) {
433                                         cur->status = sc->state;
434                                         if (!q->maskmemberstatus) {
435                                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
436                                                         "Queue: %s\r\n"
437                                                         "Location: %s\r\n"
438                                                         "Membership: %s\r\n"
439                                                         "Penalty: %d\r\n"
440                                                         "CallsTaken: %d\r\n"
441                                                         "LastCall: %ld\r\n"
442                                                         "Status: %d\r\n"
443                                                         "Paused: %d\r\n",
444                                                 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
445                                                 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
446                                         }
447                                 }
448                         }
449                         cur = cur->next;
450                 }
451                 ast_mutex_unlock(&q->lock);
452         }
453         ast_mutex_unlock(&qlock);
454         if (option_debug)
455                 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d'\n", technology, loc, sc->state);
456         free(sc);
457         return NULL;
458 }
459
460 static int statechange_queue(const char *dev, int state, void *ign)
461 {
462         /* Avoid potential for deadlocks by spawning a new thread to handle
463            the event */
464         struct statechange *sc;
465         pthread_t t;
466         pthread_attr_t attr;
467
468         sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
469         if (sc) {
470                 sc->state = state;
471                 strcpy(sc->dev, dev);
472                 pthread_attr_init(&attr);
473                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
474                 if (ast_pthread_create(&t, &attr, changethread, sc)) {
475                         ast_log(LOG_WARNING, "Failed to create update thread!\n");
476                         free(sc);
477                 }
478         }
479         return 0;
480 }
481
482 static struct member *create_queue_member(char *interface, int penalty, int paused)
483 {
484         struct member *cur;
485         
486         /* Add a new member */
487
488         cur = malloc(sizeof(struct member));
489
490         if (cur) {
491                 memset(cur, 0, sizeof(struct member));
492                 cur->penalty = penalty;
493                 cur->paused = paused;
494                 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
495                 if (!strchr(cur->interface, '/'))
496                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
497                 cur->status = ast_device_state(interface);
498         }
499
500         return cur;
501 }
502
503 static struct ast_call_queue *alloc_queue(const char *queuename)
504 {
505         struct ast_call_queue *q;
506
507         q = malloc(sizeof(*q));
508         if (q) {
509                 memset(q, 0, sizeof(*q));
510                 ast_mutex_init(&q->lock);
511                 ast_copy_string(q->name, queuename, sizeof(q->name));
512         }
513         return q;
514 }
515
516 static void init_queue(struct ast_call_queue *q)
517 {
518         q->dead = 0;
519         q->retry = DEFAULT_RETRY;
520         q->timeout = -1;
521         q->maxlen = 0;
522         q->announcefrequency = 0;
523         q->announceholdtime = 0;
524         q->roundingseconds = 0; /* Default - don't announce seconds */
525         q->servicelevel = 0;
526         q->moh[0] = '\0';
527         q->announce[0] = '\0';
528         q->context[0] = '\0';
529         q->monfmt[0] = '\0';
530         ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
531         ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
532         ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
533         ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
534         ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
535         ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
536         ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
537         ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
538         ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
539 }
540
541 static void clear_queue(struct ast_call_queue *q)
542 {
543         q->holdtime = 0;
544         q->callscompleted = 0;
545         q->callsabandoned = 0;
546         q->callscompletedinsl = 0;
547         q->wrapuptime = 0;
548 }
549
550 /* Configure a queue parameter.
551    For error reporting, line number is passed for .conf static configuration.
552    For Realtime queues, linenum is -1.
553    The failunknown flag is set for config files (and static realtime) to show
554    errors for unknown parameters. It is cleared for dynamic realtime to allow
555    extra fields in the tables. */
556 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
557 {
558         if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
559                 ast_copy_string(q->moh, val, sizeof(q->moh));
560         } else if (!strcasecmp(param, "announce")) {
561                 ast_copy_string(q->announce, val, sizeof(q->announce));
562         } else if (!strcasecmp(param, "context")) {
563                 ast_copy_string(q->context, val, sizeof(q->context));
564         } else if (!strcasecmp(param, "timeout")) {
565                 q->timeout = atoi(val);
566                 if (q->timeout < 0)
567                         q->timeout = DEFAULT_TIMEOUT;
568         } else if (!strcasecmp(param, "monitor-join")) {
569                 q->monjoin = ast_true(val);
570         } else if (!strcasecmp(param, "monitor-format")) {
571                 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
572         } else if (!strcasecmp(param, "queue-youarenext")) {
573                 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
574         } else if (!strcasecmp(param, "queue-thereare")) {
575                 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
576         } else if (!strcasecmp(param, "queue-callswaiting")) {
577                 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
578         } else if (!strcasecmp(param, "queue-holdtime")) {
579                 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
580         } else if (!strcasecmp(param, "queue-minutes")) {
581                 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
582         } else if (!strcasecmp(param, "queue-seconds")) {
583                 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
584         } else if (!strcasecmp(param, "queue-lessthan")) {
585                 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
586         } else if (!strcasecmp(param, "queue-thankyou")) {
587                 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
588         } else if (!strcasecmp(param, "queue-reporthold")) {
589                 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
590         } else if (!strcasecmp(param, "announce-frequency")) {
591                 q->announcefrequency = atoi(val);
592         } else if (!strcasecmp(param, "announce-round-seconds")) {
593                 q->roundingseconds = atoi(val);
594                 if (q->roundingseconds>60 || q->roundingseconds<0) {
595                         if (linenum >= 0) {
596                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
597                                         "using 0 instead for queue '%s' at line %d of queues.conf\n",
598                                         val, param, q->name, linenum);
599                         } else {
600                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
601                                         "using 0 instead for queue '%s'\n", val, param, q->name);
602                         }
603                         q->roundingseconds=0;
604                 }
605         } else if (!strcasecmp(param, "announce-holdtime")) {
606                 if (!strcasecmp(val, "once"))
607                         q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
608                 else if (ast_true(val))
609                         q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
610                 else
611                         q->announceholdtime = 0;
612         } else if (!strcasecmp(param, "retry")) {
613                 q->retry = atoi(val);
614                 if (q->retry < 0)
615                         q->retry = DEFAULT_RETRY;
616         } else if (!strcasecmp(param, "wrapuptime")) {
617                 q->wrapuptime = atoi(val);
618         } else if (!strcasecmp(param, "maxlen")) {
619                 q->maxlen = atoi(val);
620                 if (q->maxlen < 0)
621                         q->maxlen = 0;
622         } else if (!strcasecmp(param, "servicelevel")) {
623                 q->servicelevel= atoi(val);
624         } else if (!strcasecmp(param, "strategy")) {
625                 q->strategy = strat2int(val);
626                 if (q->strategy < 0) {
627                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
628                                 val, q->name);
629                         q->strategy = 0;
630                 }
631         } else if (!strcasecmp(param, "joinempty")) {
632                 if (!strcasecmp(val, "strict"))
633                         q->joinempty = QUEUE_EMPTY_STRICT;
634                 else if (ast_true(val))
635                         q->joinempty = QUEUE_EMPTY_NORMAL;
636                 else
637                         q->joinempty = 0;
638         } else if (!strcasecmp(param, "leavewhenempty")) {
639                 if (!strcasecmp(val, "strict"))
640                         q->leavewhenempty = QUEUE_EMPTY_STRICT;
641                 else if (ast_true(val))
642                         q->leavewhenempty = QUEUE_EMPTY_NORMAL;
643                 else
644                         q->leavewhenempty = 0;
645         } else if (!strcasecmp(param, "eventmemberstatus")) {
646                 q->maskmemberstatus = !ast_true(val);
647         } else if (!strcasecmp(param, "eventwhencalled")) {
648                 q->eventwhencalled = ast_true(val);
649         } else if (!strcasecmp(param, "reportholdtime")) {
650                 q->reportholdtime = ast_true(val);
651         } else if (!strcasecmp(param, "memberdelay")) {
652                 q->memberdelay = atoi(val);
653         } else if (!strcasecmp(param, "weight")) {
654                 q->weight = atoi(val);
655                 if (q->weight)
656                         use_weight++;
657                 /* With Realtime queues, if the last queue using weights is deleted in realtime,
658                    we will not see any effect on use_weight until next reload. */
659         } else if (!strcasecmp(param, "timeoutrestart")) {
660                 q->timeoutrestart = ast_true(val);
661         } else if(failunknown) {
662                 if (linenum >= 0) {
663                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
664                                 q->name, param, linenum);
665                 } else {
666                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
667                 }
668         }
669 }
670
671 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
672 {
673         struct member *m, *prev_m;
674         int penalty = 0;
675
676         if(penalty_str) {
677                 penalty = atoi(penalty_str);
678                 if(penalty < 0)
679                         penalty = 0;
680         }
681
682         /* Find the member, or the place to put a new one. */
683         prev_m = NULL;
684         m = q->members;
685         while (m && strcmp(m->interface, interface)) {
686                 prev_m = m;
687                 m = m->next;
688         }
689
690         /* Create a new one if not found, else update penalty */
691         if (!m) {
692                 m = create_queue_member(interface, penalty, 0);
693                 if (m) {
694                         m->dead = 0;
695                         if (prev_m) {
696                                 prev_m->next = m;
697                         } else {
698                                 q->members = m;
699                         }
700                 }
701         } else {
702                 m->dead = 0;    /* Do not delete this one. */
703                 m->penalty = penalty;
704         }
705 }
706
707
708 /* Reload a single queue via realtime. Return the queue, or NULL if it doesn't exist.
709    Should be called with the global qlock locked.
710    When found, the queue is returned with q->lock locked. */
711 static struct ast_call_queue *reload_queue_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
712 {
713         struct ast_variable *v;
714         struct ast_call_queue *q, *prev_q;
715         struct member *m, *prev_m, *next_m;
716         char *interface;
717         char *tmp, *tmp_name;
718         char tmpbuf[64];        /* Must be longer than the longest queue param name. */
719
720         /* Find the queue in the in-core list (we will create a new one if not found). */
721         q = queues;
722         prev_q = NULL;
723         while (q) {
724                 if (!strcasecmp(q->name, queuename)) {
725                         break;
726                 }
727                 q = q->next;
728                 prev_q = q;
729         }
730
731         /* Static queues override realtime. */
732         if (q) {
733                 ast_mutex_lock(&q->lock);
734                 if (!q->realtime) {
735                         if (q->dead) {
736                                 ast_mutex_unlock(&q->lock);
737                                 return NULL;
738                         } else {
739                                 return q;
740                         }
741                 }
742         }
743
744         /* Check if queue is defined in realtime. */
745         if (!queue_vars) {
746                 /* Delete queue from in-core list if it has been deleted in realtime. */
747                 if (q) {
748                         /* Hmm, can't seem to distinguish a DB failure from a not
749                            found condition... So we might delete an in-core queue
750                            in case of DB failure. */
751                         ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
752
753                         q->dead = 1;
754                         /* Delete if unused (else will be deleted when last caller leaves). */
755                         if (!q->count) {
756                                 /* Delete. */
757                                 if (!prev_q) {
758                                         queues = q->next;
759                                 } else {
760                                         prev_q->next = q->next;
761                                 }
762                                 ast_mutex_unlock(&q->lock);
763                                 free(q);
764                         } else
765                                 ast_mutex_unlock(&q->lock);
766                 }
767                 return NULL;
768         }
769
770         /* Create a new queue if an in-core entry does not exist yet. */
771         if (!q) {
772                 q = alloc_queue(queuename);
773                 if (!q)
774                         return NULL;
775                 ast_mutex_lock(&q->lock);
776                 clear_queue(q);
777                 q->realtime = 1;
778                 q->next = queues;
779                 queues = q;
780         }
781         init_queue(q);          /* Ensure defaults for all parameters not set explicitly. */
782
783         v = queue_vars;
784         memset(tmpbuf, 0, sizeof(tmpbuf));
785         while(v) {
786                 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
787                 if((tmp = strchr(v->name, '_')) != NULL) {
788                         ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
789                         tmp_name = tmpbuf;
790                         tmp = tmp_name;
791                         while((tmp = strchr(tmp, '_')) != NULL)
792                                 *tmp++ = '-';
793                 } else
794                         tmp_name = v->name;
795                 queue_set_param(q, tmp_name, v->value, -1, 0);
796                 v = v->next;
797         }
798
799         /* Temporarily set members dead so we can detect deleted ones. */
800         m = q->members;
801         while (m) {
802                 m->dead = 1;
803                 m = m->next;
804         }
805
806         interface = ast_category_browse(member_config, NULL);
807         while (interface) {
808                 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
809                 interface = ast_category_browse(member_config, interface);
810         }
811
812         /* Delete all realtime members that have been deleted in DB. */
813         m = q->members;
814         prev_m = NULL;
815         while (m) {
816                 next_m = m->next;
817                 if (m->dead) {
818                         if (prev_m) {
819                                 prev_m->next = next_m;
820                         } else {
821                                 q->members = next_m;
822                         }
823                         free(m);
824                 } else {
825                         prev_m = m;
826                 }
827                 m = next_m;
828         }
829
830         return q;
831 }
832
833 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
834 {
835         struct ast_variable *queue_vars = NULL;
836         struct ast_config *member_config = NULL;
837         struct ast_call_queue *q;
838         struct queue_ent *cur, *prev = NULL;
839         int res = -1;
840         int pos = 0;
841         int inserted = 0;
842         enum queue_member_status stat;
843
844         /* Load from realtime before taking the global qlock, to avoid blocking all
845            queue operations while waiting for the DB.
846
847            This will be two separate database transactions, so we might
848            see queue parameters as they were before another process
849            changed the queue and member list as it was after the change.
850            Thus we might see an empty member list when a queue is
851            deleted. In practise, this is unlikely to cause a problem. */
852         queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
853         if(queue_vars)
854                 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
855
856         ast_mutex_lock(&qlock);
857         q = reload_queue_rt(queuename, queue_vars, member_config);
858         /* Note: If found, reload_queue_rt() returns with q->lock locked. */
859         if(member_config)
860                 ast_config_destroy(member_config);
861         if(queue_vars)
862                 ast_variables_destroy(queue_vars);
863
864         if (!q) {
865                 ast_mutex_unlock(&qlock);
866                 return res;
867         }
868
869         /* This is our one */
870         stat = get_member_status(q);
871         if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
872                 *reason = QUEUE_JOINEMPTY;
873         else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
874                 *reason = QUEUE_JOINUNAVAIL;
875         else if (q->maxlen && (q->count >= q->maxlen))
876                 *reason = QUEUE_FULL;
877         else {
878                 /* There's space for us, put us at the right position inside
879                  * the queue. 
880                  * Take into account the priority of the calling user */
881                 inserted = 0;
882                 prev = NULL;
883                 cur = q->head;
884                 while(cur) {
885                         /* We have higher priority than the current user, enter
886                          * before him, after all the other users with priority
887                          * higher or equal to our priority. */
888                         if ((!inserted) && (qe->prio > cur->prio)) {
889                                 insert_entry(q, prev, qe, &pos);
890                                 inserted = 1;
891                         }
892                         cur->pos = ++pos;
893                         prev = cur;
894                         cur = cur->next;
895                 }
896                 /* No luck, join at the end of the queue */
897                 if (!inserted)
898                         insert_entry(q, prev, qe, &pos);
899                 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
900                 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
901                 ast_copy_string(qe->context, q->context, sizeof(qe->context));
902                 q->count++;
903                 res = 0;
904                 manager_event(EVENT_FLAG_CALL, "Join", 
905                               "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
906                               qe->chan->name, 
907                               qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
908                               qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
909                               q->name, qe->pos, q->count );
910 #if 0
911 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
912 #endif
913         }
914         ast_mutex_unlock(&q->lock);
915         ast_mutex_unlock(&qlock);
916         return res;
917 }
918
919 static void free_members(struct ast_call_queue *q, int all)
920 {
921         /* Free non-dynamic members */
922         struct member *curm, *next, *prev;
923
924         curm = q->members;
925         prev = NULL;
926         while(curm) {
927                 next = curm->next;
928                 if (all || !curm->dynamic) {
929                         if (prev)
930                                 prev->next = next;
931                         else
932                                 q->members = next;
933                         free(curm);
934                 } else 
935                         prev = curm;
936                 curm = next;
937         }
938 }
939
940 static void destroy_queue(struct ast_call_queue *q)
941 {
942         struct ast_call_queue *cur, *prev = NULL;
943
944         ast_mutex_lock(&qlock);
945         for (cur = queues; cur; cur = cur->next) {
946                 if (cur == q) {
947                         if (prev)
948                                 prev->next = cur->next;
949                         else
950                                 queues = cur->next;
951                 } else {
952                         prev = cur;
953                 }
954         }
955         ast_mutex_unlock(&qlock);
956         free_members(q, 1);
957         ast_mutex_destroy(&q->lock);
958         free(q);
959 }
960
961 static int play_file(struct ast_channel *chan, char *filename)
962 {
963         int res;
964
965         ast_stopstream(chan);
966         res = ast_streamfile(chan, filename, chan->language);
967
968         if (!res)
969                 res = ast_waitstream(chan, AST_DIGIT_ANY);
970         else
971                 res = 0;
972
973         ast_stopstream(chan);
974
975         return res;
976 }
977
978 static int valid_exit(struct queue_ent *qe, char digit)
979 {
980         char tmp[2];
981
982         if (ast_strlen_zero(qe->context))
983                 return 0;
984         tmp[0] = digit;
985         tmp[1] = '\0';
986         if (ast_exists_extension(qe->chan, qe->context, tmp, 1, qe->chan->cid.cid_num)) {
987                 ast_copy_string(qe->chan->context, qe->context, sizeof(qe->chan->context));
988                 ast_copy_string(qe->chan->exten, tmp, sizeof(qe->chan->exten));
989                 qe->chan->priority = 0;
990                 return 1;
991         }
992         return 0;
993 }
994
995 static int say_position(struct queue_ent *qe)
996 {
997         int res = 0, avgholdmins, avgholdsecs;
998         time_t now;
999
1000         /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1001         time(&now);
1002         if ( (now - qe->last_pos) < 15 )
1003                 return 0;
1004
1005         /* If either our position has changed, or we are over the freq timer, say position */
1006         if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
1007                 return 0;
1008
1009         ast_moh_stop(qe->chan);
1010         /* Say we're next, if we are */
1011         if (qe->pos == 1) {
1012                 res = play_file(qe->chan, qe->parent->sound_next);
1013                 if (res && valid_exit(qe, res))
1014                         goto playout;
1015                 else
1016                         goto posout;
1017         } else {
1018                 res = play_file(qe->chan, qe->parent->sound_thereare);
1019                 if (res && valid_exit(qe, res))
1020                         goto playout;
1021                 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1022                 if (res && valid_exit(qe, res))
1023                         goto playout;
1024                 res = play_file(qe->chan, qe->parent->sound_calls);
1025                 if (res && valid_exit(qe, res))
1026                         goto playout;
1027         }
1028         /* Round hold time to nearest minute */
1029         avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
1030
1031         /* If they have specified a rounding then round the seconds as well */
1032         if(qe->parent->roundingseconds) {
1033                 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
1034                 avgholdsecs*= qe->parent->roundingseconds;
1035         } else {
1036                 avgholdsecs=0;
1037         }
1038
1039         if (option_verbose > 2)
1040                 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1041
1042         /* If the hold time is >1 min, if it's enabled, and if it's not
1043            supposed to be only once and we have already said it, say it */
1044         if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1045             (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1046                 res = play_file(qe->chan, qe->parent->sound_holdtime);
1047                 if (res && valid_exit(qe, res))
1048                         goto playout;
1049
1050                 if (avgholdmins>0) {
1051                         if (avgholdmins < 2) {
1052                                 res = play_file(qe->chan, qe->parent->sound_lessthan);
1053                                 if (res && valid_exit(qe, res))
1054                                         goto playout;
1055
1056                                 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1057                                 if (res && valid_exit(qe, res))
1058                                         goto playout;
1059                         } else {
1060                                 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1061                                 if (res && valid_exit(qe, res))
1062                                         goto playout;
1063                         }
1064                         
1065                         res = play_file(qe->chan, qe->parent->sound_minutes);
1066                         if (res && valid_exit(qe, res))
1067                                 goto playout;
1068                 }
1069                 if (avgholdsecs>0) {
1070                         res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1071                         if (res && valid_exit(qe, res))
1072                                 goto playout;
1073
1074                         res = play_file(qe->chan, qe->parent->sound_seconds);
1075                         if (res && valid_exit(qe, res))
1076                                 goto playout;
1077                 }
1078
1079         }
1080
1081  posout:
1082         if (option_verbose > 2)
1083                 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1084                             qe->chan->name, qe->parent->name, qe->pos);
1085         res = play_file(qe->chan, qe->parent->sound_thanks);
1086
1087  playout:
1088         /* Set our last_pos indicators */
1089         qe->last_pos = now;
1090         qe->last_pos_said = qe->pos;
1091         ast_moh_start(qe->chan, qe->moh);
1092
1093         return res;
1094 }
1095
1096 static void record_abandoned(struct queue_ent *qe)
1097 {
1098         ast_mutex_lock(&qe->parent->lock);
1099         qe->parent->callsabandoned++;
1100         ast_mutex_unlock(&qe->parent->lock);
1101 }
1102
1103 static void recalc_holdtime(struct queue_ent *qe)
1104 {
1105         int oldvalue, newvalue;
1106
1107         /* Calculate holdtime using a recursive boxcar filter */
1108         /* Thanks to SRT for this contribution */
1109         /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1110
1111         newvalue = time(NULL) - qe->start;
1112
1113         ast_mutex_lock(&qe->parent->lock);
1114         if (newvalue <= qe->parent->servicelevel)
1115                 qe->parent->callscompletedinsl++;
1116         oldvalue = qe->parent->holdtime;
1117         qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1118         ast_mutex_unlock(&qe->parent->lock);
1119 }
1120
1121
1122 static void leave_queue(struct queue_ent *qe)
1123 {
1124         struct ast_call_queue *q;
1125         struct queue_ent *cur, *prev = NULL;
1126         int pos = 0;
1127
1128         q = qe->parent;
1129         if (!q)
1130                 return;
1131         ast_mutex_lock(&q->lock);
1132
1133         prev = NULL;
1134         cur = q->head;
1135         while(cur) {
1136                 if (cur == qe) {
1137                         q->count--;
1138
1139                         /* Take us out of the queue */
1140                         manager_event(EVENT_FLAG_CALL, "Leave",
1141                                 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
1142                                 qe->chan->name, q->name,  q->count);
1143 #if 0
1144 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1145 #endif
1146                         /* Take us out of the queue */
1147                         if (prev)
1148                                 prev->next = cur->next;
1149                         else
1150                                 q->head = cur->next;
1151                 } else {
1152                         /* Renumber the people after us in the queue based on a new count */
1153                         cur->pos = ++pos;
1154                         prev = cur;
1155                 }
1156                 cur = cur->next;
1157         }
1158         ast_mutex_unlock(&q->lock);
1159         if (q->dead && !q->count) {     
1160                 /* It's dead and nobody is in it, so kill it */
1161                 destroy_queue(q);
1162         }
1163 }
1164
1165 /* Hang up a list of outgoing calls */
1166 static void hangupcalls(struct localuser *outgoing, struct ast_channel *exception)
1167 {
1168         struct localuser *oo;
1169
1170         while(outgoing) {
1171                 /* Hangup any existing lines we have open */
1172                 if (outgoing->chan && (outgoing->chan != exception))
1173                         ast_hangup(outgoing->chan);
1174                 oo = outgoing;
1175                 outgoing=outgoing->next;
1176                 free(oo);
1177         }
1178 }
1179
1180 static int update_status(struct ast_call_queue *q, struct member *member, int status)
1181 {
1182         struct member *cur;
1183
1184         /* Since a reload could have taken place, we have to traverse the list to
1185                 be sure it's still valid */
1186         ast_mutex_lock(&q->lock);
1187         cur = q->members;
1188         while(cur) {
1189                 if (member == cur) {
1190                         cur->status = status;
1191                         if (!q->maskmemberstatus) {
1192                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1193                                         "Queue: %s\r\n"
1194                                         "Location: %s\r\n"
1195                                         "Membership: %s\r\n"
1196                                         "Penalty: %d\r\n"
1197                                         "CallsTaken: %d\r\n"
1198                                         "LastCall: %ld\r\n"
1199                                         "Status: %d\r\n"
1200                                         "Paused: %d\r\n",
1201                                 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1202                                 cur->penalty, cur->calls, cur->lastcall, cur->status, cur->paused);
1203                         }
1204                         break;
1205                 }
1206                 cur = cur->next;
1207         }
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                                 record_abandoned(qe);
2040                                 if (qe->parent->eventwhencalled) {
2041                                         manager_event(EVENT_FLAG_AGENT, "AgentDump",
2042                                                       "Queue: %s\r\n"
2043                                                       "Uniqueid: %s\r\n"
2044                                                       "Channel: %s\r\n"
2045                                                       "Member: %s\r\n",
2046                                                       queuename, qe->chan->uniqueid, peer->name, member->interface);
2047                                 }
2048                                 ast_hangup(peer);
2049                                 goto out;
2050                         } else if (res2) {
2051                                 /* Caller must have hung up just before being connected*/
2052                                 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2053                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2054                                 record_abandoned(qe);
2055                                 ast_hangup(peer);
2056                                 return -1;
2057                         }
2058                 }
2059                 /* Stop music on hold */
2060                 ast_moh_stop(qe->chan);
2061                 /* If appropriate, log that we have a destination channel */
2062                 if (qe->chan->cdr)
2063                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2064                 /* Make sure channels are compatible */
2065                 res = ast_channel_make_compatible(qe->chan, peer);
2066                 if (res < 0) {
2067                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2068                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2069                         record_abandoned(qe);
2070                         ast_hangup(peer);
2071                         return -1;
2072                 }
2073                 /* Begin Monitoring */
2074                 if (qe->parent->monfmt && *qe->parent->monfmt) {
2075                         monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2076                         if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2077                                 which = qe->chan;
2078                         else
2079                                 which = peer;
2080                         if (monitorfilename)
2081                                 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2082                         else
2083                                 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2084                         if (qe->parent->monjoin)
2085                                 ast_monitor_setjoinfiles(which, 1);
2086                 }
2087                 /* Drop out of the queue at this point, to prepare for next caller */
2088                 leave_queue(qe);                        
2089                 if (url && !ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2090                         if (option_debug)
2091                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2092                         ast_channel_sendurl(peer, url);
2093                 }
2094                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
2095                 if (qe->parent->eventwhencalled)
2096                         manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2097                                       "Queue: %s\r\n"
2098                                       "Uniqueid: %s\r\n"
2099                                       "Channel: %s\r\n"
2100                                       "Member: %s\r\n"
2101                                       "Holdtime: %ld\r\n",
2102                                       queuename, qe->chan->uniqueid, peer->name, member->interface,
2103                                       (long)time(NULL) - qe->start);
2104                 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2105                 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2106                 time(&callstart);
2107
2108                 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2109
2110                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2111                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
2112                 } else if (qe->chan->_softhangup) {
2113                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2114                                       (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2115                         if (qe->parent->eventwhencalled)
2116                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2117                                               "Queue: %s\r\n"
2118                                               "Uniqueid: %s\r\n"
2119                                               "Channel: %s\r\n"
2120                                               "Member: %s\r\n"
2121                                               "HoldTime: %ld\r\n"
2122                                               "TalkTime: %ld\r\n"
2123                                               "Reason: caller\r\n",
2124                                               queuename, qe->chan->uniqueid, peer->name, member->interface,
2125                                               (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2126                 } else {
2127                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2128                         if (qe->parent->eventwhencalled)
2129                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2130                                               "Queue: %s\r\n"
2131                                               "Uniqueid: %s\r\n"
2132                                               "Channel: %s\r\n"
2133                                               "HoldTime: %ld\r\n"
2134                                               "TalkTime: %ld\r\n"
2135                                               "Reason: agent\r\n",
2136                                               queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2137                                               (long)(time(NULL) - callstart));
2138                 }
2139
2140                 if(bridge != AST_PBX_NO_HANGUP_PEER)
2141                         ast_hangup(peer);
2142                 update_queue(qe->parent, member);
2143                 if (bridge == 0) 
2144                         res = 1; /* JDG: bridge successfull, leave app_queue */
2145                 else 
2146                         res = bridge; /* bridge error, stay in the queue */
2147         }       
2148 out:
2149         hangupcalls(outgoing, NULL);
2150         return res;
2151 }
2152
2153 static int wait_a_bit(struct queue_ent *qe)
2154 {
2155         /* Don't need to hold the lock while we setup the outgoing calls */
2156         int retrywait = qe->parent->retry * 1000;
2157
2158         return ast_waitfordigit(qe->chan, retrywait);
2159 }
2160
2161 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2162 {
2163         struct member *mem;
2164
2165         if (q)
2166                 for (mem = q->members; mem; mem = mem->next)
2167                         if (!strcmp(interface, mem->interface))
2168                                 return mem;
2169
2170         return NULL;
2171 }
2172
2173
2174 /* Dump all members in a specific queue to the databse
2175  *
2176  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2177  *
2178  */
2179 static void dump_queue_members(struct ast_call_queue *pm_queue)
2180 {
2181         struct member *cur_member;
2182         char value[PM_MAX_LEN];
2183         int value_len = 0;
2184         int res;
2185
2186         memset(value, 0, sizeof(value));
2187
2188         if (!pm_queue)
2189                 return;
2190
2191         for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2192                 if (!cur_member->dynamic)
2193                         continue;
2194
2195                 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2196                                cur_member->interface, cur_member->penalty, cur_member->paused,
2197                                cur_member->next ? "|" : "");
2198                 if (res != strlen(value + value_len)) {
2199                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2200                         break;
2201                 }
2202                 value_len += res;
2203         }
2204         
2205         if (value_len && !cur_member) {
2206                 if (ast_db_put(pm_family, pm_queue->name, value))
2207                         ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2208         } else
2209                 /* Delete the entry if the queue is empty or there is an error */
2210                 ast_db_del(pm_family, pm_queue->name);
2211 }
2212
2213 static int remove_from_queue(char *queuename, char *interface)
2214 {
2215         struct ast_call_queue *q;
2216         struct member *last_member, *look;
2217         int res = RES_NOSUCHQUEUE;
2218
2219         ast_mutex_lock(&qlock);
2220         for (q = queues ; q ; q = q->next) {
2221                 ast_mutex_lock(&q->lock);
2222                 if (!strcmp(q->name, queuename)) {
2223                         if ((last_member = interface_exists(q, interface))) {
2224                                 if ((look = q->members) == last_member) {
2225                                         q->members = last_member->next;
2226                                 } else {
2227                                         while (look != NULL) {
2228                                                 if (look->next == last_member) {
2229                                                         look->next = last_member->next;
2230                                                         break;
2231                                                 } else {
2232                                                          look = look->next;
2233                                                 }
2234                                         }
2235                                 }
2236                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2237                                                 "Queue: %s\r\n"
2238                                                 "Location: %s\r\n",
2239                                         q->name, last_member->interface);
2240                                 free(last_member);
2241
2242                                 if (queue_persistent_members)
2243                                     dump_queue_members(q);
2244
2245                                 res = RES_OKAY;
2246                         } else {
2247                                 res = RES_EXISTS;
2248                         }
2249                         ast_mutex_unlock(&q->lock);
2250                         break;
2251                 }
2252                 ast_mutex_unlock(&q->lock);
2253         }
2254         ast_mutex_unlock(&qlock);
2255         return res;
2256 }
2257
2258 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2259 {
2260         struct ast_call_queue *q;
2261         struct member *new_member;
2262         int res = RES_NOSUCHQUEUE;
2263
2264         ast_mutex_lock(&qlock);
2265         for (q = queues ; q ; q = q->next) {
2266                 ast_mutex_lock(&q->lock);
2267                 if (!strcmp(q->name, queuename)) {
2268                         if (interface_exists(q, interface) == NULL) {
2269                                 new_member = create_queue_member(interface, penalty, paused);
2270
2271                                 if (new_member != NULL) {
2272                                         new_member->dynamic = 1;
2273                                         new_member->next = q->members;
2274                                         q->members = new_member;
2275                                         manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2276                                                 "Queue: %s\r\n"
2277                                                 "Location: %s\r\n"
2278                                                 "Membership: %s\r\n"
2279                                                 "Penalty: %d\r\n"
2280                                                 "CallsTaken: %d\r\n"
2281                                                 "LastCall: %ld\r\n"
2282                                                 "Status: %d\r\n"
2283                                                 "Paused: %d\r\n",
2284                                         q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2285                                         new_member->penalty, new_member->calls, new_member->lastcall, new_member->status, new_member->paused);
2286                                         
2287                                         if (dump)
2288                                                 dump_queue_members(q);
2289
2290                                         res = RES_OKAY;
2291                                 } else {
2292                                         res = RES_OUTOFMEMORY;
2293                                 }
2294                         } else {
2295                                 res = RES_EXISTS;
2296                         }
2297                         ast_mutex_unlock(&q->lock);
2298                         break;
2299                 }
2300                 ast_mutex_unlock(&q->lock);
2301         }
2302         ast_mutex_unlock(&qlock);
2303         return res;
2304 }
2305
2306 static int set_member_paused(char *queuename, char *interface, int paused)
2307 {
2308         int found = 0;
2309         struct ast_call_queue *q;
2310         struct member *mem;
2311
2312         /* Special event for when all queues are paused - individual events still generated */
2313
2314         if (ast_strlen_zero(queuename))
2315                 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2316
2317         ast_mutex_lock(&qlock);
2318         for (q = queues ; q ; q = q->next) {
2319                 ast_mutex_lock(&q->lock);
2320                 if (ast_strlen_zero(queuename) || !strcmp(q->name, queuename)) {
2321                         if ((mem = interface_exists(q, interface))) {
2322                                 found++;
2323                                 if (mem->paused == paused)
2324                                         ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2325                                 mem->paused = paused;
2326
2327                                 if (queue_persistent_members)
2328                                     dump_queue_members(q);
2329
2330                                 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2331
2332                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2333                                         "Queue: %s\r\n"
2334                                         "Location: %s\r\n"
2335                                         "Paused: %d\r\n",
2336                                                 q->name, mem->interface, paused);
2337                         }
2338                 }
2339                 ast_mutex_unlock(&q->lock);
2340         }
2341         ast_mutex_unlock(&qlock);
2342
2343         if (found)
2344                 return RESULT_SUCCESS;
2345         else
2346                 return RESULT_FAILURE;
2347 }
2348
2349 /* Reload dynamic queue members persisted into the astdb */
2350 static void reload_queue_members(void)
2351 {
2352         char *cur_ptr;  
2353         char *queue_name;
2354         char *member;
2355         char *interface;
2356         char *penalty_tok;
2357         int penalty = 0;
2358         char *paused_tok;
2359         int paused = 0;
2360         struct ast_db_entry *db_tree;
2361         struct ast_db_entry *entry;
2362         struct ast_call_queue *cur_queue;
2363         char queue_data[PM_MAX_LEN];
2364
2365         ast_mutex_lock(&qlock);
2366
2367         /* Each key in 'pm_family' is the name of a queue */
2368         db_tree = ast_db_gettree(pm_family, NULL);
2369         for (entry = db_tree; entry; entry = entry->next) {
2370
2371                 queue_name = entry->key + strlen(pm_family) + 2;
2372
2373                 cur_queue = queues;
2374                 while (cur_queue) {
2375                         ast_mutex_lock(&cur_queue->lock);
2376                         if (!strcmp(queue_name, cur_queue->name))
2377                                 break;
2378                         ast_mutex_unlock(&cur_queue->lock);
2379                         cur_queue = cur_queue->next;
2380                 }
2381
2382                 if (!cur_queue) {
2383                         /* If the queue no longer exists, remove it from the
2384                          * database */
2385                         ast_db_del(pm_family, queue_name);
2386                         continue;
2387                 } else
2388                         ast_mutex_unlock(&cur_queue->lock);
2389
2390                 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2391                         continue;
2392
2393                 cur_ptr = queue_data;
2394                 while ((member = strsep(&cur_ptr, "|"))) {
2395                         if (ast_strlen_zero(member))
2396                                 continue;
2397
2398                         interface = strsep(&member, ";");
2399                         penalty_tok = strsep(&member, ";");
2400                         paused_tok = strsep(&member, ";");
2401
2402                         if (!penalty_tok) {
2403                                 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
2404                                 break;
2405                         }
2406                         penalty = strtol(penalty_tok, NULL, 10);
2407                         if (errno == ERANGE) {
2408                                 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2409                                 break;
2410                         }
2411                         
2412                         if (!paused_tok) {
2413                                 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2414                                 break;
2415                         }
2416                         paused = strtol(paused_tok, NULL, 10);
2417                         if ((errno == ERANGE) || paused < 0 || paused > 1) {
2418                                 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2419                                 break;
2420                         }
2421
2422                         if (option_debug)
2423                                 ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
2424                         
2425                         if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2426                                 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2427                                 break;
2428                         }
2429                 }
2430         }
2431
2432         ast_mutex_unlock(&qlock);
2433         if (db_tree) {
2434                 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2435                 ast_db_freetree(db_tree);
2436         }
2437 }
2438
2439 static int pqm_exec(struct ast_channel *chan, void *data)
2440 {
2441         struct localuser *u;
2442         char *queuename, *interface;
2443
2444         if (!data) {
2445                 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface])\n");
2446                 return -1;
2447         }
2448
2449         queuename = ast_strdupa((char *)data);
2450         if (!queuename) {
2451                 ast_log(LOG_ERROR, "Out of memory\n");
2452                 return -1;
2453         }
2454
2455         interface = strchr(queuename, '|');
2456         if (!interface) {
2457                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2458                 return -1;
2459         }
2460
2461         LOCAL_USER_ADD(u);
2462
2463         *interface = '\0';
2464         interface++;
2465
2466         if (set_member_paused(queuename, interface, 1)) {
2467                 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", interface);
2468                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2469                         chan->priority += 100;
2470                         LOCAL_USER_REMOVE(u);
2471                         return 0;
2472                 }
2473                 return -1;
2474         }
2475
2476         LOCAL_USER_REMOVE(u);
2477
2478         return 0;
2479 }
2480
2481 static int upqm_exec(struct ast_channel *chan, void *data)
2482 {
2483         struct localuser *u;
2484         char *queuename, *interface;
2485
2486         if (!data) {
2487                 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface])\n");
2488                 return -1;
2489         }
2490
2491         queuename = ast_strdupa((char *)data);
2492         if (!queuename) {
2493                 ast_log(LOG_ERROR, "Out of memory\n");
2494                 return -1;
2495         }
2496
2497         interface = strchr(queuename, '|');
2498         if (!interface) {
2499                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface])\n");
2500                 return -1;
2501         }
2502
2503         LOCAL_USER_ADD(u);
2504
2505         *interface = '\0';
2506         interface++;
2507
2508         if (set_member_paused(queuename, interface, 0)) {
2509                 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", interface);
2510                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2511                         chan->priority += 100;
2512                         LOCAL_USER_REMOVE(u);
2513                         return 0;
2514                 }
2515                 return -1;
2516         }
2517
2518         LOCAL_USER_REMOVE(u);
2519
2520         return 0;
2521 }
2522
2523 static int rqm_exec(struct ast_channel *chan, void *data)
2524 {
2525         int res=-1;
2526         struct localuser *u;
2527         char *info, *queuename;
2528         char tmpchan[256]="";
2529         char *interface = NULL;
2530
2531         if (!data) {
2532                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface])\n");
2533                 return -1;
2534         }
2535
2536         info = ast_strdupa((char *)data);
2537         if (!info) {
2538                 ast_log(LOG_ERROR, "Out of memory\n");
2539                 return -1;
2540         }
2541
2542         LOCAL_USER_ADD(u);
2543
2544         queuename = info;
2545         if (queuename) {
2546                 interface = strchr(queuename, '|');
2547                 if (interface) {
2548                         *interface = '\0';
2549                         interface++;
2550                 }
2551                 else {
2552                         ast_copy_string(tmpchan, chan->name, sizeof(tmpchan));
2553                         interface = strrchr(tmpchan, '-');
2554                         if (interface)
2555                                 *interface = '\0';
2556                         interface = tmpchan;
2557                 }
2558         }
2559
2560         switch (remove_from_queue(queuename, interface)) {
2561         case RES_OKAY:
2562                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", interface, queuename);
2563                 res = 0;
2564                 break;
2565         case RES_EXISTS:
2566                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
2567                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2568                         chan->priority += 100;
2569                 }
2570                 res = 0;
2571                 break;
2572         case RES_NOSUCHQUEUE:
2573                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", queuename);
2574                 res = 0;
2575                 break;
2576         case RES_OUTOFMEMORY:
2577                 ast_log(LOG_ERROR, "Out of memory\n");
2578                 break;
2579         }
2580
2581         LOCAL_USER_REMOVE(u);
2582         return res;
2583 }
2584
2585 static int aqm_exec(struct ast_channel *chan, void *data)
2586 {
2587         int res=-1;
2588         struct localuser *u;
2589         char *queuename;
2590         char *info;
2591         char tmpchan[512]="";
2592         char *interface=NULL;
2593         char *penaltys=NULL;
2594         int penalty = 0;
2595
2596         if (!data) {
2597                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface][|penalty]])\n");
2598                 return -1;
2599         }
2600
2601         info = ast_strdupa((char *)data);
2602         if (!info) {
2603                 ast_log(LOG_ERROR, "Out of memory\n");
2604                 return -1;
2605         }
2606         LOCAL_USER_ADD(u);
2607
2608         queuename = info;
2609         if (queuename) {
2610                 interface = strchr(queuename, '|');
2611                 if (interface) {
2612                         *interface = '\0';
2613                         interface++;
2614                 }
2615                 if (interface) {
2616                         penaltys = strchr(interface, '|');
2617                         if (penaltys) {
2618                                 *penaltys = '\0';
2619                                 penaltys++;
2620                         }
2621                 }
2622                 if (!interface || ast_strlen_zero(interface)) {
2623                         ast_copy_string(tmpchan, chan->name, sizeof(tmpchan));
2624                         interface = strrchr(tmpchan, '-');
2625                         if (interface)
2626                                 *interface = '\0';
2627                         interface = tmpchan;
2628                 }
2629                 if (penaltys && !ast_strlen_zero(penaltys)) {
2630                         if ((sscanf(penaltys, "%d", &penalty) != 1) || penalty < 0) {
2631                                 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", penaltys);
2632                                 penalty = 0;
2633                         }
2634                 }
2635         }
2636
2637         switch (add_to_queue(queuename, interface, penalty, 0, queue_persistent_members)) {
2638         case RES_OKAY:
2639                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", interface, queuename);
2640                 res = 0;
2641                 break;
2642         case RES_EXISTS:
2643                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
2644                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2645                         chan->priority += 100;
2646                 }
2647                 res = 0;
2648                 break;
2649         case RES_NOSUCHQUEUE:
2650                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", queuename);
2651                 res = 0;
2652                 break;
2653         case RES_OUTOFMEMORY:
2654                 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", interface, queuename);
2655                 break;
2656         }
2657
2658         LOCAL_USER_REMOVE(u);
2659         return res;
2660 }
2661
2662 static int queue_exec(struct ast_channel *chan, void *data)
2663 {
2664         int res=-1;
2665         int ringing=0;
2666         struct localuser *u;
2667         char *queuename;
2668         char info[512];
2669         char *info_ptr = info;
2670         char *options = NULL;
2671         char *url = NULL;
2672         char *announceoverride = NULL;
2673         char *user_priority;
2674         int prio;
2675         char *queuetimeoutstr = NULL;
2676         enum queue_result reason = QUEUE_UNKNOWN;
2677
2678         /* whether to exit Queue application after the timeout hits */
2679         int go_on = 0;
2680
2681         /* Our queue entry */
2682         struct queue_ent qe;
2683         
2684         if (!data || ast_strlen_zero(data)) {
2685                 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2686                 return -1;
2687         }
2688         
2689         LOCAL_USER_ADD(u);
2690
2691         /* Setup our queue entry */
2692         memset(&qe, 0, sizeof(qe));
2693         qe.start = time(NULL);
2694         
2695         /* Parse our arguments XXX Check for failure XXX */
2696         ast_copy_string(info, (char *) data, sizeof(info));
2697         queuename = strsep(&info_ptr, "|");
2698         options = strsep(&info_ptr, "|");
2699         url = strsep(&info_ptr, "|");
2700         announceoverride = strsep(&info_ptr, "|");
2701         queuetimeoutstr = info_ptr;
2702
2703         /* set the expire time based on the supplied timeout; */
2704         if (queuetimeoutstr)
2705                 qe.expire = qe.start + atoi(queuetimeoutstr);
2706         else
2707                 qe.expire = 0;
2708
2709         /* Get the priority from the variable ${QUEUE_PRIO} */
2710         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2711         if (user_priority) {
2712                 if (sscanf(user_priority, "%d", &prio) == 1) {
2713                         if (option_debug)
2714                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2715                                         chan->name, prio);
2716                 } else {
2717                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2718                                 user_priority, chan->name);
2719                         prio = 0;
2720                 }
2721         } else {
2722                 if (option_debug > 2)
2723                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2724                 prio = 0;
2725         }
2726
2727         if (options && (strchr(options, 'r')))
2728                 ringing = 1;
2729
2730         if (option_debug)  
2731                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2732                         queuename, options, url, announceoverride, (long)qe.expire, (int)prio);
2733
2734         qe.chan = chan;
2735         qe.prio = (int)prio;
2736         qe.last_pos_said = 0;
2737         qe.last_pos = 0;
2738         if (!join_queue(queuename, &qe, &reason)) {
2739                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
2740                               chan->cid.cid_num ? chan->cid.cid_num : "");
2741 check_turns:
2742                 if (ringing) {
2743                         ast_indicate(chan, AST_CONTROL_RINGING);
2744                 } else {              
2745                         ast_moh_start(chan, qe.moh);
2746                 }
2747                 for (;;) {
2748                         /* This is the wait loop for callers 2 through maxlen */
2749
2750                         res = wait_our_turn(&qe, ringing, &reason);
2751                         /* If they hungup, return immediately */
2752                         if (res < 0) {
2753                                 /* Record this abandoned call */
2754                                 record_abandoned(&qe);
2755                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2756                                 if (option_verbose > 2) {
2757                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2758                                         res = -1;
2759                                 }
2760                                 break;
2761                         }
2762                         if (!res) 
2763                                 break;
2764                         if (valid_exit(&qe, res)) {
2765                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2766                                 break;
2767                         }
2768                 }
2769                 if (!res) {
2770                         int makeannouncement = 0;
2771                         for (;;) {
2772                                 /* This is the wait loop for the head caller*/
2773                                 /* To exit, they may get their call answered; */
2774                                 /* they may dial a digit from the queue context; */
2775                                 /* or, they may timeout. */
2776
2777                                 enum queue_member_status stat;
2778
2779                                 /* Leave if we have exceeded our queuetimeout */
2780                                 if (qe.expire && (time(NULL) > qe.expire)) {
2781                                         record_abandoned(&qe);
2782                                         reason = QUEUE_TIMEOUT;
2783                                         res = 0;
2784                                         break;
2785                                 }
2786
2787                                 if (makeannouncement) {
2788                                         /* Make a position announcement, if enabled */
2789                                         if (qe.parent->announcefrequency && !ringing)
2790                                                 res = say_position(&qe);
2791                                         if (res && valid_exit(&qe, res)) {
2792                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2793                                                 break;
2794                                         }
2795
2796                                 }
2797                                 makeannouncement = 1;
2798
2799                                 /* Try calling all queue members for 'timeout' seconds */
2800                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
2801                                 if (res) {
2802                                         if (res < 0) {
2803                                                 if (!qe.handled)
2804                                                         record_abandoned(&qe);
2805                                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2806                                         } else if (res > 0)
2807                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2808                                         break;
2809                                 }
2810
2811                                 stat = get_member_status(qe.parent);
2812
2813                                 /* leave the queue if no agents, if enabled */
2814                                 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2815                                         record_abandoned(&qe);
2816                                         reason = QUEUE_LEAVEEMPTY;
2817                                         res = 0;
2818                                         break;
2819                                 }
2820
2821                                 /* leave the queue if no reachable agents, if enabled */
2822                                 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2823                                         record_abandoned(&qe);
2824                                         reason = QUEUE_LEAVEUNAVAIL;
2825                                         res = 0;
2826                                         break;
2827                                 }
2828
2829                                 /* Leave if we have exceeded our queuetimeout */
2830                                 if (qe.expire && (time(NULL) > qe.expire)) {
2831                                         record_abandoned(&qe);
2832                                         reason = QUEUE_TIMEOUT;
2833                                         res = 0;
2834                                         break;
2835                                 }
2836
2837                                 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
2838                                 res = wait_a_bit(&qe);
2839                                 if (res < 0) {
2840                                         record_abandoned(&qe);
2841                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2842                                         if (option_verbose > 2) {
2843                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
2844                                                 res = -1;
2845                                         }
2846                                         break;
2847                                 }
2848                                 if (res && valid_exit(&qe, res)) {
2849                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2850                                         break;
2851                                 }
2852                                 /* exit after 'timeout' cycle if 'n' option enabled */
2853                                 if (go_on) {
2854                                         if (option_verbose > 2) {
2855                                                 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
2856                                                 res = -1;
2857                                         }
2858                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2859                                         record_abandoned(&qe);
2860                                         reason = QUEUE_TIMEOUT;
2861                                         res = 0;
2862                                         break;
2863                                 }
2864                                 /* Since this is a priority queue and 
2865                                  * it is not sure that we are still at the head
2866                                  * of the queue, go and check for our turn again.
2867                                  */
2868                                 if (!is_our_turn(&qe)) {
2869                                         if (option_debug)
2870                                                 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
2871                                                                 qe.chan->name);
2872                                         goto check_turns;
2873                                 }
2874                         }
2875                 }
2876                 /* Don't allow return code > 0 */
2877                 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
2878                         res = 0;        
2879                         if (ringing) {
2880                                 ast_indicate(chan, -1);
2881                         } else {
2882                                 ast_moh_stop(chan);
2883                         }                       
2884                         ast_stopstream(chan);
2885                 }
2886                 leave_queue(&qe);
2887                 if (reason != QUEUE_UNKNOWN)
2888                         set_queue_result(chan, reason);
2889         } else {
2890                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
2891                 set_queue_result(chan, reason);
2892                 res = 0;
2893         }
2894         LOCAL_USER_REMOVE(u);
2895         return res;
2896 }
2897
2898 static void reload_queues(void)
2899 {
2900         struct ast_call_queue *q, *ql, *qn;
2901         struct ast_config *cfg;
2902         char *cat, *tmp;
2903         struct ast_variable *var;
2904         struct member *prev, *cur;
2905         int new;
2906         char *general_val = NULL;
2907         char interface[80];
2908         int penalty;
2909         
2910         cfg = ast_config_load("queues.conf");
2911         if (!cfg) {
2912                 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
2913                 return;
2914         }
2915         memset(interface, 0, sizeof(interface));
2916         ast_mutex_lock(&qlock);
2917         use_weight=0;
2918         /* Mark all queues as dead for the moment */
2919         q = queues;
2920         while(q) {
2921                 q->dead = 1;
2922                 q = q->next;
2923         }
2924         /* Chug through config file */
2925         cat = ast_category_browse(cfg, NULL);
2926         while(cat) {
2927                 if (!strcasecmp(cat, "general")) {      
2928                         /* Initialize global settings */
2929                         queue_persistent_members = 0;
2930                         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
2931                                 queue_persistent_members = ast_true(general_val);
2932                 } else {        /* Define queue */
2933                         /* Look for an existing one */
2934                         q = queues;
2935                         while(q) {
2936                                 if (!strcmp(q->name, cat))
2937                                         break;
2938                                 q = q->next;
2939                         }
2940                         if (!q) {
2941                                 /* Make one then */
2942                                 q = alloc_queue(cat);
2943                                 new = 1;
2944                         } else
2945                                 new = 0;
2946                         if (q) {
2947                                 if (!new)
2948                                         ast_mutex_lock(&q->lock);
2949                                 /* Re-initialize the queue, and clear statistics */
2950                                 init_queue(q);
2951                                 clear_queue(q);
2952                                 free_members(q, 0);
2953                                 prev = q->members;
2954                                 if (prev) {
2955                                         /* find the end of any dynamic members */
2956                                         while(prev->next)
2957                                                 prev = prev->next;
2958                                 }
2959                                 var = ast_variable_browse(cfg, cat);
2960                                 while(var) {
2961                                         if (!strcasecmp(var->name, "member")) {
2962                                                 /* Add a new member */
2963                                                 ast_copy_string(interface, var->value, sizeof(interface));
2964                                                 if ((tmp = strchr(interface, ','))) {
2965                                                         *tmp = '\0';
2966                                                         tmp++;
2967                                                         penalty = atoi(tmp);
2968                                                         if (penalty < 0) {
2969                                                                 penalty = 0;
2970                                                         }
2971                                                 } else
2972                                                         penalty = 0;
2973                                                 cur = create_queue_member(interface, penalty, 0);
2974                                                 if (cur) {
2975                                                         if (prev)
2976                                                                 prev->next = cur;
2977                                                         else
2978                                                                 q->members = cur;
2979                                                         prev = cur;
2980                                                 }
2981                                         } else {
2982                                                 queue_set_param(q, var->name, var->value, var->lineno, 1);
2983                                         }
2984                                         var = var->next;
2985                                 }
2986                                 if (!new) 
2987                                         ast_mutex_unlock(&q->lock);
2988                                 if (new) {
2989                                         q->next = queues;
2990                                         queues = q;
2991                                 }
2992                         }
2993                 }
2994                 cat = ast_category_browse(cfg, cat);
2995         }
2996         ast_config_destroy(cfg);
2997         q = queues;
2998         ql = NULL;
2999         while(q) {
3000                 qn = q->next;
3001                 if (q->dead) {
3002                         if (ql)
3003                                 ql->next = q->next;
3004                         else
3005                                 queues = q->next;
3006                         if (!q->count) {
3007                                 free(q);
3008                         } else
3009                                 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
3010                 } else {
3011                         for (cur = q->members; cur; cur = cur->next)
3012                                 cur->status = ast_device_state(cur->interface);
3013                         ql = q;
3014                 }
3015                 q = qn;
3016         }
3017         ast_mutex_unlock(&qlock);
3018 }
3019
3020 static char *status2str(int status, char *buf, int buflen)
3021 {
3022         switch(status) {
3023         case AST_DEVICE_UNKNOWN:
3024                 ast_copy_string(buf, "available", buflen);
3025                 break;
3026         case AST_DEVICE_NOT_INUSE:
3027                 ast_copy_string(buf, "notinuse", buflen);
3028                 break;
3029         case AST_DEVICE_INUSE:
3030                 ast_copy_string(buf, "inuse", buflen);
3031                 break;
3032         case AST_DEVICE_BUSY:
3033                 ast_copy_string(buf, "busy", buflen);
3034                 break;
3035         case AST_DEVICE_INVALID:
3036                 ast_copy_string(buf, "invalid", buflen);
3037                 break;
3038         case AST_DEVICE_UNAVAILABLE:
3039                 ast_copy_string(buf, "unavailable", buflen);
3040                 break;
3041         default:
3042                 snprintf(buf, buflen, "unknown status %d", status);
3043         }
3044         return buf;
3045 }
3046
3047 static int __queues_show(int fd, int argc, char **argv, int queue_show)
3048 {
3049         struct ast_call_queue *q;
3050         struct queue_ent *qe;
3051         struct member *mem;
3052         int pos;
3053         time_t now;
3054         char max[80] = "";
3055         char calls[80] = "";
3056         char tmpbuf[80] = "";
3057         float sl = 0;
3058
3059         time(&now);
3060         if ((!queue_show && argc != 2) || (queue_show && argc != 3))
3061                 return RESULT_SHOWUSAGE;
3062         ast_mutex_lock(&qlock);
3063         q = queues;
3064         if (!q) {       
3065                 ast_mutex_unlock(&qlock);
3066                 if (queue_show)
3067                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
3068                 else
3069                         ast_cli(fd, "No queues.\n");
3070                 return RESULT_SUCCESS;
3071         }
3072         while(q) {
3073                 ast_mutex_lock(&q->lock);
3074                 if (queue_show) {
3075                         if (strcasecmp(q->name, argv[2]) != 0) {
3076                                 ast_mutex_unlock(&q->lock);
3077                                 q = q->next;
3078                                 if (!q) {
3079                                         ast_cli(fd, "No such queue: %s.\n",argv[2]);
3080                                         break;
3081                                 }
3082                                 continue;
3083                         }
3084                 }
3085                 if (q->maxlen)
3086                         snprintf(max, sizeof(max), "%d", q->maxlen);
3087                 else
3088                         ast_copy_string(max, "unlimited", sizeof(max));
3089                 sl = 0;
3090                 if(q->callscompleted > 0)
3091                         sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
3092                 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",
3093                         q->name, q->count, max, int2strat(q->strategy), q->holdtime, q->weight, q->callscompleted, q->callsabandoned,sl,q->servicelevel);
3094                 if (q->members) {
3095                         ast_cli(fd, "   Members: \n");
3096                         for (mem = q->members; mem; mem = mem->next) {
3097                                 if (mem->penalty)
3098                                         snprintf(max, sizeof(max) - 20, " with penalty %d", mem->penalty);
3099                                 else
3100                                         max[0] = '\0';
3101                                 if (mem->dynamic)
3102                                         strncat(max, " (dynamic)", sizeof(max) - strlen(max) - 1);
3103                                 if (mem->paused)
3104                                         strncat(max, " (paused)", sizeof(max) - strlen(max) - 1);
3105                                         snprintf(max + strlen(max), sizeof(max) - strlen(max), " (%s)", status2str(mem->status, tmpbuf, sizeof(tmpbuf)));
3106                                 if (mem->calls) {
3107                                         snprintf(calls, sizeof(calls), " has taken %d calls (last was %ld secs ago)",
3108                                                         mem->calls, (long)(time(NULL) - mem->lastcall));
3109                                 } else
3110                                         ast_copy_string(calls, " has taken no calls yet", sizeof(calls));
3111                                 ast_cli(fd, "      %s%s%s\n", mem->interface, max, calls);
3112                         }
3113                 } else
3114                         ast_cli(fd, "   No Members\n");
3115                 if (q->head) {
3116                         pos = 1;
3117                         ast_cli(fd, "   Callers: \n");
3118                         for (qe = q->head; qe; qe = qe->next) 
3119                                 ast_cli(fd, "      %d. %s (wait: %ld:%2.2ld, prio: %d)\n", pos++, qe->chan->name,
3120                                                                 (long)(now - qe->start) / 60, (long)(now - qe->start) % 60, qe->prio);
3121                 } else
3122                         ast_cli(fd, "   No Callers\n");
3123                 ast_cli(fd, "\n");
3124                 ast_mutex_unlock(&q->lock);
3125                 q = q->next;
3126                 if (queue_show)
3127                         break;
3128         }
3129         ast_mutex_unlock(&qlock);
3130         return RESULT_SUCCESS;
3131 }
3132
3133 static int queues_show(int fd, int argc, char **argv)
3134 {
3135         return __queues_show(fd, argc, argv, 0);
3136 }
3137
3138 static int queue_show(int fd, int argc, char **argv)
3139 {
3140         return __queues_show(fd, argc, argv, 1);
3141 }
3142
3143 static char *complete_queue(char *line, char *word, int pos, int state)
3144 {
3145         struct ast_call_queue *q;
3146         int which=0;
3147         
3148         ast_mutex_lock(&qlock);
3149         for (q = queues; q; q = q->next) {
3150                 if (!strncasecmp(word, q->name, strlen(word))) {
3151                         if (++which > state)
3152                                 break;
3153                 }
3154         }
3155         ast_mutex_unlock(&qlock);
3156         return q ? strdup(q->name) : NULL;
3157 }
3158
3159 /* JDG: callback to display queues status in manager */
3160 static int manager_queues_show( struct mansession *s, struct message *m )
3161 {
3162         char *a[] = { "show", "queues" };
3163         ast_mutex_lock(&s->lock);
3164         queues_show(s->fd, 2, a);
3165         ast_cli(s->fd, "\r\n\r\n");     /* Properly terminate Manager output */
3166         ast_mutex_unlock(&s->lock);
3167
3168         return RESULT_SUCCESS;
3169
3170
3171 /* Dump queue status */
3172 static int manager_queues_status( struct mansession *s, struct message *m )
3173 {
3174         time_t now;
3175         int pos;
3176         char *id = astman_get_header(m,"ActionID");
3177         char *queuefilter = astman_get_header(m,"Queue");
3178         char *memberfilter = astman_get_header(m,"Member");
3179         char idText[256] = "";
3180         struct ast_call_queue *q;
3181         struct queue_ent *qe;
3182         float sl = 0;
3183         struct member *mem;
3184
3185         astman_send_ack(s, m, "Queue status will follow");
3186         time(&now);
3187         ast_mutex_lock(&qlock);
3188         if (!ast_strlen_zero(id)) {
3189                 snprintf(idText,256,"ActionID: %s\r\n",id);
3190         }
3191         for (q = queues; q; q = q->next) {
3192                 ast_mutex_lock(&q->lock);
3193
3194                 /* List queue properties */
3195                 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
3196                         if(q->callscompleted > 0)
3197                                 sl = 100*((float)q->callscompletedinsl/(float)q->callscompleted);
3198                         ast_mutex_lock(&s->lock);
3199                         ast_cli(s->fd, "Event: QueueParams\r\n"
3200                                                 "Queue: %s\r\n"
3201                                                 "Max: %d\r\n"
3202                                                 "Calls: %d\r\n"
3203                                                 "Holdtime: %d\r\n"
3204                                                 "Completed: %d\r\n"
3205                                                 "Abandoned: %d\r\n"
3206                                                 "ServiceLevel: %d\r\n"
3207                                                 "ServicelevelPerf: %2.1f\r\n"
3208                                                 "Weight: %d\r\n"
3209                                                 "%s"
3210                                                 "\r\n",
3211                                                         q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
3212                                                         q->callsabandoned, q->servicelevel, sl, q->weight, idText);
3213                         /* List Queue Members */
3214                         for (mem = q->members; mem; mem = mem->next) {
3215                                 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
3216                                         ast_cli(s->fd, "Event: QueueMember\r\n"
3217                                                 "Queue: %s\r\n"
3218                                                 "Location: %s\r\n"
3219                                                 "Membership: %s\r\n"
3220                                                 "Penalty: %d\r\n"
3221                                                 "CallsTaken: %d\r\n"
3222                                                 "LastCall: %ld\r\n"
3223                                                 "Status: %d\r\n"
3224                                                 "Paused: %d\r\n"
3225                                                 "%s"
3226                                                 "\r\n",
3227                                                         q->name, mem->interface, mem->dynamic ? "dynamic" : "static",
3228                                                         mem->penalty, mem->calls, mem->lastcall, mem->status, mem->paused, idText);
3229                                 }
3230                         }
3231                         /* List Queue Entries */
3232                         pos = 1;
3233                         for (qe = q->head; qe; qe = qe->next) {
3234                                 ast_cli(s->fd, "Event: QueueEntry\r\n"
3235                                         "Queue: %s\r\n"
3236                                         "Position: %d\r\n"</