2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief True call queues with optional send URL on answer
23 * \author Mark Spencer <markster@digium.com>
25 * \arg Config in \ref Config_qu queues.conf
27 * \par Development notes
28 * \note 2004-11-25: Persistent Dynamic Members added by:
29 * NetNation Communications (www.netnation.com)
30 * Kevin Lindsay <kevinl@netnation.com>
32 * Each dynamic agent in each queue is now stored in the astdb.
33 * When asterisk is restarted, each agent will be automatically
34 * readded into their recorded queues. This feature can be
35 * configured with the 'persistent_members=<1|0>' setting in the
36 * '[general]' category in queues.conf. The default is on.
38 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
40 * \note These features added by David C. Troy <dave@toad.net>:
41 * - Per-queue holdtime calculation
42 * - Estimated holdtime announcement
43 * - Position announcement
44 * - Abandoned/completed call counters
45 * - Failout timer passed as optional app parameter
46 * - Optional monitoring of calls, started when call is answered
48 * Patch Version 1.07 2003-12-24 01
50 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
53 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54 * by Matthew Enger <m.enger@xi.com.au>
56 * \ingroup applications
61 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
70 #include <sys/signal.h>
71 #include <netinet/in.h>
73 #include "asterisk/lock.h"
74 #include "asterisk/file.h"
75 #include "asterisk/logger.h"
76 #include "asterisk/channel.h"
77 #include "asterisk/pbx.h"
78 #include "asterisk/options.h"
79 #include "asterisk/app.h"
80 #include "asterisk/linkedlists.h"
81 #include "asterisk/module.h"
82 #include "asterisk/translate.h"
83 #include "asterisk/say.h"
84 #include "asterisk/features.h"
85 #include "asterisk/musiconhold.h"
86 #include "asterisk/cli.h"
87 #include "asterisk/manager.h"
88 #include "asterisk/config.h"
89 #include "asterisk/monitor.h"
90 #include "asterisk/utils.h"
91 #include "asterisk/causes.h"
92 #include "asterisk/astdb.h"
93 #include "asterisk/devicestate.h"
94 #include "asterisk/stringfields.h"
97 QUEUE_STRATEGY_RINGALL = 0,
98 QUEUE_STRATEGY_LEASTRECENT,
99 QUEUE_STRATEGY_FEWESTCALLS,
100 QUEUE_STRATEGY_RANDOM,
101 QUEUE_STRATEGY_RRMEMORY
104 static struct strategy {
108 { QUEUE_STRATEGY_RINGALL, "ringall" },
109 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
110 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
111 { QUEUE_STRATEGY_RANDOM, "random" },
112 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
115 #define DEFAULT_RETRY 5
116 #define DEFAULT_TIMEOUT 15
117 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
118 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
119 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /* The minimum number of seconds between position announcements
120 The default value of 15 provides backwards compatibility */
122 #define RES_OKAY 0 /* Action completed */
123 #define RES_EXISTS (-1) /* Entry already exists */
124 #define RES_OUTOFMEMORY (-2) /* Out of memory */
125 #define RES_NOSUCHQUEUE (-3) /* No such queue */
127 static char *app = "Queue";
129 static char *synopsis = "Queue a call for a call queue";
131 static char *descrip =
132 " Queue(queuename[|options[|URL][|announceoverride][|timeout][|AGI][|macro]):\n"
133 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
134 "This application will return to the dialplan if the queue does not exist, or\n"
135 "any of the join options cause the caller to not enter the queue.\n"
136 "The option string may contain zero or more of the following characters:\n"
137 " 'c' -- continue in the dialplan if the callee hangs up.\n"
138 " 'd' -- data-quality (modem) call (minimum delay).\n"
139 " 'h' -- allow callee to hang up by pressing *.\n"
140 " 'H' -- allow caller to hang up by pressing *.\n"
141 " 'n' -- no retries on the timeout; will exit this application and \n"
142 " go to the next step.\n"
143 " 'i' -- ignore call forward requests from queue members and do nothing\n"
144 " when they are requested.\n"
145 " 'r' -- ring instead of playing MOH.\n"
146 " 't' -- allow the called user to transfer the calling user.\n"
147 " 'T' -- allow the calling user to transfer the call.\n"
148 " 'w' -- allow the called user to write the conversation to disk via Monitor.\n"
149 " 'W' -- allow the calling user to write the conversation to disk via Monitor.\n"
150 " In addition to transferring the call, a call may be parked and then picked\n"
151 "up by another user.\n"
152 " The optional URL will be sent to the called party if the channel supports\n"
154 " The optional AGI parameter will setup an AGI script to be executed on the \n"
155 "calling party's channel once they are connected to a queue member.\n"
156 " The optional macro parameter will run a macro on the \n"
157 "calling party's channel once they are connected to a queue member.\n"
158 " The timeout will cause the queue to fail out after a specified number of\n"
159 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
160 " This application sets the following channel variable upon completion:\n"
161 " QUEUESTATUS The status of the call as a text string, one of\n"
162 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL | CONTINUE\n";
164 static char *app_aqm = "AddQueueMember" ;
165 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
166 static char *app_aqm_descrip =
167 " AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]]):\n"
168 "Dynamically adds interface to an existing queue.\n"
169 "If the interface is already in the queue and there exists an n+101 priority\n"
170 "then it will then jump to this priority. Otherwise it will return an error\n"
171 "The option string may contain zero or more of the following characters:\n"
172 " 'j' -- jump to +101 priority when appropriate.\n"
173 " This application sets the following channel variable upon completion:\n"
174 " AQMSTATUS The status of the attempt to add a queue member as a \n"
175 " text string, one of\n"
176 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
177 "Example: AddQueueMember(techsupport|SIP/3000)\n"
180 static char *app_rqm = "RemoveQueueMember" ;
181 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
182 static char *app_rqm_descrip =
183 " RemoveQueueMember(queuename[|interface[|options]]):\n"
184 "Dynamically removes interface to an existing queue\n"
185 "If the interface is NOT in the queue and there exists an n+101 priority\n"
186 "then it will then jump to this priority. Otherwise it will return an error\n"
187 "The option string may contain zero or more of the following characters:\n"
188 " 'j' -- jump to +101 priority when appropriate.\n"
189 " This application sets the following channel variable upon completion:\n"
190 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
191 " text string, one of\n"
192 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
193 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
196 static char *app_pqm = "PauseQueueMember" ;
197 static char *app_pqm_synopsis = "Pauses a queue member" ;
198 static char *app_pqm_descrip =
199 " PauseQueueMember([queuename]|interface[|options]):\n"
200 "Pauses (blocks calls for) a queue member.\n"
201 "The given interface will be paused in the given queue. This prevents\n"
202 "any calls from being sent from the queue to the interface until it is\n"
203 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
204 "queuename is given, the interface is paused in every queue it is a\n"
205 "member of. If the interface is not in the named queue, or if no queue\n"
206 "is given and the interface is not in any queue, it will jump to\n"
207 "priority n+101, if it exists and the appropriate options are set.\n"
208 "The application will fail if the interface is not found and no extension\n"
209 "to jump to exists.\n"
210 "The option string may contain zero or more of the following characters:\n"
211 " 'j' -- jump to +101 priority when appropriate.\n"
212 " This application sets the following channel variable upon completion:\n"
213 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
214 " text string, one of\n"
215 " PAUSED | NOTFOUND\n"
216 "Example: PauseQueueMember(|SIP/3000)\n";
218 static char *app_upqm = "UnpauseQueueMember" ;
219 static char *app_upqm_synopsis = "Unpauses a queue member" ;
220 static char *app_upqm_descrip =
221 " UnpauseQueueMember([queuename]|interface[|options]):\n"
222 "Unpauses (resumes calls to) a queue member.\n"
223 "This is the counterpart to PauseQueueMember and operates exactly the\n"
224 "same way, except it unpauses instead of pausing the given interface.\n"
225 "The option string may contain zero or more of the following characters:\n"
226 " 'j' -- jump to +101 priority when appropriate.\n"
227 " This application sets the following channel variable upon completion:\n"
228 " UPQMSTATUS The status of the attempt to unpause a queue \n"
229 " member as a text string, one of\n"
230 " UNPAUSED | NOTFOUND\n"
231 "Example: UnpauseQueueMember(|SIP/3000)\n";
233 static char *app_ql = "QueueLog" ;
234 static char *app_ql_synopsis = "Writes to the queue_log" ;
235 static char *app_ql_descrip =
236 " QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n"
237 "Allows you to write your own events into the queue log\n"
238 "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n";
240 /*! \brief Persistent Members astdb family */
241 static const char *pm_family = "/Queue/PersistentMembers";
242 /* The maximum length of each persistent member queue database entry */
243 #define PM_MAX_LEN 8192
245 /*! \brief queues.conf [general] option */
246 static int queue_keep_stats = 0;
248 /*! \brief queues.conf [general] option */
249 static int queue_persistent_members = 0;
251 /*! \brief queues.conf per-queue weight option */
252 static int use_weight = 0;
254 /*! \brief queues.conf [general] option */
255 static int autofill_default = 0;
257 /*! \brief queues.conf [general] option */
258 static int montype_default = 0;
264 QUEUE_LEAVEEMPTY = 3,
265 QUEUE_JOINUNAVAIL = 4,
266 QUEUE_LEAVEUNAVAIL = 5,
272 enum queue_result id;
274 } queue_results[] = {
275 { QUEUE_UNKNOWN, "UNKNOWN" },
276 { QUEUE_TIMEOUT, "TIMEOUT" },
277 { QUEUE_JOINEMPTY,"JOINEMPTY" },
278 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
279 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
280 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
281 { QUEUE_FULL, "FULL" },
282 { QUEUE_CONTINUE, "CONTINUE" },
285 /*! \brief We define a custom "local user" structure because we
286 use it not only for keeping track of what is in use but
287 also for keeping track of who we're dialing. */
290 struct callattempt *q_next;
291 struct ast_channel *chan;
297 struct member *member;
302 struct call_queue *parent; /*!< What queue is our parent */
303 char moh[80]; /*!< Name of musiconhold to be used */
304 char announce[80]; /*!< Announcement to play for member when call is answered */
305 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
306 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
307 int pos; /*!< Where we are in the queue */
308 int prio; /*!< Our priority */
309 int last_pos_said; /*!< Last position we told the user */
310 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
311 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
312 time_t last_pos; /*!< Last time we told the user their position */
313 int opos; /*!< Where we started in the queue */
314 int handled; /*!< Whether our call was handled */
315 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
316 time_t start; /*!< When we started holding */
317 time_t expire; /*!< When this entry should expire (time out of queue) */
318 struct ast_channel *chan; /*!< Our channel */
319 struct queue_ent *next; /*!< The next queue entry */
323 char interface[80]; /*!< Technology/Location */
324 char membername[80]; /*!< Member name to use in queue logs */
325 int penalty; /*!< Are we a last resort? */
326 int calls; /*!< Number of calls serviced by this member */
327 int dynamic; /*!< Are we dynamically added? */
328 int status; /*!< Status of queue member */
329 int paused; /*!< Are we paused (not accepting calls)? */
330 time_t lastcall; /*!< When last successful call was hungup */
331 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
332 unsigned int delme:1; /*!< Flag to delete entry on reload */
333 struct member *next; /*!< Next member */
336 struct member_interface {
338 AST_LIST_ENTRY(member_interface) list; /*!< Next call queue */
341 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
343 /* values used in multi-bit flags in call_queue */
344 #define QUEUE_EMPTY_NORMAL 1
345 #define QUEUE_EMPTY_STRICT 2
346 #define QUEUE_EMPTY_LOOSE 3
347 #define ANNOUNCEHOLDTIME_ALWAYS 1
348 #define ANNOUNCEHOLDTIME_ONCE 2
349 #define QUEUE_EVENT_VARIABLES 3
353 char name[80]; /*!< Name */
354 char moh[80]; /*!< Music On Hold class to be used */
355 char announce[80]; /*!< Announcement to play when call is answered */
356 char context[AST_MAX_CONTEXT]; /*!< Exit context */
357 unsigned int monjoin:1;
359 unsigned int joinempty:2;
360 unsigned int eventwhencalled:2;
361 unsigned int leavewhenempty:2;
362 unsigned int ringinuse:1;
363 unsigned int setinterfacevar:1;
364 unsigned int setqueuevar:1;
365 unsigned int setqueueentryvar:1;
366 unsigned int reportholdtime:1;
367 unsigned int wrapped:1;
368 unsigned int timeoutrestart:1;
369 unsigned int announceholdtime:2;
370 unsigned int strategy:3;
371 unsigned int maskmemberstatus:1;
372 unsigned int realtime:1;
373 int announcefrequency; /*!< How often to announce their position */
374 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
375 int periodicannouncefrequency; /*!< How often to play periodic announcement */
376 int roundingseconds; /*!< How many seconds do we round to? */
377 int holdtime; /*!< Current avg holdtime, based on recursive boxcar filter */
378 int callscompleted; /*!< Number of queue calls completed */
379 int callsabandoned; /*!< Number of queue calls abandoned */
380 int servicelevel; /*!< seconds setting for servicelevel*/
381 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
382 char monfmt[8]; /*!< Format to use when recording calls */
383 int montype; /*!< Monitor type Monitor vs. MixMonitor */
384 char membermacro[32]; /*!< Macro to run upon member connection */
385 char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
386 char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
387 char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
388 char sound_holdtime[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
389 char sound_minutes[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
390 char sound_lessthan[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
391 char sound_seconds[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
392 char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
393 char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
394 char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/*!< Sound files: Custom announce, no default */
396 int count; /*!< How many entries */
397 int maxlen; /*!< Max number of entries */
398 int wrapuptime; /*!< Wrapup Time */
400 int retry; /*!< Retry calling everyone after this amount of time */
401 int timeout; /*!< How long to wait for an answer */
402 int weight; /*!< Respective weight */
403 int autopause; /*!< Auto pause queue members if they fail to answer */
405 /* Queue strategy things */
406 int rrpos; /*!< Round Robin - position */
407 int memberdelay; /*!< Seconds to delay connecting member to caller */
408 int autofill; /*!< Ignore the head call status and ring an available agent */
410 struct member *members; /*!< Head of the list of members */
411 struct queue_ent *head; /*!< Head of the list of callers */
412 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
415 static AST_LIST_HEAD_STATIC(queues, call_queue);
417 static int set_member_paused(const char *queuename, const char *interface, int paused);
419 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
423 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
424 if (queue_results[i].id == res) {
425 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
431 static char *int2strat(int strategy)
435 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
436 if (strategy == strategies[x].strategy)
437 return strategies[x].name;
443 static int strat2int(const char *strategy)
447 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
448 if (!strcasecmp(strategy, strategies[x].name))
449 return strategies[x].strategy;
455 static void set_queue_variables(struct queue_ent *qe)
458 char interfacevar[256]="";
461 if (qe->parent->setqueuevar) {
463 if (qe->parent->callscompleted > 0)
464 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
466 snprintf(interfacevar,sizeof(interfacevar),
467 "QUEUEMAX=%d|QUEUESTRATEGY=%s|QUEUECALLS=%d|QUEUEHOLDTIME=%d|QUEUECOMPLETED=%d|QUEUEABANDONED=%d|QUEUESRVLEVEL=%d|QUEUESRVLEVELPERF=%2.1f",
468 qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
469 qe->parent->callsabandoned, qe->parent->servicelevel, sl);
471 pbx_builtin_setvar(qe->chan, interfacevar);
475 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
476 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
478 struct queue_ent *cur;
495 enum queue_member_status {
497 QUEUE_NO_REACHABLE_MEMBERS,
498 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
502 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
504 struct member *member;
505 enum queue_member_status result = QUEUE_NO_MEMBERS;
507 ast_mutex_lock(&q->lock);
508 for (member = q->members; member; member = member->next) {
509 if (max_penalty && (member->penalty > max_penalty))
512 switch (member->status) {
513 case AST_DEVICE_INVALID:
516 case AST_DEVICE_UNAVAILABLE:
517 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)
518 result = QUEUE_NO_REACHABLE_MEMBERS;
521 if (member->paused) {
522 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
524 ast_mutex_unlock(&q->lock);
531 ast_mutex_unlock(&q->lock);
536 AST_LIST_ENTRY(statechange) entry;
541 static void *handle_statechange(struct statechange *sc)
543 struct call_queue *q;
545 struct member_interface *curint;
549 technology = ast_strdupa(sc->dev);
550 loc = strchr(technology, '/');
558 AST_LIST_LOCK(&interfaces);
559 AST_LIST_TRAVERSE(&interfaces, curint, list) {
562 interface = ast_strdupa(curint->interface);
563 if ((slash_pos = strchr(interface, '/')))
564 if ((slash_pos = strchr(slash_pos + 1, '/')))
567 if (!strcasecmp(interface, sc->dev))
570 AST_LIST_UNLOCK(&interfaces);
573 if (option_debug > 2)
574 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
580 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
581 AST_LIST_LOCK(&queues);
582 AST_LIST_TRAVERSE(&queues, q, list) {
583 ast_mutex_lock(&q->lock);
584 for (cur = q->members; cur; cur = cur->next) {
587 interface = ast_strdupa(cur->interface);
588 if ((slash_pos = strchr(interface, '/')))
589 if ((slash_pos = strchr(slash_pos + 1, '/')))
592 if (strcasecmp(sc->dev, interface))
595 if (cur->status != sc->state) {
596 cur->status = sc->state;
597 if (q->maskmemberstatus)
600 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
610 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
611 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
614 ast_mutex_unlock(&q->lock);
616 AST_LIST_UNLOCK(&queues);
622 * \brief Data used by the device state thread
625 /*! Set to 1 to stop the thread */
627 /*! The device state monitoring thread */
629 /*! Lock for the state change queue */
631 /*! Condition for the state change queue */
633 /*! Queue of state changes */
634 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
636 .thread = AST_PTHREADT_NULL,
639 static void *device_state_thread(void *data)
641 struct statechange *sc;
643 while (!device_state.stop) {
644 ast_mutex_lock(&device_state.lock);
645 while (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
646 ast_cond_wait(&device_state.cond, &device_state.lock);
647 ast_mutex_unlock(&device_state.lock);
649 /* Check to see if we were woken up to see the request to stop */
650 if (device_state.stop)
653 handle_statechange(sc);
661 static int statechange_queue(const char *dev, enum ast_device_state state, void *data)
663 /* Avoid potential for deadlocks by spawning a new thread to handle
665 struct statechange *sc;
667 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
671 strcpy(sc->dev, dev);
673 ast_mutex_lock(&device_state.lock);
674 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
675 ast_cond_signal(&device_state.cond);
676 ast_mutex_unlock(&device_state.lock);
681 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
685 if ((cur = ast_calloc(1, sizeof(*cur)))) {
686 cur->penalty = penalty;
687 cur->paused = paused;
688 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
689 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
690 if (!strchr(cur->interface, '/'))
691 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
692 cur->status = ast_device_state(interface);
698 static struct call_queue *alloc_queue(const char *queuename)
700 struct call_queue *q;
702 if ((q = ast_calloc(1, sizeof(*q)))) {
703 ast_mutex_init(&q->lock);
704 ast_copy_string(q->name, queuename, sizeof(q->name));
709 static void init_queue(struct call_queue *q)
714 q->retry = DEFAULT_RETRY;
717 q->announcefrequency = 0;
718 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
719 q->announceholdtime = 0;
720 q->roundingseconds = 0; /* Default - don't announce seconds */
723 q->setinterfacevar = 0;
725 q->setqueueentryvar = 0;
726 q->autofill = autofill_default;
727 q->montype = montype_default;
728 q->membermacro[0] = '\0';
730 q->announce[0] = '\0';
731 q->context[0] = '\0';
733 q->periodicannouncefrequency = 0;
734 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
735 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
736 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
737 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
738 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
739 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
740 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
741 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
742 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
743 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
744 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
745 q->sound_periodicannounce[i][0]='\0';
749 static void clear_queue(struct call_queue *q)
752 q->callscompleted = 0;
753 q->callsabandoned = 0;
754 q->callscompletedinsl = 0;
758 static int add_to_interfaces(const char *interface)
760 struct member_interface *curint;
762 AST_LIST_LOCK(&interfaces);
763 AST_LIST_TRAVERSE(&interfaces, curint, list) {
764 if (!strcasecmp(curint->interface, interface))
769 AST_LIST_UNLOCK(&interfaces);
774 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
776 if ((curint = ast_calloc(1, sizeof(*curint)))) {
777 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
778 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
780 AST_LIST_UNLOCK(&interfaces);
785 static int interface_exists_global(const char *interface)
787 struct call_queue *q;
791 AST_LIST_LOCK(&queues);
792 AST_LIST_TRAVERSE(&queues, q, list) {
793 ast_mutex_lock(&q->lock);
794 for (mem = q->members; mem && !ret; mem = mem->next) {
795 if (!strcasecmp(interface, mem->interface))
798 ast_mutex_unlock(&q->lock);
802 AST_LIST_UNLOCK(&queues);
807 static int remove_from_interfaces(const char *interface)
809 struct member_interface *curint;
811 AST_LIST_LOCK(&interfaces);
812 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
813 if (!strcasecmp(curint->interface, interface)) {
814 if (!interface_exists_global(interface)) {
816 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
817 AST_LIST_REMOVE_CURRENT(&interfaces, list);
823 AST_LIST_TRAVERSE_SAFE_END;
824 AST_LIST_UNLOCK(&interfaces);
829 static void clear_and_free_interfaces(void)
831 struct member_interface *curint;
833 AST_LIST_LOCK(&interfaces);
834 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
836 AST_LIST_UNLOCK(&interfaces);
839 /*! \brief Configure a queue parameter.
841 For error reporting, line number is passed for .conf static configuration.
842 For Realtime queues, linenum is -1.
843 The failunknown flag is set for config files (and static realtime) to show
844 errors for unknown parameters. It is cleared for dynamic realtime to allow
845 extra fields in the tables. */
846 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
848 if (!strcasecmp(param, "musicclass") ||
849 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
850 ast_copy_string(q->moh, val, sizeof(q->moh));
851 } else if (!strcasecmp(param, "announce")) {
852 ast_copy_string(q->announce, val, sizeof(q->announce));
853 } else if (!strcasecmp(param, "context")) {
854 ast_copy_string(q->context, val, sizeof(q->context));
855 } else if (!strcasecmp(param, "timeout")) {
856 q->timeout = atoi(val);
858 q->timeout = DEFAULT_TIMEOUT;
859 } else if (!strcasecmp(param, "ringinuse")) {
860 q->ringinuse = ast_true(val);
861 } else if (!strcasecmp(param, "setinterfacevar")) {
862 q->setinterfacevar = ast_true(val);
863 } else if (!strcasecmp(param, "setqueuevar")) {
864 q->setqueuevar = ast_true(val);
865 } else if (!strcasecmp(param, "setqueueentryvar")) {
866 q->setqueueentryvar = ast_true(val);
867 } else if (!strcasecmp(param, "monitor-join")) {
868 q->monjoin = ast_true(val);
869 } else if (!strcasecmp(param, "monitor-format")) {
870 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
871 } else if (!strcasecmp(param, "membermacro")) {
872 ast_copy_string(q->membermacro, val, sizeof(q->membermacro));
873 } else if (!strcasecmp(param, "queue-youarenext")) {
874 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
875 } else if (!strcasecmp(param, "queue-thereare")) {
876 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
877 } else if (!strcasecmp(param, "queue-callswaiting")) {
878 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
879 } else if (!strcasecmp(param, "queue-holdtime")) {
880 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
881 } else if (!strcasecmp(param, "queue-minutes")) {
882 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
883 } else if (!strcasecmp(param, "queue-seconds")) {
884 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
885 } else if (!strcasecmp(param, "queue-lessthan")) {
886 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
887 } else if (!strcasecmp(param, "queue-thankyou")) {
888 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
889 } else if (!strcasecmp(param, "queue-reporthold")) {
890 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
891 } else if (!strcasecmp(param, "announce-frequency")) {
892 q->announcefrequency = atoi(val);
893 } else if (!strcasecmp(param, "min-announce-frequency")) {
894 q->minannouncefrequency = atoi(val);
895 ast_log(LOG_DEBUG, "%s=%s for queue '%s'\n", param, val, q->name);
896 } else if (!strcasecmp(param, "announce-round-seconds")) {
897 q->roundingseconds = atoi(val);
898 /* Rounding to any other values just doesn't make sense... */
899 if (!(q->roundingseconds == 0 || q->roundingseconds == 1 || q->roundingseconds == 5 || q->roundingseconds == 10
900 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
902 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
903 "using 0 instead for queue '%s' at line %d of queues.conf\n",
904 val, param, q->name, linenum);
906 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
907 "using 0 instead for queue '%s'\n", val, param, q->name);
909 q->roundingseconds=0;
911 } else if (!strcasecmp(param, "announce-holdtime")) {
912 if (!strcasecmp(val, "once"))
913 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
914 else if (ast_true(val))
915 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
917 q->announceholdtime = 0;
918 } else if (!strcasecmp(param, "periodic-announce")) {
919 if (strchr(val, '|')) {
920 char *s, *buf = ast_strdupa(val);
923 while ((s = strsep(&buf, "|"))) {
924 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
926 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
930 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
932 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
933 q->periodicannouncefrequency = atoi(val);
934 } else if (!strcasecmp(param, "retry")) {
935 q->retry = atoi(val);
937 q->retry = DEFAULT_RETRY;
938 } else if (!strcasecmp(param, "wrapuptime")) {
939 q->wrapuptime = atoi(val);
940 } else if (!strcasecmp(param, "autofill")) {
941 q->autofill = ast_true(val);
942 } else if (!strcasecmp(param, "monitor-type")) {
943 if (!strcasecmp(val, "mixmonitor"))
945 } else if (!strcasecmp(param, "autopause")) {
946 q->autopause = ast_true(val);
947 } else if (!strcasecmp(param, "maxlen")) {
948 q->maxlen = atoi(val);
951 } else if (!strcasecmp(param, "servicelevel")) {
952 q->servicelevel= atoi(val);
953 } else if (!strcasecmp(param, "strategy")) {
954 q->strategy = strat2int(val);
955 if (q->strategy < 0) {
956 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
958 q->strategy = QUEUE_STRATEGY_RINGALL;
960 } else if (!strcasecmp(param, "joinempty")) {
961 if (!strcasecmp(val, "loose"))
962 q->joinempty = QUEUE_EMPTY_LOOSE;
963 else if (!strcasecmp(val, "strict"))
964 q->joinempty = QUEUE_EMPTY_STRICT;
965 else if (ast_true(val))
966 q->joinempty = QUEUE_EMPTY_NORMAL;
969 } else if (!strcasecmp(param, "leavewhenempty")) {
970 if (!strcasecmp(val, "loose"))
971 q->leavewhenempty = QUEUE_EMPTY_LOOSE;
972 else if (!strcasecmp(val, "strict"))
973 q->leavewhenempty = QUEUE_EMPTY_STRICT;
974 else if (ast_true(val))
975 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
977 q->leavewhenempty = 0;
978 } else if (!strcasecmp(param, "eventmemberstatus")) {
979 q->maskmemberstatus = !ast_true(val);
980 } else if (!strcasecmp(param, "eventwhencalled")) {
981 if (!strcasecmp(val, "vars")) {
982 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
984 q->eventwhencalled = ast_true(val);
986 } else if (!strcasecmp(param, "reportholdtime")) {
987 q->reportholdtime = ast_true(val);
988 } else if (!strcasecmp(param, "memberdelay")) {
989 q->memberdelay = atoi(val);
990 } else if (!strcasecmp(param, "weight")) {
991 q->weight = atoi(val);
994 /* With Realtime queues, if the last queue using weights is deleted in realtime,
995 we will not see any effect on use_weight until next reload. */
996 } else if (!strcasecmp(param, "timeoutrestart")) {
997 q->timeoutrestart = ast_true(val);
998 } else if (failunknown) {
1000 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1001 q->name, param, linenum);
1003 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1008 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1010 struct member *m, *prev_m;
1015 penalty = atoi(penalty_str);
1021 paused = atoi(paused_str);
1026 /* Find the member, or the place to put a new one. */
1027 for (m = q->members, prev_m = NULL;
1028 m && strcmp(m->interface, interface);
1029 prev_m = m, m = m->next);
1031 /* Create a new one if not found, else update penalty */
1033 if ((m = create_queue_member(interface, membername, penalty, paused))) {
1035 add_to_interfaces(interface);
1043 m->dead = 0; /* Do not delete this one. */
1046 m->penalty = penalty;
1050 static void free_members(struct call_queue *q, int all)
1052 /* Free non-dynamic members */
1053 struct member *curm, *next, *prev = NULL;
1055 for (curm = q->members; curm; curm = next) {
1057 if (all || !curm->dynamic) {
1062 remove_from_interfaces(curm->interface);
1069 static void destroy_queue(struct call_queue *q)
1072 ast_mutex_destroy(&q->lock);
1076 /*!\brief Reload a single queue via realtime.
1077 \return Return the queue, or NULL if it doesn't exist.
1078 \note Should be called with the global qlock locked. */
1079 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1081 struct ast_variable *v;
1082 struct call_queue *q;
1083 struct member *m, *prev_m, *next_m;
1084 char *interface = NULL;
1085 char *tmp, *tmp_name;
1086 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1088 /* Find the queue in the in-core list (we will create a new one if not found). */
1089 AST_LIST_TRAVERSE(&queues, q, list) {
1090 if (!strcasecmp(q->name, queuename))
1094 /* Static queues override realtime. */
1096 ast_mutex_lock(&q->lock);
1099 ast_mutex_unlock(&q->lock);
1102 ast_mutex_unlock(&q->lock);
1106 } else if (!member_config)
1107 /* Not found in the list, and it's not realtime ... */
1110 /* Check if queue is defined in realtime. */
1112 /* Delete queue from in-core list if it has been deleted in realtime. */
1114 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1115 found condition... So we might delete an in-core queue
1116 in case of DB failure. */
1118 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
1121 /* Delete if unused (else will be deleted when last caller leaves). */
1124 AST_LIST_REMOVE(&queues, q, list);
1125 ast_mutex_unlock(&q->lock);
1128 ast_mutex_unlock(&q->lock);
1133 /* Create a new queue if an in-core entry does not exist yet. */
1135 if (!(q = alloc_queue(queuename)))
1137 ast_mutex_lock(&q->lock);
1140 AST_LIST_INSERT_HEAD(&queues, q, list);
1142 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1144 memset(tmpbuf, 0, sizeof(tmpbuf));
1145 for (v = queue_vars; v; v = v->next) {
1146 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1147 if ((tmp = strchr(v->name, '_'))) {
1148 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1151 while ((tmp = strchr(tmp, '_')))
1155 queue_set_param(q, tmp_name, v->value, -1, 0);
1158 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
1159 for (m = q->members; m; m = m->next) {
1164 while ((interface = ast_category_browse(member_config, interface))) {
1165 rt_handle_member_record(q, interface,
1166 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1167 ast_variable_retrieve(member_config, interface, "penalty"),
1168 ast_variable_retrieve(member_config, interface, "paused"));
1171 /* Delete all realtime members that have been deleted in DB. */
1178 prev_m->next = next_m;
1180 q->members = next_m;
1182 remove_from_interfaces(m->interface);
1190 ast_mutex_unlock(&q->lock);
1195 static struct call_queue *load_realtime_queue(const char *queuename)
1197 struct ast_variable *queue_vars;
1198 struct ast_config *member_config = NULL;
1199 struct call_queue *q;
1201 /* Find the queue in the in-core list first. */
1202 AST_LIST_LOCK(&queues);
1203 AST_LIST_TRAVERSE(&queues, q, list) {
1204 if (!strcasecmp(q->name, queuename)) {
1208 AST_LIST_UNLOCK(&queues);
1210 if (!q || q->realtime) {
1211 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1212 queue operations while waiting for the DB.
1214 This will be two separate database transactions, so we might
1215 see queue parameters as they were before another process
1216 changed the queue and member list as it was after the change.
1217 Thus we might see an empty member list when a queue is
1218 deleted. In practise, this is unlikely to cause a problem. */
1220 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1222 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1223 if (!member_config) {
1224 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1229 AST_LIST_LOCK(&queues);
1231 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1233 ast_config_destroy(member_config);
1235 ast_variables_destroy(queue_vars);
1237 AST_LIST_UNLOCK(&queues);
1242 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1244 struct call_queue *q;
1245 struct queue_ent *cur, *prev = NULL;
1249 enum queue_member_status stat;
1251 if (!(q = load_realtime_queue(queuename)))
1254 AST_LIST_LOCK(&queues);
1255 ast_mutex_lock(&q->lock);
1257 /* This is our one */
1258 stat = get_member_status(q, qe->max_penalty);
1259 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1260 *reason = QUEUE_JOINEMPTY;
1261 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS))
1262 *reason = QUEUE_JOINUNAVAIL;
1263 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1264 *reason = QUEUE_JOINUNAVAIL;
1265 else if (q->maxlen && (q->count >= q->maxlen))
1266 *reason = QUEUE_FULL;
1268 /* There's space for us, put us at the right position inside
1270 * Take into account the priority of the calling user */
1275 /* We have higher priority than the current user, enter
1276 * before him, after all the other users with priority
1277 * higher or equal to our priority. */
1278 if ((!inserted) && (qe->prio > cur->prio)) {
1279 insert_entry(q, prev, qe, &pos);
1286 /* No luck, join at the end of the queue */
1288 insert_entry(q, prev, qe, &pos);
1289 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1290 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1291 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1294 manager_event(EVENT_FLAG_CALL, "Join",
1295 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1297 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1298 S_OR(qe->chan->cid.cid_name, "unknown"),
1299 q->name, qe->pos, q->count, qe->chan->uniqueid );
1301 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1303 ast_mutex_unlock(&q->lock);
1304 AST_LIST_UNLOCK(&queues);
1309 static int play_file(struct ast_channel *chan, char *filename)
1313 ast_stopstream(chan);
1314 res = ast_streamfile(chan, filename, chan->language);
1316 res = ast_waitstream(chan, AST_DIGIT_ANY);
1317 ast_stopstream(chan);
1322 static int valid_exit(struct queue_ent *qe, char digit)
1324 int digitlen = strlen(qe->digits);
1326 /* Prevent possible buffer overflow */
1327 if (digitlen < sizeof(qe->digits) - 2) {
1328 qe->digits[digitlen] = digit;
1329 qe->digits[digitlen + 1] = '\0';
1331 qe->digits[0] = '\0';
1335 /* If there's no context to goto, short-circuit */
1336 if (ast_strlen_zero(qe->context))
1339 /* If the extension is bad, then reset the digits to blank */
1340 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1341 qe->digits[0] = '\0';
1345 /* We have an exact match */
1346 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1347 /* Return 1 on a successful goto */
1354 static int say_position(struct queue_ent *qe)
1356 int res = 0, avgholdmins, avgholdsecs;
1359 /* Let minannouncefrequency seconds pass between the start of each position announcement */
1361 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
1364 /* If either our position has changed, or we are over the freq timer, say position */
1365 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1368 ast_moh_stop(qe->chan);
1369 /* Say we're next, if we are */
1371 res = play_file(qe->chan, qe->parent->sound_next);
1372 if (res && valid_exit(qe, res))
1377 res = play_file(qe->chan, qe->parent->sound_thereare);
1378 if (res && valid_exit(qe, res))
1380 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1381 if (res && valid_exit(qe, res))
1383 res = play_file(qe->chan, qe->parent->sound_calls);
1384 if (res && valid_exit(qe, res))
1387 /* Round hold time to nearest minute */
1388 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1390 /* If they have specified a rounding then round the seconds as well */
1391 if (qe->parent->roundingseconds) {
1392 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1393 avgholdsecs *= qe->parent->roundingseconds;
1398 if (option_verbose > 2)
1399 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1401 /* If the hold time is >1 min, if it's enabled, and if it's not
1402 supposed to be only once and we have already said it, say it */
1403 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1404 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1405 res = play_file(qe->chan, qe->parent->sound_holdtime);
1406 if (res && valid_exit(qe, res))
1409 if (avgholdmins > 0) {
1410 if (avgholdmins < 2) {
1411 res = play_file(qe->chan, qe->parent->sound_lessthan);
1412 if (res && valid_exit(qe, res))
1415 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1416 if (res && valid_exit(qe, res))
1419 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1420 if (res && valid_exit(qe, res))
1424 res = play_file(qe->chan, qe->parent->sound_minutes);
1425 if (res && valid_exit(qe, res))
1428 if (avgholdsecs>0) {
1429 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1430 if (res && valid_exit(qe, res))
1433 res = play_file(qe->chan, qe->parent->sound_seconds);
1434 if (res && valid_exit(qe, res))
1441 if (option_verbose > 2)
1442 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1443 qe->chan->name, qe->parent->name, qe->pos);
1444 res = play_file(qe->chan, qe->parent->sound_thanks);
1445 if (res && !valid_exit(qe, res))
1449 /* Set our last_pos indicators */
1451 qe->last_pos_said = qe->pos;
1453 /* Don't restart music on hold if we're about to exit the caller from the queue */
1455 ast_moh_start(qe->chan, qe->moh, NULL);
1460 static void recalc_holdtime(struct queue_ent *qe)
1462 int oldvalue, newvalue;
1464 /* Calculate holdtime using a recursive boxcar filter */
1465 /* Thanks to SRT for this contribution */
1466 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1468 newvalue = time(NULL) - qe->start;
1470 ast_mutex_lock(&qe->parent->lock);
1471 if (newvalue <= qe->parent->servicelevel)
1472 qe->parent->callscompletedinsl++;
1473 oldvalue = qe->parent->holdtime;
1474 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1475 ast_mutex_unlock(&qe->parent->lock);
1479 static void leave_queue(struct queue_ent *qe)
1481 struct call_queue *q;
1482 struct queue_ent *cur, *prev = NULL;
1485 if (!(q = qe->parent))
1487 ast_mutex_lock(&q->lock);
1490 for (cur = q->head; cur; cur = cur->next) {
1494 /* Take us out of the queue */
1495 manager_event(EVENT_FLAG_CALL, "Leave",
1496 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1497 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1499 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1500 /* Take us out of the queue */
1502 prev->next = cur->next;
1504 q->head = cur->next;
1506 /* Renumber the people after us in the queue based on a new count */
1511 ast_mutex_unlock(&q->lock);
1513 if (q->dead && !q->count) {
1514 /* It's dead and nobody is in it, so kill it */
1515 AST_LIST_LOCK(&queues);
1516 AST_LIST_REMOVE(&queues, q, list);
1517 AST_LIST_UNLOCK(&queues);
1522 /* Hang up a list of outgoing calls */
1523 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1525 struct callattempt *oo;
1528 /* Hangup any existing lines we have open */
1529 if (outgoing->chan && (outgoing->chan != exception))
1530 ast_hangup(outgoing->chan);
1532 outgoing = outgoing->q_next;
1537 static int update_status(struct call_queue *q, struct member *member, int status)
1541 /* Since a reload could have taken place, we have to traverse the list to
1542 be sure it's still valid */
1543 ast_mutex_lock(&q->lock);
1544 for (cur = q->members; cur; cur = cur->next) {
1548 cur->status = status;
1549 if (!q->maskmemberstatus) {
1550 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1553 "MemberName: %s\r\n"
1554 "Membership: %s\r\n"
1556 "CallsTaken: %d\r\n"
1560 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
1561 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1564 ast_mutex_unlock(&q->lock);
1568 static int update_dial_status(struct call_queue *q, struct member *member, int status)
1570 if (status == AST_CAUSE_BUSY)
1571 status = AST_DEVICE_BUSY;
1572 else if (status == AST_CAUSE_UNREGISTERED)
1573 status = AST_DEVICE_UNAVAILABLE;
1574 else if (status == AST_CAUSE_NOSUCHDRIVER)
1575 status = AST_DEVICE_INVALID;
1577 status = AST_DEVICE_UNKNOWN;
1578 return update_status(q, member, status);
1581 /* traverse all defined queues which have calls waiting and contain this member
1582 return 0 if no other queue has precedence (higher weight) or 1 if found */
1583 static int compare_weight(struct call_queue *rq, struct member *member)
1585 struct call_queue *q;
1589 /* &qlock and &rq->lock already set by try_calling()
1590 * to solve deadlock */
1591 AST_LIST_TRAVERSE(&queues, q, list) {
1592 if (q == rq) /* don't check myself, could deadlock */
1594 ast_mutex_lock(&q->lock);
1595 if (q->count && q->members) {
1596 for (mem = q->members; mem; mem = mem->next) {
1597 if (strcmp(mem->interface, member->interface))
1601 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1602 if (q->weight > rq->weight) {
1604 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);
1610 ast_mutex_unlock(&q->lock);
1617 /*! \brief common hangup actions */
1618 static void do_hang(struct callattempt *o)
1621 ast_hangup(o->chan);
1625 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1627 struct ast_str *buf = ast_str_alloca(len + 1);
1630 if (pbx_builtin_serialize_variables(chan, &buf)) {
1633 /* convert "\n" to "\nVariable: " */
1634 strcpy(vars, "Variable: ");
1637 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1640 if (tmp[i + 1] == '\0')
1642 if (tmp[i] == '\n') {
1646 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1656 /* there are no channel variables; leave it blank */
1662 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1669 /* on entry here, we know that tmp->chan == NULL */
1670 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1672 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1674 ast_cdr_busy(qe->chan->cdr);
1675 tmp->stillgoing = 0;
1680 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1682 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1684 ast_cdr_busy(qe->chan->cdr);
1685 tmp->stillgoing = 0;
1689 if (tmp->member->paused) {
1691 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1693 ast_cdr_busy(qe->chan->cdr);
1694 tmp->stillgoing = 0;
1697 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1699 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1701 ast_cdr_busy(qe->chan->cdr);
1702 tmp->stillgoing = 0;
1707 ast_copy_string(tech, tmp->interface, sizeof(tech));
1708 if ((location = strchr(tech, '/')))
1713 /* Request the peer */
1714 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1715 if (!tmp->chan) { /* If we can't, just go on to the next call */
1717 ast_cdr_busy(qe->chan->cdr);
1718 tmp->stillgoing = 0;
1719 update_dial_status(qe->parent, tmp->member, status);
1721 ast_mutex_lock(&qe->parent->lock);
1722 qe->parent->rrpos++;
1723 ast_mutex_unlock(&qe->parent->lock);
1727 } else if (status != tmp->oldstatus)
1728 update_dial_status(qe->parent, tmp->member, status);
1730 tmp->chan->appl = "AppQueue";
1731 tmp->chan->data = "(Outgoing Line)";
1732 tmp->chan->whentohangup = 0;
1733 if (tmp->chan->cid.cid_num)
1734 free(tmp->chan->cid.cid_num);
1735 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1736 if (tmp->chan->cid.cid_name)
1737 free(tmp->chan->cid.cid_name);
1738 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1739 if (tmp->chan->cid.cid_ani)
1740 free(tmp->chan->cid.cid_ani);
1741 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1743 /* Inherit specially named variables from parent channel */
1744 ast_channel_inherit_variables(qe->chan, tmp->chan);
1746 /* Presense of ADSI CPE on outgoing channel follows ours */
1747 tmp->chan->adsicpe = qe->chan->adsicpe;
1749 /* Place the call, but don't wait on the answer */
1750 if ((res = ast_call(tmp->chan, location, 0))) {
1751 /* Again, keep going even if there's an error */
1753 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1754 if (option_verbose > 2)
1755 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1759 } else if (qe->parent->eventwhencalled) {
1762 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1763 "AgentCalled: %s\r\n"
1764 "ChannelCalling: %s\r\n"
1765 "CallerIDNum: %s\r\n"
1766 "CallerIDName: %s\r\n"
1771 tmp->interface, qe->chan->name,
1772 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1773 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1774 qe->chan->context, qe->chan->exten, qe->chan->priority,
1775 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1776 if (option_verbose > 2)
1777 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1783 /*! \brief find the entry with the best metric, or NULL */
1784 static struct callattempt *find_best(struct callattempt *outgoing)
1786 struct callattempt *best = NULL, *cur;
1788 for (cur = outgoing; cur; cur = cur->q_next) {
1789 if (cur->stillgoing && /* Not already done */
1790 !cur->chan && /* Isn't already going */
1791 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1799 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1804 struct callattempt *best = find_best(outgoing);
1807 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1810 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1811 struct callattempt *cur;
1812 /* Ring everyone who shares this best metric (for ringall) */
1813 for (cur = outgoing; cur; cur = cur->q_next) {
1814 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1816 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1817 ring_entry(qe, cur, busies);
1821 /* Ring just the best channel */
1823 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1824 ring_entry(qe, best, busies);
1826 if (best->chan) /* break out with result = 1 */
1833 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1835 struct callattempt *best = find_best(outgoing);
1838 /* Ring just the best channel */
1840 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1841 qe->parent->rrpos = best->metric % 1000;
1843 /* Just increment rrpos */
1844 if (qe->parent->wrapped) {
1845 /* No more channels, start over */
1846 qe->parent->rrpos = 0;
1848 /* Prioritize next entry */
1849 qe->parent->rrpos++;
1852 qe->parent->wrapped = 0;
1857 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1861 ast_stopstream(chan);
1862 res = ast_streamfile(chan, filename, chan->language);
1865 /* Wait for a keypress */
1866 res = ast_waitstream(chan, AST_DIGIT_ANY);
1867 if (res < 0 || !valid_exit(qe, res))
1871 ast_stopstream(chan);
1877 static int say_periodic_announcement(struct queue_ent *qe)
1882 /* Get the current time */
1885 /* Check to see if it is time to announce */
1886 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1889 /* Stop the music on hold so we can play our own file */
1890 ast_moh_stop(qe->chan);
1892 if (option_verbose > 2)
1893 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1895 /* Check to make sure we have a sound file. If not, reset to the first sound file */
1896 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
1897 qe->last_periodic_announce_sound = 0;
1900 /* play the announcement */
1901 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
1903 /* Resume Music on Hold if the caller is going to stay in the queue */
1905 ast_moh_start(qe->chan, qe->moh, NULL);
1907 /* update last_periodic_announce_time */
1908 qe->last_periodic_announce_time = now;
1910 /* Update the current periodic announcement to the next announcement */
1911 qe->last_periodic_announce_sound++;
1916 static void record_abandoned(struct queue_ent *qe)
1918 ast_mutex_lock(&qe->parent->lock);
1919 set_queue_variables(qe);
1920 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
1924 "OriginalPosition: %d\r\n"
1926 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
1928 qe->parent->callsabandoned++;
1929 ast_mutex_unlock(&qe->parent->lock);
1932 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
1933 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
1935 if (option_verbose > 2)
1936 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
1937 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
1938 if (qe->parent->autopause) {
1939 if (!set_member_paused(qe->parent->name, interface, 1)) {
1940 if (option_verbose > 2)
1941 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
1943 if (option_verbose > 2)
1944 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
1950 #define AST_MAX_WATCHERS 256
1952 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
1954 char *queue = qe->parent->name;
1955 struct callattempt *o;
1957 int sentringing = 0;
1958 int numbusies = prebusies;
1962 struct ast_frame *f;
1963 struct callattempt *peer = NULL;
1964 struct ast_channel *winner;
1965 struct ast_channel *in = qe->chan;
1967 char membername[80] = "";
1971 starttime = (long) time(NULL);
1973 while (*to && !peer) {
1974 int numlines, retry, pos = 1;
1975 struct ast_channel *watchers[AST_MAX_WATCHERS];
1978 for (retry = 0; retry < 2; retry++) {
1980 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
1981 if (o->stillgoing) { /* Keep track of important channels */
1984 watchers[pos++] = o->chan;
1988 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
1989 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
1991 /* On "ringall" strategy we only move to the next penalty level
1992 when *all* ringing phones are done in the current penalty level */
1993 ring_one(qe, outgoing, &numbusies);
1996 if (pos == 1 /* not found */) {
1997 if (numlines == (numbusies + numnochan)) {
1999 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
2001 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2006 winner = ast_waitfor_n(watchers, pos, to);
2007 for (o = outgoing; o; o = o->q_next) {
2008 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2010 if (option_verbose > 2)
2011 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2014 } else if (o->chan && (o->chan == winner)) {
2016 ast_copy_string(on, o->member->interface, sizeof(on));
2017 ast_copy_string(membername, o->member->membername, sizeof(membername));
2019 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2020 if (option_verbose > 2)
2021 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2026 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2031 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2032 if ((stuff = strchr(tmpchan, '/'))) {
2036 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2040 /* Before processing channel, go ahead and check for forwarding */
2041 if (option_verbose > 2)
2042 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2043 /* Setup parameters */
2044 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2045 if (status != o->oldstatus)
2046 update_dial_status(qe->parent, o->member, status);
2048 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2052 ast_channel_inherit_variables(in, o->chan);
2053 if (o->chan->cid.cid_num)
2054 free(o->chan->cid.cid_num);
2055 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2057 if (o->chan->cid.cid_name)
2058 free(o->chan->cid.cid_name);
2059 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2061 ast_string_field_set(o->chan, accountcode, in->accountcode);
2062 o->chan->cdrflags = in->cdrflags;
2064 if (in->cid.cid_ani) {
2065 if (o->chan->cid.cid_ani)
2066 free(o->chan->cid.cid_ani);
2067 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2069 if (o->chan->cid.cid_rdnis)
2070 free(o->chan->cid.cid_rdnis);
2071 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2072 if (ast_call(o->chan, tmpchan, 0)) {
2073 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2078 /* Hangup the original channel now, in case we needed it */
2082 f = ast_read(winner);
2084 if (f->frametype == AST_FRAME_CONTROL) {
2085 switch (f->subclass) {
2086 case AST_CONTROL_ANSWER:
2087 /* This is our guy if someone answered. */
2089 if (option_verbose > 2)
2090 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2094 case AST_CONTROL_BUSY:
2095 if (option_verbose > 2)
2096 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
2098 ast_cdr_busy(in->cdr);
2100 endtime = (long) time(NULL);
2101 endtime -= starttime;
2102 rna(endtime*1000, qe, on, membername);
2103 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2104 if (qe->parent->timeoutrestart)
2106 ring_one(qe, outgoing, &numbusies);
2110 case AST_CONTROL_CONGESTION:
2111 if (option_verbose > 2)
2112 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
2114 ast_cdr_busy(in->cdr);
2115 endtime = (long) time(NULL);
2116 endtime -= starttime;
2117 rna(endtime*1000, qe, on, membername);
2119 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2120 if (qe->parent->timeoutrestart)
2122 ring_one(qe, outgoing, &numbusies);
2126 case AST_CONTROL_RINGING:
2127 if (option_verbose > 2)
2128 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
2131 ast_indicate(in, AST_CONTROL_RINGING);
2136 case AST_CONTROL_OFFHOOK:
2137 /* Ignore going off hook */
2141 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
2146 endtime = (long) time(NULL) - starttime;
2147 rna(endtime * 1000, qe, on, membername);
2149 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2150 if (qe->parent->timeoutrestart)
2152 ring_one(qe, outgoing, &numbusies);
2159 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2166 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2167 if (option_verbose > 3)
2168 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
2173 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2174 if (option_verbose > 3)
2175 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
2177 *digit = f->subclass;
2184 rna(orig, qe, on, membername);
2190 static int is_our_turn(struct queue_ent *qe)
2192 struct queue_ent *ch;
2198 if (!qe->parent->autofill) {
2199 /* Atomically read the parent head -- does not need a lock */
2200 ch = qe->parent->head;
2201 /* If we are now at the top of the head, break out */
2204 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2208 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2213 /* This needs a lock. How many members are available to be served? */
2214 ast_mutex_lock(&qe->parent->lock);
2216 ch = qe->parent->head;
2218 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2220 ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in\n", avl);
2223 for (cur = qe->parent->members; cur; cur = cur->next) {
2224 switch (cur->status) {
2225 case AST_DEVICE_NOT_INUSE:
2226 case AST_DEVICE_UNKNOWN:
2234 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
2236 while ((idx < avl) && (ch) && (ch != qe)) {
2241 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2242 if (ch && idx < avl) {
2244 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2248 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2252 ast_mutex_unlock(&qe->parent->lock);
2258 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2262 /* This is the holding pen for callers 2 through maxlen */
2264 enum queue_member_status stat;
2266 if (is_our_turn(qe))
2269 /* If we have timed out, break out */
2270 if (qe->expire && (time(NULL) > qe->expire)) {
2271 *reason = QUEUE_TIMEOUT;
2275 stat = get_member_status(qe->parent, qe->max_penalty);
2277 /* leave the queue if no agents, if enabled */
2278 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2279 *reason = QUEUE_LEAVEEMPTY;
2280 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2285 /* leave the queue if no reachable agents, if enabled */
2286 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2287 *reason = QUEUE_LEAVEUNAVAIL;
2288 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2292 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2293 *reason = QUEUE_LEAVEUNAVAIL;
2294 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2299 /* Make a position announcement, if enabled */
2300 if (qe->parent->announcefrequency && !ringing &&
2301 (res = say_position(qe)))
2304 /* Make a periodic announcement, if enabled */
2305 if (qe->parent->periodicannouncefrequency && !ringing &&
2306 (res = say_periodic_announcement(qe)))
2309 /* Wait a second before checking again */
2310 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000)))
2317 static int update_queue(struct call_queue *q, struct member *member)
2321 /* Since a reload could have taken place, we have to traverse the list to
2322 be sure it's still valid */
2323 ast_mutex_lock(&q->lock);
2326 if (member == cur) {
2327 time(&cur->lastcall);
2333 q->callscompleted++;
2334 ast_mutex_unlock(&q->lock);
2338 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2340 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2343 switch (q->strategy) {
2344 case QUEUE_STRATEGY_RINGALL:
2345 /* Everyone equal, except for penalty */
2346 tmp->metric = mem->penalty * 1000000;
2348 case QUEUE_STRATEGY_RRMEMORY:
2349 if (pos < q->rrpos) {
2350 tmp->metric = 1000 + pos;
2353 /* Indicate there is another priority */
2357 tmp->metric += mem->penalty * 1000000;
2359 case QUEUE_STRATEGY_RANDOM:
2360 tmp->metric = ast_random() % 1000;
2361 tmp->metric += mem->penalty * 1000000;
2363 case QUEUE_STRATEGY_FEWESTCALLS:
2364 tmp->metric = mem->calls;
2365 tmp->metric += mem->penalty * 1000000;
2367 case QUEUE_STRATEGY_LEASTRECENT:
2371 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2372 tmp->metric += mem->penalty * 1000000;
2375 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2381 enum agent_complete_reason {
2387 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
2388 const struct ast_channel *peer, const struct member *member, time_t callstart,
2389 char *vars, size_t vars_len, enum agent_complete_reason rsn)
2393 if (!qe->parent->eventwhencalled)
2404 reason = "transfer";
2408 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2413 "MemberName: %s\r\n"
2418 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2419 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
2420 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
2423 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on, const char *agi, const char *macro)
2426 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2428 char oldexten[AST_MAX_EXTENSION]="";
2429 char oldcontext[AST_MAX_CONTEXT]="";
2430 char queuename[256]="";
2431 char interfacevar[256]="";
2432 struct ast_channel *peer;
2433 struct ast_channel *which;
2434 struct callattempt *lpeer;
2435 struct member *member;
2436 struct ast_app *app;
2437 int res = 0, bridge = 0;
2440 char *announce = NULL;
2443 time_t now = time(NULL);
2444 struct ast_bridge_config bridge_config;
2445 char nondataquality = 1;
2446 char *agiexec = NULL;
2447 char *macroexec = NULL;
2449 const char *monitorfilename;
2450 const char *monitor_exec;
2451 const char *monitor_options;
2452 char tmpid[256], tmpid2[256];
2453 char meid[1024], meid2[1024];
2454 char mixmonargs[1512];
2455 struct ast_app *mixmonapp = NULL;
2458 int forwardsallowed = 1;
2459 memset(&bridge_config, 0, sizeof(bridge_config));
2462 for (; options && *options; options++)
2465 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2468 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2471 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2474 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2480 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2483 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2486 if ((now - qe->start >= qe->parent->timeout))
2490 forwardsallowed = 0;
2494 /* Hold the lock while we setup the outgoing calls */
2496 AST_LIST_LOCK(&queues);
2497 ast_mutex_lock(&qe->parent->lock);
2499 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2501 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2502 cur = qe->parent->members;
2503 if (!ast_strlen_zero(qe->announce))
2504 announce = qe->announce;
2505 if (!ast_strlen_zero(announceoverride))
2506 announce = announceoverride;
2508 for (; cur; cur = cur->next) {
2509 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2512 ast_mutex_unlock(&qe->parent->lock);
2514 AST_LIST_UNLOCK(&queues);
2517 tmp->stillgoing = -1;
2518 tmp->member = cur; /* Never directly dereference! Could change on reload */
2519 tmp->oldstatus = cur->status;
2520 tmp->lastcall = cur->lastcall;
2521 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2522 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2523 just calculate their metric for the appropriate strategy */
2524 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2525 /* Put them in the list of outgoing thingies... We're ready now.
2526 XXX If we're forcibly removed, these outgoing calls won't get
2528 tmp->q_next = outgoing;
2530 /* If this line is up, don't try anybody else */
2531 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2537 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2538 to = (qe->expire - now) * 1000;
2540 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2541 ring_one(qe, outgoing, &numbusies);
2542 ast_mutex_unlock(&qe->parent->lock);
2544 AST_LIST_UNLOCK(&queues);
2545 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2546 ast_mutex_lock(&qe->parent->lock);
2547 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2548 store_next(qe, outgoing);
2550 ast_mutex_unlock(&qe->parent->lock);
2551 peer = lpeer ? lpeer->chan : NULL;
2554 /* Must gotten hung up */
2560 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2561 } else { /* peer is valid */
2562 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2563 we will always return with -1 so that it is hung up properly after the
2566 if (!strcmp(qe->chan->tech->type, "Zap"))
2567 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2568 if (!strcmp(peer->tech->type, "Zap"))
2569 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2570 /* Update parameters for the queue */
2571 recalc_holdtime(qe);
2572 member = lpeer->member;
2573 hangupcalls(outgoing, peer);
2575 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2578 res2 = ast_autoservice_start(qe->chan);
2580 if (qe->parent->memberdelay) {
2581 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2582 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2584 if (!res2 && announce) {
2585 if (play_file(peer, announce))
2586 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2588 if (!res2 && qe->parent->reportholdtime) {
2589 if (!play_file(peer, qe->parent->sound_reporthold)) {
2593 holdtime = abs((now - qe->start) / 60);
2595 play_file(peer, qe->parent->sound_lessthan);
2596 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2598 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2599 play_file(peer, qe->parent->sound_minutes);
2603 res2 |= ast_autoservice_stop(qe->chan);
2604 if (peer->_softhangup) {
2605 /* Agent must have hung up */
2606 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
2607 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2608 record_abandoned(qe);
2609 if (qe->parent->eventwhencalled)
2610 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2615 "MemberName: %s\r\n"
2617 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2618 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2622 /* Caller must have hung up just before being connected*/
2623 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2624 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2625 record_abandoned(qe);
2630 /* Stop music on hold */
2631 ast_moh_stop(qe->chan);
2632 /* If appropriate, log that we have a destination channel */
2634 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2635 /* Make sure channels are compatible */
2636 res = ast_channel_make_compatible(qe->chan, peer);
2638 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2639 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2640 record_abandoned(qe);
2644 /* Begin Monitoring */
2645 if (qe->parent->monfmt && *qe->parent->monfmt) {
2646 if (!qe->parent->montype) {
2648 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
2649 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2650 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2654 if (monitorfilename)
2655 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2656 else if (qe->chan->cdr)
2657 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2659 /* Last ditch effort -- no CDR, make up something */
2660 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2661 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2663 if (qe->parent->monjoin)
2664 ast_monitor_setjoinfiles(which, 1);
2667 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
2668 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2669 if (!monitorfilename) {
2671 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
2673 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2675 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
2676 for (p = tmpid2; *p ; p++) {
2677 if (*p == '^' && *(p+1) == '{') {
2682 memset(tmpid, 0, sizeof(tmpid));
2683 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2686 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2687 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2690 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
2691 for (p = meid2; *p ; p++) {
2692 if (*p == '^' && *(p+1) == '{') {
2697 memset(meid, 0, sizeof(meid));
2698 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2701 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
2703 mixmonapp = pbx_findapp("MixMonitor");
2705 if (strchr(tmpid2, '|')) {
2706 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
2710 if (!monitor_options)
2711 monitor_options = "";
2713 if (strchr(monitor_options, '|')) {
2714 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
2719 if (!ast_strlen_zero(monitor_exec))
2720 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
2722 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
2725 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2727 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2730 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2734 /* Drop out of the queue at this point, to prepare for next caller */
2736 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2738 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2739 ast_channel_sendurl(peer, url);
2742 ast_mutex_lock(&qe->parent->lock);
2743 /* if setinterfacevar is defined, make member variables available to the channel */
2744 /* use pbx_builtin_setvar to set a load of variables with one call */
2745 if (qe->parent->setinterfacevar) {
2746 snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d",
2747 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic);
2748 pbx_builtin_setvar(qe->chan, interfacevar);
2751 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
2752 /* use pbx_builtin_setvar to set a load of variables with one call */
2753 if (qe->parent->setqueueentryvar) {
2754 snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
2755 (long) time(NULL) - qe->start, qe->opos);
2756 pbx_builtin_setvar(qe->chan, interfacevar);
2759 /* try to set queue variables if configured to do so*/
2760 set_queue_variables(qe);
2761 ast_mutex_unlock(&qe->parent->lock);
2763 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
2764 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
2765 if (!ast_strlen_zero(macro)) {
2766 macroexec = ast_strdupa(macro);
2768 if (qe->parent->membermacro)
2769 macroexec = ast_strdupa(qe->parent->membermacro);
2772 if (!ast_strlen_zero(macroexec)) {
2774 ast_log(LOG_DEBUG, "app_queue: macro=%s.\n", macroexec);
2776 res = ast_autoservice_start(qe->chan);
2778 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
2782 app = pbx_findapp("Macro");
2785 res = pbx_exec(qe->chan, app, macroexec);
2787 ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
2790 ast_log(LOG_ERROR, "Could not find application Macro\n");
2794 if (ast_autoservice_stop(qe->chan) < 0) {
2795 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
2800 if (!ast_strlen_zero(agi)) {
2802 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
2803 app = pbx_findapp("agi");
2805 agiexec = ast_strdupa(agi);
2806 ret = pbx_exec(qe->chan, app, agiexec);
2808 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
2810 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long) time(NULL) - qe->start, peer->uniqueid);
2811 if (qe->parent->eventwhencalled)
2812 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2817 "MemberName: %s\r\n"
2819 "BridgedChannel: %s\r\n"
2821 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2822 (long) time(NULL) - qe->start, peer->uniqueid,
2823 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2824 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2825 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2828 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2830 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2831 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
2832 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
2833 (long) (time(NULL) - callstart));
2834 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
2835 } else if (qe->chan->_softhangup) {
2836 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
2837 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
2838 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
2840 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
2841 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
2842 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
2845 if (bridge != AST_PBX_NO_HANGUP_PEER)
2847 update_queue(qe->parent, member);
2848 res = bridge ? bridge : 1;
2851 hangupcalls(outgoing, NULL);
2856 static int wait_a_bit(struct queue_ent *qe)
2858 /* Don't need to hold the lock while we setup the outgoing calls */
2859 int retrywait = qe->parent->retry * 1000;
2861 return ast_waitfordigit(qe->chan, retrywait);
2864 static struct member *interface_exists(struct call_queue *q, const char *interface)
2871 for (mem = q->members; mem; mem = mem->next) {
2872 if (!strcasecmp(interface, mem->interface))
2880 /* Dump all members in a specific queue to the database
2882 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2885 static void dump_queue_members(struct call_queue *pm_queue)
2887 struct member *cur_member;
2888 char value[PM_MAX_LEN];
2892 memset(value, 0, sizeof(value));
2897 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2898 if (!cur_member->dynamic)
2901 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%s%s",
2902 cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername,
2903 cur_member->next ? "|" : "");
2904 if (res != strlen(value + value_len)) {
2905 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2911 if (value_len && !cur_member) {
2912 if (ast_db_put(pm_family, pm_queue->name, value))
2913 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2915 /* Delete the entry if the queue is empty or there is an error */
2916 ast_db_del(pm_family, pm_queue->name);
2919 static int remove_from_queue(const char *queuename, const char *interface)
2921 struct call_queue *q;
2922 struct member *last_member, *look;
2923 int res = RES_NOSUCHQUEUE;
2925 AST_LIST_LOCK(&queues);
2926 AST_LIST_TRAVERSE(&queues, q, list) {
2927 ast_mutex_lock(&q->lock);
2928 if (strcmp(q->name, queuename)) {
2929 ast_mutex_unlock(&q->lock);
2933 if ((last_member = interface_exists(q, interface))) {
2934 if ((look = q->members) == last_member) {
2935 q->members = last_member->next;
2937 while (look != NULL) {
2938 if (look->next == last_member) {
2939 look->next = last_member->next;
2946 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2949 "MemberName: %s\r\n",
2950 q->name, last_member->interface, last_member->membername);
2953 if (queue_persistent_members)
2954 dump_queue_members(q);
2960 ast_mutex_unlock(&q->lock);
2964 if (res == RES_OKAY)
2965 remove_from_interfaces(interface);
2967 AST_LIST_UNLOCK(&queues);
2973 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
2975 struct call_queue *q;
2976 struct member *new_member;
2977 int res = RES_NOSUCHQUEUE;
2979 /* \note Ensure the appropriate realtime queue is loaded. Note that this
2980 * short-circuits if the queue is already in memory. */
2981 if (!(q = load_realtime_queue(queuename)))
2984 AST_LIST_LOCK(&queues);
2986 ast_mutex_lock(&q->lock);
2987 if (interface_exists(q, interface) == NULL) {
2988 add_to_interfaces(interface);
2989 if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
2990 new_member->dynamic = 1;
2991 new_member->next = q->members;
2992 q->members = new_member;
2993 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2996 "MemberName: %s\r\n"
2997 "Membership: %s\r\n"
2999 "CallsTaken: %d\r\n"
3003 q->name, new_member->interface, new_member->membername,
3004 new_member->dynamic ? "dynamic" : "static",
3005 new_member->penalty, new_member->calls, (int) new_member->lastcall,
3006 new_member->status, new_member->paused);
3009 dump_queue_members(q);
3013 res = RES_OUTOFMEMORY;
3018 ast_mutex_unlock(&q->lock);
3019 AST_LIST_UNLOCK(&queues);
3024 static int set_member_paused(const char *queuename, const char *interface, int paused)
3027 struct call_queue *q;
3030 /* Special event for when all queues are paused - individual events still generated */
3031 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
3032 if (ast_strlen_zero(queuename))
3033 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
3035 AST_LIST_LOCK(&queues);
3036 AST_LIST_TRAVERSE(&queues, q, list) {
3037 ast_mutex_lock(&q->lock);
3038 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
3039 if ((mem = interface_exists(q, interface))) {
3041 if (mem->paused == paused) {
3043 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
3045 mem->paused = paused;
3047 if (queue_persistent_members)
3048 dump_queue_members(q);
3050 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
3052 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
3055 "MemberName: %s\r\n"
3057 q->name, mem->interface, mem->membername, paused);
3060 ast_mutex_unlock(&q->lock);
3062 AST_LIST_UNLOCK(&queues);
3064 return found ? RESULT_SUCCESS : RESULT_FAILURE;
3067 /* Reload dynamic queue members persisted into the astdb */
3068 static void reload_queue_members(void)
3079 struct ast_db_entry *db_tree;
3080 struct ast_db_entry *entry;
3081 struct call_queue *cur_queue;
3082 char queue_data[PM_MAX_LEN];
3084 AST_LIST_LOCK(&queues);
3086 /* Each key in 'pm_family' is the name of a queue */
3087 db_tree = ast_db_gettree(pm_family, NULL);
3088 for (entry = db_tree; entry; entry = entry->next) {
3090 queue_name = entry->key + strlen(pm_family) + 2;
3092 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
3093 ast_mutex_lock(&cur_queue->lock);
3094 if (!strcmp(queue_name, cur_queue->name))
3096 ast_mutex_unlock(&cur_queue->lock);
3100 /* If the queue no longer exists, remove it from the
3102 ast_db_del(pm_family, queue_name);
3105 ast_mutex_unlock(&cur_queue->lock);
3107 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
3110 cur_ptr = queue_data;
3111 while ((member = strsep(&cur_ptr, "|"))) {
3112 if (ast_strlen_zero(member))
3115 interface = strsep(&member, ";");
3116 penalty_tok = strsep(&member, ";");
3117 paused_tok = strsep(&member, ";");
3118 membername = strsep(&member, ";");
3121 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
3124 penalty = strtol(penalty_tok, NULL, 10);
3125 if (errno == ERANGE) {
3126 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
3131 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
3134 paused = strtol(paused_tok, NULL, 10);
3135 if ((errno == ERANGE) || paused < 0 || paused > 1) {
3136 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
3139 if (ast_strlen_zero(membername))
3140 membername = interface;
3143 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
3145 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
3146 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
3152 AST_LIST_UNLOCK(&queues);
3154 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
3155 ast_db_freetree(db_tree);
3159 static int pqm_exec(struct ast_channel *chan, void *data)
3161 struct ast_module_user *lu;
3163 int priority_jump = 0;
3164 AST_DECLARE_APP_ARGS(args,
3165 AST_APP_ARG(queuename);
3166 AST_APP_ARG(interface);
3167 AST_APP_ARG(options);
3170 if (ast_strlen_zero(data)) {
3171 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3175 parse = ast_strdupa(data);
3177 AST_STANDARD_APP_ARGS(args, parse);
3179 lu = ast_module_user_add(chan);
3182 if (strchr(args.options, 'j'))
3186 if (ast_strlen_zero(args.interface)) {
3187 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3188 ast_module_user_remove(lu);
3192 if (set_member_paused(args.queuename, args.interface, 1)) {
3193 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
3194 if (priority_jump || ast_opt_priority_jumping) {
3195 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3196 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3197 ast_module_user_remove(lu);
3201 ast_module_user_remove(lu);
3202 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
3206 ast_module_user_remove(lu);
3207 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
3212 static int upqm_exec(struct ast_channel *chan, void *data)
3214 struct ast_module_user *lu;
3216 int priority_jump = 0;
3217 AST_DECLARE_APP_ARGS(args,
3218 AST_APP_ARG(queuename);
3219 AST_APP_ARG(interface);
3220 AST_APP_ARG(options);
3223 if (ast_strlen_zero(data)) {
3224 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3228 parse = ast_strdupa(data);
3230 AST_STANDARD_APP_ARGS(args, parse);
3232 lu = ast_module_user_add(chan);
3235 if (strchr(args.options, 'j'))
3239 if (ast_strlen_zero(args.interface)) {
3240 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3241 ast_module_user_remove(lu);
3245 if (set_member_paused(args.queuename, args.interface, 0)) {
3246 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
3247 if (priority_jump || ast_opt_priority_jumping) {
3248 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
3249 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3250 ast_module_user_remove(lu);
3254 ast_module_user_remove(lu);
3255 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
3259 ast_module_user_remove(lu);
3260 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
3265 static int rqm_exec(struct ast_channel *chan, void *data)
3268 struct ast_module_user *lu;
3269 char *parse, *temppos = NULL;
3270 int priority_jump = 0;
3271 AST_DECLARE_APP_ARGS(args,
3272 AST_APP_ARG(queuename);
3273 AST_APP_ARG(interface);
3274 AST_APP_ARG(options);
3278 if (ast_strlen_zero(data)) {
3279 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
3283 parse = ast_strdupa(data);
3285 AST_STANDARD_APP_ARGS(args, parse);
3287 lu = ast_module_user_add(chan);
3289 if (ast_strlen_zero(args.interface)) {
3290 args.interface = ast_strdupa(chan->name);
3291 temppos = strrchr(args.interface, '-');
3297 if (strchr(args.options, 'j'))
3301 switch (remove_from_queue(args.queuename, args.interface)) {
3303 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
3304 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
3305 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
3310 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
3311 if (priority_jump || ast_opt_priority_jumping)
3312 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
3313 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
3316 case RES_NOSUCHQUEUE:
3317 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
3318 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
3323 ast_module_user_remove(lu);
3328 static int aqm_exec(struct ast_channel *chan, void *data)
3331 struct ast_module_user *lu;
3332 char *parse, *temppos = NULL;
3333 int priority_jump = 0;
3334 AST_DECLARE_APP_ARGS(args,
3335 AST_APP_ARG(queuename);
3336 AST_APP_ARG(interface);
3337 AST_APP_ARG(penalty);
3338 AST_APP_ARG(options);
3339 AST_APP_ARG(membername);