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
60 <depend>res_monitor</depend>
65 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
68 #include <sys/signal.h>
69 #include <netinet/in.h>
71 #include "asterisk/lock.h"
72 #include "asterisk/file.h"
73 #include "asterisk/channel.h"
74 #include "asterisk/pbx.h"
75 #include "asterisk/app.h"
76 #include "asterisk/linkedlists.h"
77 #include "asterisk/module.h"
78 #include "asterisk/translate.h"
79 #include "asterisk/say.h"
80 #include "asterisk/features.h"
81 #include "asterisk/musiconhold.h"
82 #include "asterisk/cli.h"
83 #include "asterisk/manager.h"
84 #include "asterisk/config.h"
85 #include "asterisk/monitor.h"
86 #include "asterisk/utils.h"
87 #include "asterisk/causes.h"
88 #include "asterisk/astdb.h"
89 #include "asterisk/devicestate.h"
90 #include "asterisk/stringfields.h"
91 #include "asterisk/event.h"
92 #include "asterisk/astobj2.h"
93 #include "asterisk/strings.h"
94 #include "asterisk/global_datastores.h"
95 #include "asterisk/taskprocessor.h"
98 * \par Please read before modifying this file.
99 * There are three locks which are regularly used
100 * throughout this file, the queue list lock, the lock
101 * for each individual queue, and the interface list lock.
102 * Please be extra careful to always lock in the following order
104 * 2) individual queue lock
105 * 3) interface list lock
106 * This order has sort of "evolved" over the lifetime of this
107 * application, but it is now in place this way, so please adhere
113 QUEUE_STRATEGY_RINGALL = 0,
114 QUEUE_STRATEGY_LEASTRECENT,
115 QUEUE_STRATEGY_FEWESTCALLS,
116 QUEUE_STRATEGY_RANDOM,
117 QUEUE_STRATEGY_RRMEMORY,
118 QUEUE_STRATEGY_LINEAR,
119 QUEUE_STRATEGY_WRANDOM
122 static const struct strategy {
126 { QUEUE_STRATEGY_RINGALL, "ringall" },
127 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
128 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
129 { QUEUE_STRATEGY_RANDOM, "random" },
130 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
131 { QUEUE_STRATEGY_LINEAR, "linear" },
132 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
135 static struct ast_taskprocessor *devicestate_tps;
137 #define DEFAULT_RETRY 5
138 #define DEFAULT_TIMEOUT 15
139 #define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
140 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
141 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /*!< The minimum number of seconds between position announcements \
142 The default value of 15 provides backwards compatibility */
143 #define MAX_QUEUE_BUCKETS 53
145 #define RES_OKAY 0 /*!< Action completed */
146 #define RES_EXISTS (-1) /*!< Entry already exists */
147 #define RES_OUTOFMEMORY (-2) /*!< Out of memory */
148 #define RES_NOSUCHQUEUE (-3) /*!< No such queue */
149 #define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
151 static char *app = "Queue";
153 static char *synopsis = "Queue a call for a call queue";
155 static char *descrip =
156 " Queue(queuename[,options[,URL][,announceoverride][,timeout][,AGI][,macro][,gosub][,rule]):\n"
157 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
158 "This application will return to the dialplan if the queue does not exist, or\n"
159 "any of the join options cause the caller to not enter the queue.\n"
160 "The option string may contain zero or more of the following characters:\n"
161 " 'c' -- continue in the dialplan if the callee hangs up.\n"
162 " 'd' -- data-quality (modem) call (minimum delay).\n"
163 " 'h' -- allow callee to hang up by pressing *.\n"
164 " 'H' -- allow caller to hang up by pressing *.\n"
165 " 'n' -- no retries on the timeout; will exit this application and \n"
166 " go to the next step.\n"
167 " 'i' -- ignore call forward requests from queue members and do nothing\n"
168 " when they are requested.\n"
169 " 'r' -- ring instead of playing MOH. Periodic Announcements are still made, if applicable.\n"
170 " 't' -- allow the called user to transfer the calling user.\n"
171 " 'T' -- allow the calling user to transfer the call.\n"
172 " 'w' -- allow the called user to write the conversation to disk via Monitor.\n"
173 " 'W' -- allow the calling user to write the conversation to disk via Monitor.\n"
174 " 'k' -- Allow the called party to enable parking of the call by sending\n"
175 " the DTMF sequence defined for call parking in features.conf.\n"
176 " 'K' -- Allow the calling party to enable parking of the call by sending\n"
177 " the DTMF sequence defined for call parking in features.conf.\n"
178 " 'x' -- allow the called user to write the conversation to disk via MixMonitor\n"
179 " 'X' -- allow the calling user to write the conversation to disk via MixMonitor\n"
181 " In addition to transferring the call, a call may be parked and then picked\n"
182 "up by another user.\n"
183 " The optional URL will be sent to the called party if the channel supports\n"
185 " The optional AGI parameter will setup an AGI script to be executed on the \n"
186 "calling party's channel once they are connected to a queue member.\n"
187 " The optional macro parameter will run a macro on the \n"
188 "calling party's channel once they are connected to a queue member.\n"
189 " The optional gosub parameter will run a gosub on the \n"
190 "calling party's channel once they are connected to a queue member.\n"
191 " The optional rule parameter will cause the queue's defaultrule to be\n"
192 "overridden by the rule specified.\n"
193 " The timeout will cause the queue to fail out after a specified number of\n"
194 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
195 " This application sets the following channel variable upon completion:\n"
196 " QUEUESTATUS The status of the call as a text string, one of\n"
197 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL | CONTINUE\n";
199 static char *app_aqm = "AddQueueMember" ;
200 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
201 static char *app_aqm_descrip =
202 " AddQueueMember(queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]]):\n"
203 "Dynamically adds interface to an existing queue.\n"
204 "If the interface is already in the queue it will return an error.\n"
205 " This application sets the following channel variable upon completion:\n"
206 " AQMSTATUS The status of the attempt to add a queue member as a \n"
207 " text string, one of\n"
208 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
209 "Example: AddQueueMember(techsupport,SIP/3000)\n"
212 static char *app_rqm = "RemoveQueueMember" ;
213 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
214 static char *app_rqm_descrip =
215 " RemoveQueueMember(queuename[,interface[,options]]):\n"
216 "Dynamically removes interface to an existing queue\n"
217 "If the interface is NOT in the queue it will return an error.\n"
218 " This application sets the following channel variable upon completion:\n"
219 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
220 " text string, one of\n"
221 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
222 "Example: RemoveQueueMember(techsupport,SIP/3000)\n"
225 static char *app_pqm = "PauseQueueMember" ;
226 static char *app_pqm_synopsis = "Pauses a queue member" ;
227 static char *app_pqm_descrip =
228 " PauseQueueMember([queuename],interface[,options[,reason]]):\n"
229 "Pauses (blocks calls for) a queue member.\n"
230 "The given interface will be paused in the given queue. This prevents\n"
231 "any calls from being sent from the queue to the interface until it is\n"
232 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
233 "queuename is given, the interface is paused in every queue it is a\n"
234 "member of. The application will fail if the interface is not found.\n"
235 "The reason string is entirely optional and is used to add extra information\n"
236 "to the appropriate queue_log entries and manager events.\n"
237 " This application sets the following channel variable upon completion:\n"
238 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
239 " text string, one of\n"
240 " PAUSED | NOTFOUND\n"
241 "Example: PauseQueueMember(,SIP/3000)\n";
243 static char *app_upqm = "UnpauseQueueMember" ;
244 static char *app_upqm_synopsis = "Unpauses a queue member" ;
245 static char *app_upqm_descrip =
246 " UnpauseQueueMember([queuename],interface[,options[,reason]]):\n"
247 "Unpauses (resumes calls to) a queue member.\n"
248 "This is the counterpart to PauseQueueMember and operates exactly the\n"
249 "same way, except it unpauses instead of pausing the given interface.\n"
250 "The reason string is entirely optional and is used to add extra information\n"
251 "to the appropriate queue_log entries and manager events.\n"
252 " This application sets the following channel variable upon completion:\n"
253 " UPQMSTATUS The status of the attempt to unpause a queue \n"
254 " member as a text string, one of\n"
255 " UNPAUSED | NOTFOUND\n"
256 "Example: UnpauseQueueMember(,SIP/3000)\n";
258 static char *app_ql = "QueueLog" ;
259 static char *app_ql_synopsis = "Writes to the queue_log" ;
260 static char *app_ql_descrip =
261 " QueueLog(queuename,uniqueid,agent,event[,additionalinfo]):\n"
262 "Allows you to write your own events into the queue log\n"
263 "Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)\n";
265 /*! \brief Persistent Members astdb family */
266 static const char *pm_family = "Queue/PersistentMembers";
267 /* The maximum length of each persistent member queue database entry */
268 #define PM_MAX_LEN 8192
270 /*! \brief queues.conf [general] option */
271 static int queue_keep_stats = 0;
273 /*! \brief queues.conf [general] option */
274 static int queue_persistent_members = 0;
276 /*! \brief queues.conf per-queue weight option */
277 static int use_weight = 0;
279 /*! \brief queues.conf [general] option */
280 static int autofill_default = 0;
282 /*! \brief queues.conf [general] option */
283 static int montype_default = 0;
285 /*! \brief queues.conf [general] option */
286 static int shared_lastcall = 0;
288 /*! \brief Subscription to device state change events */
289 static struct ast_event_sub *device_state_sub;
291 /*! \brief queues.conf [general] option */
292 static int update_cdr = 0;
298 QUEUE_LEAVEEMPTY = 3,
299 QUEUE_JOINUNAVAIL = 4,
300 QUEUE_LEAVEUNAVAIL = 5,
306 enum queue_result id;
308 } queue_results[] = {
309 { QUEUE_UNKNOWN, "UNKNOWN" },
310 { QUEUE_TIMEOUT, "TIMEOUT" },
311 { QUEUE_JOINEMPTY,"JOINEMPTY" },
312 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
313 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
314 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
315 { QUEUE_FULL, "FULL" },
316 { QUEUE_CONTINUE, "CONTINUE" },
319 /*! \brief We define a custom "local user" structure because we
320 * use it not only for keeping track of what is in use but
321 * also for keeping track of who we're dialing.
323 * There are two "links" defined in this structure, q_next and call_next.
324 * q_next links ALL defined callattempt structures into a linked list. call_next is
325 * a link which allows for a subset of the callattempts to be traversed. This subset
326 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
327 * also is helpful so that queue logs are always accurate in the case where a call to
328 * a member times out, especially if using the ringall strategy.
332 struct callattempt *q_next;
333 struct callattempt *call_next;
334 struct ast_channel *chan;
340 struct call_queue *lastqueue;
341 struct member *member;
346 struct call_queue *parent; /*!< What queue is our parent */
347 char moh[80]; /*!< Name of musiconhold to be used */
348 char announce[80]; /*!< Announcement to play for member when call is answered */
349 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
350 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
351 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
352 int pos; /*!< Where we are in the queue */
353 int prio; /*!< Our priority */
354 int last_pos_said; /*!< Last position we told the user */
355 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
356 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
357 time_t last_pos; /*!< Last time we told the user their position */
358 int opos; /*!< Where we started in the queue */
359 int handled; /*!< Whether our call was handled */
360 int pending; /*!< Non-zero if we are attempting to call a member */
361 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
362 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
363 int linpos; /*!< If using linear strategy, what position are we at? */
364 int linwrapped; /*!< Is the linpos wrapped? */
365 time_t start; /*!< When we started holding */
366 time_t expire; /*!< When this entry should expire (time out of queue) */
367 struct ast_channel *chan; /*!< Our channel */
368 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
369 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
370 struct queue_ent *next; /*!< The next queue entry */
374 char interface[80]; /*!< Technology/Location to dial to reach this member*/
375 char state_interface[80]; /*!< Technology/Location from which to read devicestate changes */
376 char membername[80]; /*!< Member name to use in queue logs */
377 int penalty; /*!< Are we a last resort? */
378 int calls; /*!< Number of calls serviced by this member */
379 int dynamic; /*!< Are we dynamically added? */
380 int realtime; /*!< Is this member realtime? */
381 int status; /*!< Status of queue member */
382 int paused; /*!< Are we paused (not accepting calls)? */
383 time_t lastcall; /*!< When last successful call was hungup */
384 struct call_queue *lastqueue; /*!< Last queue we received a call */
385 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
386 unsigned int delme:1; /*!< Flag to delete entry on reload */
387 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
390 struct member_interface {
392 AST_LIST_ENTRY(member_interface) list; /*!< Next call queue */
395 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
397 /* values used in multi-bit flags in call_queue */
398 #define QUEUE_EMPTY_NORMAL 1
399 #define QUEUE_EMPTY_STRICT 2
400 #define QUEUE_EMPTY_LOOSE 3
401 #define ANNOUNCEHOLDTIME_ALWAYS 1
402 #define ANNOUNCEHOLDTIME_ONCE 2
403 #define QUEUE_EVENT_VARIABLES 3
405 struct penalty_rule {
406 int time; /*!< Number of seconds that need to pass before applying this rule */
407 int max_value; /*!< The amount specified in the penalty rule for max penalty */
408 int min_value; /*!< The amount specified in the penalty rule for min penalty */
409 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
410 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
411 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
414 #define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
415 #define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
416 #define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
417 #define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
420 AST_DECLARE_STRING_FIELDS(
422 AST_STRING_FIELD(name);
423 /*! Music on Hold class */
424 AST_STRING_FIELD(moh);
425 /*! Announcement to play when call is answered */
426 AST_STRING_FIELD(announce);
428 AST_STRING_FIELD(context);
429 /*! Macro to run upon member connection */
430 AST_STRING_FIELD(membermacro);
431 /*! Gosub to run upon member connection */
432 AST_STRING_FIELD(membergosub);
433 /*! Default rule to use if none specified in call to Queue() */
434 AST_STRING_FIELD(defaultrule);
435 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
436 AST_STRING_FIELD(sound_next);
437 /*! Sound file: "There are currently" (def. queue-thereare) */
438 AST_STRING_FIELD(sound_thereare);
439 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
440 AST_STRING_FIELD(sound_calls);
441 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
442 AST_STRING_FIELD(queue_quantity1);
443 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
444 AST_STRING_FIELD(queue_quantity2);
445 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
446 AST_STRING_FIELD(sound_holdtime);
447 /*! Sound file: "minutes." (def. queue-minutes) */
448 AST_STRING_FIELD(sound_minutes);
449 /*! Sound file: "minute." (def. queue-minute) */
450 AST_STRING_FIELD(sound_minute);
451 /*! Sound file: "seconds." (def. queue-seconds) */
452 AST_STRING_FIELD(sound_seconds);
453 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
454 AST_STRING_FIELD(sound_thanks);
455 /*! Sound file: Custom announce for caller, no default */
456 AST_STRING_FIELD(sound_callerannounce);
457 /*! Sound file: "Hold time" (def. queue-reporthold) */
458 AST_STRING_FIELD(sound_reporthold);
460 /*! Sound files: Custom announce, no default */
461 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
463 unsigned int joinempty:2;
464 unsigned int eventwhencalled:2;
465 unsigned int leavewhenempty:2;
466 unsigned int ringinuse:1;
467 unsigned int setinterfacevar:1;
468 unsigned int setqueuevar:1;
469 unsigned int setqueueentryvar:1;
470 unsigned int reportholdtime:1;
471 unsigned int wrapped:1;
472 unsigned int timeoutrestart:1;
473 unsigned int announceholdtime:2;
474 unsigned int announceposition:3;
476 unsigned int maskmemberstatus:1;
477 unsigned int realtime:1;
478 unsigned int found:1;
479 int announcepositionlimit; /*!< How many positions we announce? */
480 int announcefrequency; /*!< How often to announce their position */
481 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
482 int periodicannouncefrequency; /*!< How often to play periodic announcement */
483 int numperiodicannounce; /*!< The number of periodic announcements configured */
484 int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
485 int roundingseconds; /*!< How many seconds do we round to? */
486 int holdtime; /*!< Current avg holdtime, based on an exponential average */
487 int callscompleted; /*!< Number of queue calls completed */
488 int callsabandoned; /*!< Number of queue calls abandoned */
489 int servicelevel; /*!< seconds setting for servicelevel*/
490 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
491 char monfmt[8]; /*!< Format to use when recording calls */
492 int montype; /*!< Monitor type Monitor vs. MixMonitor */
493 int count; /*!< How many entries */
494 int maxlen; /*!< Max number of entries */
495 int wrapuptime; /*!< Wrapup Time */
497 int retry; /*!< Retry calling everyone after this amount of time */
498 int timeout; /*!< How long to wait for an answer */
499 int weight; /*!< Respective weight */
500 int autopause; /*!< Auto pause queue members if they fail to answer */
502 /* Queue strategy things */
503 int rrpos; /*!< Round Robin - position */
504 int memberdelay; /*!< Seconds to delay connecting member to caller */
505 int autofill; /*!< Ignore the head call status and ring an available agent */
507 struct ao2_container *members; /*!< Head of the list of members */
509 * \brief Number of members _logged in_
510 * \note There will be members in the members container that are not logged
511 * in, so this can not simply be replaced with ao2_container_count().
514 struct queue_ent *head; /*!< Head of the list of callers */
515 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
516 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
521 AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
522 AST_LIST_ENTRY(rule_list) list;
525 AST_LIST_HEAD_STATIC(rule_lists, rule_list);
527 static struct ao2_container *queues;
529 static void update_realtime_members(struct call_queue *q);
530 static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
532 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
533 /*! \brief sets the QUEUESTATUS channel variable */
534 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
538 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
539 if (queue_results[i].id == res) {
540 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
546 static const char *int2strat(int strategy)
550 for (x = 0; x < ARRAY_LEN(strategies); x++) {
551 if (strategy == strategies[x].strategy)
552 return strategies[x].name;
558 static int strat2int(const char *strategy)
562 for (x = 0; x < ARRAY_LEN(strategies); x++) {
563 if (!strcasecmp(strategy, strategies[x].name))
564 return strategies[x].strategy;
570 static int queue_hash_cb(const void *obj, const int flags)
572 const struct call_queue *q = obj;
573 return ast_str_hash(q->name);
576 static int queue_cmp_cb(void *obj, void *arg, int flags)
578 struct call_queue *q = obj, *q2 = arg;
579 return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0;
582 static inline struct call_queue *queue_ref(struct call_queue *q)
588 static inline struct call_queue *queue_unref(struct call_queue *q)
594 /*! \brief Set variables of queue */
595 static void set_queue_variables(struct queue_ent *qe)
597 char interfacevar[256]="";
600 if (qe->parent->setqueuevar) {
602 if (qe->parent->callscompleted > 0)
603 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
605 snprintf(interfacevar, sizeof(interfacevar),
606 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
607 qe->parent->name, qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
608 qe->parent->callsabandoned, qe->parent->servicelevel, sl);
610 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
614 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
615 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
617 struct queue_ent *cur;
634 enum queue_member_status {
636 QUEUE_NO_REACHABLE_MEMBERS,
637 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
641 /*! \brief Check if members are available
643 * This function checks to see if members are available to be called. If any member
644 * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
645 * the appropriate reason why is returned
647 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty, int min_penalty)
649 struct member *member;
650 struct ao2_iterator mem_iter;
651 enum queue_member_status result = QUEUE_NO_MEMBERS;
654 mem_iter = ao2_iterator_init(q->members, 0);
655 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
656 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty)))
659 switch (member->status) {
660 case AST_DEVICE_INVALID:
663 case AST_DEVICE_UNAVAILABLE:
664 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)
665 result = QUEUE_NO_REACHABLE_MEMBERS;
668 if (member->paused) {
669 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
684 AST_LIST_ENTRY(statechange) entry;
689 /*! \brief set a member's status based on device state of that member's state_interface.
691 * Lock interface list find sc, iterate through each queues queue_member list for member to
692 * update state inside queues
694 static int update_status(const char *interface, const int status)
697 struct ao2_iterator mem_iter, queue_iter;
698 struct call_queue *q;
700 queue_iter = ao2_iterator_init(queues, 0);
701 while ((q = ao2_iterator_next(&queue_iter))) {
703 mem_iter = ao2_iterator_init(q->members, 0);
704 while ((cur = ao2_iterator_next(&mem_iter))) {
707 tmp_interface = ast_strdupa(cur->state_interface);
708 if ((slash_pos = strchr(interface, '/')))
709 if ((slash_pos = strchr(slash_pos + 1, '/')))
712 if (strcasecmp(interface, tmp_interface)) {
717 if (cur->status != status) {
718 cur->status = status;
719 if (q->maskmemberstatus) {
724 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
734 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
735 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
746 /*! \brief set a member's status based on device state of that member's interface*/
747 static int handle_statechange(void *datap)
749 struct member_interface *curint;
752 struct statechange *sc = datap;
754 technology = ast_strdupa(sc->dev);
755 loc = strchr(technology, '/');
763 AST_LIST_LOCK(&interfaces);
764 AST_LIST_TRAVERSE(&interfaces, curint, list) {
767 interface = ast_strdupa(curint->interface);
768 if ((slash_pos = strchr(interface, '/')))
769 if ((slash_pos = strchr(slash_pos + 1, '/')))
772 if (!strcasecmp(interface, sc->dev))
775 AST_LIST_UNLOCK(&interfaces);
778 if (option_debug > 2)
779 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
784 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
786 update_status(sc->dev, sc->state);
791 static void device_state_cb(const struct ast_event *event, void *unused)
793 enum ast_device_state state;
795 struct statechange *sc;
798 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
799 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
801 if (ast_strlen_zero(device)) {
802 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
805 datapsize = sizeof(*sc) + strlen(device) + 1;
806 if (!(sc = ast_calloc(1, datapsize))) {
807 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
811 strcpy(sc->dev, device);
812 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
817 /*! \brief allocate space for new queue member and set fields based on parameters passed */
818 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
822 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
823 cur->penalty = penalty;
824 cur->paused = paused;
825 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
826 if (!ast_strlen_zero(state_interface))
827 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
829 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
830 if (!ast_strlen_zero(membername))
831 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
833 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
834 if (!strchr(cur->interface, '/'))
835 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
836 cur->status = ast_device_state(cur->state_interface);
843 static int compress_char(const char c)
853 static int member_hash_fn(const void *obj, const int flags)
855 const struct member *mem = obj;
856 const char *chname = strchr(mem->interface, '/');
859 chname = mem->interface;
860 for (i = 0; i < 5 && chname[i]; i++)
861 ret += compress_char(chname[i]) << (i * 6);
865 static int member_cmp_fn(void *obj1, void *obj2, int flags)
867 struct member *mem1 = obj1, *mem2 = obj2;
868 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
872 * \brief Initialize Queue default values.
873 * \note the queue's lock must be held before executing this function
875 static void init_queue(struct call_queue *q)
878 struct penalty_rule *pr_iter;
881 q->retry = DEFAULT_RETRY;
884 q->announcefrequency = 0;
885 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
886 q->announceholdtime = 1;
887 q->announcepositionlimit = 10; /* Default 10 positions */
888 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
889 q->roundingseconds = 0; /* Default - don't announce seconds */
892 q->setinterfacevar = 0;
894 q->setqueueentryvar = 0;
895 q->autofill = autofill_default;
896 q->montype = montype_default;
898 q->reportholdtime = 0;
901 q->leavewhenempty = 0;
903 q->maskmemberstatus = 0;
904 q->eventwhencalled = 0;
906 q->timeoutrestart = 0;
907 q->periodicannouncefrequency = 0;
908 q->randomperiodicannounce = 0;
909 q->numperiodicannounce = 0;
911 if (q->strategy == QUEUE_STRATEGY_LINEAR)
912 /* linear strategy depends on order, so we have to place all members in a single bucket */
913 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
915 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
920 ast_string_field_set(q, sound_next, "queue-youarenext");
921 ast_string_field_set(q, sound_thereare, "queue-thereare");
922 ast_string_field_set(q, sound_calls, "queue-callswaiting");
923 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
924 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
925 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
926 ast_string_field_set(q, sound_minutes, "queue-minutes");
927 ast_string_field_set(q, sound_minute, "queue-minute");
928 ast_string_field_set(q, sound_seconds, "queue-seconds");
929 ast_string_field_set(q, sound_thanks, "queue-thankyou");
930 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
932 if ((q->sound_periodicannounce[0] = ast_str_create(32)))
933 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
935 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
936 if (q->sound_periodicannounce[i])
937 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
940 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
944 static void clear_queue(struct call_queue *q)
947 q->callscompleted = 0;
948 q->callsabandoned = 0;
949 q->callscompletedinsl = 0;
953 static int add_to_interfaces(const char *interface)
955 struct member_interface *curint;
957 AST_LIST_LOCK(&interfaces);
958 AST_LIST_TRAVERSE(&interfaces, curint, list) {
959 if (!strcasecmp(curint->interface, interface))
964 AST_LIST_UNLOCK(&interfaces);
968 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
970 if ((curint = ast_calloc(1, sizeof(*curint)))) {
971 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
972 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
974 AST_LIST_UNLOCK(&interfaces);
979 static int interface_exists_global(const char *interface)
981 struct call_queue *q;
982 struct member *mem, tmpmem;
983 struct ao2_iterator queue_iter, mem_iter;
986 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
987 queue_iter = ao2_iterator_init(queues, 0);
988 while ((q = ao2_iterator_next(&queue_iter))) {
990 mem_iter = ao2_iterator_init(q->members, 0);
991 while ((mem = ao2_iterator_next(&mem_iter))) {
992 if (!strcasecmp(mem->state_interface, interface)) {
1005 static int remove_from_interfaces(const char *interface)
1007 struct member_interface *curint;
1009 if (interface_exists_global(interface))
1012 AST_LIST_LOCK(&interfaces);
1013 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
1014 if (!strcasecmp(curint->interface, interface)) {
1015 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
1016 AST_LIST_REMOVE_CURRENT(list);
1021 AST_LIST_TRAVERSE_SAFE_END;
1022 AST_LIST_UNLOCK(&interfaces);
1027 static void clear_and_free_interfaces(void)
1029 struct member_interface *curint;
1031 AST_LIST_LOCK(&interfaces);
1032 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
1034 AST_LIST_UNLOCK(&interfaces);
1038 * \brief Change queue penalty by adding rule.
1040 * Check rule for errors with time or fomatting, see if rule is relative to rest
1041 * of queue, iterate list of rules to find correct insertion point, insert and return.
1042 * \retval -1 on failure
1043 * \retval 0 on success
1044 * \note Call this with the rule_lists locked
1046 static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
1048 char *timestr, *maxstr, *minstr, *contentdup;
1049 struct penalty_rule *rule = NULL, *rule_iter;
1050 struct rule_list *rl_iter;
1051 int time, inserted = 0;
1053 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
1054 ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum);
1058 contentdup = ast_strdupa(content);
1060 if (!(maxstr = strchr(contentdup, ','))) {
1061 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
1067 timestr = contentdup;
1069 if ((time = atoi(timestr)) < 0) {
1070 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
1077 if ((minstr = strchr(maxstr,',')))
1080 /* The last check will evaluate true if either no penalty change is indicated for a given rule
1081 * OR if a min penalty change is indicated but no max penalty change is */
1082 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
1083 rule->max_relative = 1;
1086 rule->max_value = atoi(maxstr);
1088 if (!ast_strlen_zero(minstr)) {
1089 if (*minstr == '+' || *minstr == '-')
1090 rule->min_relative = 1;
1091 rule->min_value = atoi(minstr);
1092 } else /*there was no minimum specified, so assume this means no change*/
1093 rule->min_relative = 1;
1095 /*We have the rule made, now we need to insert it where it belongs*/
1096 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
1097 if (strcasecmp(rl_iter->name, list_name))
1100 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
1101 if (rule->time < rule_iter->time) {
1102 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
1107 AST_LIST_TRAVERSE_SAFE_END;
1110 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
1117 /*! \brief Configure a queue parameter.
1119 * The failunknown flag is set for config files (and static realtime) to show
1120 * errors for unknown parameters. It is cleared for dynamic realtime to allow
1121 * extra fields in the tables.
1122 * \note For error reporting, line number is passed for .conf static configuration,
1123 * for Realtime queues, linenum is -1.
1125 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
1127 if (!strcasecmp(param, "musicclass") ||
1128 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
1129 ast_string_field_set(q, moh, val);
1130 } else if (!strcasecmp(param, "announce")) {
1131 ast_string_field_set(q, announce, val);
1132 } else if (!strcasecmp(param, "context")) {
1133 ast_string_field_set(q, context, val);
1134 } else if (!strcasecmp(param, "timeout")) {
1135 q->timeout = atoi(val);
1137 q->timeout = DEFAULT_TIMEOUT;
1138 } else if (!strcasecmp(param, "ringinuse")) {
1139 q->ringinuse = ast_true(val);
1140 } else if (!strcasecmp(param, "setinterfacevar")) {
1141 q->setinterfacevar = ast_true(val);
1142 } else if (!strcasecmp(param, "setqueuevar")) {
1143 q->setqueuevar = ast_true(val);
1144 } else if (!strcasecmp(param, "setqueueentryvar")) {
1145 q->setqueueentryvar = ast_true(val);
1146 } else if (!strcasecmp(param, "monitor-format")) {
1147 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
1148 } else if (!strcasecmp(param, "membermacro")) {
1149 ast_string_field_set(q, membermacro, val);
1150 } else if (!strcasecmp(param, "membergosub")) {
1151 ast_string_field_set(q, membergosub, val);
1152 } else if (!strcasecmp(param, "queue-youarenext")) {
1153 ast_string_field_set(q, sound_next, val);
1154 } else if (!strcasecmp(param, "queue-thereare")) {
1155 ast_string_field_set(q, sound_thereare, val);
1156 } else if (!strcasecmp(param, "queue-callswaiting")) {
1157 ast_string_field_set(q, sound_calls, val);
1158 } else if (!strcasecmp(param, "queue-quantity1")) {
1159 ast_string_field_set(q, queue_quantity1, val);
1160 } else if (!strcasecmp(param, "queue-quantity2")) {
1161 ast_string_field_set(q, queue_quantity2, val);
1162 } else if (!strcasecmp(param, "queue-holdtime")) {
1163 ast_string_field_set(q, sound_holdtime, val);
1164 } else if (!strcasecmp(param, "queue-minutes")) {
1165 ast_string_field_set(q, sound_minutes, val);
1166 } else if (!strcasecmp(param, "queue-minute")) {
1167 ast_string_field_set(q, sound_minute, val);
1168 } else if (!strcasecmp(param, "queue-seconds")) {
1169 ast_string_field_set(q, sound_seconds, val);
1170 } else if (!strcasecmp(param, "queue-thankyou")) {
1171 ast_string_field_set(q, sound_thanks, val);
1172 } else if (!strcasecmp(param, "queue-callerannounce")) {
1173 ast_string_field_set(q, sound_callerannounce, val);
1174 } else if (!strcasecmp(param, "queue-reporthold")) {
1175 ast_string_field_set(q, sound_reporthold, val);
1176 } else if (!strcasecmp(param, "announce-frequency")) {
1177 q->announcefrequency = atoi(val);
1178 } else if (!strcasecmp(param, "min-announce-frequency")) {
1179 q->minannouncefrequency = atoi(val);
1180 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
1181 } else if (!strcasecmp(param, "announce-round-seconds")) {
1182 q->roundingseconds = atoi(val);
1183 /* Rounding to any other values just doesn't make sense... */
1184 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
1185 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
1187 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1188 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1189 val, param, q->name, linenum);
1191 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1192 "using 0 instead for queue '%s'\n", val, param, q->name);
1194 q->roundingseconds=0;
1196 } else if (!strcasecmp(param, "announce-holdtime")) {
1197 if (!strcasecmp(val, "once"))
1198 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1199 else if (ast_true(val))
1200 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1202 q->announceholdtime = 0;
1203 } else if (!strcasecmp(param, "announce-position")) {
1204 if (!strcasecmp(val, "limit"))
1205 q->announceposition = ANNOUNCEPOSITION_LIMIT;
1206 else if (!strcasecmp(val, "more"))
1207 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
1208 else if (ast_true(val))
1209 q->announceposition = ANNOUNCEPOSITION_YES;
1211 q->announceposition = ANNOUNCEPOSITION_NO;
1212 } else if (!strcasecmp(param, "announce-position-limit")) {
1213 q->announcepositionlimit = atoi(val);
1214 } else if (!strcasecmp(param, "periodic-announce")) {
1215 if (strchr(val, ',')) {
1216 char *s, *buf = ast_strdupa(val);
1219 while ((s = strsep(&buf, ",|"))) {
1220 if (!q->sound_periodicannounce[i])
1221 q->sound_periodicannounce[i] = ast_str_create(16);
1222 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
1224 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1227 q->numperiodicannounce = i;
1229 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
1230 q->numperiodicannounce = 1;
1232 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1233 q->periodicannouncefrequency = atoi(val);
1234 } else if (!strcasecmp(param, "random-periodic-announce")) {
1235 q->randomperiodicannounce = ast_true(val);
1236 } else if (!strcasecmp(param, "retry")) {
1237 q->retry = atoi(val);
1239 q->retry = DEFAULT_RETRY;
1240 } else if (!strcasecmp(param, "wrapuptime")) {
1241 q->wrapuptime = atoi(val);
1242 } else if (!strcasecmp(param, "autofill")) {
1243 q->autofill = ast_true(val);
1244 } else if (!strcasecmp(param, "monitor-type")) {
1245 if (!strcasecmp(val, "mixmonitor"))
1247 } else if (!strcasecmp(param, "autopause")) {
1248 q->autopause = ast_true(val);
1249 } else if (!strcasecmp(param, "maxlen")) {
1250 q->maxlen = atoi(val);
1253 } else if (!strcasecmp(param, "servicelevel")) {
1254 q->servicelevel= atoi(val);
1255 } else if (!strcasecmp(param, "strategy")) {
1256 /* We already have set this, no need to do it again */
1258 } else if (!strcasecmp(param, "joinempty")) {
1259 if (!strcasecmp(val, "loose"))
1260 q->joinempty = QUEUE_EMPTY_LOOSE;
1261 else if (!strcasecmp(val, "strict"))
1262 q->joinempty = QUEUE_EMPTY_STRICT;
1263 else if (ast_true(val))
1264 q->joinempty = QUEUE_EMPTY_NORMAL;
1267 } else if (!strcasecmp(param, "leavewhenempty")) {
1268 if (!strcasecmp(val, "loose"))
1269 q->leavewhenempty = QUEUE_EMPTY_LOOSE;
1270 else if (!strcasecmp(val, "strict"))
1271 q->leavewhenempty = QUEUE_EMPTY_STRICT;
1272 else if (ast_true(val))
1273 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
1275 q->leavewhenempty = 0;
1276 } else if (!strcasecmp(param, "eventmemberstatus")) {
1277 q->maskmemberstatus = !ast_true(val);
1278 } else if (!strcasecmp(param, "eventwhencalled")) {
1279 if (!strcasecmp(val, "vars")) {
1280 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1282 q->eventwhencalled = ast_true(val) ? 1 : 0;
1284 } else if (!strcasecmp(param, "reportholdtime")) {
1285 q->reportholdtime = ast_true(val);
1286 } else if (!strcasecmp(param, "memberdelay")) {
1287 q->memberdelay = atoi(val);
1288 } else if (!strcasecmp(param, "weight")) {
1289 q->weight = atoi(val);
1292 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1293 we will not see any effect on use_weight until next reload. */
1294 } else if (!strcasecmp(param, "timeoutrestart")) {
1295 q->timeoutrestart = ast_true(val);
1296 } else if (!strcasecmp(param, "defaultrule")) {
1297 ast_string_field_set(q, defaultrule, val);
1298 } else if (failunknown) {
1300 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1301 q->name, param, linenum);
1303 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1309 * \brief Find rt member record to update otherwise create one.
1311 * Search for member in queue, if found update penalty/paused state,
1312 * if no memeber exists create one flag it as a RT member and add to queue member list.
1314 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *rt_uniqueid, const char *membername, const char *penalty_str, const char *paused_str, const char* state_interface)
1317 struct ao2_iterator mem_iter;
1323 penalty = atoi(penalty_str);
1329 paused = atoi(paused_str);
1334 /* Find member by realtime uniqueid and update */
1335 mem_iter = ao2_iterator_init(q->members, 0);
1336 while ((m = ao2_iterator_next(&mem_iter))) {
1337 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
1338 m->dead = 0; /* Do not delete this one. */
1339 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1342 if (strcasecmp(state_interface, m->state_interface)) {
1343 remove_from_interfaces(m->state_interface);
1344 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
1345 add_to_interfaces(m->state_interface);
1347 m->penalty = penalty;
1355 /* Create a new member */
1357 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
1360 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1361 add_to_interfaces(m->state_interface);
1362 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", "");
1363 ao2_link(q->members, m);
1371 /*! \brief Iterate through queue's member list and delete them */
1372 static void free_members(struct call_queue *q, int all)
1374 /* Free non-dynamic members */
1376 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1378 while ((cur = ao2_iterator_next(&mem_iter))) {
1379 if (all || !cur->dynamic) {
1380 ao2_unlink(q->members, cur);
1381 remove_from_interfaces(cur->state_interface);
1388 /*! \brief Free queue's member list then its string fields */
1389 static void destroy_queue(void *obj)
1391 struct call_queue *q = obj;
1395 ast_string_field_free_memory(q);
1396 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1397 if (q->sound_periodicannounce[i])
1398 free(q->sound_periodicannounce[i]);
1400 ao2_ref(q->members, -1);
1403 static struct call_queue *alloc_queue(const char *queuename)
1405 struct call_queue *q;
1407 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
1408 if (ast_string_field_init(q, 64)) {
1412 ast_string_field_set(q, name, queuename);
1418 * \brief Reload a single queue via realtime.
1420 * Check for statically defined queue first, check if deleted RT queue,
1421 * check for new RT queue, if queue vars are not defined init them with defaults.
1422 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
1423 * \retval the queue,
1424 * \retval NULL if it doesn't exist.
1425 * \note Should be called with the "queues" container locked.
1427 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1429 struct ast_variable *v;
1430 struct call_queue *q, tmpq = {
1434 struct ao2_iterator mem_iter;
1435 char *interface = NULL;
1436 const char *tmp_name;
1438 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1440 /* Static queues override realtime. */
1441 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
1449 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1455 } else if (!member_config)
1456 /* Not found in the list, and it's not realtime ... */
1459 /* Check if queue is defined in realtime. */
1461 /* Delete queue from in-core list if it has been deleted in realtime. */
1463 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1464 found condition... So we might delete an in-core queue
1465 in case of DB failure. */
1466 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1469 /* Delete if unused (else will be deleted when last caller leaves). */
1470 ao2_unlink(queues, q);
1477 /* Create a new queue if an in-core entry does not exist yet. */
1479 struct ast_variable *tmpvar = NULL;
1480 if (!(q = alloc_queue(queuename)))
1485 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
1486 * will allocate the members properly
1488 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
1489 if (!strcasecmp(tmpvar->name, "strategy")) {
1490 q->strategy = strat2int(tmpvar->value);
1491 if (q->strategy < 0) {
1492 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1493 tmpvar->value, q->name);
1494 q->strategy = QUEUE_STRATEGY_RINGALL;
1499 /* We traversed all variables and didn't find a strategy */
1501 q->strategy = QUEUE_STRATEGY_RINGALL;
1502 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1503 ao2_link(queues, q);
1506 memset(tmpbuf, 0, sizeof(tmpbuf));
1507 for (v = queue_vars; v; v = v->next) {
1508 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1509 if ((tmp = strchr(v->name, '_'))) {
1510 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1513 while ((tmp = strchr(tmp, '_')))
1518 if (!ast_strlen_zero(v->value)) {
1519 /* Don't want to try to set the option if the value is empty */
1520 queue_set_param(q, tmp_name, v->value, -1, 0);
1524 /* Temporarily set realtime members dead so we can detect deleted ones.
1525 * Also set the membercount correctly for realtime*/
1526 mem_iter = ao2_iterator_init(q->members, 0);
1527 while ((m = ao2_iterator_next(&mem_iter))) {
1534 while ((interface = ast_category_browse(member_config, interface))) {
1535 rt_handle_member_record(q, interface,
1536 ast_variable_retrieve(member_config, interface, "uniqueid"),
1537 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
1538 ast_variable_retrieve(member_config, interface, "penalty"),
1539 ast_variable_retrieve(member_config, interface, "paused"),
1540 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
1543 /* Delete all realtime members that have been deleted in DB. */
1544 mem_iter = ao2_iterator_init(q->members, 0);
1545 while ((m = ao2_iterator_next(&mem_iter))) {
1547 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
1548 ao2_unlink(q->members, m);
1549 remove_from_interfaces(m->state_interface);
1560 static struct call_queue *load_realtime_queue(const char *queuename)
1562 struct ast_variable *queue_vars;
1563 struct ast_config *member_config = NULL;
1564 struct call_queue *q = NULL, tmpq = {
1568 /* Find the queue in the in-core list first. */
1569 q = ao2_find(queues, &tmpq, OBJ_POINTER);
1571 if (!q || q->realtime) {
1572 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
1573 queue operations while waiting for the DB.
1575 This will be two separate database transactions, so we might
1576 see queue parameters as they were before another process
1577 changed the queue and member list as it was after the change.
1578 Thus we might see an empty member list when a queue is
1579 deleted. In practise, this is unlikely to cause a problem. */
1581 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1583 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1584 if (!member_config) {
1585 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1586 ast_variables_destroy(queue_vars);
1592 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1594 ast_config_destroy(member_config);
1596 ast_variables_destroy(queue_vars);
1600 update_realtime_members(q);
1605 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
1609 if (ast_strlen_zero(mem->rt_uniqueid))
1612 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, NULL)) > 0)
1619 static void update_realtime_members(struct call_queue *q)
1621 struct ast_config *member_config = NULL;
1623 char *interface = NULL;
1624 struct ao2_iterator mem_iter;
1626 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) {
1627 /*This queue doesn't have realtime members*/
1628 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
1634 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1635 mem_iter = ao2_iterator_init(q->members, 0);
1636 while ((m = ao2_iterator_next(&mem_iter))) {
1642 while ((interface = ast_category_browse(member_config, interface))) {
1643 rt_handle_member_record(q, interface,
1644 ast_variable_retrieve(member_config, interface, "uniqueid"),
1645 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1646 ast_variable_retrieve(member_config, interface, "penalty"),
1647 ast_variable_retrieve(member_config, interface, "paused"),
1648 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
1651 /* Delete all realtime members that have been deleted in DB. */
1652 mem_iter = ao2_iterator_init(q->members, 0);
1653 while ((m = ao2_iterator_next(&mem_iter))) {
1655 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
1656 ao2_unlink(q->members, m);
1657 remove_from_interfaces(m->state_interface);
1663 ast_config_destroy(member_config);
1666 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1668 struct call_queue *q;
1669 struct queue_ent *cur, *prev = NULL;
1673 enum queue_member_status stat;
1675 if (!(q = load_realtime_queue(queuename)))
1681 /* This is our one */
1682 stat = get_member_status(q, qe->max_penalty, qe->min_penalty);
1683 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1684 *reason = QUEUE_JOINEMPTY;
1685 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
1686 *reason = QUEUE_JOINUNAVAIL;
1687 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
1688 *reason = QUEUE_JOINUNAVAIL;
1689 else if (q->maxlen && (q->count >= q->maxlen))
1690 *reason = QUEUE_FULL;
1692 /* There's space for us, put us at the right position inside
1694 * Take into account the priority of the calling user */
1699 /* We have higher priority than the current user, enter
1700 * before him, after all the other users with priority
1701 * higher or equal to our priority. */
1702 if ((!inserted) && (qe->prio > cur->prio)) {
1703 insert_entry(q, prev, qe, &pos);
1710 /* No luck, join at the end of the queue */
1712 insert_entry(q, prev, qe, &pos);
1713 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1714 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1715 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1718 manager_event(EVENT_FLAG_CALL, "Join",
1719 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1721 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1722 S_OR(qe->chan->cid.cid_name, "unknown"),
1723 q->name, qe->pos, q->count, qe->chan->uniqueid );
1724 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1732 static int play_file(struct ast_channel *chan, const char *filename)
1736 ast_stopstream(chan);
1738 res = ast_streamfile(chan, filename, chan->language);
1740 res = ast_waitstream(chan, AST_DIGIT_ANY);
1742 ast_stopstream(chan);
1748 * \brief Check for valid exit from queue via goto
1749 * \retval 0 if failure
1750 * \retval 1 if successful
1752 static int valid_exit(struct queue_ent *qe, char digit)
1754 int digitlen = strlen(qe->digits);
1756 /* Prevent possible buffer overflow */
1757 if (digitlen < sizeof(qe->digits) - 2) {
1758 qe->digits[digitlen] = digit;
1759 qe->digits[digitlen + 1] = '\0';
1761 qe->digits[0] = '\0';
1765 /* If there's no context to goto, short-circuit */
1766 if (ast_strlen_zero(qe->context))
1769 /* If the extension is bad, then reset the digits to blank */
1770 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1771 qe->digits[0] = '\0';
1775 /* We have an exact match */
1776 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1777 qe->valid_digits = 1;
1778 /* Return 1 on a successful goto */
1785 static int say_position(struct queue_ent *qe, int ringing)
1787 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
1790 /* Let minannouncefrequency seconds pass between the start of each position announcement */
1792 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
1795 /* If either our position has changed, or we are over the freq timer, say position */
1796 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1800 ast_indicate(qe->chan,-1);
1802 ast_moh_stop(qe->chan);
1805 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
1806 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
1807 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
1808 qe->pos <= qe->parent->announcepositionlimit))
1809 announceposition = 1;
1812 if (announceposition == 1) {
1813 /* Say we're next, if we are */
1815 res = play_file(qe->chan, qe->parent->sound_next);
1821 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
1823 res = play_file(qe->chan, qe->parent->queue_quantity1);
1826 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
1831 res = play_file(qe->chan, qe->parent->sound_thereare);
1834 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
1838 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
1840 res = play_file(qe->chan, qe->parent->queue_quantity2);
1844 res = play_file(qe->chan, qe->parent->sound_calls);
1850 /* Round hold time to nearest minute */
1851 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1853 /* If they have specified a rounding then round the seconds as well */
1854 if (qe->parent->roundingseconds) {
1855 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1856 avgholdsecs *= qe->parent->roundingseconds;
1861 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1863 /* If the hold time is >1 min, if it's enabled, and if it's not
1864 supposed to be only once and we have already said it, say it */
1865 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
1866 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
1867 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
1868 res = play_file(qe->chan, qe->parent->sound_holdtime);
1872 if (avgholdmins > 1) {
1873 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1877 if (avgholdmins == 1) {
1878 res = play_file(qe->chan, qe->parent->sound_minute);
1882 res = play_file(qe->chan, qe->parent->sound_minutes);
1887 if (avgholdsecs > 1) {
1888 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1892 res = play_file(qe->chan, qe->parent->sound_seconds);
1900 if (announceposition == 1){
1901 if (qe->parent->announceposition) {
1902 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
1903 qe->chan->name, qe->parent->name, qe->pos);
1905 res = play_file(qe->chan, qe->parent->sound_thanks);
1908 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
1911 /* Set our last_pos indicators */
1913 qe->last_pos_said = qe->pos;
1915 /* Don't restart music on hold if we're about to exit the caller from the queue */
1918 ast_indicate(qe->chan, AST_CONTROL_RINGING);
1920 ast_moh_start(qe->chan, qe->moh, NULL);
1926 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
1930 /* Calculate holdtime using an exponential average */
1931 /* Thanks to SRT for this contribution */
1932 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1934 ao2_lock(qe->parent);
1935 oldvalue = qe->parent->holdtime;
1936 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
1937 ao2_unlock(qe->parent);
1940 /*! \brief Caller leaving queue.
1942 * Search the queue to find the leaving client, if found remove from queue
1943 * create manager event, move others up the queue.
1945 static void leave_queue(struct queue_ent *qe)
1947 struct call_queue *q;
1948 struct queue_ent *cur, *prev = NULL;
1949 struct penalty_rule *pr_iter;
1952 if (!(q = qe->parent))
1958 for (cur = q->head; cur; cur = cur->next) {
1962 /* Take us out of the queue */
1963 manager_event(EVENT_FLAG_CALL, "Leave",
1964 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1965 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1966 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1967 /* Take us out of the queue */
1969 prev->next = cur->next;
1971 q->head = cur->next;
1972 /* Free penalty rules */
1973 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
1976 /* Renumber the people after us in the queue based on a new count */
1983 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
1985 if (!ast_load_realtime("queues", "name", q->name, NULL))
1990 /* It's dead and nobody is in it, so kill it */
1991 ao2_unlink(queues, q);
1992 /* unref the container's reference to the queue */
1995 /* unref the explicit ref earlier in the function */
1999 /*! \brief Hang up a list of outgoing calls */
2000 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
2002 struct callattempt *oo;
2005 /* Hangup any existing lines we have open */
2006 if (outgoing->chan && (outgoing->chan != exception))
2007 ast_hangup(outgoing->chan);
2009 outgoing = outgoing->q_next;
2011 ao2_ref(oo->member, -1);
2017 * \brief traverse all defined queues which have calls waiting and contain this member
2018 * \retval 0 if no other queue has precedence (higher weight)
2019 * \retval 1 if found
2021 static int compare_weight(struct call_queue *rq, struct member *member)
2023 struct call_queue *q;
2026 struct ao2_iterator queue_iter;
2028 /* q's lock and rq's lock already set by try_calling()
2029 * to solve deadlock */
2030 queue_iter = ao2_iterator_init(queues, 0);
2031 while ((q = ao2_iterator_next(&queue_iter))) {
2032 if (q == rq) { /* don't check myself, could deadlock */
2037 if (q->count && q->members) {
2038 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
2039 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
2040 if (q->weight > rq->weight) {
2041 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);
2057 /*! \brief common hangup actions */
2058 static void do_hang(struct callattempt *o)
2061 ast_hangup(o->chan);
2065 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
2066 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
2068 struct ast_str *buf = ast_str_alloca(len + 1);
2071 if (pbx_builtin_serialize_variables(chan, &buf)) {
2074 /* convert "\n" to "\nVariable: " */
2075 strcpy(vars, "Variable: ");
2078 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
2081 if (tmp[i + 1] == '\0')
2083 if (tmp[i] == '\n') {
2087 ast_copy_string(&(vars[j]), "Variable: ", len - j);
2097 /* there are no channel variables; leave it blank */
2104 * \brief Part 2 of ring_one
2106 * Does error checking before attempting to request a channel and call a member.
2107 * This function is only called from ring_one().
2108 * Failure can occur if:
2111 * - Wrapup time not expired
2112 * - Priority by another queue
2114 * \retval 1 on success to reach a free agent
2115 * \retval 0 on failure to get agent.
2117 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
2123 const char *macrocontext, *macroexten;
2125 /* on entry here, we know that tmp->chan == NULL */
2126 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
2127 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
2128 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
2129 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
2131 ast_cdr_busy(qe->chan->cdr);
2132 tmp->stillgoing = 0;
2137 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
2138 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
2140 ast_cdr_busy(qe->chan->cdr);
2141 tmp->stillgoing = 0;
2145 if (tmp->member->paused) {
2146 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
2148 ast_cdr_busy(qe->chan->cdr);
2149 tmp->stillgoing = 0;
2152 if (use_weight && compare_weight(qe->parent,tmp->member)) {
2153 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
2155 ast_cdr_busy(qe->chan->cdr);
2156 tmp->stillgoing = 0;
2161 ast_copy_string(tech, tmp->interface, sizeof(tech));
2162 if ((location = strchr(tech, '/')))
2167 /* Request the peer */
2168 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
2169 if (!tmp->chan) { /* If we can't, just go on to the next call */
2171 ast_cdr_busy(qe->chan->cdr);
2172 tmp->stillgoing = 0;
2174 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
2176 ao2_lock(qe->parent);
2177 qe->parent->rrpos++;
2179 ao2_unlock(qe->parent);
2186 tmp->chan->appl = "AppQueue";
2187 tmp->chan->data = "(Outgoing Line)";
2188 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
2189 if (tmp->chan->cid.cid_num)
2190 ast_free(tmp->chan->cid.cid_num);
2191 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
2192 if (tmp->chan->cid.cid_name)
2193 ast_free(tmp->chan->cid.cid_name);
2194 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
2195 if (tmp->chan->cid.cid_ani)
2196 ast_free(tmp->chan->cid.cid_ani);
2197 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
2199 /* Inherit specially named variables from parent channel */
2200 ast_channel_inherit_variables(qe->chan, tmp->chan);
2202 /* Presense of ADSI CPE on outgoing channel follows ours */
2203 tmp->chan->adsicpe = qe->chan->adsicpe;
2205 /* Inherit context and extension */
2206 ast_channel_lock(qe->chan);
2207 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
2208 if (!ast_strlen_zero(macrocontext))
2209 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
2211 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
2212 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
2213 if (!ast_strlen_zero(macroexten))
2214 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
2216 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
2217 ast_channel_unlock(qe->chan);
2219 /* Place the call, but don't wait on the answer */
2220 if ((res = ast_call(tmp->chan, location, 0))) {
2221 /* Again, keep going even if there's an error */
2222 ast_debug(1, "ast call on peer returned %d\n", res);
2223 ast_verb(3, "Couldn't call %s\n", tmp->interface);
2227 } else if (qe->parent->eventwhencalled) {
2230 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
2232 "AgentCalled: %s\r\n"
2234 "ChannelCalling: %s\r\n"
2235 "DestinationChannel: %s\r\n"
2236 "CallerIDNum: %s\r\n"
2237 "CallerIDName: %s\r\n"
2243 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
2244 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
2245 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
2246 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
2247 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2248 ast_verb(3, "Called %s\n", tmp->interface);
2254 /*! \brief find the entry with the best metric, or NULL */
2255 static struct callattempt *find_best(struct callattempt *outgoing)
2257 struct callattempt *best = NULL, *cur;
2259 for (cur = outgoing; cur; cur = cur->q_next) {
2260 if (cur->stillgoing && /* Not already done */
2261 !cur->chan && /* Isn't already going */
2262 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
2271 * \brief Place a call to a queue member.
2273 * Once metrics have been calculated for each member, this function is used
2274 * to place a call to the appropriate member (or members). The low-level
2275 * channel-handling and error detection is handled in ring_entry
2277 * \retval 1 if a member was called successfully
2278 * \retval 0 otherwise
2280 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
2285 struct callattempt *best = find_best(outgoing);
2287 ast_debug(1, "Nobody left to try ringing in queue\n");
2290 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2291 struct callattempt *cur;
2292 /* Ring everyone who shares this best metric (for ringall) */
2293 for (cur = outgoing; cur; cur = cur->q_next) {
2294 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
2295 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
2296 ret |= ring_entry(qe, cur, busies);
2300 /* Ring just the best channel */
2301 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
2302 ret = ring_entry(qe, best, busies);
2309 /*! \brief Search for best metric and add to Round Robbin queue */
2310 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
2312 struct callattempt *best = find_best(outgoing);
2315 /* Ring just the best channel */
2316 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2317 qe->parent->rrpos = best->metric % 1000;
2319 /* Just increment rrpos */
2320 if (qe->parent->wrapped) {
2321 /* No more channels, start over */
2322 qe->parent->rrpos = 0;
2324 /* Prioritize next entry */
2325 qe->parent->rrpos++;
2328 qe->parent->wrapped = 0;
2333 /*! \brief Search for best metric and add to Linear queue */
2334 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
2336 struct callattempt *best = find_best(outgoing);
2339 /* Ring just the best channel */
2340 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2341 qe->linpos = best->metric % 1000;
2343 /* Just increment rrpos */
2344 if (qe->linwrapped) {
2345 /* No more channels, start over */
2348 /* Prioritize next entry */
2357 /*! \brief Playback announcement to queued members if peroid has elapsed */
2358 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
2363 /* Get the current time */
2366 /* Check to see if it is time to announce */
2367 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2370 /* Stop the music on hold so we can play our own file */
2372 ast_indicate(qe->chan,-1);
2374 ast_moh_stop(qe->chan);
2376 ast_verb(3, "Playing periodic announcement\n");
2378 if (qe->parent->randomperiodicannounce) {
2379 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
2380 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
2381 ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) {
2382 qe->last_periodic_announce_sound = 0;
2385 /* play the announcement */
2386 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str);
2388 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2391 /* Resume Music on Hold if the caller is going to stay in the queue */
2394 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2396 ast_moh_start(qe->chan, qe->moh, NULL);
2399 /* update last_periodic_announce_time */
2400 qe->last_periodic_announce_time = now;
2402 /* Update the current periodic announcement to the next announcement */
2403 if (!qe->parent->randomperiodicannounce) {
2404 qe->last_periodic_announce_sound++;
2410 /*! \brief Record that a caller gave up on waiting in queue */
2411 static void record_abandoned(struct queue_ent *qe)
2413 ao2_lock(qe->parent);
2414 set_queue_variables(qe);
2415 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2419 "OriginalPosition: %d\r\n"
2421 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2423 qe->parent->callsabandoned++;
2424 ao2_unlock(qe->parent);
2427 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2428 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2430 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
2431 if (qe->parent->eventwhencalled)
2432 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
2437 "MemberName: %s\r\n"
2445 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2446 if (qe->parent->autopause) {
2447 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
2448 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2450 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2456 #define AST_MAX_WATCHERS 256
2457 /*! \brief Wait for a member to answer the call
2459 * \param[in] qe the queue_ent corresponding to the caller in the queue
2460 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
2461 * \param[in] to the amount of time (in milliseconds) to wait for a response
2462 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
2463 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
2464 * \param[in] caller_disconnect if the 'H' option is used when calling Queue(), this is used to detect if the caller pressed * to disconnect the call
2465 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
2467 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2469 const char *queue = qe->parent->name;
2470 struct callattempt *o, *start = NULL, *prev = NULL;
2472 int numbusies = prebusies;
2476 struct ast_frame *f;
2477 struct callattempt *peer = NULL;
2478 struct ast_channel *winner;
2479 struct ast_channel *in = qe->chan;
2481 char membername[80] = "";
2485 struct callattempt *epollo;
2488 starttime = (long) time(NULL);
2490 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2492 ast_poll_channel_add(in, epollo->chan);
2496 while (*to && !peer) {
2497 int numlines, retry, pos = 1;
2498 struct ast_channel *watchers[AST_MAX_WATCHERS];
2502 for (retry = 0; retry < 2; retry++) {
2504 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2505 if (o->stillgoing) { /* Keep track of important channels */
2508 watchers[pos++] = o->chan;
2512 prev->call_next = o;
2518 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2519 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2521 /* On "ringall" strategy we only move to the next penalty level
2522 when *all* ringing phones are done in the current penalty level */
2523 ring_one(qe, outgoing, &numbusies);
2526 if (pos == 1 /* not found */) {
2527 if (numlines == (numbusies + numnochan)) {
2528 ast_debug(1, "Everyone is busy at this time\n");
2530 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2535 winner = ast_waitfor_n(watchers, pos, to);
2536 for (o = start; o; o = o->call_next) {
2537 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2539 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2542 } else if (o->chan && (o->chan == winner)) {
2544 ast_copy_string(on, o->member->interface, sizeof(on));
2545 ast_copy_string(membername, o->member->membername, sizeof(membername));
2547 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2548 ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2553 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2558 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2559 if ((stuff = strchr(tmpchan, '/'))) {
2563 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2567 /* Before processing channel, go ahead and check for forwarding */
2568 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2569 /* Setup parameters */
2570 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2572 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2576 ast_channel_inherit_variables(in, o->chan);
2577 ast_channel_datastore_inherit(in, o->chan);
2578 if (o->chan->cid.cid_num)
2579 ast_free(o->chan->cid.cid_num);
2580 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2582 if (o->chan->cid.cid_name)
2583 ast_free(o->chan->cid.cid_name);
2584 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2586 ast_string_field_set(o->chan, accountcode, in->accountcode);
2587 o->chan->cdrflags = in->cdrflags;
2589 if (in->cid.cid_ani) {
2590 if (o->chan->cid.cid_ani)
2591 ast_free(o->chan->cid.cid_ani);
2592 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2594 if (o->chan->cid.cid_rdnis)
2595 ast_free(o->chan->cid.cid_rdnis);
2596 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2597 if (ast_call(o->chan, tmpchan, 0)) {
2598 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2603 /* Hangup the original channel now, in case we needed it */
2607 f = ast_read(winner);
2609 if (f->frametype == AST_FRAME_CONTROL) {
2610 switch (f->subclass) {
2611 case AST_CONTROL_ANSWER:
2612 /* This is our guy if someone answered. */
2614 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2618 case AST_CONTROL_BUSY:
2619 ast_verb(3, "%s is busy\n", o->chan->name);
2621 ast_cdr_busy(in->cdr);
2623 endtime = (long) time(NULL);
2624 endtime -= starttime;
2625 rna(endtime*1000, qe, on, membername);
2626 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2627 if (qe->parent->timeoutrestart)
2629 ring_one(qe, outgoing, &numbusies);
2633 case AST_CONTROL_CONGESTION:
2634 ast_verb(3, "%s is circuit-busy\n", o->chan->name);
2636 ast_cdr_busy(in->cdr);
2637 endtime = (long) time(NULL);
2638 endtime -= starttime;
2639 rna(endtime*1000, qe, on, membername);
2641 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2642 if (qe->parent->timeoutrestart)
2644 ring_one(qe, outgoing, &numbusies);
2648 case AST_CONTROL_RINGING:
2649 ast_verb(3, "%s is ringing\n", o->chan->name);
2651 case AST_CONTROL_OFFHOOK:
2652 /* Ignore going off hook */
2655 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
2660 endtime = (long) time(NULL) - starttime;
2661 rna(endtime * 1000, qe, on, membername);
2663 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2664 if (qe->parent->timeoutrestart)
2666 ring_one(qe, outgoing, &numbusies);
2673 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2677 if (f->data.uint32) {
2678 in->hangupcause = f->data.uint32;
2684 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2685 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
2690 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2691 ast_verb(3, "User pressed digit: %c\n", f->subclass);
2693 *digit = f->subclass;
2700 for (o = start; o; o = o->call_next)
2701 rna(orig, qe, o->interface, o->member->membername);
2706 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2708 ast_poll_channel_del(in, epollo->chan);
2716 * \brief Check if we should start attempting to call queue members.
2718 * The behavior of this function is dependent first on whether autofill is enabled
2719 * and second on whether the ring strategy is ringall. If autofill is not enabled,
2720 * then return true if we're the head of the queue. If autofill is enabled, then
2721 * we count the available members and see if the number of available members is enough
2722 * that given our position in the queue, we would theoretically be able to connect to
2723 * one of those available members
2725 static int is_our_turn(struct queue_ent *qe)
2727 struct queue_ent *ch;
2733 if (!qe->parent->autofill) {
2734 /* Atomically read the parent head -- does not need a lock */
2735 ch = qe->parent->head;
2736 /* If we are now at the top of the head, break out */
2738 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2741 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2746 /* This needs a lock. How many members are available to be served? */
2747 ao2_lock(qe->parent);
2749 ch = qe->parent->head;
2751 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2752 ast_debug(1, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
2755 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2756 while ((cur = ao2_iterator_next(&mem_iter))) {
2757 switch (cur->status) {
2758 case AST_DEVICE_INUSE:
2759 if (!qe->parent->ringinuse)
2761 /* else fall through */
2762 case AST_DEVICE_NOT_INUSE:
2763 case AST_DEVICE_UNKNOWN:
2772 ast_debug(1, "There are %d available members.\n", avl);
2774 while ((idx < avl) && (ch) && (ch != qe)) {
2780 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2781 if (ch && idx < avl) {
2782 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2785 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2789 ao2_unlock(qe->parent);
2796 * \brief update rules for queues
2798 * Calculate min/max penalties making sure if relative they stay within bounds.
2799 * Update queues penalty and set dialplan vars, goto next list entry.
2801 static void update_qe_rule(struct queue_ent *qe)
2803 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
2804 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
2805 char max_penalty_str[20], min_penalty_str[20];
2806 /* a relative change to the penalty could put it below 0 */
2807 if (max_penalty < 0)
2809 if (min_penalty < 0)
2811 if (min_penalty > max_penalty)
2812 min_penalty = max_penalty;
2813 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
2814 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
2815 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
2816 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
2817 qe->max_penalty = max_penalty;
2818 qe->min_penalty = min_penalty;
2819 ast_debug(3, "Setting max penalty to %d and min penalty to %d for caller %s since %d seconds have elapsed\n", qe->max_penalty, qe->min_penalty, qe->chan->name, qe->pr->time);
2820 qe->pr = AST_LIST_NEXT(qe->pr, list);
2823 /*! \brief The waiting areas for callers who are not actively calling members
2825 * This function is one large loop. This function will return if a caller
2826 * either exits the queue or it becomes that caller's turn to attempt calling
2827 * queue members. Inside the loop, we service the caller with periodic announcements,
2828 * holdtime announcements, etc. as configured in queues.conf
2830 * \retval 0 if the caller's turn has arrived
2831 * \retval -1 if the caller should exit the queue.
2833 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2837 /* This is the holding pen for callers 2 through maxlen */
2839 enum queue_member_status stat;
2841 if (is_our_turn(qe))
2844 /* If we have timed out, break out */
2845 if (qe->expire && (time(NULL) > qe->expire)) {
2846 *reason = QUEUE_TIMEOUT;
2850 stat = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty);
2852 /* leave the queue if no agents, if enabled */
2853 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2854 *reason = QUEUE_LEAVEEMPTY;
2855 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2860 /* leave the queue if no reachable agents, if enabled */
2861 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2862 *reason = QUEUE_LEAVEUNAVAIL;
2863 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2867 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2868 *reason = QUEUE_LEAVEUNAVAIL;
2869 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2874 /* Make a position announcement, if enabled */
2875 if (qe->parent->announcefrequency &&
2876 (res = say_position(qe,ringing)))
2879 /* Make a periodic announcement, if enabled */
2880 if (qe->parent->periodicannouncefrequency &&
2881 (res = say_periodic_announcement(qe,ringing)))
2884 /* see if we need to move to the next penalty level for this queue */
2885 while (qe->pr && ((time(NULL) - qe->start) > qe->pr->time)) {
2889 /* Wait a second before checking again */
2890 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
2891 if (res > 0 && !valid_exit(qe, res))
2902 * \brief update the queue status
2905 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
2908 struct call_queue *qtmp;
2909 struct ao2_iterator queue_iter;
2911 if (shared_lastcall) {
2912 queue_iter = ao2_iterator_init(queues, 0);
2913 while ((qtmp = ao2_iterator_next(&queue_iter))) {
2915 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
2916 time(&mem->lastcall);
2926 time(&member->lastcall);
2928 member->lastqueue = q;
2932 q->callscompleted++;
2933 if (callcompletedinsl)
2934 q->callscompletedinsl++;
2939 /*! \brief Calculate the metric of each member in the outgoing callattempts
2941 * A numeric metric is given to each member depending on the ring strategy used
2942 * by the queue. Members with lower metrics will be called before members with
2944 * \retval -1 if penalties are exceeded
2945 * \retval 0 otherwise
2947 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2949 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty)))
2952 switch (q->strategy) {
2953 case QUEUE_STRATEGY_RINGALL:
2954 /* Everyone equal, except for penalty */
2955 tmp->metric = mem->penalty * 1000000;
2957 case QUEUE_STRATEGY_LINEAR:
2958 if (pos < qe->linpos) {
2959 tmp->metric = 1000 + pos;
2961 if (pos > qe->linpos)
2962 /* Indicate there is another priority */
2966 tmp->metric += mem->penalty * 1000000;
2968 case QUEUE_STRATEGY_RRMEMORY:
2969 if (pos < q->rrpos) {
2970 tmp->metric = 1000 + pos;
2973 /* Indicate there is another priority */
2977 tmp->metric += mem->penalty * 1000000;
2979 case QUEUE_STRATEGY_RANDOM:
2980 tmp->metric = ast_random() % 1000;
2981 tmp->metric += mem->penalty * 1000000;
2983 case QUEUE_STRATEGY_WRANDOM:
2984 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
2986 case QUEUE_STRATEGY_FEWESTCALLS:
2987 tmp->metric = mem->calls;
2988 tmp->metric += mem->penalty * 1000000;
2990 case QUEUE_STRATEGY_LEASTRECENT:
2994 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2995 tmp->metric += mem->penalty * 1000000;
2998 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);