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 recursive boxcar filter */
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 /*! \brief sets the QUEUESTATUS channel variable */
533 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
537 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
538 if (queue_results[i].id == res) {
539 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
545 static const char *int2strat(int strategy)
549 for (x = 0; x < ARRAY_LEN(strategies); x++) {
550 if (strategy == strategies[x].strategy)
551 return strategies[x].name;
557 static int strat2int(const char *strategy)
561 for (x = 0; x < ARRAY_LEN(strategies); x++) {
562 if (!strcasecmp(strategy, strategies[x].name))
563 return strategies[x].strategy;
569 static int queue_hash_cb(const void *obj, const int flags)
571 const struct call_queue *q = obj;
572 return ast_str_hash(q->name);
575 static int queue_cmp_cb(void *obj, void *arg, int flags)
577 struct call_queue *q = obj, *q2 = arg;
578 return !strcasecmp(q->name, q2->name) ? CMP_MATCH : 0;
581 static inline struct call_queue *queue_ref(struct call_queue *q)
587 static inline struct call_queue *queue_unref(struct call_queue *q)
593 /*! \brief Set variables of queue */
594 static void set_queue_variables(struct queue_ent *qe)
596 char interfacevar[256]="";
599 if (qe->parent->setqueuevar) {
601 if (qe->parent->callscompleted > 0)
602 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
604 snprintf(interfacevar, sizeof(interfacevar),
605 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
606 qe->parent->name, qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
607 qe->parent->callsabandoned, qe->parent->servicelevel, sl);
609 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
613 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
614 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
616 struct queue_ent *cur;
633 enum queue_member_status {
635 QUEUE_NO_REACHABLE_MEMBERS,
636 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
640 /*! \brief Check if members are available
642 * This function checks to see if members are available to be called. If any member
643 * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
644 * the appropriate reason why is returned
646 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty, int min_penalty)
648 struct member *member;
649 struct ao2_iterator mem_iter;
650 enum queue_member_status result = QUEUE_NO_MEMBERS;
653 mem_iter = ao2_iterator_init(q->members, 0);
654 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
655 if ((max_penalty && (member->penalty > max_penalty)) || (min_penalty && (member->penalty < min_penalty)))
658 switch (member->status) {
659 case AST_DEVICE_INVALID:
662 case AST_DEVICE_UNAVAILABLE:
663 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)
664 result = QUEUE_NO_REACHABLE_MEMBERS;
667 if (member->paused) {
668 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
683 AST_LIST_ENTRY(statechange) entry;
688 /*! \brief set a member's status based on device state of that member's state_interface.
690 * Lock interface list find sc, iterate through each queues queue_member list for member to
691 * update state inside queues
693 static int update_status(const char *interface, const int status)
696 struct ao2_iterator mem_iter, queue_iter;
697 struct call_queue *q;
699 queue_iter = ao2_iterator_init(queues, 0);
700 while ((q = ao2_iterator_next(&queue_iter))) {
702 mem_iter = ao2_iterator_init(q->members, 0);
703 while ((cur = ao2_iterator_next(&mem_iter))) {
706 tmp_interface = ast_strdupa(cur->state_interface);
707 if ((slash_pos = strchr(interface, '/')))
708 if ((slash_pos = strchr(slash_pos + 1, '/')))
711 if (strcasecmp(interface, tmp_interface)) {
716 if (cur->status != status) {
717 cur->status = status;
718 if (q->maskmemberstatus) {
723 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
733 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
734 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
745 /*! \brief set a member's status based on device state of that member's interface*/
746 static int handle_statechange(void *datap)
748 struct member_interface *curint;
751 struct statechange *sc = datap;
753 technology = ast_strdupa(sc->dev);
754 loc = strchr(technology, '/');
762 AST_LIST_LOCK(&interfaces);
763 AST_LIST_TRAVERSE(&interfaces, curint, list) {
766 interface = ast_strdupa(curint->interface);
767 if ((slash_pos = strchr(interface, '/')))
768 if ((slash_pos = strchr(slash_pos + 1, '/')))
771 if (!strcasecmp(interface, sc->dev))
774 AST_LIST_UNLOCK(&interfaces);
777 if (option_debug > 2)
778 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));
783 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
785 update_status(sc->dev, sc->state);
790 static void device_state_cb(const struct ast_event *event, void *unused)
792 enum ast_device_state state;
794 struct statechange *sc;
797 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
798 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
800 if (ast_strlen_zero(device)) {
801 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
804 datapsize = sizeof(*sc) + strlen(device) + 1;
805 if (!(sc = ast_calloc(1, datapsize))) {
806 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
810 strcpy(sc->dev, device);
811 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
816 /*! \brief allocate space for new queue member and set fields based on parameters passed */
817 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
821 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
822 cur->penalty = penalty;
823 cur->paused = paused;
824 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
825 if (!ast_strlen_zero(state_interface))
826 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
828 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
829 if (!ast_strlen_zero(membername))
830 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
832 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
833 if (!strchr(cur->interface, '/'))
834 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
835 cur->status = ast_device_state(cur->state_interface);
842 static int compress_char(const char c)
852 static int member_hash_fn(const void *obj, const int flags)
854 const struct member *mem = obj;
855 const char *chname = strchr(mem->interface, '/');
858 chname = mem->interface;
859 for (i = 0; i < 5 && chname[i]; i++)
860 ret += compress_char(chname[i]) << (i * 6);
864 static int member_cmp_fn(void *obj1, void *obj2, int flags)
866 struct member *mem1 = obj1, *mem2 = obj2;
867 return strcasecmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH;
871 * \brief Initialize Queue default values.
872 * \note the queue's lock must be held before executing this function
874 static void init_queue(struct call_queue *q)
877 struct penalty_rule *pr_iter;
880 q->retry = DEFAULT_RETRY;
883 q->announcefrequency = 0;
884 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
885 q->announceholdtime = 1;
886 q->announcepositionlimit = 10; /* Default 10 positions */
887 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
888 q->roundingseconds = 0; /* Default - don't announce seconds */
891 q->setinterfacevar = 0;
893 q->setqueueentryvar = 0;
894 q->autofill = autofill_default;
895 q->montype = montype_default;
897 q->reportholdtime = 0;
900 q->leavewhenempty = 0;
902 q->maskmemberstatus = 0;
903 q->eventwhencalled = 0;
905 q->timeoutrestart = 0;
906 q->periodicannouncefrequency = 0;
907 q->randomperiodicannounce = 0;
908 q->numperiodicannounce = 0;
910 if (q->strategy == QUEUE_STRATEGY_LINEAR)
911 /* linear strategy depends on order, so we have to place all members in a single bucket */
912 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
914 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
919 ast_string_field_set(q, sound_next, "queue-youarenext");
920 ast_string_field_set(q, sound_thereare, "queue-thereare");
921 ast_string_field_set(q, sound_calls, "queue-callswaiting");
922 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
923 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
924 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
925 ast_string_field_set(q, sound_minutes, "queue-minutes");
926 ast_string_field_set(q, sound_minute, "queue-minute");
927 ast_string_field_set(q, sound_seconds, "queue-seconds");
928 ast_string_field_set(q, sound_thanks, "queue-thankyou");
929 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
931 if ((q->sound_periodicannounce[0] = ast_str_create(32)))
932 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
934 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
935 if (q->sound_periodicannounce[i])
936 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
939 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list)))
943 static void clear_queue(struct call_queue *q)
946 q->callscompleted = 0;
947 q->callsabandoned = 0;
948 q->callscompletedinsl = 0;
952 static int add_to_interfaces(const char *interface)
954 struct member_interface *curint;
956 AST_LIST_LOCK(&interfaces);
957 AST_LIST_TRAVERSE(&interfaces, curint, list) {
958 if (!strcasecmp(curint->interface, interface))
963 AST_LIST_UNLOCK(&interfaces);
967 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
969 if ((curint = ast_calloc(1, sizeof(*curint)))) {
970 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
971 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
973 AST_LIST_UNLOCK(&interfaces);
978 static int interface_exists_global(const char *interface)
980 struct call_queue *q;
981 struct member *mem, tmpmem;
982 struct ao2_iterator queue_iter, mem_iter;
985 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
986 queue_iter = ao2_iterator_init(queues, 0);
987 while ((q = ao2_iterator_next(&queue_iter))) {
989 mem_iter = ao2_iterator_init(q->members, 0);
990 while ((mem = ao2_iterator_next(&mem_iter))) {
991 if (!strcasecmp(mem->state_interface, interface)) {
1004 static int remove_from_interfaces(const char *interface)
1006 struct member_interface *curint;
1008 if (interface_exists_global(interface))
1011 AST_LIST_LOCK(&interfaces);
1012 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
1013 if (!strcasecmp(curint->interface, interface)) {
1014 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
1015 AST_LIST_REMOVE_CURRENT(list);
1020 AST_LIST_TRAVERSE_SAFE_END;
1021 AST_LIST_UNLOCK(&interfaces);
1026 static void clear_and_free_interfaces(void)
1028 struct member_interface *curint;
1030 AST_LIST_LOCK(&interfaces);
1031 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
1033 AST_LIST_UNLOCK(&interfaces);
1037 * \brief Change queue penalty by adding rule.
1039 * Check rule for errors with time or fomatting, see if rule is relative to rest
1040 * of queue, iterate list of rules to find correct insertion point, insert and return.
1041 * \retval -1 on failure
1042 * \retval 0 on success
1043 * \note Call this with the rule_lists locked
1045 static int insert_penaltychange (const char *list_name, const char *content, const int linenum)
1047 char *timestr, *maxstr, *minstr, *contentdup;
1048 struct penalty_rule *rule = NULL, *rule_iter;
1049 struct rule_list *rl_iter;
1050 int time, inserted = 0;
1052 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
1053 ast_log(LOG_ERROR, "Cannot allocate memory for penaltychange rule at line %d!\n", linenum);
1057 contentdup = ast_strdupa(content);
1059 if (!(maxstr = strchr(contentdup, ','))) {
1060 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
1066 timestr = contentdup;
1068 if ((time = atoi(timestr)) < 0) {
1069 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
1076 if ((minstr = strchr(maxstr,',')))
1079 /* The last check will evaluate true if either no penalty change is indicated for a given rule
1080 * OR if a min penalty change is indicated but no max penalty change is */
1081 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
1082 rule->max_relative = 1;
1085 rule->max_value = atoi(maxstr);
1087 if (!ast_strlen_zero(minstr)) {
1088 if (*minstr == '+' || *minstr == '-')
1089 rule->min_relative = 1;
1090 rule->min_value = atoi(minstr);
1091 } else /*there was no minimum specified, so assume this means no change*/
1092 rule->min_relative = 1;
1094 /*We have the rule made, now we need to insert it where it belongs*/
1095 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
1096 if (strcasecmp(rl_iter->name, list_name))
1099 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
1100 if (rule->time < rule_iter->time) {
1101 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
1106 AST_LIST_TRAVERSE_SAFE_END;
1109 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
1116 /*! \brief Configure a queue parameter.
1118 * The failunknown flag is set for config files (and static realtime) to show
1119 * errors for unknown parameters. It is cleared for dynamic realtime to allow
1120 * extra fields in the tables.
1121 * \note For error reporting, line number is passed for .conf static configuration,
1122 * for Realtime queues, linenum is -1.
1124 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
1126 if (!strcasecmp(param, "musicclass") ||
1127 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
1128 ast_string_field_set(q, moh, val);
1129 } else if (!strcasecmp(param, "announce")) {
1130 ast_string_field_set(q, announce, val);
1131 } else if (!strcasecmp(param, "context")) {
1132 ast_string_field_set(q, context, val);
1133 } else if (!strcasecmp(param, "timeout")) {
1134 q->timeout = atoi(val);
1136 q->timeout = DEFAULT_TIMEOUT;
1137 } else if (!strcasecmp(param, "ringinuse")) {
1138 q->ringinuse = ast_true(val);
1139 } else if (!strcasecmp(param, "setinterfacevar")) {
1140 q->setinterfacevar = ast_true(val);
1141 } else if (!strcasecmp(param, "setqueuevar")) {
1142 q->setqueuevar = ast_true(val);
1143 } else if (!strcasecmp(param, "setqueueentryvar")) {
1144 q->setqueueentryvar = ast_true(val);
1145 } else if (!strcasecmp(param, "monitor-format")) {
1146 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
1147 } else if (!strcasecmp(param, "membermacro")) {
1148 ast_string_field_set(q, membermacro, val);
1149 } else if (!strcasecmp(param, "membergosub")) {
1150 ast_string_field_set(q, membergosub, val);
1151 } else if (!strcasecmp(param, "queue-youarenext")) {
1152 ast_string_field_set(q, sound_next, val);
1153 } else if (!strcasecmp(param, "queue-thereare")) {
1154 ast_string_field_set(q, sound_thereare, val);
1155 } else if (!strcasecmp(param, "queue-callswaiting")) {
1156 ast_string_field_set(q, sound_calls, val);
1157 } else if (!strcasecmp(param, "queue-quantity1")) {
1158 ast_string_field_set(q, queue_quantity1, val);
1159 } else if (!strcasecmp(param, "queue-quantity2")) {
1160 ast_string_field_set(q, queue_quantity2, val);
1161 } else if (!strcasecmp(param, "queue-holdtime")) {
1162 ast_string_field_set(q, sound_holdtime, val);
1163 } else if (!strcasecmp(param, "queue-minutes")) {
1164 ast_string_field_set(q, sound_minutes, val);
1165 } else if (!strcasecmp(param, "queue-minute")) {
1166 ast_string_field_set(q, sound_minute, val);
1167 } else if (!strcasecmp(param, "queue-seconds")) {
1168 ast_string_field_set(q, sound_seconds, val);
1169 } else if (!strcasecmp(param, "queue-thankyou")) {
1170 ast_string_field_set(q, sound_thanks, val);
1171 } else if (!strcasecmp(param, "queue-callerannounce")) {
1172 ast_string_field_set(q, sound_callerannounce, val);
1173 } else if (!strcasecmp(param, "queue-reporthold")) {
1174 ast_string_field_set(q, sound_reporthold, val);
1175 } else if (!strcasecmp(param, "announce-frequency")) {
1176 q->announcefrequency = atoi(val);
1177 } else if (!strcasecmp(param, "min-announce-frequency")) {
1178 q->minannouncefrequency = atoi(val);
1179 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
1180 } else if (!strcasecmp(param, "announce-round-seconds")) {
1181 q->roundingseconds = atoi(val);
1182 /* Rounding to any other values just doesn't make sense... */
1183 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
1184 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
1186 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1187 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1188 val, param, q->name, linenum);
1190 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
1191 "using 0 instead for queue '%s'\n", val, param, q->name);
1193 q->roundingseconds=0;
1195 } else if (!strcasecmp(param, "announce-holdtime")) {
1196 if (!strcasecmp(val, "once"))
1197 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
1198 else if (ast_true(val))
1199 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
1201 q->announceholdtime = 0;
1202 } else if (!strcasecmp(param, "announce-position")) {
1203 if (!strcasecmp(val, "limit"))
1204 q->announceposition = ANNOUNCEPOSITION_LIMIT;
1205 else if (!strcasecmp(val, "more"))
1206 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
1207 else if (ast_true(val))
1208 q->announceposition = ANNOUNCEPOSITION_YES;
1210 q->announceposition = ANNOUNCEPOSITION_NO;
1211 } else if (!strcasecmp(param, "announce-position-limit")) {
1212 q->announcepositionlimit = atoi(val);
1213 } else if (!strcasecmp(param, "periodic-announce")) {
1214 if (strchr(val, ',')) {
1215 char *s, *buf = ast_strdupa(val);
1218 while ((s = strsep(&buf, ",|"))) {
1219 if (!q->sound_periodicannounce[i])
1220 q->sound_periodicannounce[i] = ast_str_create(16);
1221 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
1223 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
1226 q->numperiodicannounce = i;
1228 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
1229 q->numperiodicannounce = 1;
1231 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
1232 q->periodicannouncefrequency = atoi(val);
1233 } else if (!strcasecmp(param, "random-periodic-announce")) {
1234 q->randomperiodicannounce = ast_true(val);
1235 } else if (!strcasecmp(param, "retry")) {
1236 q->retry = atoi(val);
1238 q->retry = DEFAULT_RETRY;
1239 } else if (!strcasecmp(param, "wrapuptime")) {
1240 q->wrapuptime = atoi(val);
1241 } else if (!strcasecmp(param, "autofill")) {
1242 q->autofill = ast_true(val);
1243 } else if (!strcasecmp(param, "monitor-type")) {
1244 if (!strcasecmp(val, "mixmonitor"))
1246 } else if (!strcasecmp(param, "autopause")) {
1247 q->autopause = ast_true(val);
1248 } else if (!strcasecmp(param, "maxlen")) {
1249 q->maxlen = atoi(val);
1252 } else if (!strcasecmp(param, "servicelevel")) {
1253 q->servicelevel= atoi(val);
1254 } else if (!strcasecmp(param, "strategy")) {
1255 /* We already have set this, no need to do it again */
1257 } else if (!strcasecmp(param, "joinempty")) {
1258 if (!strcasecmp(val, "loose"))
1259 q->joinempty = QUEUE_EMPTY_LOOSE;
1260 else if (!strcasecmp(val, "strict"))
1261 q->joinempty = QUEUE_EMPTY_STRICT;
1262 else if (ast_true(val))
1263 q->joinempty = QUEUE_EMPTY_NORMAL;
1266 } else if (!strcasecmp(param, "leavewhenempty")) {
1267 if (!strcasecmp(val, "loose"))
1268 q->leavewhenempty = QUEUE_EMPTY_LOOSE;
1269 else if (!strcasecmp(val, "strict"))
1270 q->leavewhenempty = QUEUE_EMPTY_STRICT;
1271 else if (ast_true(val))
1272 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
1274 q->leavewhenempty = 0;
1275 } else if (!strcasecmp(param, "eventmemberstatus")) {
1276 q->maskmemberstatus = !ast_true(val);
1277 } else if (!strcasecmp(param, "eventwhencalled")) {
1278 if (!strcasecmp(val, "vars")) {
1279 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
1281 q->eventwhencalled = ast_true(val) ? 1 : 0;
1283 } else if (!strcasecmp(param, "reportholdtime")) {
1284 q->reportholdtime = ast_true(val);
1285 } else if (!strcasecmp(param, "memberdelay")) {
1286 q->memberdelay = atoi(val);
1287 } else if (!strcasecmp(param, "weight")) {
1288 q->weight = atoi(val);
1291 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1292 we will not see any effect on use_weight until next reload. */
1293 } else if (!strcasecmp(param, "timeoutrestart")) {
1294 q->timeoutrestart = ast_true(val);
1295 } else if (!strcasecmp(param, "defaultrule")) {
1296 ast_string_field_set(q, defaultrule, val);
1297 } else if (failunknown) {
1299 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1300 q->name, param, linenum);
1302 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1308 * \brief Find rt member record to update otherwise create one.
1310 * Search for member in queue, if found update penalty/paused state,
1311 * if no memeber exists create one flag it as a RT member and add to queue member list.
1313 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)
1316 struct ao2_iterator mem_iter;
1322 penalty = atoi(penalty_str);
1328 paused = atoi(paused_str);
1333 /* Find member by realtime uniqueid and update */
1334 mem_iter = ao2_iterator_init(q->members, 0);
1335 while ((m = ao2_iterator_next(&mem_iter))) {
1336 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
1337 m->dead = 0; /* Do not delete this one. */
1338 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1341 if (strcasecmp(state_interface, m->state_interface)) {
1342 remove_from_interfaces(m->state_interface);
1343 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
1344 add_to_interfaces(m->state_interface);
1346 m->penalty = penalty;
1354 /* Create a new member */
1356 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
1359 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
1360 add_to_interfaces(m->state_interface);
1361 ao2_link(q->members, m);
1369 /*! \brief Iterate through queue's member list and delete them */
1370 static void free_members(struct call_queue *q, int all)
1372 /* Free non-dynamic members */
1374 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1376 while ((cur = ao2_iterator_next(&mem_iter))) {
1377 if (all || !cur->dynamic) {
1378 ao2_unlink(q->members, cur);
1379 remove_from_interfaces(cur->state_interface);
1386 /*! \brief Free queue's member list then its string fields */
1387 static void destroy_queue(void *obj)
1389 struct call_queue *q = obj;
1393 ast_string_field_free_memory(q);
1394 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
1395 if (q->sound_periodicannounce[i])
1396 free(q->sound_periodicannounce[i]);
1398 ao2_ref(q->members, -1);
1401 static struct call_queue *alloc_queue(const char *queuename)
1403 struct call_queue *q;
1405 if ((q = ao2_alloc(sizeof(*q), destroy_queue))) {
1406 if (ast_string_field_init(q, 64)) {
1410 ast_string_field_set(q, name, queuename);
1416 * \brief Reload a single queue via realtime.
1418 * Check for statically defined queue first, check if deleted RT queue,
1419 * check for new RT queue, if queue vars are not defined init them with defaults.
1420 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
1421 * \retval the queue,
1422 * \retval NULL if it doesn't exist.
1423 * \note Should be called with the "queues" container locked.
1425 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1427 struct ast_variable *v;
1428 struct call_queue *q, tmpq = {
1432 struct ao2_iterator mem_iter;
1433 char *interface = NULL;
1434 const char *tmp_name;
1436 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1438 /* Static queues override realtime. */
1439 if ((q = ao2_find(queues, &tmpq, OBJ_POINTER))) {
1447 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
1453 } else if (!member_config)
1454 /* Not found in the list, and it's not realtime ... */
1457 /* Check if queue is defined in realtime. */
1459 /* Delete queue from in-core list if it has been deleted in realtime. */
1461 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1462 found condition... So we might delete an in-core queue
1463 in case of DB failure. */
1464 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1467 /* Delete if unused (else will be deleted when last caller leaves). */
1468 ao2_unlink(queues, q);
1475 /* Create a new queue if an in-core entry does not exist yet. */
1477 struct ast_variable *tmpvar = NULL;
1478 if (!(q = alloc_queue(queuename)))
1483 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
1484 * will allocate the members properly
1486 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
1487 if (!strcasecmp(tmpvar->name, "strategy")) {
1488 q->strategy = strat2int(tmpvar->value);
1489 if (q->strategy < 0) {
1490 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1491 tmpvar->value, q->name);
1492 q->strategy = QUEUE_STRATEGY_RINGALL;
1497 /* We traversed all variables and didn't find a strategy */
1499 q->strategy = QUEUE_STRATEGY_RINGALL;
1500 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1501 ao2_link(queues, q);
1504 memset(tmpbuf, 0, sizeof(tmpbuf));
1505 for (v = queue_vars; v; v = v->next) {
1506 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1507 if ((tmp = strchr(v->name, '_'))) {
1508 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1511 while ((tmp = strchr(tmp, '_')))
1516 if (!ast_strlen_zero(v->value)) {
1517 /* Don't want to try to set the option if the value is empty */
1518 queue_set_param(q, tmp_name, v->value, -1, 0);
1522 /* Temporarily set realtime members dead so we can detect deleted ones.
1523 * Also set the membercount correctly for realtime*/
1524 mem_iter = ao2_iterator_init(q->members, 0);
1525 while ((m = ao2_iterator_next(&mem_iter))) {
1532 while ((interface = ast_category_browse(member_config, interface))) {
1533 rt_handle_member_record(q, interface,
1534 ast_variable_retrieve(member_config, interface, "uniqueid"),
1535 S_OR(ast_variable_retrieve(member_config, interface, "membername"),interface),
1536 ast_variable_retrieve(member_config, interface, "penalty"),
1537 ast_variable_retrieve(member_config, interface, "paused"),
1538 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
1541 /* Delete all realtime members that have been deleted in DB. */
1542 mem_iter = ao2_iterator_init(q->members, 0);
1543 while ((m = ao2_iterator_next(&mem_iter))) {
1545 ao2_unlink(q->members, m);
1546 remove_from_interfaces(m->state_interface);
1557 static struct call_queue *load_realtime_queue(const char *queuename)
1559 struct ast_variable *queue_vars;
1560 struct ast_config *member_config = NULL;
1561 struct call_queue *q = NULL, tmpq = {
1565 /* Find the queue in the in-core list first. */
1566 q = ao2_find(queues, &tmpq, OBJ_POINTER);
1568 if (!q || q->realtime) {
1569 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
1570 queue operations while waiting for the DB.
1572 This will be two separate database transactions, so we might
1573 see queue parameters as they were before another process
1574 changed the queue and member list as it was after the change.
1575 Thus we might see an empty member list when a queue is
1576 deleted. In practise, this is unlikely to cause a problem. */
1578 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1580 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1581 if (!member_config) {
1582 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1583 ast_variables_destroy(queue_vars);
1589 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1591 ast_config_destroy(member_config);
1593 ast_variables_destroy(queue_vars);
1597 update_realtime_members(q);
1602 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
1606 if (ast_strlen_zero(mem->rt_uniqueid))
1609 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, NULL)) > 0)
1616 static void update_realtime_members(struct call_queue *q)
1618 struct ast_config *member_config = NULL;
1620 char *interface = NULL;
1621 struct ao2_iterator mem_iter;
1623 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) {
1624 /*This queue doesn't have realtime members*/
1625 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
1631 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1632 mem_iter = ao2_iterator_init(q->members, 0);
1633 while ((m = ao2_iterator_next(&mem_iter))) {
1639 while ((interface = ast_category_browse(member_config, interface))) {
1640 rt_handle_member_record(q, interface,
1641 ast_variable_retrieve(member_config, interface, "uniqueid"),
1642 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1643 ast_variable_retrieve(member_config, interface, "penalty"),
1644 ast_variable_retrieve(member_config, interface, "paused"),
1645 S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
1648 /* Delete all realtime members that have been deleted in DB. */
1649 mem_iter = ao2_iterator_init(q->members, 0);
1650 while ((m = ao2_iterator_next(&mem_iter))) {
1652 ao2_unlink(q->members, m);
1653 remove_from_interfaces(m->state_interface);
1659 ast_config_destroy(member_config);
1662 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1664 struct call_queue *q;
1665 struct queue_ent *cur, *prev = NULL;
1669 enum queue_member_status stat;
1671 if (!(q = load_realtime_queue(queuename)))
1677 /* This is our one */
1678 stat = get_member_status(q, qe->max_penalty, qe->min_penalty);
1679 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1680 *reason = QUEUE_JOINEMPTY;
1681 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
1682 *reason = QUEUE_JOINUNAVAIL;
1683 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
1684 *reason = QUEUE_JOINUNAVAIL;
1685 else if (q->maxlen && (q->count >= q->maxlen))
1686 *reason = QUEUE_FULL;
1688 /* There's space for us, put us at the right position inside
1690 * Take into account the priority of the calling user */
1695 /* We have higher priority than the current user, enter
1696 * before him, after all the other users with priority
1697 * higher or equal to our priority. */
1698 if ((!inserted) && (qe->prio > cur->prio)) {
1699 insert_entry(q, prev, qe, &pos);
1706 /* No luck, join at the end of the queue */
1708 insert_entry(q, prev, qe, &pos);
1709 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1710 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1711 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1714 manager_event(EVENT_FLAG_CALL, "Join",
1715 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1717 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1718 S_OR(qe->chan->cid.cid_name, "unknown"),
1719 q->name, qe->pos, q->count, qe->chan->uniqueid );
1720 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1728 static int play_file(struct ast_channel *chan, const char *filename)
1732 ast_stopstream(chan);
1734 res = ast_streamfile(chan, filename, chan->language);
1736 res = ast_waitstream(chan, AST_DIGIT_ANY);
1738 ast_stopstream(chan);
1744 * \brief Check for valid exit from queue via goto
1745 * \retval 0 if failure
1746 * \retval 1 if successful
1748 static int valid_exit(struct queue_ent *qe, char digit)
1750 int digitlen = strlen(qe->digits);
1752 /* Prevent possible buffer overflow */
1753 if (digitlen < sizeof(qe->digits) - 2) {
1754 qe->digits[digitlen] = digit;
1755 qe->digits[digitlen + 1] = '\0';
1757 qe->digits[0] = '\0';
1761 /* If there's no context to goto, short-circuit */
1762 if (ast_strlen_zero(qe->context))
1765 /* If the extension is bad, then reset the digits to blank */
1766 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1767 qe->digits[0] = '\0';
1771 /* We have an exact match */
1772 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1773 qe->valid_digits = 1;
1774 /* Return 1 on a successful goto */
1781 static int say_position(struct queue_ent *qe, int ringing)
1783 int res = 0, avgholdmins, avgholdsecs, announceposition = 0;
1786 /* Let minannouncefrequency seconds pass between the start of each position announcement */
1788 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
1791 /* If either our position has changed, or we are over the freq timer, say position */
1792 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1796 ast_indicate(qe->chan,-1);
1798 ast_moh_stop(qe->chan);
1801 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
1802 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
1803 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
1804 qe->pos <= qe->parent->announcepositionlimit))
1805 announceposition = 1;
1808 if (announceposition == 1) {
1809 /* Say we're next, if we are */
1811 res = play_file(qe->chan, qe->parent->sound_next);
1817 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
1819 res = play_file(qe->chan, qe->parent->queue_quantity1);
1822 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
1827 res = play_file(qe->chan, qe->parent->sound_thereare);
1830 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
1834 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
1836 res = play_file(qe->chan, qe->parent->queue_quantity2);
1840 res = play_file(qe->chan, qe->parent->sound_calls);
1846 /* Round hold time to nearest minute */
1847 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1849 /* If they have specified a rounding then round the seconds as well */
1850 if (qe->parent->roundingseconds) {
1851 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1852 avgholdsecs *= qe->parent->roundingseconds;
1857 ast_verb(3, "Hold time for %s is %d minute(s) %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1859 /* If the hold time is >1 min, if it's enabled, and if it's not
1860 supposed to be only once and we have already said it, say it */
1861 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1862 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1863 res = play_file(qe->chan, qe->parent->sound_holdtime);
1867 if (avgholdmins > 1) {
1868 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1872 if (avgholdmins == 1) {
1873 res = play_file(qe->chan, qe->parent->sound_minute);
1877 res = play_file(qe->chan, qe->parent->sound_minutes);
1882 if (avgholdsecs > 1) {
1883 res = ast_say_number(qe->chan, avgholdmins > 1 ? avgholdsecs : avgholdmins * 60 + avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1887 res = play_file(qe->chan, qe->parent->sound_seconds);
1895 if (announceposition == 1){
1896 if (qe->parent->announceposition) {
1897 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
1898 qe->chan->name, qe->parent->name, qe->pos);
1900 res = play_file(qe->chan, qe->parent->sound_thanks);
1903 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
1906 /* Set our last_pos indicators */
1908 qe->last_pos_said = qe->pos;
1910 /* Don't restart music on hold if we're about to exit the caller from the queue */
1913 ast_indicate(qe->chan, AST_CONTROL_RINGING);
1915 ast_moh_start(qe->chan, qe->moh, NULL);
1921 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
1925 /* Calculate holdtime using a recursive boxcar filter */
1926 /* Thanks to SRT for this contribution */
1927 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1929 ao2_lock(qe->parent);
1930 oldvalue = qe->parent->holdtime;
1931 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
1932 ao2_unlock(qe->parent);
1935 /*! \brief Caller leaving queue.
1937 * Search the queue to find the leaving client, if found remove from queue
1938 * create manager event, move others up the queue.
1940 static void leave_queue(struct queue_ent *qe)
1942 struct call_queue *q;
1943 struct queue_ent *cur, *prev = NULL;
1944 struct penalty_rule *pr_iter;
1947 if (!(q = qe->parent))
1953 for (cur = q->head; cur; cur = cur->next) {
1957 /* Take us out of the queue */
1958 manager_event(EVENT_FLAG_CALL, "Leave",
1959 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1960 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1961 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1962 /* Take us out of the queue */
1964 prev->next = cur->next;
1966 q->head = cur->next;
1967 /* Free penalty rules */
1968 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list)))
1971 /* Renumber the people after us in the queue based on a new count */
1978 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
1980 if (!ast_load_realtime("queues", "name", q->name, NULL))
1985 /* It's dead and nobody is in it, so kill it */
1986 ao2_unlink(queues, q);
1987 /* unref the container's reference to the queue */
1990 /* unref the explicit ref earlier in the function */
1994 /*! \brief Hang up a list of outgoing calls */
1995 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1997 struct callattempt *oo;
2000 /* Hangup any existing lines we have open */
2001 if (outgoing->chan && (outgoing->chan != exception))
2002 ast_hangup(outgoing->chan);
2004 outgoing = outgoing->q_next;
2006 ao2_ref(oo->member, -1);
2012 * \brief traverse all defined queues which have calls waiting and contain this member
2013 * \retval 0 if no other queue has precedence (higher weight)
2014 * \retval 1 if found
2016 static int compare_weight(struct call_queue *rq, struct member *member)
2018 struct call_queue *q;
2021 struct ao2_iterator queue_iter;
2023 /* q's lock and rq's lock already set by try_calling()
2024 * to solve deadlock */
2025 queue_iter = ao2_iterator_init(queues, 0);
2026 while ((q = ao2_iterator_next(&queue_iter))) {
2027 if (q == rq) { /* don't check myself, could deadlock */
2032 if (q->count && q->members) {
2033 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
2034 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
2035 if (q->weight > rq->weight) {
2036 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);
2052 /*! \brief common hangup actions */
2053 static void do_hang(struct callattempt *o)
2056 ast_hangup(o->chan);
2060 /*! \brief convert "\n" to "\nVariable: " ready for manager to use */
2061 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
2063 struct ast_str *buf = ast_str_alloca(len + 1);
2066 if (pbx_builtin_serialize_variables(chan, &buf)) {
2069 /* convert "\n" to "\nVariable: " */
2070 strcpy(vars, "Variable: ");
2073 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
2076 if (tmp[i + 1] == '\0')
2078 if (tmp[i] == '\n') {
2082 ast_copy_string(&(vars[j]), "Variable: ", len - j);
2092 /* there are no channel variables; leave it blank */
2099 * \brief Part 2 of ring_one
2101 * Does error checking before attempting to request a channel and call a member.
2102 * This function is only called from ring_one().
2103 * Failure can occur if:
2106 * - Wrapup time not expired
2107 * - Priority by another queue
2109 * \retval 1 on success to reach a free agent
2110 * \retval 0 on failure to get agent.
2112 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
2118 const char *macrocontext, *macroexten;
2120 /* on entry here, we know that tmp->chan == NULL */
2121 if ((tmp->lastqueue && tmp->lastqueue->wrapuptime && (time(NULL) - tmp->lastcall < tmp->lastqueue->wrapuptime)) ||
2122 (!tmp->lastqueue && qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime))) {
2123 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
2124 (tmp->lastqueue ? tmp->lastqueue->name : qe->parent->name), tmp->interface);
2126 ast_cdr_busy(qe->chan->cdr);
2127 tmp->stillgoing = 0;
2132 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
2133 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
2135 ast_cdr_busy(qe->chan->cdr);
2136 tmp->stillgoing = 0;
2140 if (tmp->member->paused) {
2141 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
2143 ast_cdr_busy(qe->chan->cdr);
2144 tmp->stillgoing = 0;
2147 if (use_weight && compare_weight(qe->parent,tmp->member)) {
2148 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
2150 ast_cdr_busy(qe->chan->cdr);
2151 tmp->stillgoing = 0;
2156 ast_copy_string(tech, tmp->interface, sizeof(tech));
2157 if ((location = strchr(tech, '/')))
2162 /* Request the peer */
2163 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
2164 if (!tmp->chan) { /* If we can't, just go on to the next call */
2166 ast_cdr_busy(qe->chan->cdr);
2167 tmp->stillgoing = 0;
2169 update_status(tmp->member->state_interface, ast_device_state(tmp->member->state_interface));
2171 ao2_lock(qe->parent);
2172 qe->parent->rrpos++;
2174 ao2_unlock(qe->parent);
2181 tmp->chan->appl = "AppQueue";
2182 tmp->chan->data = "(Outgoing Line)";
2183 memset(&tmp->chan->whentohangup, 0, sizeof(tmp->chan->whentohangup));
2184 if (tmp->chan->cid.cid_num)
2185 ast_free(tmp->chan->cid.cid_num);
2186 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
2187 if (tmp->chan->cid.cid_name)
2188 ast_free(tmp->chan->cid.cid_name);
2189 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
2190 if (tmp->chan->cid.cid_ani)
2191 ast_free(tmp->chan->cid.cid_ani);
2192 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
2194 /* Inherit specially named variables from parent channel */
2195 ast_channel_inherit_variables(qe->chan, tmp->chan);
2197 /* Presense of ADSI CPE on outgoing channel follows ours */
2198 tmp->chan->adsicpe = qe->chan->adsicpe;
2200 /* Inherit context and extension */
2201 ast_channel_lock(qe->chan);
2202 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
2203 if (!ast_strlen_zero(macrocontext))
2204 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
2206 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
2207 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
2208 if (!ast_strlen_zero(macroexten))
2209 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
2211 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
2212 ast_channel_unlock(qe->chan);
2214 /* Place the call, but don't wait on the answer */
2215 if ((res = ast_call(tmp->chan, location, 0))) {
2216 /* Again, keep going even if there's an error */
2217 ast_debug(1, "ast call on peer returned %d\n", res);
2218 ast_verb(3, "Couldn't call %s\n", tmp->interface);
2222 } else if (qe->parent->eventwhencalled) {
2225 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
2227 "AgentCalled: %s\r\n"
2229 "ChannelCalling: %s\r\n"
2230 "DestinationChannel: %s\r\n"
2231 "CallerIDNum: %s\r\n"
2232 "CallerIDName: %s\r\n"
2238 qe->parent->name, tmp->interface, tmp->member->membername, qe->chan->name, tmp->chan->name,
2239 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
2240 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
2241 qe->chan->context, qe->chan->exten, qe->chan->priority, qe->chan->uniqueid,
2242 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2243 ast_verb(3, "Called %s\n", tmp->interface);
2249 /*! \brief find the entry with the best metric, or NULL */
2250 static struct callattempt *find_best(struct callattempt *outgoing)
2252 struct callattempt *best = NULL, *cur;
2254 for (cur = outgoing; cur; cur = cur->q_next) {
2255 if (cur->stillgoing && /* Not already done */
2256 !cur->chan && /* Isn't already going */
2257 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
2266 * \brief Place a call to a queue member.
2268 * Once metrics have been calculated for each member, this function is used
2269 * to place a call to the appropriate member (or members). The low-level
2270 * channel-handling and error detection is handled in ring_entry
2272 * \retval 1 if a member was called successfully
2273 * \retval 0 otherwise
2275 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
2280 struct callattempt *best = find_best(outgoing);
2282 ast_debug(1, "Nobody left to try ringing in queue\n");
2285 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2286 struct callattempt *cur;
2287 /* Ring everyone who shares this best metric (for ringall) */
2288 for (cur = outgoing; cur; cur = cur->q_next) {
2289 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
2290 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
2291 ret |= ring_entry(qe, cur, busies);
2295 /* Ring just the best channel */
2296 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
2297 ret = ring_entry(qe, best, busies);
2304 /*! \brief Search for best metric and add to Round Robbin queue */
2305 static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
2307 struct callattempt *best = find_best(outgoing);
2310 /* Ring just the best channel */
2311 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2312 qe->parent->rrpos = best->metric % 1000;
2314 /* Just increment rrpos */
2315 if (qe->parent->wrapped) {
2316 /* No more channels, start over */
2317 qe->parent->rrpos = 0;
2319 /* Prioritize next entry */
2320 qe->parent->rrpos++;
2323 qe->parent->wrapped = 0;
2328 /*! \brief Search for best metric and add to Linear queue */
2329 static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
2331 struct callattempt *best = find_best(outgoing);
2334 /* Ring just the best channel */
2335 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
2336 qe->linpos = best->metric % 1000;
2338 /* Just increment rrpos */
2339 if (qe->linwrapped) {
2340 /* No more channels, start over */
2343 /* Prioritize next entry */
2352 /*! \brief Playback announcement to queued members if peroid has elapsed */
2353 static int say_periodic_announcement(struct queue_ent *qe, int ringing)
2358 /* Get the current time */
2361 /* Check to see if it is time to announce */
2362 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
2365 /* Stop the music on hold so we can play our own file */
2367 ast_indicate(qe->chan,-1);
2369 ast_moh_stop(qe->chan);
2371 ast_verb(3, "Playing periodic announcement\n");
2373 if (qe->parent->randomperiodicannounce) {
2374 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
2375 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
2376 ast_strlen_zero(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str)) {
2377 qe->last_periodic_announce_sound = 0;
2380 /* play the announcement */
2381 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]->str);
2383 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
2386 /* Resume Music on Hold if the caller is going to stay in the queue */
2389 ast_indicate(qe->chan, AST_CONTROL_RINGING);
2391 ast_moh_start(qe->chan, qe->moh, NULL);
2394 /* update last_periodic_announce_time */
2395 qe->last_periodic_announce_time = now;
2397 /* Update the current periodic announcement to the next announcement */
2398 if (!qe->parent->randomperiodicannounce) {
2399 qe->last_periodic_announce_sound++;
2405 /*! \brief Record that a caller gave up on waiting in queue */
2406 static void record_abandoned(struct queue_ent *qe)
2408 ao2_lock(qe->parent);
2409 set_queue_variables(qe);
2410 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
2414 "OriginalPosition: %d\r\n"
2416 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
2418 qe->parent->callsabandoned++;
2419 ao2_unlock(qe->parent);
2422 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2423 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
2425 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
2426 if (qe->parent->eventwhencalled)
2427 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
2432 "MemberName: %s\r\n"
2440 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
2441 if (qe->parent->autopause) {
2442 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
2443 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
2445 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
2451 #define AST_MAX_WATCHERS 256
2452 /*! \brief Wait for a member to answer the call
2454 * \param[in] qe the queue_ent corresponding to the caller in the queue
2455 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
2456 * \param[in] to the amount of time (in milliseconds) to wait for a response
2457 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
2458 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
2459 * \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
2460 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
2462 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
2464 const char *queue = qe->parent->name;
2465 struct callattempt *o, *start = NULL, *prev = NULL;
2467 int numbusies = prebusies;
2471 struct ast_frame *f;
2472 struct callattempt *peer = NULL;
2473 struct ast_channel *winner;
2474 struct ast_channel *in = qe->chan;
2476 char membername[80] = "";
2480 struct callattempt *epollo;
2483 starttime = (long) time(NULL);
2485 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2487 ast_poll_channel_add(in, epollo->chan);
2491 while (*to && !peer) {
2492 int numlines, retry, pos = 1;
2493 struct ast_channel *watchers[AST_MAX_WATCHERS];
2497 for (retry = 0; retry < 2; retry++) {
2499 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
2500 if (o->stillgoing) { /* Keep track of important channels */
2503 watchers[pos++] = o->chan;
2507 prev->call_next = o;
2513 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
2514 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
2516 /* On "ringall" strategy we only move to the next penalty level
2517 when *all* ringing phones are done in the current penalty level */
2518 ring_one(qe, outgoing, &numbusies);
2521 if (pos == 1 /* not found */) {
2522 if (numlines == (numbusies + numnochan)) {
2523 ast_debug(1, "Everyone is busy at this time\n");
2525 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2530 winner = ast_waitfor_n(watchers, pos, to);
2531 for (o = start; o; o = o->call_next) {
2532 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2534 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2537 } else if (o->chan && (o->chan == winner)) {
2539 ast_copy_string(on, o->member->interface, sizeof(on));
2540 ast_copy_string(membername, o->member->membername, sizeof(membername));
2542 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2543 ast_verb(3, "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2548 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2553 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2554 if ((stuff = strchr(tmpchan, '/'))) {
2558 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2562 /* Before processing channel, go ahead and check for forwarding */
2563 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2564 /* Setup parameters */
2565 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2567 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2571 ast_channel_inherit_variables(in, o->chan);
2572 ast_channel_datastore_inherit(in, o->chan);
2573 if (o->chan->cid.cid_num)
2574 ast_free(o->chan->cid.cid_num);
2575 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2577 if (o->chan->cid.cid_name)
2578 ast_free(o->chan->cid.cid_name);
2579 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2581 ast_string_field_set(o->chan, accountcode, in->accountcode);
2582 o->chan->cdrflags = in->cdrflags;
2584 if (in->cid.cid_ani) {
2585 if (o->chan->cid.cid_ani)
2586 ast_free(o->chan->cid.cid_ani);
2587 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2589 if (o->chan->cid.cid_rdnis)
2590 ast_free(o->chan->cid.cid_rdnis);
2591 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2592 if (ast_call(o->chan, tmpchan, 0)) {
2593 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2598 /* Hangup the original channel now, in case we needed it */
2602 f = ast_read(winner);
2604 if (f->frametype == AST_FRAME_CONTROL) {
2605 switch (f->subclass) {
2606 case AST_CONTROL_ANSWER:
2607 /* This is our guy if someone answered. */
2609 ast_verb(3, "%s answered %s\n", o->chan->name, in->name);
2613 case AST_CONTROL_BUSY:
2614 ast_verb(3, "%s is busy\n", o->chan->name);
2616 ast_cdr_busy(in->cdr);
2618 endtime = (long) time(NULL);
2619 endtime -= starttime;
2620 rna(endtime*1000, qe, on, membername);
2621 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2622 if (qe->parent->timeoutrestart)
2624 ring_one(qe, outgoing, &numbusies);
2628 case AST_CONTROL_CONGESTION:
2629 ast_verb(3, "%s is circuit-busy\n", o->chan->name);
2631 ast_cdr_busy(in->cdr);
2632 endtime = (long) time(NULL);
2633 endtime -= starttime;
2634 rna(endtime*1000, qe, on, membername);
2636 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2637 if (qe->parent->timeoutrestart)
2639 ring_one(qe, outgoing, &numbusies);
2643 case AST_CONTROL_RINGING:
2644 ast_verb(3, "%s is ringing\n", o->chan->name);
2646 case AST_CONTROL_OFFHOOK:
2647 /* Ignore going off hook */
2650 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
2655 endtime = (long) time(NULL) - starttime;
2656 rna(endtime * 1000, qe, on, membername);
2658 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2659 if (qe->parent->timeoutrestart)
2661 ring_one(qe, outgoing, &numbusies);
2668 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2672 if (f->data.uint32) {
2673 in->hangupcause = f->data.uint32;
2679 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2680 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass);
2685 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2686 ast_verb(3, "User pressed digit: %c\n", f->subclass);
2688 *digit = f->subclass;
2695 for (o = start; o; o = o->call_next)
2696 rna(orig, qe, o->interface, o->member->membername);
2701 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
2703 ast_poll_channel_del(in, epollo->chan);
2711 * \brief Check if we should start attempting to call queue members.
2713 * The behavior of this function is dependent first on whether autofill is enabled
2714 * and second on whether the ring strategy is ringall. If autofill is not enabled,
2715 * then return true if we're the head of the queue. If autofill is enabled, then
2716 * we count the available members and see if the number of available members is enough
2717 * that given our position in the queue, we would theoretically be able to connect to
2718 * one of those available members
2720 static int is_our_turn(struct queue_ent *qe)
2722 struct queue_ent *ch;
2728 if (!qe->parent->autofill) {
2729 /* Atomically read the parent head -- does not need a lock */
2730 ch = qe->parent->head;
2731 /* If we are now at the top of the head, break out */
2733 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2736 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2741 /* This needs a lock. How many members are available to be served? */
2742 ao2_lock(qe->parent);
2744 ch = qe->parent->head;
2746 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2747 ast_debug(1, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
2750 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
2751 while ((cur = ao2_iterator_next(&mem_iter))) {
2752 switch (cur->status) {
2753 case AST_DEVICE_INUSE:
2754 if (!qe->parent->ringinuse)
2756 /* else fall through */
2757 case AST_DEVICE_NOT_INUSE:
2758 case AST_DEVICE_UNKNOWN:
2767 ast_debug(1, "There are %d available members.\n", avl);
2769 while ((idx < avl) && (ch) && (ch != qe)) {
2775 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2776 if (ch && idx < avl) {
2777 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2780 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2784 ao2_unlock(qe->parent);
2791 * \brief update rules for queues
2793 * Calculate min/max penalties making sure if relative they stay within bounds.
2794 * Update queues penalty and set dialplan vars, goto next list entry.
2796 static void update_qe_rule(struct queue_ent *qe)
2798 int max_penalty = qe->pr->max_relative ? qe->max_penalty + qe->pr->max_value : qe->pr->max_value;
2799 int min_penalty = qe->pr->min_relative ? qe->min_penalty + qe->pr->min_value : qe->pr->min_value;
2800 char max_penalty_str[20], min_penalty_str[20];
2801 /* a relative change to the penalty could put it below 0 */
2802 if (max_penalty < 0)
2804 if (min_penalty < 0)
2806 if (min_penalty > max_penalty)
2807 min_penalty = max_penalty;
2808 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
2809 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
2810 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
2811 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
2812 qe->max_penalty = max_penalty;
2813 qe->min_penalty = min_penalty;
2814 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);
2815 qe->pr = AST_LIST_NEXT(qe->pr, list);
2818 /*! \brief The waiting areas for callers who are not actively calling members
2820 * This function is one large loop. This function will return if a caller
2821 * either exits the queue or it becomes that caller's turn to attempt calling
2822 * queue members. Inside the loop, we service the caller with periodic announcements,
2823 * holdtime announcements, etc. as configured in queues.conf
2825 * \retval 0 if the caller's turn has arrived
2826 * \retval -1 if the caller should exit the queue.
2828 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2832 /* This is the holding pen for callers 2 through maxlen */
2834 enum queue_member_status stat;
2836 if (is_our_turn(qe))
2839 /* If we have timed out, break out */
2840 if (qe->expire && (time(NULL) > qe->expire)) {
2841 *reason = QUEUE_TIMEOUT;
2845 stat = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty);
2847 /* leave the queue if no agents, if enabled */
2848 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2849 *reason = QUEUE_LEAVEEMPTY;
2850 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2855 /* leave the queue if no reachable agents, if enabled */
2856 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2857 *reason = QUEUE_LEAVEUNAVAIL;
2858 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2862 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2863 *reason = QUEUE_LEAVEUNAVAIL;
2864 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2869 /* Make a position announcement, if enabled */
2870 if (qe->parent->announcefrequency &&
2871 (res = say_position(qe,ringing)))
2874 /* Make a periodic announcement, if enabled */
2875 if (qe->parent->periodicannouncefrequency &&
2876 (res = say_periodic_announcement(qe,ringing)))
2879 /* see if we need to move to the next penalty level for this queue */
2880 while (qe->pr && ((time(NULL) - qe->start) > qe->pr->time)) {
2884 /* Wait a second before checking again */
2885 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
2886 if (res > 0 && !valid_exit(qe, res))
2897 * \brief update the queue status
2900 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
2903 struct call_queue *qtmp;
2904 struct ao2_iterator queue_iter;
2906 if (shared_lastcall) {
2907 queue_iter = ao2_iterator_init(queues, 0);
2908 while ((qtmp = ao2_iterator_next(&queue_iter))) {
2910 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
2911 time(&mem->lastcall);
2921 time(&member->lastcall);
2923 member->lastqueue = q;
2927 q->callscompleted++;
2928 if (callcompletedinsl)
2929 q->callscompletedinsl++;
2934 /*! \brief Calculate the metric of each member in the outgoing callattempts
2936 * A numeric metric is given to each member depending on the ring strategy used
2937 * by the queue. Members with lower metrics will be called before members with
2939 * \retval -1 if penalties are exceeded
2940 * \retval 0 otherwise
2942 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2944 if ((qe->max_penalty && (mem->penalty > qe->max_penalty)) || (qe->min_penalty && (mem->penalty < qe->min_penalty)))
2947 switch (q->strategy) {
2948 case QUEUE_STRATEGY_RINGALL:
2949 /* Everyone equal, except for penalty */
2950 tmp->metric = mem->penalty * 1000000;
2952 case QUEUE_STRATEGY_LINEAR:
2953 if (pos < qe->linpos) {
2954 tmp->metric = 1000 + pos;
2956 if (pos > qe->linpos)
2957 /* Indicate there is another priority */
2961 tmp->metric += mem->penalty * 1000000;
2963 case QUEUE_STRATEGY_RRMEMORY:
2964 if (pos < q->rrpos) {
2965 tmp->metric = 1000 + pos;
2968 /* Indicate there is another priority */
2972 tmp->metric += mem->penalty * 1000000;
2974 case QUEUE_STRATEGY_RANDOM:
2975 tmp->metric = ast_random() % 1000;
2976 tmp->metric += mem->penalty * 1000000;
2978 case QUEUE_STRATEGY_WRANDOM:
2979 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
2981 case QUEUE_STRATEGY_FEWESTCALLS:
2982 tmp->metric = mem->calls;
2983 tmp->metric += mem->penalty * 1000000;
2985 case QUEUE_STRATEGY_LEASTRECENT:
2989 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2990 tmp->metric += mem->penalty * 1000000;
2993 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2999 enum agent_complete_reason {