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