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