2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, 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"
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
102 static struct strategy {
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" },
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 */
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 */
123 static char *tdesc = "True Call Queueing";
125 static char *app = "Queue";
127 static char *synopsis = "Queue a call for a call queue";
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"
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";
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"
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"
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";
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";
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
229 /*! \brief queues.conf [general] option */
230 static int queue_persistent_members = 0;
232 /*! \brief queues.conf per-queue weight option */
233 static int use_weight = 0;
239 QUEUE_LEAVEEMPTY = 3,
240 QUEUE_JOINUNAVAIL = 4,
241 QUEUE_LEAVEUNAVAIL = 5,
246 enum queue_result id;
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" },
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. */
263 struct ast_channel *chan;
269 struct member *member;
270 struct localuser *next;
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 */
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 */
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
313 struct ast_call_queue {
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;
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 */
351 int count; /*!< How many entries */
352 int maxlen; /*!< Max number of entries */
353 int wrapuptime; /*!< Wrapup Time */
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 */
359 /* Queue strategy things */
360 int rrpos; /*!< Round Robin - position */
361 int memberdelay; /*!< Seconds to delay connecting member to caller */
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 */
368 static struct ast_call_queue *queues = NULL;
369 AST_MUTEX_DEFINE_STATIC(qlock);
371 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
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);
383 static char *int2strat(int strategy)
386 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
387 if (strategy == strategies[x].strategy)
388 return strategies[x].name;
393 static int strat2int(const char *strategy)
396 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
397 if (!strcasecmp(strategy, strategies[x].name))
398 return strategies[x].strategy;
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)
406 struct queue_ent *cur;
423 enum queue_member_status {
425 QUEUE_NO_REACHABLE_MEMBERS,
429 static enum queue_member_status get_member_status(const struct ast_call_queue *q)
431 struct member *member;
432 enum queue_member_status result = QUEUE_NO_MEMBERS;
434 for (member = q->members; member; member = member->next) {
435 switch (member->status) {
436 case AST_DEVICE_INVALID:
439 case AST_DEVICE_UNAVAILABLE:
440 result = QUEUE_NO_REACHABLE_MEMBERS;
455 static void *changethread(void *data)
457 struct ast_call_queue *q;
458 struct statechange *sc = data;
463 technology = ast_strdupa(sc->dev);
464 loc = strchr(technology, '/');
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);
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",
492 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
493 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
499 ast_mutex_unlock(&q->lock);
501 ast_mutex_unlock(&qlock);
506 static int statechange_queue(const char *dev, int state, void *ign)
508 /* Avoid potential for deadlocks by spawning a new thread to handle
510 struct statechange *sc;
514 sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
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");
528 static struct member *create_queue_member(char *interface, int penalty, int paused)
532 /* Add a new member */
534 cur = malloc(sizeof(struct member));
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);
549 static struct ast_call_queue *alloc_queue(const char *queuename)
551 struct ast_call_queue *q;
553 q = malloc(sizeof(*q));
555 memset(q, 0, sizeof(*q));
556 ast_mutex_init(&q->lock);
557 ast_copy_string(q->name, queuename, sizeof(q->name));
562 static void init_queue(struct ast_call_queue *q)
565 q->retry = DEFAULT_RETRY;
568 q->announcefrequency = 0;
569 q->announceholdtime = 0;
570 q->roundingseconds = 0; /* Default - don't announce seconds */
573 q->announce[0] = '\0';
574 q->context[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));
589 static void clear_queue(struct ast_call_queue *q)
592 q->callscompleted = 0;
593 q->callsabandoned = 0;
594 q->callscompletedinsl = 0;
598 /*! \brief Configure a queue parameter.
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)
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);
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) {
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);
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);
652 q->roundingseconds=0;
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;
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);
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);
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",
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;
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;
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);
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) {
716 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
717 q->name, param, linenum);
719 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
724 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
726 struct member *m, *prev_m;
730 penalty = atoi(penalty_str);
735 /* Find the member, or the place to put a new one. */
738 while (m && strcmp(m->interface, interface)) {
743 /* Create a new one if not found, else update penalty */
745 m = create_queue_member(interface, penalty, 0);
755 m->dead = 0; /* Do not delete this one. */
756 m->penalty = penalty;
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)
767 struct ast_variable *v;
768 struct ast_call_queue *q, *prev_q;
769 struct member *m, *prev_m, *next_m;
771 char *tmp, *tmp_name;
772 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
774 /* Find the queue in the in-core list (we will create a new one if not found). */
778 if (!strcasecmp(q->name, queuename)) {
785 /* Static queues override realtime. */
787 ast_mutex_lock(&q->lock);
790 ast_mutex_unlock(&q->lock);
796 } else if (!member_config)
797 /* Not found in the list, and it's not realtime ... */
800 /* Check if queue is defined in realtime. */
802 /* Delete queue from in-core list if it has been deleted in realtime. */
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);
810 /* Delete if unused (else will be deleted when last caller leaves). */
816 prev_q->next = q->next;
818 ast_mutex_unlock(&q->lock);
821 ast_mutex_unlock(&q->lock);
826 /* Create a new queue if an in-core entry does not exist yet. */
828 q = alloc_queue(queuename);
831 ast_mutex_lock(&q->lock);
837 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
840 memset(tmpbuf, 0, sizeof(tmpbuf));
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));
847 while((tmp = strchr(tmp, '_')) != NULL)
851 queue_set_param(q, tmp_name, v->value, -1, 0);
855 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
863 interface = ast_category_browse(member_config, NULL);
865 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
866 interface = ast_category_browse(member_config, interface);
869 /* Delete all realtime members that have been deleted in DB. */
876 prev_m->next = next_m;
890 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
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;
899 enum queue_member_status stat;
901 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
902 queue operations while waiting for the DB.
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);
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");
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. */
922 ast_config_destroy(member_config);
924 ast_variables_destroy(queue_vars);
927 ast_mutex_unlock(&qlock);
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;
940 /* There's space for us, put us at the right position inside
942 * Take into account the priority of the calling user */
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);
958 /* No luck, join at the end of the queue */
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));
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",
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 );
973 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
976 ast_mutex_unlock(&q->lock);
977 ast_mutex_unlock(&qlock);
981 static void free_members(struct ast_call_queue *q, int all)
983 /* Free non-dynamic members */
984 struct member *curm, *next, *prev;
990 if (all || !curm->dynamic) {
1002 static void destroy_queue(struct ast_call_queue *q)
1004 struct ast_call_queue *cur, *prev = NULL;
1006 ast_mutex_lock(&qlock);
1007 for (cur = queues; cur; cur = cur->next) {
1010 prev->next = cur->next;
1017 ast_mutex_unlock(&qlock);
1019 ast_mutex_destroy(&q->lock);
1023 static int play_file(struct ast_channel *chan, char *filename)
1027 ast_stopstream(chan);
1028 res = ast_streamfile(chan, filename, chan->language);
1031 res = ast_waitstream(chan, AST_DIGIT_ANY);
1035 ast_stopstream(chan);
1040 static int valid_exit(struct queue_ent *qe, char digit)
1042 int digitlen = strlen(qe->digits);
1044 /* Prevent possible buffer overflow */
1045 if (digitlen < sizeof(qe->digits) - 2) {
1046 qe->digits[digitlen] = digit;
1047 qe->digits[digitlen + 1] = '\0';
1049 qe->digits[0] = '\0';
1053 /* If there's no context to goto, short-circuit */
1054 if (ast_strlen_zero(qe->context))
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';
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 */
1071 static int say_position(struct queue_ent *qe)
1073 int res = 0, avgholdmins, avgholdsecs;
1076 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1078 if ( (now - qe->last_pos) < 15 )
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) )
1085 ast_moh_stop(qe->chan);
1086 /* Say we're next, if we are */
1088 res = play_file(qe->chan, qe->parent->sound_next);
1089 if (res && valid_exit(qe, res))
1094 res = play_file(qe->chan, qe->parent->sound_thereare);
1095 if (res && valid_exit(qe, res))
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))
1100 res = play_file(qe->chan, qe->parent->sound_calls);
1101 if (res && valid_exit(qe, res))
1104 /* Round hold time to nearest minute */
1105 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
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;
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);
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))
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))
1132 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1133 if (res && valid_exit(qe, res))
1136 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1137 if (res && valid_exit(qe, res))
1141 res = play_file(qe->chan, qe->parent->sound_minutes);
1142 if (res && valid_exit(qe, res))
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))
1150 res = play_file(qe->chan, qe->parent->sound_seconds);
1151 if (res && valid_exit(qe, res))
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);
1164 /* Set our last_pos indicators */
1166 qe->last_pos_said = qe->pos;
1167 ast_moh_start(qe->chan, qe->moh);
1172 static void recalc_holdtime(struct queue_ent *qe)
1174 int oldvalue, newvalue;
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 */
1180 newvalue = time(NULL) - qe->start;
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);
1191 static void leave_queue(struct queue_ent *qe)
1193 struct ast_call_queue *q;
1194 struct queue_ent *cur, *prev = NULL;
1200 ast_mutex_lock(&q->lock);
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);
1213 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1215 /* Take us out of the queue */
1217 prev->next = cur->next;
1219 q->head = cur->next;
1221 /* Renumber the people after us in the queue based on a new count */
1227 ast_mutex_unlock(&q->lock);
1228 if (q->dead && !q->count) {
1229 /* It's dead and nobody is in it, so kill it */
1234 /* Hang up a list of outgoing calls */
1235 static void hangupcalls(struct localuser *outgoing, struct ast_channel *exception)
1237 struct localuser *oo;
1240 /* Hangup any existing lines we have open */
1241 if (outgoing->chan && (outgoing->chan != exception))
1242 ast_hangup(outgoing->chan);
1244 outgoing=outgoing->next;
1249 static int update_status(struct ast_call_queue *q, struct member *member, int status)
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);
1258 if (member == cur) {
1259 cur->status = status;
1260 if (!q->maskmemberstatus) {
1261 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1264 "Membership: %s\r\n"
1266 "CallsTaken: %d\r\n"
1270 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1271 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1277 ast_mutex_unlock(&q->lock);
1281 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
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;
1290 status = AST_DEVICE_UNKNOWN;
1291 return update_status(q, member, status);
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)
1298 struct ast_call_queue *q;
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 */
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);
1320 ast_mutex_unlock(&q->lock);
1324 ast_mutex_unlock(&qlock);
1328 static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
1335 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1337 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1339 ast_cdr_busy(qe->chan->cdr);
1340 tmp->stillgoing = 0;
1345 if (tmp->member->paused) {
1347 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1349 ast_cdr_busy(qe->chan->cdr);
1350 tmp->stillgoing = 0;
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);
1356 ast_cdr_busy(qe->chan->cdr);
1357 tmp->stillgoing = 0;
1362 ast_copy_string(tech, tmp->interface, sizeof(tech));
1363 if ((location = strchr(tech, '/')))
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 */
1372 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
1375 ast_cdr_busy(qe->chan->cdr);
1376 tmp->stillgoing = 0;
1377 update_dial_status(qe->parent, tmp->member, status);
1380 } else if (status != tmp->oldstatus)
1381 update_dial_status(qe->parent, tmp->member, status);
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);
1402 /* Inherit specially named variables from parent channel */
1403 ast_channel_inherit_variables(qe->chan, tmp->chan);
1405 /* Presense of ADSI CPE on outgoing channel follows ours */
1406 tmp->chan->adsicpe = qe->chan->adsicpe;
1408 /* Place the call, but don't wait on the answer */
1409 res = ast_call(tmp->chan, location, 0);
1411 /* Again, keep going even if there's an error */
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);
1418 tmp->stillgoing = 0;
1422 if (qe->parent->eventwhencalled) {
1423 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1424 "AgentCalled: %s\r\n"
1425 "ChannelCalling: %s\r\n"
1427 "CallerIDName: %s\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);
1436 if (option_verbose > 2)
1437 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1442 static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
1444 struct localuser *cur;
1445 struct localuser *best;
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;
1461 if (!qe->parent->strategy) {
1462 /* Ring everyone who shares this best metric (for ringall) */
1465 if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
1467 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1468 ring_entry(qe, cur, busies);
1473 /* Ring just the best channel */
1475 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1476 ring_entry(qe, best, busies);
1479 } while (best && !best->chan);
1482 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1488 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
1490 struct localuser *cur;
1491 struct localuser *best;
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;
1506 /* Ring just the best channel */
1508 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1509 qe->parent->rrpos = best->metric % 1000;
1511 /* Just increment rrpos */
1512 if (qe->parent->wrapped) {
1513 /* No more channels, start over */
1514 qe->parent->rrpos = 0;
1516 /* Prioritize next entry */
1517 qe->parent->rrpos++;
1520 qe->parent->wrapped = 0;
1524 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1528 ast_stopstream(chan);
1529 res = ast_streamfile(chan, filename, chan->language);
1532 /* Wait for a keypress */
1533 res = ast_waitstream(chan, AST_DIGIT_ANY);
1534 if (res <= 0 || !valid_exit(qe, res))
1538 ast_stopstream(chan);
1544 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
1551 static int say_periodic_announcement(struct queue_ent *qe)
1556 /* Get the current time */
1559 /* Check to see if it is time to announce */
1560 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1563 /* Stop the music on hold so we can play our own file */
1564 ast_moh_stop(qe->chan);
1566 if (option_verbose > 2)
1567 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1569 /* play the announcement */
1570 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce);
1572 /* Resume Music on Hold */
1573 ast_moh_start(qe->chan, qe->moh);
1575 /* update last_periodic_announce_time */
1576 qe->last_periodic_announce_time = now;
1581 static void record_abandoned(struct queue_ent *qe)
1583 ast_mutex_lock(&qe->parent->lock);
1584 qe->parent->callsabandoned++;
1585 ast_mutex_unlock(&qe->parent->lock);
1589 #define AST_MAX_WATCHERS 256
1591 #define BUILD_WATCHERS do { \
1598 /* Keep track of important channels */ \
1599 if (o->stillgoing) { \
1602 watchers[pos++] = o->chan; \
1611 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1613 char *queue = qe->parent->name;
1614 struct localuser *o;
1618 int sentringing = 0;
1619 int numbusies = prebusies;
1623 struct ast_frame *f;
1624 struct localuser *peer = NULL;
1625 struct ast_channel *watchers[AST_MAX_WATCHERS];
1627 struct ast_channel *winner;
1628 struct ast_channel *in = qe->chan;
1630 while(*to && !peer) {
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);
1639 if (numlines == (numbusies + numnochan)) {
1640 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1642 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1647 winner = ast_waitfor_n(watchers, pos, to);
1650 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
1652 if (option_verbose > 2)
1653 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1656 } else if (o->chan && (o->chan == winner)) {
1657 if (!ast_strlen_zero(o->chan->call_forward)) {
1658 char tmpchan[256]="";
1661 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1662 if ((stuff = strchr(tmpchan, '/'))) {
1667 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
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);
1679 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
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;
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");
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");
1700 ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
1701 o->chan->cdrflags = in->cdrflags;
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);
1710 ast_log(LOG_WARNING, "Out of memory\n");
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);
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);
1721 ast_hangup(o->chan);
1726 /* Hangup the original channel now, in case we needed it */
1730 f = ast_read(winner);
1732 if (f->frametype == AST_FRAME_CONTROL) {
1733 switch(f->subclass) {
1734 case AST_CONTROL_ANSWER:
1735 /* This is our guy if someone answered. */
1737 if (option_verbose > 2)
1738 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1742 case AST_CONTROL_BUSY:
1743 if (option_verbose > 2)
1744 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1747 ast_cdr_busy(in->cdr);
1748 ast_hangup(o->chan);
1750 if (qe->parent->strategy) {
1751 if (qe->parent->timeoutrestart)
1753 ring_one(qe, outgoing, &numbusies);
1757 case AST_CONTROL_CONGESTION:
1758 if (option_verbose > 2)
1759 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1762 ast_cdr_busy(in->cdr);
1763 ast_hangup(o->chan);
1765 if (qe->parent->strategy) {
1766 if (qe->parent->timeoutrestart)
1768 ring_one(qe, outgoing, &numbusies);
1772 case AST_CONTROL_RINGING:
1773 if (option_verbose > 2)
1774 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1777 ast_indicate(in, AST_CONTROL_RINGING);
1782 case AST_CONTROL_OFFHOOK:
1783 /* Ignore going off hook */
1786 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1792 ast_hangup(o->chan);
1794 if (qe->parent->strategy) {
1795 if (qe->parent->timeoutrestart)
1797 ring_one(qe, outgoing, &numbusies);
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);
1811 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
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);
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);
1835 if (!*to && (option_verbose > 2))
1836 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1843 static int is_our_turn(struct queue_ent *qe)
1845 struct queue_ent *ch;
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 */
1853 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1857 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1863 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1867 /* This is the holding pen for callers 2 through maxlen */
1869 enum queue_member_status stat;
1871 if (is_our_turn(qe))
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);
1881 stat = get_member_status(qe->parent);
1883 /* leave the queue if no agents, if enabled */
1884 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1885 *reason = QUEUE_LEAVEEMPTY;
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;
1897 /* Make a position announcement, if enabled */
1898 if (qe->parent->announcefrequency && !ringing)
1899 res = say_position(qe);
1903 /* Make a periodic announcement, if enabled */
1904 if (qe->parent->periodicannouncefrequency && !ringing)
1905 res = say_periodic_announcement(qe);
1907 /* Wait a second before checking again */
1908 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1915 static int update_queue(struct ast_call_queue *q, struct member *member)
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);
1924 if (member == cur) {
1925 time(&cur->lastcall);
1931 q->callscompleted++;
1932 ast_mutex_unlock(&q->lock);
1936 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1938 switch (q->strategy) {
1939 case QUEUE_STRATEGY_RINGALL:
1940 /* Everyone equal, except for penalty */
1941 tmp->metric = mem->penalty * 1000000;
1943 case QUEUE_STRATEGY_ROUNDROBIN:
1946 /* No more channels, start over */
1949 /* Prioritize next entry */
1955 case QUEUE_STRATEGY_RRMEMORY:
1956 if (pos < q->rrpos) {
1957 tmp->metric = 1000 + pos;
1960 /* Indicate there is another priority */
1964 tmp->metric += mem->penalty * 1000000;
1966 case QUEUE_STRATEGY_RANDOM:
1967 tmp->metric = rand() % 1000;
1968 tmp->metric += mem->penalty * 1000000;
1970 case QUEUE_STRATEGY_FEWESTCALLS:
1971 tmp->metric = mem->calls;
1972 tmp->metric += mem->penalty * 1000000;
1974 case QUEUE_STRATEGY_LEASTRECENT:
1978 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1979 tmp->metric += mem->penalty * 1000000;
1982 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1988 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
1991 struct localuser *outgoing=NULL, *tmp = NULL;
1993 char restofit[AST_MAX_EXTENSION];
1994 char oldexten[AST_MAX_EXTENSION]="";
1995 char oldcontext[AST_MAX_CONTEXT]="";
1996 char queuename[256]="";
1998 struct ast_channel *peer;
1999 struct ast_channel *which;
2000 struct localuser *lpeer;
2001 struct member *member;
2002 int res = 0, bridge = 0;
2005 char *announce = NULL;
2008 time_t now = time(NULL);
2009 struct ast_bridge_config bridge_config;
2010 char nondataquality = 1;
2012 memset(&bridge_config, 0, sizeof(bridge_config));
2015 for (; options && *options; options++)
2018 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2021 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2024 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2027 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2033 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2036 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2039 if ((now - qe->start >= qe->parent->timeout))
2044 /* Hold the lock while we setup the outgoing calls */
2046 ast_mutex_lock(&qlock);
2047 ast_mutex_lock(&qe->parent->lock);
2049 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
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;
2059 tmp = malloc(sizeof(*tmp));
2061 ast_mutex_unlock(&qe->parent->lock);
2063 ast_mutex_unlock(&qlock);
2064 ast_log(LOG_WARNING, "Out of memory\n");
2067 memset(tmp, 0, sizeof(*tmp));
2068 tmp->stillgoing = -1;
2071 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2073 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
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"))) {
2083 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
2084 snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
2086 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
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
2094 tmp->next = outgoing;
2096 /* If this line is up, don't try anybody else */
2097 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2102 if (qe->parent->timeout)
2103 to = qe->parent->timeout * 1000;
2106 ring_one(qe, outgoing, &numbusies);
2107 ast_mutex_unlock(&qe->parent->lock);
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);
2115 ast_mutex_unlock(&qe->parent->lock);
2122 /* Musta gotten hung up */
2123 record_abandoned(qe);
2129 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
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
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);
2146 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2148 res2 = ast_autoservice_start(qe->chan);
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);
2154 if (!res2 && announce) {
2155 if (play_file(peer, announce))
2156 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2158 if (!res2 && qe->parent->reportholdtime) {
2159 if (!play_file(peer, qe->parent->sound_reporthold)) {
2163 holdtime = abs((now - qe->start) / 60);
2165 play_file(peer, qe->parent->sound_lessthan);
2166 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2168 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2169 play_file(peer, qe->parent->sound_minutes);
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",
2185 queuename, qe->chan->uniqueid, peer->name, member->interface);
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);
2198 /* Stop music on hold */
2199 ast_moh_stop(qe->chan);
2200 /* If appropriate, log that we have a destination channel */
2202 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2203 /* Make sure channels are compatible */
2204 res = ast_channel_make_compatible(qe->chan, peer);
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);
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"))
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 );
2224 /* Last ditch effort -- no CDR, make up something */
2226 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
2227 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2229 if (qe->parent->monjoin)
2230 ast_monitor_setjoinfiles(which, 1);
2232 /* Drop out of the queue at this point, to prepare for next caller */
2234 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2236 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2237 ast_channel_sendurl(peer, url);
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",
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));
2253 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
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",
2268 "Reason: caller\r\n",
2269 queuename, qe->chan->uniqueid, peer->name, member->interface,
2270 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
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",
2280 "Reason: agent\r\n",
2281 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2282 (long)(time(NULL) - callstart));
2285 if(bridge != AST_PBX_NO_HANGUP_PEER)
2287 update_queue(qe->parent, member);
2289 res = 1; /* JDG: bridge successfull, leave app_queue */
2291 res = bridge; /* bridge error, stay in the queue */
2294 hangupcalls(outgoing, NULL);
2298 static int wait_a_bit(struct queue_ent *qe)
2300 /* Don't need to hold the lock while we setup the outgoing calls */
2301 int retrywait = qe->parent->retry * 1000;
2303 return ast_waitfordigit(qe->chan, retrywait);
2306 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2311 for (mem = q->members; mem; mem = mem->next)
2312 if (!strcasecmp(interface, mem->interface))
2319 /* Dump all members in a specific queue to the databse
2321 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2324 static void dump_queue_members(struct ast_call_queue *pm_queue)
2326 struct member *cur_member;
2327 char value[PM_MAX_LEN];
2331 memset(value, 0, sizeof(value));
2336 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2337 if (!cur_member->dynamic)
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");
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");
2354 /* Delete the entry if the queue is empty or there is an error */
2355 ast_db_del(pm_family, pm_queue->name);
2358 static int remove_from_queue(char *queuename, char *interface)
2360 struct ast_call_queue *q;
2361 struct member *last_member, *look;
2362 int res = RES_NOSUCHQUEUE;
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;
2372 while (look != NULL) {
2373 if (look->next == last_member) {
2374 look->next = last_member->next;
2381 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2384 q->name, last_member->interface);
2387 if (queue_persistent_members)
2388 dump_queue_members(q);
2394 ast_mutex_unlock(&q->lock);
2397 ast_mutex_unlock(&q->lock);
2399 ast_mutex_unlock(&qlock);
2403 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2405 struct ast_call_queue *q;
2406 struct member *new_member;
2407 int res = RES_NOSUCHQUEUE;
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);
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",
2423 "Membership: %s\r\n"
2425 "CallsTaken: %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);
2433 dump_queue_members(q);
2437 res = RES_OUTOFMEMORY;
2442 ast_mutex_unlock(&q->lock);
2445 ast_mutex_unlock(&q->lock);
2447 ast_mutex_unlock(&qlock);
2451 static int set_member_paused(char *queuename, char *interface, int paused)
2454 struct ast_call_queue *q;
2457 /* Special event for when all queues are paused - individual events still generated */
2459 if (ast_strlen_zero(queuename))
2460 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
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))) {
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;
2472 if (queue_persistent_members)
2473 dump_queue_members(q);
2475 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2477 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2481 q->name, mem->interface, paused);
2484 ast_mutex_unlock(&q->lock);
2486 ast_mutex_unlock(&qlock);
2489 return RESULT_SUCCESS;
2491 return RESULT_FAILURE;
2494 /* Reload dynamic queue members persisted into the astdb */
2495 static void reload_queue_members(void)
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];
2510 ast_mutex_lock(&qlock);
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) {
2516 queue_name = entry->key + strlen(pm_family) + 2;
2520 ast_mutex_lock(&cur_queue->lock);
2521 if (!strcmp(queue_name, cur_queue->name))
2523 ast_mutex_unlock(&cur_queue->lock);
2524 cur_queue = cur_queue->next;
2528 /* If the queue no longer exists, remove it from the
2530 ast_db_del(pm_family, queue_name);
2533 ast_mutex_unlock(&cur_queue->lock);
2535 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2538 cur_ptr = queue_data;
2539 while ((member = strsep(&cur_ptr, "|"))) {
2540 if (ast_strlen_zero(member))
2543 interface = strsep(&member, ";");
2544 penalty_tok = strsep(&member, ";");
2545 paused_tok = strsep(&member, ";");
2548 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
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);
2558 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
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);
2568 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused);
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");
2577 ast_mutex_unlock(&qlock);
2579 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2580 ast_db_freetree(db_tree);
2584 static int pqm_exec(struct ast_channel *chan, void *data)
2586 struct localuser *u;
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);
2595 if (ast_strlen_zero(data)) {
2596 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2602 if (!(parse = ast_strdupa(data))) {
2603 ast_log(LOG_WARNING, "Memory Error!\n");
2604 LOCAL_USER_REMOVE(u);
2608 AST_STANDARD_APP_ARGS(args, parse);
2611 if (strchr(args.options, 'j'))
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);
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);
2630 LOCAL_USER_REMOVE(u);
2631 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2635 LOCAL_USER_REMOVE(u);
2636 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2640 static int upqm_exec(struct ast_channel *chan, void *data)
2642 struct localuser *u;
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);
2651 if (ast_strlen_zero(data)) {
2652 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2658 if (!(parse = ast_strdupa(data))) {
2659 ast_log(LOG_WARNING, "Memory Error!\n");
2660 LOCAL_USER_REMOVE(u);
2664 AST_STANDARD_APP_ARGS(args, parse);
2667 if (strchr(args.options, 'j'))
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);
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);
2686 LOCAL_USER_REMOVE(u);
2687 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2691 LOCAL_USER_REMOVE(u);
2692 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2696 static int rqm_exec(struct ast_channel *chan, void *data)
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);
2709 if (ast_strlen_zero(data)) {
2710 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2716 if (!(parse = ast_strdupa(data))) {
2717 ast_log(LOG_WARNING, "Memory Error!\n");
2718 LOCAL_USER_REMOVE(u);
2722 AST_STANDARD_APP_ARGS(args, parse);
2724 if (ast_strlen_zero(args.interface)) {
2725 args.interface = ast_strdupa(chan->name);
2726 temppos = strrchr(args.interface, '-');
2732 if (strchr(args.options, 'j'))
2736 switch (remove_from_queue(args.queuename, args.interface)) {
2738 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2739 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
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");
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");
2754 case RES_OUTOFMEMORY:
2755 ast_log(LOG_ERROR, "Out of memory\n");
2759 LOCAL_USER_REMOVE(u);
2763 static int aqm_exec(struct ast_channel *chan, void *data)
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);
2777 if (ast_strlen_zero(data)) {
2778 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2784 if (!(parse = ast_strdupa(data))) {
2785 ast_log(LOG_WARNING, "Memory Error!\n");
2786 LOCAL_USER_REMOVE(u);
2790 AST_STANDARD_APP_ARGS(args, parse);
2792 if (ast_strlen_zero(args.interface)) {
2793 args.interface = ast_strdupa(chan->name);
2794 temppos = strrchr(args.interface, '-');
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);
2807 if (strchr(args.options, 'j'))
2812 switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2814 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2815 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
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");
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");
2830 case RES_OUTOFMEMORY:
2831 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2835 LOCAL_USER_REMOVE(u);
2839 static int queue_exec(struct ast_channel *chan, void *data)
2843 struct localuser *u;
2846 char *info_ptr = info;
2847 char *options = NULL;
2849 char *announceoverride = NULL;
2850 const char *user_priority;
2852 char *queuetimeoutstr = NULL;
2853 enum queue_result reason = QUEUE_UNKNOWN;
2855 /* whether to exit Queue application after the timeout hits */
2858 /* Our queue entry */
2859 struct queue_ent qe;
2861 if (ast_strlen_zero(data)) {
2862 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2868 /* Setup our queue entry */
2869 memset(&qe, 0, sizeof(qe));
2870 qe.start = time(NULL);
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;
2880 /* set the expire time based on the supplied timeout; */
2881 if (queuetimeoutstr)
2882 qe.expire = qe.start + atoi(queuetimeoutstr);
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) {
2891 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2894 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2895 user_priority, chan->name);
2899 if (option_debug > 2)
2900 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2904 if (options && (strchr(options, 'r')))
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);
2912 qe.prio = (int)prio;
2913 qe.last_pos_said = 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 : "");