2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief True call queues with optional send URL on answer
23 * \author Mark Spencer <markster@digium.com>
25 * \arg Config in \ref Config_qu queues.conf
27 * \par Development notes
28 * \note 2004-11-25: Persistent Dynamic Members added by:
29 * NetNation Communications (www.netnation.com)
30 * Kevin Lindsay <kevinl@netnation.com>
32 * Each dynamic agent in each queue is now stored in the astdb.
33 * When asterisk is restarted, each agent will be automatically
34 * readded into their recorded queues. This feature can be
35 * configured with the 'persistent_members=<1|0>' setting in the
36 * '[general]' category in queues.conf. The default is on.
38 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
40 * \note These features added by David C. Troy <dave@toad.net>:
41 * - Per-queue holdtime calculation
42 * - Estimated holdtime announcement
43 * - Position announcement
44 * - Abandoned/completed call counters
45 * - Failout timer passed as optional app parameter
46 * - Optional monitoring of calls, started when call is answered
48 * Patch Version 1.07 2003-12-24 01
50 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
53 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54 * by Matthew Enger <m.enger@xi.com.au>
56 * \ingroup applications
61 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
70 #include <sys/signal.h>
71 #include <netinet/in.h>
73 #include "asterisk/lock.h"
74 #include "asterisk/file.h"
75 #include "asterisk/logger.h"
76 #include "asterisk/channel.h"
77 #include "asterisk/pbx.h"
78 #include "asterisk/options.h"
79 #include "asterisk/app.h"
80 #include "asterisk/linkedlists.h"
81 #include "asterisk/module.h"
82 #include "asterisk/translate.h"
83 #include "asterisk/say.h"
84 #include "asterisk/features.h"
85 #include "asterisk/musiconhold.h"
86 #include "asterisk/cli.h"
87 #include "asterisk/manager.h"
88 #include "asterisk/config.h"
89 #include "asterisk/monitor.h"
90 #include "asterisk/utils.h"
91 #include "asterisk/causes.h"
92 #include "asterisk/astdb.h"
93 #include "asterisk/devicestate.h"
94 #include "asterisk/stringfields.h"
95 #include "asterisk/event.h"
96 #include "asterisk/astobj2.h"
99 QUEUE_STRATEGY_RINGALL = 0,
100 QUEUE_STRATEGY_LEASTRECENT,
101 QUEUE_STRATEGY_FEWESTCALLS,
102 QUEUE_STRATEGY_RANDOM,
103 QUEUE_STRATEGY_RRMEMORY
106 static struct strategy {
110 { QUEUE_STRATEGY_RINGALL, "ringall" },
111 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
112 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
113 { QUEUE_STRATEGY_RANDOM, "random" },
114 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
117 #define DEFAULT_RETRY 5
118 #define DEFAULT_TIMEOUT 15
119 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
120 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
121 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /* The minimum number of seconds between position announcements
122 The default value of 15 provides backwards compatibility */
123 #define MAX_QUEUE_BUCKETS 53
125 #define RES_OKAY 0 /* Action completed */
126 #define RES_EXISTS (-1) /* Entry already exists */
127 #define RES_OUTOFMEMORY (-2) /* Out of memory */
128 #define RES_NOSUCHQUEUE (-3) /* No such queue */
130 static char *app = "Queue";
132 static char *synopsis = "Queue a call for a call queue";
134 static char *descrip =
135 " Queue(queuename[,options[,URL][,announceoverride][,timeout][,AGI][,macro][,gosub]):\n"
136 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
137 "This application will return to the dialplan if the queue does not exist, or\n"
138 "any of the join options cause the caller to not enter the queue.\n"
139 "The option string may contain zero or more of the following characters:\n"
140 " 'c' -- continue in the dialplan if the callee hangs up.\n"
141 " 'd' -- data-quality (modem) call (minimum delay).\n"
142 " 'h' -- allow callee to hang up by pressing *.\n"
143 " 'H' -- allow caller to hang up by pressing *.\n"
144 " 'n' -- no retries on the timeout; will exit this application and \n"
145 " go to the next step.\n"
146 " 'i' -- ignore call forward requests from queue members and do nothing\n"
147 " when they are requested.\n"
148 " 'r' -- ring instead of playing MOH. Periodic Announcements are still made, if applicable.\n"
149 " 't' -- allow the called user to transfer the calling user.\n"
150 " 'T' -- allow the calling user to transfer the call.\n"
151 " 'w' -- allow the called user to write the conversation to disk via Monitor.\n"
152 " 'W' -- allow the calling user to write the conversation to disk via Monitor.\n"
153 " 'k' -- Allow the called party to enable parking of the call by sending\n"
154 " the DTMF sequence defined for call parking in features.conf.\n"
155 " 'K' -- Allow the calling party to enable parking of the call by sending\n"
156 " the DTMF sequence defined for call parking in features.conf.\n"
157 " In addition to transferring the call, a call may be parked and then picked\n"
158 "up by another user.\n"
159 " The optional URL will be sent to the called party if the channel supports\n"
161 " The optional AGI parameter will setup an AGI script to be executed on the \n"
162 "calling party's channel once they are connected to a queue member.\n"
163 " The optional macro parameter will run a macro on the \n"
164 "calling party's channel once they are connected to a queue member.\n"
165 " The optional gosub parameter will run a gosub on the \n"
166 "calling party's channel once they are connected to a queue member.\n"
167 " The timeout will cause the queue to fail out after a specified number of\n"
168 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
169 " This application sets the following channel variable upon completion:\n"
170 " QUEUESTATUS The status of the call as a text string, one of\n"
171 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL | CONTINUE\n";
173 static char *app_aqm = "AddQueueMember" ;
174 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
175 static char *app_aqm_descrip =
176 " AddQueueMember(queuename[,interface[,penalty[,options[,membername]]]]):\n"
177 "Dynamically adds interface to an existing queue.\n"
178 "If the interface is already in the queue it will return an error.\n"
179 " This application sets the following channel variable upon completion:\n"
180 " AQMSTATUS The status of the attempt to add a queue member as a \n"
181 " text string, one of\n"
182 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
183 "Example: AddQueueMember(techsupport,SIP/3000)\n"
186 static char *app_rqm = "RemoveQueueMember" ;
187 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
188 static char *app_rqm_descrip =
189 " RemoveQueueMember(queuename[,interface[,options]]):\n"
190 "Dynamically removes interface to an existing queue\n"
191 "If the interface is NOT in the queue it will return an error.\n"
192 " This application sets the following channel variable upon completion:\n"
193 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
194 " text string, one of\n"
195 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
196 "Example: RemoveQueueMember(techsupport,SIP/3000)\n"
199 static char *app_pqm = "PauseQueueMember" ;
200 static char *app_pqm_synopsis = "Pauses a queue member" ;
201 static char *app_pqm_descrip =
202 " PauseQueueMember([queuename],interface[,options[,reason]]):\n"
203 "Pauses (blocks calls for) a queue member.\n"
204 "The given interface will be paused in the given queue. This prevents\n"
205 "any calls from being sent from the queue to the interface until it is\n"
206 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
207 "queuename is given, the interface is paused in every queue it is a\n"
208 "member of. The application will fail if the interface is not found.\n"
209 "The reason string is entirely optional and is used to add extra information\n"
210 "to the appropriate queue_log entries and manager events.\n"
211 " This application sets the following channel variable upon completion:\n"
212 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
213 " text string, one of\n"
214 " PAUSED | NOTFOUND\n"
215 "Example: PauseQueueMember(,SIP/3000)\n";
217 static char *app_upqm = "UnpauseQueueMember" ;
218 static char *app_upqm_synopsis = "Unpauses a queue member" ;
219 static char *app_upqm_descrip =
220 " UnpauseQueueMember([queuename],interface[,options[,reason]]):\n"
221 "Unpauses (resumes calls to) a queue member.\n"
222 "This is the counterpart to PauseQueueMember and operates exactly the\n"
223 "same way, except it unpauses instead of pausing the given interface.\n"
224 "The reason string is entirely optional and is used to add extra information\n"
225 "to the appropriate queue_log entries and manager events.\n"
226 " This application sets the following channel variable upon completion:\n"
227 " UPQMSTATUS The status of the attempt to unpause a queue \n"
228 " member as a text string, one of\n"
229 " UNPAUSED | NOTFOUND\n"
230 "Example: UnpauseQueueMember(,SIP/3000)\n";
232 static char *app_ql = "QueueLog" ;
233 static char *app_ql_synopsis = "Writes to the queue_log" ;
234 static char *app_ql_descrip =
235 " QueueLog(queuename,uniqueid,agent,event[,additionalinfo]):\n"
236 "Allows you to write your own events into the queue log\n"
237 "Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)\n";
239 /*! \brief Persistent Members astdb family */
240 static const char *pm_family = "Queue/PersistentMembers";
241 /* The maximum length of each persistent member queue database entry */
242 #define PM_MAX_LEN 8192
244 /*! \brief queues.conf [general] option */
245 static int queue_keep_stats = 0;
247 /*! \brief queues.conf [general] option */
248 static int queue_persistent_members = 0;
250 /*! \brief queues.conf per-queue weight option */
251 static int use_weight = 0;
253 /*! \brief queues.conf [general] option */
254 static int autofill_default = 0;
256 /*! \brief queues.conf [general] option */
257 static int montype_default = 0;
259 /*! \brief Subscription to device state change events */
260 static struct ast_event_sub *device_state_sub;
262 /*! \brief queues.conf [general] option */
263 static int update_cdr = 0;
269 QUEUE_LEAVEEMPTY = 3,
270 QUEUE_JOINUNAVAIL = 4,
271 QUEUE_LEAVEUNAVAIL = 5,
277 enum queue_result id;
279 } queue_results[] = {
280 { QUEUE_UNKNOWN, "UNKNOWN" },
281 { QUEUE_TIMEOUT, "TIMEOUT" },
282 { QUEUE_JOINEMPTY,"JOINEMPTY" },
283 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
284 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
285 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
286 { QUEUE_FULL, "FULL" },
287 { QUEUE_CONTINUE, "CONTINUE" },
290 /*! \brief We define a custom "local user" structure because we
291 use it not only for keeping track of what is in use but
292 also for keeping track of who we're dialing. */
295 struct callattempt *q_next;
296 struct ast_channel *chan;
302 struct member *member;
307 struct call_queue *parent; /*!< What queue is our parent */
308 char moh[80]; /*!< Name of musiconhold to be used */
309 char announce[80]; /*!< Announcement to play for member when call is answered */
310 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
311 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
312 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
313 int pos; /*!< Where we are in the queue */
314 int prio; /*!< Our priority */
315 int last_pos_said; /*!< Last position we told the user */
316 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
317 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
318 time_t last_pos; /*!< Last time we told the user their position */
319 int opos; /*!< Where we started in the queue */
320 int handled; /*!< Whether our call was handled */
321 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
322 time_t start; /*!< When we started holding */
323 time_t expire; /*!< When this entry should expire (time out of queue) */
324 struct ast_channel *chan; /*!< Our channel */
325 struct queue_ent *next; /*!< The next queue entry */
329 char interface[80]; /*!< Technology/Location */
330 char membername[80]; /*!< Member name to use in queue logs */
331 int penalty; /*!< Are we a last resort? */
332 int calls; /*!< Number of calls serviced by this member */
333 int dynamic; /*!< Are we dynamically added? */
334 int realtime; /*!< Is this member realtime? */
335 int status; /*!< Status of queue member */
336 int paused; /*!< Are we paused (not accepting calls)? */
337 time_t lastcall; /*!< When last successful call was hungup */
338 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
339 unsigned int delme:1; /*!< Flag to delete entry on reload */
342 struct member_interface {
344 AST_LIST_ENTRY(member_interface) list; /*!< Next call queue */
347 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
349 /* values used in multi-bit flags in call_queue */
350 #define QUEUE_EMPTY_NORMAL 1
351 #define QUEUE_EMPTY_STRICT 2
352 #define QUEUE_EMPTY_LOOSE 3
353 #define ANNOUNCEHOLDTIME_ALWAYS 1
354 #define ANNOUNCEHOLDTIME_ONCE 2
355 #define QUEUE_EVENT_VARIABLES 3
358 char name[80]; /*!< Name */
359 char moh[80]; /*!< Music On Hold class to be used */
360 char announce[80]; /*!< Announcement to play when call is answered */
361 char context[AST_MAX_CONTEXT]; /*!< Exit context */
362 unsigned int monjoin:1;
364 unsigned int joinempty:2;
365 unsigned int eventwhencalled:2;
366 unsigned int leavewhenempty:2;
367 unsigned int ringinuse:1;
368 unsigned int setinterfacevar:1;
369 unsigned int setqueuevar:1;
370 unsigned int setqueueentryvar:1;
371 unsigned int reportholdtime:1;
372 unsigned int wrapped:1;
373 unsigned int timeoutrestart:1;
374 unsigned int announceholdtime:2;
375 unsigned int announceposition:1;
376 unsigned int strategy:3;
377 unsigned int maskmemberstatus:1;
378 unsigned int realtime:1;
379 unsigned int found:1;
380 int announcefrequency; /*!< How often to announce their position */
381 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
382 int periodicannouncefrequency; /*!< How often to play periodic announcement */
383 int roundingseconds; /*!< How many seconds do we round to? */
384 int holdtime; /*!< Current avg holdtime, based on recursive boxcar filter */
385 int callscompleted; /*!< Number of queue calls completed */
386 int callsabandoned; /*!< Number of queue calls abandoned */
387 int servicelevel; /*!< seconds setting for servicelevel*/
388 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
389 char monfmt[8]; /*!< Format to use when recording calls */
390 int montype; /*!< Monitor type Monitor vs. MixMonitor */
391 char membermacro[32]; /*!< Macro to run upon member connection */
392 char membergosub[32]; /*!< Gosub to run upon member connection */
393 char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
394 char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
395 char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
396 char sound_holdtime[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
397 char sound_minutes[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
398 char sound_lessthan[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
399 char sound_seconds[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
400 char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
401 char sound_callerannounce[80]; /*!< Sound file: Custom announce for caller, no default */
402 char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
403 char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/*!< Sound files: Custom announce, no default */
405 int count; /*!< How many entries */
406 int maxlen; /*!< Max number of entries */
407 int wrapuptime; /*!< Wrapup Time */
409 int retry; /*!< Retry calling everyone after this amount of time */
410 int timeout; /*!< How long to wait for an answer */
411 int weight; /*!< Respective weight */
412 int autopause; /*!< Auto pause queue members if they fail to answer */
414 /* Queue strategy things */
415 int rrpos; /*!< Round Robin - position */
416 int memberdelay; /*!< Seconds to delay connecting member to caller */
417 int autofill; /*!< Ignore the head call status and ring an available agent */
419 struct ao2_container *members; /*!< Head of the list of members */
421 * \brief Number of members _logged in_
422 * \note There will be members in the members container that are not logged
423 * in, so this can not simply be replaced with ao2_container_count().
426 struct queue_ent *head; /*!< Head of the list of callers */
427 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
430 static struct ao2_container *queues;
432 static void update_realtime_members(struct call_queue *q);
433 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
435 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
439 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
440 if (queue_results[i].id == res) {
441 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
447 static char *int2strat(int strategy)
451 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
452 if (strategy == strategies[x].strategy)
453 return strategies[x].name;
459 static int strat2int(const char *strategy)
463 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
464 if (!strcasecmp(strategy, strategies[x].name))
465 return strategies[x].strategy;
471 static int queue_hash_cb(const void *obj, const int flags)
473 const struct call_queue *q = obj;
474 return ast_str_hash(q->name);
477 static int queue_cmp_cb(void *obj, void *arg, int flags)
479 struct call_queue *q = obj, *q2 = arg;
480 return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0;
483 static inline struct call_queue *queue_ref(struct call_queue *q)
489 static inline struct call_queue *queue_unref(struct call_queue *q)
495 static void set_queue_variables(struct queue_ent *qe)
498 char interfacevar[256]="";
501 if (qe->parent->setqueuevar) {
503 if (qe->parent->callscompleted > 0)
504 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
506 snprintf(interfacevar,sizeof(interfacevar),
507 "QUEUEMAX=%d|QUEUESTRATEGY=%s|QUEUECALLS=%d|QUEUEHOLDTIME=%d|QUEUECOMPLETED=%d|QUEUEABANDONED=%d|QUEUESRVLEVEL=%d|QUEUESRVLEVELPERF=%2.1f",
508 qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
509 qe->parent->callsabandoned, qe->parent->servicelevel, sl);
511 pbx_builtin_setvar(qe->chan, interfacevar);
515 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
516 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
518 struct queue_ent *cur;
535 enum queue_member_status {
537 QUEUE_NO_REACHABLE_MEMBERS,
538 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
542 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
544 struct member *member;
545 struct ao2_iterator mem_iter;
546 enum queue_member_status result = QUEUE_NO_MEMBERS;
549 mem_iter = ao2_iterator_init(q->members, 0);
550 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
551 if (max_penalty && (member->penalty > max_penalty))
554 switch (member->status) {
555 case AST_DEVICE_INVALID:
558 case AST_DEVICE_UNAVAILABLE:
559 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)
560 result = QUEUE_NO_REACHABLE_MEMBERS;
563 if (member->paused) {
564 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
579 AST_LIST_ENTRY(statechange) entry;
584 static void *handle_statechange(struct statechange *sc)
586 struct call_queue *q;
588 struct ao2_iterator mem_iter;
589 struct member_interface *curint;
590 struct ao2_iterator queue_iter;
594 technology = ast_strdupa(sc->dev);
595 loc = strchr(technology, '/');
602 AST_LIST_LOCK(&interfaces);
603 AST_LIST_TRAVERSE(&interfaces, curint, list) {
606 interface = ast_strdupa(curint->interface);
607 if ((slash_pos = strchr(interface, '/')))
608 if ((slash_pos = strchr(slash_pos + 1, '/')))
611 if (!strcasecmp(interface, sc->dev))
614 AST_LIST_UNLOCK(&interfaces);
617 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));
621 ast_debug(1, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
622 queue_iter = ao2_iterator_init(queues, 0);
623 while ((q = ao2_iterator_next(&queue_iter))) {
625 mem_iter = ao2_iterator_init(q->members, 0);
626 while ((cur = ao2_iterator_next(&mem_iter))) {
629 interface = ast_strdupa(cur->interface);
630 if ((slash_pos = strchr(interface, '/')))
631 if ((slash_pos = strchr(slash_pos + 1, '/')))
634 if (strcasecmp(sc->dev, interface)) {
639 if (cur->status != sc->state) {
640 cur->status = sc->state;
641 if (q->maskmemberstatus) {
646 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
656 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
657 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
669 * \brief Data used by the device state thread
672 /*! Set to 1 to stop the thread */
674 /*! The device state monitoring thread */
676 /*! Lock for the state change queue */
678 /*! Condition for the state change queue */
680 /*! Queue of state changes */
681 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
683 .thread = AST_PTHREADT_NULL,
686 static void *device_state_thread(void *data)
688 struct statechange *sc = NULL;
690 while (!device_state.stop) {
691 ast_mutex_lock(&device_state.lock);
692 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
693 ast_cond_wait(&device_state.cond, &device_state.lock);
694 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
696 ast_mutex_unlock(&device_state.lock);
698 /* Check to see if we were woken up to see the request to stop */
699 if (device_state.stop)
705 handle_statechange(sc);
714 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
720 static int statechange_queue(const char *dev, enum ast_device_state state)
722 struct statechange *sc;
724 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
728 strcpy(sc->dev, dev);
730 ast_mutex_lock(&device_state.lock);
731 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
732 ast_cond_signal(&device_state.cond);
733 ast_mutex_unlock(&device_state.lock);
738 static void device_state_cb(const struct ast_event *event, void *unused)
740 enum ast_device_state state;
743 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
744 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
746 if (ast_strlen_zero(device)) {
747 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
751 statechange_queue(device, state);
754 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
758 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
759 cur->penalty = penalty;
760 cur->paused = paused;
761 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
762 if(!ast_strlen_zero(membername))
763 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
765 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
766 if (!strchr(cur->interface, '/'))
767 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
768 cur->status = ast_device_state(interface);
775 static int compress_char(const char c)
785 static int member_hash_fn(const void *obj, const int flags)
787 const struct member *mem = obj;
788 const char *chname = strchr(mem->interface, '/');
791 chname = mem->interface;
792 for (i = 0; i < 5 && chname[i]; i++)
793 ret += compress_char(chname[i]) << (i * 6);
797 static int member_cmp_fn(void *obj1, void *obj2, int flags)
799 struct member *mem1 = obj1, *mem2 = obj2;
800 return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
803 static void init_queue(struct call_queue *q)
808 q->retry = DEFAULT_RETRY;
811 q->announcefrequency = 0;
812 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
813 q->announceholdtime = 0;
814 q->announceholdtime = 1;
815 q->roundingseconds = 0; /* Default - don't announce seconds */
818 q->setinterfacevar = 0;
820 q->setqueueentryvar = 0;
821 q->autofill = autofill_default;
822 q->montype = montype_default;
823 q->membermacro[0] = '\0';
824 q->membergosub[0] = '\0';
826 q->announce[0] = '\0';
827 q->context[0] = '\0';
829 q->periodicannouncefrequency = 0;
830 q->sound_callerannounce[0] = '\0'; /* Default, don't announce the caller that he has been answered */
832 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
835 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
836 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
837 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
838 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
839 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
840 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
841 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
842 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
843 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
844 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
845 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
846 q->sound_periodicannounce[i][0]='\0';
850 static void clear_queue(struct call_queue *q)
853 q->callscompleted = 0;
854 q->callsabandoned = 0;
855 q->callscompletedinsl = 0;
859 static int add_to_interfaces(const char *interface)
861 struct member_interface *curint;
863 AST_LIST_LOCK(&interfaces);
864 AST_LIST_TRAVERSE(&interfaces, curint, list) {
865 if (!strcasecmp(curint->interface, interface))
870 AST_LIST_UNLOCK(&interfaces);
874 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
876 if ((curint = ast_calloc(1, sizeof(*curint)))) {
877 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
878 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
880 AST_LIST_UNLOCK(&interfaces);
885 static int interface_exists_global(const char *interface)
887 struct call_queue *q;
888 struct member *mem, tmpmem;
889 struct ao2_iterator queue_iter;
892 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
893 queue_iter = ao2_iterator_init(queues, 0);
894 while ((q = ao2_iterator_next(&queue_iter))) {
897 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
911 static int remove_from_interfaces(const char *interface)
913 struct member_interface *curint;
915 AST_LIST_LOCK(&interfaces);
916 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
917 if (!strcasecmp(curint->interface, interface)) {
918 if (!interface_exists_global(interface)) {
919 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
920 AST_LIST_REMOVE_CURRENT(&interfaces, list);
926 AST_LIST_TRAVERSE_SAFE_END;
927 AST_LIST_UNLOCK(&interfaces);
932 static void clear_and_free_interfaces(void)
934 struct member_interface *curint;
936 AST_LIST_LOCK(&interfaces);
937 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
939 AST_LIST_UNLOCK(&interfaces);
942 /*! \brief Configure a queue parameter.
944 For error reporting, line number is passed for .conf static configuration.
945 For Realtime queues, linenum is -1.
946 The failunknown flag is set for config files (and static realtime) to show
947 errors for unknown parameters. It is cleared for dynamic realtime to allow
948 extra fields in the tables. */
949 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
951 if (!strcasecmp(param, "musicclass") ||
952 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
953 ast_copy_string(q->moh, val, sizeof(q->moh));
954 } else if (!strcasecmp(param, "announce")) {
955 ast_copy_string(q->announce, val, sizeof(q->announce));
956 } else if (!strcasecmp(param, "context")) {
957 ast_copy_string(q->context, val, sizeof(q->context));
958 } else if (!strcasecmp(param, "timeout")) {
959 q->timeout = atoi(val);
961 q->timeout = DEFAULT_TIMEOUT;
962 } else if (!strcasecmp(param, "ringinuse")) {
963 q->ringinuse = ast_true(val);
964 } else if (!strcasecmp(param, "setinterfacevar")) {
965 q->setinterfacevar = ast_true(val);
966 } else if (!strcasecmp(param, "setqueuevar")) {
967 q->setqueuevar = ast_true(val);
968 } else if (!strcasecmp(param, "setqueueentryvar")) {
969 q->setqueueentryvar = ast_true(val);
970 } else if (!strcasecmp(param, "monitor-join")) {
971 q->monjoin = ast_true(val);
972 } else if (!strcasecmp(param, "monitor-format")) {
973 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
974 } else if (!strcasecmp(param, "membermacro")) {
975 ast_copy_string(q->membermacro, val, sizeof(q->membermacro));
976 } else if (!strcasecmp(param, "membergosub")) {
977 ast_copy_string(q->membergosub, val, sizeof(q->membergosub));
978 } else if (!strcasecmp(param, "queue-youarenext")) {
979 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
980 } else if (!strcasecmp(param, "queue-thereare")) {
981 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
982 } else if (!strcasecmp(param, "queue-callswaiting")) {
983 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
984 } else if (!strcasecmp(param, "queue-holdtime")) {
985 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
986 } else if (!strcasecmp(param, "queue-minutes")) {
987 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
988 } else if (!strcasecmp(param, "queue-seconds")) {
989 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
990 } else if (!strcasecmp(param, "queue-lessthan")) {
991 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
992 } else if (!strcasecmp(param, "queue-thankyou")) {
993 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
994 } else if (!strcasecmp(param, "queue-callerannounce")) {
995 ast_copy_string(q->sound_callerannounce, val, sizeof(q->sound_callerannounce));
996 } else if (!strcasecmp(param, "queue-reporthold")) {
997 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
998 } else if (!strcasecmp(param, "announce-frequency")) {
999 q->announcefrequency = atoi(val);
1000 } else if (!strcasecmp(param, "min-announce-frequency")) {
1001 q->minannouncefrequency = atoi(val);
1002 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
1003 } else if (!strcasecmp(param, "announce-round-seconds")) {
1004 q->roundingseconds = atoi(val);
1005 /* Rounding to any other values just doesn't make sense... */
1006 if (!(q->roundingseconds == 0 || q->roundingseconds == 1 || q->roundingseconds == 5 || q->roundingseconds == 10
1007 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
1009 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1010 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1011 val, param, q->name, linenum);
1013 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1014 "using 0 instead for queue '%s'\n", val, param, q->name);
1016 q->roundingseconds=0;
1018 } else if (!strcasecmp(param, "announce-holdtime")) {
1019 if (!strcasecmp(val, "once"))
1020 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1021 else if (ast_true(val))
1022 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1024 q->announceholdtime = 0;
1025 } else if (!strcasecmp(param, "announce-position")) {
1026 q->announceposition = ast_true(val);
1027 } else if (!strcasecmp(param, "periodic-announce")) {
1028 if (strchr(val, ',')) {
1029 char *s, *buf = ast_strdupa(val);
1032 while ((s = strsep(&buf, ",|"))) {
1033 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
1035 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1039 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
1041 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1042 q->periodicannouncefrequency = atoi(val);
1043 } else if (!strcasecmp(param, "retry")) {
1044 q->retry = atoi(val);
1046 q->retry = DEFAULT_RETRY;
1047 } else if (!strcasecmp(param, "wrapuptime")) {
1048 q->wrapuptime = atoi(val);
1049 } else if (!strcasecmp(param, "autofill")) {
1050 q->autofill = ast_true(val);
1051 } else if (!strcasecmp(param, "monitor-type")) {
1052 if (!strcasecmp(val, "mixmonitor"))
1054 } else if (!strcasecmp(param, "autopause")) {
1055 q->autopause = ast_true(val);
1056 } else if (!strcasecmp(param, "maxlen")) {
1057 q->maxlen = atoi(val);
1060 } else if (!strcasecmp(param, "servicelevel")) {
1061 q->servicelevel= atoi(val);
1062 } else if (!strcasecmp(param, "strategy")) {
1063 q->strategy = strat2int(val);
1064 if (q->strategy < 0) {
1065 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1067 q->strategy = QUEUE_STRATEGY_RINGALL;
1069 } else if (!strcasecmp(param, "joinempty")) {
1070 if (!strcasecmp(val, "loose"))
1071 q->joinempty = QUEUE_EMPTY_LOOSE;
1072 else if (!strcasecmp(val, "strict"))
1073 q->joinempty = QUEUE_EMPTY_STRICT;
1074 else if (ast_true(val))
1075 q->joinempty = QUEUE_EMPTY_NORMAL;
1078 } else if (!strcasecmp(param, "leavewhenempty")) {
1079 if (!strcasecmp(val, "loose"))
1080 q->leavewhenempty = QUEUE_EMPTY_LOOSE;
1081 else if (!strcasecmp(val, "strict"))
1082 q->leavewhenempty = QUEUE_EMPTY_STRICT;
1083 else if (ast_true(val))
1084 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
1086 q->leavewhenempty = 0;
1087 } else if (!strcasecmp(param, "eventmemberstatus")) {
1088 q->maskmemberstatus = !ast_true(val);
1089 } else if (!strcasecmp(param, "eventwhencalled")) {
1090 if (!strcasecmp(val, "vars")) {
1091 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1093 q->eventwhencalled = ast_true(val);
1095 } else if (!strcasecmp(param, "reportholdtime")) {
1096 q->reportholdtime = ast_true(val);
1097 } else if (!strcasecmp(param, "memberdelay")) {
1098 q->memberdelay = atoi(val);
1099 } else if (!strcasecmp(param, "weight")) {
1100 q->weight = atoi(val);
1103 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1104 we will not see any effect on use_weight until next reload. */
1105 } else if (!strcasecmp(param, "timeoutrestart")) {
1106 q->timeoutrestart = ast_true(val);
1107 } else if (failunknown) {
1109 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1110 q->name, param, linenum);
1112 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1117 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1119 struct member *m, tmpmem;
1124 penalty = atoi(penalty_str);
1130 paused = atoi(paused_str);
1135 /* Find the member, or the place to put a new one. */
1136 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
1137 m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1139 /* Create a new one if not found, else update penalty */
1141 if ((m = create_queue_member(interface, membername, penalty, paused))) {
1144 add_to_interfaces(interface);
1145 ao2_link(q->members, m);
1149 m->dead = 0; /* Do not delete this one. */
1152 m->penalty = penalty;
1157 static void free_members(struct call_queue *q, int all)
1159 /* Free non-dynamic members */
1161 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1163 while ((cur = ao2_iterator_next(&mem_iter))) {
1164 if (all || !cur->dynamic) {
1165 ao2_unlink(q->members, cur);
1166 remove_from_interfaces(cur->interface);
1173 static void destroy_queue(void *obj)
1175 struct call_queue *q = obj;
1176 ast_debug(0, "Queue destructor called for queue '%s'!\n", q->name);
1178 ao2_ref(q->members, -1);
1181 static struct call_queue *alloc_queue(const char *queuename)
1183 struct call_queue *q;
1185 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
1186 ast_copy_string(q->name, queuename, sizeof(q->name));
1191 /*!\brief Reload a single queue via realtime.
1192 \return Return the queue, or NULL if it doesn't exist.
1193 \note Should be called with the global qlock locked. */
1194 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1196 struct ast_variable *v;
1197 struct call_queue *q, tmpq;
1199 struct ao2_iterator mem_iter;
1200 char *interface = NULL;
1201 char *tmp, *tmp_name;
1202 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1204 /* Find the queue in the in-core list (we will create a new one if not found). */
1205 ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
1207 /* Static queues override realtime. */
1208 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
1216 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1222 } else if (!member_config)
1223 /* Not found in the list, and it's not realtime ... */
1226 /* Check if queue is defined in realtime. */
1228 /* Delete queue from in-core list if it has been deleted in realtime. */
1230 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1231 found condition... So we might delete an in-core queue
1232 in case of DB failure. */
1233 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1236 /* Delete if unused (else will be deleted when last caller leaves). */
1237 ao2_unlink(queues, q);
1244 /* Create a new queue if an in-core entry does not exist yet. */
1246 if (!(q = alloc_queue(queuename)))
1251 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1252 ao2_link(queues, q);
1256 memset(tmpbuf, 0, sizeof(tmpbuf));
1257 for (v = queue_vars; v; v = v->next) {
1258 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1259 if ((tmp = strchr(v->name, '_'))) {
1260 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1263 while ((tmp = strchr(tmp, '_')))
1267 queue_set_param(q, tmp_name, v->value, -1, 0);
1270 /* Temporarily set realtime members dead so we can detect deleted ones.
1271 * Also set the membercount correctly for realtime*/
1272 mem_iter = ao2_iterator_init(q->members, 0);
1273 while ((m = ao2_iterator_next(&mem_iter))) {
1280 while ((interface = ast_category_browse(member_config, interface))) {
1281 rt_handle_member_record(q, interface,
1282 ast_variable_retrieve(member_config, interface, "membername"),
1283 ast_variable_retrieve(member_config, interface, "penalty"),
1284 ast_variable_retrieve(member_config, interface, "paused"));
1287 /* Delete all realtime members that have been deleted in DB. */
1288 mem_iter = ao2_iterator_init(q->members, 0);
1289 while ((m = ao2_iterator_next(&mem_iter))) {
1291 ao2_unlink(q->members, m);
1293 remove_from_interfaces(m->interface);
1305 static struct call_queue *load_realtime_queue(const char *queuename)
1307 struct ast_variable *queue_vars;
1308 struct ast_config *member_config = NULL;
1309 struct call_queue *q = NULL, tmpq;
1311 /* Find the queue in the in-core list first. */
1312 ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
1313 q = ao2_find(queues, &tmpq, OBJ_POINTER);
1315 if (!q || q->realtime) {
1316 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1317 queue operations while waiting for the DB.
1319 This will be two separate database transactions, so we might
1320 see queue parameters as they were before another process
1321 changed the queue and member list as it was after the change.
1322 Thus we might see an empty member list when a queue is
1323 deleted. In practise, this is unlikely to cause a problem. */
1325 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1327 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1328 if (!member_config) {
1329 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1335 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1337 ast_config_destroy(member_config);
1339 ast_variables_destroy(queue_vars);
1343 update_realtime_members(q);
1348 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
1350 struct ast_variable *var;
1353 if(!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL)))
1356 if(!strcmp(var->name, "uniqueid"))
1360 if(var && !ast_strlen_zero(var->value)) {
1361 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
1367 static void update_realtime_members(struct call_queue *q)
1369 struct ast_config *member_config = NULL;
1371 char *interface = NULL;
1372 struct ao2_iterator mem_iter;
1374 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL);
1375 if (!member_config) {
1376 /*This queue doesn't have realtime members*/
1377 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
1383 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1384 mem_iter = ao2_iterator_init(q->members, 0);
1385 while ((m = ao2_iterator_next(&mem_iter))) {
1391 while ((interface = ast_category_browse(member_config, interface))) {
1392 rt_handle_member_record(q, interface,
1393 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1394 ast_variable_retrieve(member_config, interface, "penalty"),
1395 ast_variable_retrieve(member_config, interface, "paused"));
1398 /* Delete all realtime members that have been deleted in DB. */
1399 mem_iter = ao2_iterator_init(q->members, 0);
1400 while ((m = ao2_iterator_next(&mem_iter))) {
1402 ao2_unlink(q->members, m);
1404 remove_from_interfaces(m->interface);
1413 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1415 struct call_queue *q;
1416 struct queue_ent *cur, *prev = NULL;
1420 enum queue_member_status stat;
1422 if (!(q = load_realtime_queue(queuename)))
1428 /* This is our one */
1429 stat = get_member_status(q, qe->max_penalty);
1430 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1431 *reason = QUEUE_JOINEMPTY;
1432 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS))
1433 *reason = QUEUE_JOINUNAVAIL;
1434 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1435 *reason = QUEUE_JOINUNAVAIL;
1436 else if (q->maxlen && (q->count >= q->maxlen))
1437 *reason = QUEUE_FULL;
1439 /* There's space for us, put us at the right position inside
1441 * Take into account the priority of the calling user */
1446 /* We have higher priority than the current user, enter
1447 * before him, after all the other users with priority
1448 * higher or equal to our priority. */
1449 if ((!inserted) && (qe->prio > cur->prio)) {
1450 insert_entry(q, prev, qe, &pos);
1457 /* No luck, join at the end of the queue */
1459 insert_entry(q, prev, qe, &pos);
1460 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1461 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1462 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1465 manager_event(EVENT_FLAG_CALL, "Join",
1466 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1468 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1469 S_OR(qe->chan->cid.cid_name, "unknown"),
1470 q->name, qe->pos, q->count, qe->chan->uniqueid );
1471 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1479 static int play_file(struct ast_channel *chan, char *filename)
1483 ast_stopstream(chan);
1485 res = ast_streamfile(chan, filename, chan->language);
1487 res = ast_waitstream(chan, AST_DIGIT_ANY);
1489 ast_stopstream(chan);
1494 static int valid_exit(struct queue_ent *qe, char digit)
1496 int digitlen = strlen(qe->digits);
1498 /* Prevent possible buffer overflow */
1499 if (digitlen < sizeof(qe->digits) - 2) {
1500 qe->digits[digitlen] = digit;
1501 qe->digits[digitlen + 1] = '\0';
1503 qe->digits[0] = '\0';
1507 /* If there's no context to goto, short-circuit */
1508 if (ast_strlen_zero(qe->context))
1511 /* If the extension is bad, then reset the digits to blank */
1512 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1513 qe->digits[0] = '\0';
1517 /* We have an exact match */
1518 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1519 qe->valid_digits = 1;
1520 /* Return 1 on a successful goto */
1527 static int say_position(struct queue_ent *qe, int ringing)
1529 int res = 0, avgholdmins, avgholdsecs;
1532 /* Let minannouncefrequency seconds pass between the start of each position announcement */
1534 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
1537 /* If either our position has changed, or we are over the freq timer, say position */
1538 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1542 ast_indicate(qe->chan,-1);
1544 ast_moh_stop(qe->chan);
1546 if (qe->parent->announceposition) {
1547 /* Say we're next, if we are */
1549 res = play_file(qe->chan, qe->parent->sound_next);
1555 res = play_file(qe->chan, qe->parent->sound_thereare);
1558 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1561 res = play_file(qe->chan, qe->parent->sound_calls);
1566 /* Round hold time to nearest minute */
1567 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1569 /* If they have specified a rounding then round the seconds as well */
1570 if (qe->parent->roundingseconds) {
1571 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1572 avgholdsecs *= qe->parent->roundingseconds;
1577 ast_verb(3, "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1579 /* If the hold time is >1 min, if it's enabled, and if it's not
1580 supposed to be only once and we have already said it, say it */
1581 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1582 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1583 res = play_file(qe->chan, qe->parent->sound_holdtime);
1587 if (avgholdmins > 0) {
1588 if (avgholdmins < 2) {
1589 res = play_file(qe->chan, qe->parent->sound_lessthan);
1593 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1597 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1602 res = play_file(qe->chan, qe->parent->sound_minutes);
1606 if (avgholdsecs>0) {
1607 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1611 res = play_file(qe->chan, qe->parent->sound_seconds);
1619 if (qe->parent->announceposition) {
1620 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
1621 qe->chan->name, qe->parent->name, qe->pos);
1623 res = play_file(qe->chan, qe->parent->sound_thanks);
1626 if (res > 0 && !valid_exit(qe, res))
1629 /* Set our last_pos indicators */
1631 qe->last_pos_said = qe->pos;
1633 /* Don't restart music on hold if we're about to exit the caller from the queue */
1636 ast_indicate(qe->chan, AST_CONTROL_RINGING);
1638 ast_moh_start(qe->chan, qe->moh, NULL);
1643 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
1647 /* Calculate holdtime using a recursive boxcar filter */
1648 /* Thanks to SRT for this contribution */
1649 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1651 ao2_lock(qe->parent);
1652 oldvalue = qe->parent->holdtime;
1653 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
1654 ao2_unlock(qe->parent);
1658 static void leave_queue(struct queue_ent *qe)
1660 struct call_queue *q;
1661 struct queue_ent *cur, *prev = NULL;
1664 if (!(q = qe->parent))
1670 for (cur = q->head; cur; cur = cur->next) {
1674 /* Take us out of the queue */
1675 manager_event(EVENT_FLAG_CALL, "Leave",
1676 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1677 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1678 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1679 /* Take us out of the queue */
1681 prev->next = cur->next;
1683 q->head = cur->next;
1685 /* Renumber the people after us in the queue based on a new count */
1692 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
1694 if(!ast_load_realtime("queues", "name", q->name, NULL))
1699 /* It's dead and nobody is in it, so kill it */
1700 ao2_unlink(queues, q);
1706 /* Hang up a list of outgoing calls */
1707 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1709 struct callattempt *oo;
1712 /* Hangup any existing lines we have open */
1713 if (outgoing->chan && (outgoing->chan != exception))
1714 ast_hangup(outgoing->chan);
1716 outgoing = outgoing->q_next;
1718 ao2_ref(oo->member, -1);
1723 static int update_status(struct call_queue *q, struct member *member, int status)
1726 struct ao2_iterator mem_iter;
1728 /* Since a reload could have taken place, we have to traverse the list to
1729 be sure it's still valid */
1731 mem_iter = ao2_iterator_init(q->members, 0);
1732 while ((cur = ao2_iterator_next(&mem_iter))) {
1733 if (member != cur) {
1738 cur->status = status;
1739 if (!q->maskmemberstatus) {
1740 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1743 "MemberName: %s\r\n"
1744 "Membership: %s\r\n"
1746 "CallsTaken: %d\r\n"
1750 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime": "static",
1751 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1759 static int update_dial_status(struct call_queue *q, struct member *member, int status)
1761 if (status == AST_CAUSE_BUSY)
1762 status = AST_DEVICE_BUSY;
1763 else if (status == AST_CAUSE_UNREGISTERED)
1764 status = AST_DEVICE_UNAVAILABLE;
1765 else if (status == AST_CAUSE_NOSUCHDRIVER)
1766 status = AST_DEVICE_INVALID;
1768 status = AST_DEVICE_UNKNOWN;
1769 return update_status(q, member, status);
1772 /* traverse all defined queues which have calls waiting and contain this member
1773 return 0 if no other queue has precedence (higher weight) or 1 if found */
1774 static int compare_weight(struct call_queue *rq, struct member *member)
1776 struct call_queue *q;
1779 struct ao2_iterator queue_iter;
1781 /* &qlock and &rq->lock already set by try_calling()
1782 * to solve deadlock */
1783 queue_iter = ao2_iterator_init(queues, 0);
1784 while ((q = ao2_iterator_next(&queue_iter))) {
1785 if (q == rq) { /* don't check myself, could deadlock */
1790 if (q->count && q->members) {
1791 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
1792 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1793 if (q->weight > rq->weight) {
1794 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);
1810 /*! \brief common hangup actions */
1811 static void do_hang(struct callattempt *o)
1814 ast_hangup(o->chan);
1818 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1820 struct ast_str *buf = ast_str_alloca(len + 1);
1823 if (pbx_builtin_serialize_variables(chan, &buf)) {
1826 /* convert "\n" to "\nVariable: " */
1827 strcpy(vars, "Variable: ");
1830 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1833 if (tmp[i + 1] == '\0')
1835 if (tmp[i] == '\n') {
1839 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1849 /* there are no channel variables; leave it blank */
1855 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1862 /* on entry here, we know that tmp->chan == NULL */
1863 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1864 ast_debug(1, "Wrapuptime not yet expired for %s\n", tmp->interface);
1866 ast_cdr_busy(qe->chan->cdr);
1867 tmp->stillgoing = 0;
1872 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1873 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
1875 ast_cdr_busy(qe->chan->cdr);
1876 tmp->stillgoing = 0;
1880 if (tmp->member->paused) {
1881 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
1883 ast_cdr_busy(qe->chan->cdr);
1884 tmp->stillgoing = 0;
1887 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1888 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1890 ast_cdr_busy(qe->chan->cdr);
1891 tmp->stillgoing = 0;
1896 ast_copy_string(tech, tmp->interface, sizeof(tech));
1897 if ((location = strchr(tech, '/')))
1902 /* Request the peer */
1903 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1904 if (!tmp->chan) { /* If we can't, just go on to the next call */
1906 ast_cdr_busy(qe->chan->cdr);
1907 tmp->stillgoing = 0;
1908 update_dial_status(qe->parent, tmp->member, status);
1910 ao2_lock(qe->parent);
1911 qe->parent->rrpos++;
1912 ao2_unlock(qe->parent);
1916 } else if (status != tmp->oldstatus)
1917 update_dial_status(qe->parent, tmp->member, status);
1919 tmp->chan->appl = "AppQueue";
1920 tmp->chan->data = "(Outgoing Line)";
1921 tmp->chan->whentohangup = 0;
1922 if (tmp->chan->cid.cid_num)
1923 ast_free(tmp->chan->cid.cid_num);
1924 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1925 if (tmp->chan->cid.cid_name)
1926 ast_free(tmp->chan->cid.cid_name);
1927 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1928 if (tmp->chan->cid.cid_ani)
1929 ast_free(tmp->chan->cid.cid_ani);
1930 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1932 /* Inherit specially named variables from parent channel */
1933 ast_channel_inherit_variables(qe->chan, tmp->chan);
1935 /* Presense of ADSI CPE on outgoing channel follows ours */
1936 tmp->chan->adsicpe = qe->chan->adsicpe;
1938 /* Place the call, but don't wait on the answer */
1939 if ((res = ast_call(tmp->chan, location, 0))) {
1940 /* Again, keep going even if there's an error */
1941 ast_debug(1, "ast call on peer returned %d\n", res);
1942 ast_verb(3, "Couldn't call %s\n", tmp->interface);
1946 } else if (qe->parent->eventwhencalled) {
1949 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1951 "AgentCalled: %s\r\n"
1953 "ChannelCalling: %s\r\n"
1954 "DestinationChannel: %s\r\n"
1955 "CallerIDNum: %s\r\n"
1956 "CallerIDName: %s\r\n"
1961 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
1962 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1963 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1964 qe->chan->context, qe->chan->exten, qe->chan->priority,
1965 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1966 ast_verb(3, "Called %s\n", tmp->interface);
1972 /*! \brief find the entry with the best metric, or NULL */
1973 static struct callattempt *find_best(struct callattempt *outgoing)
1975 struct callattempt *best = NULL, *cur;
1977 for (cur = outgoing; cur; cur = cur->q_next) {
1978 if (cur->stillgoing && /* Not already done */
1979 !cur->chan && /* Isn't already going */
1980 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1988 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1993 struct callattempt *best = find_best(outgoing);
1995 ast_debug(1, "Nobody left to try ringing in queue\n");
1998 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1999 struct callattempt *cur;
2000 /* Ring everyone who shares this best metric (for ringall) */
2001 for (cur = outgoing; cur; cur = cur->q_next) {
2002 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
2003 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
2004 ring_entry(qe, cur, busies);
2008 /* Ring just the best channel */
2009 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
2010 ring_entry(qe, best, busies);
2012 if (best->chan) /* break out with result = 1 */
2019 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
2021 struct callattempt *best = find_best(outgoing);
2024 /* Ring just the best channel */
2025 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2026 qe->parent->rrpos = best->metric % 1000;
2028 /* Just increment rrpos */
2029 if (qe->parent->wrapped) {
2030 /* No more channels, start over */
2031 qe->parent->rrpos = 0;
2033 /* Prioritize next entry */
2034 qe->parent->rrpos++;
2037 qe->parent->wrapped = 0;
2042 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
2047 /* Get the current time */
2050 /* Check to see if it is time to announce */
2051 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2054 /* Stop the music on hold so we can play our own file */
2056 ast_indicate(qe->chan,-1);
2058 ast_moh_stop(qe->chan);
2060 ast_verb(3, "Playing periodic announcement\n");
2062 /* Check to make sure we have a sound file. If not, reset to the first sound file */
2063 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
2064 qe->last_periodic_announce_sound = 0;
2067 /* play the announcement */
2068 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
2070 if (res > 0 && !valid_exit(qe, res))
2073 /* Resume Music on Hold if the caller is going to stay in the queue */
2076 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2078 ast_moh_start(qe->chan, qe->moh, NULL);
2081 /* update last_periodic_announce_time */
2082 qe->last_periodic_announce_time = now;
2084 /* Update the current periodic announcement to the next announcement */
2085 qe->last_periodic_announce_sound++;
2090 static void record_abandoned(struct queue_ent *qe)
2092 ao2_lock(qe->parent);
2093 set_queue_variables(qe);
2094 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2098 "OriginalPosition: %d\r\n"
2100 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2102 qe->parent->callsabandoned++;
2103 ao2_unlock(qe->parent);
2106 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2107 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2109 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
2110 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2111 if (qe->parent->autopause) {
2112 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
2113 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2115 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2121 #define AST_MAX_WATCHERS 256
2123 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2125 char *queue = qe->parent->name;
2126 struct callattempt *o;
2128 int sentringing = 0;
2129 int numbusies = prebusies;
2133 struct ast_frame *f;
2134 struct callattempt *peer = NULL;
2135 struct ast_channel *winner;
2136 struct ast_channel *in = qe->chan;
2138 char membername[80] = "";
2142 struct callattempt *epollo;
2145 starttime = (long) time(NULL);
2147 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2149 ast_poll_channel_add(in, epollo->chan);
2153 while (*to && !peer) {
2154 int numlines, retry, pos = 1;
2155 struct ast_channel *watchers[AST_MAX_WATCHERS];
2158 for (retry = 0; retry < 2; retry++) {
2160 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2161 if (o->stillgoing) { /* Keep track of important channels */
2164 watchers[pos++] = o->chan;
2168 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2169 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2171 /* On "ringall" strategy we only move to the next penalty level
2172 when *all* ringing phones are done in the current penalty level */
2173 ring_one(qe, outgoing, &numbusies);
2176 if (pos == 1 /* not found */) {
2177 if (numlines == (numbusies + numnochan)) {
2178 ast_debug(1, "Everyone is busy at this time\n");
2180 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2185 winner = ast_waitfor_n(watchers, pos, to);
2186 for (o = outgoing; o; o = o->q_next) {
2187 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2189 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2192 } else if (o->chan && (o->chan == winner)) {
2194 ast_copy_string(on, o->member->interface, sizeof(on));
2195 ast_copy_string(membername, o->member->membername, sizeof(membername));
2197 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2198 ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2203 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2208 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2209 if ((stuff = strchr(tmpchan, '/'))) {
2213 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2217 /* Before processing channel, go ahead and check for forwarding */
2218 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2219 /* Setup parameters */
2220 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2221 if (status != o->oldstatus)
2222 update_dial_status(qe->parent, o->member, status);
2224 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2228 ast_channel_inherit_variables(in, o->chan);
2229 if (o->chan->cid.cid_num)
2230 ast_free(o->chan->cid.cid_num);
2231 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2233 if (o->chan->cid.cid_name)
2234 ast_free(o->chan->cid.cid_name);
2235 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2237 ast_string_field_set(o->chan, accountcode, in->accountcode);
2238 o->chan->cdrflags = in->cdrflags;
2240 if (in->cid.cid_ani) {
2241 if (o->chan->cid.cid_ani)
2242 ast_free(o->chan->cid.cid_ani);
2243 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2245 if (o->chan->cid.cid_rdnis)
2246 ast_free(o->chan->cid.cid_rdnis);
2247 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2248 if (ast_call(o->chan, tmpchan, 0)) {
2249 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2254 /* Hangup the original channel now, in case we needed it */
2258 f = ast_read(winner);
2260 if (f->frametype == AST_FRAME_CONTROL) {
2261 switch (f->subclass) {
2262 case AST_CONTROL_ANSWER:
2263 /* This is our guy if someone answered. */
2265 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2269 case AST_CONTROL_BUSY:
2270 ast_verb(3, "%s is busy\n", o->chan->name);
2272 ast_cdr_busy(in->cdr);
2274 endtime = (long) time(NULL);
2275 endtime -= starttime;
2276 rna(endtime*1000, qe, on, membername);
2277 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2278 if (qe->parent->timeoutrestart)
2280 ring_one(qe, outgoing, &numbusies);
2284 case AST_CONTROL_CONGESTION:
2285 ast_verb(3, "%s is circuit-busy\n", o->chan->name);
2287 ast_cdr_busy(in->cdr);
2288 endtime = (long) time(NULL);
2289 endtime -= starttime;
2290 rna(endtime*1000, qe, on, membername);
2292 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2293 if (qe->parent->timeoutrestart)
2295 ring_one(qe, outgoing, &numbusies);
2299 case AST_CONTROL_RINGING:
2300 ast_verb(3, "%s is ringing\n", o->chan->name);
2303 ast_indicate(in, AST_CONTROL_RINGING);
2308 case AST_CONTROL_OFFHOOK:
2309 /* Ignore going off hook */
2312 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
2317 endtime = (long) time(NULL) - starttime;
2318 rna(endtime * 1000, qe, on, membername);
2320 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2321 if (qe->parent->timeoutrestart)
2323 ring_one(qe, outgoing, &numbusies);
2330 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2338 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2339 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
2344 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2345 ast_verb(3, "User pressed digit: %c\n", f->subclass);
2347 *digit = f->subclass;
2354 rna(orig, qe, on, membername);
2358 for(epollo = outgoing; epollo; epollo = epollo->q_next) {
2360 ast_poll_channel_del(in, epollo->chan);
2367 static int is_our_turn(struct queue_ent *qe)
2369 struct queue_ent *ch;
2375 if (!qe->parent->autofill) {
2376 /* Atomically read the parent head -- does not need a lock */
2377 ch = qe->parent->head;
2378 /* If we are now at the top of the head, break out */
2380 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2383 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2388 /* This needs a lock. How many members are available to be served? */
2389 ao2_lock(qe->parent);
2391 ch = qe->parent->head;
2393 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2394 ast_debug(1, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in\n", avl);
2397 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2398 while ((cur = ao2_iterator_next(&mem_iter))) {
2399 switch (cur->status) {
2400 case AST_DEVICE_NOT_INUSE:
2401 case AST_DEVICE_UNKNOWN:
2410 ast_debug(1, "There are %d available members.\n", avl);
2412 while ((idx < avl) && (ch) && (ch != qe)) {
2417 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2418 if (ch && idx < avl) {
2419 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2422 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2426 ao2_unlock(qe->parent);
2432 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2436 /* This is the holding pen for callers 2 through maxlen */
2438 enum queue_member_status stat;
2440 if (is_our_turn(qe))
2443 /* If we have timed out, break out */
2444 if (qe->expire && (time(NULL) > qe->expire)) {
2445 *reason = QUEUE_TIMEOUT;
2449 stat = get_member_status(qe->parent, qe->max_penalty);
2451 /* leave the queue if no agents, if enabled */
2452 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2453 *reason = QUEUE_LEAVEEMPTY;
2454 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2459 /* leave the queue if no reachable agents, if enabled */
2460 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2461 *reason = QUEUE_LEAVEUNAVAIL;
2462 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2466 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2467 *reason = QUEUE_LEAVEUNAVAIL;
2468 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2473 /* Make a position announcement, if enabled */
2474 if (qe->parent->announcefrequency &&
2475 (res = say_position(qe,ringing)))
2478 /* Make a periodic announcement, if enabled */
2479 if (qe->parent->periodicannouncefrequency &&
2480 (res = say_periodic_announcement(qe,ringing)))
2483 /* Wait a second before checking again */
2484 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
2485 if (res > 0 && !valid_exit(qe, res))
2495 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
2498 time(&member->lastcall);
2500 q->callscompleted++;
2501 if (callcompletedinsl)
2502 q->callscompletedinsl++;
2507 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2509 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2512 switch (q->strategy) {
2513 case QUEUE_STRATEGY_RINGALL:
2514 /* Everyone equal, except for penalty */
2515 tmp->metric = mem->penalty * 1000000;
2517 case QUEUE_STRATEGY_RRMEMORY:
2518 if (pos < q->rrpos) {
2519 tmp->metric = 1000 + pos;
2522 /* Indicate there is another priority */
2526 tmp->metric += mem->penalty * 1000000;
2528 case QUEUE_STRATEGY_RANDOM:
2529 tmp->metric = ast_random() % 1000;
2530 tmp->metric += mem->penalty * 1000000;
2532 case QUEUE_STRATEGY_FEWESTCALLS:
2533 tmp->metric = mem->calls;
2534 tmp->metric += mem->penalty * 1000000;
2536 case QUEUE_STRATEGY_LEASTRECENT:
2540 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2541 tmp->metric += mem->penalty * 1000000;
2544 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2550 enum agent_complete_reason {
2556 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
2557 const struct ast_channel *peer, const struct member *member, time_t callstart,
2558 char *vars, size_t vars_len, enum agent_complete_reason rsn)
2562 if (!qe->parent->eventwhencalled)
2573 reason = "transfer";
2577 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2582 "MemberName: %s\r\n"
2587 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2588 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
2589 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
2592 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)
2595 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2597 char oldexten[AST_MAX_EXTENSION]="";
2598 char oldcontext[AST_MAX_CONTEXT]="";
2599 char queuename[256]="";
2600 char interfacevar[256]="";
2601 struct ast_channel *peer;
2602 struct ast_channel *which;
2603 struct callattempt *lpeer;
2604 struct member *member;
2605 struct ast_app *app;
2606 int res = 0, bridge = 0;
2609 char *announce = NULL;
2612 time_t now = time(NULL);
2613 struct ast_bridge_config bridge_config;
2614 char nondataquality = 1;
2615 char *agiexec = NULL;
2616 char *macroexec = NULL;
2617 char *gosubexec = NULL;
2619 const char *monitorfilename;
2620 const char *monitor_exec;
2621 const char *monitor_options;
2622 char tmpid[256], tmpid2[256];
2623 char meid[1024], meid2[1024];
2624 char mixmonargs[1512];
2625 struct ast_app *mixmonapp = NULL;
2628 int forwardsallowed = 1;
2629 int callcompletedinsl;
2630 struct ao2_iterator memi;
2632 memset(&bridge_config, 0, sizeof(bridge_config));
2635 for (; options && *options; options++)
2638 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2641 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2644 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2647 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2653 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2656 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2659 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
2662 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
2665 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
2668 *tries = qe->parent->membercount;
2672 forwardsallowed = 0;
2676 /* Hold the lock while we setup the outgoing calls */
2679 ao2_lock(qe->parent);
2680 ast_debug(1, "%s is trying to call a queue member.\n",
2682 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2683 if (!ast_strlen_zero(qe->announce))
2684 announce = qe->announce;
2685 if (!ast_strlen_zero(announceoverride))
2686 announce = announceoverride;
2688 memi = ao2_iterator_init(qe->parent->members, 0);
2689 while ((cur = ao2_iterator_next(&memi))) {
2690 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2694 ao2_unlock(qe->parent);
2699 tmp->stillgoing = -1;
2701 tmp->oldstatus = cur->status;
2702 tmp->lastcall = cur->lastcall;
2703 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2704 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2705 just calculate their metric for the appropriate strategy */
2706 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2707 /* Put them in the list of outgoing thingies... We're ready now.
2708 XXX If we're forcibly removed, these outgoing calls won't get
2710 tmp->q_next = outgoing;
2712 /* If this line is up, don't try anybody else */
2713 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2720 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2721 to = (qe->expire - now) * 1000;
2723 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2725 ring_one(qe, outgoing, &numbusies);
2726 ao2_unlock(qe->parent);
2729 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2730 ao2_lock(qe->parent);
2731 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2732 store_next(qe, outgoing);
2734 ao2_unlock(qe->parent);
2735 peer = lpeer ? lpeer->chan : NULL;
2738 /* Must gotten hung up */
2741 /* User exited by pressing a digit */
2745 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
2746 } else { /* peer is valid */
2747 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2748 we will always return with -1 so that it is hung up properly after the
2751 if (!strcmp(qe->chan->tech->type, "Zap"))
2752 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2753 if (!strcmp(peer->tech->type, "Zap"))
2754 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2755 /* Update parameters for the queue */
2757 recalc_holdtime(qe, (now - qe->start));
2758 ao2_lock(qe->parent);
2759 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
2760 ao2_unlock(qe->parent);
2761 member = lpeer->member;
2762 hangupcalls(outgoing, peer);
2764 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2767 res2 = ast_autoservice_start(qe->chan);
2769 if (qe->parent->memberdelay) {
2770 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2771 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2773 if (!res2 && announce) {
2774 play_file(peer, announce);
2776 if (!res2 && qe->parent->reportholdtime) {
2777 if (!play_file(peer, qe->parent->sound_reporthold)) {
2781 holdtime = abs((now - qe->start) / 60);
2783 play_file(peer, qe->parent->sound_lessthan);
2784 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2786 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2787 play_file(peer, qe->parent->sound_minutes);
2791 res2 |= ast_autoservice_stop(qe->chan);
2792 if (ast_check_hangup(peer)) {
2793 /* Agent must have hung up */
2794 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
2795 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2796 record_abandoned(qe);
2797 if (qe->parent->eventwhencalled)
2798 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2803 "MemberName: %s\r\n"
2805 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2806 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2810 /* Caller must have hung up just before being connected*/
2811 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2812 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2813 record_abandoned(qe);
2818 /* Stop music on hold */
2820 ast_indicate(qe->chan,-1);
2822 ast_moh_stop(qe->chan);
2823 /* If appropriate, log that we have a destination channel */
2825 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2826 /* Make sure channels are compatible */
2827 res = ast_channel_make_compatible(qe->chan, peer);
2829 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2830 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2831 record_abandoned(qe);
2836 /* Play announcement to the caller telling it's his turn if defined */
2837 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
2838 if (play_file(qe->chan, qe->parent->sound_callerannounce))
2839 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
2842 ao2_lock(qe->parent);
2843 /* if setinterfacevar is defined, make member variables available to the channel */
2844 /* use pbx_builtin_setvar to set a load of variables with one call */
2845 if (qe->parent->setinterfacevar) {
2846 snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d|MEMBERREALTIME=%d",
2847 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
2848 pbx_builtin_setvar(qe->chan, interfacevar);
2851 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
2852 /* use pbx_builtin_setvar to set a load of variables with one call */
2853 if (qe->parent->setqueueentryvar) {
2854 snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
2855 (long) time(NULL) - qe->start, qe->opos);
2856 pbx_builtin_setvar(qe->chan, interfacevar);
2859 /* try to set queue variables if configured to do so*/
2860 set_queue_variables(qe);
2861 ao2_unlock(qe->parent);
2863 /* Begin Monitoring */
2864 if (qe->parent->monfmt && *qe->parent->monfmt) {
2865 if (!qe->parent->montype) {
2866 ast_debug(1, "Starting Monitor as requested.\n");
2867 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2868 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2872 if (monitorfilename)
2873 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
2874 else if (qe->chan->cdr)
2875 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1, X_REC_IN | X_REC_OUT);
2877 /* Last ditch effort -- no CDR, make up something */
2878 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2879 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
2881 if (qe->parent->monjoin)
2882 ast_monitor_setjoinfiles(which, 1);
2884 ast_debug(1, "Starting MixMonitor as requested.\n");
2885 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2886 if (!monitorfilename) {
2888 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid));
2890 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2892 const char *m = monitorfilename;
2893 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
2896 if (*(m + 1) == '{')
2908 if (p == tmpid2 + sizeof(tmpid2))
2909 tmpid2[sizeof(tmpid2) - 1] = '\0';
2911 memset(tmpid, 0, sizeof(tmpid));
2912 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2915 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2916 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2919 const char *m = monitor_exec;
2920 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
2923 if (*(m + 1) == '{')
2935 if (p == meid2 + sizeof(meid2))
2936 meid2[sizeof(meid2) - 1] = '\0';
2938 memset(meid, 0, sizeof(meid));
2939 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2942 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
2944 mixmonapp = pbx_findapp("MixMonitor");
2946 if (!monitor_options)
2947 monitor_options = "";
2950 if (!ast_strlen_zero(monitor_exec))
2951 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
2953 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
2955 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2956 /* We purposely lock the CDR so that pbx_exec does not update the application data */
2958 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
2959 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2961 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
2964 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2968 /* Drop out of the queue at this point, to prepare for next caller */
2970 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2971 ast_debug(1, "app_queue: sendurl=%s.\n", url);
2972 ast_channel_sendurl(peer, url);
2975 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
2976 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
2977 if (!ast_strlen_zero(macro)) {
2978 macroexec = ast_strdupa(macro);
2980 if (qe->parent->membermacro)
2981 macroexec = ast_strdupa(qe->parent->membermacro);
2984 if (!ast_strlen_zero(macroexec)) {
2985 ast_debug(1, "app_queue: macro=%s.\n", macroexec);
2987 res = ast_autoservice_start(qe->chan);
2989 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
2993 app = pbx_findapp("Macro");
2996 res = pbx_exec(qe->chan, app, macroexec);
2997 ast_debug(1, "Macro exited with status %d\n", res);
3000 ast_log(LOG_ERROR, "Could not find application Macro\n");
3004 if (ast_autoservice_stop(qe->chan) < 0) {
3005 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
3010 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
3011 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
3012 if (!ast_strlen_zero(gosub)) {
3013 gosubexec = ast_strdupa(gosub);
3015 if (qe->parent->membergosub)
3016 gosubexec = ast_strdupa(qe->parent->membergosub);
3019 if (!ast_strlen_zero(gosubexec)) {
3021 ast_log(LOG_DEBUG, "app_queue: gosub=%s.\n", gosubexec);
3023 res = ast_autoservice_start(qe->chan);
3025 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
3029 app = pbx_findapp("Gosub");
3032 char *gosub_args, *gosub_argstart;
3034 /* Set where we came from */
3035 ast_copy_string(qe->chan->context, "app_dial_gosub_virtual_context", sizeof(qe->chan->context));
3036 ast_copy_string(qe->chan->exten, "s", sizeof(qe->chan->exten));
3037 qe->chan->priority = 0;
3039 gosub_argstart = strchr(gosubexec, ',');
3040 if (gosub_argstart) {
3041 *gosub_argstart = 0;
3042 asprintf(&gosub_args, "%s,s,1(%s)", gosubexec, gosub_argstart + 1);
3043 *gosub_argstart = '|';
3045 asprintf(&gosub_args, "%s,s,1", gosubexec);
3048 res = pbx_exec(qe->chan, app, gosub_args);
3049 ast_pbx_run(qe->chan);
3052 ast_log(LOG_DEBUG, "Gosub exited with status %d\n", res);
3054 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
3058 ast_log(LOG_ERROR, "Could not find application Gosub\n");
3062 if (ast_autoservice_stop(qe->chan) < 0) {
3063 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
3068 if (!ast_strlen_zero(agi)) {
3069 ast_debug(1, "app_queue: agi=%s.\n", agi);
3070 app = pbx_findapp("agi");
3072 agiexec = ast_strdupa(agi);
3073 ret = pbx_exec(qe->chan, app, agiexec);
3075 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
3077 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s|%ld", (long) time(NULL) - qe->start, peer->uniqueid,
3078 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
3079 if (update_cdr && qe->chan->cdr)
3080 ast_copy_string(qe->chan->cdr->dstchannel, member->membername, sizeof(qe->chan->cdr->dstchannel));
3081 if (qe->parent->eventwhencalled)
3082 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
3087 "MemberName: %s\r\n"
3089 "BridgedChannel: %s\r\n"
3092 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
3093 (long) time(NULL) - qe->start, peer->uniqueid, (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
3094 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3095 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
3096 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
3099 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
3101 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
3102 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
3103 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
3104 (long) (time(NULL) - callstart));
3105 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
3106 } else if (ast_check_hangup(qe->chan)) {
3107 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
3108 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3109 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
3111 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
3112 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
3113 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
3116 if (bridge != AST_PBX_NO_HANGUP_PEER)
3118 update_queue(qe->parent, member, callcompletedinsl);
3119 res = bridge ? bridge : 1;
3122 hangupcalls(outgoing, NULL);
3127 static int wait_a_bit(struct queue_ent *qe)
3129 /* Don't need to hold the lock while we setup the outgoing calls */
3130 int retrywait = qe->parent->retry * 1000;
3132 int res = ast_waitfordigit(qe->chan, retrywait);
3133 if (res > 0 && !valid_exit(qe, res))
3139 static struct member *interface_exists(struct call_queue *q, const char *interface)
3142 struct ao2_iterator mem_iter;
3147 mem_iter = ao2_iterator_init(q->members, 0);
3148 while ((mem = ao2_iterator_next(&mem_iter))) {
3149 if (!strcasecmp(interface, mem->interface))
3158 /* Dump all members in a specific queue to the database
3160 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3163 static void dump_queue_members(struct call_queue *pm_queue)
3165 struct member *cur_member;
3166 char value[PM_MAX_LEN];
3169 struct ao2_iterator mem_iter;
3171 memset(value, 0, sizeof(value));
3176 mem_iter = ao2_iterator_init(pm_queue->members, 0);
3177 while ((cur_member = ao2_iterator_next(&mem_iter))) {
3178 if (!cur_member->dynamic) {
3179 ao2_ref(cur_member, -1);
3183 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
3184 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
3186 ao2_ref(cur_member, -1);
3188 if (res != strlen(value + value_len)) {
3189 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
3195 if (value_len && !cur_member) {
3196 if (ast_db_put(pm_family, pm_queue->name, value))
3197 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
3199 /* Delete the entry if the queue is empty or there is an error */
3200 ast_db_del(pm_family, pm_queue->name);
3203 static int remove_from_queue(const char *queuename, const char *interface)
3205 struct call_queue *q, tmpq;
3206 struct member *mem, tmpmem;
3207 int res = RES_NOSUCHQUEUE;
3209 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
3210 ast_copy_string(tmpq.name, queuename, sizeof(tmpq.name));
3211 if((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
3213 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK))) {
3215 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
3218 "MemberName: %s\r\n",
3219 q->name, mem->interface, mem->membername);
3222 if (queue_persistent_members)
3223 dump_queue_members(q);
3233 if (res == RES_OKAY)
3234 remove_from_interfaces(interface);
3240 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
3242 struct call_queue *q;
3243 struct member *new_member, *old_member;
3244 int res = RES_NOSUCHQUEUE;
3246 /* \note Ensure the appropriate realtime queue is loaded. Note that this
3247 * short-circuits if the queue is already in memory. */
3248 if (!(q = load_realtime_queue(queuename)))
3254 if ((old_member = interface_exists(q, interface)) == NULL) {
3255 add_to_interfaces(interface);
3256 if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
3257 new_member->dynamic = 1;
3258 ao2_link(q->members, new_member);
3260 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
3263 "MemberName: %s\r\n"
3264 "Membership: %s\r\n"
3266 "CallsTaken: %d\r\n"
3270 q->name, new_member->interface, new_member->membername,
3272 new_member->penalty, new_member->calls, (int) new_member->lastcall,
3273 new_member->status, new_member->paused);
3276 dump_queue_members(q);
3280 res = RES_OUTOFMEMORY;
3283 ao2_ref(old_member, -1);
3292 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
3295 struct call_queue *q;
3297 struct ao2_iterator queue_iter;
3299 /* Special event for when all queues are paused - individual events still generated */
3300 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
3301 if (ast_strlen_zero(queuename))
3302 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
3304 queue_iter = ao2_iterator_init(queues, 0);
3305 while((q = ao2_iterator_next(&queue_iter))) {
3307 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
3308 if ((mem = interface_exists(q, interface))) {
3310 if (mem->paused == paused) {
3311 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
3313 mem->paused = paused;
3315 if (queue_persistent_members)
3316 dump_queue_members(q);
3319 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
3321 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", S_OR(reason, ""));
3323 if (!ast_strlen_zero(reason)) {
3324 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
3327 "MemberName: %s\r\n"
3330 q->name, mem->interface, mem->membername, paused, reason);
3332 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",