ab4b2af976abc1885ebc24d4c267a267009cfccc
[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         if ((sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) {
519                 sc->state = state;
520                 strcpy(sc->dev, dev);
521                 pthread_attr_init(&attr);
522                 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
523                 if (ast_pthread_create(&t, &attr, changethread, sc)) {
524                         ast_log(LOG_WARNING, "Failed to create update thread!\n");
525                         free(sc);
526                 }
527         }
528         return 0;
529 }
530
531 static struct member *create_queue_member(char *interface, int penalty, int paused)
532 {
533         struct member *cur;
534         
535         /* Add a new member */
536
537         if ((cur = ast_calloc(1, sizeof(*cur)))) {
538                 cur->penalty = penalty;
539                 cur->paused = paused;
540                 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
541                 if (!strchr(cur->interface, '/'))
542                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
543                 cur->status = ast_device_state(interface);
544         }
545
546         return cur;
547 }
548
549 static struct ast_call_queue *alloc_queue(const char *queuename)
550 {
551         struct ast_call_queue *q;
552
553         if ((q = ast_calloc(1, sizeof(*q)))) {
554                 ast_mutex_init(&q->lock);
555                 ast_copy_string(q->name, queuename, sizeof(q->name));
556         }
557         return q;
558 }
559
560 static void init_queue(struct ast_call_queue *q)
561 {
562         q->dead = 0;
563         q->retry = DEFAULT_RETRY;
564         q->timeout = -1;
565         q->maxlen = 0;
566         q->announcefrequency = 0;
567         q->announceholdtime = 0;
568         q->roundingseconds = 0; /* Default - don't announce seconds */
569         q->servicelevel = 0;
570         q->moh[0] = '\0';
571         q->announce[0] = '\0';
572         q->context[0] = '\0';
573         q->monfmt[0] = '\0';
574         q->periodicannouncefrequency = 0;
575         ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
576         ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
577         ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
578         ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
579         ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
580         ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
581         ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
582         ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
583         ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
584         ast_copy_string(q->sound_periodicannounce, "queue-periodic-announce", sizeof(q->sound_periodicannounce));
585 }
586
587 static void clear_queue(struct ast_call_queue *q)
588 {
589         q->holdtime = 0;
590         q->callscompleted = 0;
591         q->callsabandoned = 0;
592         q->callscompletedinsl = 0;
593         q->wrapuptime = 0;
594 }
595
596 /*! \brief Configure a queue parameter.
597 \par
598    For error reporting, line number is passed for .conf static configuration.
599    For Realtime queues, linenum is -1.
600    The failunknown flag is set for config files (and static realtime) to show
601    errors for unknown parameters. It is cleared for dynamic realtime to allow
602    extra fields in the tables. */
603 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
604 {
605         if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
606                 ast_copy_string(q->moh, val, sizeof(q->moh));
607         } else if (!strcasecmp(param, "announce")) {
608                 ast_copy_string(q->announce, val, sizeof(q->announce));
609         } else if (!strcasecmp(param, "context")) {
610                 ast_copy_string(q->context, val, sizeof(q->context));
611         } else if (!strcasecmp(param, "timeout")) {
612                 q->timeout = atoi(val);
613                 if (q->timeout < 0)
614                         q->timeout = DEFAULT_TIMEOUT;
615         } else if (!strcasecmp(param, "monitor-join")) {
616                 q->monjoin = ast_true(val);
617         } else if (!strcasecmp(param, "monitor-format")) {
618                 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
619         } else if (!strcasecmp(param, "queue-youarenext")) {
620                 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
621         } else if (!strcasecmp(param, "queue-thereare")) {
622                 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
623         } else if (!strcasecmp(param, "queue-callswaiting")) {
624                 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
625         } else if (!strcasecmp(param, "queue-holdtime")) {
626                 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
627         } else if (!strcasecmp(param, "queue-minutes")) {
628                 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
629         } else if (!strcasecmp(param, "queue-seconds")) {
630                 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
631         } else if (!strcasecmp(param, "queue-lessthan")) {
632                 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
633         } else if (!strcasecmp(param, "queue-thankyou")) {
634                 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
635         } else if (!strcasecmp(param, "queue-reporthold")) {
636                 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
637         } else if (!strcasecmp(param, "announce-frequency")) {
638                 q->announcefrequency = atoi(val);
639         } else if (!strcasecmp(param, "announce-round-seconds")) {
640                 q->roundingseconds = atoi(val);
641                 if (q->roundingseconds>60 || q->roundingseconds<0) {
642                         if (linenum >= 0) {
643                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
644                                         "using 0 instead for queue '%s' at line %d of queues.conf\n",
645                                         val, param, q->name, linenum);
646                         } else {
647                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
648                                         "using 0 instead for queue '%s'\n", val, param, q->name);
649                         }
650                         q->roundingseconds=0;
651                 }
652         } else if (!strcasecmp(param, "announce-holdtime")) {
653                 if (!strcasecmp(val, "once"))
654                         q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
655                 else if (ast_true(val))
656                         q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
657                 else
658                         q->announceholdtime = 0;
659          } else if (!strcasecmp(param, "periodic-announce")) {
660                 ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce));
661         } else if (!strcasecmp(param, "periodic-announce-frequency")) {
662                 q->periodicannouncefrequency = atoi(val);
663         } else if (!strcasecmp(param, "retry")) {
664                 q->retry = atoi(val);
665                 if (q->retry < 0)
666                         q->retry = DEFAULT_RETRY;
667         } else if (!strcasecmp(param, "wrapuptime")) {
668                 q->wrapuptime = atoi(val);
669         } else if (!strcasecmp(param, "maxlen")) {
670                 q->maxlen = atoi(val);
671                 if (q->maxlen < 0)
672                         q->maxlen = 0;
673         } else if (!strcasecmp(param, "servicelevel")) {
674                 q->servicelevel= atoi(val);
675         } else if (!strcasecmp(param, "strategy")) {
676                 q->strategy = strat2int(val);
677                 if (q->strategy < 0) {
678                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
679                                 val, q->name);
680                         q->strategy = 0;
681                 }
682         } else if (!strcasecmp(param, "joinempty")) {
683                 if (!strcasecmp(val, "strict"))
684                         q->joinempty = QUEUE_EMPTY_STRICT;
685                 else if (ast_true(val))
686                         q->joinempty = QUEUE_EMPTY_NORMAL;
687                 else
688                         q->joinempty = 0;
689         } else if (!strcasecmp(param, "leavewhenempty")) {
690                 if (!strcasecmp(val, "strict"))
691                         q->leavewhenempty = QUEUE_EMPTY_STRICT;
692                 else if (ast_true(val))
693                         q->leavewhenempty = QUEUE_EMPTY_NORMAL;
694                 else
695                         q->leavewhenempty = 0;
696         } else if (!strcasecmp(param, "eventmemberstatus")) {
697                 q->maskmemberstatus = !ast_true(val);
698         } else if (!strcasecmp(param, "eventwhencalled")) {
699                 q->eventwhencalled = ast_true(val);
700         } else if (!strcasecmp(param, "reportholdtime")) {
701                 q->reportholdtime = ast_true(val);
702         } else if (!strcasecmp(param, "memberdelay")) {
703                 q->memberdelay = atoi(val);
704         } else if (!strcasecmp(param, "weight")) {
705                 q->weight = atoi(val);
706                 if (q->weight)
707                         use_weight++;
708                 /* With Realtime queues, if the last queue using weights is deleted in realtime,
709                    we will not see any effect on use_weight until next reload. */
710         } else if (!strcasecmp(param, "timeoutrestart")) {
711                 q->timeoutrestart = ast_true(val);
712         } else if(failunknown) {
713                 if (linenum >= 0) {
714                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
715                                 q->name, param, linenum);
716                 } else {
717                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
718                 }
719         }
720 }
721
722 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
723 {
724         struct member *m, *prev_m;
725         int penalty = 0;
726
727         if(penalty_str) {
728                 penalty = atoi(penalty_str);
729                 if(penalty < 0)
730                         penalty = 0;
731         }
732
733         /* Find the member, or the place to put a new one. */
734         prev_m = NULL;
735         m = q->members;
736         while (m && strcmp(m->interface, interface)) {
737                 prev_m = m;
738                 m = m->next;
739         }
740
741         /* Create a new one if not found, else update penalty */
742         if (!m) {
743                 m = create_queue_member(interface, penalty, 0);
744                 if (m) {
745                         m->dead = 0;
746                         if (prev_m) {
747                                 prev_m->next = m;
748                         } else {
749                                 q->members = m;
750                         }
751                 }
752         } else {
753                 m->dead = 0;    /* Do not delete this one. */
754                 m->penalty = penalty;
755         }
756 }
757
758
759 /*!\brief Reload a single queue via realtime.
760    \return Return the queue, or NULL if it doesn't exist.
761    \note Should be called with the global qlock locked.
762    When found, the queue is returned with q->lock locked. */
763 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
764 {
765         struct ast_variable *v;
766         struct ast_call_queue *q, *prev_q;
767         struct member *m, *prev_m, *next_m;
768         char *interface;
769         char *tmp, *tmp_name;
770         char tmpbuf[64];        /* Must be longer than the longest queue param name. */
771
772         /* Find the queue in the in-core list (we will create a new one if not found). */
773         q = queues;
774         prev_q = NULL;
775         while (q) {
776                 if (!strcasecmp(q->name, queuename)) {
777                         break;
778                 }
779                 q = q->next;
780                 prev_q = q;
781         }
782
783         /* Static queues override realtime. */
784         if (q) {
785                 ast_mutex_lock(&q->lock);
786                 if (!q->realtime) {
787                         if (q->dead) {
788                                 ast_mutex_unlock(&q->lock);
789                                 return NULL;
790                         } else {
791                                 return q;
792                         }
793                 }
794         } else if (!member_config)
795                 /* Not found in the list, and it's not realtime ... */
796                 return NULL;
797
798         /* Check if queue is defined in realtime. */
799         if (!queue_vars) {
800                 /* Delete queue from in-core list if it has been deleted in realtime. */
801                 if (q) {
802                         /*! \note Hmm, can't seem to distinguish a DB failure from a not
803                            found condition... So we might delete an in-core queue
804                            in case of DB failure. */
805                         ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
806
807                         q->dead = 1;
808                         /* Delete if unused (else will be deleted when last caller leaves). */
809                         if (!q->count) {
810                                 /* Delete. */
811                                 if (!prev_q) {
812                                         queues = q->next;
813                                 } else {
814                                         prev_q->next = q->next;
815                                 }
816                                 ast_mutex_unlock(&q->lock);
817                                 free(q);
818                         } else
819                                 ast_mutex_unlock(&q->lock);
820                 }
821                 return NULL;
822         }
823
824         /* Create a new queue if an in-core entry does not exist yet. */
825         if (!q) {
826                 if (!(q = alloc_queue(queuename)))
827                         return NULL;
828                 ast_mutex_lock(&q->lock);
829                 clear_queue(q);
830                 q->realtime = 1;
831                 q->next = queues;
832                 queues = q;
833         }
834         init_queue(q);          /* Ensure defaults for all parameters not set explicitly. */
835
836         v = queue_vars;
837         memset(tmpbuf, 0, sizeof(tmpbuf));
838         while(v) {
839                 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
840                 if((tmp = strchr(v->name, '_')) != NULL) {
841                         ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
842                         tmp_name = tmpbuf;
843                         tmp = tmp_name;
844                         while((tmp = strchr(tmp, '_')) != NULL)
845                                 *tmp++ = '-';
846                 } else
847                         tmp_name = v->name;
848                 queue_set_param(q, tmp_name, v->value, -1, 0);
849                 v = v->next;
850         }
851
852         /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
853         m = q->members;
854         while (m) {
855                 if (!m->dynamic)
856                         m->dead = 1;
857                 m = m->next;
858         }
859
860         interface = ast_category_browse(member_config, NULL);
861         while (interface) {
862                 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
863                 interface = ast_category_browse(member_config, interface);
864         }
865
866         /* Delete all realtime members that have been deleted in DB. */
867         m = q->members;
868         prev_m = NULL;
869         while (m) {
870                 next_m = m->next;
871                 if (m->dead) {
872                         if (prev_m) {
873                                 prev_m->next = next_m;
874                         } else {
875                                 q->members = next_m;
876                         }
877                         free(m);
878                 } else {
879                         prev_m = m;
880                 }
881                 m = next_m;
882         }
883
884         return q;
885 }
886
887 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
888 {
889         struct ast_variable *queue_vars = NULL;
890         struct ast_config *member_config = NULL;
891         struct ast_call_queue *q;
892         struct queue_ent *cur, *prev = NULL;
893         int res = -1;
894         int pos = 0;
895         int inserted = 0;
896         enum queue_member_status stat;
897
898         /*! \note Load from realtime before taking the global qlock, to avoid blocking all
899            queue operations while waiting for the DB.
900
901            This will be two separate database transactions, so we might
902            see queue parameters as they were before another process
903            changed the queue and member list as it was after the change.
904            Thus we might see an empty member list when a queue is
905            deleted. In practise, this is unlikely to cause a problem. */
906         queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
907         if (queue_vars) {
908                 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
909                 if (!member_config) {
910                         ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
911                         return res;
912                 }
913         }
914
915         ast_mutex_lock(&qlock);
916         q = find_queue_by_name_rt(queuename, queue_vars, member_config);
917         /* Note: If found, find_queue_by_name_rt() returns with q->lock locked. */
918         if(member_config)
919                 ast_config_destroy(member_config);
920         if(queue_vars)
921                 ast_variables_destroy(queue_vars);
922
923         if (!q) {
924                 ast_mutex_unlock(&qlock);
925                 return res;
926         }
927
928         /* This is our one */
929         stat = get_member_status(q, qe->max_penalty);
930         if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
931                 *reason = QUEUE_JOINEMPTY;
932         else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
933                 *reason = QUEUE_JOINUNAVAIL;
934         else if (q->maxlen && (q->count >= q->maxlen))
935                 *reason = QUEUE_FULL;
936         else {
937                 /* There's space for us, put us at the right position inside
938                  * the queue. 
939                  * Take into account the priority of the calling user */
940                 inserted = 0;
941                 prev = NULL;
942                 cur = q->head;
943                 while(cur) {
944                         /* We have higher priority than the current user, enter
945                          * before him, after all the other users with priority
946                          * higher or equal to our priority. */
947                         if ((!inserted) && (qe->prio > cur->prio)) {
948                                 insert_entry(q, prev, qe, &pos);
949                                 inserted = 1;
950                         }
951                         cur->pos = ++pos;
952                         prev = cur;
953                         cur = cur->next;
954                 }
955                 /* No luck, join at the end of the queue */
956                 if (!inserted)
957                         insert_entry(q, prev, qe, &pos);
958                 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
959                 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
960                 ast_copy_string(qe->context, q->context, sizeof(qe->context));
961                 q->count++;
962                 res = 0;
963                 manager_event(EVENT_FLAG_CALL, "Join", 
964                               "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
965                               qe->chan->name, 
966                               qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
967                               qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
968                               q->name, qe->pos, q->count );
969 #if 0
970 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
971 #endif
972         }
973         ast_mutex_unlock(&q->lock);
974         ast_mutex_unlock(&qlock);
975         return res;
976 }
977
978 static void free_members(struct ast_call_queue *q, int all)
979 {
980         /* Free non-dynamic members */
981         struct member *curm, *next, *prev;
982
983         curm = q->members;
984         prev = NULL;
985         while(curm) {
986                 next = curm->next;
987                 if (all || !curm->dynamic) {
988                         if (prev)
989                                 prev->next = next;
990                         else
991                                 q->members = next;
992                         free(curm);
993                 } else 
994                         prev = curm;
995                 curm = next;
996         }
997 }
998
999 static void destroy_queue(struct ast_call_queue *q)
1000 {
1001         struct ast_call_queue *cur, *prev = NULL;
1002
1003         ast_mutex_lock(&qlock);
1004         for (cur = queues; cur; cur = cur->next) {
1005                 if (cur == q) {
1006                         if (prev)
1007                                 prev->next = cur->next;
1008                         else
1009                                 queues = cur->next;
1010                 } else {
1011                         prev = cur;
1012                 }
1013         }
1014         ast_mutex_unlock(&qlock);
1015         free_members(q, 1);
1016         ast_mutex_destroy(&q->lock);
1017         free(q);
1018 }
1019
1020 static int play_file(struct ast_channel *chan, char *filename)
1021 {
1022         int res;
1023
1024         ast_stopstream(chan);
1025         res = ast_streamfile(chan, filename, chan->language);
1026
1027         if (!res)
1028                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1029         else
1030                 res = 0;
1031
1032         ast_stopstream(chan);
1033
1034         return res;
1035 }
1036
1037 static int valid_exit(struct queue_ent *qe, char digit)
1038 {
1039         int digitlen = strlen(qe->digits);
1040
1041         /* Prevent possible buffer overflow */
1042         if (digitlen < sizeof(qe->digits) - 2) {
1043                 qe->digits[digitlen] = digit;
1044                 qe->digits[digitlen + 1] = '\0';
1045         } else {
1046                 qe->digits[0] = '\0';
1047                 return 0;
1048         }
1049
1050         /* If there's no context to goto, short-circuit */
1051         if (ast_strlen_zero(qe->context))
1052                 return 0;
1053
1054         /* If the extension is bad, then reset the digits to blank */
1055         if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1056                 qe->digits[0] = '\0';
1057                 return 0;
1058         }
1059
1060         /* We have an exact match */
1061         if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1062                 /* Return 1 on a successful goto */
1063                 return 1;
1064         }
1065         return 0;
1066 }
1067
1068 static int say_position(struct queue_ent *qe)
1069 {
1070         int res = 0, avgholdmins, avgholdsecs;
1071         time_t now;
1072
1073         /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1074         time(&now);
1075         if ( (now - qe->last_pos) < 15 )
1076                 return 0;
1077
1078         /* If either our position has changed, or we are over the freq timer, say position */
1079         if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
1080                 return 0;
1081
1082         ast_moh_stop(qe->chan);
1083         /* Say we're next, if we are */
1084         if (qe->pos == 1) {
1085                 res = play_file(qe->chan, qe->parent->sound_next);
1086                 if (res && valid_exit(qe, res))
1087                         goto playout;
1088                 else
1089                         goto posout;
1090         } else {
1091                 res = play_file(qe->chan, qe->parent->sound_thereare);
1092                 if (res && valid_exit(qe, res))
1093                         goto playout;
1094                 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1095                 if (res && valid_exit(qe, res))
1096                         goto playout;
1097                 res = play_file(qe->chan, qe->parent->sound_calls);
1098                 if (res && valid_exit(qe, res))
1099                         goto playout;
1100         }
1101         /* Round hold time to nearest minute */
1102         avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
1103
1104         /* If they have specified a rounding then round the seconds as well */
1105         if(qe->parent->roundingseconds) {
1106                 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
1107                 avgholdsecs*= qe->parent->roundingseconds;
1108         } else {
1109                 avgholdsecs=0;
1110         }
1111
1112         if (option_verbose > 2)
1113                 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1114
1115         /* If the hold time is >1 min, if it's enabled, and if it's not
1116            supposed to be only once and we have already said it, say it */
1117         if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1118             (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1119                 res = play_file(qe->chan, qe->parent->sound_holdtime);
1120                 if (res && valid_exit(qe, res))
1121                         goto playout;
1122
1123                 if (avgholdmins>0) {
1124                         if (avgholdmins < 2) {
1125                                 res = play_file(qe->chan, qe->parent->sound_lessthan);
1126                                 if (res && valid_exit(qe, res))
1127                                         goto playout;
1128
1129                                 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1130                                 if (res && valid_exit(qe, res))
1131                                         goto playout;
1132                         } else {
1133                                 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1134                                 if (res && valid_exit(qe, res))
1135                                         goto playout;
1136                         }
1137                         
1138                         res = play_file(qe->chan, qe->parent->sound_minutes);
1139                         if (res && valid_exit(qe, res))
1140                                 goto playout;
1141                 }
1142                 if (avgholdsecs>0) {
1143                         res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1144                         if (res && valid_exit(qe, res))
1145                                 goto playout;
1146
1147                         res = play_file(qe->chan, qe->parent->sound_seconds);
1148                         if (res && valid_exit(qe, res))
1149                                 goto playout;
1150                 }
1151
1152         }
1153
1154  posout:
1155         if (option_verbose > 2)
1156                 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1157                             qe->chan->name, qe->parent->name, qe->pos);
1158         res = play_file(qe->chan, qe->parent->sound_thanks);
1159
1160  playout:
1161         /* Set our last_pos indicators */
1162         qe->last_pos = now;
1163         qe->last_pos_said = qe->pos;
1164         ast_moh_start(qe->chan, qe->moh);
1165
1166         return res;
1167 }
1168
1169 static void recalc_holdtime(struct queue_ent *qe)
1170 {
1171         int oldvalue, newvalue;
1172
1173         /* Calculate holdtime using a recursive boxcar filter */
1174         /* Thanks to SRT for this contribution */
1175         /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1176
1177         newvalue = time(NULL) - qe->start;
1178
1179         ast_mutex_lock(&qe->parent->lock);
1180         if (newvalue <= qe->parent->servicelevel)
1181                 qe->parent->callscompletedinsl++;
1182         oldvalue = qe->parent->holdtime;
1183         qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1184         ast_mutex_unlock(&qe->parent->lock);
1185 }
1186
1187
1188 static void leave_queue(struct queue_ent *qe)
1189 {
1190         struct ast_call_queue *q;
1191         struct queue_ent *cur, *prev = NULL;
1192         int pos = 0;
1193
1194         q = qe->parent;
1195         if (!q)
1196                 return;
1197         ast_mutex_lock(&q->lock);
1198
1199         prev = NULL;
1200         cur = q->head;
1201         while(cur) {
1202                 if (cur == qe) {
1203                         q->count--;
1204
1205                         /* Take us out of the queue */
1206                         manager_event(EVENT_FLAG_CALL, "Leave",
1207                                 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
1208                                 qe->chan->name, q->name,  q->count);
1209 #if 0
1210 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1211 #endif
1212                         /* Take us out of the queue */
1213                         if (prev)
1214                                 prev->next = cur->next;
1215                         else
1216                                 q->head = cur->next;
1217                 } else {
1218                         /* Renumber the people after us in the queue based on a new count */
1219                         cur->pos = ++pos;
1220                         prev = cur;
1221                 }
1222                 cur = cur->next;
1223         }
1224         ast_mutex_unlock(&q->lock);
1225         if (q->dead && !q->count) {     
1226                 /* It's dead and nobody is in it, so kill it */
1227                 destroy_queue(q);
1228         }
1229 }
1230
1231 /* Hang up a list of outgoing calls */
1232 static void hangupcalls(struct localuser *outgoing, struct ast_channel *exception)
1233 {
1234         struct localuser *oo;
1235
1236         while(outgoing) {
1237                 /* Hangup any existing lines we have open */
1238                 if (outgoing->chan && (outgoing->chan != exception))
1239                         ast_hangup(outgoing->chan);
1240                 oo = outgoing;
1241                 outgoing=outgoing->next;
1242                 free(oo);
1243         }
1244 }
1245
1246 static int update_status(struct ast_call_queue *q, struct member *member, int status)
1247 {
1248         struct member *cur;
1249
1250         /* Since a reload could have taken place, we have to traverse the list to
1251                 be sure it's still valid */
1252         ast_mutex_lock(&q->lock);
1253         cur = q->members;
1254         while(cur) {
1255                 if (member == cur) {
1256                         cur->status = status;
1257                         if (!q->maskmemberstatus) {
1258                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1259                                         "Queue: %s\r\n"
1260                                         "Location: %s\r\n"
1261                                         "Membership: %s\r\n"
1262                                         "Penalty: %d\r\n"
1263                                         "CallsTaken: %d\r\n"
1264                                         "LastCall: %d\r\n"
1265                                         "Status: %d\r\n"
1266                                         "Paused: %d\r\n",
1267                                 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1268                                 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1269                         }
1270                         break;
1271                 }
1272                 cur = cur->next;
1273         }
1274         ast_mutex_unlock(&q->lock);
1275         return 0;
1276 }
1277
1278 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
1279 {
1280         if (status == AST_CAUSE_BUSY)
1281                 status = AST_DEVICE_BUSY;
1282         else if (status == AST_CAUSE_UNREGISTERED)
1283                 status = AST_DEVICE_UNAVAILABLE;
1284         else if (status == AST_CAUSE_NOSUCHDRIVER)
1285                 status = AST_DEVICE_INVALID;
1286         else
1287                 status = AST_DEVICE_UNKNOWN;
1288         return update_status(q, member, status);
1289 }
1290
1291 /* traverse all defined queues which have calls waiting and contain this member
1292    return 0 if no other queue has precedence (higher weight) or 1 if found  */
1293 static int compare_weight(struct ast_call_queue *rq, struct member *member)
1294 {
1295         struct ast_call_queue *q;
1296         struct member *mem;
1297         int found = 0;
1298         
1299         /* &qlock and &rq->lock already set by try_calling()
1300          * to solve deadlock */
1301         for (q = queues; q; q = q->next) {
1302                 if (q == rq) /* don't check myself, could deadlock */
1303                         continue; 
1304                 ast_mutex_lock(&q->lock);
1305                 if (q->count && q->members) {
1306                         for (mem = q->members; mem; mem = mem->next) {
1307                                 if (!strcmp(mem->interface, member->interface)) {
1308                                         ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1309                                         if (q->weight > rq->weight) {
1310                                                 ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
1311                                                 found = 1;
1312                                                 break;
1313                                         }
1314                                 }
1315                         }
1316                 }
1317                 ast_mutex_unlock(&q->lock);
1318                 if (found) 
1319                         break;
1320         }
1321         return found;
1322 }
1323
1324 static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
1325 {
1326         int res;
1327         int status;
1328         char tech[256];
1329         char *location;
1330
1331         if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1332                 if (option_debug)
1333                         ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1334                 if (qe->chan->cdr)
1335                         ast_cdr_busy(qe->chan->cdr);
1336                 tmp->stillgoing = 0;
1337                 (*busies)++;
1338                 return 0;
1339         }
1340         
1341         if (tmp->member->paused) {
1342                 if (option_debug)
1343                         ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1344                 if (qe->chan->cdr)
1345                         ast_cdr_busy(qe->chan->cdr);
1346                 tmp->stillgoing = 0;
1347                 return 0;
1348         }
1349         if (use_weight && compare_weight(qe->parent,tmp->member)) {
1350                 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1351                 if (qe->chan->cdr)
1352                         ast_cdr_busy(qe->chan->cdr);
1353                 tmp->stillgoing = 0;
1354                 (*busies)++;
1355                 return 0;
1356         }
1357
1358         ast_copy_string(tech, tmp->interface, sizeof(tech));
1359         if ((location = strchr(tech, '/')))
1360                 *location++ = '\0';
1361         else
1362                 location = "";
1363
1364         /* Request the peer */
1365         tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1366         if (!tmp->chan) {                       /* If we can't, just go on to the next call */
1367 #if 0
1368                 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
1369 #endif                  
1370                 if (qe->chan->cdr)
1371                         ast_cdr_busy(qe->chan->cdr);
1372                 tmp->stillgoing = 0;
1373                 update_dial_status(qe->parent, tmp->member, status);
1374                 (*busies)++;
1375                 return 0;
1376         } else if (status != tmp->oldstatus) 
1377                 update_dial_status(qe->parent, tmp->member, status);
1378         
1379         tmp->chan->appl = "AppQueue";
1380         tmp->chan->data = "(Outgoing Line)";
1381         tmp->chan->whentohangup = 0;
1382         if (tmp->chan->cid.cid_num)
1383                 free(tmp->chan->cid.cid_num);
1384         tmp->chan->cid.cid_num = NULL;
1385         if (tmp->chan->cid.cid_name)
1386                 free(tmp->chan->cid.cid_name);
1387         tmp->chan->cid.cid_name = NULL;
1388         if (tmp->chan->cid.cid_ani)
1389                 free(tmp->chan->cid.cid_ani);
1390         tmp->chan->cid.cid_ani = NULL;
1391         if (qe->chan->cid.cid_num)
1392                 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
1393         if (qe->chan->cid.cid_name)
1394                 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
1395         if (qe->chan->cid.cid_ani)
1396                 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
1397
1398         /* Inherit specially named variables from parent channel */
1399         ast_channel_inherit_variables(qe->chan, tmp->chan);
1400
1401         /* Presense of ADSI CPE on outgoing channel follows ours */
1402         tmp->chan->adsicpe = qe->chan->adsicpe;
1403
1404         /* Place the call, but don't wait on the answer */
1405         res = ast_call(tmp->chan, location, 0);
1406         if (res) {
1407                 /* Again, keep going even if there's an error */
1408                 if (option_debug)
1409                         ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1410                 else if (option_verbose > 2)
1411                         ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1412                 ast_hangup(tmp->chan);
1413                 tmp->chan = NULL;
1414                 tmp->stillgoing = 0;
1415                 (*busies)++;
1416                 return 0;
1417         } else {
1418                 if (qe->parent->eventwhencalled) {
1419                         manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1420                                                 "AgentCalled: %s\r\n"
1421                                                 "ChannelCalling: %s\r\n"
1422                                                 "CallerID: %s\r\n"
1423                                                 "CallerIDName: %s\r\n"
1424                                                 "Context: %s\r\n"
1425                                                 "Extension: %s\r\n"
1426                                                 "Priority: %d\r\n",
1427                                                 tmp->interface, qe->chan->name,
1428                                                 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1429                                                 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1430                                                 qe->chan->context, qe->chan->exten, qe->chan->priority);
1431                 }
1432                 if (option_verbose > 2)
1433                         ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1434         }
1435         return 1;
1436 }
1437
1438 static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
1439 {
1440         struct localuser *cur;
1441         struct localuser *best;
1442         int bestmetric=0;
1443
1444         do {
1445                 best = NULL;
1446                 cur = outgoing;
1447                 while(cur) {
1448                         if (cur->stillgoing &&                                  /* Not already done */
1449                                 !cur->chan &&                                   /* Isn't already going */
1450                                 (!best || (cur->metric < bestmetric))) {        /* We haven't found one yet, or it's better */
1451                                         bestmetric = cur->metric;
1452                                         best = cur;
1453                         }
1454                         cur = cur->next;
1455                 }
1456                 if (best) {
1457                         if (!qe->parent->strategy) {
1458                                 /* Ring everyone who shares this best metric (for ringall) */
1459                                 cur = outgoing;
1460                                 while(cur) {
1461                                         if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
1462                                                 if (option_debug)
1463                                                         ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1464                                                 ring_entry(qe, cur, busies);
1465                                         }
1466                                         cur = cur->next;
1467                                 }
1468                         } else {
1469                                 /* Ring just the best channel */
1470                                 if (option_debug)
1471                                         ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1472                                 ring_entry(qe, best, busies);
1473                         }
1474                 }
1475         } while (best && !best->chan);
1476         if (!best) {
1477                 if (option_debug)
1478                         ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1479                 return 0;
1480         }
1481         return 1;
1482 }
1483
1484 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
1485 {
1486         struct localuser *cur;
1487         struct localuser *best;
1488         int bestmetric=0;
1489
1490         best = NULL;
1491         cur = outgoing;
1492         while(cur) {
1493                 if (cur->stillgoing &&                                  /* Not already done */
1494                         !cur->chan &&                                   /* Isn't already going */
1495                         (!best || (cur->metric < bestmetric))) {        /* We haven't found one yet, or it's better */
1496                                 bestmetric = cur->metric;
1497                                 best = cur;
1498                 }
1499                 cur = cur->next;
1500         }
1501         if (best) {
1502                 /* Ring just the best channel */
1503                 if (option_debug)
1504                         ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1505                 qe->parent->rrpos = best->metric % 1000;
1506         } else {
1507                 /* Just increment rrpos */
1508                 if (qe->parent->wrapped) {
1509                         /* No more channels, start over */
1510                         qe->parent->rrpos = 0;
1511                 } else {
1512                         /* Prioritize next entry */
1513                         qe->parent->rrpos++;
1514                 }
1515         }
1516         qe->parent->wrapped = 0;
1517         return 0;
1518 }
1519
1520 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1521 {
1522         int res;
1523
1524         ast_stopstream(chan);
1525         res = ast_streamfile(chan, filename, chan->language);
1526
1527         if (!res) {
1528                 /* Wait for a keypress */
1529                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1530                 if (res <= 0 || !valid_exit(qe, res))
1531                         res = 0;
1532
1533                 /* Stop playback */
1534                 ast_stopstream(chan);
1535         } else {
1536                 res = 0;
1537         }
1538         
1539         /*if (res) {
1540                 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
1541                 res = 0;
1542         }*/
1543
1544         return res;
1545 }
1546
1547 static int say_periodic_announcement(struct queue_ent *qe)
1548 {
1549         int res = 0;
1550         time_t now;
1551
1552         /* Get the current time */
1553         time(&now);
1554
1555         /* Check to see if it is time to announce */
1556         if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1557                 return 0;
1558
1559         /* Stop the music on hold so we can play our own file */
1560         ast_moh_stop(qe->chan);
1561
1562         if (option_verbose > 2)
1563                 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1564
1565         /* play the announcement */
1566         res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce);
1567
1568         /* Resume Music on Hold */
1569         ast_moh_start(qe->chan, qe->moh);
1570
1571         /* update last_periodic_announce_time */
1572         qe->last_periodic_announce_time = now;
1573
1574         return res;
1575 }
1576
1577 static void record_abandoned(struct queue_ent *qe)
1578 {
1579         ast_mutex_lock(&qe->parent->lock);
1580         qe->parent->callsabandoned++;
1581         ast_mutex_unlock(&qe->parent->lock);
1582 }
1583
1584
1585 #define AST_MAX_WATCHERS 256
1586
1587 #define BUILD_WATCHERS do { \
1588                 o = outgoing; \
1589                 found = -1; \
1590                 pos = 1; \
1591                 numlines = 0; \
1592                 watchers[0] = in; \
1593                 while(o) { \
1594                         /* Keep track of important channels */ \
1595                         if (o->stillgoing) { \
1596                                 stillgoing = 1; \
1597                                 if (o->chan) { \
1598                                         watchers[pos++] = o->chan; \
1599                                         found = 1; \
1600                                 } \
1601                         } \
1602                         o = o->next; \
1603                         numlines++; \
1604                 } \
1605         } while(0)
1606         
1607 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1608 {
1609         char *queue = qe->parent->name;
1610         struct localuser *o;
1611         int found;
1612         int numlines;
1613         int status;
1614         int sentringing = 0;
1615         int numbusies = prebusies;
1616         int numnochan = 0;
1617         int stillgoing = 0;
1618         int orig = *to;
1619         struct ast_frame *f;
1620         struct localuser *peer = NULL;
1621         struct ast_channel *watchers[AST_MAX_WATCHERS];
1622         int pos;
1623         struct ast_channel *winner;
1624         struct ast_channel *in = qe->chan;
1625         
1626         while(*to && !peer) {
1627                 BUILD_WATCHERS;
1628                 if ((found < 0) && stillgoing && !qe->parent->strategy) {
1629                         /* On "ringall" strategy we only move to the next penalty level
1630                            when *all* ringing phones are done in the current penalty level */
1631                         ring_one(qe, outgoing, &numbusies);
1632                         BUILD_WATCHERS;
1633                 }
1634                 if (found < 0) {
1635                         if (numlines == (numbusies + numnochan)) {
1636                                 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1637                         } else {
1638                                 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1639                         }
1640                         *to = 0;
1641                         return NULL;
1642                 }
1643                 winner = ast_waitfor_n(watchers, pos, to);
1644                 o = outgoing;
1645                 while(o) {
1646                         if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
1647                                 if (!peer) {
1648                                         if (option_verbose > 2)
1649                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1650                                         peer = o;
1651                                 }
1652                         } else if (o->chan && (o->chan == winner)) {
1653                                 if (!ast_strlen_zero(o->chan->call_forward)) {
1654                                         char tmpchan[256]="";
1655                                         char *stuff;
1656                                         char *tech;
1657                                         ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1658                                         if ((stuff = strchr(tmpchan, '/'))) {
1659                                                 *stuff = '\0';
1660                                                 stuff++;
1661                                                 tech = tmpchan;
1662                                         } else {
1663                                                 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1664                                                 stuff = tmpchan;
1665                                                 tech = "Local";
1666                                         }
1667                                         /* Before processing channel, go ahead and check for forwarding */
1668                                         if (option_verbose > 2)
1669                                                 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1670                                         /* Setup parameters */
1671                                         o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1672                                         if (status != o->oldstatus) 
1673                                                 update_dial_status(qe->parent, o->member, status);                                              
1674                                         if (!o->chan) {
1675                                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1676                                                 o->stillgoing = 0;
1677                                                 numnochan++;
1678                                         } else {
1679                                                 if (o->chan->cid.cid_num)
1680                                                         free(o->chan->cid.cid_num);
1681                                                 o->chan->cid.cid_num = NULL;
1682                                                 if (o->chan->cid.cid_name)
1683                                                         free(o->chan->cid.cid_name);
1684                                                 o->chan->cid.cid_name = NULL;
1685
1686                                                 if (in->cid.cid_num) {
1687                                                         o->chan->cid.cid_num = strdup(in->cid.cid_num);
1688                                                         if (!o->chan->cid.cid_num)
1689                                                                 ast_log(LOG_WARNING, "Out of memory\n");        
1690                                                 }
1691                                                 if (in->cid.cid_name) {
1692                                                         o->chan->cid.cid_name = strdup(in->cid.cid_name);
1693                                                         if (!o->chan->cid.cid_name)
1694                                                                 ast_log(LOG_WARNING, "Out of memory\n");        
1695                                                 }
1696                                                 ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
1697                                                 o->chan->cdrflags = in->cdrflags;
1698
1699                                                 if (in->cid.cid_ani) {
1700                                                         if (o->chan->cid.cid_ani)
1701                                                                 free(o->chan->cid.cid_ani);
1702                                                         if ((o->chan->cid.cid_ani = ast_calloc(1, strlen(in->cid.cid_ani) + 1)))
1703                                                                 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
1704                                                 }
1705                                                 if (o->chan->cid.cid_rdnis) 
1706                                                         free(o->chan->cid.cid_rdnis);
1707                                                 if (!ast_strlen_zero(in->macroexten))
1708                                                         o->chan->cid.cid_rdnis = strdup(in->macroexten);
1709                                                 else
1710                                                         o->chan->cid.cid_rdnis = strdup(in->exten);
1711                                                 if (ast_call(o->chan, tmpchan, 0)) {
1712                                                         ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1713                                                         o->stillgoing = 0;
1714                                                         ast_hangup(o->chan);
1715                                                         o->chan = NULL;
1716                                                         numnochan++;
1717                                                 }
1718                                         }
1719                                         /* Hangup the original channel now, in case we needed it */
1720                                         ast_hangup(winner);
1721                                         continue;
1722                                 }
1723                                 f = ast_read(winner);
1724                                 if (f) {
1725                                         if (f->frametype == AST_FRAME_CONTROL) {
1726                                                 switch(f->subclass) {
1727                                         case AST_CONTROL_ANSWER:
1728                                                         /* This is our guy if someone answered. */
1729                                                         if (!peer) {
1730                                                                 if (option_verbose > 2)
1731                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1732                                                                 peer = o;
1733                                                         }
1734                                                         break;
1735                                                 case AST_CONTROL_BUSY:
1736                                                         if (option_verbose > 2)
1737                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1738                                                         o->stillgoing = 0;
1739                                                         if (in->cdr)
1740                                                                 ast_cdr_busy(in->cdr);
1741                                                         ast_hangup(o->chan);
1742                                                         o->chan = NULL;
1743                                                         if (qe->parent->strategy) {
1744                                                                 if (qe->parent->timeoutrestart)
1745                                                                         *to = orig;
1746                                                                 ring_one(qe, outgoing, &numbusies);
1747                                                         }
1748                                                         numbusies++;
1749                                                         break;
1750                                                 case AST_CONTROL_CONGESTION:
1751                                                         if (option_verbose > 2)
1752                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1753                                                         o->stillgoing = 0;
1754                                                         if (in->cdr)
1755                                                                 ast_cdr_busy(in->cdr);
1756                                                         ast_hangup(o->chan);
1757                                                         o->chan = NULL;
1758                                                         if (qe->parent->strategy) {
1759                                                                 if (qe->parent->timeoutrestart)
1760                                                                         *to = orig;
1761                                                                 ring_one(qe, outgoing, &numbusies);
1762                                                         }
1763                                                         numbusies++;
1764                                                         break;
1765                                                 case AST_CONTROL_RINGING:
1766                                                         if (option_verbose > 2)
1767                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1768                                                         if (!sentringing) {
1769 #if 0
1770                                                                 ast_indicate(in, AST_CONTROL_RINGING);
1771 #endif                                                          
1772                                                                 sentringing++;
1773                                                         }
1774                                                         break;
1775                                                 case AST_CONTROL_OFFHOOK:
1776                                                         /* Ignore going off hook */
1777                                                         break;
1778                                                 default:
1779                                                         ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1780                                                 }
1781                                         }
1782                                         ast_frfree(f);
1783                                 } else {
1784                                         o->stillgoing = 0;
1785                                         ast_hangup(o->chan);
1786                                         o->chan = NULL;
1787                                         if (qe->parent->strategy) {
1788                                                 if (qe->parent->timeoutrestart)
1789                                                         *to = orig;
1790                                                 ring_one(qe, outgoing, &numbusies);
1791                                         }
1792                                 }
1793                         }
1794                         o = o->next;
1795                 }
1796                 if (winner == in) {
1797                         f = ast_read(in);
1798 #if 0
1799                         if (f && (f->frametype != AST_FRAME_VOICE))
1800                                         printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1801                         else if (!f || (f->frametype != AST_FRAME_VOICE))
1802                                 printf("Hangup received on %s\n", in->name);
1803 #endif
1804                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1805                                 /* Got hung up */
1806                                 *to=-1;
1807                                 if (f)
1808                                         ast_frfree(f);
1809                                 return NULL;
1810                         }
1811                         if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1812                                 if (option_verbose > 3)
1813                                         ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1814                                 *to=0;
1815                                 ast_frfree(f);
1816                                 return NULL;
1817                         }
1818                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1819                                 if (option_verbose > 3)
1820                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1821                                 *to=0;
1822                                 *digit=f->subclass;
1823                                 ast_frfree(f);
1824                                 return NULL;
1825                         }
1826                         ast_frfree(f);
1827                 }
1828                 if (!*to && (option_verbose > 2))
1829                         ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1830         }
1831
1832         return peer;
1833         
1834 }
1835
1836 static int is_our_turn(struct queue_ent *qe)
1837 {
1838         struct queue_ent *ch;
1839         int res;
1840
1841         /* Atomically read the parent head -- does not need a lock */
1842         ch = qe->parent->head;
1843         /* If we are now at the top of the head, break out */
1844         if (ch == qe) {
1845                 if (option_debug)
1846                         ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1847                 res = 1;
1848         } else {
1849                 if (option_debug)
1850                         ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1851                 res = 0;
1852         }
1853         return res;
1854 }
1855
1856 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1857 {
1858         int res = 0;
1859
1860         /* This is the holding pen for callers 2 through maxlen */
1861         for (;;) {
1862                 enum queue_member_status stat;
1863
1864                 if (is_our_turn(qe))
1865                         break;
1866
1867                 /* If we have timed out, break out */
1868                 if (qe->expire && (time(NULL) > qe->expire)) {
1869                         *reason = QUEUE_TIMEOUT;
1870                         ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
1871                         break;
1872                 }
1873
1874                 stat = get_member_status(qe->parent, qe->max_penalty);
1875
1876                 /* leave the queue if no agents, if enabled */
1877                 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1878                         *reason = QUEUE_LEAVEEMPTY;
1879                         leave_queue(qe);
1880                         break;
1881                 }
1882
1883                 /* leave the queue if no reachable agents, if enabled */
1884                 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1885                         *reason = QUEUE_LEAVEUNAVAIL;
1886                         leave_queue(qe);
1887                         break;
1888                 }
1889
1890                 /* Make a position announcement, if enabled */
1891                 if (qe->parent->announcefrequency && !ringing)
1892                         res = say_position(qe);
1893                 if (res)
1894                         break;
1895
1896                 /* Make a periodic announcement, if enabled */
1897                 if (qe->parent->periodicannouncefrequency && !ringing)
1898                         res = say_periodic_announcement(qe);
1899
1900                 /* Wait a second before checking again */
1901                 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1902                 if (res)
1903                         break;
1904         }
1905         return res;
1906 }
1907
1908 static int update_queue(struct ast_call_queue *q, struct member *member)
1909 {
1910         struct member *cur;
1911
1912         /* Since a reload could have taken place, we have to traverse the list to
1913                 be sure it's still valid */
1914         ast_mutex_lock(&q->lock);
1915         cur = q->members;
1916         while(cur) {
1917                 if (member == cur) {
1918                         time(&cur->lastcall);
1919                         cur->calls++;
1920                         break;
1921                 }
1922                 cur = cur->next;
1923         }
1924         q->callscompleted++;
1925         ast_mutex_unlock(&q->lock);
1926         return 0;
1927 }
1928
1929 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1930 {
1931         if (mem->penalty > qe->max_penalty)
1932                 return -1;
1933
1934         switch (q->strategy) {
1935         case QUEUE_STRATEGY_RINGALL:
1936                 /* Everyone equal, except for penalty */
1937                 tmp->metric = mem->penalty * 1000000;
1938                 break;
1939         case QUEUE_STRATEGY_ROUNDROBIN:
1940                 if (!pos) {
1941                         if (!q->wrapped) {
1942                                 /* No more channels, start over */
1943                                 q->rrpos = 0;
1944                         } else {
1945                                 /* Prioritize next entry */
1946                                 q->rrpos++;
1947                         }
1948                         q->wrapped = 0;
1949                 }
1950                 /* Fall through */
1951         case QUEUE_STRATEGY_RRMEMORY:
1952                 if (pos < q->rrpos) {
1953                         tmp->metric = 1000 + pos;
1954                 } else {
1955                         if (pos > q->rrpos)
1956                                 /* Indicate there is another priority */
1957                                 q->wrapped = 1;
1958                         tmp->metric = pos;
1959                 }
1960                 tmp->metric += mem->penalty * 1000000;
1961                 break;
1962         case QUEUE_STRATEGY_RANDOM:
1963                 tmp->metric = rand() % 1000;
1964                 tmp->metric += mem->penalty * 1000000;
1965                 break;
1966         case QUEUE_STRATEGY_FEWESTCALLS:
1967                 tmp->metric = mem->calls;
1968                 tmp->metric += mem->penalty * 1000000;
1969                 break;
1970         case QUEUE_STRATEGY_LEASTRECENT:
1971                 if (!mem->lastcall)
1972                         tmp->metric = 0;
1973                 else
1974                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1975                 tmp->metric += mem->penalty * 1000000;
1976                 break;
1977         default:
1978                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1979                 break;
1980         }
1981         return 0;
1982 }
1983
1984 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
1985 {
1986         struct member *cur;
1987         struct localuser *outgoing=NULL, *tmp = NULL;
1988         int to;
1989         char restofit[AST_MAX_EXTENSION];
1990         char oldexten[AST_MAX_EXTENSION]="";
1991         char oldcontext[AST_MAX_CONTEXT]="";
1992         char queuename[256]="";
1993         char *newnum;
1994         struct ast_channel *peer;
1995         struct ast_channel *which;
1996         struct localuser *lpeer;
1997         struct member *member;
1998         int res = 0, bridge = 0;
1999         int numbusies = 0;
2000         int x=0;
2001         char *announce = NULL;
2002         char digit = 0;
2003         time_t callstart;
2004         time_t now = time(NULL);
2005         struct ast_bridge_config bridge_config;
2006         char nondataquality = 1;
2007
2008         memset(&bridge_config, 0, sizeof(bridge_config));
2009         time(&now);
2010                 
2011         for (; options && *options; options++)
2012                 switch (*options) {
2013                 case 't':
2014                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2015                         break;
2016                 case 'T':
2017                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2018                         break;
2019                 case 'w':
2020                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2021                         break;
2022                 case 'W':
2023                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2024                         break;
2025                 case 'd':
2026                         nondataquality = 0;
2027                         break;
2028                 case 'h':
2029                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2030                         break;
2031                 case 'H':
2032                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2033                         break;
2034                 case 'n':
2035                         if ((now - qe->start >= qe->parent->timeout))
2036                                 *go_on = 1;
2037                         break;
2038                 }
2039
2040         /* Hold the lock while we setup the outgoing calls */
2041         if (use_weight) 
2042                 ast_mutex_lock(&qlock);
2043         ast_mutex_lock(&qe->parent->lock);
2044         if (option_debug)
2045                 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n", 
2046                                                         qe->chan->name);
2047         ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2048         cur = qe->parent->members;
2049         if (!ast_strlen_zero(qe->announce))
2050                 announce = qe->announce;
2051         if (!ast_strlen_zero(announceoverride))
2052                 announce = announceoverride;
2053
2054         while(cur) {
2055                 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
2056                         ast_mutex_unlock(&qe->parent->lock);
2057                         if (use_weight) 
2058                                 ast_mutex_unlock(&qlock);
2059                         goto out;
2060                 }
2061                 tmp->stillgoing = -1;
2062                 if (option_debug) {
2063                         if (url)
2064                                 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2065                         else 
2066                                 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
2067                 }
2068
2069                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
2070                 tmp->oldstatus = cur->status;
2071                 tmp->lastcall = cur->lastcall;
2072                 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2073                 /* If we're dialing by extension, look at the extension to know what to dial */
2074                 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
2075                         newnum++;
2076                         strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
2077                         snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
2078                         if (option_debug)
2079                                 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
2080                 }
2081                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2082                    just calculate their metric for the appropriate strategy */
2083                 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2084                         /* Put them in the list of outgoing thingies...  We're ready now. 
2085                            XXX If we're forcibly removed, these outgoing calls won't get
2086                            hung up XXX */
2087                         tmp->next = outgoing;
2088                         outgoing = tmp;         
2089                         /* If this line is up, don't try anybody else */
2090                         if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2091                                 break;
2092                 } else {
2093                         free(tmp);
2094                 }
2095
2096                 cur = cur->next;
2097         }
2098         if (qe->parent->timeout)
2099                 to = qe->parent->timeout * 1000;
2100         else
2101                 to = -1;
2102         ring_one(qe, outgoing, &numbusies);
2103         ast_mutex_unlock(&qe->parent->lock);
2104         if (use_weight) 
2105                 ast_mutex_unlock(&qlock);
2106         lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
2107         ast_mutex_lock(&qe->parent->lock);
2108         if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2109                 store_next(qe, outgoing);
2110         }
2111         ast_mutex_unlock(&qe->parent->lock);
2112         if (lpeer)
2113                 peer = lpeer->chan;
2114         else
2115                 peer = NULL;
2116         if (!peer) {
2117                 if (to) {
2118                         /* Musta gotten hung up */
2119                         record_abandoned(qe);
2120                         res = -1;
2121                 } else {
2122                         res = digit;
2123                 }
2124                 if (option_debug)
2125                         ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2126                 goto out;
2127         }
2128         if (peer) {
2129                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
2130                    we will always return with -1 so that it is hung up properly after the 
2131                    conversation.  */
2132                 qe->handled++;
2133                 if (!strcmp(qe->chan->type,"Zap"))
2134                         ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2135                 if (!strcmp(peer->type,"Zap"))
2136                         ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2137                 /* Update parameters for the queue */
2138                 recalc_holdtime(qe);
2139                 member = lpeer->member;
2140                 hangupcalls(outgoing, peer);
2141                 outgoing = NULL;
2142                 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2143                         int res2;
2144                         res2 = ast_autoservice_start(qe->chan);
2145                         if (!res2) {
2146                                 if (qe->parent->memberdelay) {
2147                                         ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2148                                         res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2149                                 }
2150                                 if (!res2 && announce) {
2151                                         if (play_file(peer, announce))
2152                                                 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2153                                 }
2154                                 if (!res2 && qe->parent->reportholdtime) {
2155                                         if (!play_file(peer, qe->parent->sound_reporthold)) {
2156                                                 int holdtime;
2157
2158                                                 time(&now);
2159                                                 holdtime = abs((now - qe->start) / 60);
2160                                                 if (holdtime < 2) {
2161                                                         play_file(peer, qe->parent->sound_lessthan);
2162                                                         ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2163                                                 } else 
2164                                                         ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2165                                                 play_file(peer, qe->parent->sound_minutes);
2166                                         }
2167                                 }
2168                         }
2169                         res2 |= ast_autoservice_stop(qe->chan);
2170                         if (peer->_softhangup) {
2171                                 /* Agent must have hung up */
2172                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
2173                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
2174                                 record_abandoned(qe);
2175                                 if (qe->parent->eventwhencalled) {
2176                                         manager_event(EVENT_FLAG_AGENT, "AgentDump",
2177                                                       "Queue: %s\r\n"
2178                                                       "Uniqueid: %s\r\n"
2179                                                       "Channel: %s\r\n"
2180                                                       "Member: %s\r\n",
2181                                                       queuename, qe->chan->uniqueid, peer->name, member->interface);
2182                                 }
2183                                 ast_hangup(peer);
2184                                 goto out;
2185                         } else if (res2) {
2186                                 /* Caller must have hung up just before being connected*/
2187                                 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2188                                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2189                                 record_abandoned(qe);
2190                                 ast_hangup(peer);
2191                                 return -1;
2192                         }
2193                 }
2194                 /* Stop music on hold */
2195                 ast_moh_stop(qe->chan);
2196                 /* If appropriate, log that we have a destination channel */
2197                 if (qe->chan->cdr)
2198                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2199                 /* Make sure channels are compatible */
2200                 res = ast_channel_make_compatible(qe->chan, peer);
2201                 if (res < 0) {
2202                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2203                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2204                         record_abandoned(qe);
2205                         ast_hangup(peer);
2206                         return -1;
2207                 }
2208                 /* Begin Monitoring */
2209                 if (qe->parent->monfmt && *qe->parent->monfmt) {
2210                         const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2211                         if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2212                                 which = qe->chan;
2213                         else
2214                                 which = peer;
2215                         if (monitorfilename)
2216                                 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2217                         else if (qe->chan->cdr) 
2218                                 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2219                         else {
2220                                 /* Last ditch effort -- no CDR, make up something */
2221                                 char tmpid[256];
2222                                 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
2223                                 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2224                         }
2225                         if (qe->parent->monjoin)
2226                                 ast_monitor_setjoinfiles(which, 1);
2227                 }
2228                 /* Drop out of the queue at this point, to prepare for next caller */
2229                 leave_queue(qe);                        
2230                 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2231                         if (option_debug)
2232                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2233                         ast_channel_sendurl(peer, url);
2234                 }
2235                 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
2236                 if (qe->parent->eventwhencalled)
2237                         manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2238                                       "Queue: %s\r\n"
2239                                       "Uniqueid: %s\r\n"
2240                                       "Channel: %s\r\n"
2241                                       "Member: %s\r\n"
2242                                       "Holdtime: %ld\r\n",
2243                                       queuename, qe->chan->uniqueid, peer->name, member->interface,
2244                                       (long)time(NULL) - qe->start);
2245                 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2246                 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2247                 time(&callstart);
2248
2249                 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2250
2251                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2252                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
2253                 } else if (qe->chan->_softhangup) {
2254                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2255                                       (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2256                         if (qe->parent->eventwhencalled)
2257                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2258                                               "Queue: %s\r\n"
2259                                               "Uniqueid: %s\r\n"
2260                                               "Channel: %s\r\n"
2261                                               "Member: %s\r\n"
2262                                               "HoldTime: %ld\r\n"
2263                                               "TalkTime: %ld\r\n"
2264                                               "Reason: caller\r\n",
2265                                               queuename, qe->chan->uniqueid, peer->name, member->interface,
2266                                               (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2267                 } else {
2268                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2269                         if (qe->parent->eventwhencalled)
2270                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2271                                               "Queue: %s\r\n"
2272                                               "Uniqueid: %s\r\n"
2273                                               "Channel: %s\r\n"
2274                                               "HoldTime: %ld\r\n"
2275                                               "TalkTime: %ld\r\n"
2276                                               "Reason: agent\r\n",
2277                                               queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2278                                               (long)(time(NULL) - callstart));
2279                 }
2280
2281                 if(bridge != AST_PBX_NO_HANGUP_PEER)
2282                         ast_hangup(peer);
2283                 update_queue(qe->parent, member);
2284                 if (bridge == 0) 
2285                         res = 1; /* JDG: bridge successfull, leave app_queue */
2286                 else 
2287                         res = bridge; /* bridge error, stay in the queue */
2288         }       
2289 out:
2290         hangupcalls(outgoing, NULL);
2291         return res;
2292 }
2293
2294 static int wait_a_bit(struct queue_ent *qe)
2295 {
2296         /* Don't need to hold the lock while we setup the outgoing calls */
2297         int retrywait = qe->parent->retry * 1000;
2298
2299         return ast_waitfordigit(qe->chan, retrywait);
2300 }
2301
2302 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2303 {
2304         struct member *mem;
2305
2306         if (q)
2307                 for (mem = q->members; mem; mem = mem->next)
2308                         if (!strcasecmp(interface, mem->interface))
2309                                 return mem;
2310
2311         return NULL;
2312 }
2313
2314
2315 /* Dump all members in a specific queue to the databse
2316  *
2317  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2318  *
2319  */
2320 static void dump_queue_members(struct ast_call_queue *pm_queue)
2321 {
2322         struct member *cur_member;
2323         char value[PM_MAX_LEN];
2324         int value_len = 0;
2325         int res;
2326
2327         memset(value, 0, sizeof(value));
2328
2329         if (!pm_queue)
2330                 return;
2331
2332         for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2333                 if (!cur_member->dynamic)
2334                         continue;
2335
2336                 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2337                                cur_member->interface, cur_member->penalty, cur_member->paused,
2338                                cur_member->next ? "|" : "");
2339                 if (res != strlen(value + value_len)) {
2340                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2341                         break;
2342                 }
2343                 value_len += res;
2344         }
2345         
2346         if (value_len && !cur_member) {
2347                 if (ast_db_put(pm_family, pm_queue->name, value))
2348                         ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2349         } else
2350                 /* Delete the entry if the queue is empty or there is an error */
2351                 ast_db_del(pm_family, pm_queue->name);
2352 }
2353
2354 static int remove_from_queue(char *queuename, char *interface)
2355 {
2356         struct ast_call_queue *q;
2357         struct member *last_member, *look;
2358         int res = RES_NOSUCHQUEUE;
2359
2360         ast_mutex_lock(&qlock);
2361         for (q = queues ; q ; q = q->next) {
2362                 ast_mutex_lock(&q->lock);
2363                 if (!strcmp(q->name, queuename)) {
2364                         if ((last_member = interface_exists(q, interface))) {
2365                                 if ((look = q->members) == last_member) {
2366                                         q->members = last_member->next;
2367                                 } else {
2368                                         while (look != NULL) {
2369                                                 if (look->next == last_member) {
2370                                                         look->next = last_member->next;
2371                                                         break;
2372                                                 } else {
2373                                                          look = look->next;
2374                                                 }
2375                                         }
2376                                 }
2377                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2378                                                 "Queue: %s\r\n"
2379                                                 "Location: %s\r\n",
2380                                         q->name, last_member->interface);
2381                                 free(last_member);
2382
2383                                 if (queue_persistent_members)
2384                                     dump_queue_members(q);
2385
2386                                 res = RES_OKAY;
2387                         } else {
2388                                 res = RES_EXISTS;
2389                         }
2390                         ast_mutex_unlock(&q->lock);
2391                         break;
2392                 }
2393                 ast_mutex_unlock(&q->lock);
2394         }
2395         ast_mutex_unlock(&qlock);
2396         return res;
2397 }
2398
2399 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2400 {
2401         struct ast_call_queue *q;
2402         struct member *new_member;
2403         int res = RES_NOSUCHQUEUE;
2404
2405         ast_mutex_lock(&qlock);
2406         for (q = queues ; q ; q = q->next) {
2407                 ast_mutex_lock(&q->lock);
2408                 if (!strcmp(q->name, queuename)) {
2409                         if (interface_exists(q, interface) == NULL) {
2410                                 new_member = create_queue_member(interface, penalty, paused);
2411
2412                                 if (new_member != NULL) {
2413                                         new_member->dynamic = 1;
2414                                         new_member->next = q->members;
2415                                         q->members = new_member;
2416                                         manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2417                                                 "Queue: %s\r\n"
2418                                                 "Location: %s\r\n"
2419                                                 "Membership: %s\r\n"
2420                                                 "Penalty: %d\r\n"
2421                                                 "CallsTaken: %d\r\n"
2422                                                 "LastCall: %d\r\n"
2423                                                 "Status: %d\r\n"
2424                                                 "Paused: %d\r\n",
2425                                         q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2426                                         new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
2427                                         
2428                                         if (dump)
2429                                                 dump_queue_members(q);
2430
2431                                         res = RES_OKAY;
2432                                 } else {
2433                                         res = RES_OUTOFMEMORY;
2434                                 }
2435                         } else {
2436                                 res = RES_EXISTS;
2437                         }
2438                         ast_mutex_unlock(&q->lock);
2439                         break;
2440                 }
2441                 ast_mutex_unlock(&q->lock);
2442         }
2443         ast_mutex_unlock(&qlock);
2444         return res;
2445 }
2446
2447 static int set_member_paused(char *queuename, char *interface, int paused)
2448 {
2449         int found = 0;
2450         struct ast_call_queue *q;
2451         struct member *mem;
2452
2453         /* Special event for when all queues are paused - individual events still generated */
2454
2455         if (ast_strlen_zero(queuename))
2456                 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2457
2458         ast_mutex_lock(&qlock);
2459         for (q = queues ; q ; q = q->next) {
2460                 ast_mutex_lock(&q->lock);
2461                 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
2462                         if ((mem = interface_exists(q, interface))) {
2463                                 found++;
2464                                 if (mem->paused == paused)
2465                                         ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2466                                 mem->paused = paused;
2467
2468                                 if (queue_persistent_members)
2469                                     dump_queue_members(q);
2470
2471                                 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2472
2473                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2474                                         "Queue: %s\r\n"
2475                                         "Location: %s\r\n"
2476                                         "Paused: %d\r\n",
2477                                                 q->name, mem->interface, paused);
2478                         }
2479                 }
2480                 ast_mutex_unlock(&q->lock);
2481         }
2482         ast_mutex_unlock(&qlock);
2483
2484         if (found)
2485                 return RESULT_SUCCESS;
2486         else
2487                 return RESULT_FAILURE;
2488 }
2489
2490 /* Reload dynamic queue members persisted into the astdb */
2491 static void reload_queue_members(void)
2492 {
2493         char *cur_ptr;  
2494         char *queue_name;
2495         char *member;
2496         char *interface;
2497         char *penalty_tok;
2498         int penalty = 0;
2499         char *paused_tok;
2500         int paused = 0;
2501         struct ast_db_entry *db_tree;
2502         struct ast_db_entry *entry;
2503         struct ast_call_queue *cur_queue;
2504         char queue_data[PM_MAX_LEN];
2505
2506         ast_mutex_lock(&qlock);
2507
2508         /* Each key in 'pm_family' is the name of a queue */
2509         db_tree = ast_db_gettree(pm_family, NULL);
2510         for (entry = db_tree; entry; entry = entry->next) {
2511
2512                 queue_name = entry->key + strlen(pm_family) + 2;
2513
2514                 cur_queue = queues;
2515                 while (cur_queue) {
2516                         ast_mutex_lock(&cur_queue->lock);
2517                         if (!strcmp(queue_name, cur_queue->name))
2518                                 break;
2519                         ast_mutex_unlock(&cur_queue->lock);
2520                         cur_queue = cur_queue->next;
2521                 }
2522
2523                 if (!cur_queue) {
2524                         /* If the queue no longer exists, remove it from the
2525                          * database */
2526                         ast_db_del(pm_family, queue_name);
2527                         continue;
2528                 } else
2529                         ast_mutex_unlock(&cur_queue->lock);
2530
2531                 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2532                         continue;
2533
2534                 cur_ptr = queue_data;
2535                 while ((member = strsep(&cur_ptr, "|"))) {
2536                         if (ast_strlen_zero(member))
2537                                 continue;
2538
2539                         interface = strsep(&member, ";");
2540                         penalty_tok = strsep(&member, ";");
2541                         paused_tok = strsep(&member, ";");
2542
2543                         if (!penalty_tok) {
2544                                 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
2545                                 break;
2546                         }
2547                         penalty = strtol(penalty_tok, NULL, 10);
2548                         if (errno == ERANGE) {
2549                                 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2550                                 break;
2551                         }
2552                         
2553                         if (!paused_tok) {
2554                                 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2555                                 break;
2556                         }
2557                         paused = strtol(paused_tok, NULL, 10);
2558                         if ((errno == ERANGE) || paused < 0 || paused > 1) {
2559                                 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2560                                 break;
2561                         }
2562
2563                         if (option_debug)
2564                                 ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Penalty: %d  Paused: %d\n", queue_name, interface, penalty, paused);
2565                         
2566                         if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2567                                 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2568                                 break;
2569                         }
2570                 }
2571         }
2572
2573         ast_mutex_unlock(&qlock);
2574         if (db_tree) {
2575                 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2576                 ast_db_freetree(db_tree);
2577         }
2578 }
2579
2580 static int pqm_exec(struct ast_channel *chan, void *data)
2581 {
2582         struct localuser *u;
2583         char *parse;
2584         int priority_jump = 0;
2585         AST_DECLARE_APP_ARGS(args,
2586                 AST_APP_ARG(queuename);
2587                 AST_APP_ARG(interface);
2588                 AST_APP_ARG(options);
2589         );
2590
2591         if (ast_strlen_zero(data)) {
2592                 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2593                 return -1;
2594         }
2595
2596         LOCAL_USER_ADD(u);
2597
2598         if (!(parse = ast_strdupa(data))) {
2599                 ast_log(LOG_WARNING, "Memory Error!\n");
2600                 LOCAL_USER_REMOVE(u);
2601                 return -1;
2602         }
2603
2604         AST_STANDARD_APP_ARGS(args, parse);
2605
2606         if (args.options) {
2607                 if (strchr(args.options, 'j'))
2608                         priority_jump = 1;
2609         }
2610
2611         if (ast_strlen_zero(args.interface)) {
2612                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2613                 LOCAL_USER_REMOVE(u);
2614                 return -1;
2615         }
2616
2617         if (set_member_paused(args.queuename, args.interface, 1)) {
2618                 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
2619                 if (priority_jump || ast_opt_priority_jumping) {
2620                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2621                                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2622                                 LOCAL_USER_REMOVE(u);
2623                                 return 0;
2624                         }
2625                 }
2626                 LOCAL_USER_REMOVE(u);
2627                 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2628                 return -1;
2629         }
2630
2631         LOCAL_USER_REMOVE(u);
2632         pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2633         return 0;
2634 }
2635
2636 static int upqm_exec(struct ast_channel *chan, void *data)
2637 {
2638         struct localuser *u;
2639         char *parse;
2640         int priority_jump = 0;
2641         AST_DECLARE_APP_ARGS(args,
2642                 AST_APP_ARG(queuename);
2643                 AST_APP_ARG(interface);
2644                 AST_APP_ARG(options);
2645         );
2646
2647         if (ast_strlen_zero(data)) {
2648                 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2649                 return -1;
2650         }
2651
2652         LOCAL_USER_ADD(u);
2653
2654         if (!(parse = ast_strdupa(data))) {
2655                 ast_log(LOG_WARNING, "Memory Error!\n");
2656                 LOCAL_USER_REMOVE(u);
2657                 return -1;
2658         }
2659
2660         AST_STANDARD_APP_ARGS(args, parse);
2661
2662         if (args.options) {
2663                 if (strchr(args.options, 'j'))
2664                         priority_jump = 1;
2665         }
2666
2667         if (ast_strlen_zero(args.interface)) {
2668                 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2669                 LOCAL_USER_REMOVE(u);
2670                 return -1;
2671         }
2672
2673         if (set_member_paused(args.queuename, args.interface, 0)) {
2674                 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
2675                 if (priority_jump || ast_opt_priority_jumping) {
2676                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2677                                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2678                                 LOCAL_USER_REMOVE(u);
2679                                 return 0;
2680                         }
2681                 }
2682                 LOCAL_USER_REMOVE(u);
2683                 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2684                 return -1;
2685         }
2686
2687         LOCAL_USER_REMOVE(u);
2688         pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2689         return 0;
2690 }
2691
2692 static int rqm_exec(struct ast_channel *chan, void *data)
2693 {
2694         int res=-1;
2695         struct localuser *u;
2696         char *parse, *temppos = NULL;
2697         int priority_jump = 0;
2698         AST_DECLARE_APP_ARGS(args,
2699                 AST_APP_ARG(queuename);
2700                 AST_APP_ARG(interface);
2701                 AST_APP_ARG(options);
2702         );
2703
2704
2705         if (ast_strlen_zero(data)) {
2706                 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2707                 return -1;
2708         }
2709
2710         LOCAL_USER_ADD(u);
2711
2712         if (!(parse = ast_strdupa(data))) {
2713                 ast_log(LOG_WARNING, "Memory Error!\n");
2714                 LOCAL_USER_REMOVE(u);
2715                 return -1;
2716         }
2717
2718         AST_STANDARD_APP_ARGS(args, parse);
2719
2720         if (ast_strlen_zero(args.interface)) {
2721                 args.interface = ast_strdupa(chan->name);
2722                 temppos = strrchr(args.interface, '-');
2723                 if (temppos)
2724                         *temppos = '\0';
2725         }
2726
2727         if (args.options) {
2728                 if (strchr(args.options, 'j'))
2729                         priority_jump = 1;
2730         }
2731
2732         switch (remove_from_queue(args.queuename, args.interface)) {
2733         case RES_OKAY:
2734                 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2735                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
2736                 res = 0;
2737                 break;
2738         case RES_EXISTS:
2739                 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
2740                 if (priority_jump || ast_opt_priority_jumping) 
2741                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2742                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
2743                 res = 0;
2744                 break;
2745         case RES_NOSUCHQUEUE:
2746                 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
2747                 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
2748                 res = 0;
2749                 break;
2750         case RES_OUTOFMEMORY:
2751                 ast_log(LOG_ERROR, "Out of memory\n");
2752                 break;
2753         }
2754
2755         LOCAL_USER_REMOVE(u);
2756         return res;
2757 }
2758
2759 static int aqm_exec(struct ast_channel *chan, void *data)
2760 {
2761         int res=-1;
2762         struct localuser *u;
2763         char *parse, *temppos = NULL;
2764         int priority_jump = 0;
2765         AST_DECLARE_APP_ARGS(args,
2766                 AST_APP_ARG(queuename);
2767                 AST_APP_ARG(interface);
2768                 AST_APP_ARG(penalty);
2769                 AST_APP_ARG(options);
2770         );
2771         int penalty = 0;
2772
2773         if (ast_strlen_zero(data)) {
2774                 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2775                 return -1;
2776         }
2777
2778         LOCAL_USER_ADD(u);
2779
2780         if (!(parse = ast_strdupa(data))) {
2781                 ast_log(LOG_WARNING, "Memory Error!\n");
2782                 LOCAL_USER_REMOVE(u);
2783                 return -1;
2784         }
2785
2786         AST_STANDARD_APP_ARGS(args, parse);
2787
2788         if (ast_strlen_zero(args.interface)) {
2789                 args.interface = ast_strdupa(chan->name);
2790                 temppos = strrchr(args.interface, '-');
2791                 if (temppos)
2792                         *temppos = '\0';
2793         }
2794
2795         if (!ast_strlen_zero(args.penalty)) {
2796                 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
2797                         ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
2798                         penalty = 0;
2799                 }
2800         }
2801         
2802         if (args.options) {
2803                 if (strchr(args.options, 'j'))
2804                         priority_jump = 1;
2805         }
2806
2807
2808         switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2809         case RES_OKAY:
2810                 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2811                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
2812                 res = 0;
2813                 break;
2814         case RES_EXISTS:
2815                 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
2816                 if (priority_jump || ast_opt_priority_jumping) 
2817                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2818                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
2819                 res = 0;
2820                 break;
2821         case RES_NOSUCHQUEUE:
2822                 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
2823                 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
2824                 res = 0;
2825                 break;
2826         case RES_OUTOFMEMORY:
2827                 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2828                 break;
2829         }
2830
2831         LOCAL_USER_REMOVE(u);
2832         return res;
2833 }
2834
2835 static int queue_exec(struct ast_channel *chan, void *data)
2836 {
2837         int res=-1;
2838         int ringing=0;
2839         struct localuser *u;
2840         char *queuename;
2841         char info[512];
2842         char *info_ptr = info;
2843         char *options = NULL;
2844         char *url = NULL;
2845         char *announceoverride = NULL;
2846         const char *user_priority;
2847         const char *max_penalty_str;
2848         int prio;
2849         int max_penalty;
2850         char *queuetimeoutstr = NULL;
2851         enum queue_result reason = QUEUE_UNKNOWN;
2852
2853         /* whether to exit Queue application after the timeout hits */
2854         int go_on = 0;
2855
2856         /* Our queue entry */
2857         struct queue_ent qe;
2858         
2859         if (ast_strlen_zero(data)) {
2860                 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2861                 return -1;
2862         }
2863
2864         LOCAL_USER_ADD(u);
2865
2866         /* Setup our queue entry */
2867         memset(&qe, 0, sizeof(qe));
2868         qe.start = time(NULL);
2869         
2870         /* Parse our arguments XXX Check for failure XXX */
2871         ast_copy_string(info, (char *) data, sizeof(info));
2872         queuename = strsep(&info_ptr, "|");
2873         options = strsep(&info_ptr, "|");
2874         url = strsep(&info_ptr, "|");
2875         announceoverride = strsep(&info_ptr, "|");
2876         queuetimeoutstr = info_ptr;
2877
2878         /* set the expire time based on the supplied timeout; */
2879         if (queuetimeoutstr)
2880                 qe.expire = qe.start + atoi(queuetimeoutstr);
2881         else
2882                 qe.expire = 0;
2883
2884         /* Get the priority from the variable ${QUEUE_PRIO} */
2885         user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2886         if (user_priority) {
2887                 if (sscanf(user_priority, "%d", &prio) == 1) {
2888                         if (option_debug)
2889                                 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2890                                         chan->name, prio);
2891                 } else {
2892                         ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2893                                 user_priority, chan->name);
2894                         prio = 0;
2895                 }
2896         } else {
2897                 if (option_debug > 2)
2898                         ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2899                 prio = 0;
2900         }
2901
2902         /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
2903         if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
2904                 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
2905                         if (option_debug)
2906                                 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
2907                                         chan->name, max_penalty);
2908                 } else {
2909                         ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
2910                                 max_penalty_str, chan->name);
2911                         max_penalty = 0;
2912                 }
2913         } else {
2914                 max_penalty = 0;
2915         }
2916
2917         if (options && (strchr(options, 'r')))
2918                 ringing = 1;
2919
2920         if (option_debug)  
2921                 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2922                         queuename, options, url, announceoverride, (long)qe.expire, prio);
2923
2924         qe.chan = chan;
2925         qe.prio = prio;
2926         qe.max_penalty = max_penalty;
2927         qe.last_pos_said = 0;
2928         qe.last_pos = 0;
2929         qe.last_periodic_announce_time = time(NULL);
2930         if (!join_queue(queuename, &qe, &reason)) {
2931                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "",
2932                               chan->cid.cid_num ? chan->cid.cid_num : "");
2933 check_turns:
2934                 if (ringing) {
2935                         ast_indicate(chan, AST_CONTROL_RINGING);
2936                 } else {              
2937                         ast_moh_start(chan, qe.moh);
2938                 }
2939                 for (;;) {
2940                         /* This is the wait loop for callers 2 through maxlen */
2941
2942                         res = wait_our_turn(&qe, ringing, &reason);
2943                         /* If they hungup, return immediately */
2944                         if (res < 0) {
2945                                 /* Record this abandoned call */
2946                                 record_abandoned(&qe);
2947                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
2948                                 if (option_verbose > 2) {
2949                                         ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", queuename);
2950                                         res = -1;
2951                                 }
2952                                 break;
2953                         }
2954                         if (!res) 
2955                                 break;
2956                         if (valid_exit(&qe, res)) {
2957                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
2958                                 break;
2959                         }
2960                 }
2961                 if (!res) {
2962                         int makeannouncement = 0;
2963                         for (;;) {
2964                                 /* This is the wait loop for the head caller*/
2965                                 /* To exit, they may get their call answered; */
2966                                 /* they may dial a digit from the queue context; */
2967                                 /* or, they may timeout. */
2968
2969                                 enum queue_member_status stat;
2970
2971                                 /* Leave if we have exceeded our queuetimeout */
2972                                 if (qe.expire && (time(NULL) > qe.expire)) {
2973                                         record_abandoned(&qe);
2974                                         reason = QUEUE_TIMEOUT;
2975                                         res = 0;
2976                                         ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
2977                                         break;
2978                                 }
2979
2980                                 if (makeannouncement) {
2981                                         /* Make a position announcement, if enabled */
2982                                         if (qe.parent->announcefrequency && !ringing)
2983                                                 res = say_position(&qe);
2984                                         if (res && valid_exit(&qe, res)) {
2985                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
2986                                                 break;
2987                                         }
2988
2989                                 }
2990                                 makeannouncement = 1;
2991
2992                                 /* Make a periodic announcement, if enabled */
2993                                 if (qe.parent->periodicannouncefrequency && !ringing)
2994                                         res = say_periodic_announcement(&qe);
2995
2996                                 if (res && valid_exit(&qe, res)) {
2997                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
2998                                         break;
2999                                 }
3000
3001                                 /* Try calling all queue members for 'timeout' seconds */
3002                                 res = try_calling(&qe, options, announceoverride, url, &go_on);
3003                                 if (res) {
3004                                         if (res < 0) {
3005                                                 if (!qe.handled) {
3006                                                         record_abandoned(&qe);
3007                                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3008                                                 }
3009                                         } else if (res > 0)
3010                                                 ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3011                                         break;
3012                                 }
3013
3014                                 stat = get_member_status(qe.parent, qe.max_penalty);
3015
3016                                 /* leave the queue if no agents, if enabled */
3017                                 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
3018                                         record_abandoned(&qe);
3019                                         reason = QUEUE_LEAVEEMPTY;
3020                                         res = 0;
3021                                         break;
3022                                 }
3023
3024                                 /* leave the queue if no reachable agents, if enabled */
3025                                 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
3026                                         record_abandoned(&qe);
3027                                         reason = QUEUE_LEAVEUNAVAIL;
3028                                         res = 0;
3029                                         break;
3030                                 }
3031
3032                                 /* Leave if we have exceeded our queuetimeout */
3033                                 if (qe.expire && (time(NULL) > qe.expire)) {
3034                                         record_abandoned(&qe);
3035                                         reason = QUEUE_TIMEOUT;
3036                                         res = 0;
3037                                         ast_queue_log(queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);       
3038                                         break;
3039                                 }
3040
3041                                 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3042                                 res = wait_a_bit(&qe);
3043                                 if (res < 0) {
3044                                         record_abandoned(&qe);
3045                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3046                                         if (option_verbose > 2) {
3047                                                 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", queuename);
3048                                                 res = -1;
3049                                         }
3050                                         break;
3051                                 }
3052                                 if (res && valid_exit(&qe, res)) {
3053                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3054                                         break;
3055                                 }
3056                                 /* exit after 'timeout' cycle if 'n' option enabled */
3057                                 if (go_on) {
3058                                         if (option_verbose > 2) {
3059                                                 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
3060                                                 res = -1;
3061                                         }
3062                                         ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3063                                         record_abandoned(&qe);
3064                                         reason = QUEUE_TIMEOUT;
3065                                         res = 0;
3066                                         break;
3067                                 }
3068                                 /* Since this is a priority queue and 
3069                                  * it is not sure that we are still at the head
3070                                  * of the queue, go and check for our turn again.
3071                                  */
3072                                 if (!is_our_turn(&qe)) {
3073                                         if (option_debug)
3074                                                 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
3075                                                                 qe.chan->name);
3076                                         goto check_turns;
3077                                 }
3078                         }
3079                 }
3080                 /* Don't allow return code > 0 */
3081                 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
3082                         res = 0;        
3083                         if (ringing) {
3084                                 ast_indicate(chan, -1);
3085                         } else {
3086                                 ast_moh_stop(chan);
3087                         }                       
3088                         ast_stopstream(chan);
3089                 }
3090                 leave_queue(&qe);
3091                 if (reason != QUEUE_UNKNOWN)
3092                         set_queue_result(chan, reason);
3093         } else {
3094                 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename);
3095                 set_queue_result(chan, reason);
3096                 res = 0;
3097         }
3098         LOCAL_USER_REMOVE(u);
3099         return res;
3100 }
3101
3102 static char *queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3103 {
3104         int count = 0;
3105         struct ast_call_queue *q;
3106         struct localuser *u;
3107         struct member *m;
3108
3109         LOCAL_USER_ACF_ADD(u);
3110
3111         ast_copy_string(buf, "0", len);
3112         
3113         if (ast_strlen_zero(data)) {
3114                 ast_log(LOG_ERROR, "QUEUEAGENTCOUNT requires an argument: queuename\n");
3115                 LOCAL_USER_REMOVE(u);
3116                 return buf;
3117         }
3118
3119         ast_mutex_lock(&qlock);
3120
3121         /* Find the right queue */
3122         for (q = queues; q; q = q->next) {
3123                 if (!strcasecmp(q->name, data)) {
3124                         ast_mutex_lock(&q->lock);
3125                         break;
3126                 }
3127         }
3128
3129         ast_mutex_unlock(&qlock);
3130
3131         if (q) {
3132                 for (m = q->members; m; m = m->next) {
3133                         /* Count the agents who are logged in and presently answering calls */
3134                         if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
3135                                 count++;
3136                         }
3137                 }
3138                 ast_mutex_unlock(&q->lock);
3139         }
3140
3141         snprintf(buf, len, "%d", count);
3142         LOCAL_USER_REMOVE(u);
3143         return buf;
3144 }
3145
3146 static struct ast_custom_function queueagentcount_function = {
3147         .name = "QUEUEAGENTCOUNT",
3148         .synopsis = "Count number of agents answering a queue",
3149         .syntax = "QUEUEAGENTCOUNT(<queuename>)",
3150         .read = queue_function_qac,
3151 };
3152
3153 static void reload_queues(void)
3154 {
3155         struct ast_call_queue *q, *ql, *qn;
3156         struct ast_config *cfg;
3157         char *cat, *tmp;
3158         struct ast_variable *var;
3159         struct member *prev, *cur;
3160         int new;
3161         char *general_val = NULL;
3162         char interface[80];
3163         int penalty;
3164         
3165         cfg = ast_config_load("queues.conf");
3166         if (!cfg) {
3167                 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
3168                 return;
3169         }
3170         memset(interface, 0, sizeof(interface));
3171         ast_mutex_lock(&qlock);
3172         use_weight=0;
3173         /* Mark all queues as dead for the moment */
3174         q = queues;
3175         while(q) {
3176                 q->dead = 1;
3177                 q = q->next;
3178         }
3179         /* Chug through config file */
3180         cat = ast_category_browse(cfg, NULL);
3181         while(cat) {
3182                 if (!strcasecmp(cat, "general")) {      
3183                         /* Initialize global settings */
3184                         queue_persistent_members = 0;
3185                         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
3186                                 queue_persistent_members = ast_true(general_val);
3187                 } else {        /* Define queue */
3188                         /* Look for an existing one */
3189                         q = queues;
3190                         while(q) {
3191                                 if (!strcmp(q->name, cat))
3192                                         break;
3193                                 q = q->next;
3194                         }
3195                         if (!q) {
3196                                 /* Make one then */
3197                                 if (!(q = alloc_queue(cat))) {
3198                                         /* TODO: Handle memory allocation failure */
3199                                 }
3200                                 new = 1;
3201                         } else
3202                                 new = 0;
3203                         if (q) {
3204                                 if (!new)
3205                                         ast_mutex_lock(&q->lock);
3206                                 /* Re-initialize the queue, and clear statistics */
3207                                 init_queue(q);
3208                                 clear_queue(q);
3209                                 free_members(q, 0);
3210                                 prev = q->members;
3211                                 if (prev) {
3212                                         /* find the end of any dynamic members */
3213                                         while(prev->next)
3214                                                 prev = prev->next;
3215                                 }
3216                                 var = ast_variable_browse(cfg, cat);
3217                                 while(var) {
3218                                         if (!strcasecmp(var->name, "member")) {
3219                                                 /* Add a new member */
3220                                                 ast_copy_string(interface, var->value, sizeof(interface));
3221                                                 if ((tmp = strchr(interface, ','))) {
3222                                                         *tmp = '\0';
3223                                                         tmp++;
3224                                                         penalty = atoi(tmp);
3225                                                         if (penalty < 0) {
3226                                                                 penalty = 0;
3227                                                         }
3228                                                 } else
3229                                                         penalty = 0;
3230                                                 cur = create_queue_member(interface, penalty, 0);
3231                                                 if (cur) {
3232                                                         if (prev)
3233                                                                 prev->next = cur;
3234                                                         else
3235                                                                 q->members = cur;
3236                                                         prev = cur;
3237                                                 }
3238                                         } else {
3239                                                 queue_set_param(q, var->name, var->value, var->lineno, 1);
3240                                         }
3241                                         var = var->next;
3242                                 }
3243                                 if (!new) 
3244                                         ast_mutex_unlock(&q->lock);
3245                                 if (new) {
3246                                         q->next = queues;
3247                                         queues = q;
3248                                 }
3249                         }
3250                 }
3251                 cat = ast_category_browse(cfg, cat);
3252         }
3253         ast_config_destroy(cfg);
3254         q = queues;
3255         ql = NULL;
3256         while(q) {
3257                 qn = q->next;
3258                 if (q->dead) {
3259                         if (ql)
3260                                 ql->next = q->next;
3261                         else
3262                                 queues = q->next;
3263                         if (!q->count) {
3264                                 free(q);
3265                         } else
3266                                 ast_log(LOG_WARNING, "XXX Leaking a little memory :( XXX\n");
3267                 } else {
3268                         for (cur = q->members; cur; cur = cur->next)
3269                                 cur->status = ast_device_state(cur->interface);
3270                         ql = q;