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