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, '/');
557 AST_LIST_LOCK(&interfaces);
558 AST_LIST_TRAVERSE(&interfaces, curint, list) {
561 interface = ast_strdupa(curint->interface);
562 if ((slash_pos = strchr(interface, '/')))
563 if ((slash_pos = strchr(slash_pos + 1, '/')))
566 if (!strcasecmp(interface, sc->dev))
569 AST_LIST_UNLOCK(&interfaces);
572 if (option_debug > 2)
573 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));
578 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
579 AST_LIST_LOCK(&queues);
580 AST_LIST_TRAVERSE(&queues, q, list) {
581 ast_mutex_lock(&q->lock);
582 for (cur = q->members; cur; cur = cur->next) {
585 interface = ast_strdupa(cur->interface);
586 if ((slash_pos = strchr(interface, '/')))
587 if ((slash_pos = strchr(slash_pos + 1, '/')))
590 if (strcasecmp(sc->dev, interface))
593 if (cur->status != sc->state) {
594 cur->status = sc->state;
595 if (q->maskmemberstatus)
598 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
608 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
609 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
612 ast_mutex_unlock(&q->lock);
614 AST_LIST_UNLOCK(&queues);
620 * \brief Data used by the device state thread
623 /*! Set to 1 to stop the thread */
625 /*! The device state monitoring thread */
627 /*! Lock for the state change queue */
629 /*! Condition for the state change queue */
631 /*! Queue of state changes */
632 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
634 .thread = AST_PTHREADT_NULL,
637 static void *device_state_thread(void *data)
639 struct statechange *sc;
641 while (!device_state.stop) {
642 ast_mutex_lock(&device_state.lock);
643 while (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
644 ast_cond_wait(&device_state.cond, &device_state.lock);
645 ast_mutex_unlock(&device_state.lock);
647 /* Check to see if we were woken up to see the request to stop */
648 if (device_state.stop)
651 handle_statechange(sc);
659 static int statechange_queue(const char *dev, enum ast_device_state state, void *data)
661 /* Avoid potential for deadlocks by spawning a new thread to handle
663 struct statechange *sc;
665 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
669 strcpy(sc->dev, dev);
671 ast_mutex_lock(&device_state.lock);
672 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
673 ast_cond_signal(&device_state.cond);
674 ast_mutex_unlock(&device_state.lock);
679 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
683 if ((cur = ast_calloc(1, sizeof(*cur)))) {
684 cur->penalty = penalty;
685 cur->paused = paused;
686 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
687 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
688 if (!strchr(cur->interface, '/'))
689 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
690 cur->status = ast_device_state(interface);
696 static struct call_queue *alloc_queue(const char *queuename)
698 struct call_queue *q;
700 if ((q = ast_calloc(1, sizeof(*q)))) {
701 ast_mutex_init(&q->lock);
702 ast_copy_string(q->name, queuename, sizeof(q->name));
707 static void init_queue(struct call_queue *q)
712 q->retry = DEFAULT_RETRY;
715 q->announcefrequency = 0;
716 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
717 q->announceholdtime = 0;
718 q->roundingseconds = 0; /* Default - don't announce seconds */
721 q->setinterfacevar = 0;
723 q->setqueueentryvar = 0;
724 q->autofill = autofill_default;
725 q->montype = montype_default;
726 q->membermacro[0] = '\0';
728 q->announce[0] = '\0';
729 q->context[0] = '\0';
731 q->periodicannouncefrequency = 0;
732 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
733 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
734 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
735 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
736 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
737 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
738 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
739 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
740 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
741 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
742 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
743 q->sound_periodicannounce[i][0]='\0';
747 static void clear_queue(struct call_queue *q)
750 q->callscompleted = 0;
751 q->callsabandoned = 0;
752 q->callscompletedinsl = 0;
756 static int add_to_interfaces(const char *interface)
758 struct member_interface *curint;
760 AST_LIST_LOCK(&interfaces);
761 AST_LIST_TRAVERSE(&interfaces, curint, list) {
762 if (!strcasecmp(curint->interface, interface))
767 AST_LIST_UNLOCK(&interfaces);
772 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
774 if ((curint = ast_calloc(1, sizeof(*curint)))) {
775 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
776 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
778 AST_LIST_UNLOCK(&interfaces);
783 static int interface_exists_global(const char *interface)
785 struct call_queue *q;
789 AST_LIST_LOCK(&queues);
790 AST_LIST_TRAVERSE(&queues, q, list) {
791 ast_mutex_lock(&q->lock);
792 for (mem = q->members; mem && !ret; mem = mem->next) {
793 if (!strcasecmp(interface, mem->interface))
796 ast_mutex_unlock(&q->lock);
800 AST_LIST_UNLOCK(&queues);
805 static int remove_from_interfaces(const char *interface)
807 struct member_interface *curint;
809 AST_LIST_LOCK(&interfaces);
810 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
811 if (!strcasecmp(curint->interface, interface)) {
812 if (!interface_exists_global(interface)) {
814 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
815 AST_LIST_REMOVE_CURRENT(&interfaces, list);
821 AST_LIST_TRAVERSE_SAFE_END;
822 AST_LIST_UNLOCK(&interfaces);
827 static void clear_and_free_interfaces(void)
829 struct member_interface *curint;
831 AST_LIST_LOCK(&interfaces);
832 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
834 AST_LIST_UNLOCK(&interfaces);
837 /*! \brief Configure a queue parameter.
839 For error reporting, line number is passed for .conf static configuration.
840 For Realtime queues, linenum is -1.
841 The failunknown flag is set for config files (and static realtime) to show
842 errors for unknown parameters. It is cleared for dynamic realtime to allow
843 extra fields in the tables. */
844 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
846 if (!strcasecmp(param, "musicclass") ||
847 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
848 ast_copy_string(q->moh, val, sizeof(q->moh));
849 } else if (!strcasecmp(param, "announce")) {
850 ast_copy_string(q->announce, val, sizeof(q->announce));
851 } else if (!strcasecmp(param, "context")) {
852 ast_copy_string(q->context, val, sizeof(q->context));
853 } else if (!strcasecmp(param, "timeout")) {
854 q->timeout = atoi(val);
856 q->timeout = DEFAULT_TIMEOUT;
857 } else if (!strcasecmp(param, "ringinuse")) {
858 q->ringinuse = ast_true(val);
859 } else if (!strcasecmp(param, "setinterfacevar")) {
860 q->setinterfacevar = ast_true(val);
861 } else if (!strcasecmp(param, "setqueuevar")) {
862 q->setqueuevar = ast_true(val);
863 } else if (!strcasecmp(param, "setqueueentryvar")) {
864 q->setqueueentryvar = ast_true(val);
865 } else if (!strcasecmp(param, "monitor-join")) {
866 q->monjoin = ast_true(val);
867 } else if (!strcasecmp(param, "monitor-format")) {
868 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
869 } else if (!strcasecmp(param, "membermacro")) {
870 ast_copy_string(q->membermacro, val, sizeof(q->membermacro));
871 } else if (!strcasecmp(param, "queue-youarenext")) {
872 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
873 } else if (!strcasecmp(param, "queue-thereare")) {
874 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
875 } else if (!strcasecmp(param, "queue-callswaiting")) {
876 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
877 } else if (!strcasecmp(param, "queue-holdtime")) {
878 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
879 } else if (!strcasecmp(param, "queue-minutes")) {
880 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
881 } else if (!strcasecmp(param, "queue-seconds")) {
882 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
883 } else if (!strcasecmp(param, "queue-lessthan")) {
884 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
885 } else if (!strcasecmp(param, "queue-thankyou")) {
886 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
887 } else if (!strcasecmp(param, "queue-reporthold")) {
888 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
889 } else if (!strcasecmp(param, "announce-frequency")) {
890 q->announcefrequency = atoi(val);
891 } else if (!strcasecmp(param, "min-announce-frequency")) {
892 q->minannouncefrequency = atoi(val);
893 ast_log(LOG_DEBUG, "%s=%s for queue '%s'\n", param, val, q->name);
894 } else if (!strcasecmp(param, "announce-round-seconds")) {
895 q->roundingseconds = atoi(val);
896 /* Rounding to any other values just doesn't make sense... */
897 if (!(q->roundingseconds == 0 || q->roundingseconds == 1 || q->roundingseconds == 5 || q->roundingseconds == 10
898 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
900 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
901 "using 0 instead for queue '%s' at line %d of queues.conf\n",
902 val, param, q->name, linenum);
904 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
905 "using 0 instead for queue '%s'\n", val, param, q->name);
907 q->roundingseconds=0;
909 } else if (!strcasecmp(param, "announce-holdtime")) {
910 if (!strcasecmp(val, "once"))
911 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
912 else if (ast_true(val))
913 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
915 q->announceholdtime = 0;
916 } else if (!strcasecmp(param, "periodic-announce")) {
917 if (strchr(val, '|')) {
918 char *s, *buf = ast_strdupa(val);
921 while ((s = strsep(&buf, "|"))) {
922 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
924 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
928 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
930 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
931 q->periodicannouncefrequency = atoi(val);
932 } else if (!strcasecmp(param, "retry")) {
933 q->retry = atoi(val);
935 q->retry = DEFAULT_RETRY;
936 } else if (!strcasecmp(param, "wrapuptime")) {
937 q->wrapuptime = atoi(val);
938 } else if (!strcasecmp(param, "autofill")) {
939 q->autofill = ast_true(val);
940 } else if (!strcasecmp(param, "monitor-type")) {
941 if (!strcasecmp(val, "mixmonitor"))
943 } else if (!strcasecmp(param, "autopause")) {
944 q->autopause = ast_true(val);
945 } else if (!strcasecmp(param, "maxlen")) {
946 q->maxlen = atoi(val);
949 } else if (!strcasecmp(param, "servicelevel")) {
950 q->servicelevel= atoi(val);
951 } else if (!strcasecmp(param, "strategy")) {
952 q->strategy = strat2int(val);
953 if (q->strategy < 0) {
954 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
956 q->strategy = QUEUE_STRATEGY_RINGALL;
958 } else if (!strcasecmp(param, "joinempty")) {
959 if (!strcasecmp(val, "loose"))
960 q->joinempty = QUEUE_EMPTY_LOOSE;
961 else if (!strcasecmp(val, "strict"))
962 q->joinempty = QUEUE_EMPTY_STRICT;
963 else if (ast_true(val))
964 q->joinempty = QUEUE_EMPTY_NORMAL;
967 } else if (!strcasecmp(param, "leavewhenempty")) {
968 if (!strcasecmp(val, "loose"))
969 q->leavewhenempty = QUEUE_EMPTY_LOOSE;
970 else if (!strcasecmp(val, "strict"))
971 q->leavewhenempty = QUEUE_EMPTY_STRICT;
972 else if (ast_true(val))
973 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
975 q->leavewhenempty = 0;
976 } else if (!strcasecmp(param, "eventmemberstatus")) {
977 q->maskmemberstatus = !ast_true(val);
978 } else if (!strcasecmp(param, "eventwhencalled")) {
979 if (!strcasecmp(val, "vars")) {
980 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
982 q->eventwhencalled = ast_true(val);
984 } else if (!strcasecmp(param, "reportholdtime")) {
985 q->reportholdtime = ast_true(val);
986 } else if (!strcasecmp(param, "memberdelay")) {
987 q->memberdelay = atoi(val);
988 } else if (!strcasecmp(param, "weight")) {
989 q->weight = atoi(val);
992 /* With Realtime queues, if the last queue using weights is deleted in realtime,
993 we will not see any effect on use_weight until next reload. */
994 } else if (!strcasecmp(param, "timeoutrestart")) {
995 q->timeoutrestart = ast_true(val);
996 } else if (failunknown) {
998 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
999 q->name, param, linenum);
1001 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1006 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1008 struct member *m, *prev_m;
1013 penalty = atoi(penalty_str);
1019 paused = atoi(paused_str);
1024 /* Find the member, or the place to put a new one. */
1025 for (m = q->members, prev_m = NULL;
1026 m && strcmp(m->interface, interface);
1027 prev_m = m, m = m->next);
1029 /* Create a new one if not found, else update penalty */
1031 if ((m = create_queue_member(interface, membername, penalty, paused))) {
1033 add_to_interfaces(interface);
1041 m->dead = 0; /* Do not delete this one. */
1044 m->penalty = penalty;
1048 static void free_members(struct call_queue *q, int all)
1050 /* Free non-dynamic members */
1051 struct member *curm, *next, *prev = NULL;
1053 for (curm = q->members; curm; curm = next) {
1055 if (all || !curm->dynamic) {
1060 remove_from_interfaces(curm->interface);
1067 static void destroy_queue(struct call_queue *q)
1070 ast_mutex_destroy(&q->lock);
1074 /*!\brief Reload a single queue via realtime.
1075 \return Return the queue, or NULL if it doesn't exist.
1076 \note Should be called with the global qlock locked. */
1077 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1079 struct ast_variable *v;
1080 struct call_queue *q;
1081 struct member *m, *prev_m, *next_m;
1082 char *interface = NULL;
1083 char *tmp, *tmp_name;
1084 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1086 /* Find the queue in the in-core list (we will create a new one if not found). */
1087 AST_LIST_TRAVERSE(&queues, q, list) {
1088 if (!strcasecmp(q->name, queuename))
1092 /* Static queues override realtime. */
1094 ast_mutex_lock(&q->lock);
1097 ast_mutex_unlock(&q->lock);
1100 ast_mutex_unlock(&q->lock);
1104 } else if (!member_config)
1105 /* Not found in the list, and it's not realtime ... */
1108 /* Check if queue is defined in realtime. */
1110 /* Delete queue from in-core list if it has been deleted in realtime. */
1112 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1113 found condition... So we might delete an in-core queue
1114 in case of DB failure. */
1116 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
1119 /* Delete if unused (else will be deleted when last caller leaves). */
1122 AST_LIST_REMOVE(&queues, q, list);
1123 ast_mutex_unlock(&q->lock);
1126 ast_mutex_unlock(&q->lock);
1131 /* Create a new queue if an in-core entry does not exist yet. */
1133 if (!(q = alloc_queue(queuename)))
1135 ast_mutex_lock(&q->lock);
1138 AST_LIST_INSERT_HEAD(&queues, q, list);
1140 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1142 memset(tmpbuf, 0, sizeof(tmpbuf));
1143 for (v = queue_vars; v; v = v->next) {
1144 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1145 if ((tmp = strchr(v->name, '_'))) {
1146 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1149 while ((tmp = strchr(tmp, '_')))
1153 queue_set_param(q, tmp_name, v->value, -1, 0);
1156 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
1157 for (m = q->members; m; m = m->next) {
1162 while ((interface = ast_category_browse(member_config, interface))) {
1163 rt_handle_member_record(q, interface,
1164 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1165 ast_variable_retrieve(member_config, interface, "penalty"),
1166 ast_variable_retrieve(member_config, interface, "paused"));
1169 /* Delete all realtime members that have been deleted in DB. */
1176 prev_m->next = next_m;
1178 q->members = next_m;
1180 remove_from_interfaces(m->interface);
1188 ast_mutex_unlock(&q->lock);
1193 static struct call_queue *load_realtime_queue(const char *queuename)
1195 struct ast_variable *queue_vars;
1196 struct ast_config *member_config = NULL;
1197 struct call_queue *q;
1199 /* Find the queue in the in-core list first. */
1200 AST_LIST_LOCK(&queues);
1201 AST_LIST_TRAVERSE(&queues, q, list) {
1202 if (!strcasecmp(q->name, queuename)) {
1206 AST_LIST_UNLOCK(&queues);
1208 if (!q || q->realtime) {
1209 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1210 queue operations while waiting for the DB.
1212 This will be two separate database transactions, so we might
1213 see queue parameters as they were before another process
1214 changed the queue and member list as it was after the change.
1215 Thus we might see an empty member list when a queue is
1216 deleted. In practise, this is unlikely to cause a problem. */
1218 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1220 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1221 if (!member_config) {
1222 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1227 AST_LIST_LOCK(&queues);
1229 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1231 ast_config_destroy(member_config);
1233 ast_variables_destroy(queue_vars);
1235 AST_LIST_UNLOCK(&queues);
1240 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1242 struct call_queue *q;
1243 struct queue_ent *cur, *prev = NULL;
1247 enum queue_member_status stat;
1249 if (!(q = load_realtime_queue(queuename)))
1252 AST_LIST_LOCK(&queues);
1253 ast_mutex_lock(&q->lock);
1255 /* This is our one */
1256 stat = get_member_status(q, qe->max_penalty);
1257 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1258 *reason = QUEUE_JOINEMPTY;
1259 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS))
1260 *reason = QUEUE_JOINUNAVAIL;
1261 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1262 *reason = QUEUE_JOINUNAVAIL;
1263 else if (q->maxlen && (q->count >= q->maxlen))
1264 *reason = QUEUE_FULL;
1266 /* There's space for us, put us at the right position inside
1268 * Take into account the priority of the calling user */
1273 /* We have higher priority than the current user, enter
1274 * before him, after all the other users with priority
1275 * higher or equal to our priority. */
1276 if ((!inserted) && (qe->prio > cur->prio)) {
1277 insert_entry(q, prev, qe, &pos);
1284 /* No luck, join at the end of the queue */
1286 insert_entry(q, prev, qe, &pos);
1287 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1288 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1289 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1292 manager_event(EVENT_FLAG_CALL, "Join",
1293 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1295 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1296 S_OR(qe->chan->cid.cid_name, "unknown"),
1297 q->name, qe->pos, q->count, qe->chan->uniqueid );
1299 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1301 ast_mutex_unlock(&q->lock);
1302 AST_LIST_UNLOCK(&queues);
1307 static int play_file(struct ast_channel *chan, char *filename)
1311 ast_stopstream(chan);
1312 res = ast_streamfile(chan, filename, chan->language);
1314 res = ast_waitstream(chan, AST_DIGIT_ANY);
1315 ast_stopstream(chan);
1320 static int valid_exit(struct queue_ent *qe, char digit)
1322 int digitlen = strlen(qe->digits);
1324 /* Prevent possible buffer overflow */
1325 if (digitlen < sizeof(qe->digits) - 2) {
1326 qe->digits[digitlen] = digit;
1327 qe->digits[digitlen + 1] = '\0';
1329 qe->digits[0] = '\0';
1333 /* If there's no context to goto, short-circuit */
1334 if (ast_strlen_zero(qe->context))
1337 /* If the extension is bad, then reset the digits to blank */
1338 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1339 qe->digits[0] = '\0';
1343 /* We have an exact match */
1344 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1345 /* Return 1 on a successful goto */
1352 static int say_position(struct queue_ent *qe)
1354 int res = 0, avgholdmins, avgholdsecs;
1357 /* Let minannouncefrequency seconds pass between the start of each position announcement */
1359 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
1362 /* If either our position has changed, or we are over the freq timer, say position */
1363 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1366 ast_moh_stop(qe->chan);
1367 /* Say we're next, if we are */
1369 res = play_file(qe->chan, qe->parent->sound_next);
1370 if (res && valid_exit(qe, res))
1375 res = play_file(qe->chan, qe->parent->sound_thereare);
1376 if (res && valid_exit(qe, res))
1378 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1379 if (res && valid_exit(qe, res))
1381 res = play_file(qe->chan, qe->parent->sound_calls);
1382 if (res && valid_exit(qe, res))
1385 /* Round hold time to nearest minute */
1386 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1388 /* If they have specified a rounding then round the seconds as well */
1389 if (qe->parent->roundingseconds) {
1390 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1391 avgholdsecs *= qe->parent->roundingseconds;
1396 if (option_verbose > 2)
1397 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1399 /* If the hold time is >1 min, if it's enabled, and if it's not
1400 supposed to be only once and we have already said it, say it */
1401 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1402 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1403 res = play_file(qe->chan, qe->parent->sound_holdtime);
1404 if (res && valid_exit(qe, res))
1407 if (avgholdmins > 0) {
1408 if (avgholdmins < 2) {
1409 res = play_file(qe->chan, qe->parent->sound_lessthan);
1410 if (res && valid_exit(qe, res))
1413 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1414 if (res && valid_exit(qe, res))
1417 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1418 if (res && valid_exit(qe, res))
1422 res = play_file(qe->chan, qe->parent->sound_minutes);
1423 if (res && valid_exit(qe, res))
1426 if (avgholdsecs>0) {
1427 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1428 if (res && valid_exit(qe, res))
1431 res = play_file(qe->chan, qe->parent->sound_seconds);
1432 if (res && valid_exit(qe, res))
1439 if (option_verbose > 2)
1440 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1441 qe->chan->name, qe->parent->name, qe->pos);
1442 res = play_file(qe->chan, qe->parent->sound_thanks);
1443 if (res && !valid_exit(qe, res))
1447 /* Set our last_pos indicators */
1449 qe->last_pos_said = qe->pos;
1451 /* Don't restart music on hold if we're about to exit the caller from the queue */
1453 ast_moh_start(qe->chan, qe->moh, NULL);
1458 static void recalc_holdtime(struct queue_ent *qe)
1460 int oldvalue, newvalue;
1462 /* Calculate holdtime using a recursive boxcar filter */
1463 /* Thanks to SRT for this contribution */
1464 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1466 newvalue = time(NULL) - qe->start;
1468 ast_mutex_lock(&qe->parent->lock);
1469 if (newvalue <= qe->parent->servicelevel)
1470 qe->parent->callscompletedinsl++;
1471 oldvalue = qe->parent->holdtime;
1472 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1473 ast_mutex_unlock(&qe->parent->lock);
1477 static void leave_queue(struct queue_ent *qe)
1479 struct call_queue *q;
1480 struct queue_ent *cur, *prev = NULL;
1483 if (!(q = qe->parent))
1485 ast_mutex_lock(&q->lock);
1488 for (cur = q->head; cur; cur = cur->next) {
1492 /* Take us out of the queue */
1493 manager_event(EVENT_FLAG_CALL, "Leave",
1494 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1495 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1497 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1498 /* Take us out of the queue */
1500 prev->next = cur->next;
1502 q->head = cur->next;
1504 /* Renumber the people after us in the queue based on a new count */
1509 ast_mutex_unlock(&q->lock);
1511 if (q->dead && !q->count) {
1512 /* It's dead and nobody is in it, so kill it */
1513 AST_LIST_LOCK(&queues);
1514 AST_LIST_REMOVE(&queues, q, list);
1515 AST_LIST_UNLOCK(&queues);
1520 /* Hang up a list of outgoing calls */
1521 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1523 struct callattempt *oo;
1526 /* Hangup any existing lines we have open */
1527 if (outgoing->chan && (outgoing->chan != exception))
1528 ast_hangup(outgoing->chan);
1530 outgoing = outgoing->q_next;
1535 static int update_status(struct call_queue *q, struct member *member, int status)
1539 /* Since a reload could have taken place, we have to traverse the list to
1540 be sure it's still valid */
1541 ast_mutex_lock(&q->lock);
1542 for (cur = q->members; cur; cur = cur->next) {
1546 cur->status = status;
1547 if (!q->maskmemberstatus) {
1548 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1551 "MemberName: %s\r\n"
1552 "Membership: %s\r\n"
1554 "CallsTaken: %d\r\n"
1558 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
1559 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1562 ast_mutex_unlock(&q->lock);
1566 static int update_dial_status(struct call_queue *q, struct member *member, int status)
1568 if (status == AST_CAUSE_BUSY)
1569 status = AST_DEVICE_BUSY;
1570 else if (status == AST_CAUSE_UNREGISTERED)
1571 status = AST_DEVICE_UNAVAILABLE;
1572 else if (status == AST_CAUSE_NOSUCHDRIVER)
1573 status = AST_DEVICE_INVALID;
1575 status = AST_DEVICE_UNKNOWN;
1576 return update_status(q, member, status);
1579 /* traverse all defined queues which have calls waiting and contain this member
1580 return 0 if no other queue has precedence (higher weight) or 1 if found */
1581 static int compare_weight(struct call_queue *rq, struct member *member)
1583 struct call_queue *q;
1587 /* &qlock and &rq->lock already set by try_calling()
1588 * to solve deadlock */
1589 AST_LIST_TRAVERSE(&queues, q, list) {
1590 if (q == rq) /* don't check myself, could deadlock */
1592 ast_mutex_lock(&q->lock);
1593 if (q->count && q->members) {
1594 for (mem = q->members; mem; mem = mem->next) {
1595 if (strcmp(mem->interface, member->interface))
1599 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1600 if (q->weight > rq->weight) {
1602 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);
1608 ast_mutex_unlock(&q->lock);
1615 /*! \brief common hangup actions */
1616 static void do_hang(struct callattempt *o)
1619 ast_hangup(o->chan);
1623 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1625 struct ast_str *buf = ast_str_alloca(len + 1);
1628 if (pbx_builtin_serialize_variables(chan, &buf)) {
1631 /* convert "\n" to "\nVariable: " */
1632 strcpy(vars, "Variable: ");
1635 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1638 if (tmp[i + 1] == '\0')
1640 if (tmp[i] == '\n') {
1644 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1654 /* there are no channel variables; leave it blank */
1660 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1667 /* on entry here, we know that tmp->chan == NULL */
1668 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1670 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1672 ast_cdr_busy(qe->chan->cdr);
1673 tmp->stillgoing = 0;
1678 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1680 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1682 ast_cdr_busy(qe->chan->cdr);
1683 tmp->stillgoing = 0;
1687 if (tmp->member->paused) {
1689 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1691 ast_cdr_busy(qe->chan->cdr);
1692 tmp->stillgoing = 0;
1695 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1697 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1699 ast_cdr_busy(qe->chan->cdr);
1700 tmp->stillgoing = 0;
1705 ast_copy_string(tech, tmp->interface, sizeof(tech));
1706 if ((location = strchr(tech, '/')))
1711 /* Request the peer */
1712 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1713 if (!tmp->chan) { /* If we can't, just go on to the next call */
1715 ast_cdr_busy(qe->chan->cdr);
1716 tmp->stillgoing = 0;
1717 update_dial_status(qe->parent, tmp->member, status);
1719 ast_mutex_lock(&qe->parent->lock);
1720 qe->parent->rrpos++;
1721 ast_mutex_unlock(&qe->parent->lock);
1725 } else if (status != tmp->oldstatus)
1726 update_dial_status(qe->parent, tmp->member, status);
1728 tmp->chan->appl = "AppQueue";
1729 tmp->chan->data = "(Outgoing Line)";
1730 tmp->chan->whentohangup = 0;
1731 if (tmp->chan->cid.cid_num)
1732 free(tmp->chan->cid.cid_num);
1733 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1734 if (tmp->chan->cid.cid_name)
1735 free(tmp->chan->cid.cid_name);
1736 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1737 if (tmp->chan->cid.cid_ani)
1738 free(tmp->chan->cid.cid_ani);
1739 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1741 /* Inherit specially named variables from parent channel */
1742 ast_channel_inherit_variables(qe->chan, tmp->chan);
1744 /* Presense of ADSI CPE on outgoing channel follows ours */
1745 tmp->chan->adsicpe = qe->chan->adsicpe;
1747 /* Place the call, but don't wait on the answer */
1748 if ((res = ast_call(tmp->chan, location, 0))) {
1749 /* Again, keep going even if there's an error */
1751 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1752 if (option_verbose > 2)
1753 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1757 } else if (qe->parent->eventwhencalled) {
1760 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1761 "AgentCalled: %s\r\n"
1762 "ChannelCalling: %s\r\n"
1763 "CallerIDNum: %s\r\n"
1764 "CallerIDName: %s\r\n"
1769 tmp->interface, qe->chan->name,
1770 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1771 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1772 qe->chan->context, qe->chan->exten, qe->chan->priority,
1773 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1774 if (option_verbose > 2)
1775 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1781 /*! \brief find the entry with the best metric, or NULL */
1782 static struct callattempt *find_best(struct callattempt *outgoing)
1784 struct callattempt *best = NULL, *cur;
1786 for (cur = outgoing; cur; cur = cur->q_next) {
1787 if (cur->stillgoing && /* Not already done */
1788 !cur->chan && /* Isn't already going */
1789 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1797 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1802 struct callattempt *best = find_best(outgoing);
1805 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1808 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1809 struct callattempt *cur;
1810 /* Ring everyone who shares this best metric (for ringall) */
1811 for (cur = outgoing; cur; cur = cur->q_next) {
1812 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1814 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1815 ring_entry(qe, cur, busies);
1819 /* Ring just the best channel */
1821 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1822 ring_entry(qe, best, busies);
1824 if (best->chan) /* break out with result = 1 */
1831 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1833 struct callattempt *best = find_best(outgoing);
1836 /* Ring just the best channel */
1838 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1839 qe->parent->rrpos = best->metric % 1000;
1841 /* Just increment rrpos */
1842 if (qe->parent->wrapped) {
1843 /* No more channels, start over */
1844 qe->parent->rrpos = 0;
1846 /* Prioritize next entry */
1847 qe->parent->rrpos++;
1850 qe->parent->wrapped = 0;
1855 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1859 ast_stopstream(chan);
1860 res = ast_streamfile(chan, filename, chan->language);
1863 /* Wait for a keypress */
1864 res = ast_waitstream(chan, AST_DIGIT_ANY);
1865 if (res < 0 || !valid_exit(qe, res))
1869 ast_stopstream(chan);
1875 static int say_periodic_announcement(struct queue_ent *qe)
1880 /* Get the current time */
1883 /* Check to see if it is time to announce */
1884 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1887 /* Stop the music on hold so we can play our own file */
1888 ast_moh_stop(qe->chan);
1890 if (option_verbose > 2)
1891 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1893 /* Check to make sure we have a sound file. If not, reset to the first sound file */
1894 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
1895 qe->last_periodic_announce_sound = 0;
1898 /* play the announcement */
1899 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
1901 /* Resume Music on Hold if the caller is going to stay in the queue */
1903 ast_moh_start(qe->chan, qe->moh, NULL);
1905 /* update last_periodic_announce_time */
1906 qe->last_periodic_announce_time = now;
1908 /* Update the current periodic announcement to the next announcement */
1909 qe->last_periodic_announce_sound++;
1914 static void record_abandoned(struct queue_ent *qe)
1916 ast_mutex_lock(&qe->parent->lock);
1917 set_queue_variables(qe);
1918 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
1922 "OriginalPosition: %d\r\n"
1924 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
1926 qe->parent->callsabandoned++;
1927 ast_mutex_unlock(&qe->parent->lock);
1930 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
1931 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
1933 if (option_verbose > 2)
1934 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
1935 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
1936 if (qe->parent->autopause) {
1937 if (!set_member_paused(qe->parent->name, interface, 1)) {
1938 if (option_verbose > 2)
1939 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
1941 if (option_verbose > 2)
1942 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
1948 #define AST_MAX_WATCHERS 256
1950 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
1952 char *queue = qe->parent->name;
1953 struct callattempt *o;
1955 int sentringing = 0;
1956 int numbusies = prebusies;
1960 struct ast_frame *f;
1961 struct callattempt *peer = NULL;
1962 struct ast_channel *winner;
1963 struct ast_channel *in = qe->chan;
1965 char membername[80] = "";
1969 starttime = (long) time(NULL);
1971 while (*to && !peer) {
1972 int numlines, retry, pos = 1;
1973 struct ast_channel *watchers[AST_MAX_WATCHERS];
1976 for (retry = 0; retry < 2; retry++) {
1978 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
1979 if (o->stillgoing) { /* Keep track of important channels */
1982 watchers[pos++] = o->chan;
1986 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
1987 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
1989 /* On "ringall" strategy we only move to the next penalty level
1990 when *all* ringing phones are done in the current penalty level */
1991 ring_one(qe, outgoing, &numbusies);
1994 if (pos == 1 /* not found */) {
1995 if (numlines == (numbusies + numnochan)) {
1997 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1999 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2004 winner = ast_waitfor_n(watchers, pos, to);
2005 for (o = outgoing; o; o = o->q_next) {
2006 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2008 if (option_verbose > 2)
2009 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2012 } else if (o->chan && (o->chan == winner)) {
2014 ast_copy_string(on, o->member->interface, sizeof(on));
2015 ast_copy_string(membername, o->member->membername, sizeof(membername));
2017 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2018 if (option_verbose > 2)
2019 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2024 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2029 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2030 if ((stuff = strchr(tmpchan, '/'))) {
2034 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2038 /* Before processing channel, go ahead and check for forwarding */
2039 if (option_verbose > 2)
2040 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2041 /* Setup parameters */
2042 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2043 if (status != o->oldstatus)
2044 update_dial_status(qe->parent, o->member, status);
2046 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2050 ast_channel_inherit_variables(in, o->chan);
2051 if (o->chan->cid.cid_num)
2052 free(o->chan->cid.cid_num);
2053 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2055 if (o->chan->cid.cid_name)
2056 free(o->chan->cid.cid_name);
2057 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2059 ast_string_field_set(o->chan, accountcode, in->accountcode);
2060 o->chan->cdrflags = in->cdrflags;
2062 if (in->cid.cid_ani) {
2063 if (o->chan->cid.cid_ani)
2064 free(o->chan->cid.cid_ani);
2065 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2067 if (o->chan->cid.cid_rdnis)
2068 free(o->chan->cid.cid_rdnis);
2069 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2070 if (ast_call(o->chan, tmpchan, 0)) {
2071 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2076 /* Hangup the original channel now, in case we needed it */
2080 f = ast_read(winner);
2082 if (f->frametype == AST_FRAME_CONTROL) {
2083 switch (f->subclass) {
2084 case AST_CONTROL_ANSWER:
2085 /* This is our guy if someone answered. */
2087 if (option_verbose > 2)
2088 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2092 case AST_CONTROL_BUSY:
2093 if (option_verbose > 2)
2094 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
2096 ast_cdr_busy(in->cdr);
2098 endtime = (long) time(NULL);
2099 endtime -= starttime;
2100 rna(endtime*1000, qe, on, membername);
2101 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2102 if (qe->parent->timeoutrestart)
2104 ring_one(qe, outgoing, &numbusies);
2108 case AST_CONTROL_CONGESTION:
2109 if (option_verbose > 2)
2110 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
2112 ast_cdr_busy(in->cdr);
2113 endtime = (long) time(NULL);
2114 endtime -= starttime;
2115 rna(endtime*1000, qe, on, membername);
2117 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2118 if (qe->parent->timeoutrestart)
2120 ring_one(qe, outgoing, &numbusies);
2124 case AST_CONTROL_RINGING:
2125 if (option_verbose > 2)
2126 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
2129 ast_indicate(in, AST_CONTROL_RINGING);
2134 case AST_CONTROL_OFFHOOK:
2135 /* Ignore going off hook */
2139 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
2144 endtime = (long) time(NULL) - starttime;
2145 rna(endtime * 1000, qe, on, membername);
2147 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2148 if (qe->parent->timeoutrestart)
2150 ring_one(qe, outgoing, &numbusies);
2157 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2164 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2165 if (option_verbose > 3)
2166 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
2171 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2172 if (option_verbose > 3)
2173 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
2175 *digit = f->subclass;
2182 rna(orig, qe, on, membername);
2188 static int is_our_turn(struct queue_ent *qe)
2190 struct queue_ent *ch;
2196 if (!qe->parent->autofill) {
2197 /* Atomically read the parent head -- does not need a lock */
2198 ch = qe->parent->head;
2199 /* If we are now at the top of the head, break out */
2202 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2206 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2211 /* This needs a lock. How many members are available to be served? */
2212 ast_mutex_lock(&qe->parent->lock);
2214 ch = qe->parent->head;
2216 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2218 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);
2221 for (cur = qe->parent->members; cur; cur = cur->next) {
2222 switch (cur->status) {
2223 case AST_DEVICE_NOT_INUSE:
2224 case AST_DEVICE_UNKNOWN:
2232 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
2234 while ((idx < avl) && (ch) && (ch != qe)) {
2239 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2240 if (ch && idx < avl) {
2242 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2246 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2250 ast_mutex_unlock(&qe->parent->lock);
2256 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2260 /* This is the holding pen for callers 2 through maxlen */
2262 enum queue_member_status stat;
2264 if (is_our_turn(qe))
2267 /* If we have timed out, break out */
2268 if (qe->expire && (time(NULL) > qe->expire)) {
2269 *reason = QUEUE_TIMEOUT;
2273 stat = get_member_status(qe->parent, qe->max_penalty);
2275 /* leave the queue if no agents, if enabled */
2276 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2277 *reason = QUEUE_LEAVEEMPTY;
2278 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2283 /* leave the queue if no reachable agents, if enabled */
2284 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2285 *reason = QUEUE_LEAVEUNAVAIL;
2286 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2290 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2291 *reason = QUEUE_LEAVEUNAVAIL;
2292 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2297 /* Make a position announcement, if enabled */
2298 if (qe->parent->announcefrequency && !ringing &&
2299 (res = say_position(qe)))
2302 /* Make a periodic announcement, if enabled */
2303 if (qe->parent->periodicannouncefrequency && !ringing &&
2304 (res = say_periodic_announcement(qe)))
2307 /* Wait a second before checking again */
2308 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000)))
2315 static int update_queue(struct call_queue *q, struct member *member)
2319 /* Since a reload could have taken place, we have to traverse the list to
2320 be sure it's still valid */
2321 ast_mutex_lock(&q->lock);
2324 if (member == cur) {
2325 time(&cur->lastcall);
2331 q->callscompleted++;
2332 ast_mutex_unlock(&q->lock);
2336 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2338 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2341 switch (q->strategy) {
2342 case QUEUE_STRATEGY_RINGALL:
2343 /* Everyone equal, except for penalty */
2344 tmp->metric = mem->penalty * 1000000;
2346 case QUEUE_STRATEGY_RRMEMORY:
2347 if (pos < q->rrpos) {
2348 tmp->metric = 1000 + pos;
2351 /* Indicate there is another priority */
2355 tmp->metric += mem->penalty * 1000000;
2357 case QUEUE_STRATEGY_RANDOM:
2358 tmp->metric = ast_random() % 1000;
2359 tmp->metric += mem->penalty * 1000000;
2361 case QUEUE_STRATEGY_FEWESTCALLS:
2362 tmp->metric = mem->calls;
2363 tmp->metric += mem->penalty * 1000000;
2365 case QUEUE_STRATEGY_LEASTRECENT:
2369 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2370 tmp->metric += mem->penalty * 1000000;
2373 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2379 enum agent_complete_reason {
2385 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
2386 const struct ast_channel *peer, const struct member *member, time_t callstart,
2387 char *vars, size_t vars_len, enum agent_complete_reason rsn)
2391 if (!qe->parent->eventwhencalled)
2402 reason = "transfer";
2406 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2411 "MemberName: %s\r\n"
2416 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2417 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
2418 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
2421 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)
2424 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2426 char oldexten[AST_MAX_EXTENSION]="";
2427 char oldcontext[AST_MAX_CONTEXT]="";
2428 char queuename[256]="";
2429 char interfacevar[256]="";
2430 struct ast_channel *peer;
2431 struct ast_channel *which;
2432 struct callattempt *lpeer;
2433 struct member *member;
2434 struct ast_app *app;
2435 int res = 0, bridge = 0;
2438 char *announce = NULL;
2441 time_t now = time(NULL);
2442 struct ast_bridge_config bridge_config;
2443 char nondataquality = 1;
2444 char *agiexec = NULL;
2445 char *macroexec = NULL;
2447 const char *monitorfilename;
2448 const char *monitor_exec;
2449 const char *monitor_options;
2450 char tmpid[256], tmpid2[256];
2451 char meid[1024], meid2[1024];
2452 char mixmonargs[1512];
2453 struct ast_app *mixmonapp = NULL;
2456 int forwardsallowed = 1;
2457 memset(&bridge_config, 0, sizeof(bridge_config));
2460 for (; options && *options; options++)
2463 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2466 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2469 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2472 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2478 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2481 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2484 if ((now - qe->start >= qe->parent->timeout))
2488 forwardsallowed = 0;
2492 /* Hold the lock while we setup the outgoing calls */
2494 AST_LIST_LOCK(&queues);
2495 ast_mutex_lock(&qe->parent->lock);
2497 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2499 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2500 cur = qe->parent->members;
2501 if (!ast_strlen_zero(qe->announce))
2502 announce = qe->announce;
2503 if (!ast_strlen_zero(announceoverride))
2504 announce = announceoverride;
2506 for (; cur; cur = cur->next) {
2507 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2510 ast_mutex_unlock(&qe->parent->lock);
2512 AST_LIST_UNLOCK(&queues);
2515 tmp->stillgoing = -1;
2516 tmp->member = cur; /* Never directly dereference! Could change on reload */
2517 tmp->oldstatus = cur->status;
2518 tmp->lastcall = cur->lastcall;
2519 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2520 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2521 just calculate their metric for the appropriate strategy */
2522 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2523 /* Put them in the list of outgoing thingies... We're ready now.
2524 XXX If we're forcibly removed, these outgoing calls won't get
2526 tmp->q_next = outgoing;
2528 /* If this line is up, don't try anybody else */
2529 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2535 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2536 to = (qe->expire - now) * 1000;
2538 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2539 ring_one(qe, outgoing, &numbusies);
2540 ast_mutex_unlock(&qe->parent->lock);
2542 AST_LIST_UNLOCK(&queues);
2543 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2544 ast_mutex_lock(&qe->parent->lock);
2545 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2546 store_next(qe, outgoing);
2548 ast_mutex_unlock(&qe->parent->lock);
2549 peer = lpeer ? lpeer->chan : NULL;
2552 /* Must gotten hung up */
2558 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2559 } else { /* peer is valid */
2560 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2561 we will always return with -1 so that it is hung up properly after the
2564 if (!strcmp(qe->chan->tech->type, "Zap"))
2565 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2566 if (!strcmp(peer->tech->type, "Zap"))
2567 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2568 /* Update parameters for the queue */
2569 recalc_holdtime(qe);
2570 member = lpeer->member;
2571 hangupcalls(outgoing, peer);
2573 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2576 res2 = ast_autoservice_start(qe->chan);
2578 if (qe->parent->memberdelay) {
2579 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2580 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2582 if (!res2 && announce) {
2583 if (play_file(peer, announce))
2584 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2586 if (!res2 && qe->parent->reportholdtime) {
2587 if (!play_file(peer, qe->parent->sound_reporthold)) {
2591 holdtime = abs((now - qe->start) / 60);
2593 play_file(peer, qe->parent->sound_lessthan);
2594 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2596 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2597 play_file(peer, qe->parent->sound_minutes);
2601 res2 |= ast_autoservice_stop(qe->chan);
2602 if (peer->_softhangup) {
2603 /* Agent must have hung up */
2604 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
2605 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2606 record_abandoned(qe);
2607 if (qe->parent->eventwhencalled)
2608 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2613 "MemberName: %s\r\n"
2615 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2616 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2620 /* Caller must have hung up just before being connected*/
2621 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2622 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2623 record_abandoned(qe);
2628 /* Stop music on hold */
2629 ast_moh_stop(qe->chan);
2630 /* If appropriate, log that we have a destination channel */
2632 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2633 /* Make sure channels are compatible */
2634 res = ast_channel_make_compatible(qe->chan, peer);
2636 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2637 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2638 record_abandoned(qe);
2642 /* Begin Monitoring */
2643 if (qe->parent->monfmt && *qe->parent->monfmt) {
2644 if (!qe->parent->montype) {
2646 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
2647 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2648 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2652 if (monitorfilename)
2653 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2654 else if (qe->chan->cdr)
2655 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2657 /* Last ditch effort -- no CDR, make up something */
2658 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2659 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2661 if (qe->parent->monjoin)
2662 ast_monitor_setjoinfiles(which, 1);
2665 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
2666 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2667 if (!monitorfilename) {
2669 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
2671 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2673 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
2674 for (p = tmpid2; *p ; p++) {
2675 if (*p == '^' && *(p+1) == '{') {
2680 memset(tmpid, 0, sizeof(tmpid));
2681 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2684 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2685 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2688 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
2689 for (p = meid2; *p ; p++) {
2690 if (*p == '^' && *(p+1) == '{') {
2695 memset(meid, 0, sizeof(meid));
2696 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2699 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
2701 mixmonapp = pbx_findapp("MixMonitor");
2703 if (strchr(tmpid2, '|')) {
2704 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
2708 if (!monitor_options)
2709 monitor_options = "";
2711 if (strchr(monitor_options, '|')) {
2712 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
2717 if (!ast_strlen_zero(monitor_exec))
2718 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
2720 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
2723 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2725 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2728 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2732 /* Drop out of the queue at this point, to prepare for next caller */
2734 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2736 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2737 ast_channel_sendurl(peer, url);
2740 ast_mutex_lock(&qe->parent->lock);
2741 /* if setinterfacevar is defined, make member variables available to the channel */
2742 /* use pbx_builtin_setvar to set a load of variables with one call */
2743 if (qe->parent->setinterfacevar) {
2744 snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d",
2745 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic);
2746 pbx_builtin_setvar(qe->chan, interfacevar);
2749 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
2750 /* use pbx_builtin_setvar to set a load of variables with one call */
2751 if (qe->parent->setqueueentryvar) {
2752 snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
2753 (long) time(NULL) - qe->start, qe->opos);
2754 pbx_builtin_setvar(qe->chan, interfacevar);
2757 /* try to set queue variables if configured to do so*/
2758 set_queue_variables(qe);
2759 ast_mutex_unlock(&qe->parent->lock);
2761 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
2762 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
2763 if (!ast_strlen_zero(macro)) {
2764 macroexec = ast_strdupa(macro);
2766 if (qe->parent->membermacro)
2767 macroexec = ast_strdupa(qe->parent->membermacro);
2770 if (!ast_strlen_zero(macroexec)) {
2772 ast_log(LOG_DEBUG, "app_queue: macro=%s.\n", macroexec);
2774 res = ast_autoservice_start(qe->chan);
2776 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
2780 app = pbx_findapp("Macro");
2783 res = pbx_exec(qe->chan, app, macroexec);
2785 ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
2788 ast_log(LOG_ERROR, "Could not find application Macro\n");
2792 if (ast_autoservice_stop(qe->chan) < 0) {
2793 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
2798 if (!ast_strlen_zero(agi)) {
2800 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
2801 app = pbx_findapp("agi");
2803 agiexec = ast_strdupa(agi);
2804 ret = pbx_exec(qe->chan, app, agiexec);
2806 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
2808 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long) time(NULL) - qe->start, peer->uniqueid);
2809 if (qe->parent->eventwhencalled)
2810 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2815 "MemberName: %s\r\n"
2817 "BridgedChannel: %s\r\n"
2819 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2820 (long) time(NULL) - qe->start, peer->uniqueid,
2821 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2822 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2823 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2826 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2828 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2829 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
2830 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
2831 (long) (time(NULL) - callstart));
2832 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
2833 } else if (qe->chan->_softhangup) {
2834 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
2835 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
2836 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
2838 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
2839 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
2840 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
2843 if (bridge != AST_PBX_NO_HANGUP_PEER)
2845 update_queue(qe->parent, member);
2846 res = bridge ? bridge : 1;
2849 hangupcalls(outgoing, NULL);
2854 static int wait_a_bit(struct queue_ent *qe)
2856 /* Don't need to hold the lock while we setup the outgoing calls */
2857 int retrywait = qe->parent->retry * 1000;
2859 return ast_waitfordigit(qe->chan, retrywait);
2862 static struct member *interface_exists(struct call_queue *q, const char *interface)
2869 for (mem = q->members; mem; mem = mem->next) {
2870 if (!strcasecmp(interface, mem->interface))
2878 /* Dump all members in a specific queue to the database
2880 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2883 static void dump_queue_members(struct call_queue *pm_queue)
2885 struct member *cur_member;
2886 char value[PM_MAX_LEN];
2890 memset(value, 0, sizeof(value));
2895 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2896 if (!cur_member->dynamic)
2899 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%s%s",
2900 cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername,
2901 cur_member->next ? "|" : "");
2902 if (res != strlen(value + value_len)) {
2903 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2909 if (value_len && !cur_member) {