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