2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
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.
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.
21 * \brief True call queues with optional send URL on answer
23 * \author Mark Spencer <markster@digium.com>
25 * \arg Config in \ref Config_qu queues.conf
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>
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.
38 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
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
48 * Patch Version 1.07 2003-12-24 01
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>
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>
56 * \ingroup applications
66 #include <sys/signal.h>
67 #include <netinet/in.h>
71 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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 #include "asterisk/stringfields.h"
96 #define QUEUE_STRATEGY_RINGALL 0
97 #define QUEUE_STRATEGY_ROUNDROBIN 1
98 #define QUEUE_STRATEGY_LEASTRECENT 2
99 #define QUEUE_STRATEGY_FEWESTCALLS 3
100 #define QUEUE_STRATEGY_RANDOM 4
101 #define QUEUE_STRATEGY_RRMEMORY 5
103 static struct strategy {
107 { QUEUE_STRATEGY_RINGALL, "ringall" },
108 { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
109 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
110 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
111 { QUEUE_STRATEGY_RANDOM, "random" },
112 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
115 #define DEFAULT_RETRY 5
116 #define DEFAULT_TIMEOUT 15
117 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
118 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
120 #define RES_OKAY 0 /* Action completed */
121 #define RES_EXISTS (-1) /* Entry already exists */
122 #define RES_OUTOFMEMORY (-2) /* Out of memory */
123 #define RES_NOSUCHQUEUE (-3) /* No such queue */
125 static char *tdesc = "True Call Queueing";
127 static char *app = "Queue";
129 static char *synopsis = "Queue a call for a call queue";
131 static char *descrip =
132 " Queue(queuename[|options[|URL][|announceoverride][|timeout]]):\n"
133 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
134 "This application will return to the dialplan if the queue does not exist, or\n"
135 "any of the join options cause the caller to not enter the queue.\n"
136 "The option string may contain zero or more of the following characters:\n"
137 " 'd' -- data-quality (modem) call (minimum delay).\n"
138 " 'h' -- allow callee to hang up by hitting *.\n"
139 " 'H' -- allow caller to hang up by hitting *.\n"
140 " 'n' -- no retries on the timeout; will exit this application and \n"
141 " go to the next step.\n"
142 " 'r' -- ring instead of playing MOH\n"
143 " 't' -- allow the called user transfer the calling user\n"
144 " 'T' -- to allow the calling user to transfer the call.\n"
145 " 'w' -- allow the called user to write the conversation to disk via Monitor\n"
146 " 'W' -- allow the calling user to write the conversation to disk via Monitor\n"
147 " In addition to transferring the call, a call may be parked and then picked\n"
148 "up by another user.\n"
149 " The optional URL will be sent to the called party if the channel supports\n"
151 " The timeout will cause the queue to fail out after a specified number of\n"
152 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
153 " This application sets the following channel variable upon completion:\n"
154 " QUEUESTATUS The status of the call as a text string, one of\n"
155 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
157 static char *app_aqm = "AddQueueMember" ;
158 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
159 static char *app_aqm_descrip =
160 " AddQueueMember(queuename[|interface[|penalty[|options]]]):\n"
161 "Dynamically adds interface to an existing queue.\n"
162 "If the interface is already in the queue and there exists an n+101 priority\n"
163 "then it will then jump to this priority. Otherwise it will return an error\n"
164 "The option string may contain zero or more of the following characters:\n"
165 " 'j' -- jump to +101 priority when appropriate.\n"
166 " This application sets the following channel variable upon completion:\n"
167 " AQMSTATUS The status of the attempt to add a queue member as a \n"
168 " text string, one of\n"
169 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
170 "Example: AddQueueMember(techsupport|SIP/3000)\n"
173 static char *app_rqm = "RemoveQueueMember" ;
174 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
175 static char *app_rqm_descrip =
176 " RemoveQueueMember(queuename[|interface[|options]]):\n"
177 "Dynamically removes interface to an existing queue\n"
178 "If the interface is NOT in the queue and there exists an n+101 priority\n"
179 "then it will then jump to this priority. Otherwise it will return an error\n"
180 "The option string may contain zero or more of the following characters:\n"
181 " 'j' -- jump to +101 priority when appropriate.\n"
182 " This application sets the following channel variable upon completion:\n"
183 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
184 " text string, one of\n"
185 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
186 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
189 static char *app_pqm = "PauseQueueMember" ;
190 static char *app_pqm_synopsis = "Pauses a queue member" ;
191 static char *app_pqm_descrip =
192 " PauseQueueMember([queuename]|interface[|options]):\n"
193 "Pauses (blocks calls for) a queue member.\n"
194 "The given interface will be paused in the given queue. This prevents\n"
195 "any calls from being sent from the queue to the interface until it is\n"
196 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
197 "queuename is given, the interface is paused in every queue it is a\n"
198 "member of. If the interface is not in the named queue, or if no queue\n"
199 "is given and the interface is not in any queue, it will jump to\n"
200 "priority n+101, if it exists and the appropriate options are set.\n"
201 "The application will fail if the interface is not found and no extension\n"
202 "to jump to exists.\n"
203 "The option string may contain zero or more of the following characters:\n"
204 " 'j' -- jump to +101 priority when appropriate.\n"
205 " This application sets the following channel variable upon completion:\n"
206 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
207 " text string, one of\n"
208 " PAUSED | NOTFOUND\n"
209 "Example: PauseQueueMember(|SIP/3000)\n";
211 static char *app_upqm = "UnpauseQueueMember" ;
212 static char *app_upqm_synopsis = "Unpauses a queue member" ;
213 static char *app_upqm_descrip =
214 " UnpauseQueueMember([queuename]|interface[|options]):\n"
215 "Unpauses (resumes calls to) a queue member.\n"
216 "This is the counterpart to PauseQueueMember and operates exactly the\n"
217 "same way, except it unpauses instead of pausing the given interface.\n"
218 "The option string may contain zero or more of the following characters:\n"
219 " 'j' -- jump to +101 priority when appropriate.\n"
220 " This application sets the following channel variable upon completion:\n"
221 " UPQMSTATUS The status of the attempt to unpause a queue \n"
222 " member as a text string, one of\n"
223 " UNPAUSED | NOTFOUND\n"
224 "Example: UnpauseQueueMember(|SIP/3000)\n";
226 /*! \brief Persistent Members astdb family */
227 static const char *pm_family = "/Queue/PersistentMembers";
228 /* The maximum length of each persistent member queue database entry */
229 #define PM_MAX_LEN 2048
231 /*! \brief queues.conf [general] option */
232 static int queue_persistent_members = 0;
234 /*! \brief queues.conf per-queue weight option */
235 static int use_weight = 0;
241 QUEUE_LEAVEEMPTY = 3,
242 QUEUE_JOINUNAVAIL = 4,
243 QUEUE_LEAVEUNAVAIL = 5,
248 enum queue_result id;
250 } queue_results[] = {
251 { QUEUE_UNKNOWN, "UNKNOWN" },
252 { QUEUE_TIMEOUT, "TIMEOUT" },
253 { QUEUE_JOINEMPTY,"JOINEMPTY" },
254 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
255 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
256 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
257 { QUEUE_FULL, "FULL" },
260 /*! \brief We define a custom "local user" structure because we
261 use it not only for keeping track of what is in use but
262 also for keeping track of who we're dialing. */
265 struct callattempt *q_next;
266 struct ast_channel *chan;
272 struct member *member;
278 struct ast_call_queue *parent; /*!< What queue is our parent */
279 char moh[80]; /*!< Name of musiconhold to be used */
280 char announce[80]; /*!< Announcement to play for member when call is answered */
281 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
282 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
283 int pos; /*!< Where we are in the queue */
284 int prio; /*!< Our priority */
285 int last_pos_said; /*!< Last position we told the user */
286 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
287 int last_periodic_announce_sound; /* The last periodic announcement we made */
288 time_t last_pos; /*!< Last time we told the user their position */
289 int opos; /*!< Where we started in the queue */
290 int handled; /*!< Whether our call was handled */
291 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
292 time_t start; /*!< When we started holding */
293 time_t expire; /*!< When this entry should expire (time out of queue) */
294 struct ast_channel *chan; /*!< Our channel */
295 struct queue_ent *next; /*!< The next queue entry */
299 char interface[80]; /*!< Technology/Location */
300 int penalty; /*!< Are we a last resort? */
301 int calls; /*!< Number of calls serviced by this member */
302 int dynamic; /*!< Are we dynamically added? */
303 int status; /*!< Status of queue member */
304 int paused; /*!< Are we paused (not accepting calls)? */
305 time_t lastcall; /*!< When last successful call was hungup */
306 int dead; /*!< Used to detect members deleted in realtime */
307 struct member *next; /*!< Next member */
310 /* values used in multi-bit flags in ast_call_queue */
311 #define QUEUE_EMPTY_NORMAL 1
312 #define QUEUE_EMPTY_STRICT 2
313 #define ANNOUNCEHOLDTIME_ALWAYS 1
314 #define ANNOUNCEHOLDTIME_ONCE 2
316 struct ast_call_queue {
318 char name[80]; /*!< Name */
319 char moh[80]; /*!< Music On Hold class to be used */
320 char announce[80]; /*!< Announcement to play when call is answered */
321 char context[AST_MAX_CONTEXT]; /*!< Exit context */
322 unsigned int monjoin:1;
324 unsigned int joinempty:2;
325 unsigned int eventwhencalled:1;
326 unsigned int leavewhenempty:2;
327 unsigned int ringinuse:1;
328 unsigned int reportholdtime:1;
329 unsigned int wrapped:1;
330 unsigned int timeoutrestart:1;
331 unsigned int announceholdtime:2;
332 unsigned int strategy:3;
333 unsigned int maskmemberstatus:1;
334 unsigned int realtime:1;
335 int announcefrequency; /*!< How often to announce their position */
336 int periodicannouncefrequency; /*!< How often to play periodic announcement */
337 int roundingseconds; /*!< How many seconds do we round to? */
338 int holdtime; /*!< Current avg holdtime, based on recursive boxcar filter */
339 int callscompleted; /*!< Number of queue calls completed */
340 int callsabandoned; /*!< Number of queue calls abandoned */
341 int servicelevel; /*!< seconds setting for servicelevel*/
342 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
343 char monfmt[8]; /*!< Format to use when recording calls */
344 char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
345 char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
346 char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
347 char sound_holdtime[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
348 char sound_minutes[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
349 char sound_lessthan[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
350 char sound_seconds[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
351 char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
352 char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
353 char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/* Sound files: Custom announce, no default */
355 int count; /*!< How many entries */
356 int maxlen; /*!< Max number of entries */
357 int wrapuptime; /*!< Wrapup Time */
359 int retry; /*!< Retry calling everyone after this amount of time */
360 int timeout; /*!< How long to wait for an answer */
361 int weight; /*!< Respective weight */
362 int autopause; /*!< Auto pause queue members if they fail to answer */
364 /* Queue strategy things */
365 int rrpos; /*!< Round Robin - position */
366 int memberdelay; /*!< Seconds to delay connecting member to caller */
367 int autofill; /*!< Ignore the head call status and ring an available agent */
369 struct member *members; /*!< Head of the list of members */
370 struct queue_ent *head; /*!< Head of the list of callers */
371 AST_LIST_ENTRY(ast_call_queue) list; /*!< Next call queue */
374 static AST_LIST_HEAD_STATIC(queues, ast_call_queue);
376 static int set_member_paused(char *queuename, char *interface, int paused);
378 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
382 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
383 if (queue_results[i].id == res) {
384 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
390 static char *int2strat(int strategy)
393 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
394 if (strategy == strategies[x].strategy)
395 return strategies[x].name;
400 static int strat2int(const char *strategy)
403 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
404 if (!strcasecmp(strategy, strategies[x].name))
405 return strategies[x].strategy;
410 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
411 static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
413 struct queue_ent *cur;
430 enum queue_member_status {
432 QUEUE_NO_REACHABLE_MEMBERS,
436 static enum queue_member_status get_member_status(const struct ast_call_queue *q, int max_penalty)
438 struct member *member;
439 enum queue_member_status result = QUEUE_NO_MEMBERS;
441 for (member = q->members; member; member = member->next) {
442 if (max_penalty && (member->penalty > max_penalty))
445 switch (member->status) {
446 case AST_DEVICE_INVALID:
449 case AST_DEVICE_UNAVAILABLE:
450 result = QUEUE_NO_REACHABLE_MEMBERS;
465 static void *changethread(void *data)
467 struct ast_call_queue *q;
468 struct statechange *sc = data;
473 technology = ast_strdupa(sc->dev);
474 loc = strchr(technology, '/');
483 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
484 AST_LIST_LOCK(&queues);
485 AST_LIST_TRAVERSE(&queues, q, list) {
486 ast_mutex_lock(&q->lock);
489 if (!strcasecmp(sc->dev, cur->interface)) {
490 if (cur->status != sc->state) {
491 cur->status = sc->state;
492 if (!q->maskmemberstatus) {
493 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
502 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
503 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
509 ast_mutex_unlock(&q->lock);
511 AST_LIST_UNLOCK(&queues);
516 static int statechange_queue(const char *dev, int state, void *ign)
518 /* Avoid potential for deadlocks by spawning a new thread to handle
520 struct statechange *sc;
524 if ((sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) {
526 strcpy(sc->dev, dev);
527 pthread_attr_init(&attr);
528 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
529 if (ast_pthread_create(&t, &attr, changethread, sc)) {
530 ast_log(LOG_WARNING, "Failed to create update thread!\n");
537 static struct member *create_queue_member(char *interface, int penalty, int paused)
541 /* Add a new member */
543 if ((cur = ast_calloc(1, sizeof(*cur)))) {
544 cur->penalty = penalty;
545 cur->paused = paused;
546 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
547 if (!strchr(cur->interface, '/'))
548 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
549 cur->status = ast_device_state(interface);
555 static struct ast_call_queue *alloc_queue(const char *queuename)
557 struct ast_call_queue *q;
559 if ((q = ast_calloc(1, sizeof(*q)))) {
560 ast_mutex_init(&q->lock);
561 ast_copy_string(q->name, queuename, sizeof(q->name));
566 static void init_queue(struct ast_call_queue *q)
570 q->retry = DEFAULT_RETRY;
573 q->announcefrequency = 0;
574 q->announceholdtime = 0;
575 q->roundingseconds = 0; /* Default - don't announce seconds */
579 q->announce[0] = '\0';
580 q->context[0] = '\0';
582 q->periodicannouncefrequency = 0;
583 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
584 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
585 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
586 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
587 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
588 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
589 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
590 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
591 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
592 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
593 for (i=1;i<MAX_PERIODIC_ANNOUNCEMENTS;i++) {
594 q->sound_periodicannounce[i][0]='\0';
598 static void clear_queue(struct ast_call_queue *q)
601 q->callscompleted = 0;
602 q->callsabandoned = 0;
603 q->callscompletedinsl = 0;
607 /*! \brief Configure a queue parameter.
609 For error reporting, line number is passed for .conf static configuration.
610 For Realtime queues, linenum is -1.
611 The failunknown flag is set for config files (and static realtime) to show
612 errors for unknown parameters. It is cleared for dynamic realtime to allow
613 extra fields in the tables. */
614 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
619 if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
620 ast_copy_string(q->moh, val, sizeof(q->moh));
621 } else if (!strcasecmp(param, "announce")) {
622 ast_copy_string(q->announce, val, sizeof(q->announce));
623 } else if (!strcasecmp(param, "context")) {
624 ast_copy_string(q->context, val, sizeof(q->context));
625 } else if (!strcasecmp(param, "timeout")) {
626 q->timeout = atoi(val);
628 q->timeout = DEFAULT_TIMEOUT;
629 } else if (!strcasecmp(param, "ringinuse")) {
630 q->ringinuse = ast_true(val);
631 } else if (!strcasecmp(param, "monitor-join")) {
632 q->monjoin = ast_true(val);
633 } else if (!strcasecmp(param, "monitor-format")) {
634 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
635 } else if (!strcasecmp(param, "queue-youarenext")) {
636 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
637 } else if (!strcasecmp(param, "queue-thereare")) {
638 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
639 } else if (!strcasecmp(param, "queue-callswaiting")) {
640 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
641 } else if (!strcasecmp(param, "queue-holdtime")) {
642 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
643 } else if (!strcasecmp(param, "queue-minutes")) {
644 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
645 } else if (!strcasecmp(param, "queue-seconds")) {
646 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
647 } else if (!strcasecmp(param, "queue-lessthan")) {
648 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
649 } else if (!strcasecmp(param, "queue-thankyou")) {
650 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
651 } else if (!strcasecmp(param, "queue-reporthold")) {
652 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
653 } else if (!strcasecmp(param, "announce-frequency")) {
654 q->announcefrequency = atoi(val);
655 } else if (!strcasecmp(param, "announce-round-seconds")) {
656 q->roundingseconds = atoi(val);
657 if (q->roundingseconds>60 || q->roundingseconds<0) {
659 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
660 "using 0 instead for queue '%s' at line %d of queues.conf\n",
661 val, param, q->name, linenum);
663 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
664 "using 0 instead for queue '%s'\n", val, param, q->name);
666 q->roundingseconds=0;
668 } else if (!strcasecmp(param, "announce-holdtime")) {
669 if (!strcasecmp(val, "once"))
670 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
671 else if (ast_true(val))
672 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
674 q->announceholdtime = 0;
675 } else if (!strcasecmp(param, "periodic-announce")) {
676 if (strchr(val,'|')) {
678 while ((c = strchr(lastc,'|'))) {
679 if (i > MAX_PERIODIC_ANNOUNCEMENTS)
681 strncpy(buff, lastc, abs(lastc - c));
682 buff[abs(lastc - c)] = '\0';
683 ast_copy_string(q->sound_periodicannounce[i], buff, sizeof(q->sound_periodicannounce[i]));
688 ast_copy_string(q->sound_periodicannounce[i], lastc, sizeof(q->sound_periodicannounce[i]));
691 ast_copy_string(q->sound_periodicannounce[i], val, sizeof(q->sound_periodicannounce[i]));
693 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
694 q->periodicannouncefrequency = atoi(val);
695 } else if (!strcasecmp(param, "retry")) {
696 q->retry = atoi(val);
698 q->retry = DEFAULT_RETRY;
699 } else if (!strcasecmp(param, "wrapuptime")) {
700 q->wrapuptime = atoi(val);
701 } else if (!strcasecmp(param, "autofill")) {
702 q->autofill = ast_true(val);
703 } else if (!strcasecmp(param, "autopause")) {
704 q->autopause = ast_true(val);
705 } else if (!strcasecmp(param, "maxlen")) {
706 q->maxlen = atoi(val);
709 } else if (!strcasecmp(param, "servicelevel")) {
710 q->servicelevel= atoi(val);
711 } else if (!strcasecmp(param, "strategy")) {
712 q->strategy = strat2int(val);
713 if (q->strategy < 0) {
714 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
718 } else if (!strcasecmp(param, "joinempty")) {
719 if (!strcasecmp(val, "strict"))
720 q->joinempty = QUEUE_EMPTY_STRICT;
721 else if (ast_true(val))
722 q->joinempty = QUEUE_EMPTY_NORMAL;
725 } else if (!strcasecmp(param, "leavewhenempty")) {
726 if (!strcasecmp(val, "strict"))
727 q->leavewhenempty = QUEUE_EMPTY_STRICT;
728 else if (ast_true(val))
729 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
731 q->leavewhenempty = 0;
732 } else if (!strcasecmp(param, "eventmemberstatus")) {
733 q->maskmemberstatus = !ast_true(val);
734 } else if (!strcasecmp(param, "eventwhencalled")) {
735 q->eventwhencalled = ast_true(val);
736 } else if (!strcasecmp(param, "reportholdtime")) {
737 q->reportholdtime = ast_true(val);
738 } else if (!strcasecmp(param, "memberdelay")) {
739 q->memberdelay = atoi(val);
740 } else if (!strcasecmp(param, "weight")) {
741 q->weight = atoi(val);
744 /* With Realtime queues, if the last queue using weights is deleted in realtime,
745 we will not see any effect on use_weight until next reload. */
746 } else if (!strcasecmp(param, "timeoutrestart")) {
747 q->timeoutrestart = ast_true(val);
748 } else if(failunknown) {
750 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
751 q->name, param, linenum);
753 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
758 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
760 struct member *m, *prev_m;
764 penalty = atoi(penalty_str);
769 /* Find the member, or the place to put a new one. */
772 while (m && strcmp(m->interface, interface)) {
777 /* Create a new one if not found, else update penalty */
779 m = create_queue_member(interface, penalty, 0);
789 m->dead = 0; /* Do not delete this one. */
790 m->penalty = penalty;
794 static void free_members(struct ast_call_queue *q, int all)
796 /* Free non-dynamic members */
797 struct member *curm, *next, *prev = NULL;
799 for (curm = q->members; curm; curm = next) {
801 if (all || !curm->dynamic) {
812 static void destroy_queue(struct ast_call_queue *q)
815 ast_mutex_destroy(&q->lock);
819 /*!\brief Reload a single queue via realtime.
820 \return Return the queue, or NULL if it doesn't exist.
821 \note Should be called with the global qlock locked. */
822 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
824 struct ast_variable *v;
825 struct ast_call_queue *q;
826 struct member *m, *prev_m, *next_m;
828 char *tmp, *tmp_name;
829 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
831 /* Find the queue in the in-core list (we will create a new one if not found). */
832 AST_LIST_TRAVERSE(&queues, q, list) {
833 if (!strcasecmp(q->name, queuename)) {
838 /* Static queues override realtime. */
840 ast_mutex_lock(&q->lock);
843 ast_mutex_unlock(&q->lock);
846 ast_mutex_unlock(&q->lock);
850 } else if (!member_config)
851 /* Not found in the list, and it's not realtime ... */
854 /* Check if queue is defined in realtime. */
856 /* Delete queue from in-core list if it has been deleted in realtime. */
858 /*! \note Hmm, can't seem to distinguish a DB failure from a not
859 found condition... So we might delete an in-core queue
860 in case of DB failure. */
861 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
864 /* Delete if unused (else will be deleted when last caller leaves). */
867 AST_LIST_REMOVE(&queues, q, list);
868 ast_mutex_unlock(&q->lock);
871 ast_mutex_unlock(&q->lock);
876 /* Create a new queue if an in-core entry does not exist yet. */
878 if (!(q = alloc_queue(queuename)))
880 ast_mutex_lock(&q->lock);
883 AST_LIST_INSERT_HEAD(&queues, q, list);
885 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
888 memset(tmpbuf, 0, sizeof(tmpbuf));
890 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
891 if((tmp = strchr(v->name, '_')) != NULL) {
892 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
895 while((tmp = strchr(tmp, '_')) != NULL)
899 queue_set_param(q, tmp_name, v->value, -1, 0);
903 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
911 interface = ast_category_browse(member_config, NULL);
913 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
914 interface = ast_category_browse(member_config, interface);
917 /* Delete all realtime members that have been deleted in DB. */
924 prev_m->next = next_m;
935 ast_mutex_unlock(&q->lock);
940 static struct ast_call_queue *load_realtime_queue(char *queuename)
942 struct ast_variable *queue_vars = NULL;
943 struct ast_config *member_config = NULL;
944 struct ast_call_queue *q;
946 /* Find the queue in the in-core list first. */
947 AST_LIST_LOCK(&queues);
948 AST_LIST_TRAVERSE(&queues, q, list) {
949 if (!strcasecmp(q->name, queuename)) {
953 AST_LIST_UNLOCK(&queues);
955 if (!q || q->realtime) {
956 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
957 queue operations while waiting for the DB.
959 This will be two separate database transactions, so we might
960 see queue parameters as they were before another process
961 changed the queue and member list as it was after the change.
962 Thus we might see an empty member list when a queue is
963 deleted. In practise, this is unlikely to cause a problem. */
965 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
967 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
968 if (!member_config) {
969 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
974 AST_LIST_LOCK(&queues);
976 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
978 ast_config_destroy(member_config);
980 ast_variables_destroy(queue_vars);
982 AST_LIST_UNLOCK(&queues);
987 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
989 struct ast_call_queue *q;
990 struct queue_ent *cur, *prev = NULL;
994 enum queue_member_status stat;
996 q = load_realtime_queue(queuename);
1000 AST_LIST_LOCK(&queues);
1001 ast_mutex_lock(&q->lock);
1003 /* This is our one */
1004 stat = get_member_status(q, qe->max_penalty);
1005 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1006 *reason = QUEUE_JOINEMPTY;
1007 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1008 *reason = QUEUE_JOINUNAVAIL;
1009 else if (q->maxlen && (q->count >= q->maxlen))
1010 *reason = QUEUE_FULL;
1012 /* There's space for us, put us at the right position inside
1014 * Take into account the priority of the calling user */
1019 /* We have higher priority than the current user, enter
1020 * before him, after all the other users with priority
1021 * higher or equal to our priority. */
1022 if ((!inserted) && (qe->prio > cur->prio)) {
1023 insert_entry(q, prev, qe, &pos);
1030 /* No luck, join at the end of the queue */
1032 insert_entry(q, prev, qe, &pos);
1033 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1034 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1035 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1038 manager_event(EVENT_FLAG_CALL, "Join",
1039 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1041 qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
1042 qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
1043 q->name, qe->pos, q->count, qe->chan->uniqueid );
1045 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1048 ast_mutex_unlock(&q->lock);
1049 AST_LIST_UNLOCK(&queues);
1053 static int play_file(struct ast_channel *chan, char *filename)
1057 ast_stopstream(chan);
1058 res = ast_streamfile(chan, filename, chan->language);
1061 res = ast_waitstream(chan, AST_DIGIT_ANY);
1065 ast_stopstream(chan);
1070 static int valid_exit(struct queue_ent *qe, char digit)
1072 int digitlen = strlen(qe->digits);
1074 /* Prevent possible buffer overflow */
1075 if (digitlen < sizeof(qe->digits) - 2) {
1076 qe->digits[digitlen] = digit;
1077 qe->digits[digitlen + 1] = '\0';
1079 qe->digits[0] = '\0';
1083 /* If there's no context to goto, short-circuit */
1084 if (ast_strlen_zero(qe->context))
1087 /* If the extension is bad, then reset the digits to blank */
1088 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1089 qe->digits[0] = '\0';
1093 /* We have an exact match */
1094 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1095 /* Return 1 on a successful goto */
1101 static int say_position(struct queue_ent *qe)
1103 int res = 0, avgholdmins, avgholdsecs;
1106 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1108 if ( (now - qe->last_pos) < 15 )
1111 /* If either our position has changed, or we are over the freq timer, say position */
1112 if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
1115 ast_moh_stop(qe->chan);
1116 /* Say we're next, if we are */
1118 res = play_file(qe->chan, qe->parent->sound_next);
1119 if (res && valid_exit(qe, res))
1124 res = play_file(qe->chan, qe->parent->sound_thereare);
1125 if (res && valid_exit(qe, res))
1127 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1128 if (res && valid_exit(qe, res))
1130 res = play_file(qe->chan, qe->parent->sound_calls);
1131 if (res && valid_exit(qe, res))
1134 /* Round hold time to nearest minute */
1135 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
1137 /* If they have specified a rounding then round the seconds as well */
1138 if(qe->parent->roundingseconds) {
1139 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
1140 avgholdsecs*= qe->parent->roundingseconds;
1145 if (option_verbose > 2)
1146 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1148 /* If the hold time is >1 min, if it's enabled, and if it's not
1149 supposed to be only once and we have already said it, say it */
1150 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1151 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1152 res = play_file(qe->chan, qe->parent->sound_holdtime);
1153 if (res && valid_exit(qe, res))
1156 if (avgholdmins>0) {
1157 if (avgholdmins < 2) {
1158 res = play_file(qe->chan, qe->parent->sound_lessthan);
1159 if (res && valid_exit(qe, res))
1162 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1163 if (res && valid_exit(qe, res))
1166 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1167 if (res && valid_exit(qe, res))
1171 res = play_file(qe->chan, qe->parent->sound_minutes);
1172 if (res && valid_exit(qe, res))
1175 if (avgholdsecs>0) {
1176 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1177 if (res && valid_exit(qe, res))
1180 res = play_file(qe->chan, qe->parent->sound_seconds);
1181 if (res && valid_exit(qe, res))
1188 if (option_verbose > 2)
1189 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1190 qe->chan->name, qe->parent->name, qe->pos);
1191 res = play_file(qe->chan, qe->parent->sound_thanks);
1194 /* Set our last_pos indicators */
1196 qe->last_pos_said = qe->pos;
1197 ast_moh_start(qe->chan, qe->moh);
1202 static void recalc_holdtime(struct queue_ent *qe)
1204 int oldvalue, newvalue;
1206 /* Calculate holdtime using a recursive boxcar filter */
1207 /* Thanks to SRT for this contribution */
1208 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1210 newvalue = time(NULL) - qe->start;
1212 ast_mutex_lock(&qe->parent->lock);
1213 if (newvalue <= qe->parent->servicelevel)
1214 qe->parent->callscompletedinsl++;
1215 oldvalue = qe->parent->holdtime;
1216 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1217 ast_mutex_unlock(&qe->parent->lock);
1221 static void leave_queue(struct queue_ent *qe)
1223 struct ast_call_queue *q;
1224 struct queue_ent *cur, *prev = NULL;
1230 ast_mutex_lock(&q->lock);
1238 /* Take us out of the queue */
1239 manager_event(EVENT_FLAG_CALL, "Leave",
1240 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
1241 qe->chan->name, q->name, q->count);
1243 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1245 /* Take us out of the queue */
1247 prev->next = cur->next;
1249 q->head = cur->next;
1251 /* Renumber the people after us in the queue based on a new count */
1257 ast_mutex_unlock(&q->lock);
1258 if (q->dead && !q->count) {
1259 /* It's dead and nobody is in it, so kill it */
1260 AST_LIST_LOCK(&queues);
1261 AST_LIST_REMOVE(&queues, q, list);
1262 AST_LIST_UNLOCK(&queues);
1267 /* Hang up a list of outgoing calls */
1268 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1270 struct callattempt *oo;
1273 /* Hangup any existing lines we have open */
1274 if (outgoing->chan && (outgoing->chan != exception))
1275 ast_hangup(outgoing->chan);
1277 outgoing=outgoing->q_next;
1282 static int update_status(struct ast_call_queue *q, struct member *member, int status)
1286 /* Since a reload could have taken place, we have to traverse the list to
1287 be sure it's still valid */
1288 ast_mutex_lock(&q->lock);
1289 for (cur = q->members; cur; cur = cur->next) {
1290 if (member == cur) {
1291 cur->status = status;
1292 if (!q->maskmemberstatus) {
1293 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1296 "Membership: %s\r\n"
1298 "CallsTaken: %d\r\n"
1302 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1303 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1308 ast_mutex_unlock(&q->lock);
1312 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
1314 if (status == AST_CAUSE_BUSY)
1315 status = AST_DEVICE_BUSY;
1316 else if (status == AST_CAUSE_UNREGISTERED)
1317 status = AST_DEVICE_UNAVAILABLE;
1318 else if (status == AST_CAUSE_NOSUCHDRIVER)
1319 status = AST_DEVICE_INVALID;
1321 status = AST_DEVICE_UNKNOWN;
1322 return update_status(q, member, status);
1325 /* traverse all defined queues which have calls waiting and contain this member
1326 return 0 if no other queue has precedence (higher weight) or 1 if found */
1327 static int compare_weight(struct ast_call_queue *rq, struct member *member)
1329 struct ast_call_queue *q;
1333 /* &qlock and &rq->lock already set by try_calling()
1334 * to solve deadlock */
1335 AST_LIST_TRAVERSE(&queues, q, list) {
1336 if (q == rq) /* don't check myself, could deadlock */
1338 ast_mutex_lock(&q->lock);
1339 if (q->count && q->members) {
1340 for (mem = q->members; mem; mem = mem->next) {
1341 if (!strcmp(mem->interface, member->interface)) {
1342 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1343 if (q->weight > rq->weight) {
1344 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);
1351 ast_mutex_unlock(&q->lock);
1358 /*! \brief common hangup actions */
1359 static void do_hang(struct callattempt *o)
1362 ast_hangup(o->chan);
1366 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1373 /* on entry here, we know that tmp->chan == NULL */
1374 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1376 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1378 ast_cdr_busy(qe->chan->cdr);
1379 tmp->stillgoing = 0;
1384 if (!qe->parent->ringinuse && (tmp->member->status == AST_DEVICE_INUSE)) {
1386 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1388 ast_cdr_busy(qe->chan->cdr);
1389 tmp->stillgoing = 0;
1393 if (tmp->member->paused) {
1395 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1397 ast_cdr_busy(qe->chan->cdr);
1398 tmp->stillgoing = 0;
1401 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1402 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1404 ast_cdr_busy(qe->chan->cdr);
1405 tmp->stillgoing = 0;
1410 ast_copy_string(tech, tmp->interface, sizeof(tech));
1411 if ((location = strchr(tech, '/')))
1416 /* Request the peer */
1417 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1418 if (!tmp->chan) { /* If we can't, just go on to the next call */
1420 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
1423 ast_cdr_busy(qe->chan->cdr);
1424 tmp->stillgoing = 0;
1425 update_dial_status(qe->parent, tmp->member, status);
1428 } else if (status != tmp->oldstatus)
1429 update_dial_status(qe->parent, tmp->member, status);
1431 tmp->chan->appl = "AppQueue";
1432 tmp->chan->data = "(Outgoing Line)";
1433 tmp->chan->whentohangup = 0;
1434 if (tmp->chan->cid.cid_num)
1435 free(tmp->chan->cid.cid_num);
1436 tmp->chan->cid.cid_num = NULL;
1437 if (tmp->chan->cid.cid_name)
1438 free(tmp->chan->cid.cid_name);
1439 tmp->chan->cid.cid_name = NULL;
1440 if (tmp->chan->cid.cid_ani)
1441 free(tmp->chan->cid.cid_ani);
1442 tmp->chan->cid.cid_ani = NULL;
1443 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1444 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1445 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1447 /* Inherit specially named variables from parent channel */
1448 ast_channel_inherit_variables(qe->chan, tmp->chan);
1450 /* Presense of ADSI CPE on outgoing channel follows ours */
1451 tmp->chan->adsicpe = qe->chan->adsicpe;
1453 /* Place the call, but don't wait on the answer */
1454 res = ast_call(tmp->chan, location, 0);
1456 /* Again, keep going even if there's an error */
1458 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1459 else if (option_verbose > 2)
1460 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1465 if (qe->parent->eventwhencalled) {
1466 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1467 "AgentCalled: %s\r\n"
1468 "ChannelCalling: %s\r\n"
1470 "CallerIDName: %s\r\n"
1474 tmp->interface, qe->chan->name,
1475 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1476 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1477 qe->chan->context, qe->chan->exten, qe->chan->priority);
1479 if (option_verbose > 2)
1480 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1485 /*! \brief find the entry with the best metric, or NULL */
1486 static struct callattempt *find_best(struct callattempt *outgoing)
1488 struct callattempt *best = NULL, *cur;
1490 for (cur = outgoing; cur; cur = cur->q_next) {
1491 if (cur->stillgoing && /* Not already done */
1492 !cur->chan && /* Isn't already going */
1493 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1500 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1505 struct callattempt *best = find_best(outgoing);
1508 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1511 if (!qe->parent->strategy) {
1512 struct callattempt *cur;
1513 /* Ring everyone who shares this best metric (for ringall) */
1514 for (cur = outgoing; cur; cur = cur->q_next) {
1515 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1517 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1518 ring_entry(qe, cur, busies);
1522 /* Ring just the best channel */
1524 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1525 ring_entry(qe, best, busies);
1527 if (best->chan) /* break out with result = 1 */
1533 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1535 struct callattempt *best = find_best(outgoing);
1538 /* Ring just the best channel */
1540 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1541 qe->parent->rrpos = best->metric % 1000;
1543 /* Just increment rrpos */
1544 if (qe->parent->wrapped) {
1545 /* No more channels, start over */
1546 qe->parent->rrpos = 0;
1548 /* Prioritize next entry */
1549 qe->parent->rrpos++;
1552 qe->parent->wrapped = 0;
1556 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1560 ast_stopstream(chan);
1561 res = ast_streamfile(chan, filename, chan->language);
1564 /* Wait for a keypress */
1565 res = ast_waitstream(chan, AST_DIGIT_ANY);
1566 if (res <= 0 || !valid_exit(qe, res))
1570 ast_stopstream(chan);
1576 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
1583 static int say_periodic_announcement(struct queue_ent *qe)
1588 /* Get the current time */
1591 /* Check to see if it is time to announce */
1592 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1595 /* Stop the music on hold so we can play our own file */
1596 ast_moh_stop(qe->chan);
1598 if (option_verbose > 2)
1599 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1601 /* Check to make sure we have a sound file. If not, reset to the first sound file */
1602 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
1603 qe->last_periodic_announce_sound = 0;
1606 /* play the announcement */
1607 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
1609 /* Resume Music on Hold */
1610 ast_moh_start(qe->chan, qe->moh);
1612 /* update last_periodic_announce_time */
1613 qe->last_periodic_announce_time = now;
1615 /* Update the current periodic announcement to the next announcement */
1616 qe->last_periodic_announce_sound++;
1621 static void record_abandoned(struct queue_ent *qe)
1623 ast_mutex_lock(&qe->parent->lock);
1624 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
1628 "OriginalPosition: %d\r\n"
1630 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
1632 qe->parent->callsabandoned++;
1633 ast_mutex_unlock(&qe->parent->lock);
1637 #define AST_MAX_WATCHERS 256
1639 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1641 char *queue = qe->parent->name;
1642 struct callattempt *o;
1644 int sentringing = 0;
1645 int numbusies = prebusies;
1649 struct ast_frame *f;
1650 struct callattempt *peer = NULL;
1651 struct ast_channel *winner;
1652 struct ast_channel *in = qe->chan;
1655 while(*to && !peer) {
1656 int numlines, retry, pos = 1;
1657 struct ast_channel *watchers[AST_MAX_WATCHERS];
1660 for (retry = 0; retry < 2; retry++) {
1662 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
1663 if (o->stillgoing) { /* Keep track of important channels */
1666 watchers[pos++] = o->chan;
1670 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
1671 qe->parent->strategy /* ring would not be delivered */)
1673 /* On "ringall" strategy we only move to the next penalty level
1674 when *all* ringing phones are done in the current penalty level */
1675 ring_one(qe, outgoing, &numbusies);
1678 if (pos == 1 /* not found */) {
1679 if (numlines == (numbusies + numnochan)) {
1680 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1682 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1687 winner = ast_waitfor_n(watchers, pos, to);
1688 for (o = outgoing; o; o = o->q_next) {
1689 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
1691 if (option_verbose > 2)
1692 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1695 } else if (o->chan && (o->chan == winner)) {
1696 ast_copy_string(on, o->member->interface, sizeof(on));
1697 if (!ast_strlen_zero(o->chan->call_forward)) {
1698 char tmpchan[256]="";
1701 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1702 if ((stuff = strchr(tmpchan, '/'))) {
1706 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1710 /* Before processing channel, go ahead and check for forwarding */
1711 if (option_verbose > 2)
1712 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1713 /* Setup parameters */
1714 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1715 if (status != o->oldstatus)
1716 update_dial_status(qe->parent, o->member, status);
1718 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1722 if (o->chan->cid.cid_num)
1723 free(o->chan->cid.cid_num);
1724 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
1726 if (o->chan->cid.cid_name)
1727 free(o->chan->cid.cid_name);
1728 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
1730 ast_string_field_set(o->chan, accountcode, in->accountcode);
1731 o->chan->cdrflags = in->cdrflags;
1733 if (in->cid.cid_ani) {
1734 if (o->chan->cid.cid_ani)
1735 free(o->chan->cid.cid_ani);
1736 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
1738 if (o->chan->cid.cid_rdnis)
1739 free(o->chan->cid.cid_rdnis);
1740 o->chan->cid.cid_rdnis =
1741 ast_strdup(S_OR(in->macroexten, in->exten));
1742 if (ast_call(o->chan, tmpchan, 0)) {
1743 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1748 /* Hangup the original channel now, in case we needed it */
1752 f = ast_read(winner);
1754 if (f->frametype == AST_FRAME_CONTROL) {
1755 switch(f->subclass) {
1756 case AST_CONTROL_ANSWER:
1757 /* This is our guy if someone answered. */
1759 if (option_verbose > 2)
1760 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1764 case AST_CONTROL_BUSY:
1765 if (option_verbose > 2)
1766 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1768 ast_cdr_busy(in->cdr);
1770 if (qe->parent->strategy) {
1771 if (qe->parent->timeoutrestart)
1773 ring_one(qe, outgoing, &numbusies);
1777 case AST_CONTROL_CONGESTION:
1778 if (option_verbose > 2)
1779 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1781 ast_cdr_busy(in->cdr);
1783 if (qe->parent->strategy) {
1784 if (qe->parent->timeoutrestart)
1786 ring_one(qe, outgoing, &numbusies);
1790 case AST_CONTROL_RINGING:
1791 if (option_verbose > 2)
1792 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1795 ast_indicate(in, AST_CONTROL_RINGING);
1800 case AST_CONTROL_OFFHOOK:
1801 /* Ignore going off hook */
1804 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1810 if (qe->parent->strategy) {
1811 if (qe->parent->timeoutrestart)
1813 ring_one(qe, outgoing, &numbusies);
1821 if (f && (f->frametype != AST_FRAME_VOICE))
1822 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1823 else if (!f || (f->frametype != AST_FRAME_VOICE))
1824 printf("Hangup received on %s\n", in->name);
1826 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1833 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1834 if (option_verbose > 3)
1835 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1840 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1841 if (option_verbose > 3)
1842 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1851 if (option_verbose > 2)
1852 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1853 if (qe->parent->autopause) {
1854 if (!set_member_paused(qe->parent->name, on, 1)) {
1855 if (option_verbose > 2)
1856 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", on, qe->parent->name);
1858 if (option_verbose > 2)
1859 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", on, qe->parent->name);
1868 static int is_our_turn(struct queue_ent *qe)
1870 struct queue_ent *ch;
1873 /* Atomically read the parent head -- does not need a lock */
1874 ch = qe->parent->head;
1875 /* If we are now at the top of the head, break out */
1876 if ((ch == qe) || (qe->parent->autofill)) {
1878 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1882 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1888 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1892 /* This is the holding pen for callers 2 through maxlen */
1894 enum queue_member_status stat;
1896 if (is_our_turn(qe))
1899 /* If we have timed out, break out */
1900 if (qe->expire && (time(NULL) > qe->expire)) {
1901 *reason = QUEUE_TIMEOUT;
1902 ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
1906 stat = get_member_status(qe->parent, qe->max_penalty);
1908 /* leave the queue if no agents, if enabled */
1909 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1910 *reason = QUEUE_LEAVEEMPTY;
1915 /* leave the queue if no reachable agents, if enabled */
1916 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1917 *reason = QUEUE_LEAVEUNAVAIL;
1922 /* Make a position announcement, if enabled */
1923 if (qe->parent->announcefrequency && !ringing)
1924 res = say_position(qe);
1928 /* Make a periodic announcement, if enabled */
1929 if (qe->parent->periodicannouncefrequency && !ringing)
1930 res = say_periodic_announcement(qe);
1932 /* Wait a second before checking again */
1933 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1940 static int update_queue(struct ast_call_queue *q, struct member *member)
1944 /* Since a reload could have taken place, we have to traverse the list to
1945 be sure it's still valid */
1946 ast_mutex_lock(&q->lock);
1949 if (member == cur) {
1950 time(&cur->lastcall);
1956 q->callscompleted++;
1957 ast_mutex_unlock(&q->lock);
1961 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
1963 if (mem->penalty > qe->max_penalty)
1966 switch (q->strategy) {
1967 case QUEUE_STRATEGY_RINGALL:
1968 /* Everyone equal, except for penalty */
1969 tmp->metric = mem->penalty * 1000000;
1971 case QUEUE_STRATEGY_ROUNDROBIN:
1974 /* No more channels, start over */
1977 /* Prioritize next entry */
1983 case QUEUE_STRATEGY_RRMEMORY:
1984 if (pos < q->rrpos) {
1985 tmp->metric = 1000 + pos;
1988 /* Indicate there is another priority */
1992 tmp->metric += mem->penalty * 1000000;
1994 case QUEUE_STRATEGY_RANDOM:
1995 tmp->metric = rand() % 1000;
1996 tmp->metric += mem->penalty * 1000000;
1998 case QUEUE_STRATEGY_FEWESTCALLS:
1999 tmp->metric = mem->calls;
2000 tmp->metric += mem->penalty * 1000000;
2002 case QUEUE_STRATEGY_LEASTRECENT:
2006 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2007 tmp->metric += mem->penalty * 1000000;
2010 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2016 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
2019 struct callattempt *outgoing=NULL; /* the queue we are building */
2021 char restofit[AST_MAX_EXTENSION];
2022 char oldexten[AST_MAX_EXTENSION]="";
2023 char oldcontext[AST_MAX_CONTEXT]="";
2024 char queuename[256]="";
2026 struct ast_channel *peer;
2027 struct ast_channel *which;
2028 struct callattempt *lpeer;
2029 struct member *member;
2030 int res = 0, bridge = 0;
2033 char *announce = NULL;
2036 time_t now = time(NULL);
2037 struct ast_bridge_config bridge_config;
2038 char nondataquality = 1;
2040 memset(&bridge_config, 0, sizeof(bridge_config));
2043 for (; options && *options; options++)
2046 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2049 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2052 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2055 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2061 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2064 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2067 if ((now - qe->start >= qe->parent->timeout))
2072 /* Hold the lock while we setup the outgoing calls */
2074 AST_LIST_LOCK(&queues);
2075 ast_mutex_lock(&qe->parent->lock);
2077 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2079 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2080 cur = qe->parent->members;
2081 if (!ast_strlen_zero(qe->announce))
2082 announce = qe->announce;
2083 if (!ast_strlen_zero(announceoverride))
2084 announce = announceoverride;
2086 for (;cur; cur = cur->next) {
2087 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2089 ast_mutex_unlock(&qe->parent->lock);
2091 AST_LIST_UNLOCK(&queues);
2094 tmp->stillgoing = -1;
2097 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2099 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
2102 tmp->member = cur; /* Never directly dereference! Could change on reload */
2103 tmp->oldstatus = cur->status;
2104 tmp->lastcall = cur->lastcall;
2105 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2106 /* If we're dialing by extension, look at the extension to know what to dial */
2107 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
2109 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
2110 snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
2112 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
2114 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2115 just calculate their metric for the appropriate strategy */
2116 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2117 /* Put them in the list of outgoing thingies... We're ready now.
2118 XXX If we're forcibly removed, these outgoing calls won't get
2120 tmp->q_next = outgoing;
2122 /* If this line is up, don't try anybody else */
2123 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2129 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2130 ring_one(qe, outgoing, &numbusies);
2131 ast_mutex_unlock(&qe->parent->lock);
2133 AST_LIST_UNLOCK(&queues);
2134 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
2135 ast_mutex_lock(&qe->parent->lock);
2136 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2137 store_next(qe, outgoing);
2139 ast_mutex_unlock(&qe->parent->lock);
2140 peer = lpeer ? lpeer->chan : NULL;
2143 /* Must gotten hung up */
2149 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2150 } else { /* peer is valid */
2151 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2152 we will always return with -1 so that it is hung up properly after the
2155 if (!strcmp(qe->chan->tech->type, "Zap"))
2156 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2157 if (!strcmp(peer->tech->type, "Zap"))
2158 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2159 /* Update parameters for the queue */
2160 recalc_holdtime(qe);
2161 member = lpeer->member;
2162 hangupcalls(outgoing, peer);
2164 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2166 res2 = ast_autoservice_start(qe->chan);
2168 if (qe->parent->memberdelay) {
2169 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2170 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2172 if (!res2 && announce) {
2173 if (play_file(peer, announce))
2174 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2176 if (!res2 && qe->parent->reportholdtime) {
2177 if (!play_file(peer, qe->parent->sound_reporthold)) {
2181 holdtime = abs((now - qe->start) / 60);
2183 play_file(peer, qe->parent->sound_lessthan);
2184 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2186 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2187 play_file(peer, qe->parent->sound_minutes);
2191 res2 |= ast_autoservice_stop(qe->chan);
2192 if (peer->_softhangup) {
2193 /* Agent must have hung up */
2194 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
2195 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
2196 record_abandoned(qe);
2197 if (qe->parent->eventwhencalled) {
2198 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2203 queuename, qe->chan->uniqueid, peer->name, member->interface);
2208 /* Caller must have hung up just before being connected*/
2209 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2210 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2211 record_abandoned(qe);
2216 /* Stop music on hold */
2217 ast_moh_stop(qe->chan);
2218 /* If appropriate, log that we have a destination channel */
2220 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2221 /* Make sure channels are compatible */
2222 res = ast_channel_make_compatible(qe->chan, peer);
2224 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2225 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2226 record_abandoned(qe);
2230 /* Begin Monitoring */
2231 if (qe->parent->monfmt && *qe->parent->monfmt) {
2232 const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2233 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2237 if (monitorfilename)
2238 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2239 else if (qe->chan->cdr)
2240 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2242 /* Last ditch effort -- no CDR, make up something */
2244 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
2245 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2247 if (qe->parent->monjoin)
2248 ast_monitor_setjoinfiles(which, 1);
2250 /* Drop out of the queue at this point, to prepare for next caller */
2252 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2254 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2255 ast_channel_sendurl(peer, url);
2257 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
2258 if (qe->parent->eventwhencalled)
2259 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2264 "Holdtime: %ld\r\n",
2265 queuename, qe->chan->uniqueid, peer->name, member->interface,
2266 (long)time(NULL) - qe->start);
2267 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2268 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2271 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2273 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2274 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
2275 } else if (qe->chan->_softhangup) {
2276 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2277 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2278 if (qe->parent->eventwhencalled)
2279 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2286 "Reason: caller\r\n",
2287 queuename, qe->chan->uniqueid, peer->name, member->interface,
2288 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2290 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2291 if (qe->parent->eventwhencalled)
2292 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2298 "Reason: agent\r\n",
2299 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2300 (long)(time(NULL) - callstart));
2303 if(bridge != AST_PBX_NO_HANGUP_PEER)
2305 update_queue(qe->parent, member);
2307 res = 1; /* JDG: bridge successfully, leave app_queue */
2309 res = bridge; /* bridge error, stay in the queue */
2312 hangupcalls(outgoing, NULL);
2316 static int wait_a_bit(struct queue_ent *qe)
2318 /* Don't need to hold the lock while we setup the outgoing calls */
2319 int retrywait = qe->parent->retry * 1000;
2321 return ast_waitfordigit(qe->chan, retrywait);
2324 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2329 for (mem = q->members; mem; mem = mem->next)
2330 if (!strcasecmp(interface, mem->interface))
2337 /* Dump all members in a specific queue to the database
2339 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2342 static void dump_queue_members(struct ast_call_queue *pm_queue)
2344 struct member *cur_member;
2345 char value[PM_MAX_LEN];
2349 memset(value, 0, sizeof(value));
2354 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2355 if (!cur_member->dynamic)
2358 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2359 cur_member->interface, cur_member->penalty, cur_member->paused,
2360 cur_member->next ? "|" : "");
2361 if (res != strlen(value + value_len)) {
2362 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2368 if (value_len && !cur_member) {
2369 if (ast_db_put(pm_family, pm_queue->name, value))
2370 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2372 /* Delete the entry if the queue is empty or there is an error */
2373 ast_db_del(pm_family, pm_queue->name);
2376 static int remove_from_queue(char *queuename, char *interface)
2378 struct ast_call_queue *q;
2379 struct member *last_member, *look;
2380 int res = RES_NOSUCHQUEUE;
2382 AST_LIST_LOCK(&queues);
2383 AST_LIST_TRAVERSE(&queues, q, list) {
2384 ast_mutex_lock(&q->lock);
2385 if (!strcmp(q->name, queuename)) {
2386 if ((last_member = interface_exists(q, interface))) {
2387 if ((look = q->members) == last_member) {
2388 q->members = last_member->next;
2390 while (look != NULL) {
2391 if (look->next == last_member) {
2392 look->next = last_member->next;
2399 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2402 q->name, last_member->interface);
2405 if (queue_persistent_members)
2406 dump_queue_members(q);
2412 ast_mutex_unlock(&q->lock);
2415 ast_mutex_unlock(&q->lock);
2417 AST_LIST_UNLOCK(&queues);
2421 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2423 struct ast_call_queue *q;
2424 struct member *new_member;
2425 int res = RES_NOSUCHQUEUE;
2427 /* \note Ensure the appropriate realtime queue is loaded. Note that this
2428 * short-circuits if the queue is already in memory. */
2429 q = load_realtime_queue(queuename);
2431 AST_LIST_LOCK(&queues);
2434 ast_mutex_lock(&q->lock);
2435 if (interface_exists(q, interface) == NULL) {
2436 new_member = create_queue_member(interface, penalty, paused);
2438 if (new_member != NULL) {
2439 new_member->dynamic = 1;
2440 new_member->next = q->members;
2441 q->members = new_member;
2442 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2445 "Membership: %s\r\n"
2447 "CallsTaken: %d\r\n"
2451 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2452 new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
2455 dump_queue_members(q);
2459 res = RES_OUTOFMEMORY;
2464 ast_mutex_unlock(&q->lock);
2466 AST_LIST_UNLOCK(&queues);
2470 static int set_member_paused(char *queuename, char *interface, int paused)
2473 struct ast_call_queue *q;
2476 /* Special event for when all queues are paused - individual events still generated */
2478 if (ast_strlen_zero(queuename))
2479 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2481 AST_LIST_LOCK(&queues);
2482 AST_LIST_TRAVERSE(&queues, q, list) {
2483 ast_mutex_lock(&q->lock);
2484 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
2485 if ((mem = interface_exists(q, interface))) {
2487 if (mem->paused == paused)
2488 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2489 mem->paused = paused;
2491 if (queue_persistent_members)
2492 dump_queue_members(q);
2494 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2496 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2500 q->name, mem->interface, paused);
2503 ast_mutex_unlock(&q->lock);
2505 AST_LIST_UNLOCK(&queues);
2508 return RESULT_SUCCESS;
2510 return RESULT_FAILURE;
2513 /* Reload dynamic queue members persisted into the astdb */
2514 static void reload_queue_members(void)
2524 struct ast_db_entry *db_tree;
2525 struct ast_db_entry *entry;
2526 struct ast_call_queue *cur_queue;
2527 char queue_data[PM_MAX_LEN];
2529 AST_LIST_LOCK(&queues);
2531 /* Each key in 'pm_family' is the name of a queue */
2532 db_tree = ast_db_gettree(pm_family, NULL);
2533 for (entry = db_tree; entry; entry = entry->next) {
2535 queue_name = entry->key + strlen(pm_family) + 2;
2537 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
2538 ast_mutex_lock(&cur_queue->lock);
2539 if (!strcmp(queue_name, cur_queue->name))
2541 ast_mutex_unlock(&cur_queue->lock);
2545 /* If the queue no longer exists, remove it from the
2547 ast_db_del(pm_family, queue_name);
2550 ast_mutex_unlock(&cur_queue->lock);
2552 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2555 cur_ptr = queue_data;
2556 while ((member = strsep(&cur_ptr, "|"))) {
2557 if (ast_strlen_zero(member))
2560 interface = strsep(&member, ";");
2561 penalty_tok = strsep(&member, ";");
2562 paused_tok = strsep(&member, ";");
2565 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
2568 penalty = strtol(penalty_tok, NULL, 10);
2569 if (errno == ERANGE) {
2570 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2575 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2578 paused = strtol(paused_tok, NULL, 10);
2579 if ((errno == ERANGE) || paused < 0 || paused > 1) {
2580 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2585 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused);
2587 if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2588 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2594 AST_LIST_UNLOCK(&queues);
2596 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
2597 ast_db_freetree(db_tree);
2601 static int pqm_exec(struct ast_channel *chan, void *data)
2603 struct localuser *lu;
2605 int priority_jump = 0;
2606 AST_DECLARE_APP_ARGS(args,
2607 AST_APP_ARG(queuename);
2608 AST_APP_ARG(interface);
2609 AST_APP_ARG(options);
2612 if (ast_strlen_zero(data)) {
2613 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2617 if (!(parse = ast_strdupa(data)))
2620 AST_STANDARD_APP_ARGS(args, parse);
2625 if (strchr(args.options, 'j'))
2629 if (ast_strlen_zero(args.interface)) {
2630 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2631 LOCAL_USER_REMOVE(lu);
2635 if (set_member_paused(args.queuename, args.interface, 1)) {
2636 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
2637 if (priority_jump || ast_opt_priority_jumping) {
2638 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2639 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2640 LOCAL_USER_REMOVE(lu);
2644 LOCAL_USER_REMOVE(lu);
2645 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2649 LOCAL_USER_REMOVE(lu);
2650 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2654 static int upqm_exec(struct ast_channel *chan, void *data)
2656 struct localuser *lu;
2658 int priority_jump = 0;
2659 AST_DECLARE_APP_ARGS(args,
2660 AST_APP_ARG(queuename);
2661 AST_APP_ARG(interface);
2662 AST_APP_ARG(options);
2665 if (ast_strlen_zero(data)) {
2666 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2670 if (!(parse = ast_strdupa(data)))
2673 AST_STANDARD_APP_ARGS(args, parse);
2678 if (strchr(args.options, 'j'))
2682 if (ast_strlen_zero(args.interface)) {
2683 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2684 LOCAL_USER_REMOVE(lu);
2688 if (set_member_paused(args.queuename, args.interface, 0)) {
2689 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
2690 if (priority_jump || ast_opt_priority_jumping) {
2691 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2692 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2693 LOCAL_USER_REMOVE(lu);
2697 LOCAL_USER_REMOVE(lu);
2698 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2702 LOCAL_USER_REMOVE(lu);
2703 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2707 static int rqm_exec(struct ast_channel *chan, void *data)
2710 struct localuser *lu;
2711 char *parse, *temppos = NULL;
2712 int priority_jump = 0;
2713 AST_DECLARE_APP_ARGS(args,
2714 AST_APP_ARG(queuename);
2715 AST_APP_ARG(interface);
2716 AST_APP_ARG(options);
2720 if (ast_strlen_zero(data)) {
2721 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2725 if (!(parse = ast_strdupa(data)))
2728 AST_STANDARD_APP_ARGS(args, parse);
2732 if (ast_strlen_zero(args.interface)) {
2733 args.interface = ast_strdupa(chan->name);
2734 temppos = strrchr(args.interface, '-');
2740 if (strchr(args.options, 'j'))
2744 switch (remove_from_queue(args.queuename, args.interface)) {
2746 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2747 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
2751 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
2752 if (priority_jump || ast_opt_priority_jumping)
2753 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2754 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
2757 case RES_NOSUCHQUEUE:
2758 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
2759 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
2762 case RES_OUTOFMEMORY:
2763 ast_log(LOG_ERROR, "Out of memory\n");
2767 LOCAL_USER_REMOVE(lu);
2771 static int aqm_exec(struct ast_channel *chan, void *data)
2774 struct localuser *lu;
2775 char *parse, *temppos = NULL;
2776 int priority_jump = 0;
2777 AST_DECLARE_APP_ARGS(args,
2778 AST_APP_ARG(queuename);
2779 AST_APP_ARG(interface);
2780 AST_APP_ARG(penalty);
2781 AST_APP_ARG(options);
2785 if (ast_strlen_zero(data)) {
2786 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2790 if (!(parse = ast_strdupa(data)))
2793 AST_STANDARD_APP_ARGS(args, parse);
2797 if (ast_strlen_zero(args.interface)) {
2798 args.interface = ast_strdupa(chan->name);
2799 temppos = strrchr(args.interface, '-');
2804 if (!ast_strlen_zero(args.penalty)) {
2805 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
2806 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
2812 if (strchr(args.options, 'j'))
2817 switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2819 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2820 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
2824 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
2825 if (priority_jump || ast_opt_priority_jumping)
2826 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2827 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
2830 case RES_NOSUCHQUEUE:
2831 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
2832 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
2835 case RES_OUTOFMEMORY:
2836 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2840 LOCAL_USER_REMOVE(lu);
2844 static int queue_exec(struct ast_channel *chan, void *data)
2848 struct localuser *lu;
2849 const char *user_priority;
2850 const char *max_penalty_str;
2853 enum queue_result reason = QUEUE_UNKNOWN;
2855 /* whether to exit Queue application after the timeout hits */
2859 AST_DECLARE_APP_ARGS(args,
2860 AST_APP_ARG(queuename);
2861 AST_APP_ARG(options);
2863 AST_APP_ARG(announceoverride);
2864 AST_APP_ARG(queuetimeoutstr);
2867 /* Our queue entry */
2868 struct queue_ent qe;
2870 if (ast_strlen_zero(data)) {
2871 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2875 parse = ast_strdupa(data);
2877 ast_log(LOG_ERROR, "Out of memory!\n");
2880 AST_STANDARD_APP_ARGS(args, parse);
2884 /* Setup our queue entry */
2885 memset(&qe, 0, sizeof(qe));
2886 qe.start = time(NULL);
2888 /* set the expire time based on the supplied timeout; */
2889 if (args.queuetimeoutstr)
2890 qe.expire = qe.start + atoi(args.queuetimeoutstr);
2894 /* Get the priority from the variable ${QUEUE_PRIO} */
2895 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2896 if (user_priority) {
2897 if (sscanf(user_priority, "%d", &prio) == 1) {
2899 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2902 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2903 user_priority, chan->name);
2907 if (option_debug > 2)
2908 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2912 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
2913 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
2914 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
2916 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
2917 chan->name, max_penalty);
2919 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
2920 max_penalty_str, chan->name);
2927 if (args.options && (strchr(args.options, 'r')))
2931 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
2932 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
2936 qe.max_penalty = max_penalty;
2937 qe.last_pos_said = 0;