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$")
64 #include <sys/signal.h>
65 #include <netinet/in.h>
67 #include "asterisk/lock.h"
68 #include "asterisk/file.h"
69 #include "asterisk/channel.h"
70 #include "asterisk/pbx.h"
71 #include "asterisk/app.h"
72 #include "asterisk/linkedlists.h"
73 #include "asterisk/module.h"
74 #include "asterisk/translate.h"
75 #include "asterisk/say.h"
76 #include "asterisk/features.h"
77 #include "asterisk/musiconhold.h"
78 #include "asterisk/cli.h"
79 #include "asterisk/manager.h"
80 #include "asterisk/config.h"
81 #include "asterisk/monitor.h"
82 #include "asterisk/utils.h"
83 #include "asterisk/causes.h"
84 #include "asterisk/astdb.h"
85 #include "asterisk/devicestate.h"
86 #include "asterisk/stringfields.h"
87 #include "asterisk/event.h"
88 #include "asterisk/astobj2.h"
89 #include "asterisk/strings.h"
92 QUEUE_STRATEGY_RINGALL = 0,
93 QUEUE_STRATEGY_LEASTRECENT,
94 QUEUE_STRATEGY_FEWESTCALLS,
95 QUEUE_STRATEGY_RANDOM,
96 QUEUE_STRATEGY_RRMEMORY,
97 QUEUE_STRATEGY_LINEAR,
98 QUEUE_STRATEGY_WRANDOM
101 static struct strategy {
105 { QUEUE_STRATEGY_RINGALL, "ringall" },
106 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
107 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
108 { QUEUE_STRATEGY_RANDOM, "random" },
109 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
110 { QUEUE_STRATEGY_LINEAR, "linear" },
111 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
114 #define DEFAULT_RETRY 5
115 #define DEFAULT_TIMEOUT 15
116 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
117 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
118 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /* The minimum number of seconds between position announcements
119 The default value of 15 provides backwards compatibility */
120 #define MAX_QUEUE_BUCKETS 53
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 */
126 #define RES_NOT_DYNAMIC (-4) /* Member is not dynamic */
128 static char *app = "Queue";
130 static char *synopsis = "Queue a call for a call queue";
132 static char *descrip =
133 " Queue(queuename[,options[,URL][,announceoverride][,timeout][,AGI][,macro][,gosub]):\n"
134 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
135 "This application will return to the dialplan if the queue does not exist, or\n"
136 "any of the join options cause the caller to not enter the queue.\n"
137 "The option string may contain zero or more of the following characters:\n"
138 " 'c' -- continue in the dialplan if the callee hangs up.\n"
139 " 'd' -- data-quality (modem) call (minimum delay).\n"
140 " 'h' -- allow callee to hang up by pressing *.\n"
141 " 'H' -- allow caller to hang up by pressing *.\n"
142 " 'n' -- no retries on the timeout; will exit this application and \n"
143 " go to the next step.\n"
144 " 'i' -- ignore call forward requests from queue members and do nothing\n"
145 " when they are requested.\n"
146 " 'r' -- ring instead of playing MOH. Periodic Announcements are still made, if applicable.\n"
147 " 't' -- allow the called user to transfer the calling user.\n"
148 " 'T' -- allow the calling user to transfer the call.\n"
149 " 'w' -- allow the called user to write the conversation to disk via Monitor.\n"
150 " 'W' -- allow the calling user to write the conversation to disk via Monitor.\n"
151 " 'k' -- Allow the called party to enable parking of the call by sending\n"
152 " the DTMF sequence defined for call parking in features.conf.\n"
153 " 'K' -- Allow the calling party to enable parking of the call by sending\n"
154 " the DTMF sequence defined for call parking in features.conf.\n"
155 " In addition to transferring the call, a call may be parked and then picked\n"
156 "up by another user.\n"
157 " The optional URL will be sent to the called party if the channel supports\n"
159 " The optional AGI parameter will setup an AGI script to be executed on the \n"
160 "calling party's channel once they are connected to a queue member.\n"
161 " The optional macro parameter will run a macro on the \n"
162 "calling party's channel once they are connected to a queue member.\n"
163 " The optional gosub parameter will run a gosub on the \n"
164 "calling party's channel once they are connected to a queue member.\n"
165 " The timeout will cause the queue to fail out after a specified number of\n"
166 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
167 " This application sets the following channel variable upon completion:\n"
168 " QUEUESTATUS The status of the call as a text string, one of\n"
169 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL | CONTINUE\n";
171 static char *app_aqm = "AddQueueMember" ;
172 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
173 static char *app_aqm_descrip =
174 " AddQueueMember(queuename[,interface[,penalty[,options[,membername]]]]):\n"
175 "Dynamically adds interface to an existing queue.\n"
176 "If the interface is already in the queue it will return an error.\n"
177 " This application sets the following channel variable upon completion:\n"
178 " AQMSTATUS The status of the attempt to add a queue member as a \n"
179 " text string, one of\n"
180 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
181 "Example: AddQueueMember(techsupport,SIP/3000)\n"
184 static char *app_rqm = "RemoveQueueMember" ;
185 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
186 static char *app_rqm_descrip =
187 " RemoveQueueMember(queuename[,interface[,options]]):\n"
188 "Dynamically removes interface to an existing queue\n"
189 "If the interface is NOT in the queue it will return an error.\n"
190 " This application sets the following channel variable upon completion:\n"
191 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
192 " text string, one of\n"
193 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
194 "Example: RemoveQueueMember(techsupport,SIP/3000)\n"
197 static char *app_pqm = "PauseQueueMember" ;
198 static char *app_pqm_synopsis = "Pauses a queue member" ;
199 static char *app_pqm_descrip =
200 " PauseQueueMember([queuename],interface[,options[,reason]]):\n"
201 "Pauses (blocks calls for) a queue member.\n"
202 "The given interface will be paused in the given queue. This prevents\n"
203 "any calls from being sent from the queue to the interface until it is\n"
204 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
205 "queuename is given, the interface is paused in every queue it is a\n"
206 "member of. The application will fail if the interface is not found.\n"
207 "The reason string is entirely optional and is used to add extra information\n"
208 "to the appropriate queue_log entries and manager events.\n"
209 " This application sets the following channel variable upon completion:\n"
210 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
211 " text string, one of\n"
212 " PAUSED | NOTFOUND\n"
213 "Example: PauseQueueMember(,SIP/3000)\n";
215 static char *app_upqm = "UnpauseQueueMember" ;
216 static char *app_upqm_synopsis = "Unpauses a queue member" ;
217 static char *app_upqm_descrip =
218 " UnpauseQueueMember([queuename],interface[,options[,reason]]):\n"
219 "Unpauses (resumes calls to) a queue member.\n"
220 "This is the counterpart to PauseQueueMember and operates exactly the\n"
221 "same way, except it unpauses instead of pausing the given interface.\n"
222 "The reason string is entirely optional and is used to add extra information\n"
223 "to the appropriate queue_log entries and manager events.\n"
224 " This application sets the following channel variable upon completion:\n"
225 " UPQMSTATUS The status of the attempt to unpause a queue \n"
226 " member as a text string, one of\n"
227 " UNPAUSED | NOTFOUND\n"
228 "Example: UnpauseQueueMember(,SIP/3000)\n";
230 static char *app_ql = "QueueLog" ;
231 static char *app_ql_synopsis = "Writes to the queue_log" ;
232 static char *app_ql_descrip =
233 " QueueLog(queuename,uniqueid,agent,event[,additionalinfo]):\n"
234 "Allows you to write your own events into the queue log\n"
235 "Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)\n";
237 /*! \brief Persistent Members astdb family */
238 static const char *pm_family = "Queue/PersistentMembers";
239 /* The maximum length of each persistent member queue database entry */
240 #define PM_MAX_LEN 8192
242 /*! \brief queues.conf [general] option */
243 static int queue_keep_stats = 0;
245 /*! \brief queues.conf [general] option */
246 static int queue_persistent_members = 0;
248 /*! \brief queues.conf per-queue weight option */
249 static int use_weight = 0;
251 /*! \brief queues.conf [general] option */
252 static int autofill_default = 0;
254 /*! \brief queues.conf [general] option */
255 static int montype_default = 0;
257 /*! \brief queues.conf [general] option */
258 static int shared_lastcall = 0;
260 /*! \brief Subscription to device state change events */
261 static struct ast_event_sub *device_state_sub;
263 /*! \brief queues.conf [general] option */
264 static int update_cdr = 0;
270 QUEUE_LEAVEEMPTY = 3,
271 QUEUE_JOINUNAVAIL = 4,
272 QUEUE_LEAVEUNAVAIL = 5,
278 enum queue_result id;
280 } queue_results[] = {
281 { QUEUE_UNKNOWN, "UNKNOWN" },
282 { QUEUE_TIMEOUT, "TIMEOUT" },
283 { QUEUE_JOINEMPTY,"JOINEMPTY" },
284 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
285 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
286 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
287 { QUEUE_FULL, "FULL" },
288 { QUEUE_CONTINUE, "CONTINUE" },
291 /*! \brief We define a custom "local user" structure because we
292 use it not only for keeping track of what is in use but
293 also for keeping track of who we're dialing. */
296 struct callattempt *q_next;
297 struct ast_channel *chan;
303 struct call_queue *lastqueue;
304 struct member *member;
309 struct call_queue *parent; /*!< What queue is our parent */
310 char moh[80]; /*!< Name of musiconhold to be used */
311 char announce[80]; /*!< Announcement to play for member when call is answered */
312 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
313 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
314 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
315 int pos; /*!< Where we are in the queue */
316 int prio; /*!< Our priority */
317 int last_pos_said; /*!< Last position we told the user */
318 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
319 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
320 time_t last_pos; /*!< Last time we told the user their position */
321 int opos; /*!< Where we started in the queue */
322 int handled; /*!< Whether our call was handled */
323 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
324 int linpos; /*!< If using linear strategy, what position are we at? */
325 int linwrapped; /*!< Is the linpos wrapped? */
326 time_t start; /*!< When we started holding */
327 time_t expire; /*!< When this entry should expire (time out of queue) */
328 struct ast_channel *chan; /*!< Our channel */
329 struct queue_ent *next; /*!< The next queue entry */
333 char interface[80]; /*!< Technology/Location */
334 char membername[80]; /*!< Member name to use in queue logs */
335 int penalty; /*!< Are we a last resort? */
336 int calls; /*!< Number of calls serviced by this member */
337 int dynamic; /*!< Are we dynamically added? */
338 int realtime; /*!< Is this member realtime? */
339 int status; /*!< Status of queue member */
340 int paused; /*!< Are we paused (not accepting calls)? */
341 time_t lastcall; /*!< When last successful call was hungup */
342 struct call_queue *lastqueue; /*!< Last queue we received a call */
343 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
344 unsigned int delme:1; /*!< Flag to delete entry on reload */
347 struct member_interface {
349 AST_LIST_ENTRY(member_interface) list; /*!< Next call queue */
352 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
354 /* values used in multi-bit flags in call_queue */
355 #define QUEUE_EMPTY_NORMAL 1
356 #define QUEUE_EMPTY_STRICT 2
357 #define QUEUE_EMPTY_LOOSE 3
358 #define ANNOUNCEHOLDTIME_ALWAYS 1
359 #define ANNOUNCEHOLDTIME_ONCE 2
360 #define QUEUE_EVENT_VARIABLES 3
363 AST_DECLARE_STRING_FIELDS(
365 AST_STRING_FIELD(name);
366 /*! Music on Hold class */
367 AST_STRING_FIELD(moh);
368 /*! Announcement to play when call is answered */
369 AST_STRING_FIELD(announce);
371 AST_STRING_FIELD(context);
372 /*! Macro to run upon member connection */
373 AST_STRING_FIELD(membermacro);
374 /*! Gosub to run upon member connection */
375 AST_STRING_FIELD(membergosub);
376 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
377 AST_STRING_FIELD(sound_next);
378 /*! Sound file: "There are currently" (def. queue-thereare) */
379 AST_STRING_FIELD(sound_thereare);
380 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
381 AST_STRING_FIELD(sound_calls);
382 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
383 AST_STRING_FIELD(sound_holdtime);
384 /*! Sound file: "minutes." (def. queue-minutes) */
385 AST_STRING_FIELD(sound_minutes);
386 /*! Sound file: "less-than" (def. queue-lessthan) */
387 AST_STRING_FIELD(sound_lessthan);
388 /*! Sound file: "seconds." (def. queue-seconds) */
389 AST_STRING_FIELD(sound_seconds);
390 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
391 AST_STRING_FIELD(sound_thanks);
392 /*! Sound file: Custom announce for caller, no default */
393 AST_STRING_FIELD(sound_callerannounce);
394 /*! Sound file: "Hold time" (def. queue-reporthold) */
395 AST_STRING_FIELD(sound_reporthold);
397 /*! Sound files: Custom announce, no default */
398 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
400 unsigned int joinempty:2;
401 unsigned int eventwhencalled:2;
402 unsigned int leavewhenempty:2;
403 unsigned int ringinuse:1;
404 unsigned int setinterfacevar:1;
405 unsigned int setqueuevar:1;
406 unsigned int setqueueentryvar:1;
407 unsigned int reportholdtime:1;
408 unsigned int wrapped:1;
409 unsigned int timeoutrestart:1;
410 unsigned int announceholdtime:2;
411 unsigned int announceposition:1;
413 unsigned int maskmemberstatus:1;
414 unsigned int realtime:1;
415 unsigned int found:1;
416 int announcefrequency; /*!< How often to announce their position */
417 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
418 int periodicannouncefrequency; /*!< How often to play periodic announcement */
419 int roundingseconds; /*!< How many seconds do we round to? */
420 int holdtime; /*!< Current avg holdtime, based on recursive boxcar filter */
421 int callscompleted; /*!< Number of queue calls completed */
422 int callsabandoned; /*!< Number of queue calls abandoned */
423 int servicelevel; /*!< seconds setting for servicelevel*/
424 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
425 char monfmt[8]; /*!< Format to use when recording calls */
426 int montype; /*!< Monitor type Monitor vs. MixMonitor */
427 int count; /*!< How many entries */
428 int maxlen; /*!< Max number of entries */
429 int wrapuptime; /*!< Wrapup Time */
431 int retry; /*!< Retry calling everyone after this amount of time */
432 int timeout; /*!< How long to wait for an answer */
433 int weight; /*!< Respective weight */
434 int autopause; /*!< Auto pause queue members if they fail to answer */
436 /* Queue strategy things */
437 int rrpos; /*!< Round Robin - position */
438 int memberdelay; /*!< Seconds to delay connecting member to caller */
439 int autofill; /*!< Ignore the head call status and ring an available agent */
441 struct ao2_container *members; /*!< Head of the list of members */
443 * \brief Number of members _logged in_
444 * \note There will be members in the members container that are not logged
445 * in, so this can not simply be replaced with ao2_container_count().
448 struct queue_ent *head; /*!< Head of the list of callers */
449 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
452 static struct ao2_container *queues;
454 static void update_realtime_members(struct call_queue *q);
455 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
457 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
461 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
462 if (queue_results[i].id == res) {
463 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
469 static char *int2strat(int strategy)
473 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
474 if (strategy == strategies[x].strategy)
475 return strategies[x].name;
481 static int strat2int(const char *strategy)
485 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
486 if (!strcasecmp(strategy, strategies[x].name))
487 return strategies[x].strategy;
493 static int queue_hash_cb(const void *obj, const int flags)
495 const struct call_queue *q = obj;
496 return ast_str_hash(q->name);
499 static int queue_cmp_cb(void *obj, void *arg, int flags)
501 struct call_queue *q = obj, *q2 = arg;
502 return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0;
505 static inline struct call_queue *queue_ref(struct call_queue *q)
511 static inline struct call_queue *queue_unref(struct call_queue *q)
517 static void set_queue_variables(struct queue_ent *qe)
520 char interfacevar[256]="";
523 if (qe->parent->setqueuevar) {
525 if (qe->parent->callscompleted > 0)
526 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
528 snprintf(interfacevar,sizeof(interfacevar),
529 "QUEUEMAX=%d|QUEUESTRATEGY=%s|QUEUECALLS=%d|QUEUEHOLDTIME=%d|QUEUECOMPLETED=%d|QUEUEABANDONED=%d|QUEUESRVLEVEL=%d|QUEUESRVLEVELPERF=%2.1f",
530 qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
531 qe->parent->callsabandoned, qe->parent->servicelevel, sl);
533 pbx_builtin_setvar(qe->chan, interfacevar);
537 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
538 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
540 struct queue_ent *cur;
557 enum queue_member_status {
559 QUEUE_NO_REACHABLE_MEMBERS,
560 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
564 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
566 struct member *member;
567 struct ao2_iterator mem_iter;
568 enum queue_member_status result = QUEUE_NO_MEMBERS;
571 mem_iter = ao2_iterator_init(q->members, 0);
572 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
573 if (max_penalty && (member->penalty > max_penalty))
576 switch (member->status) {
577 case AST_DEVICE_INVALID:
580 case AST_DEVICE_UNAVAILABLE:
581 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)
582 result = QUEUE_NO_REACHABLE_MEMBERS;
585 if (member->paused) {
586 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
601 AST_LIST_ENTRY(statechange) entry;
606 static void *handle_statechange(struct statechange *sc)
608 struct call_queue *q;
610 struct ao2_iterator mem_iter;
611 struct member_interface *curint;
612 struct ao2_iterator queue_iter;
616 technology = ast_strdupa(sc->dev);
617 loc = strchr(technology, '/');
624 AST_LIST_LOCK(&interfaces);
625 AST_LIST_TRAVERSE(&interfaces, curint, list) {
628 interface = ast_strdupa(curint->interface);
629 if ((slash_pos = strchr(interface, '/')))
630 if ((slash_pos = strchr(slash_pos + 1, '/')))
633 if (!strcasecmp(interface, sc->dev))
636 AST_LIST_UNLOCK(&interfaces);
639 ast_debug(3, "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));
643 ast_debug(1, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
644 queue_iter = ao2_iterator_init(queues, 0);
645 while ((q = ao2_iterator_next(&queue_iter))) {
647 mem_iter = ao2_iterator_init(q->members, 0);
648 while ((cur = ao2_iterator_next(&mem_iter))) {
651 interface = ast_strdupa(cur->interface);
652 if ((slash_pos = strchr(interface, '/')))
653 if ((slash_pos = strchr(slash_pos + 1, '/')))
656 if (strcasecmp(sc->dev, interface)) {
661 if (cur->status != sc->state) {
662 cur->status = sc->state;
663 if (q->maskmemberstatus) {
668 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
678 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
679 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
691 * \brief Data used by the device state thread
694 /*! Set to 1 to stop the thread */
696 /*! The device state monitoring thread */
698 /*! Lock for the state change queue */
700 /*! Condition for the state change queue */
702 /*! Queue of state changes */
703 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
705 .thread = AST_PTHREADT_NULL,
708 static void *device_state_thread(void *data)
710 struct statechange *sc = NULL;
712 while (!device_state.stop) {
713 ast_mutex_lock(&device_state.lock);
714 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
715 ast_cond_wait(&device_state.cond, &device_state.lock);
716 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
718 ast_mutex_unlock(&device_state.lock);
720 /* Check to see if we were woken up to see the request to stop */
721 if (device_state.stop)
727 handle_statechange(sc);
736 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
742 static int statechange_queue(const char *dev, enum ast_device_state state)
744 struct statechange *sc;
746 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
750 strcpy(sc->dev, dev);
752 ast_mutex_lock(&device_state.lock);
753 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
754 ast_cond_signal(&device_state.cond);
755 ast_mutex_unlock(&device_state.lock);
760 static void device_state_cb(const struct ast_event *event, void *unused)
762 enum ast_device_state state;
765 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
766 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
768 if (ast_strlen_zero(device)) {
769 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
773 statechange_queue(device, state);
776 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
780 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
781 cur->penalty = penalty;
782 cur->paused = paused;
783 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
784 if(!ast_strlen_zero(membername))
785 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
787 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
788 if (!strchr(cur->interface, '/'))
789 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
790 cur->status = ast_device_state(interface);
797 static int compress_char(const char c)
807 static int member_hash_fn(const void *obj, const int flags)
809 const struct member *mem = obj;
810 const char *chname = strchr(mem->interface, '/');
813 chname = mem->interface;
814 for (i = 0; i < 5 && chname[i]; i++)
815 ret += compress_char(chname[i]) << (i * 6);
819 static int member_cmp_fn(void *obj1, void *obj2, int flags)
821 struct member *mem1 = obj1, *mem2 = obj2;
822 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
825 static void init_queue(struct call_queue *q)
830 q->retry = DEFAULT_RETRY;
833 q->announcefrequency = 0;
834 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
835 q->announceholdtime = 0;
836 q->announceholdtime = 1;
837 q->roundingseconds = 0; /* Default - don't announce seconds */
840 q->setinterfacevar = 0;
842 q->setqueueentryvar = 0;
843 q->autofill = autofill_default;
844 q->montype = montype_default;
846 q->periodicannouncefrequency = 0;
848 if(q->strategy == QUEUE_STRATEGY_LINEAR)
849 /* linear strategy depends on order, so we have to place all members in a single bucket */
850 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
852 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
857 ast_string_field_set(q, sound_next, "queue-youarenext");
858 ast_string_field_set(q, sound_thereare, "queue-thereare");
859 ast_string_field_set(q, sound_calls, "queue-callswaiting");
860 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
861 ast_string_field_set(q, sound_minutes, "queue-minutes");
862 ast_string_field_set(q, sound_seconds, "queue-seconds");
863 ast_string_field_set(q, sound_thanks, "queue-thankyou");
864 ast_string_field_set(q, sound_lessthan, "queue-less-than");
865 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
867 if ((q->sound_periodicannounce[0] = ast_str_create(32)))
868 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
870 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
871 if (q->sound_periodicannounce[i])
872 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
876 static void clear_queue(struct call_queue *q)
879 q->callscompleted = 0;
880 q->callsabandoned = 0;
881 q->callscompletedinsl = 0;
885 static int add_to_interfaces(const char *interface)
887 struct member_interface *curint;
889 AST_LIST_LOCK(&interfaces);
890 AST_LIST_TRAVERSE(&interfaces, curint, list) {
891 if (!strcasecmp(curint->interface, interface))
896 AST_LIST_UNLOCK(&interfaces);
900 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
902 if ((curint = ast_calloc(1, sizeof(*curint)))) {
903 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
904 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
906 AST_LIST_UNLOCK(&interfaces);
911 static int interface_exists_global(const char *interface)
913 struct call_queue *q;
914 struct member *mem, tmpmem;
915 struct ao2_iterator queue_iter;
918 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
919 queue_iter = ao2_iterator_init(queues, 0);
920 while ((q = ao2_iterator_next(&queue_iter))) {
923 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
937 static int remove_from_interfaces(const char *interface)
939 struct member_interface *curint;
941 AST_LIST_LOCK(&interfaces);
942 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
943 if (!strcasecmp(curint->interface, interface)) {
944 if (!interface_exists_global(interface)) {
945 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
946 AST_LIST_REMOVE_CURRENT(list);
952 AST_LIST_TRAVERSE_SAFE_END;
953 AST_LIST_UNLOCK(&interfaces);
958 static void clear_and_free_interfaces(void)
960 struct member_interface *curint;
962 AST_LIST_LOCK(&interfaces);
963 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
965 AST_LIST_UNLOCK(&interfaces);
968 /*! \brief Configure a queue parameter.
970 For error reporting, line number is passed for .conf static configuration.
971 For Realtime queues, linenum is -1.
972 The failunknown flag is set for config files (and static realtime) to show
973 errors for unknown parameters. It is cleared for dynamic realtime to allow
974 extra fields in the tables. */
975 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
977 if (!strcasecmp(param, "musicclass") ||
978 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
979 ast_string_field_set(q, moh, val);
980 } else if (!strcasecmp(param, "announce")) {
981 ast_string_field_set(q, announce, val);
982 } else if (!strcasecmp(param, "context")) {
983 ast_string_field_set(q, context, val);
984 } else if (!strcasecmp(param, "timeout")) {
985 q->timeout = atoi(val);
987 q->timeout = DEFAULT_TIMEOUT;
988 } else if (!strcasecmp(param, "ringinuse")) {
989 q->ringinuse = ast_true(val);
990 } else if (!strcasecmp(param, "setinterfacevar")) {
991 q->setinterfacevar = ast_true(val);
992 } else if (!strcasecmp(param, "setqueuevar")) {
993 q->setqueuevar = ast_true(val);
994 } else if (!strcasecmp(param, "setqueueentryvar")) {
995 q->setqueueentryvar = ast_true(val);
996 } else if (!strcasecmp(param, "monitor-format")) {
997 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
998 } else if (!strcasecmp(param, "membermacro")) {
999 ast_string_field_set(q, membermacro, val);
1000 } else if (!strcasecmp(param, "membergosub")) {
1001 ast_string_field_set(q, membergosub, val);
1002 } else if (!strcasecmp(param, "queue-youarenext")) {
1003 ast_string_field_set(q, sound_next, val);
1004 } else if (!strcasecmp(param, "queue-thereare")) {
1005 ast_string_field_set(q, sound_thereare, val);
1006 } else if (!strcasecmp(param, "queue-callswaiting")) {
1007 ast_string_field_set(q, sound_calls, val);
1008 } else if (!strcasecmp(param, "queue-holdtime")) {
1009 ast_string_field_set(q, sound_holdtime, val);
1010 } else if (!strcasecmp(param, "queue-minutes")) {
1011 ast_string_field_set(q, sound_minutes, val);
1012 } else if (!strcasecmp(param, "queue-seconds")) {
1013 ast_string_field_set(q, sound_seconds, val);
1014 } else if (!strcasecmp(param, "queue-lessthan")) {
1015 ast_string_field_set(q, sound_lessthan, val);
1016 } else if (!strcasecmp(param, "queue-thankyou")) {
1017 ast_string_field_set(q, sound_thanks, val);
1018 } else if (!strcasecmp(param, "queue-callerannounce")) {
1019 ast_string_field_set(q, sound_callerannounce, val);
1020 } else if (!strcasecmp(param, "queue-reporthold")) {
1021 ast_string_field_set(q, sound_reporthold, val);
1022 } else if (!strcasecmp(param, "announce-frequency")) {
1023 q->announcefrequency = atoi(val);
1024 } else if (!strcasecmp(param, "min-announce-frequency")) {
1025 q->minannouncefrequency = atoi(val);
1026 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
1027 } else if (!strcasecmp(param, "announce-round-seconds")) {
1028 q->roundingseconds = atoi(val);
1029 /* Rounding to any other values just doesn't make sense... */
1030 if (!(q->roundingseconds == 0 || q->roundingseconds == 1 || q->roundingseconds == 5 || q->roundingseconds == 10
1031 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
1033 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1034 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1035 val, param, q->name, linenum);
1037 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1038 "using 0 instead for queue '%s'\n", val, param, q->name);
1040 q->roundingseconds=0;
1042 } else if (!strcasecmp(param, "announce-holdtime")) {
1043 if (!strcasecmp(val, "once"))
1044 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1045 else if (ast_true(val))
1046 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1048 q->announceholdtime = 0;
1049 } else if (!strcasecmp(param, "announce-position")) {
1050 q->announceposition = ast_true(val);
1051 } else if (!strcasecmp(param, "periodic-announce")) {
1052 if (strchr(val, ',')) {
1053 char *s, *buf = ast_strdupa(val);
1056 while ((s = strsep(&buf, ",|"))) {
1057 if (!q->sound_periodicannounce[i])
1058 q->sound_periodicannounce[i] = ast_str_create(16);
1059 ast_str_set(&q->sound_periodicannounce[i], 0, s);
1061 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1065 ast_str_set(&q->sound_periodicannounce[0], 0, val);
1067 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1068 q->periodicannouncefrequency = atoi(val);
1069 } else if (!strcasecmp(param, "retry")) {
1070 q->retry = atoi(val);
1072 q->retry = DEFAULT_RETRY;
1073 } else if (!strcasecmp(param, "wrapuptime")) {
1074 q->wrapuptime = atoi(val);
1075 } else if (!strcasecmp(param, "autofill")) {
1076 q->autofill = ast_true(val);
1077 } else if (!strcasecmp(param, "monitor-type")) {
1078 if (!strcasecmp(val, "mixmonitor"))
1080 } else if (!strcasecmp(param, "autopause")) {
1081 q->autopause = ast_true(val);
1082 } else if (!strcasecmp(param, "maxlen")) {
1083 q->maxlen = atoi(val);
1086 } else if (!strcasecmp(param, "servicelevel")) {
1087 q->servicelevel= atoi(val);
1088 } else if (!strcasecmp(param, "strategy")) {
1089 /* We already have set this, no need to do it again */
1091 } else if (!strcasecmp(param, "joinempty")) {
1092 if (!strcasecmp(val, "loose"))
1093 q->joinempty = QUEUE_EMPTY_LOOSE;
1094 else if (!strcasecmp(val, "strict"))
1095 q->joinempty = QUEUE_EMPTY_STRICT;
1096 else if (ast_true(val))
1097 q->joinempty = QUEUE_EMPTY_NORMAL;
1100 } else if (!strcasecmp(param, "leavewhenempty")) {
1101 if (!strcasecmp(val, "loose"))
1102 q->leavewhenempty = QUEUE_EMPTY_LOOSE;
1103 else if (!strcasecmp(val, "strict"))
1104 q->leavewhenempty = QUEUE_EMPTY_STRICT;
1105 else if (ast_true(val))
1106 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
1108 q->leavewhenempty = 0;
1109 } else if (!strcasecmp(param, "eventmemberstatus")) {
1110 q->maskmemberstatus = !ast_true(val);
1111 } else if (!strcasecmp(param, "eventwhencalled")) {
1112 if (!strcasecmp(val, "vars")) {
1113 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1115 q->eventwhencalled = ast_true(val) ? 1 : 0;
1117 } else if (!strcasecmp(param, "reportholdtime")) {
1118 q->reportholdtime = ast_true(val);
1119 } else if (!strcasecmp(param, "memberdelay")) {
1120 q->memberdelay = atoi(val);
1121 } else if (!strcasecmp(param, "weight")) {
1122 q->weight = atoi(val);
1125 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1126 we will not see any effect on use_weight until next reload. */
1127 } else if (!strcasecmp(param, "timeoutrestart")) {
1128 q->timeoutrestart = ast_true(val);
1129 } else if (failunknown) {
1131 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1132 q->name, param, linenum);
1134 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1139 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1141 struct member *m, tmpmem;
1146 penalty = atoi(penalty_str);
1152 paused = atoi(paused_str);
1157 /* Find the member, or the place to put a new one. */
1158 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
1159 m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1161 /* Create a new one if not found, else update penalty */
1163 if ((m = create_queue_member(interface, membername, penalty, paused))) {
1166 add_to_interfaces(interface);
1167 ao2_link(q->members, m);
1171 m->dead = 0; /* Do not delete this one. */
1174 m->penalty = penalty;
1179 static void free_members(struct call_queue *q, int all)
1181 /* Free non-dynamic members */
1183 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1185 while ((cur = ao2_iterator_next(&mem_iter))) {
1186 if (all || !cur->dynamic) {
1187 ao2_unlink(q->members, cur);
1188 remove_from_interfaces(cur->interface);
1195 static void destroy_queue(void *obj)
1197 struct call_queue *q = obj;
1200 ast_debug(0, "Queue destructor called for queue '%s'!\n", q->name);
1203 ast_string_field_free_memory(q);
1204 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1205 if (q->sound_periodicannounce[i])
1206 free(q->sound_periodicannounce[i]);
1208 ao2_ref(q->members, -1);
1211 static struct call_queue *alloc_queue(const char *queuename)
1213 struct call_queue *q;
1215 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
1216 if (ast_string_field_init(q, 64)) {
1220 ast_string_field_set(q, name, queuename);
1225 /*!\brief Reload a single queue via realtime.
1226 \return Return the queue, or NULL if it doesn't exist.
1227 \note Should be called with the global qlock locked. */
1228 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1230 struct ast_variable *v;
1231 struct call_queue *q, tmpq = {
1235 struct ao2_iterator mem_iter;
1236 char *interface = NULL;
1237 const char *tmp_name;
1239 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1241 /* Static queues override realtime. */
1242 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
1250 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1256 } else if (!member_config)
1257 /* Not found in the list, and it's not realtime ... */
1260 /* Check if queue is defined in realtime. */
1262 /* Delete queue from in-core list if it has been deleted in realtime. */
1264 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1265 found condition... So we might delete an in-core queue
1266 in case of DB failure. */
1267 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1270 /* Delete if unused (else will be deleted when last caller leaves). */
1271 ao2_unlink(queues, q);
1278 /* Create a new queue if an in-core entry does not exist yet. */
1280 if (!(q = alloc_queue(queuename)))
1285 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1286 ao2_link(queues, q);
1290 memset(tmpbuf, 0, sizeof(tmpbuf));
1291 for (v = queue_vars; v; v = v->next) {
1292 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1293 if ((tmp = strchr(v->name, '_'))) {
1294 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1297 while ((tmp = strchr(tmp, '_')))
1301 queue_set_param(q, tmp_name, v->value, -1, 0);
1304 /* Temporarily set realtime members dead so we can detect deleted ones.
1305 * Also set the membercount correctly for realtime*/
1306 mem_iter = ao2_iterator_init(q->members, 0);
1307 while ((m = ao2_iterator_next(&mem_iter))) {
1314 while ((interface = ast_category_browse(member_config, interface))) {
1315 rt_handle_member_record(q, interface,
1316 ast_variable_retrieve(member_config, interface, "membername"),
1317 ast_variable_retrieve(member_config, interface, "penalty"),
1318 ast_variable_retrieve(member_config, interface, "paused"));
1321 /* Delete all realtime members that have been deleted in DB. */
1322 mem_iter = ao2_iterator_init(q->members, 0);
1323 while ((m = ao2_iterator_next(&mem_iter))) {
1325 ao2_unlink(q->members, m);
1327 remove_from_interfaces(m->interface);
1339 static struct call_queue *load_realtime_queue(const char *queuename)
1341 struct ast_variable *queue_vars;
1342 struct ast_config *member_config = NULL;
1343 struct call_queue *q = NULL, tmpq = {
1347 /* Find the queue in the in-core list first. */
1348 q = ao2_find(queues, &tmpq, OBJ_POINTER);
1350 if (!q || q->realtime) {
1351 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1352 queue operations while waiting for the DB.
1354 This will be two separate database transactions, so we might
1355 see queue parameters as they were before another process
1356 changed the queue and member list as it was after the change.
1357 Thus we might see an empty member list when a queue is
1358 deleted. In practise, this is unlikely to cause a problem. */
1360 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1362 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1363 if (!member_config) {
1364 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1370 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1372 ast_config_destroy(member_config);
1374 ast_variables_destroy(queue_vars);
1378 update_realtime_members(q);
1383 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
1385 struct ast_variable *var;
1388 if(!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL)))
1391 if(!strcmp(var->name, "uniqueid"))
1395 if(var && !ast_strlen_zero(var->value)) {
1396 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
1402 static void update_realtime_members(struct call_queue *q)
1404 struct ast_config *member_config = NULL;
1406 char *interface = NULL;
1407 struct ao2_iterator mem_iter;
1409 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL);
1410 if (!member_config) {
1411 /*This queue doesn't have realtime members*/
1412 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
1418 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1419 mem_iter = ao2_iterator_init(q->members, 0);
1420 while ((m = ao2_iterator_next(&mem_iter))) {
1426 while ((interface = ast_category_browse(member_config, interface))) {
1427 rt_handle_member_record(q, interface,
1428 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1429 ast_variable_retrieve(member_config, interface, "penalty"),
1430 ast_variable_retrieve(member_config, interface, "paused"));
1433 /* Delete all realtime members that have been deleted in DB. */
1434 mem_iter = ao2_iterator_init(q->members, 0);
1435 while ((m = ao2_iterator_next(&mem_iter))) {
1437 ao2_unlink(q->members, m);
1439 remove_from_interfaces(m->interface);
1448 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1450 struct call_queue *q;
1451 struct queue_ent *cur, *prev = NULL;
1455 enum queue_member_status stat;
1457 if (!(q = load_realtime_queue(queuename)))
1463 /* This is our one */
1464 stat = get_member_status(q, qe->max_penalty);
1465 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1466 *reason = QUEUE_JOINEMPTY;
1467 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS))
1468 *reason = QUEUE_JOINUNAVAIL;
1469 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1470 *reason = QUEUE_JOINUNAVAIL;
1471 else if (q->maxlen && (q->count >= q->maxlen))
1472 *reason = QUEUE_FULL;
1474 /* There's space for us, put us at the right position inside
1476 * Take into account the priority of the calling user */
1481 /* We have higher priority than the current user, enter
1482 * before him, after all the other users with priority
1483 * higher or equal to our priority. */
1484 if ((!inserted) && (qe->prio > cur->prio)) {
1485 insert_entry(q, prev, qe, &pos);
1492 /* No luck, join at the end of the queue */
1494 insert_entry(q, prev, qe, &pos);
1495 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1496 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1497 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1500 manager_event(EVENT_FLAG_CALL, "Join",
1501 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1503 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1504 S_OR(qe->chan->cid.cid_name, "unknown"),
1505 q->name, qe->pos, q->count, qe->chan->uniqueid );
1506 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1514 static int play_file(struct ast_channel *chan, const char *filename)
1518 ast_stopstream(chan);
1520 res = ast_streamfile(chan, filename, chan->language);
1522 res = ast_waitstream(chan, AST_DIGIT_ANY);
1524 ast_stopstream(chan);
1529 static int valid_exit(struct queue_ent *qe, char digit)
1531 int digitlen = strlen(qe->digits);
1533 /* Prevent possible buffer overflow */
1534 if (digitlen < sizeof(qe->digits) - 2) {
1535 qe->digits[digitlen] = digit;
1536 qe->digits[digitlen + 1] = '\0';
1538 qe->digits[0] = '\0';
1542 /* If there's no context to goto, short-circuit */
1543 if (ast_strlen_zero(qe->context))
1546 /* If the extension is bad, then reset the digits to blank */
1547 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1548 qe->digits[0] = '\0';
1552 /* We have an exact match */
1553 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1554 qe->valid_digits = 1;
1555 /* Return 1 on a successful goto */
1562 static int say_position(struct queue_ent *qe, int ringing)
1564 int res = 0, avgholdmins, avgholdsecs;
1567 /* Let minannouncefrequency seconds pass between the start of each position announcement */
1569 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
1572 /* If either our position has changed, or we are over the freq timer, say position */
1573 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1577 ast_indicate(qe->chan,-1);
1579 ast_moh_stop(qe->chan);
1581 if (qe->parent->announceposition) {
1582 /* Say we're next, if we are */
1584 res = play_file(qe->chan, qe->parent->sound_next);
1590 res = play_file(qe->chan, qe->parent->sound_thereare);
1593 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1596 res = play_file(qe->chan, qe->parent->sound_calls);
1601 /* Round hold time to nearest minute */
1602 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1604 /* If they have specified a rounding then round the seconds as well */
1605 if (qe->parent->roundingseconds) {
1606 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1607 avgholdsecs *= qe->parent->roundingseconds;
1612 ast_verb(3, "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1614 /* If the hold time is >1 min, if it's enabled, and if it's not
1615 supposed to be only once and we have already said it, say it */
1616 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1617 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1618 res = play_file(qe->chan, qe->parent->sound_holdtime);
1622 if (avgholdmins > 0) {
1623 if (avgholdmins < 2) {
1624 res = play_file(qe->chan, qe->parent->sound_lessthan);
1628 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1632 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1637 res = play_file(qe->chan, qe->parent->sound_minutes);
1641 if (avgholdsecs>0) {
1642 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1646 res = play_file(qe->chan, qe->parent->sound_seconds);
1654 if (qe->parent->announceposition) {
1655 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
1656 qe->chan->name, qe->parent->name, qe->pos);
1658 res = play_file(qe->chan, qe->parent->sound_thanks);
1661 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
1664 /* Set our last_pos indicators */
1666 qe->last_pos_said = qe->pos;
1668 /* Don't restart music on hold if we're about to exit the caller from the queue */
1671 ast_indicate(qe->chan, AST_CONTROL_RINGING);
1673 ast_moh_start(qe->chan, qe->moh, NULL);
1678 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
1682 /* Calculate holdtime using a recursive boxcar filter */
1683 /* Thanks to SRT for this contribution */
1684 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1686 ao2_lock(qe->parent);
1687 oldvalue = qe->parent->holdtime;
1688 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
1689 ao2_unlock(qe->parent);
1693 static void leave_queue(struct queue_ent *qe)
1695 struct call_queue *q;
1696 struct queue_ent *cur, *prev = NULL;
1699 if (!(q = qe->parent))
1705 for (cur = q->head; cur; cur = cur->next) {
1709 /* Take us out of the queue */
1710 manager_event(EVENT_FLAG_CALL, "Leave",
1711 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1712 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1713 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1714 /* Take us out of the queue */
1716 prev->next = cur->next;
1718 q->head = cur->next;
1720 /* Renumber the people after us in the queue based on a new count */
1727 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
1729 if(!ast_load_realtime("queues", "name", q->name, NULL))
1734 /* It's dead and nobody is in it, so kill it */
1735 ao2_unlink(queues, q);
1741 /* Hang up a list of outgoing calls */
1742 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1744 struct callattempt *oo;
1747 /* Hangup any existing lines we have open */
1748 if (outgoing->chan && (outgoing->chan != exception))
1749 ast_hangup(outgoing->chan);
1751 outgoing = outgoing->q_next;
1753 ao2_ref(oo->member, -1);
1758 static int update_status(struct call_queue *q, struct member *member, int status)
1761 struct ao2_iterator mem_iter;
1763 /* Since a reload could have taken place, we have to traverse the list to
1764 be sure it's still valid */
1766 mem_iter = ao2_iterator_init(q->members, 0);
1767 while ((cur = ao2_iterator_next(&mem_iter))) {
1768 if (member != cur) {
1773 cur->status = status;
1774 if (!q->maskmemberstatus) {
1775 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1778 "MemberName: %s\r\n"
1779 "Membership: %s\r\n"
1781 "CallsTaken: %d\r\n"
1785 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime": "static",
1786 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1794 static int update_dial_status(struct call_queue *q, struct member *member, int status)
1796 if (status == AST_CAUSE_BUSY)
1797 status = AST_DEVICE_BUSY;
1798 else if (status == AST_CAUSE_UNREGISTERED)
1799 status = AST_DEVICE_UNAVAILABLE;
1800 else if (status == AST_CAUSE_NOSUCHDRIVER)
1801 status = AST_DEVICE_INVALID;
1803 status = AST_DEVICE_UNKNOWN;
1804 return update_status(q, member, status);
1807 /* traverse all defined queues which have calls waiting and contain this member
1808 return 0 if no other queue has precedence (higher weight) or 1 if found */
1809 static int compare_weight(struct call_queue *rq, struct member *member)
1811 struct call_queue *q;
1814 struct ao2_iterator queue_iter;
1816 /* &qlock and &rq->lock already set by try_calling()
1817 * to solve deadlock */
1818 queue_iter = ao2_iterator_init(queues, 0);
1819 while ((q = ao2_iterator_next(&queue_iter))) {
1820 if (q == rq) { /* don't check myself, could deadlock */
1825 if (q->count && q->members) {
1826 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
1827 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1828 if (q->weight > rq->weight) {
1829 ast_debug(1, "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);
1845 /*! \brief common hangup actions */
1846 static void do_hang(struct callattempt *o)
1849 ast_hangup(o->chan);
1853 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1855 struct ast_str *buf = ast_str_alloca(len + 1);
1858 if (pbx_builtin_serialize_variables(chan, &buf)) {
1861 /* convert "\n" to "\nVariable: " */
1862 strcpy(vars, "Variable: ");
1865 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1868 if (tmp[i + 1] == '\0')
1870 if (tmp[i] == '\n') {
1874 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1884 /* there are no channel variables; leave it blank */
1890 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1897 /* on entry here, we know that tmp->chan == NULL */
1898 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
1899 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
1900 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
1901 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
1903 ast_cdr_busy(qe->chan->cdr);
1904 tmp->stillgoing = 0;
1909 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1910 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
1912 ast_cdr_busy(qe->chan->cdr);
1913 tmp->stillgoing = 0;
1917 if (tmp->member->paused) {
1918 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
1920 ast_cdr_busy(qe->chan->cdr);
1921 tmp->stillgoing = 0;
1924 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1925 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1927 ast_cdr_busy(qe->chan->cdr);
1928 tmp->stillgoing = 0;
1933 ast_copy_string(tech, tmp->interface, sizeof(tech));
1934 if ((location = strchr(tech, '/')))
1939 /* Request the peer */
1940 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1941 if (!tmp->chan) { /* If we can't, just go on to the next call */
1943 ast_cdr_busy(qe->chan->cdr);
1944 tmp->stillgoing = 0;
1945 update_dial_status(qe->parent, tmp->member, status);
1947 ao2_lock(qe->parent);
1948 qe->parent->rrpos++;
1950 ao2_unlock(qe->parent);
1955 } else if (status != tmp->oldstatus)
1956 update_dial_status(qe->parent, tmp->member, status);
1958 tmp->chan->appl = "AppQueue";
1959 tmp->chan->data = "(Outgoing Line)";
1960 tmp->chan->whentohangup = 0;
1961 if (tmp->chan->cid.cid_num)
1962 ast_free(tmp->chan->cid.cid_num);
1963 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1964 if (tmp->chan->cid.cid_name)
1965 ast_free(tmp->chan->cid.cid_name);
1966 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1967 if (tmp->chan->cid.cid_ani)
1968 ast_free(tmp->chan->cid.cid_ani);
1969 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1971 /* Inherit specially named variables from parent channel */
1972 ast_channel_inherit_variables(qe->chan, tmp->chan);
1974 /* Presense of ADSI CPE on outgoing channel follows ours */
1975 tmp->chan->adsicpe = qe->chan->adsicpe;
1977 /* Place the call, but don't wait on the answer */
1978 if ((res = ast_call(tmp->chan, location, 0))) {
1979 /* Again, keep going even if there's an error */
1980 ast_debug(1, "ast call on peer returned %d\n", res);
1981 ast_verb(3, "Couldn't call %s\n", tmp->interface);
1985 } else if (qe->parent->eventwhencalled) {
1988 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1990 "AgentCalled: %s\r\n"
1992 "ChannelCalling: %s\r\n"
1993 "DestinationChannel: %s\r\n"
1994 "CallerIDNum: %s\r\n"
1995 "CallerIDName: %s\r\n"
2000 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
2001 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
2002 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
2003 qe->chan->context, qe->chan->exten, qe->chan->priority,
2004 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2005 ast_verb(3, "Called %s\n", tmp->interface);
2011 /*! \brief find the entry with the best metric, or NULL */
2012 static struct callattempt *find_best(struct callattempt *outgoing)
2014 struct callattempt *best = NULL, *cur;
2016 for (cur = outgoing; cur; cur = cur->q_next) {
2017 if (cur->stillgoing && /* Not already done */
2018 !cur->chan && /* Isn't already going */
2019 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
2027 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
2032 struct callattempt *best = find_best(outgoing);
2034 ast_debug(1, "Nobody left to try ringing in queue\n");
2037 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2038 struct callattempt *cur;
2039 /* Ring everyone who shares this best metric (for ringall) */
2040 for (cur = outgoing; cur; cur = cur->q_next) {
2041 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
2042 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
2043 ring_entry(qe, cur, busies);
2047 /* Ring just the best channel */
2048 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
2049 ring_entry(qe, best, busies);
2051 if (best->chan) /* break out with result = 1 */
2058 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
2060 struct callattempt *best = find_best(outgoing);
2063 /* Ring just the best channel */
2064 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2065 qe->parent->rrpos = best->metric % 1000;
2067 /* Just increment rrpos */
2068 if (qe->parent->wrapped) {
2069 /* No more channels, start over */
2070 qe->parent->rrpos = 0;
2072 /* Prioritize next entry */
2073 qe->parent->rrpos++;
2076 qe->parent->wrapped = 0;
2081 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
2083 struct callattempt *best = find_best(outgoing);
2086 /* Ring just the best channel */
2087 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2088 qe->linpos = best->metric % 1000;
2090 /* Just increment rrpos */
2091 if (qe->linwrapped) {
2092 /* No more channels, start over */
2095 /* Prioritize next entry */
2104 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
2109 /* Get the current time */
2112 /* Check to see if it is time to announce */
2113 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2116 /* Stop the music on hold so we can play our own file */
2118 ast_indicate(qe->chan,-1);
2120 ast_moh_stop(qe->chan);
2122 ast_verb(3, "Playing periodic announcement\n");
2124 /* Check to make sure we have a sound file. If not, reset to the first sound file */
2125 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS ||
2126 !qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound] ||
2127 ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) {
2128 qe->last_periodic_announce_sound = 0;
2131 /* play the announcement */
2132 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str);
2134 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2137 /* Resume Music on Hold if the caller is going to stay in the queue */
2140 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2142 ast_moh_start(qe->chan, qe->moh, NULL);
2145 /* update last_periodic_announce_time */
2146 qe->last_periodic_announce_time = now;
2148 /* Update the current periodic announcement to the next announcement */
2149 qe->last_periodic_announce_sound++;
2154 static void record_abandoned(struct queue_ent *qe)
2156 ao2_lock(qe->parent);
2157 set_queue_variables(qe);
2158 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2162 "OriginalPosition: %d\r\n"
2164 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2166 qe->parent->callsabandoned++;
2167 ao2_unlock(qe->parent);
2170 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2171 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2173 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
2174 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2175 if (qe->parent->autopause) {
2176 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
2177 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2179 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2185 #define AST_MAX_WATCHERS 256
2187 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2189 const char *queue = qe->parent->name;
2190 struct callattempt *o;
2192 int sentringing = 0;
2193 int numbusies = prebusies;
2197 struct ast_frame *f;
2198 struct callattempt *peer = NULL;
2199 struct ast_channel *winner;
2200 struct ast_channel *in = qe->chan;
2202 char membername[80] = "";
2206 struct callattempt *epollo;
2209 starttime = (long) time(NULL);
2211 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2213 ast_poll_channel_add(in, epollo->chan);
2217 while (*to && !peer) {
2218 int numlines, retry, pos = 1;
2219 struct ast_channel *watchers[AST_MAX_WATCHERS];
2222 for (retry = 0; retry < 2; retry++) {
2224 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2225 if (o->stillgoing) { /* Keep track of important channels */
2228 watchers[pos++] = o->chan;
2232 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2233 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2235 /* On "ringall" strategy we only move to the next penalty level
2236 when *all* ringing phones are done in the current penalty level */
2237 ring_one(qe, outgoing, &numbusies);
2240 if (pos == 1 /* not found */) {
2241 if (numlines == (numbusies + numnochan)) {
2242 ast_debug(1, "Everyone is busy at this time\n");
2244 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2249 winner = ast_waitfor_n(watchers, pos, to);
2250 for (o = outgoing; o; o = o->q_next) {
2251 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2253 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2256 } else if (o->chan && (o->chan == winner)) {
2258 ast_copy_string(on, o->member->interface, sizeof(on));
2259 ast_copy_string(membername, o->member->membername, sizeof(membername));
2261 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2262 ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2267 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2272 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2273 if ((stuff = strchr(tmpchan, '/'))) {
2277 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2281 /* Before processing channel, go ahead and check for forwarding */
2282 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2283 /* Setup parameters */
2284 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2285 if (status != o->oldstatus)
2286 update_dial_status(qe->parent, o->member, status);
2288 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2292 ast_channel_inherit_variables(in, o->chan);
2293 if (o->chan->cid.cid_num)
2294 ast_free(o->chan->cid.cid_num);
2295 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2297 if (o->chan->cid.cid_name)
2298 ast_free(o->chan->cid.cid_name);
2299 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2301 ast_string_field_set(o->chan, accountcode, in->accountcode);
2302 o->chan->cdrflags = in->cdrflags;
2304 if (in->cid.cid_ani) {
2305 if (o->chan->cid.cid_ani)
2306 ast_free(o->chan->cid.cid_ani);
2307 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2309 if (o->chan->cid.cid_rdnis)
2310 ast_free(o->chan->cid.cid_rdnis);
2311 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2312 if (ast_call(o->chan, tmpchan, 0)) {
2313 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2318 /* Hangup the original channel now, in case we needed it */
2322 f = ast_read(winner);
2324 if (f->frametype == AST_FRAME_CONTROL) {
2325 switch (f->subclass) {
2326 case AST_CONTROL_ANSWER:
2327 /* This is our guy if someone answered. */
2329 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2333 case AST_CONTROL_BUSY:
2334 ast_verb(3, "%s is busy\n", o->chan->name);
2336 ast_cdr_busy(in->cdr);
2338 endtime = (long) time(NULL);
2339 endtime -= starttime;
2340 rna(endtime*1000, qe, on, membername);
2341 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2342 if (qe->parent->timeoutrestart)
2344 ring_one(qe, outgoing, &numbusies);
2348 case AST_CONTROL_CONGESTION:
2349 ast_verb(3, "%s is circuit-busy\n", o->chan->name);
2351 ast_cdr_busy(in->cdr);
2352 endtime = (long) time(NULL);
2353 endtime -= starttime;
2354 rna(endtime*1000, qe, on, membername);
2356 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2357 if (qe->parent->timeoutrestart)
2359 ring_one(qe, outgoing, &numbusies);
2363 case AST_CONTROL_RINGING:
2364 ast_verb(3, "%s is ringing\n", o->chan->name);
2367 ast_indicate(in, AST_CONTROL_RINGING);
2372 case AST_CONTROL_OFFHOOK:
2373 /* Ignore going off hook */
2376 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
2381 endtime = (long) time(NULL) - starttime;
2382 rna(endtime * 1000, qe, on, membername);
2384 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2385 if (qe->parent->timeoutrestart)
2387 ring_one(qe, outgoing, &numbusies);
2394 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2402 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2403 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
2408 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2409 ast_verb(3, "User pressed digit: %c\n", f->subclass);
2411 *digit = f->subclass;
2418 rna(orig, qe, on, membername);
2422 for(epollo = outgoing; epollo; epollo = epollo->q_next) {
2424 ast_poll_channel_del(in, epollo->chan);
2431 static int is_our_turn(struct queue_ent *qe)
2433 struct queue_ent *ch;
2439 if (!qe->parent->autofill) {
2440 /* Atomically read the parent head -- does not need a lock */
2441 ch = qe->parent->head;
2442 /* If we are now at the top of the head, break out */
2444 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2447 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2452 /* This needs a lock. How many members are available to be served? */
2453 ao2_lock(qe->parent);
2455 ch = qe->parent->head;
2457 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2458 ast_debug(1, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
2461 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2462 while ((cur = ao2_iterator_next(&mem_iter))) {
2463 switch (cur->status) {
2464 case AST_DEVICE_NOT_INUSE:
2465 case AST_DEVICE_UNKNOWN:
2474 ast_debug(1, "There are %d available members.\n", avl);
2476 while ((idx < avl) && (ch) && (ch != qe)) {
2481 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2482 if (ch && idx < avl) {
2483 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2486 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2490 ao2_unlock(qe->parent);
2496 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2500 /* This is the holding pen for callers 2 through maxlen */
2502 enum queue_member_status stat;
2504 if (is_our_turn(qe))
2507 /* If we have timed out, break out */
2508 if (qe->expire && (time(NULL) > qe->expire)) {
2509 *reason = QUEUE_TIMEOUT;
2513 stat = get_member_status(qe->parent, qe->max_penalty);
2515 /* leave the queue if no agents, if enabled */
2516 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2517 *reason = QUEUE_LEAVEEMPTY;
2518 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2523 /* leave the queue if no reachable agents, if enabled */
2524 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2525 *reason = QUEUE_LEAVEUNAVAIL;
2526 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2530 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2531 *reason = QUEUE_LEAVEUNAVAIL;
2532 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2537 /* Make a position announcement, if enabled */
2538 if (qe->parent->announcefrequency &&
2539 (res = say_position(qe,ringing)))
2542 /* Make a periodic announcement, if enabled */
2543 if (qe->parent->periodicannouncefrequency &&
2544 (res = say_periodic_announcement(qe,ringing)))
2547 /* Wait a second before checking again */
2548 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
2549 if (res > 0 && !valid_exit(qe, res))
2559 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
2562 struct call_queue *qtmp;
2563 struct ao2_iterator queue_iter;
2565 if (shared_lastcall) {
2566 queue_iter = ao2_iterator_init(queues, 0);
2567 while ((qtmp = ao2_iterator_next(&queue_iter))) {
2569 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
2570 time(&mem->lastcall);
2580 time(&member->lastcall);
2582 member->lastqueue = q;
2586 q->callscompleted++;
2587 if (callcompletedinsl)
2588 q->callscompletedinsl++;
2593 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2595 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2598 switch (q->strategy) {
2599 case QUEUE_STRATEGY_RINGALL:
2600 /* Everyone equal, except for penalty */
2601 tmp->metric = mem->penalty * 1000000;
2603 case QUEUE_STRATEGY_LINEAR:
2604 if (pos < qe->linpos) {
2605 tmp->metric = 1000 + pos;
2607 if (pos > qe->linpos)
2608 /* Indicate there is another priority */
2612 tmp->metric += mem->penalty * 1000000;
2614 case QUEUE_STRATEGY_RRMEMORY:
2615 if (pos < q->rrpos) {
2616 tmp->metric = 1000 + pos;
2619 /* Indicate there is another priority */
2623 tmp->metric += mem->penalty * 1000000;
2625 case QUEUE_STRATEGY_RANDOM:
2626 tmp->metric = ast_random() % 1000;
2627 tmp->metric += mem->penalty * 1000000;
2629 case QUEUE_STRATEGY_WRANDOM:
2630 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
2632 case QUEUE_STRATEGY_FEWESTCALLS:
2633 tmp->metric = mem->calls;
2634 tmp->metric += mem->penalty * 1000000;
2636 case QUEUE_STRATEGY_LEASTRECENT:
2640 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2641 tmp->metric += mem->penalty * 1000000;
2644 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2650 enum agent_complete_reason {
2656 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
2657 const struct ast_channel *peer, const struct member *member, time_t callstart,
2658 char *vars, size_t vars_len, enum agent_complete_reason rsn)
2660 const char *reason = NULL; /* silence dumb compilers */
2662 if (!qe->parent->eventwhencalled)
2673 reason = "transfer";
2677 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2682 "MemberName: %s\r\n"
2687 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2688 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
2689 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
2692 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
2695 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2697 char oldexten[AST_MAX_EXTENSION]="";
2698 char oldcontext[AST_MAX_CONTEXT]="";
2699 char queuename[256]="";
2700 char interfacevar[256]="";
2701 struct ast_channel *peer;
2702 struct ast_channel *which;
2703 struct callattempt *lpeer;
2704 struct member *member;
2705 struct ast_app *app;
2706 int res = 0, bridge = 0;
2709 char *announce = NULL;
2712 time_t now = time(NULL);
2713 struct ast_bridge_config bridge_config;
2714 char nondataquality = 1;
2715 char *agiexec = NULL;
2716 char *macroexec = NULL;
2717 char *gosubexec = NULL;
2719 const char *monitorfilename;
2720 const char *monitor_exec;
2721 const char *monitor_options;
2722 char tmpid[256], tmpid2[256];
2723 char meid[1024], meid2[1024];
2724 char mixmonargs[1512];
2725 struct ast_app *mixmonapp = NULL;
2728 int forwardsallowed = 1;
2729 int callcompletedinsl;
2730 struct ao2_iterator memi;
2732 memset(&bridge_config, 0, sizeof(bridge_config));
2737 for (; options && *options; options++)
2740 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2743 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2746 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2749 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2755 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2758 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2761 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
2764 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
2767 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR)
2770 *tries = qe->parent->membercount;
2774 forwardsallowed = 0;
2778 /* Hold the lock while we setup the outgoing calls */
2781 ao2_lock(qe->parent);
2782 ast_debug(1, "%s is trying to call a queue member.\n",
2784 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2785 if (!ast_strlen_zero(qe->announce))
2786 announce = qe->announce;
2787 if (!ast_strlen_zero(announceoverride))
2788 announce = announceoverride;
2790 memi = ao2_iterator_init(qe->parent->members, 0);
2791 while ((cur = ao2_iterator_next(&memi))) {
2792 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2796 ao2_unlock(qe->parent);
2801 tmp->stillgoing = -1;
2803 tmp->oldstatus = cur->status;
2804 tmp->lastcall = cur->lastcall;
2805 tmp->lastqueue = cur->lastqueue;
2806 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2807 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2808 just calculate their metric for the appropriate strategy */
2809 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2810 /* Put them in the list of outgoing thingies... We're ready now.
2811 XXX If we're forcibly removed, these outgoing calls won't get
2813 tmp->q_next = outgoing;
2815 /* If this line is up, don't try anybody else */
2816 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2823 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2824 to = (qe->expire - now) * 1000;
2826 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2828 ring_one(qe, outgoing, &numbusies);
2829 ao2_unlock(qe->parent);
2832 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2833 ao2_lock(qe->parent);
2834 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2835 store_next_rr(qe, outgoing);
2837 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
2838 store_next_lin(qe, outgoing);
2840 ao2_unlock(qe->parent);
2841 peer = lpeer ? lpeer->chan : NULL;
2844 /* Must gotten hung up */
2847 /* User exited by pressing a digit */
2851 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
2852 } else { /* peer is valid */
2853 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2854 we will always return with -1 so that it is hung up properly after the
2857 if (!strcmp(qe->chan->tech->type, "Zap"))
2858 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2859 if (!strcmp(peer->tech->type, "Zap"))
2860 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2861 /* Update parameters for the queue */
2863 recalc_holdtime(qe, (now - qe->start));
2864 ao2_lock(qe->parent);
2865 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
2866 ao2_unlock(qe->parent);
2867 member = lpeer->member;
2868 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
2870 hangupcalls(outgoing, peer);
2872 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2875 res2 = ast_autoservice_start(qe->chan);
2877 if (qe->parent->memberdelay) {
2878 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2879 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2881 if (!res2 && announce) {
2882 play_file(peer, announce);
2884 if (!res2 && qe->parent->reportholdtime) {
2885 if (!play_file(peer, qe->parent->sound_reporthold)) {
2889 holdtime = abs((now - qe->start) / 60);
2891 play_file(peer, qe->parent->sound_lessthan);
2892 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2894 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2895 play_file(peer, qe->parent->sound_minutes);
2899 res2 |= ast_autoservice_stop(qe->chan);
2900 if (ast_check_hangup(peer)) {
2901 /* Agent must have hung up */
2902 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
2903 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2904 record_abandoned(qe);
2905 if (qe->parent->eventwhencalled)
2906 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2911 "MemberName: %s\r\n"
2913 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2914 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2916 ao2_ref(member, -1);
2919 /* Caller must have hung up just before being connected*/
2920 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2921 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2922 record_abandoned(qe);
2924 ao2_ref(member, -1);
2928 /* Stop music on hold */
2930 ast_indicate(qe->chan,-1);
2932 ast_moh_stop(qe->chan);
2933 /* If appropriate, log that we have a destination channel */
2935 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2936 /* Make sure channels are compatible */
2937 res = ast_channel_make_compatible(qe->chan, peer);
2939 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2940 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2941 record_abandoned(qe);
2943 ao2_ref(member, -1);
2947 /* Play announcement to the caller telling it's his turn if defined */
2948 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
2949 if (play_file(qe->chan, qe->parent->sound_callerannounce))
2950 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
2953 ao2_lock(qe->parent);
2954 /* if setinterfacevar is defined, make member variables available to the channel */
2955 /* use pbx_builtin_setvar to set a load of variables with one call */
2956 if (qe->parent->setinterfacevar) {
2957 snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d|MEMBERREALTIME=%d",
2958 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
2959 pbx_builtin_setvar(qe->chan, interfacevar);
2962 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
2963 /* use pbx_builtin_setvar to set a load of variables with one call */
2964 if (qe->parent->setqueueentryvar) {
2965 snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
2966 (long) time(NULL) - qe->start, qe->opos);
2967 pbx_builtin_setvar(qe->chan, interfacevar);
2970 /* try to set queue variables if configured to do so*/
2971 set_queue_variables(qe);
2972 ao2_unlock(qe->parent);
2974 /* Begin Monitoring */
2975 if (qe->parent->monfmt && *qe->parent->monfmt) {
2976 if (!qe->parent->montype) {
2977 ast_debug(1, "Starting Monitor as requested.\n");
2978 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2979 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2983 if (monitorfilename)
2984 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
2985 else if (qe->chan->cdr)
2986 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
2988 /* Last ditch effort -- no CDR, make up something */
2989 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2990 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
2993 ast_debug(1, "Starting MixMonitor as requested.\n");
2994 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2995 if (!monitorfilename) {
2997 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
2999 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
3001 const char *m = monitorfilename;
3002 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
3005 if (*(m + 1) == '{')
3017 if (p == tmpid2 + sizeof(tmpid2))
3018 tmpid2[sizeof(tmpid2) - 1] = '\0';
3020 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
3023 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
3024 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
3027 const char *m = monitor_exec;
3028 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
3031 if (*(m + 1) == '{')
3043 if (p == meid2 + sizeof(meid2))
3044 meid2[sizeof(meid2) - 1] = '\0';
3046 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
3049 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
3051 mixmonapp = pbx_findapp("MixMonitor");
3053 if (!monitor_options)
3054 monitor_options = "";
3057 if (!ast_strlen_zero(monitor_exec))
3058 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
3060 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
3062 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
3063 /* We purposely lock the CDR so that pbx_exec does not update the application data */
3065 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
3066 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
3068 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
3071 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
3075 /* Drop out of the queue at this point, to prepare for next caller */
3077 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
3078 ast_debug(1, "app_queue: sendurl=%s.\n", url);
3079 ast_channel_sendurl(peer, url);
3082 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
3083 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
3084 if (!ast_strlen_zero(macro)) {
3085 macroexec = ast_strdupa(macro);
3087 if (qe->parent->membermacro)
3088 macroexec = ast_strdupa(qe->parent->membermacro);
3091 if (!ast_strlen_zero(macroexec)) {
3092 ast_debug(1, "app_queue: macro=%s.\n", macroexec);
3094 res = ast_autoservice_start(qe->chan);
3096 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
3100 app = pbx_findapp("Macro");
3103 res = pbx_exec(qe->chan, app, macroexec);
3104 ast_debug(1, "Macro exited with status %d\n", res);
3107 ast_log(LOG_ERROR, "Could not find application Macro\n");
3111 if (ast_autoservice_stop(qe->chan) < 0) {
3112 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
3117 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
3118 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
3119 if (!ast_strlen_zero(gosub)) {
3120 gosubexec = ast_strdupa(gosub);
3122 if (qe->parent->membergosub)
3123 gosubexec = ast_strdupa(qe->parent->membergosub);
3126 if (!ast_strlen_zero(gosubexec)) {
3128 ast_log(LOG_DEBUG, "app_queue: gosub=%s.\n", gosubexec);
3130 res = ast_autoservice_start(qe->chan);
3132 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
3136 app = pbx_findapp("Gosub");
3139 char *gosub_args, *gosub_argstart;
3141 /* Set where we came from */
3142 ast_copy_string(qe->chan->context, "app_dial_gosub_virtual_context", sizeof(qe->chan->context));
3143 ast_copy_string(qe->chan->exten, "s", sizeof(qe->chan->exten));
3144 qe->chan->priority = 0;
3146 gosub_argstart = strchr(gosubexec, ',');
3147 if (gosub_argstart) {
3148 *gosub_argstart = 0;
3149 asprintf(&gosub_args, "%s,s,1(%s)", gosubexec, gosub_argstart + 1);
3150 *gosub_argstart = '|';
3152 asprintf(&gosub_args, "%s,s,1", gosubexec);
3155 res = pbx_exec(qe->chan, app, gosub_args);
3156 ast_pbx_run(qe->chan);
3159 ast_log(LOG_DEBUG, "Gosub exited with status %d\n", res);
3161 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
3165 ast_log(LOG_ERROR, "Could not find application Gosub\n");
3169 if (ast_autoservice_stop(qe->chan) < 0) {
3170 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
3175 if (!ast_strlen_zero(agi)) {
3176 ast_debug(1, "app_queue: agi=%s.\n", agi);
3177 app = pbx_findapp("agi");
3179 agiexec = ast_strdupa(agi);
3180 ret = pbx_exec(qe->chan, app, agiexec);
3182 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
3184 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
3185 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
3186 if (update_cdr && qe->chan->cdr)
3187 ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel));
3188 if (qe->parent->eventwhencalled)
3189 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
3194 "MemberName: %s\r\n"
3196 "BridgedChannel: %s\r\n"
3199 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3200 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
3201 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3202 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
3203 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
3206 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
3208 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
3209 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
3210 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
3211 (long) (time(NULL) - callstart));
3212 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
3213 } else if (ast_check_hangup(qe->chan)) {
3214 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
3215 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3216 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
3218 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
3219 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3220 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
3223 if (bridge != AST_PBX_NO_HANGUP_PEER)
3225 update_queue(qe->parent, member, callcompletedinsl);
3226 res = bridge ? bridge : 1;
3227 ao2_ref(member, -1);
3230 hangupcalls(outgoing, NULL);
3235 static int wait_a_bit(struct queue_ent *qe)
3237 /* Don't need to hold the lock while we setup the outgoing calls */
3238 int retrywait = qe->parent->retry * 1000;
3240 int res = ast_waitfordigit(qe->chan, retrywait);
3241 if (res > 0 && !valid_exit(qe, res))
3247 static struct member *interface_exists(struct call_queue *q, const char *interface)
3250 struct ao2_iterator mem_iter;
3255 mem_iter = ao2_iterator_init(q->members, 0);
3256 while ((mem = ao2_iterator_next(&mem_iter))) {
3257 if (!strcasecmp(interface, mem->interface))
3266 /* Dump all members in a specific queue to the database
3268 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3271 static void dump_queue_members(struct call_queue *pm_queue)
3273 struct member *cur_member;
3274 char value[PM_MAX_LEN];
3277 struct ao2_iterator mem_iter;
3279 memset(value, 0, sizeof(value));
3284 mem_iter = ao2_iterator_init(pm_queue->members, 0);
3285 while ((cur_member = ao2_iterator_next(&mem_iter))) {
3286 if (!cur_member->dynamic) {
3287 ao2_ref(cur_member, -1);
3291 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
3292 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
3294 ao2_ref(cur_member, -1);
3296 if (res != strlen(value + value_len)) {
3297 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
3303 if (value_len && !cur_member) {
3304 if (ast_db_put(pm_family, pm_queue->name, value))
3305 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
3307 /* Delete the entry if the queue is empty or there is an error */
3308 ast_db_del(pm_family, pm_queue->name);
3311 static int remove_from_queue(const char *queuename, const char *interface)
3313 struct call_queue *q, tmpq = {
3316 struct member *mem, tmpmem;
3317 int res = RES_NOSUCHQUEUE;
3319 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
3320 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
3322 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
3323 /* XXX future changes should beware of this assumption!! */
3327 return RES_NOT_DYNAMIC;
3330 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
3333 "MemberName: %s\r\n",
3334 q->name, mem->interface, mem->membername);
3335 ao2_unlink(q->members, mem);
3338 if (queue_persistent_members)
3339 dump_queue_members(q);