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 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
290 time_t start; /*!< When we started holding */
291 time_t expire; /*!< When this entry should expire (time out of queue) */
292 struct ast_channel *chan; /*!< Our channel */
293 struct queue_ent *next; /*!< The next queue entry */
297 char interface[80]; /*!< Technology/Location */
298 int penalty; /*!< Are we a last resort? */
299 int calls; /*!< Number of calls serviced by this member */
300 int dynamic; /*!< Are we dynamically added? */
301 int status; /*!< Status of queue member */
302 int paused; /*!< Are we paused (not accepting calls)? */
303 time_t lastcall; /*!< When last successful call was hungup */
304 int dead; /*!< Used to detect members deleted in realtime */
305 struct member *next; /*!< Next member */
308 /* values used in multi-bit flags in ast_call_queue */
309 #define QUEUE_EMPTY_NORMAL 1
310 #define QUEUE_EMPTY_STRICT 2
311 #define ANNOUNCEHOLDTIME_ALWAYS 1
312 #define ANNOUNCEHOLDTIME_ONCE 2
314 struct ast_call_queue {
316 char name[80]; /*!< Name */
317 char moh[80]; /*!< Music On Hold class to be used */
318 char announce[80]; /*!< Announcement to play when call is answered */
319 char context[AST_MAX_CONTEXT]; /*!< Exit context */
320 unsigned int monjoin:1;
322 unsigned int joinempty:2;
323 unsigned int eventwhencalled:1;
324 unsigned int leavewhenempty:2;
325 unsigned int reportholdtime:1;
326 unsigned int wrapped:1;
327 unsigned int timeoutrestart:1;
328 unsigned int announceholdtime:2;
329 unsigned int strategy:3;
330 unsigned int maskmemberstatus:1;
331 unsigned int realtime:1;
332 int announcefrequency; /*!< How often to announce their position */
333 int periodicannouncefrequency; /*!< How often to play periodic announcement */
334 int roundingseconds; /*!< How many seconds do we round to? */
335 int holdtime; /*!< Current avg holdtime, based on recursive boxcar filter */
336 int callscompleted; /*!< Number of queue calls completed */
337 int callsabandoned; /*!< Number of queue calls abandoned */
338 int servicelevel; /*!< seconds setting for servicelevel*/
339 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
340 char monfmt[8]; /*!< Format to use when recording calls */
341 char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
342 char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
343 char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
344 char sound_holdtime[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
345 char sound_minutes[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
346 char sound_lessthan[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
347 char sound_seconds[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
348 char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
349 char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
350 char sound_periodicannounce[80];/*!< Sound file: Custom announce, no default */
352 int count; /*!< How many entries */
353 int maxlen; /*!< Max number of entries */
354 int wrapuptime; /*!< Wrapup Time */
356 int retry; /*!< Retry calling everyone after this amount of time */
357 int timeout; /*!< How long to wait for an answer */
358 int weight; /*!< Respective weight */
360 /* Queue strategy things */
361 int rrpos; /*!< Round Robin - position */
362 int memberdelay; /*!< Seconds to delay connecting member to caller */
364 struct member *members; /*!< Head of the list of members */
365 struct queue_ent *head; /*!< Head of the list of callers */
366 struct ast_call_queue *next; /*!< Next call queue */
369 static struct ast_call_queue *queues = NULL;
370 AST_MUTEX_DEFINE_STATIC(qlock);
372 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
376 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
377 if (queue_results[i].id == res) {
378 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
384 static char *int2strat(int strategy)
387 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
388 if (strategy == strategies[x].strategy)
389 return strategies[x].name;
394 static int strat2int(const char *strategy)
397 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
398 if (!strcasecmp(strategy, strategies[x].name))
399 return strategies[x].strategy;
404 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
405 static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
407 struct queue_ent *cur;
424 enum queue_member_status {
426 QUEUE_NO_REACHABLE_MEMBERS,
430 static enum queue_member_status get_member_status(const struct ast_call_queue *q, int max_penalty)
432 struct member *member;
433 enum queue_member_status result = QUEUE_NO_MEMBERS;
435 for (member = q->members; member; member = member->next) {
436 if (max_penalty && (member->penalty > max_penalty))
439 switch (member->status) {
440 case AST_DEVICE_INVALID:
443 case AST_DEVICE_UNAVAILABLE:
444 result = QUEUE_NO_REACHABLE_MEMBERS;
459 static void *changethread(void *data)
461 struct ast_call_queue *q;
462 struct statechange *sc = data;
467 technology = ast_strdupa(sc->dev);
468 loc = strchr(technology, '/');
477 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
478 ast_mutex_lock(&qlock);
479 for (q = queues; q; q = q->next) {
480 ast_mutex_lock(&q->lock);
483 if (!strcasecmp(sc->dev, cur->interface)) {
484 if (cur->status != sc->state) {
485 cur->status = sc->state;
486 if (!q->maskmemberstatus) {
487 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
496 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
497 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
503 ast_mutex_unlock(&q->lock);
505 ast_mutex_unlock(&qlock);
510 static int statechange_queue(const char *dev, int state, void *ign)
512 /* Avoid potential for deadlocks by spawning a new thread to handle
514 struct statechange *sc;
518 sc = malloc(sizeof(struct statechange) + strlen(dev) + 1);
521 strcpy(sc->dev, dev);
522 pthread_attr_init(&attr);
523 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
524 if (ast_pthread_create(&t, &attr, changethread, sc)) {
525 ast_log(LOG_WARNING, "Failed to create update thread!\n");
532 static struct member *create_queue_member(char *interface, int penalty, int paused)
536 /* Add a new member */
538 cur = malloc(sizeof(struct member));
541 memset(cur, 0, sizeof(struct member));
542 cur->penalty = penalty;
543 cur->paused = paused;
544 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
545 if (!strchr(cur->interface, '/'))
546 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
547 cur->status = ast_device_state(interface);
553 static struct ast_call_queue *alloc_queue(const char *queuename)
555 struct ast_call_queue *q;
557 q = malloc(sizeof(*q));
559 memset(q, 0, 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)
569 q->retry = DEFAULT_RETRY;
572 q->announcefrequency = 0;
573 q->announceholdtime = 0;
574 q->roundingseconds = 0; /* Default - don't announce seconds */
577 q->announce[0] = '\0';
578 q->context[0] = '\0';
580 q->periodicannouncefrequency = 0;
581 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
582 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
583 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
584 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
585 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
586 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
587 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
588 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
589 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
590 ast_copy_string(q->sound_periodicannounce, "queue-periodic-announce", sizeof(q->sound_periodicannounce));
593 static void clear_queue(struct ast_call_queue *q)
596 q->callscompleted = 0;
597 q->callsabandoned = 0;
598 q->callscompletedinsl = 0;
602 /*! \brief Configure a queue parameter.
604 For error reporting, line number is passed for .conf static configuration.
605 For Realtime queues, linenum is -1.
606 The failunknown flag is set for config files (and static realtime) to show
607 errors for unknown parameters. It is cleared for dynamic realtime to allow
608 extra fields in the tables. */
609 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
611 if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
612 ast_copy_string(q->moh, val, sizeof(q->moh));
613 } else if (!strcasecmp(param, "announce")) {
614 ast_copy_string(q->announce, val, sizeof(q->announce));
615 } else if (!strcasecmp(param, "context")) {
616 ast_copy_string(q->context, val, sizeof(q->context));
617 } else if (!strcasecmp(param, "timeout")) {
618 q->timeout = atoi(val);
620 q->timeout = DEFAULT_TIMEOUT;
621 } else if (!strcasecmp(param, "monitor-join")) {
622 q->monjoin = ast_true(val);
623 } else if (!strcasecmp(param, "monitor-format")) {
624 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
625 } else if (!strcasecmp(param, "queue-youarenext")) {
626 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
627 } else if (!strcasecmp(param, "queue-thereare")) {
628 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
629 } else if (!strcasecmp(param, "queue-callswaiting")) {
630 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
631 } else if (!strcasecmp(param, "queue-holdtime")) {
632 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
633 } else if (!strcasecmp(param, "queue-minutes")) {
634 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
635 } else if (!strcasecmp(param, "queue-seconds")) {
636 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
637 } else if (!strcasecmp(param, "queue-lessthan")) {
638 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
639 } else if (!strcasecmp(param, "queue-thankyou")) {
640 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
641 } else if (!strcasecmp(param, "queue-reporthold")) {
642 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
643 } else if (!strcasecmp(param, "announce-frequency")) {
644 q->announcefrequency = atoi(val);
645 } else if (!strcasecmp(param, "announce-round-seconds")) {
646 q->roundingseconds = atoi(val);
647 if (q->roundingseconds>60 || q->roundingseconds<0) {
649 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
650 "using 0 instead for queue '%s' at line %d of queues.conf\n",
651 val, param, q->name, linenum);
653 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
654 "using 0 instead for queue '%s'\n", val, param, q->name);
656 q->roundingseconds=0;
658 } else if (!strcasecmp(param, "announce-holdtime")) {
659 if (!strcasecmp(val, "once"))
660 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
661 else if (ast_true(val))
662 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
664 q->announceholdtime = 0;
665 } else if (!strcasecmp(param, "periodic-announce")) {
666 ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce));
667 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
668 q->periodicannouncefrequency = atoi(val);
669 } else if (!strcasecmp(param, "retry")) {
670 q->retry = atoi(val);
672 q->retry = DEFAULT_RETRY;
673 } else if (!strcasecmp(param, "wrapuptime")) {
674 q->wrapuptime = atoi(val);
675 } else if (!strcasecmp(param, "maxlen")) {
676 q->maxlen = atoi(val);
679 } else if (!strcasecmp(param, "servicelevel")) {
680 q->servicelevel= atoi(val);
681 } else if (!strcasecmp(param, "strategy")) {
682 q->strategy = strat2int(val);
683 if (q->strategy < 0) {
684 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
688 } else if (!strcasecmp(param, "joinempty")) {
689 if (!strcasecmp(val, "strict"))
690 q->joinempty = QUEUE_EMPTY_STRICT;
691 else if (ast_true(val))
692 q->joinempty = QUEUE_EMPTY_NORMAL;
695 } else if (!strcasecmp(param, "leavewhenempty")) {
696 if (!strcasecmp(val, "strict"))
697 q->leavewhenempty = QUEUE_EMPTY_STRICT;
698 else if (ast_true(val))
699 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
701 q->leavewhenempty = 0;
702 } else if (!strcasecmp(param, "eventmemberstatus")) {
703 q->maskmemberstatus = !ast_true(val);
704 } else if (!strcasecmp(param, "eventwhencalled")) {
705 q->eventwhencalled = ast_true(val);
706 } else if (!strcasecmp(param, "reportholdtime")) {
707 q->reportholdtime = ast_true(val);
708 } else if (!strcasecmp(param, "memberdelay")) {
709 q->memberdelay = atoi(val);
710 } else if (!strcasecmp(param, "weight")) {
711 q->weight = atoi(val);
714 /* With Realtime queues, if the last queue using weights is deleted in realtime,
715 we will not see any effect on use_weight until next reload. */
716 } else if (!strcasecmp(param, "timeoutrestart")) {
717 q->timeoutrestart = ast_true(val);
718 } else if(failunknown) {
720 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
721 q->name, param, linenum);
723 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
728 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
730 struct member *m, *prev_m;
734 penalty = atoi(penalty_str);
739 /* Find the member, or the place to put a new one. */
742 while (m && strcmp(m->interface, interface)) {
747 /* Create a new one if not found, else update penalty */
749 m = create_queue_member(interface, penalty, 0);
759 m->dead = 0; /* Do not delete this one. */
760 m->penalty = penalty;
765 /*!\brief Reload a single queue via realtime.
766 \return Return the queue, or NULL if it doesn't exist.
767 \note Should be called with the global qlock locked.
768 When found, the queue is returned with q->lock locked. */
769 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
771 struct ast_variable *v;
772 struct ast_call_queue *q, *prev_q;
773 struct member *m, *prev_m, *next_m;
775 char *tmp, *tmp_name;
776 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
778 /* Find the queue in the in-core list (we will create a new one if not found). */
782 if (!strcasecmp(q->name, queuename)) {
789 /* Static queues override realtime. */
791 ast_mutex_lock(&q->lock);
794 ast_mutex_unlock(&q->lock);
800 } else if (!member_config)
801 /* Not found in the list, and it's not realtime ... */
804 /* Check if queue is defined in realtime. */
806 /* Delete queue from in-core list if it has been deleted in realtime. */
808 /*! \note Hmm, can't seem to distinguish a DB failure from a not
809 found condition... So we might delete an in-core queue
810 in case of DB failure. */
811 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
814 /* Delete if unused (else will be deleted when last caller leaves). */
820 prev_q->next = q->next;
822 ast_mutex_unlock(&q->lock);
825 ast_mutex_unlock(&q->lock);
830 /* Create a new queue if an in-core entry does not exist yet. */
832 q = alloc_queue(queuename);
835 ast_mutex_lock(&q->lock);
841 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
844 memset(tmpbuf, 0, sizeof(tmpbuf));
846 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
847 if((tmp = strchr(v->name, '_')) != NULL) {
848 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
851 while((tmp = strchr(tmp, '_')) != NULL)
855 queue_set_param(q, tmp_name, v->value, -1, 0);
859 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
867 interface = ast_category_browse(member_config, NULL);
869 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
870 interface = ast_category_browse(member_config, interface);
873 /* Delete all realtime members that have been deleted in DB. */
880 prev_m->next = next_m;
894 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
896 struct ast_variable *queue_vars = NULL;
897 struct ast_config *member_config = NULL;
898 struct ast_call_queue *q;
899 struct queue_ent *cur, *prev = NULL;
903 enum queue_member_status stat;
905 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
906 queue operations while waiting for the DB.
908 This will be two separate database transactions, so we might
909 see queue parameters as they were before another process
910 changed the queue and member list as it was after the change.
911 Thus we might see an empty member list when a queue is
912 deleted. In practise, this is unlikely to cause a problem. */
913 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
915 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
916 if (!member_config) {
917 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
922 ast_mutex_lock(&qlock);
923 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
924 /* Note: If found, find_queue_by_name_rt() returns with q->lock locked. */
926 ast_config_destroy(member_config);
928 ast_variables_destroy(queue_vars);
931 ast_mutex_unlock(&qlock);
935 /* This is our one */
936 stat = get_member_status(q, qe->max_penalty);
937 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
938 *reason = QUEUE_JOINEMPTY;
939 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
940 *reason = QUEUE_JOINUNAVAIL;
941 else if (q->maxlen && (q->count >= q->maxlen))
942 *reason = QUEUE_FULL;
944 /* There's space for us, put us at the right position inside
946 * Take into account the priority of the calling user */
951 /* We have higher priority than the current user, enter
952 * before him, after all the other users with priority
953 * higher or equal to our priority. */
954 if ((!inserted) && (qe->prio > cur->prio)) {
955 insert_entry(q, prev, qe, &pos);
962 /* No luck, join at the end of the queue */
964 insert_entry(q, prev, qe, &pos);
965 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
966 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
967 ast_copy_string(qe->context, q->context, sizeof(qe->context));
970 manager_event(EVENT_FLAG_CALL, "Join",
971 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\n",
973 qe->chan->cid.cid_num ? qe->chan->cid.cid_num : "unknown",
974 qe->chan->cid.cid_name ? qe->chan->cid.cid_name : "unknown",
975 q->name, qe->pos, q->count );
977 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
980 ast_mutex_unlock(&q->lock);
981 ast_mutex_unlock(&qlock);
985 static void free_members(struct ast_call_queue *q, int all)
987 /* Free non-dynamic members */
988 struct member *curm, *next, *prev;
994 if (all || !curm->dynamic) {
1006 static void destroy_queue(struct ast_call_queue *q)
1008 struct ast_call_queue *cur, *prev = NULL;
1010 ast_mutex_lock(&qlock);
1011 for (cur = queues; cur; cur = cur->next) {
1014 prev->next = cur->next;
1021 ast_mutex_unlock(&qlock);
1023 ast_mutex_destroy(&q->lock);
1027 static int play_file(struct ast_channel *chan, char *filename)
1031 ast_stopstream(chan);
1032 res = ast_streamfile(chan, filename, chan->language);
1035 res = ast_waitstream(chan, AST_DIGIT_ANY);
1039 ast_stopstream(chan);
1044 static int valid_exit(struct queue_ent *qe, char digit)
1046 int digitlen = strlen(qe->digits);
1048 /* Prevent possible buffer overflow */
1049 if (digitlen < sizeof(qe->digits) - 2) {
1050 qe->digits[digitlen] = digit;
1051 qe->digits[digitlen + 1] = '\0';
1053 qe->digits[0] = '\0';
1057 /* If there's no context to goto, short-circuit */
1058 if (ast_strlen_zero(qe->context))
1061 /* If the extension is bad, then reset the digits to blank */
1062 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1063 qe->digits[0] = '\0';
1067 /* We have an exact match */
1068 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1069 /* Return 1 on a successful goto */
1075 static int say_position(struct queue_ent *qe)
1077 int res = 0, avgholdmins, avgholdsecs;
1080 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1082 if ( (now - qe->last_pos) < 15 )
1085 /* If either our position has changed, or we are over the freq timer, say position */
1086 if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
1089 ast_moh_stop(qe->chan);
1090 /* Say we're next, if we are */
1092 res = play_file(qe->chan, qe->parent->sound_next);
1093 if (res && valid_exit(qe, res))
1098 res = play_file(qe->chan, qe->parent->sound_thereare);
1099 if (res && valid_exit(qe, res))
1101 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1102 if (res && valid_exit(qe, res))
1104 res = play_file(qe->chan, qe->parent->sound_calls);
1105 if (res && valid_exit(qe, res))
1108 /* Round hold time to nearest minute */
1109 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
1111 /* If they have specified a rounding then round the seconds as well */
1112 if(qe->parent->roundingseconds) {
1113 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
1114 avgholdsecs*= qe->parent->roundingseconds;
1119 if (option_verbose > 2)
1120 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1122 /* If the hold time is >1 min, if it's enabled, and if it's not
1123 supposed to be only once and we have already said it, say it */
1124 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1125 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1126 res = play_file(qe->chan, qe->parent->sound_holdtime);
1127 if (res && valid_exit(qe, res))
1130 if (avgholdmins>0) {
1131 if (avgholdmins < 2) {
1132 res = play_file(qe->chan, qe->parent->sound_lessthan);
1133 if (res && valid_exit(qe, res))
1136 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1137 if (res && valid_exit(qe, res))
1140 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1141 if (res && valid_exit(qe, res))
1145 res = play_file(qe->chan, qe->parent->sound_minutes);
1146 if (res && valid_exit(qe, res))
1149 if (avgholdsecs>0) {
1150 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1151 if (res && valid_exit(qe, res))
1154 res = play_file(qe->chan, qe->parent->sound_seconds);
1155 if (res && valid_exit(qe, res))
1162 if (option_verbose > 2)
1163 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1164 qe->chan->name, qe->parent->name, qe->pos);
1165 res = play_file(qe->chan, qe->parent->sound_thanks);
1168 /* Set our last_pos indicators */
1170 qe->last_pos_said = qe->pos;
1171 ast_moh_start(qe->chan, qe->moh);
1176 static void recalc_holdtime(struct queue_ent *qe)
1178 int oldvalue, newvalue;
1180 /* Calculate holdtime using a recursive boxcar filter */
1181 /* Thanks to SRT for this contribution */
1182 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1184 newvalue = time(NULL) - qe->start;
1186 ast_mutex_lock(&qe->parent->lock);
1187 if (newvalue <= qe->parent->servicelevel)
1188 qe->parent->callscompletedinsl++;
1189 oldvalue = qe->parent->holdtime;
1190 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1191 ast_mutex_unlock(&qe->parent->lock);
1195 static void leave_queue(struct queue_ent *qe)
1197 struct ast_call_queue *q;
1198 struct queue_ent *cur, *prev = NULL;
1204 ast_mutex_lock(&q->lock);
1212 /* Take us out of the queue */
1213 manager_event(EVENT_FLAG_CALL, "Leave",
1214 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
1215 qe->chan->name, q->name, q->count);
1217 ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1219 /* Take us out of the queue */
1221 prev->next = cur->next;
1223 q->head = cur->next;
1225 /* Renumber the people after us in the queue based on a new count */
1231 ast_mutex_unlock(&q->lock);
1232 if (q->dead && !q->count) {
1233 /* It's dead and nobody is in it, so kill it */
1238 /* Hang up a list of outgoing calls */
1239 static void hangupcalls(struct localuser *outgoing, struct ast_channel *exception)
1241 struct localuser *oo;
1244 /* Hangup any existing lines we have open */
1245 if (outgoing->chan && (outgoing->chan != exception))
1246 ast_hangup(outgoing->chan);
1248 outgoing=outgoing->next;
1253 static int update_status(struct ast_call_queue *q, struct member *member, int status)
1257 /* Since a reload could have taken place, we have to traverse the list to
1258 be sure it's still valid */
1259 ast_mutex_lock(&q->lock);
1262 if (member == cur) {
1263 cur->status = status;
1264 if (!q->maskmemberstatus) {
1265 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1268 "Membership: %s\r\n"
1270 "CallsTaken: %d\r\n"
1274 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1275 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1281 ast_mutex_unlock(&q->lock);
1285 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
1287 if (status == AST_CAUSE_BUSY)
1288 status = AST_DEVICE_BUSY;
1289 else if (status == AST_CAUSE_UNREGISTERED)
1290 status = AST_DEVICE_UNAVAILABLE;
1291 else if (status == AST_CAUSE_NOSUCHDRIVER)
1292 status = AST_DEVICE_INVALID;
1294 status = AST_DEVICE_UNKNOWN;
1295 return update_status(q, member, status);
1298 /* traverse all defined queues which have calls waiting and contain this member
1299 return 0 if no other queue has precedence (higher weight) or 1 if found */
1300 static int compare_weight(struct ast_call_queue *rq, struct member *member)
1302 struct ast_call_queue *q;
1306 /* &qlock and &rq->lock already set by try_calling()
1307 * to solve deadlock */
1308 for (q = queues; q; q = q->next) {
1309 if (q == rq) /* don't check myself, could deadlock */
1311 ast_mutex_lock(&q->lock);
1312 if (q->count && q->members) {
1313 for (mem = q->members; mem; mem = mem->next) {
1314 if (!strcmp(mem->interface, member->interface)) {
1315 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1316 if (q->weight > rq->weight) {
1317 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);
1324 ast_mutex_unlock(&q->lock);
1328 ast_mutex_unlock(&qlock);
1332 static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies)
1339 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1341 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1343 ast_cdr_busy(qe->chan->cdr);
1344 tmp->stillgoing = 0;
1349 if (tmp->member->paused) {
1351 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1353 ast_cdr_busy(qe->chan->cdr);
1354 tmp->stillgoing = 0;
1357 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1358 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1360 ast_cdr_busy(qe->chan->cdr);
1361 tmp->stillgoing = 0;
1366 ast_copy_string(tech, tmp->interface, sizeof(tech));
1367 if ((location = strchr(tech, '/')))
1372 /* Request the peer */
1373 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1374 if (!tmp->chan) { /* If we can't, just go on to the next call */
1376 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
1379 ast_cdr_busy(qe->chan->cdr);
1380 tmp->stillgoing = 0;
1381 update_dial_status(qe->parent, tmp->member, status);
1384 } else if (status != tmp->oldstatus)
1385 update_dial_status(qe->parent, tmp->member, status);
1387 tmp->chan->appl = "AppQueue";
1388 tmp->chan->data = "(Outgoing Line)";
1389 tmp->chan->whentohangup = 0;
1390 if (tmp->chan->cid.cid_num)
1391 free(tmp->chan->cid.cid_num);
1392 tmp->chan->cid.cid_num = NULL;
1393 if (tmp->chan->cid.cid_name)
1394 free(tmp->chan->cid.cid_name);
1395 tmp->chan->cid.cid_name = NULL;
1396 if (tmp->chan->cid.cid_ani)
1397 free(tmp->chan->cid.cid_ani);
1398 tmp->chan->cid.cid_ani = NULL;
1399 if (qe->chan->cid.cid_num)
1400 tmp->chan->cid.cid_num = strdup(qe->chan->cid.cid_num);
1401 if (qe->chan->cid.cid_name)
1402 tmp->chan->cid.cid_name = strdup(qe->chan->cid.cid_name);
1403 if (qe->chan->cid.cid_ani)
1404 tmp->chan->cid.cid_ani = strdup(qe->chan->cid.cid_ani);
1406 /* Inherit specially named variables from parent channel */
1407 ast_channel_inherit_variables(qe->chan, tmp->chan);
1409 /* Presense of ADSI CPE on outgoing channel follows ours */
1410 tmp->chan->adsicpe = qe->chan->adsicpe;
1412 /* Place the call, but don't wait on the answer */
1413 res = ast_call(tmp->chan, location, 0);
1415 /* Again, keep going even if there's an error */
1417 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1418 else if (option_verbose > 2)
1419 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1420 ast_hangup(tmp->chan);
1422 tmp->stillgoing = 0;
1426 if (qe->parent->eventwhencalled) {
1427 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1428 "AgentCalled: %s\r\n"
1429 "ChannelCalling: %s\r\n"
1431 "CallerIDName: %s\r\n"
1435 tmp->interface, qe->chan->name,
1436 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1437 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1438 qe->chan->context, qe->chan->exten, qe->chan->priority);
1440 if (option_verbose > 2)
1441 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1446 static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busies)
1448 struct localuser *cur;
1449 struct localuser *best;
1456 if (cur->stillgoing && /* Not already done */
1457 !cur->chan && /* Isn't already going */
1458 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
1459 bestmetric = cur->metric;
1465 if (!qe->parent->strategy) {
1466 /* Ring everyone who shares this best metric (for ringall) */
1469 if (cur->stillgoing && !cur->chan && (cur->metric <= bestmetric)) {
1471 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1472 ring_entry(qe, cur, busies);
1477 /* Ring just the best channel */
1479 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1480 ring_entry(qe, best, busies);
1483 } while (best && !best->chan);
1486 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1492 static int store_next(struct queue_ent *qe, struct localuser *outgoing)
1494 struct localuser *cur;
1495 struct localuser *best;
1501 if (cur->stillgoing && /* Not already done */
1502 !cur->chan && /* Isn't already going */
1503 (!best || (cur->metric < bestmetric))) { /* We haven't found one yet, or it's better */
1504 bestmetric = cur->metric;
1510 /* Ring just the best channel */
1512 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1513 qe->parent->rrpos = best->metric % 1000;
1515 /* Just increment rrpos */
1516 if (qe->parent->wrapped) {
1517 /* No more channels, start over */
1518 qe->parent->rrpos = 0;
1520 /* Prioritize next entry */
1521 qe->parent->rrpos++;
1524 qe->parent->wrapped = 0;
1528 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1532 ast_stopstream(chan);
1533 res = ast_streamfile(chan, filename, chan->language);
1536 /* Wait for a keypress */
1537 res = ast_waitstream(chan, AST_DIGIT_ANY);
1538 if (res <= 0 || !valid_exit(qe, res))
1542 ast_stopstream(chan);
1548 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
1555 static int say_periodic_announcement(struct queue_ent *qe)
1560 /* Get the current time */
1563 /* Check to see if it is time to announce */
1564 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1567 /* Stop the music on hold so we can play our own file */
1568 ast_moh_stop(qe->chan);
1570 if (option_verbose > 2)
1571 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1573 /* play the announcement */
1574 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce);
1576 /* Resume Music on Hold */
1577 ast_moh_start(qe->chan, qe->moh);
1579 /* update last_periodic_announce_time */
1580 qe->last_periodic_announce_time = now;
1585 static void record_abandoned(struct queue_ent *qe)
1587 ast_mutex_lock(&qe->parent->lock);
1588 qe->parent->callsabandoned++;
1589 ast_mutex_unlock(&qe->parent->lock);
1593 #define AST_MAX_WATCHERS 256
1595 #define BUILD_WATCHERS do { \
1602 /* Keep track of important channels */ \
1603 if (o->stillgoing) { \
1606 watchers[pos++] = o->chan; \
1615 static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1617 char *queue = qe->parent->name;
1618 struct localuser *o;
1622 int sentringing = 0;
1623 int numbusies = prebusies;
1627 struct ast_frame *f;
1628 struct localuser *peer = NULL;
1629 struct ast_channel *watchers[AST_MAX_WATCHERS];
1631 struct ast_channel *winner;
1632 struct ast_channel *in = qe->chan;
1634 while(*to && !peer) {
1636 if ((found < 0) && stillgoing && !qe->parent->strategy) {
1637 /* On "ringall" strategy we only move to the next penalty level
1638 when *all* ringing phones are done in the current penalty level */
1639 ring_one(qe, outgoing, &numbusies);
1643 if (numlines == (numbusies + numnochan)) {
1644 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1646 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1651 winner = ast_waitfor_n(watchers, pos, to);
1654 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
1656 if (option_verbose > 2)
1657 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1660 } else if (o->chan && (o->chan == winner)) {
1661 if (!ast_strlen_zero(o->chan->call_forward)) {
1662 char tmpchan[256]="";
1665 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1666 if ((stuff = strchr(tmpchan, '/'))) {
1671 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1675 /* Before processing channel, go ahead and check for forwarding */
1676 if (option_verbose > 2)
1677 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1678 /* Setup parameters */
1679 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1680 if (status != o->oldstatus)
1681 update_dial_status(qe->parent, o->member, status);
1683 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1687 if (o->chan->cid.cid_num)
1688 free(o->chan->cid.cid_num);
1689 o->chan->cid.cid_num = NULL;
1690 if (o->chan->cid.cid_name)
1691 free(o->chan->cid.cid_name);
1692 o->chan->cid.cid_name = NULL;
1694 if (in->cid.cid_num) {
1695 o->chan->cid.cid_num = strdup(in->cid.cid_num);
1696 if (!o->chan->cid.cid_num)
1697 ast_log(LOG_WARNING, "Out of memory\n");
1699 if (in->cid.cid_name) {
1700 o->chan->cid.cid_name = strdup(in->cid.cid_name);
1701 if (!o->chan->cid.cid_name)
1702 ast_log(LOG_WARNING, "Out of memory\n");
1704 ast_copy_string(o->chan->accountcode, in->accountcode, sizeof(o->chan->accountcode));
1705 o->chan->cdrflags = in->cdrflags;
1707 if (in->cid.cid_ani) {
1708 if (o->chan->cid.cid_ani)
1709 free(o->chan->cid.cid_ani);
1710 o->chan->cid.cid_ani = malloc(strlen(in->cid.cid_ani) + 1);
1711 if (o->chan->cid.cid_ani)
1712 strncpy(o->chan->cid.cid_ani, in->cid.cid_ani, strlen(in->cid.cid_ani) + 1);
1714 ast_log(LOG_WARNING, "Out of memory\n");
1716 if (o->chan->cid.cid_rdnis)
1717 free(o->chan->cid.cid_rdnis);
1718 if (!ast_strlen_zero(in->macroexten))
1719 o->chan->cid.cid_rdnis = strdup(in->macroexten);
1721 o->chan->cid.cid_rdnis = strdup(in->exten);
1722 if (ast_call(o->chan, tmpchan, 0)) {
1723 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1725 ast_hangup(o->chan);
1730 /* Hangup the original channel now, in case we needed it */
1734 f = ast_read(winner);
1736 if (f->frametype == AST_FRAME_CONTROL) {
1737 switch(f->subclass) {
1738 case AST_CONTROL_ANSWER:
1739 /* This is our guy if someone answered. */
1741 if (option_verbose > 2)
1742 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1746 case AST_CONTROL_BUSY:
1747 if (option_verbose > 2)
1748 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1751 ast_cdr_busy(in->cdr);
1752 ast_hangup(o->chan);
1754 if (qe->parent->strategy) {
1755 if (qe->parent->timeoutrestart)
1757 ring_one(qe, outgoing, &numbusies);
1761 case AST_CONTROL_CONGESTION:
1762 if (option_verbose > 2)
1763 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1766 ast_cdr_busy(in->cdr);
1767 ast_hangup(o->chan);
1769 if (qe->parent->strategy) {
1770 if (qe->parent->timeoutrestart)
1772 ring_one(qe, outgoing, &numbusies);
1776 case AST_CONTROL_RINGING:
1777 if (option_verbose > 2)
1778 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1781 ast_indicate(in, AST_CONTROL_RINGING);
1786 case AST_CONTROL_OFFHOOK:
1787 /* Ignore going off hook */
1790 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1796 ast_hangup(o->chan);
1798 if (qe->parent->strategy) {
1799 if (qe->parent->timeoutrestart)
1801 ring_one(qe, outgoing, &numbusies);
1810 if (f && (f->frametype != AST_FRAME_VOICE))
1811 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1812 else if (!f || (f->frametype != AST_FRAME_VOICE))
1813 printf("Hangup received on %s\n", in->name);
1815 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1822 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1823 if (option_verbose > 3)
1824 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1829 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1830 if (option_verbose > 3)
1831 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1839 if (!*to && (option_verbose > 2))
1840 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1847 static int is_our_turn(struct queue_ent *qe)
1849 struct queue_ent *ch;
1852 /* Atomically read the parent head -- does not need a lock */
1853 ch = qe->parent->head;
1854 /* If we are now at the top of the head, break out */
1857 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1861 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1867 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1871 /* This is the holding pen for callers 2 through maxlen */
1873 enum queue_member_status stat;
1875 if (is_our_turn(qe))
1878 /* If we have timed out, break out */
1879 if (qe->expire && (time(NULL) > qe->expire)) {
1880 *reason = QUEUE_TIMEOUT;
1881 ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
1885 stat = get_member_status(qe->parent, qe->max_penalty);
1887 /* leave the queue if no agents, if enabled */
1888 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1889 *reason = QUEUE_LEAVEEMPTY;
1894 /* leave the queue if no reachable agents, if enabled */
1895 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1896 *reason = QUEUE_LEAVEUNAVAIL;
1901 /* Make a position announcement, if enabled */
1902 if (qe->parent->announcefrequency && !ringing)
1903 res = say_position(qe);
1907 /* Make a periodic announcement, if enabled */
1908 if (qe->parent->periodicannouncefrequency && !ringing)
1909 res = say_periodic_announcement(qe);
1911 /* Wait a second before checking again */
1912 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
1919 static int update_queue(struct ast_call_queue *q, struct member *member)
1923 /* Since a reload could have taken place, we have to traverse the list to
1924 be sure it's still valid */
1925 ast_mutex_lock(&q->lock);
1928 if (member == cur) {
1929 time(&cur->lastcall);
1935 q->callscompleted++;
1936 ast_mutex_unlock(&q->lock);
1940 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct localuser *tmp)
1942 if (mem->penalty > qe->max_penalty)
1945 switch (q->strategy) {
1946 case QUEUE_STRATEGY_RINGALL:
1947 /* Everyone equal, except for penalty */
1948 tmp->metric = mem->penalty * 1000000;
1950 case QUEUE_STRATEGY_ROUNDROBIN:
1953 /* No more channels, start over */
1956 /* Prioritize next entry */
1962 case QUEUE_STRATEGY_RRMEMORY:
1963 if (pos < q->rrpos) {
1964 tmp->metric = 1000 + pos;
1967 /* Indicate there is another priority */
1971 tmp->metric += mem->penalty * 1000000;
1973 case QUEUE_STRATEGY_RANDOM:
1974 tmp->metric = rand() % 1000;
1975 tmp->metric += mem->penalty * 1000000;
1977 case QUEUE_STRATEGY_FEWESTCALLS:
1978 tmp->metric = mem->calls;
1979 tmp->metric += mem->penalty * 1000000;
1981 case QUEUE_STRATEGY_LEASTRECENT:
1985 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
1986 tmp->metric += mem->penalty * 1000000;
1989 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
1995 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on)
1998 struct localuser *outgoing=NULL, *tmp = NULL;
2000 char restofit[AST_MAX_EXTENSION];
2001 char oldexten[AST_MAX_EXTENSION]="";
2002 char oldcontext[AST_MAX_CONTEXT]="";
2003 char queuename[256]="";
2005 struct ast_channel *peer;
2006 struct ast_channel *which;
2007 struct localuser *lpeer;
2008 struct member *member;
2009 int res = 0, bridge = 0;
2012 char *announce = NULL;
2015 time_t now = time(NULL);
2016 struct ast_bridge_config bridge_config;
2017 char nondataquality = 1;
2019 memset(&bridge_config, 0, sizeof(bridge_config));
2022 for (; options && *options; options++)
2025 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2028 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2031 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2034 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2040 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2043 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2046 if ((now - qe->start >= qe->parent->timeout))
2051 /* Hold the lock while we setup the outgoing calls */
2053 ast_mutex_lock(&qlock);
2054 ast_mutex_lock(&qe->parent->lock);
2056 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2058 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2059 cur = qe->parent->members;
2060 if (!ast_strlen_zero(qe->announce))
2061 announce = qe->announce;
2062 if (!ast_strlen_zero(announceoverride))
2063 announce = announceoverride;
2066 tmp = malloc(sizeof(*tmp));
2068 ast_mutex_unlock(&qe->parent->lock);
2070 ast_mutex_unlock(&qlock);
2071 ast_log(LOG_WARNING, "Out of memory\n");
2074 memset(tmp, 0, sizeof(*tmp));
2075 tmp->stillgoing = -1;
2078 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2080 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
2083 tmp->member = cur; /* Never directly dereference! Could change on reload */
2084 tmp->oldstatus = cur->status;
2085 tmp->lastcall = cur->lastcall;
2086 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2087 /* If we're dialing by extension, look at the extension to know what to dial */
2088 if ((newnum = strstr(tmp->interface, "/BYEXTENSION"))) {
2090 strncpy(restofit, newnum + strlen("BYEXTENSION"), sizeof(restofit) - 1);
2091 snprintf(newnum, sizeof(tmp->interface) - (newnum - tmp->interface), "%s%s", qe->chan->exten, restofit);
2093 ast_log(LOG_DEBUG, "Dialing by extension %s\n", tmp->interface);
2095 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2096 just calculate their metric for the appropriate strategy */
2097 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2098 /* Put them in the list of outgoing thingies... We're ready now.
2099 XXX If we're forcibly removed, these outgoing calls won't get
2101 tmp->next = outgoing;
2103 /* If this line is up, don't try anybody else */
2104 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2112 if (qe->parent->timeout)
2113 to = qe->parent->timeout * 1000;
2116 ring_one(qe, outgoing, &numbusies);
2117 ast_mutex_unlock(&qe->parent->lock);
2119 ast_mutex_unlock(&qlock);
2120 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
2121 ast_mutex_lock(&qe->parent->lock);
2122 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2123 store_next(qe, outgoing);
2125 ast_mutex_unlock(&qe->parent->lock);
2132 /* Musta gotten hung up */
2133 record_abandoned(qe);
2139 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2143 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2144 we will always return with -1 so that it is hung up properly after the
2147 if (!strcmp(qe->chan->type,"Zap"))
2148 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2149 if (!strcmp(peer->type,"Zap"))
2150 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2151 /* Update parameters for the queue */
2152 recalc_holdtime(qe);
2153 member = lpeer->member;
2154 hangupcalls(outgoing, peer);
2156 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2158 res2 = ast_autoservice_start(qe->chan);
2160 if (qe->parent->memberdelay) {
2161 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2162 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2164 if (!res2 && announce) {
2165 if (play_file(peer, announce))
2166 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2168 if (!res2 && qe->parent->reportholdtime) {
2169 if (!play_file(peer, qe->parent->sound_reporthold)) {
2173 holdtime = abs((now - qe->start) / 60);
2175 play_file(peer, qe->parent->sound_lessthan);
2176 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2178 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2179 play_file(peer, qe->parent->sound_minutes);
2183 res2 |= ast_autoservice_stop(qe->chan);
2184 if (peer->_softhangup) {
2185 /* Agent must have hung up */
2186 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
2187 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
2188 record_abandoned(qe);
2189 if (qe->parent->eventwhencalled) {
2190 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2195 queuename, qe->chan->uniqueid, peer->name, member->interface);
2200 /* Caller must have hung up just before being connected*/
2201 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2202 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2203 record_abandoned(qe);
2208 /* Stop music on hold */
2209 ast_moh_stop(qe->chan);
2210 /* If appropriate, log that we have a destination channel */
2212 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2213 /* Make sure channels are compatible */
2214 res = ast_channel_make_compatible(qe->chan, peer);
2216 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2217 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2218 record_abandoned(qe);
2222 /* Begin Monitoring */
2223 if (qe->parent->monfmt && *qe->parent->monfmt) {
2224 const char *monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2225 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2229 if (monitorfilename)
2230 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2231 else if (qe->chan->cdr)
2232 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2234 /* Last ditch effort -- no CDR, make up something */
2236 snprintf(tmpid, sizeof(tmpid), "chan-%x", rand());
2237 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2239 if (qe->parent->monjoin)
2240 ast_monitor_setjoinfiles(which, 1);
2242 /* Drop out of the queue at this point, to prepare for next caller */
2244 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2246 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2247 ast_channel_sendurl(peer, url);
2249 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start);
2250 if (qe->parent->eventwhencalled)
2251 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2256 "Holdtime: %ld\r\n",
2257 queuename, qe->chan->uniqueid, peer->name, member->interface,
2258 (long)time(NULL) - qe->start);
2259 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2260 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2263 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2265 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2266 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
2267 } else if (qe->chan->_softhangup) {
2268 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2269 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2270 if (qe->parent->eventwhencalled)
2271 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2278 "Reason: caller\r\n",
2279 queuename, qe->chan->uniqueid, peer->name, member->interface,
2280 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2282 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2283 if (qe->parent->eventwhencalled)
2284 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2290 "Reason: agent\r\n",
2291 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2292 (long)(time(NULL) - callstart));
2295 if(bridge != AST_PBX_NO_HANGUP_PEER)
2297 update_queue(qe->parent, member);
2299 res = 1; /* JDG: bridge successfull, leave app_queue */
2301 res = bridge; /* bridge error, stay in the queue */
2304 hangupcalls(outgoing, NULL);
2308 static int wait_a_bit(struct queue_ent *qe)
2310 /* Don't need to hold the lock while we setup the outgoing calls */
2311 int retrywait = qe->parent->retry * 1000;
2313 return ast_waitfordigit(qe->chan, retrywait);
2316 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2321 for (mem = q->members; mem; mem = mem->next)
2322 if (!strcasecmp(interface, mem->interface))
2329 /* Dump all members in a specific queue to the databse
2331 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2334 static void dump_queue_members(struct ast_call_queue *pm_queue)
2336 struct member *cur_member;
2337 char value[PM_MAX_LEN];
2341 memset(value, 0, sizeof(value));
2346 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2347 if (!cur_member->dynamic)
2350 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2351 cur_member->interface, cur_member->penalty, cur_member->paused,
2352 cur_member->next ? "|" : "");
2353 if (res != strlen(value + value_len)) {
2354 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2360 if (value_len && !cur_member) {
2361 if (ast_db_put(pm_family, pm_queue->name, value))
2362 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2364 /* Delete the entry if the queue is empty or there is an error */
2365 ast_db_del(pm_family, pm_queue->name);
2368 static int remove_from_queue(char *queuename, char *interface)
2370 struct ast_call_queue *q;
2371 struct member *last_member, *look;
2372 int res = RES_NOSUCHQUEUE;
2374 ast_mutex_lock(&qlock);
2375 for (q = queues ; q ; q = q->next) {
2376 ast_mutex_lock(&q->lock);
2377 if (!strcmp(q->name, queuename)) {
2378 if ((last_member = interface_exists(q, interface))) {
2379 if ((look = q->members) == last_member) {
2380 q->members = last_member->next;
2382 while (look != NULL) {
2383 if (look->next == last_member) {
2384 look->next = last_member->next;
2391 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2394 q->name, last_member->interface);
2397 if (queue_persistent_members)
2398 dump_queue_members(q);
2404 ast_mutex_unlock(&q->lock);
2407 ast_mutex_unlock(&q->lock);
2409 ast_mutex_unlock(&qlock);
2413 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2415 struct ast_call_queue *q;
2416 struct member *new_member;
2417 int res = RES_NOSUCHQUEUE;
2419 ast_mutex_lock(&qlock);
2420 for (q = queues ; q ; q = q->next) {
2421 ast_mutex_lock(&q->lock);
2422 if (!strcmp(q->name, queuename)) {
2423 if (interface_exists(q, interface) == NULL) {
2424 new_member = create_queue_member(interface, penalty, paused);
2426 if (new_member != NULL) {
2427 new_member->dynamic = 1;
2428 new_member->next = q->members;
2429 q->members = new_member;
2430 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2433 "Membership: %s\r\n"
2435 "CallsTaken: %d\r\n"
2439 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2440 new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
2443 dump_queue_members(q);
2447 res = RES_OUTOFMEMORY;
2452 ast_mutex_unlock(&q->lock);
2455 ast_mutex_unlock(&q->lock);
2457 ast_mutex_unlock(&qlock);
2461 static int set_member_paused(char *queuename, char *interface, int paused)
2464 struct ast_call_queue *q;
2467 /* Special event for when all queues are paused - individual events still generated */
2469 if (ast_strlen_zero(queuename))
2470 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2472 ast_mutex_lock(&qlock);
2473 for (q = queues ; q ; q = q->next) {
2474 ast_mutex_lock(&q->lock);
2475 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
2476 if ((mem = interface_exists(q, interface))) {
2478 if (mem->paused == paused)
2479 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2480 mem->paused = paused;
2482 if (queue_persistent_members)
2483 dump_queue_members(q);
2485 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2487 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2491 q->name, mem->interface, paused);
2494 ast_mutex_unlock(&q->lock);
2496 ast_mutex_unlock(&qlock);
2499 return RESULT_SUCCESS;
2501 return RESULT_FAILURE;
2504 /* Reload dynamic queue members persisted into the astdb */
2505 static void reload_queue_members(void)
2515 struct ast_db_entry *db_tree;
2516 struct ast_db_entry *entry;
2517 struct ast_call_queue *cur_queue;
2518 char queue_data[PM_MAX_LEN];
2520 ast_mutex_lock(&qlock);
2522 /* Each key in 'pm_family' is the name of a queue */
2523 db_tree = ast_db_gettree(pm_family, NULL);
2524 for (entry = db_tree; entry; entry = entry->next) {
2526 queue_name = entry->key + strlen(pm_family) + 2;
2530 ast_mutex_lock(&cur_queue->lock);
2531 if (!strcmp(queue_name, cur_queue->name))
2533 ast_mutex_unlock(&cur_queue->lock);
2534 cur_queue = cur_queue->next;
2538 /* If the queue no longer exists, remove it from the
2540 ast_db_del(pm_family, queue_name);
2543 ast_mutex_unlock(&cur_queue->lock);
2545 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2548 cur_ptr = queue_data;
2549 while ((member = strsep(&cur_ptr, "|"))) {
2550 if (ast_strlen_zero(member))
2553 interface = strsep(&member, ";");
2554 penalty_tok = strsep(&member, ";");
2555 paused_tok = strsep(&member, ";");
2558 ast_log(LOG_WARNING, "Error parsing persisent member string for '%s' (penalty)\n", queue_name);
2561 penalty = strtol(penalty_tok, NULL, 10);
2562 if (errno == ERANGE) {
2563 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2568 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2571 paused = strtol(paused_tok, NULL, 10);
2572 if ((errno == ERANGE) || paused < 0 || paused > 1) {
2573 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2578 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused);
2580 if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2581 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2587 ast_mutex_unlock(&qlock);
2589 ast_log(LOG_NOTICE, "Queue members sucessfully reloaded from database.\n");
2590 ast_db_freetree(db_tree);
2594 static int pqm_exec(struct ast_channel *chan, void *data)
2596 struct localuser *u;
2598 int priority_jump = 0;
2599 AST_DECLARE_APP_ARGS(args,
2600 AST_APP_ARG(queuename);
2601 AST_APP_ARG(interface);
2602 AST_APP_ARG(options);
2605 if (ast_strlen_zero(data)) {
2606 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2612 if (!(parse = ast_strdupa(data))) {
2613 ast_log(LOG_WARNING, "Memory Error!\n");
2614 LOCAL_USER_REMOVE(u);
2618 AST_STANDARD_APP_ARGS(args, parse);
2621 if (strchr(args.options, 'j'))
2625 if (ast_strlen_zero(args.interface)) {
2626 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2627 LOCAL_USER_REMOVE(u);
2631 if (set_member_paused(args.queuename, args.interface, 1)) {
2632 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
2633 if (priority_jump || ast_opt_priority_jumping) {
2634 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2635 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2636 LOCAL_USER_REMOVE(u);
2640 LOCAL_USER_REMOVE(u);
2641 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2645 LOCAL_USER_REMOVE(u);
2646 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2650 static int upqm_exec(struct ast_channel *chan, void *data)
2652 struct localuser *u;
2654 int priority_jump = 0;
2655 AST_DECLARE_APP_ARGS(args,
2656 AST_APP_ARG(queuename);
2657 AST_APP_ARG(interface);
2658 AST_APP_ARG(options);
2661 if (ast_strlen_zero(data)) {
2662 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2668 if (!(parse = ast_strdupa(data))) {
2669 ast_log(LOG_WARNING, "Memory Error!\n");
2670 LOCAL_USER_REMOVE(u);
2674 AST_STANDARD_APP_ARGS(args, parse);
2677 if (strchr(args.options, 'j'))
2681 if (ast_strlen_zero(args.interface)) {
2682 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2683 LOCAL_USER_REMOVE(u);
2687 if (set_member_paused(args.queuename, args.interface, 0)) {
2688 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
2689 if (priority_jump || ast_opt_priority_jumping) {
2690 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2691 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2692 LOCAL_USER_REMOVE(u);
2696 LOCAL_USER_REMOVE(u);
2697 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2701 LOCAL_USER_REMOVE(u);
2702 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2706 static int rqm_exec(struct ast_channel *chan, void *data)
2709 struct localuser *u;
2710 char *parse, *temppos = NULL;
2711 int priority_jump = 0;
2712 AST_DECLARE_APP_ARGS(args,
2713 AST_APP_ARG(queuename);
2714 AST_APP_ARG(interface);
2715 AST_APP_ARG(options);
2719 if (ast_strlen_zero(data)) {
2720 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2726 if (!(parse = ast_strdupa(data))) {
2727 ast_log(LOG_WARNING, "Memory Error!\n");
2728 LOCAL_USER_REMOVE(u);
2732 AST_STANDARD_APP_ARGS(args, parse);
2734 if (ast_strlen_zero(args.interface)) {
2735 args.interface = ast_strdupa(chan->name);
2736 temppos = strrchr(args.interface, '-');
2742 if (strchr(args.options, 'j'))
2746 switch (remove_from_queue(args.queuename, args.interface)) {
2748 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2749 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
2753 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
2754 if (priority_jump || ast_opt_priority_jumping)
2755 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2756 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
2759 case RES_NOSUCHQUEUE:
2760 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
2761 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
2764 case RES_OUTOFMEMORY:
2765 ast_log(LOG_ERROR, "Out of memory\n");
2769 LOCAL_USER_REMOVE(u);
2773 static int aqm_exec(struct ast_channel *chan, void *data)
2776 struct localuser *u;
2777 char *parse, *temppos = NULL;
2778 int priority_jump = 0;
2779 AST_DECLARE_APP_ARGS(args,
2780 AST_APP_ARG(queuename);
2781 AST_APP_ARG(interface);
2782 AST_APP_ARG(penalty);
2783 AST_APP_ARG(options);
2787 if (ast_strlen_zero(data)) {
2788 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2794 if (!(parse = ast_strdupa(data))) {
2795 ast_log(LOG_WARNING, "Memory Error!\n");
2796 LOCAL_USER_REMOVE(u);
2800 AST_STANDARD_APP_ARGS(args, parse);
2802 if (ast_strlen_zero(args.interface)) {
2803 args.interface = ast_strdupa(chan->name);
2804 temppos = strrchr(args.interface, '-');
2809 if (!ast_strlen_zero(args.penalty)) {
2810 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
2811 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
2817 if (strchr(args.options, 'j'))
2822 switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2824 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2825 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
2829 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
2830 if (priority_jump || ast_opt_priority_jumping)
2831 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2832 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
2835 case RES_NOSUCHQUEUE:
2836 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
2837 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
2840 case RES_OUTOFMEMORY:
2841 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2845 LOCAL_USER_REMOVE(u);
2849 static int queue_exec(struct ast_channel *chan, void *data)
2853 struct localuser *u;
2856 char *info_ptr = info;
2857 char *options = NULL;
2859 char *announceoverride = NULL;
2860 const char *user_priority;
2861 const char *max_penalty_str;
2864 char *queuetimeoutstr = NULL;
2865 enum queue_result reason = QUEUE_UNKNOWN;
2867 /* whether to exit Queue application after the timeout hits */
2870 /* Our queue entry */
2871 struct queue_ent qe;
2873 if (ast_strlen_zero(data)) {
2874 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
2880 /* Setup our queue entry */
2881 memset(&qe, 0, sizeof(qe));
2882 qe.start = time(NULL);
2884 /* Parse our arguments XXX Check for failure XXX */
2885 ast_copy_string(info, (char *) data, sizeof(info));
2886 queuename = strsep(&info_ptr, "|");
2887 options = strsep(&info_ptr, "|");
2888 url = strsep(&info_ptr, "|");
2889 announceoverride = strsep(&info_ptr, "|");
2890 queuetimeoutstr = info_ptr;
2892 /* set the expire time based on the supplied timeout; */
2893 if (queuetimeoutstr)
2894 qe.expire = qe.start + atoi(queuetimeoutstr);
2898 /* Get the priority from the variable ${QUEUE_PRIO} */
2899 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
2900 if (user_priority) {
2901 if (sscanf(user_priority, "%d", &prio) == 1) {
2903 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
2906 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
2907 user_priority, chan->name);
2911 if (option_debug > 2)
2912 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
2916 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
2917 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
2918 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {