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$")
74 #include <sys/signal.h>
75 #include <netinet/in.h>
77 #include "asterisk/lock.h"
78 #include "asterisk/file.h"
79 #include "asterisk/logger.h"
80 #include "asterisk/channel.h"
81 #include "asterisk/pbx.h"
82 #include "asterisk/options.h"
83 #include "asterisk/app.h"
84 #include "asterisk/linkedlists.h"
85 #include "asterisk/module.h"
86 #include "asterisk/translate.h"
87 #include "asterisk/say.h"
88 #include "asterisk/features.h"
89 #include "asterisk/musiconhold.h"
90 #include "asterisk/cli.h"
91 #include "asterisk/manager.h"
92 #include "asterisk/config.h"
93 #include "asterisk/monitor.h"
94 #include "asterisk/utils.h"
95 #include "asterisk/causes.h"
96 #include "asterisk/astdb.h"
97 #include "asterisk/devicestate.h"
98 #include "asterisk/stringfields.h"
99 #include "asterisk/astobj2.h"
100 #include "asterisk/global_datastores.h"
102 /* Please read before modifying this file.
103 * There are three locks which are regularly used
104 * throughout this file, the queue list lock, the lock
105 * for each individual queue, and the interface list lock.
106 * Please be extra careful to always lock in the following order
108 * 2) individual queue lock
109 * 3) interface list lock
110 * This order has sort of "evolved" over the lifetime of this
111 * application, but it is now in place this way, so please adhere
117 QUEUE_STRATEGY_RINGALL
= 0,
118 QUEUE_STRATEGY_ROUNDROBIN
,
119 QUEUE_STRATEGY_LEASTRECENT
,
120 QUEUE_STRATEGY_FEWESTCALLS
,
121 QUEUE_STRATEGY_RANDOM
,
122 QUEUE_STRATEGY_RRMEMORY
125 static struct strategy
{
129 { QUEUE_STRATEGY_RINGALL
, "ringall" },
130 { QUEUE_STRATEGY_ROUNDROBIN
, "roundrobin" },
131 { QUEUE_STRATEGY_LEASTRECENT
, "leastrecent" },
132 { QUEUE_STRATEGY_FEWESTCALLS
, "fewestcalls" },
133 { QUEUE_STRATEGY_RANDOM
, "random" },
134 { QUEUE_STRATEGY_RRMEMORY
, "rrmemory" },
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 */
142 #define RES_OKAY 0 /* Action completed */
143 #define RES_EXISTS (-1) /* Entry already exists */
144 #define RES_OUTOFMEMORY (-2) /* Out of memory */
145 #define RES_NOSUCHQUEUE (-3) /* No such queue */
146 #define RES_NOT_DYNAMIC (-4) /* Member is not dynamic */
148 static char *app
= "Queue";
150 static char *synopsis
= "Queue a call for a call queue";
152 static char *descrip
=
153 " Queue(queuename[|options[|URL][|announceoverride][|timeout][|AGI]):\n"
154 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
155 "This application will return to the dialplan if the queue does not exist, or\n"
156 "any of the join options cause the caller to not enter the queue.\n"
157 "The option string may contain zero or more of the following characters:\n"
158 " 'd' -- data-quality (modem) call (minimum delay).\n"
159 " 'h' -- allow callee to hang up by hitting *.\n"
160 " 'H' -- allow caller to hang up by hitting *.\n"
161 " 'n' -- no retries on the timeout; will exit this application and \n"
162 " go to the next step.\n"
163 " 'i' -- ignore call forward requests from queue members and do nothing\n"
164 " when they are requested.\n"
165 " 'r' -- ring instead of playing MOH\n"
166 " 't' -- allow the called user transfer the calling user\n"
167 " 'T' -- to allow the calling user to transfer the call.\n"
168 " 'w' -- allow the called user to write the conversation to disk via Monitor\n"
169 " 'W' -- allow the calling user to write the conversation to disk via Monitor\n"
170 " In addition to transferring the call, a call may be parked and then picked\n"
171 "up by another user.\n"
172 " The optional URL will be sent to the called party if the channel supports\n"
174 " The optional AGI parameter will setup an AGI script to be executed on the \n"
175 "calling party's channel once they are connected to a queue member.\n"
176 " The timeout will cause the queue to fail out after a specified number of\n"
177 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
178 " This application sets the following channel variable upon completion:\n"
179 " QUEUESTATUS The status of the call as a text string, one of\n"
180 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
182 static char *app_aqm
= "AddQueueMember" ;
183 static char *app_aqm_synopsis
= "Dynamically adds queue members" ;
184 static char *app_aqm_descrip
=
185 " AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]]):\n"
186 "Dynamically adds interface to an existing queue.\n"
187 "If the interface is already in the queue and there exists an n+101 priority\n"
188 "then it will then jump to this priority. Otherwise it will return an error\n"
189 "The option string may contain zero or more of the following characters:\n"
190 " 'j' -- jump to +101 priority when appropriate.\n"
191 " This application sets the following channel variable upon completion:\n"
192 " AQMSTATUS The status of the attempt to add a queue member as a \n"
193 " text string, one of\n"
194 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
195 "Example: AddQueueMember(techsupport|SIP/3000)\n"
198 static char *app_rqm
= "RemoveQueueMember" ;
199 static char *app_rqm_synopsis
= "Dynamically removes queue members" ;
200 static char *app_rqm_descrip
=
201 " RemoveQueueMember(queuename[|interface[|options]]):\n"
202 "Dynamically removes interface to an existing queue\n"
203 "If the interface is NOT in the queue and there exists an n+101 priority\n"
204 "then it will then jump to this priority. Otherwise it will return an error\n"
205 "The option string may contain zero or more of the following characters:\n"
206 " 'j' -- jump to +101 priority when appropriate.\n"
207 " This application sets the following channel variable upon completion:\n"
208 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
209 " text string, one of\n"
210 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
211 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
214 static char *app_pqm
= "PauseQueueMember" ;
215 static char *app_pqm_synopsis
= "Pauses a queue member" ;
216 static char *app_pqm_descrip
=
217 " PauseQueueMember([queuename]|interface[|options]):\n"
218 "Pauses (blocks calls for) a queue member.\n"
219 "The given interface will be paused in the given queue. This prevents\n"
220 "any calls from being sent from the queue to the interface until it is\n"
221 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
222 "queuename is given, the interface is paused in every queue it is a\n"
223 "member of. If the interface is not in the named queue, or if no queue\n"
224 "is given and the interface is not in any queue, it will jump to\n"
225 "priority n+101, if it exists and the appropriate options are set.\n"
226 "The application will fail if the interface is not found and no extension\n"
227 "to jump to exists.\n"
228 "The option string may contain zero or more of the following characters:\n"
229 " 'j' -- jump to +101 priority when appropriate.\n"
230 " This application sets the following channel variable upon completion:\n"
231 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
232 " text string, one of\n"
233 " PAUSED | NOTFOUND\n"
234 "Example: PauseQueueMember(|SIP/3000)\n";
236 static char *app_upqm
= "UnpauseQueueMember" ;
237 static char *app_upqm_synopsis
= "Unpauses a queue member" ;
238 static char *app_upqm_descrip
=
239 " UnpauseQueueMember([queuename]|interface[|options]):\n"
240 "Unpauses (resumes calls to) a queue member.\n"
241 "This is the counterpart to PauseQueueMember and operates exactly the\n"
242 "same way, except it unpauses instead of pausing the given interface.\n"
243 "The option string may contain zero or more of the following characters:\n"
244 " 'j' -- jump to +101 priority when appropriate.\n"
245 " This application sets the following channel variable upon completion:\n"
246 " UPQMSTATUS The status of the attempt to unpause a queue \n"
247 " member as a text string, one of\n"
248 " UNPAUSED | NOTFOUND\n"
249 "Example: UnpauseQueueMember(|SIP/3000)\n";
251 static char *app_ql
= "QueueLog" ;
252 static char *app_ql_synopsis
= "Writes to the queue_log" ;
253 static char *app_ql_descrip
=
254 " QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n"
255 "Allows you to write your own events into the queue log\n"
256 "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n";
258 /*! \brief Persistent Members astdb family */
259 static const char *pm_family
= "Queue/PersistentMembers";
260 /* The maximum length of each persistent member queue database entry */
261 #define PM_MAX_LEN 8192
263 /*! \brief queues.conf [general] option */
264 static int queue_persistent_members
= 0;
266 /*! \brief queues.conf per-queue weight option */
267 static int use_weight
= 0;
269 /*! \brief queues.conf [general] option */
270 static int autofill_default
= 0;
272 /*! \brief queues.conf [general] option */
273 static int montype_default
= 0;
279 QUEUE_LEAVEEMPTY
= 3,
280 QUEUE_JOINUNAVAIL
= 4,
281 QUEUE_LEAVEUNAVAIL
= 5,
286 enum queue_result id
;
288 } queue_results
[] = {
289 { QUEUE_UNKNOWN
, "UNKNOWN" },
290 { QUEUE_TIMEOUT
, "TIMEOUT" },
291 { QUEUE_JOINEMPTY
,"JOINEMPTY" },
292 { QUEUE_LEAVEEMPTY
, "LEAVEEMPTY" },
293 { QUEUE_JOINUNAVAIL
, "JOINUNAVAIL" },
294 { QUEUE_LEAVEUNAVAIL
, "LEAVEUNAVAIL" },
295 { QUEUE_FULL
, "FULL" },
298 /*! \brief We define a custom "local user" structure because we
299 use it not only for keeping track of what is in use but
300 also for keeping track of who we're dialing.
302 There are two "links" defined in this structure, q_next and call_next.
303 q_next links ALL defined callattempt structures into a linked list. call_next is
304 a link which allows for a subset of the callattempts to be traversed. This subset
305 is used in wait_for_answer so that irrelevant callattempts are not traversed. This
306 also is helpful so that queue logs are always accurate in the case where a call to
307 a member times out, especially if using the ringall strategy. */
310 struct callattempt
*q_next
;
311 struct callattempt
*call_next
;
312 struct ast_channel
*chan
;
318 struct member
*member
;
323 struct call_queue
*parent
; /*!< What queue is our parent */
324 char moh
[80]; /*!< Name of musiconhold to be used */
325 char announce
[80]; /*!< Announcement to play for member when call is answered */
326 char context
[AST_MAX_CONTEXT
]; /*!< Context when user exits queue */
327 char digits
[AST_MAX_EXTENSION
]; /*!< Digits entered while in queue */
328 int valid_digits
; /*!< Digits entered correspond to valid extension. Exited */
329 int pos
; /*!< Where we are in the queue */
330 int prio
; /*!< Our priority */
331 int last_pos_said
; /*!< Last position we told the user */
332 time_t last_periodic_announce_time
; /*!< The last time we played a periodic announcement */
333 int last_periodic_announce_sound
; /*!< The last periodic announcement we made */
334 time_t last_pos
; /*!< Last time we told the user their position */
335 int opos
; /*!< Where we started in the queue */
336 int handled
; /*!< Whether our call was handled */
337 int pending
; /*!< Non-zero if we are attempting to call a member */
338 int max_penalty
; /*!< Limit the members that can take this call to this penalty or lower */
339 time_t start
; /*!< When we started holding */
340 time_t expire
; /*!< When this entry should expire (time out of queue) */
341 struct ast_channel
*chan
; /*!< Our channel */
342 struct queue_ent
*next
; /*!< The next queue entry */
346 char interface
[80]; /*!< Technology/Location */
347 char membername
[80]; /*!< Member name to use in queue logs */
348 int penalty
; /*!< Are we a last resort? */
349 int calls
; /*!< Number of calls serviced by this member */
350 int dynamic
; /*!< Are we dynamically added? */
351 int realtime
; /*!< Is this member realtime? */
352 int status
; /*!< Status of queue member */
353 int paused
; /*!< Are we paused (not accepting calls)? */
354 time_t lastcall
; /*!< When last successful call was hungup */
355 unsigned int dead
:1; /*!< Used to detect members deleted in realtime */
356 unsigned int delme
:1; /*!< Flag to delete entry on reload */
359 struct member_interface
{
361 AST_LIST_ENTRY(member_interface
) list
; /*!< Next call queue */
364 static AST_LIST_HEAD_STATIC(interfaces
, member_interface
);
366 /* values used in multi-bit flags in call_queue */
367 #define QUEUE_EMPTY_NORMAL 1
368 #define QUEUE_EMPTY_STRICT 2
369 #define ANNOUNCEHOLDTIME_ALWAYS 1
370 #define ANNOUNCEHOLDTIME_ONCE 2
371 #define QUEUE_EVENT_VARIABLES 3
375 char name
[80]; /*!< Name */
376 char moh
[80]; /*!< Music On Hold class to be used */
377 char announce
[80]; /*!< Announcement to play when call is answered */
378 char context
[AST_MAX_CONTEXT
]; /*!< Exit context */
379 unsigned int monjoin
:1;
381 unsigned int joinempty
:2;
382 unsigned int eventwhencalled
:2;
383 unsigned int leavewhenempty
:2;
384 unsigned int ringinuse
:1;
385 unsigned int setinterfacevar
:1;
386 unsigned int reportholdtime
:1;
387 unsigned int wrapped
:1;
388 unsigned int timeoutrestart
:1;
389 unsigned int announceholdtime
:2;
391 unsigned int maskmemberstatus
:1;
392 unsigned int realtime
:1;
393 unsigned int found
:1;
394 int announcefrequency
; /*!< How often to announce their position */
395 int periodicannouncefrequency
; /*!< How often to play periodic announcement */
396 int roundingseconds
; /*!< How many seconds do we round to? */
397 int holdtime
; /*!< Current avg holdtime, based on an exponential average */
398 int callscompleted
; /*!< Number of queue calls completed */
399 int callsabandoned
; /*!< Number of queue calls abandoned */
400 int servicelevel
; /*!< seconds setting for servicelevel*/
401 int callscompletedinsl
; /*!< Number of calls answered with servicelevel*/
402 char monfmt
[8]; /*!< Format to use when recording calls */
403 int montype
; /*!< Monitor type Monitor vs. MixMonitor */
404 char sound_next
[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
405 char sound_thereare
[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
406 char sound_calls
[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
407 char sound_holdtime
[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
408 char sound_minutes
[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
409 char sound_lessthan
[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
410 char sound_seconds
[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
411 char sound_thanks
[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
412 char sound_reporthold
[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
413 char sound_periodicannounce
[MAX_PERIODIC_ANNOUNCEMENTS
][80];/*!< Sound files: Custom announce, no default */
415 int count
; /*!< How many entries */
416 int maxlen
; /*!< Max number of entries */
417 int wrapuptime
; /*!< Wrapup Time */
419 int retry
; /*!< Retry calling everyone after this amount of time */
420 int timeout
; /*!< How long to wait for an answer */
421 int weight
; /*!< Respective weight */
422 int autopause
; /*!< Auto pause queue members if they fail to answer */
424 /* Queue strategy things */
425 int rrpos
; /*!< Round Robin - position */
426 int memberdelay
; /*!< Seconds to delay connecting member to caller */
427 int autofill
; /*!< Ignore the head call status and ring an available agent */
429 struct ao2_container
*members
; /*!< Head of the list of members */
431 * \brief Number of members _logged in_
432 * \note There will be members in the members container that are not logged
433 * in, so this can not simply be replaced with ao2_container_count().
436 struct queue_ent
*head
; /*!< Head of the list of callers */
437 AST_LIST_ENTRY(call_queue
) list
; /*!< Next call queue */
440 static AST_LIST_HEAD_STATIC(queues
, call_queue
);
442 static int set_member_paused(const char *queuename
, const char *interface
, int paused
);
444 static void queue_transfer_fixup(void *data
, struct ast_channel
*old_chan
, struct ast_channel
*new_chan
);
446 static void rr_dep_warning(void)
448 static unsigned int warned
= 0;
451 ast_log(LOG_NOTICE
, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n");
456 static void monjoin_dep_warning(void)
458 static unsigned int warned
= 0;
460 ast_log(LOG_NOTICE
, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n");
464 /*! \brief sets the QUEUESTATUS channel variable */
465 static void set_queue_result(struct ast_channel
*chan
, enum queue_result res
)
469 for (i
= 0; i
< sizeof(queue_results
) / sizeof(queue_results
[0]); i
++) {
470 if (queue_results
[i
].id
== res
) {
471 pbx_builtin_setvar_helper(chan
, "QUEUESTATUS", queue_results
[i
].text
);
477 static char *int2strat(int strategy
)
481 for (x
= 0; x
< sizeof(strategies
) / sizeof(strategies
[0]); x
++) {
482 if (strategy
== strategies
[x
].strategy
)
483 return strategies
[x
].name
;
489 static int strat2int(const char *strategy
)
493 for (x
= 0; x
< sizeof(strategies
) / sizeof(strategies
[0]); x
++) {
494 if (!strcasecmp(strategy
, strategies
[x
].name
))
495 return strategies
[x
].strategy
;
501 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
502 static inline void insert_entry(struct call_queue
*q
, struct queue_ent
*prev
, struct queue_ent
*new, int *pos
)
504 struct queue_ent
*cur
;
521 enum queue_member_status
{
523 QUEUE_NO_REACHABLE_MEMBERS
,
527 /*! \brief Check if members are available
529 * This function checks to see if members are available to be called. If any member
530 * is available, the function immediately returns QUEUE_NORMAL. If no members are available,
531 * the appropriate reason why is returned
533 static enum queue_member_status
get_member_status(struct call_queue
*q
, int max_penalty
)
535 struct member
*member
;
536 struct ao2_iterator mem_iter
;
537 enum queue_member_status result
= QUEUE_NO_MEMBERS
;
539 ast_mutex_lock(&q
->lock
);
540 mem_iter
= ao2_iterator_init(q
->members
, 0);
541 while ((member
= ao2_iterator_next(&mem_iter
))) {
542 if (max_penalty
&& (member
->penalty
> max_penalty
)) {
547 if (member
->paused
) {
552 switch (member
->status
) {
553 case AST_DEVICE_INVALID
:
557 case AST_DEVICE_UNAVAILABLE
:
558 result
= QUEUE_NO_REACHABLE_MEMBERS
;
562 ast_mutex_unlock(&q
->lock
);
568 ast_mutex_unlock(&q
->lock
);
573 AST_LIST_ENTRY(statechange
) entry
;
578 static int update_status(const char *interface
, const int status
)
581 struct ao2_iterator mem_iter
;
582 struct call_queue
*q
;
584 AST_LIST_LOCK(&queues
);
585 AST_LIST_TRAVERSE(&queues
, q
, list
) {
586 ast_mutex_lock(&q
->lock
);
587 mem_iter
= ao2_iterator_init(q
->members
, 0);
588 while ((cur
= ao2_iterator_next(&mem_iter
))) {
591 tmp_interface
= ast_strdupa(cur
->interface
);
592 if ((slash_pos
= strchr(tmp_interface
, '/')))
593 if ((slash_pos
= strchr(slash_pos
+ 1, '/')))
596 if (strcasecmp(interface
, tmp_interface
)) {
601 if (cur
->status
!= status
) {
602 cur
->status
= status
;
603 if (q
->maskmemberstatus
) {
608 manager_event(EVENT_FLAG_AGENT
, "QueueMemberStatus",
618 q
->name
, cur
->interface
, cur
->membername
, cur
->dynamic
? "dynamic" : cur
->realtime
? "realtime" : "static",
619 cur
->penalty
, cur
->calls
, (int)cur
->lastcall
, cur
->status
, cur
->paused
);
623 ast_mutex_unlock(&q
->lock
);
625 AST_LIST_UNLOCK(&queues
);
630 /*! \brief set a member's status based on device state of that member's interface*/
631 static void *handle_statechange(struct statechange
*sc
)
633 struct member_interface
*curint
;
637 technology
= ast_strdupa(sc
->dev
);
638 loc
= strchr(technology
, '/');
645 AST_LIST_LOCK(&interfaces
);
646 AST_LIST_TRAVERSE(&interfaces
, curint
, list
) {
649 interface
= ast_strdupa(curint
->interface
);
650 if ((slash_pos
= strchr(interface
, '/')))
651 if ((slash_pos
= strchr(slash_pos
+ 1, '/')))
654 if (!strcasecmp(interface
, sc
->dev
))
657 AST_LIST_UNLOCK(&interfaces
);
660 if (option_debug
> 2)
661 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
));
666 ast_log(LOG_DEBUG
, "Device '%s/%s' changed to state '%d' (%s)\n", technology
, loc
, sc
->state
, devstate2str(sc
->state
));
668 update_status(sc
->dev
, sc
->state
);
674 * \brief Data used by the device state thread
677 /*! Set to 1 to stop the thread */
679 /*! The device state monitoring thread */
681 /*! Lock for the state change queue */
683 /*! Condition for the state change queue */
685 /*! Queue of state changes */
686 AST_LIST_HEAD_NOLOCK(, statechange
) state_change_q
;
688 .thread
= AST_PTHREADT_NULL
,
691 /*! \brief Consumer of the statechange queue */
692 static void *device_state_thread(void *data
)
694 struct statechange
*sc
= NULL
;
696 while (!device_state
.stop
) {
697 ast_mutex_lock(&device_state
.lock
);
698 if (!(sc
= AST_LIST_REMOVE_HEAD(&device_state
.state_change_q
, entry
))) {
699 ast_cond_wait(&device_state
.cond
, &device_state
.lock
);
700 sc
= AST_LIST_REMOVE_HEAD(&device_state
.state_change_q
, entry
);
702 ast_mutex_unlock(&device_state
.lock
);
704 /* Check to see if we were woken up to see the request to stop */
705 if (device_state
.stop
)
711 handle_statechange(sc
);
720 while ((sc
= AST_LIST_REMOVE_HEAD(&device_state
.state_change_q
, entry
)))
725 /*! \brief Producer of the statechange queue */
726 static int statechange_queue(const char *dev
, int state
, void *ign
)
728 struct statechange
*sc
;
730 if (!(sc
= ast_calloc(1, sizeof(*sc
) + strlen(dev
) + 1)))
734 strcpy(sc
->dev
, dev
);
736 ast_mutex_lock(&device_state
.lock
);
737 AST_LIST_INSERT_TAIL(&device_state
.state_change_q
, sc
, entry
);
738 ast_cond_signal(&device_state
.cond
);
739 ast_mutex_unlock(&device_state
.lock
);
743 /*! \brief allocate space for new queue member and set fields based on parameters passed */
744 static struct member
*create_queue_member(const char *interface
, const char *membername
, int penalty
, int paused
)
748 if ((cur
= ao2_alloc(sizeof(*cur
), NULL
))) {
749 cur
->penalty
= penalty
;
750 cur
->paused
= paused
;
751 ast_copy_string(cur
->interface
, interface
, sizeof(cur
->interface
));
752 if (!ast_strlen_zero(membername
))
753 ast_copy_string(cur
->membername
, membername
, sizeof(cur
->membername
));
755 ast_copy_string(cur
->membername
, interface
, sizeof(cur
->membername
));
756 if (!strchr(cur
->interface
, '/'))
757 ast_log(LOG_WARNING
, "No location at interface '%s'\n", interface
);
758 cur
->status
= ast_device_state(interface
);
764 static struct call_queue
*alloc_queue(const char *queuename
)
766 struct call_queue
*q
;
768 if ((q
= ast_calloc(1, sizeof(*q
)))) {
769 ast_mutex_init(&q
->lock
);
770 ast_copy_string(q
->name
, queuename
, sizeof(q
->name
));
775 static int compress_char(const char c
)
785 static int member_hash_fn(const void *obj
, const int flags
)
787 const struct member
*mem
= obj
;
788 const char *chname
= strchr(mem
->interface
, '/');
791 chname
= mem
->interface
;
792 for (i
= 0; i
< 5 && chname
[i
]; i
++)
793 ret
+= compress_char(chname
[i
]) << (i
* 6);
797 static int member_cmp_fn(void *obj1
, void *obj2
, int flags
)
799 struct member
*mem1
= obj1
, *mem2
= obj2
;
800 return strcmp(mem1
->interface
, mem2
->interface
) ? 0 : CMP_MATCH
;
803 static void init_queue(struct call_queue
*q
)
808 q
->retry
= DEFAULT_RETRY
;
811 q
->announcefrequency
= 0;
812 q
->announceholdtime
= 0;
813 q
->roundingseconds
= 0; /* Default - don't announce seconds */
816 q
->setinterfacevar
= 0;
817 q
->autofill
= autofill_default
;
818 q
->montype
= montype_default
;
820 q
->announce
[0] = '\0';
821 q
->context
[0] = '\0';
823 q
->periodicannouncefrequency
= 0;
824 q
->reportholdtime
= 0;
828 q
->leavewhenempty
= 0;
830 q
->maskmemberstatus
= 0;
831 q
->eventwhencalled
= 0;
833 q
->timeoutrestart
= 0;
835 q
->members
= ao2_container_alloc(37, member_hash_fn
, member_cmp_fn
);
838 ast_copy_string(q
->sound_next
, "queue-youarenext", sizeof(q
->sound_next
));
839 ast_copy_string(q
->sound_thereare
, "queue-thereare", sizeof(q
->sound_thereare
));
840 ast_copy_string(q
->sound_calls
, "queue-callswaiting", sizeof(q
->sound_calls
));
841 ast_copy_string(q
->sound_holdtime
, "queue-holdtime", sizeof(q
->sound_holdtime
));
842 ast_copy_string(q
->sound_minutes
, "queue-minutes", sizeof(q
->sound_minutes
));
843 ast_copy_string(q
->sound_seconds
, "queue-seconds", sizeof(q
->sound_seconds
));
844 ast_copy_string(q
->sound_thanks
, "queue-thankyou", sizeof(q
->sound_thanks
));
845 ast_copy_string(q
->sound_lessthan
, "queue-less-than", sizeof(q
->sound_lessthan
));
846 ast_copy_string(q
->sound_reporthold
, "queue-reporthold", sizeof(q
->sound_reporthold
));
847 ast_copy_string(q
->sound_periodicannounce
[0], "queue-periodic-announce", sizeof(q
->sound_periodicannounce
[0]));
848 for (i
= 1; i
< MAX_PERIODIC_ANNOUNCEMENTS
; i
++) {
849 q
->sound_periodicannounce
[i
][0]='\0';
853 static void clear_queue(struct call_queue
*q
)
856 q
->callscompleted
= 0;
857 q
->callsabandoned
= 0;
858 q
->callscompletedinsl
= 0;
862 static int add_to_interfaces(const char *interface
)
864 struct member_interface
*curint
;
866 AST_LIST_LOCK(&interfaces
);
867 AST_LIST_TRAVERSE(&interfaces
, curint
, list
) {
868 if (!strcasecmp(curint
->interface
, interface
))
873 AST_LIST_UNLOCK(&interfaces
);
878 ast_log(LOG_DEBUG
, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface
);
880 if ((curint
= ast_calloc(1, sizeof(*curint
)))) {
881 ast_copy_string(curint
->interface
, interface
, sizeof(curint
->interface
));
882 AST_LIST_INSERT_HEAD(&interfaces
, curint
, list
);
884 AST_LIST_UNLOCK(&interfaces
);
889 static int interface_exists_global(const char *interface
)
891 struct call_queue
*q
;
892 struct member
*mem
, tmpmem
;
895 ast_copy_string(tmpmem
.interface
, interface
, sizeof(tmpmem
.interface
));
897 AST_LIST_LOCK(&queues
);
898 AST_LIST_TRAVERSE(&queues
, q
, list
) {
899 ast_mutex_lock(&q
->lock
);
900 if ((mem
= ao2_find(q
->members
, &tmpmem
, OBJ_POINTER
))) {
904 ast_mutex_unlock(&q
->lock
);
908 AST_LIST_UNLOCK(&queues
);
913 static int remove_from_interfaces(const char *interface
)
915 struct member_interface
*curint
;
917 if (interface_exists_global(interface
))
920 AST_LIST_LOCK(&interfaces
);
921 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces
, curint
, list
) {
922 if (!strcasecmp(curint
->interface
, interface
)) {
924 ast_log(LOG_DEBUG
, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface
);
925 AST_LIST_REMOVE_CURRENT(&interfaces
, list
);
930 AST_LIST_TRAVERSE_SAFE_END
;
931 AST_LIST_UNLOCK(&interfaces
);
936 static void clear_and_free_interfaces(void)
938 struct member_interface
*curint
;
940 AST_LIST_LOCK(&interfaces
);
941 while ((curint
= AST_LIST_REMOVE_HEAD(&interfaces
, list
)))
943 AST_LIST_UNLOCK(&interfaces
);
946 /*! \brief Configure a queue parameter.
948 For error reporting, line number is passed for .conf static configuration.
949 For Realtime queues, linenum is -1.
950 The failunknown flag is set for config files (and static realtime) to show
951 errors for unknown parameters. It is cleared for dynamic realtime to allow
952 extra fields in the tables. */
953 static void queue_set_param(struct call_queue
*q
, const char *param
, const char *val
, int linenum
, int failunknown
)
955 if (!strcasecmp(param
, "musicclass") ||
956 !strcasecmp(param
, "music") || !strcasecmp(param
, "musiconhold")) {
957 ast_copy_string(q
->moh
, val
, sizeof(q
->moh
));
958 } else if (!strcasecmp(param
, "announce")) {
959 ast_copy_string(q
->announce
, val
, sizeof(q
->announce
));
960 } else if (!strcasecmp(param
, "context")) {
961 ast_copy_string(q
->context
, val
, sizeof(q
->context
));
962 } else if (!strcasecmp(param
, "timeout")) {
963 q
->timeout
= atoi(val
);
965 q
->timeout
= DEFAULT_TIMEOUT
;
966 } else if (!strcasecmp(param
, "ringinuse")) {
967 q
->ringinuse
= ast_true(val
);
968 } else if (!strcasecmp(param
, "setinterfacevar")) {
969 q
->setinterfacevar
= ast_true(val
);
970 } else if (!strcasecmp(param
, "monitor-join")) {
971 monjoin_dep_warning();
972 q
->monjoin
= ast_true(val
);
973 } else if (!strcasecmp(param
, "monitor-format")) {
974 ast_copy_string(q
->monfmt
, val
, sizeof(q
->monfmt
));
975 } else if (!strcasecmp(param
, "queue-youarenext")) {
976 ast_copy_string(q
->sound_next
, val
, sizeof(q
->sound_next
));
977 } else if (!strcasecmp(param
, "queue-thereare")) {
978 ast_copy_string(q
->sound_thereare
, val
, sizeof(q
->sound_thereare
));
979 } else if (!strcasecmp(param
, "queue-callswaiting")) {
980 ast_copy_string(q
->sound_calls
, val
, sizeof(q
->sound_calls
));
981 } else if (!strcasecmp(param
, "queue-holdtime")) {
982 ast_copy_string(q
->sound_holdtime
, val
, sizeof(q
->sound_holdtime
));
983 } else if (!strcasecmp(param
, "queue-minutes")) {
984 ast_copy_string(q
->sound_minutes
, val
, sizeof(q
->sound_minutes
));
985 } else if (!strcasecmp(param
, "queue-seconds")) {
986 ast_copy_string(q
->sound_seconds
, val
, sizeof(q
->sound_seconds
));
987 } else if (!strcasecmp(param
, "queue-lessthan")) {
988 ast_copy_string(q
->sound_lessthan
, val
, sizeof(q
->sound_lessthan
));
989 } else if (!strcasecmp(param
, "queue-thankyou")) {
990 ast_copy_string(q
->sound_thanks
, val
, sizeof(q
->sound_thanks
));
991 } else if (!strcasecmp(param
, "queue-reporthold")) {
992 ast_copy_string(q
->sound_reporthold
, val
, sizeof(q
->sound_reporthold
));
993 } else if (!strcasecmp(param
, "announce-frequency")) {
994 q
->announcefrequency
= atoi(val
);
995 } else if (!strcasecmp(param
, "announce-round-seconds")) {
996 q
->roundingseconds
= atoi(val
);
997 if (q
->roundingseconds
>60 || q
->roundingseconds
<0) {
999 ast_log(LOG_WARNING
, "'%s' isn't a valid value for %s "
1000 "using 0 instead for queue '%s' at line %d of queues.conf\n",
1001 val
, param
, q
->name
, linenum
);
1003 ast_log(LOG_WARNING
, "'%s' isn't a valid value for %s "
1004 "using 0 instead for queue '%s'\n", val
, param
, q
->name
);
1006 q
->roundingseconds
=0;
1008 } else if (!strcasecmp(param
, "announce-holdtime")) {
1009 if (!strcasecmp(val
, "once"))
1010 q
->announceholdtime
= ANNOUNCEHOLDTIME_ONCE
;
1011 else if (ast_true(val
))
1012 q
->announceholdtime
= ANNOUNCEHOLDTIME_ALWAYS
;
1014 q
->announceholdtime
= 0;
1015 } else if (!strcasecmp(param
, "periodic-announce")) {
1016 if (strchr(val
, '|')) {
1017 char *s
, *buf
= ast_strdupa(val
);
1020 while ((s
= strsep(&buf
, "|"))) {
1021 ast_copy_string(q
->sound_periodicannounce
[i
], s
, sizeof(q
->sound_periodicannounce
[i
]));
1023 if (i
== MAX_PERIODIC_ANNOUNCEMENTS
)
1027 ast_copy_string(q
->sound_periodicannounce
[0], val
, sizeof(q
->sound_periodicannounce
[0]));
1029 } else if (!strcasecmp(param
, "periodic-announce-frequency")) {
1030 q
->periodicannouncefrequency
= atoi(val
);
1031 } else if (!strcasecmp(param
, "retry")) {
1032 q
->retry
= atoi(val
);
1034 q
->retry
= DEFAULT_RETRY
;
1035 } else if (!strcasecmp(param
, "wrapuptime")) {
1036 q
->wrapuptime
= atoi(val
);
1037 } else if (!strcasecmp(param
, "autofill")) {
1038 q
->autofill
= ast_true(val
);
1039 } else if (!strcasecmp(param
, "monitor-type")) {
1040 if (!strcasecmp(val
, "mixmonitor"))
1042 } else if (!strcasecmp(param
, "autopause")) {
1043 q
->autopause
= ast_true(val
);
1044 } else if (!strcasecmp(param
, "maxlen")) {
1045 q
->maxlen
= atoi(val
);
1048 } else if (!strcasecmp(param
, "servicelevel")) {
1049 q
->servicelevel
= atoi(val
);
1050 } else if (!strcasecmp(param
, "strategy")) {
1051 q
->strategy
= strat2int(val
);
1052 if (q
->strategy
< 0) {
1053 ast_log(LOG_WARNING
, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
1055 q
->strategy
= QUEUE_STRATEGY_RINGALL
;
1057 } else if (!strcasecmp(param
, "joinempty")) {
1058 if (!strcasecmp(val
, "strict"))
1059 q
->joinempty
= QUEUE_EMPTY_STRICT
;
1060 else if (ast_true(val
))
1061 q
->joinempty
= QUEUE_EMPTY_NORMAL
;
1064 } else if (!strcasecmp(param
, "leavewhenempty")) {
1065 if (!strcasecmp(val
, "strict"))
1066 q
->leavewhenempty
= QUEUE_EMPTY_STRICT
;
1067 else if (ast_true(val
))
1068 q
->leavewhenempty
= QUEUE_EMPTY_NORMAL
;
1070 q
->leavewhenempty
= 0;
1071 } else if (!strcasecmp(param
, "eventmemberstatus")) {
1072 q
->maskmemberstatus
= !ast_true(val
);
1073 } else if (!strcasecmp(param
, "eventwhencalled")) {
1074 if (!strcasecmp(val
, "vars")) {
1075 q
->eventwhencalled
= QUEUE_EVENT_VARIABLES
;
1077 q
->eventwhencalled
= ast_true(val
) ? 1 : 0;
1079 } else if (!strcasecmp(param
, "reportholdtime")) {
1080 q
->reportholdtime
= ast_true(val
);
1081 } else if (!strcasecmp(param
, "memberdelay")) {
1082 q
->memberdelay
= atoi(val
);
1083 } else if (!strcasecmp(param
, "weight")) {
1084 q
->weight
= atoi(val
);
1087 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1088 we will not see any effect on use_weight until next reload. */
1089 } else if (!strcasecmp(param
, "timeoutrestart")) {
1090 q
->timeoutrestart
= ast_true(val
);
1091 } else if (failunknown
) {
1093 ast_log(LOG_WARNING
, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1094 q
->name
, param
, linenum
);
1096 ast_log(LOG_WARNING
, "Unknown keyword in queue '%s': %s\n", q
->name
, param
);
1101 static void rt_handle_member_record(struct call_queue
*q
, char *interface
, const char *membername
, const char *penalty_str
, const char *paused_str
)
1103 struct member
*m
, tmpmem
;
1108 penalty
= atoi(penalty_str
);
1114 paused
= atoi(paused_str
);
1119 /* Find the member, or the place to put a new one. */
1120 ast_copy_string(tmpmem
.interface
, interface
, sizeof(tmpmem
.interface
));
1121 m
= ao2_find(q
->members
, &tmpmem
, OBJ_POINTER
);
1123 /* Create a new one if not found, else update penalty */
1125 if ((m
= create_queue_member(interface
, membername
, penalty
, paused
))) {
1128 add_to_interfaces(interface
);
1129 ao2_link(q
->members
, m
);
1135 m
->dead
= 0; /* Do not delete this one. */
1138 m
->penalty
= penalty
;
1143 static void free_members(struct call_queue
*q
, int all
)
1145 /* Free non-dynamic members */
1147 struct ao2_iterator mem_iter
= ao2_iterator_init(q
->members
, 0);
1149 while ((cur
= ao2_iterator_next(&mem_iter
))) {
1150 if (all
|| !cur
->dynamic
) {
1151 ao2_unlink(q
->members
, cur
);
1152 remove_from_interfaces(cur
->interface
);
1159 static void destroy_queue(struct call_queue
*q
)
1162 ast_mutex_destroy(&q
->lock
);
1163 ao2_ref(q
->members
, -1);
1167 /*!\brief Reload a single queue via realtime.
1168 \return Return the queue, or NULL if it doesn't exist.
1169 \note Should be called with the global qlock locked. */
1170 static struct call_queue
*find_queue_by_name_rt(const char *queuename
, struct ast_variable
*queue_vars
, struct ast_config
*member_config
)
1172 struct ast_variable
*v
;
1173 struct call_queue
*q
;
1175 struct ao2_iterator mem_iter
;
1176 char *interface
= NULL
;
1177 char *tmp
, *tmp_name
;
1178 char tmpbuf
[64]; /* Must be longer than the longest queue param name. */
1180 /* Find the queue in the in-core list (we will create a new one if not found). */
1181 AST_LIST_TRAVERSE(&queues
, q
, list
) {
1182 if (!strcasecmp(q
->name
, queuename
))
1186 /* Static queues override realtime. */
1188 ast_mutex_lock(&q
->lock
);
1191 ast_mutex_unlock(&q
->lock
);
1194 ast_log(LOG_WARNING
, "Static queue '%s' already exists. Not loading from realtime\n", q
->name
);
1195 ast_mutex_unlock(&q
->lock
);
1199 } else if (!member_config
)
1200 /* Not found in the list, and it's not realtime ... */
1203 /* Check if queue is defined in realtime. */
1205 /* Delete queue from in-core list if it has been deleted in realtime. */
1207 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1208 found condition... So we might delete an in-core queue
1209 in case of DB failure. */
1210 ast_log(LOG_DEBUG
, "Queue %s not found in realtime.\n", queuename
);
1213 /* Delete if unused (else will be deleted when last caller leaves). */
1216 AST_LIST_REMOVE(&queues
, q
, list
);
1217 ast_mutex_unlock(&q
->lock
);
1220 ast_mutex_unlock(&q
->lock
);
1225 /* Create a new queue if an in-core entry does not exist yet. */
1227 if (!(q
= alloc_queue(queuename
)))
1229 ast_mutex_lock(&q
->lock
);
1232 init_queue(q
); /* Ensure defaults for all parameters not set explicitly. */
1233 AST_LIST_INSERT_HEAD(&queues
, q
, list
);
1236 memset(tmpbuf
, 0, sizeof(tmpbuf
));
1237 for (v
= queue_vars
; v
; v
= v
->next
) {
1238 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1239 if ((tmp
= strchr(v
->name
, '_'))) {
1240 ast_copy_string(tmpbuf
, v
->name
, sizeof(tmpbuf
));
1243 while ((tmp
= strchr(tmp
, '_')))
1248 if (!ast_strlen_zero(v
->value
)) {
1249 /* Don't want to try to set the option if the value is empty */
1250 queue_set_param(q
, tmp_name
, v
->value
, -1, 0);
1254 if (q
->strategy
== QUEUE_STRATEGY_ROUNDROBIN
)
1257 /* Temporarily set realtime members dead so we can detect deleted ones.
1258 * Also set the membercount correctly for realtime*/
1259 mem_iter
= ao2_iterator_init(q
->members
, 0);
1260 while ((m
= ao2_iterator_next(&mem_iter
))) {
1267 while ((interface
= ast_category_browse(member_config
, interface
))) {
1268 rt_handle_member_record(q
, interface
,
1269 ast_variable_retrieve(member_config
, interface
, "membername"),
1270 ast_variable_retrieve(member_config
, interface
, "penalty"),
1271 ast_variable_retrieve(member_config
, interface
, "paused"));
1274 /* Delete all realtime members that have been deleted in DB. */
1275 mem_iter
= ao2_iterator_init(q
->members
, 0);
1276 while ((m
= ao2_iterator_next(&mem_iter
))) {
1278 ao2_unlink(q
->members
, m
);
1279 ast_mutex_unlock(&q
->lock
);
1280 remove_from_interfaces(m
->interface
);
1281 ast_mutex_lock(&q
->lock
);
1287 ast_mutex_unlock(&q
->lock
);
1292 static int update_realtime_member_field(struct member
*mem
, const char *queue_name
, const char *field
, const char *value
)
1294 struct ast_variable
*var
;
1297 if (!(var
= ast_load_realtime("queue_members", "interface", mem
->interface
, "queue_name", queue_name
, NULL
)))
1300 if (!strcmp(var
->name
, "uniqueid"))
1304 if (var
&& !ast_strlen_zero(var
->value
)) {
1305 if ((ast_update_realtime("queue_members", "uniqueid", var
->value
, field
, value
, NULL
)) > -1)
1311 static void update_realtime_members(struct call_queue
*q
)
1313 struct ast_config
*member_config
= NULL
;
1315 char *interface
= NULL
;
1316 struct ao2_iterator mem_iter
;
1318 if (!(member_config
= ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q
->name
, NULL
))) {
1319 /*This queue doesn't have realtime members*/
1320 if (option_debug
> 2)
1321 ast_log(LOG_DEBUG
, "Queue %s has no realtime members defined. No need for update\n", q
->name
);
1325 ast_mutex_lock(&q
->lock
);
1327 /* Temporarily set realtime members dead so we can detect deleted ones.*/
1328 mem_iter
= ao2_iterator_init(q
->members
, 0);
1329 while ((m
= ao2_iterator_next(&mem_iter
))) {
1335 while ((interface
= ast_category_browse(member_config
, interface
))) {
1336 rt_handle_member_record(q
, interface
,
1337 S_OR(ast_variable_retrieve(member_config
, interface
, "membername"), interface
),
1338 ast_variable_retrieve(member_config
, interface
, "penalty"),
1339 ast_variable_retrieve(member_config
, interface
, "paused"));
1342 /* Delete all realtime members that have been deleted in DB. */
1343 mem_iter
= ao2_iterator_init(q
->members
, 0);
1344 while ((m
= ao2_iterator_next(&mem_iter
))) {
1346 ao2_unlink(q
->members
, m
);
1347 ast_mutex_unlock(&q
->lock
);
1348 remove_from_interfaces(m
->interface
);
1349 ast_mutex_lock(&q
->lock
);
1354 ast_mutex_unlock(&q
->lock
);
1355 ast_config_destroy(member_config
);
1358 static struct call_queue
*load_realtime_queue(const char *queuename
)
1360 struct ast_variable
*queue_vars
;
1361 struct ast_config
*member_config
= NULL
;
1362 struct call_queue
*q
;
1364 /* Find the queue in the in-core list first. */
1365 AST_LIST_LOCK(&queues
);
1366 AST_LIST_TRAVERSE(&queues
, q
, list
) {
1367 if (!strcasecmp(q
->name
, queuename
)) {
1371 AST_LIST_UNLOCK(&queues
);
1373 if (!q
|| q
->realtime
) {
1374 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1375 queue operations while waiting for the DB.
1377 This will be two separate database transactions, so we might
1378 see queue parameters as they were before another process
1379 changed the queue and member list as it was after the change.
1380 Thus we might see an empty member list when a queue is
1381 deleted. In practise, this is unlikely to cause a problem. */
1383 queue_vars
= ast_load_realtime("queues", "name", queuename
, NULL
);
1385 member_config
= ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename
, NULL
);
1386 if (!member_config
) {
1387 ast_log(LOG_ERROR
, "no queue_members defined in your config (extconfig.conf).\n");
1388 ast_variables_destroy(queue_vars
);
1393 AST_LIST_LOCK(&queues
);
1395 q
= find_queue_by_name_rt(queuename
, queue_vars
, member_config
);
1397 ast_config_destroy(member_config
);
1399 ast_variables_destroy(queue_vars
);
1401 AST_LIST_UNLOCK(&queues
);
1403 update_realtime_members(q
);
1408 static int join_queue(char *queuename
, struct queue_ent
*qe
, enum queue_result
*reason
)
1410 struct call_queue
*q
;
1411 struct queue_ent
*cur
, *prev
= NULL
;
1415 enum queue_member_status stat
;
1417 if (!(q
= load_realtime_queue(queuename
)))
1420 AST_LIST_LOCK(&queues
);
1421 ast_mutex_lock(&q
->lock
);
1423 /* This is our one */
1424 stat
= get_member_status(q
, qe
->max_penalty
);
1425 if (!q
->joinempty
&& (stat
== QUEUE_NO_MEMBERS
))
1426 *reason
= QUEUE_JOINEMPTY
;
1427 else if ((q
->joinempty
== QUEUE_EMPTY_STRICT
) && (stat
== QUEUE_NO_REACHABLE_MEMBERS
|| stat
== QUEUE_NO_MEMBERS
))
1428 *reason
= QUEUE_JOINUNAVAIL
;
1429 else if (q
->maxlen
&& (q
->count
>= q
->maxlen
))
1430 *reason
= QUEUE_FULL
;
1432 /* There's space for us, put us at the right position inside
1434 * Take into account the priority of the calling user */
1439 /* We have higher priority than the current user, enter
1440 * before him, after all the other users with priority
1441 * higher or equal to our priority. */
1442 if ((!inserted
) && (qe
->prio
> cur
->prio
)) {
1443 insert_entry(q
, prev
, qe
, &pos
);
1450 /* No luck, join at the end of the queue */
1452 insert_entry(q
, prev
, qe
, &pos
);
1453 ast_copy_string(qe
->moh
, q
->moh
, sizeof(qe
->moh
));
1454 ast_copy_string(qe
->announce
, q
->announce
, sizeof(qe
->announce
));
1455 ast_copy_string(qe
->context
, q
->context
, sizeof(qe
->context
));
1458 manager_event(EVENT_FLAG_CALL
, "Join",
1459 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1461 S_OR(qe
->chan
->cid
.cid_num
, "unknown"), /* XXX somewhere else it is <unknown> */
1462 S_OR(qe
->chan
->cid
.cid_name
, "unknown"),
1463 q
->name
, qe
->pos
, q
->count
, qe
->chan
->uniqueid
);
1465 ast_log(LOG_DEBUG
, "Queue '%s' Join, Channel '%s', Position '%d'\n", q
->name
, qe
->chan
->name
, qe
->pos
);
1467 ast_mutex_unlock(&q
->lock
);
1468 AST_LIST_UNLOCK(&queues
);
1473 static int play_file(struct ast_channel
*chan
, char *filename
)
1477 ast_stopstream(chan
);
1479 res
= ast_streamfile(chan
, filename
, chan
->language
);
1481 res
= ast_waitstream(chan
, AST_DIGIT_ANY
);
1483 ast_stopstream(chan
);
1488 static int valid_exit(struct queue_ent
*qe
, char digit
)
1490 int digitlen
= strlen(qe
->digits
);
1492 /* Prevent possible buffer overflow */
1493 if (digitlen
< sizeof(qe
->digits
) - 2) {
1494 qe
->digits
[digitlen
] = digit
;
1495 qe
->digits
[digitlen
+ 1] = '\0';
1497 qe
->digits
[0] = '\0';
1501 /* If there's no context to goto, short-circuit */
1502 if (ast_strlen_zero(qe
->context
))
1505 /* If the extension is bad, then reset the digits to blank */
1506 if (!ast_canmatch_extension(qe
->chan
, qe
->context
, qe
->digits
, 1, qe
->chan
->cid
.cid_num
)) {
1507 qe
->digits
[0] = '\0';
1511 /* We have an exact match */
1512 if (!ast_goto_if_exists(qe
->chan
, qe
->context
, qe
->digits
, 1)) {
1513 qe
->valid_digits
= 1;
1514 /* Return 1 on a successful goto */
1521 static int say_position(struct queue_ent
*qe
)
1523 int res
= 0, avgholdmins
, avgholdsecs
;
1526 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1528 if ((now
- qe
->last_pos
) < 15)
1531 /* If either our position has changed, or we are over the freq timer, say position */
1532 if ((qe
->last_pos_said
== qe
->pos
) && ((now
- qe
->last_pos
) < qe
->parent
->announcefrequency
))
1535 ast_moh_stop(qe
->chan
);
1536 /* Say we're next, if we are */
1538 res
= play_file(qe
->chan
, qe
->parent
->sound_next
);
1544 res
= play_file(qe
->chan
, qe
->parent
->sound_thereare
);
1547 res
= ast_say_number(qe
->chan
, qe
->pos
, AST_DIGIT_ANY
, qe
->chan
->language
, (char *) NULL
); /* Needs gender */
1550 res
= play_file(qe
->chan
, qe
->parent
->sound_calls
);
1554 /* Round hold time to nearest minute */
1555 avgholdmins
= abs(((qe
->parent
->holdtime
+ 30) - (now
- qe
->start
)) / 60);
1557 /* If they have specified a rounding then round the seconds as well */
1558 if (qe
->parent
->roundingseconds
) {
1559 avgholdsecs
= (abs(((qe
->parent
->holdtime
+ 30) - (now
- qe
->start
))) - 60 * avgholdmins
) / qe
->parent
->roundingseconds
;
1560 avgholdsecs
*= qe
->parent
->roundingseconds
;
1565 if (option_verbose
> 2)
1566 ast_verbose(VERBOSE_PREFIX_3
"Hold time for %s is %d minutes %d seconds\n", qe
->parent
->name
, avgholdmins
, avgholdsecs
);
1568 /* If the hold time is >1 min, if it's enabled, and if it's not
1569 supposed to be only once and we have already said it, say it */
1570 if ((avgholdmins
+avgholdsecs
) > 0 && (qe
->parent
->announceholdtime
) &&
1571 (!(qe
->parent
->announceholdtime
== ANNOUNCEHOLDTIME_ONCE
) && qe
->last_pos
)) {
1572 res
= play_file(qe
->chan
, qe
->parent
->sound_holdtime
);
1576 if (avgholdmins
> 0) {
1577 if (avgholdmins
< 2) {
1578 res
= play_file(qe
->chan
, qe
->parent
->sound_lessthan
);
1582 res
= ast_say_number(qe
->chan
, 2, AST_DIGIT_ANY
, qe
->chan
->language
, NULL
);
1586 res
= ast_say_number(qe
->chan
, avgholdmins
, AST_DIGIT_ANY
, qe
->chan
->language
, NULL
);
1591 res
= play_file(qe
->chan
, qe
->parent
->sound_minutes
);
1595 if (avgholdsecs
>0) {
1596 res
= ast_say_number(qe
->chan
, avgholdsecs
, AST_DIGIT_ANY
, qe
->chan
->language
, NULL
);
1600 res
= play_file(qe
->chan
, qe
->parent
->sound_seconds
);
1608 if (option_verbose
> 2)
1609 ast_verbose(VERBOSE_PREFIX_3
"Told %s in %s their queue position (which was %d)\n",
1610 qe
->chan
->name
, qe
->parent
->name
, qe
->pos
);
1611 res
= play_file(qe
->chan
, qe
->parent
->sound_thanks
);
1614 if ((res
> 0 && !valid_exit(qe
, res
)) || res
< 0)
1617 /* Set our last_pos indicators */
1619 qe
->last_pos_said
= qe
->pos
;
1621 /* Don't restart music on hold if we're about to exit the caller from the queue */
1623 ast_moh_start(qe
->chan
, qe
->moh
, NULL
);
1628 static void recalc_holdtime(struct queue_ent
*qe
, int newholdtime
)
1632 /* Calculate holdtime using an exponential average */
1633 /* Thanks to SRT for this contribution */
1634 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1636 ast_mutex_lock(&qe
->parent
->lock
);
1637 oldvalue
= qe
->parent
->holdtime
;
1638 qe
->parent
->holdtime
= (((oldvalue
<< 2) - oldvalue
) + newholdtime
) >> 2;
1639 ast_mutex_unlock(&qe
->parent
->lock
);
1643 static void leave_queue(struct queue_ent
*qe
)
1645 struct call_queue
*q
;
1646 struct queue_ent
*cur
, *prev
= NULL
;
1649 if (!(q
= qe
->parent
))
1651 ast_mutex_lock(&q
->lock
);
1654 for (cur
= q
->head
; cur
; cur
= cur
->next
) {
1658 /* Take us out of the queue */
1659 manager_event(EVENT_FLAG_CALL
, "Leave",
1660 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1661 qe
->chan
->name
, q
->name
, q
->count
, qe
->chan
->uniqueid
);
1663 ast_log(LOG_DEBUG
, "Queue '%s' Leave, Channel '%s'\n", q
->name
, qe
->chan
->name
);
1664 /* Take us out of the queue */
1666 prev
->next
= cur
->next
;
1668 q
->head
= cur
->next
;
1670 /* Renumber the people after us in the queue based on a new count */
1675 ast_mutex_unlock(&q
->lock
);
1677 if (q
->dead
&& !q
->count
) {
1678 /* It's dead and nobody is in it, so kill it */
1679 AST_LIST_LOCK(&queues
);
1680 AST_LIST_REMOVE(&queues
, q
, list
);
1681 AST_LIST_UNLOCK(&queues
);
1686 /* Hang up a list of outgoing calls */
1687 static void hangupcalls(struct callattempt
*outgoing
, struct ast_channel
*exception
)
1689 struct callattempt
*oo
;
1692 /* Hangup any existing lines we have open */
1693 if (outgoing
->chan
&& (outgoing
->chan
!= exception
))
1694 ast_hangup(outgoing
->chan
);
1696 outgoing
= outgoing
->q_next
;
1698 ao2_ref(oo
->member
, -1);
1704 /* traverse all defined queues which have calls waiting and contain this member
1705 return 0 if no other queue has precedence (higher weight) or 1 if found */
1706 static int compare_weight(struct call_queue
*rq
, struct member
*member
)
1708 struct call_queue
*q
;
1712 /* &qlock and &rq->lock already set by try_calling()
1713 * to solve deadlock */
1714 AST_LIST_TRAVERSE(&queues
, q
, list
) {
1715 if (q
== rq
) /* don't check myself, could deadlock */
1717 ast_mutex_lock(&q
->lock
);
1718 if (q
->count
&& q
->members
) {
1719 if ((mem
= ao2_find(q
->members
, member
, OBJ_POINTER
))) {
1720 ast_log(LOG_DEBUG
, "Found matching member %s in queue '%s'\n", mem
->interface
, q
->name
);
1721 if (q
->weight
> rq
->weight
) {
1722 ast_log(LOG_DEBUG
, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q
->name
, q
->weight
, q
->count
, rq
->name
, rq
->weight
, rq
->count
);
1728 ast_mutex_unlock(&q
->lock
);
1735 /*! \brief common hangup actions */
1736 static void do_hang(struct callattempt
*o
)
1739 ast_hangup(o
->chan
);
1743 static char *vars2manager(struct ast_channel
*chan
, char *vars
, size_t len
)
1745 char *tmp
= alloca(len
);
1747 if (pbx_builtin_serialize_variables(chan
, tmp
, len
)) {
1750 /* convert "\n" to "\nVariable: " */
1751 strcpy(vars
, "Variable: ");
1753 for (i
= 0, j
= 10; (i
< len
- 1) && (j
< len
- 1); i
++, j
++) {
1756 if (tmp
[i
+ 1] == '\0')
1758 if (tmp
[i
] == '\n') {
1762 ast_copy_string(&(vars
[j
]), "Variable: ", len
- j
);
1772 /* there are no channel variables; leave it blank */
1778 /*! \brief Part 2 of ring_one
1780 * Does error checking before attempting to request a channel and call a member. This
1781 * function is only called from ring_one
1783 static int ring_entry(struct queue_ent
*qe
, struct callattempt
*tmp
, int *busies
)
1789 const char *macrocontext
, *macroexten
;
1791 /* on entry here, we know that tmp->chan == NULL */
1792 if (qe
->parent
->wrapuptime
&& (time(NULL
) - tmp
->lastcall
< qe
->parent
->wrapuptime
)) {
1794 ast_log(LOG_DEBUG
, "Wrapuptime not yet expired for %s\n", tmp
->interface
);
1796 ast_cdr_busy(qe
->chan
->cdr
);
1797 tmp
->stillgoing
= 0;
1802 if (!qe
->parent
->ringinuse
&& (tmp
->member
->status
!= AST_DEVICE_NOT_INUSE
) && (tmp
->member
->status
!= AST_DEVICE_UNKNOWN
)) {
1804 ast_log(LOG_DEBUG
, "%s in use, can't receive call\n", tmp
->interface
);
1806 ast_cdr_busy(qe
->chan
->cdr
);
1807 tmp
->stillgoing
= 0;
1811 if (tmp
->member
->paused
) {
1813 ast_log(LOG_DEBUG
, "%s paused, can't receive call\n", tmp
->interface
);
1815 ast_cdr_busy(qe
->chan
->cdr
);
1816 tmp
->stillgoing
= 0;
1819 if (use_weight
&& compare_weight(qe
->parent
,tmp
->member
)) {
1820 ast_log(LOG_DEBUG
, "Priority queue delaying call to %s:%s\n", qe
->parent
->name
, tmp
->interface
);
1822 ast_cdr_busy(qe
->chan
->cdr
);
1823 tmp
->stillgoing
= 0;
1828 ast_copy_string(tech
, tmp
->interface
, sizeof(tech
));
1829 if ((location
= strchr(tech
, '/')))
1834 /* Request the peer */
1835 tmp
->chan
= ast_request(tech
, qe
->chan
->nativeformats
, location
, &status
);
1836 if (!tmp
->chan
) { /* If we can't, just go on to the next call */
1838 ast_cdr_busy(qe
->chan
->cdr
);
1839 tmp
->stillgoing
= 0;
1841 update_status(tmp
->member
->interface
, ast_device_state(tmp
->member
->interface
));
1843 ast_mutex_lock(&qe
->parent
->lock
);
1844 qe
->parent
->rrpos
++;
1845 ast_mutex_unlock(&qe
->parent
->lock
);
1851 tmp
->chan
->appl
= "AppQueue";
1852 tmp
->chan
->data
= "(Outgoing Line)";
1853 tmp
->chan
->whentohangup
= 0;
1854 if (tmp
->chan
->cid
.cid_num
)
1855 free(tmp
->chan
->cid
.cid_num
);
1856 tmp
->chan
->cid
.cid_num
= ast_strdup(qe
->chan
->cid
.cid_num
);
1857 if (tmp
->chan
->cid
.cid_name
)
1858 free(tmp
->chan
->cid
.cid_name
);
1859 tmp
->chan
->cid
.cid_name
= ast_strdup(qe
->chan
->cid
.cid_name
);
1860 if (tmp
->chan
->cid
.cid_ani
)
1861 free(tmp
->chan
->cid
.cid_ani
);
1862 tmp
->chan
->cid
.cid_ani
= ast_strdup(qe
->chan
->cid
.cid_ani
);
1864 /* Inherit specially named variables from parent channel */
1865 ast_channel_inherit_variables(qe
->chan
, tmp
->chan
);
1867 /* Presense of ADSI CPE on outgoing channel follows ours */
1868 tmp
->chan
->adsicpe
= qe
->chan
->adsicpe
;
1870 /* Inherit context and extension */
1871 ast_channel_lock(qe
->chan
);
1872 macrocontext
= pbx_builtin_getvar_helper(qe
->chan
, "MACRO_CONTEXT");
1873 if (!ast_strlen_zero(macrocontext
))
1874 ast_copy_string(tmp
->chan
->dialcontext
, macrocontext
, sizeof(tmp
->chan
->dialcontext
));
1876 ast_copy_string(tmp
->chan
->dialcontext
, qe
->chan
->context
, sizeof(tmp
->chan
->dialcontext
));
1877 macroexten
= pbx_builtin_getvar_helper(qe
->chan
, "MACRO_EXTEN");
1878 if (!ast_strlen_zero(macroexten
))
1879 ast_copy_string(tmp
->chan
->exten
, macroexten
, sizeof(tmp
->chan
->exten
));
1881 ast_copy_string(tmp
->chan
->exten
, qe
->chan
->exten
, sizeof(tmp
->chan
->exten
));
1882 ast_channel_unlock(qe
->chan
);
1884 /* Place the call, but don't wait on the answer */
1885 if ((res
= ast_call(tmp
->chan
, location
, 0))) {
1886 /* Again, keep going even if there's an error */
1888 ast_log(LOG_DEBUG
, "ast call on peer returned %d\n", res
);
1889 if (option_verbose
> 2)
1890 ast_verbose(VERBOSE_PREFIX_3
"Couldn't call %s\n", tmp
->interface
);
1894 } else if (qe
->parent
->eventwhencalled
) {
1897 manager_event(EVENT_FLAG_AGENT
, "AgentCalled",
1898 "AgentCalled: %s\r\n"
1900 "ChannelCalling: %s\r\n"
1902 "CallerIDName: %s\r\n"
1907 tmp
->interface
, tmp
->member
->membername
, qe
->chan
->name
,
1908 tmp
->chan
->cid
.cid_num
? tmp
->chan
->cid
.cid_num
: "unknown",
1909 tmp
->chan
->cid
.cid_name
? tmp
->chan
->cid
.cid_name
: "unknown",
1910 qe
->chan
->context
, qe
->chan
->exten
, qe
->chan
->priority
,
1911 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
1912 if (option_verbose
> 2)
1913 ast_verbose(VERBOSE_PREFIX_3
"Called %s\n", tmp
->interface
);
1919 /*! \brief find the entry with the best metric, or NULL */
1920 static struct callattempt
*find_best(struct callattempt
*outgoing
)
1922 struct callattempt
*best
= NULL
, *cur
;
1924 for (cur
= outgoing
; cur
; cur
= cur
->q_next
) {
1925 if (cur
->stillgoing
&& /* Not already done */
1926 !cur
->chan
&& /* Isn't already going */
1927 (!best
|| cur
->metric
< best
->metric
)) { /* We haven't found one yet, or it's better */
1935 /*! \brief Place a call to a queue member
1937 * Once metrics have been calculated for each member, this function is used
1938 * to place a call to the appropriate member (or members). The low-level
1939 * channel-handling and error detection is handled in ring_entry
1941 * Returns 1 if a member was called successfully, 0 otherwise
1943 static int ring_one(struct queue_ent
*qe
, struct callattempt
*outgoing
, int *busies
)
1948 struct callattempt
*best
= find_best(outgoing
);
1951 ast_log(LOG_DEBUG
, "Nobody left to try ringing in queue\n");
1954 if (qe
->parent
->strategy
== QUEUE_STRATEGY_RINGALL
) {
1955 struct callattempt
*cur
;
1956 /* Ring everyone who shares this best metric (for ringall) */
1957 for (cur
= outgoing
; cur
; cur
= cur
->q_next
) {
1958 if (cur
->stillgoing
&& !cur
->chan
&& cur
->metric
<= best
->metric
) {
1960 ast_log(LOG_DEBUG
, "(Parallel) Trying '%s' with metric %d\n", cur
->interface
, cur
->metric
);
1961 ret
|= ring_entry(qe
, cur
, busies
);
1965 /* Ring just the best channel */
1967 ast_log(LOG_DEBUG
, "Trying '%s' with metric %d\n", best
->interface
, best
->metric
);
1968 ret
= ring_entry(qe
, best
, busies
);
1975 static int store_next(struct queue_ent
*qe
, struct callattempt
*outgoing
)
1977 struct callattempt
*best
= find_best(outgoing
);
1980 /* Ring just the best channel */
1982 ast_log(LOG_DEBUG
, "Next is '%s' with metric %d\n", best
->interface
, best
->metric
);
1983 qe
->parent
->rrpos
= best
->metric
% 1000;
1985 /* Just increment rrpos */
1986 if (qe
->parent
->wrapped
) {
1987 /* No more channels, start over */
1988 qe
->parent
->rrpos
= 0;
1990 /* Prioritize next entry */
1991 qe
->parent
->rrpos
++;
1994 qe
->parent
->wrapped
= 0;
1999 static int say_periodic_announcement(struct queue_ent
*qe
)
2004 /* Get the current time */
2007 /* Check to see if it is time to announce */
2008 if ((now
- qe
->last_periodic_announce_time
) < qe
->parent
->periodicannouncefrequency
)
2011 /* Stop the music on hold so we can play our own file */
2012 ast_moh_stop(qe
->chan
);
2014 if (option_verbose
> 2)
2015 ast_verbose(VERBOSE_PREFIX_3
"Playing periodic announcement\n");
2017 /* Check to make sure we have a sound file. If not, reset to the first sound file */
2018 if (qe
->last_periodic_announce_sound
>= MAX_PERIODIC_ANNOUNCEMENTS
|| !strlen(qe
->parent
->sound_periodicannounce
[qe
->last_periodic_announce_sound
])) {
2019 qe
->last_periodic_announce_sound
= 0;
2022 /* play the announcement */
2023 res
= play_file(qe
->chan
, qe
->parent
->sound_periodicannounce
[qe
->last_periodic_announce_sound
]);
2025 if ((res
> 0 && !valid_exit(qe
, res
)) || res
< 0)
2028 /* Resume Music on Hold if the caller is going to stay in the queue */
2030 ast_moh_start(qe
->chan
, qe
->moh
, NULL
);
2032 /* update last_periodic_announce_time */
2033 qe
->last_periodic_announce_time
= now
;
2035 /* Update the current periodic announcement to the next announcement */
2036 qe
->last_periodic_announce_sound
++;
2041 static void record_abandoned(struct queue_ent
*qe
)
2043 ast_mutex_lock(&qe
->parent
->lock
);
2044 manager_event(EVENT_FLAG_AGENT
, "QueueCallerAbandon",
2048 "OriginalPosition: %d\r\n"
2050 qe
->parent
->name
, qe
->chan
->uniqueid
, qe
->pos
, qe
->opos
, (int)(time(NULL
) - qe
->start
));
2052 qe
->parent
->callsabandoned
++;
2053 ast_mutex_unlock(&qe
->parent
->lock
);
2056 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
2057 static void rna(int rnatime
, struct queue_ent
*qe
, char *interface
, char *membername
)
2059 if (option_verbose
> 2)
2060 ast_verbose( VERBOSE_PREFIX_3
"Nobody picked up in %d ms\n", rnatime
);
2061 ast_queue_log(qe
->parent
->name
, qe
->chan
->uniqueid
, membername
, "RINGNOANSWER", "%d", rnatime
);
2062 if (qe
->parent
->autopause
) {
2063 if (!set_member_paused(qe
->parent
->name
, interface
, 1)) {
2064 if (option_verbose
> 2)
2065 ast_verbose( VERBOSE_PREFIX_3
"Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface
, qe
->parent
->name
);
2067 if (option_verbose
> 2)
2068 ast_verbose( VERBOSE_PREFIX_3
"Failed to pause Queue Member %s in queue %s!\n", interface
, qe
->parent
->name
);
2074 #define AST_MAX_WATCHERS 256
2075 /*! \brief Wait for a member to answer the call
2077 * \param[in] qe the queue_ent corresponding to the caller in the queue
2078 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
2079 * \param[in] to the amount of time (in milliseconds) to wait for a response
2080 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
2081 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
2082 * \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
2083 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
2085 static struct callattempt
*wait_for_answer(struct queue_ent
*qe
, struct callattempt
*outgoing
, int *to
, char *digit
, int prebusies
, int caller_disconnect
, int forwardsallowed
)
2087 char *queue
= qe
->parent
->name
;
2088 struct callattempt
*o
, *start
= NULL
, *prev
= NULL
;
2090 int numbusies
= prebusies
;
2094 struct ast_frame
*f
;
2095 struct callattempt
*peer
= NULL
;
2096 struct ast_channel
*winner
;
2097 struct ast_channel
*in
= qe
->chan
;
2099 char membername
[80] = "";
2103 starttime
= (long) time(NULL
);
2105 while (*to
&& !peer
) {
2106 int numlines
, retry
, pos
= 1;
2107 struct ast_channel
*watchers
[AST_MAX_WATCHERS
];
2111 for (retry
= 0; retry
< 2; retry
++) {
2113 for (o
= outgoing
; o
; o
= o
->q_next
) { /* Keep track of important channels */
2114 if (o
->stillgoing
) { /* Keep track of important channels */
2117 watchers
[pos
++] = o
->chan
;
2121 prev
->call_next
= o
;
2127 if (pos
> 1 /* found */ || !stillgoing
/* nobody listening */ ||
2128 (qe
->parent
->strategy
!= QUEUE_STRATEGY_RINGALL
) /* ring would not be delivered */)
2130 /* On "ringall" strategy we only move to the next penalty level
2131 when *all* ringing phones are done in the current penalty level */
2132 ring_one(qe
, outgoing
, &numbusies
);
2135 if (pos
== 1 /* not found */) {
2136 if (numlines
== (numbusies
+ numnochan
)) {
2137 ast_log(LOG_DEBUG
, "Everyone is busy at this time\n");
2139 ast_log(LOG_NOTICE
, "No one is answering queue '%s' (%d/%d/%d)\n", queue
, numlines
, numbusies
, numnochan
);
2144 winner
= ast_waitfor_n(watchers
, pos
, to
);
2145 for (o
= start
; o
; o
= o
->call_next
) {
2146 if (o
->stillgoing
&& (o
->chan
) && (o
->chan
->_state
== AST_STATE_UP
)) {
2148 if (option_verbose
> 2)
2149 ast_verbose( VERBOSE_PREFIX_3
"%s answered %s\n", o
->chan
->name
, in
->name
);
2152 } else if (o
->chan
&& (o
->chan
== winner
)) {
2154 ast_copy_string(on
, o
->member
->interface
, sizeof(on
));
2155 ast_copy_string(membername
, o
->member
->membername
, sizeof(membername
));
2157 if (!ast_strlen_zero(o
->chan
->call_forward
) && !forwardsallowed
) {
2158 if (option_verbose
> 2)
2159 ast_verbose(VERBOSE_PREFIX_3
"Forwarding %s to '%s' prevented.\n", in
->name
, o
->chan
->call_forward
);
2164 } else if (!ast_strlen_zero(o
->chan
->call_forward
)) {
2169 ast_copy_string(tmpchan
, o
->chan
->call_forward
, sizeof(tmpchan
));
2170 if ((stuff
= strchr(tmpchan
, '/'))) {
2174 snprintf(tmpchan
, sizeof(tmpchan
), "%s@%s", o
->chan
->call_forward
, o
->chan
->context
);
2178 /* Before processing channel, go ahead and check for forwarding */
2179 if (option_verbose
> 2)
2180 ast_verbose(VERBOSE_PREFIX_3
"Now forwarding %s to '%s/%s' (thanks to %s)\n", in
->name
, tech
, stuff
, o
->chan
->name
);
2181 /* Setup parameters */
2182 o
->chan
= ast_request(tech
, in
->nativeformats
, stuff
, &status
);
2184 ast_log(LOG_NOTICE
, "Unable to create local channel for call forward to '%s/%s'\n", tech
, stuff
);
2188 ast_channel_inherit_variables(in
, o
->chan
);
2189 ast_channel_datastore_inherit(in
, o
->chan
);
2190 if (o
->chan
->cid
.cid_num
)
2191 free(o
->chan
->cid
.cid_num
);
2192 o
->chan
->cid
.cid_num
= ast_strdup(in
->cid
.cid_num
);
2194 if (o
->chan
->cid
.cid_name
)
2195 free(o
->chan
->cid
.cid_name
);
2196 o
->chan
->cid
.cid_name
= ast_strdup(in
->cid
.cid_name
);
2198 ast_string_field_set(o
->chan
, accountcode
, in
->accountcode
);
2199 o
->chan
->cdrflags
= in
->cdrflags
;
2201 if (in
->cid
.cid_ani
) {
2202 if (o
->chan
->cid
.cid_ani
)
2203 free(o
->chan
->cid
.cid_ani
);
2204 o
->chan
->cid
.cid_ani
= ast_strdup(in
->cid
.cid_ani
);
2206 if (o
->chan
->cid
.cid_rdnis
)
2207 free(o
->chan
->cid
.cid_rdnis
);
2208 o
->chan
->cid
.cid_rdnis
= ast_strdup(S_OR(in
->macroexten
, in
->exten
));
2209 if (ast_call(o
->chan
, tmpchan
, 0)) {
2210 ast_log(LOG_NOTICE
, "Failed to dial on local channel for call forward to '%s'\n", tmpchan
);
2215 /* Hangup the original channel now, in case we needed it */
2219 f
= ast_read(winner
);
2221 if (f
->frametype
== AST_FRAME_CONTROL
) {
2222 switch (f
->subclass
) {
2223 case AST_CONTROL_ANSWER
:
2224 /* This is our guy if someone answered. */
2226 if (option_verbose
> 2)
2227 ast_verbose( VERBOSE_PREFIX_3
"%s answered %s\n", o
->chan
->name
, in
->name
);
2231 case AST_CONTROL_BUSY
:
2232 if (option_verbose
> 2)
2233 ast_verbose( VERBOSE_PREFIX_3
"%s is busy\n", o
->chan
->name
);
2235 ast_cdr_busy(in
->cdr
);
2237 endtime
= (long)time(NULL
);
2238 endtime
-= starttime
;
2239 rna(endtime
*1000, qe
, on
, membername
);
2240 if (qe
->parent
->strategy
!= QUEUE_STRATEGY_RINGALL
) {
2241 if (qe
->parent
->timeoutrestart
)
2243 ring_one(qe
, outgoing
, &numbusies
);
2247 case AST_CONTROL_CONGESTION
:
2248 if (option_verbose
> 2)
2249 ast_verbose( VERBOSE_PREFIX_3
"%s is circuit-busy\n", o
->chan
->name
);
2251 ast_cdr_busy(in
->cdr
);
2252 endtime
= (long)time(NULL
);
2253 endtime
-= starttime
;
2254 rna(endtime
*1000, qe
, on
, membername
);
2256 if (qe
->parent
->strategy
!= QUEUE_STRATEGY_RINGALL
) {
2257 if (qe
->parent
->timeoutrestart
)
2259 ring_one(qe
, outgoing
, &numbusies
);
2263 case AST_CONTROL_RINGING
:
2264 if (option_verbose
> 2)
2265 ast_verbose( VERBOSE_PREFIX_3
"%s is ringing\n", o
->chan
->name
);
2267 case AST_CONTROL_OFFHOOK
:
2268 /* Ignore going off hook */
2271 ast_log(LOG_DEBUG
, "Dunno what to do with control type %d\n", f
->subclass
);
2276 endtime
= (long) time(NULL
) - starttime
;
2277 rna(endtime
* 1000, qe
, on
, membername
);
2279 if (qe
->parent
->strategy
!= QUEUE_STRATEGY_RINGALL
) {
2280 if (qe
->parent
->timeoutrestart
)
2282 ring_one(qe
, outgoing
, &numbusies
);
2289 if (!f
|| ((f
->frametype
== AST_FRAME_CONTROL
) && (f
->subclass
== AST_CONTROL_HANGUP
))) {
2296 if ((f
->frametype
== AST_FRAME_DTMF
) && caller_disconnect
&& (f
->subclass
== '*')) {
2297 if (option_verbose
> 3)
2298 ast_verbose(VERBOSE_PREFIX_3
"User hit %c to disconnect call.\n", f
->subclass
);
2303 if ((f
->frametype
== AST_FRAME_DTMF
) && valid_exit(qe
, f
->subclass
)) {
2304 if (option_verbose
> 3)
2305 ast_verbose(VERBOSE_PREFIX_3
"User pressed digit: %c\n", f
->subclass
);
2307 *digit
= f
->subclass
;
2314 for (o
= start
; o
; o
= o
->call_next
)
2315 rna(orig
, qe
, o
->interface
, o
->member
->membername
);
2321 /*! \brief Check if we should start attempting to call queue members
2323 * The behavior of this function is dependent first on whether autofill is enabled
2324 * and second on whether the ring strategy is ringall. If autofill is not enabled,
2325 * then return true if we're the head of the queue. If autofill is enabled, then
2326 * we count the available members and see if the number of available members is enough
2327 * that given our position in the queue, we would theoretically be able to connect to
2328 * one of those available members
2330 static int is_our_turn(struct queue_ent
*qe
)
2332 struct queue_ent
*ch
;
2338 if (!qe
->parent
->autofill
) {
2339 /* Atomically read the parent head -- does not need a lock */
2340 ch
= qe
->parent
->head
;
2341 /* If we are now at the top of the head, break out */
2344 ast_log(LOG_DEBUG
, "It's our turn (%s).\n", qe
->chan
->name
);
2348 ast_log(LOG_DEBUG
, "It's not our turn (%s).\n", qe
->chan
->name
);
2353 /* This needs a lock. How many members are available to be served? */
2354 ast_mutex_lock(&qe
->parent
->lock
);
2356 ch
= qe
->parent
->head
;
2358 if (qe
->parent
->strategy
== QUEUE_STRATEGY_RINGALL
) {
2360 ast_log(LOG_DEBUG
, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
2363 struct ao2_iterator mem_iter
= ao2_iterator_init(qe
->parent
->members
, 0);
2364 while ((cur
= ao2_iterator_next(&mem_iter
))) {
2365 switch (cur
->status
) {
2366 case AST_DEVICE_INUSE
:
2367 if (!qe
->parent
->ringinuse
)
2369 /* else fall through */
2370 case AST_DEVICE_NOT_INUSE
:
2371 case AST_DEVICE_UNKNOWN
:
2381 ast_log(LOG_DEBUG
, "There are %d available members.\n", avl
);
2383 while ((idx
< avl
) && (ch
) && (ch
!= qe
)) {
2389 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2390 if (ch
&& idx
< avl
) {
2392 ast_log(LOG_DEBUG
, "It's our turn (%s).\n", qe
->chan
->name
);
2396 ast_log(LOG_DEBUG
, "It's not our turn (%s).\n", qe
->chan
->name
);
2400 ast_mutex_unlock(&qe
->parent
->lock
);
2405 /*! \brief The waiting areas for callers who are not actively calling members
2407 * This function is one large loop. This function will return if a caller
2408 * either exits the queue or it becomes that caller's turn to attempt calling
2409 * queue members. Inside the loop, we service the caller with periodic announcements,
2410 * holdtime announcements, etc. as configured in queues.conf
2412 * \retval 0 if the caller's turn has arrived
2413 * \retval -1 if the caller should exit the queue.
2415 static int wait_our_turn(struct queue_ent
*qe
, int ringing
, enum queue_result
*reason
)
2419 /* This is the holding pen for callers 2 through maxlen */
2421 enum queue_member_status stat
;
2423 if (is_our_turn(qe
))
2426 /* If we have timed out, break out */
2427 if (qe
->expire
&& (time(NULL
) > qe
->expire
)) {
2428 *reason
= QUEUE_TIMEOUT
;
2432 stat
= get_member_status(qe
->parent
, qe
->max_penalty
);
2434 /* leave the queue if no agents, if enabled */
2435 if (qe
->parent
->leavewhenempty
&& (stat
== QUEUE_NO_MEMBERS
)) {
2436 *reason
= QUEUE_LEAVEEMPTY
;
2437 ast_queue_log(qe
->parent
->name
, qe
->chan
->uniqueid
, "NONE", "EXITEMPTY", "%d|%d|%ld", qe
->pos
, qe
->opos
, (long)time(NULL
) - qe
->start
);
2442 /* leave the queue if no reachable agents, if enabled */
2443 if ((qe
->parent
->leavewhenempty
== QUEUE_EMPTY_STRICT
) && (stat
== QUEUE_NO_REACHABLE_MEMBERS
)) {
2444 *reason
= QUEUE_LEAVEUNAVAIL
;
2445 ast_queue_log(qe
->parent
->name
, qe
->chan
->uniqueid
, "NONE", "EXITEMPTY", "%d|%d|%ld", qe
->pos
, qe
->opos
, (long)time(NULL
) - qe
->start
);
2450 /* Make a position announcement, if enabled */
2451 if (qe
->parent
->announcefrequency
&& !ringing
&&
2452 (res
= say_position(qe
)))
2455 /* Make a periodic announcement, if enabled */
2456 if (qe
->parent
->periodicannouncefrequency
&& !ringing
&&
2457 (res
= say_periodic_announcement(qe
)))
2460 /* Wait a second before checking again */
2461 if ((res
= ast_waitfordigit(qe
->chan
, RECHECK
* 1000))) {
2462 if (res
> 0 && !valid_exit(qe
, res
))
2472 static int update_queue(struct call_queue
*q
, struct member
*member
, int callcompletedinsl
)
2474 ast_mutex_lock(&q
->lock
);
2475 time(&member
->lastcall
);
2477 q
->callscompleted
++;
2478 if (callcompletedinsl
)
2479 q
->callscompletedinsl
++;
2480 ast_mutex_unlock(&q
->lock
);
2484 /*! \brief Calculate the metric of each member in the outgoing callattempts
2486 * A numeric metric is given to each member depending on the ring strategy used
2487 * by the queue. Members with lower metrics will be called before members with
2490 static int calc_metric(struct call_queue
*q
, struct member
*mem
, int pos
, struct queue_ent
*qe
, struct callattempt
*tmp
)
2492 if (qe
->max_penalty
&& (mem
->penalty
> qe
->max_penalty
))
2495 switch (q
->strategy
) {
2496 case QUEUE_STRATEGY_RINGALL
:
2497 /* Everyone equal, except for penalty */
2498 tmp
->metric
= mem
->penalty
* 1000000;
2500 case QUEUE_STRATEGY_ROUNDROBIN
:
2503 /* No more channels, start over */
2506 /* Prioritize next entry */
2512 case QUEUE_STRATEGY_RRMEMORY
:
2513 if (pos
< q
->rrpos
) {
2514 tmp
->metric
= 1000 + pos
;
2517 /* Indicate there is another priority */
2521 tmp
->metric
+= mem
->penalty
* 1000000;
2523 case QUEUE_STRATEGY_RANDOM
:
2524 tmp
->metric
= ast_random() % 1000;
2525 tmp
->metric
+= mem
->penalty
* 1000000;
2527 case QUEUE_STRATEGY_FEWESTCALLS
:
2528 tmp
->metric
= mem
->calls
;
2529 tmp
->metric
+= mem
->penalty
* 1000000;
2531 case QUEUE_STRATEGY_LEASTRECENT
:
2535 tmp
->metric
= 1000000 - (time(NULL
) - mem
->lastcall
);
2536 tmp
->metric
+= mem
->penalty
* 1000000;
2539 ast_log(LOG_WARNING
, "Can't calculate metric for unknown strategy %d\n", q
->strategy
);
2545 struct queue_transfer_ds
{
2546 struct queue_ent
*qe
;
2547 struct member
*member
;
2551 static void queue_transfer_destroy(void *data
)
2553 struct queue_transfer_ds
*qtds
= data
;
2557 /*! \brief a datastore used to help correctly log attended transfers of queue callers
2559 static const struct ast_datastore_info queue_transfer_info
= {
2560 .type
= "queue_transfer",
2561 .chan_fixup
= queue_transfer_fixup
,
2562 .destroy
= queue_transfer_destroy
,
2565 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
2567 * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
2568 * the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
2569 * to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
2571 * At the end of this, we want to remove the datastore so that this fixup function is not called on any
2572 * future masquerades of the caller during the current call.
2574 static void queue_transfer_fixup(void *data
, struct ast_channel
*old_chan
, struct ast_channel
*new_chan
)
2576 struct queue_transfer_ds
*qtds
= data
;
2577 struct queue_ent
*qe
= qtds
->qe
;
2578 struct member
*member
= qtds
->member
;
2579 int callstart
= qtds
->starttime
;
2580 struct ast_datastore
*datastore
;
2582 ast_queue_log(qe
->parent
->name
, qe
->chan
->uniqueid
, member
->membername
, "TRANSFER", "%s|%s|%ld|%ld",
2583 new_chan
->exten
, new_chan
->context
, (long) (callstart
- qe
->start
),
2584 (long) (time(NULL
) - callstart
));
2586 if (!(datastore
= ast_channel_datastore_find(new_chan
, &queue_transfer_info
, NULL
))) {
2587 ast_log(LOG_WARNING
, "Can't find the queue_transfer datastore.\n");
2591 ast_channel_datastore_remove(new_chan
, datastore
);
2594 /*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
2596 * When a caller is atxferred, then the queue_transfer_info datastore
2597 * is removed from the channel. If it's still there after the bridge is
2598 * broken, then the caller was not atxferred.
2600 static int attended_transfer_occurred(struct ast_channel
*chan
)
2602 return ast_channel_datastore_find(chan
, &queue_transfer_info
, NULL
) ? 0 : 1;
2605 /*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
2607 static void setup_transfer_datastore(struct queue_ent
*qe
, struct member
*member
, int starttime
)
2609 struct ast_datastore
*ds
;
2610 struct queue_transfer_ds
*qtds
= ast_calloc(1, sizeof(*qtds
));
2613 ast_log(LOG_WARNING
, "Memory allocation error!\n");
2617 ast_channel_lock(qe
->chan
);
2618 if (!(ds
= ast_channel_datastore_alloc(&queue_transfer_info
, NULL
))) {
2619 ast_channel_unlock(qe
->chan
);
2620 ast_log(LOG_WARNING
, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
2625 /* This member is refcounted in try_calling, so no need to add it here, too */
2626 qtds
->member
= member
;
2627 qtds
->starttime
= starttime
;
2629 ast_channel_datastore_add(qe
->chan
, ds
);
2630 ast_channel_unlock(qe
->chan
);
2634 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
2636 * Here is the process of this function
2637 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
2638 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
2639 * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
2640 * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
2641 * during each iteration, we call calc_metric to determine which members should be rung when.
2642 * 3. Call ring_one to place a call to the appropriate member(s)
2643 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
2644 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
2645 * 6. Start the monitor or mixmonitor if the option is set
2646 * 7. Remove the caller from the queue to allow other callers to advance
2647 * 8. Bridge the call.
2648 * 9. Do any post processing after the call has disconnected.
2650 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
2651 * \param[in] options the options passed as the third parameter to the Queue() application
2652 * \param[in] url the url passed as the fourth parameter to the Queue() application
2653 * \param[in,out] tries the number of times we have tried calling queue members
2654 * \param[out] noption set if the call to Queue() has the 'n' option set.
2655 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
2658 static int try_calling(struct queue_ent
*qe
, const char *options
, char *announceoverride
, const char *url
, int *tries
, int *noption
, const char *agi
)
2661 struct callattempt
*outgoing
= NULL
; /* the list of calls we are building */
2663 char oldexten
[AST_MAX_EXTENSION
]="";
2664 char oldcontext
[AST_MAX_CONTEXT
]="";
2665 char queuename
[256]="";
2666 struct ast_channel
*peer
;
2667 struct ast_channel
*which
;
2668 struct callattempt
*lpeer
;
2669 struct member
*member
;
2670 struct ast_app
*app
;
2671 int res
= 0, bridge
= 0;
2674 char *announce
= NULL
;
2677 time_t now
= time(NULL
);
2678 struct ast_bridge_config bridge_config
;
2679 char nondataquality
= 1;
2680 char *agiexec
= NULL
;
2682 const char *monitorfilename
;
2683 const char *monitor_exec
;
2684 const char *monitor_options
;
2685 char tmpid
[256], tmpid2
[256];
2686 char meid
[1024], meid2
[1024];
2687 char mixmonargs
[1512];
2688 struct ast_app
*mixmonapp
= NULL
;
2691 int forwardsallowed
= 1;
2692 int callcompletedinsl
;
2693 struct ao2_iterator memi
;
2694 struct ast_datastore
*datastore
;
2696 ast_channel_lock(qe
->chan
);
2697 datastore
= ast_channel_datastore_find(qe
->chan
, &dialed_interface_info
, NULL
);
2698 ast_channel_unlock(qe
->chan
);
2700 memset(&bridge_config
, 0, sizeof(bridge_config
));
2703 for (; options
&& *options
; options
++)
2706 ast_set_flag(&(bridge_config
.features_callee
), AST_FEATURE_REDIRECT
);
2709 ast_set_flag(&(bridge_config
.features_caller
), AST_FEATURE_REDIRECT
);
2712 ast_set_flag(&(bridge_config
.features_callee
), AST_FEATURE_AUTOMON
);
2715 ast_set_flag(&(bridge_config
.features_caller
), AST_FEATURE_AUTOMON
);
2721 ast_set_flag(&(bridge_config
.features_callee
), AST_FEATURE_DISCONNECT
);
2724 ast_set_flag(&(bridge_config
.features_caller
), AST_FEATURE_DISCONNECT
);
2727 if (qe
->parent
->strategy
== QUEUE_STRATEGY_ROUNDROBIN
|| qe
->parent
->strategy
== QUEUE_STRATEGY_RRMEMORY
)
2730 *tries
= qe
->parent
->membercount
;
2734 forwardsallowed
= 0;
2738 /* Hold the lock while we setup the outgoing calls */
2740 AST_LIST_LOCK(&queues
);
2741 ast_mutex_lock(&qe
->parent
->lock
);
2743 ast_log(LOG_DEBUG
, "%s is trying to call a queue member.\n",
2745 ast_copy_string(queuename
, qe
->parent
->name
, sizeof(queuename
));
2746 if (!ast_strlen_zero(qe
->announce
))
2747 announce
= qe
->announce
;
2748 if (!ast_strlen_zero(announceoverride
))
2749 announce
= announceoverride
;
2751 memi
= ao2_iterator_init(qe
->parent
->members
, 0);
2752 while ((cur
= ao2_iterator_next(&memi
))) {
2753 struct callattempt
*tmp
= ast_calloc(1, sizeof(*tmp
));
2754 struct ast_dialed_interface
*di
;
2755 AST_LIST_HEAD(, ast_dialed_interface
) *dialed_interfaces
;
2758 ast_mutex_unlock(&qe
->parent
->lock
);
2760 AST_LIST_UNLOCK(&queues
);
2764 if (!(datastore
= ast_channel_datastore_alloc(&dialed_interface_info
, NULL
))) {
2766 ast_mutex_unlock(&qe
->parent
->lock
);
2768 AST_LIST_UNLOCK(&queues
);
2772 datastore
->inheritance
= DATASTORE_INHERIT_FOREVER
;
2773 if (!(dialed_interfaces
= ast_calloc(1, sizeof(*dialed_interfaces
)))) {
2775 ast_mutex_unlock(&qe
->parent
->lock
);
2777 AST_LIST_UNLOCK(&queues
);
2781 datastore
->data
= dialed_interfaces
;
2782 AST_LIST_HEAD_INIT(dialed_interfaces
);
2784 ast_channel_lock(qe
->chan
);
2785 ast_channel_datastore_add(qe
->chan
, datastore
);
2786 ast_channel_unlock(qe
->chan
);
2788 dialed_interfaces
= datastore
->data
;
2790 AST_LIST_LOCK(dialed_interfaces
);
2791 AST_LIST_TRAVERSE(dialed_interfaces
, di
, list
) {
2792 if (!strcasecmp(cur
->interface
, di
->interface
)) {
2793 ast_log(LOG_DEBUG
, "Skipping dialing interface '%s' since it has already been dialed\n",
2798 AST_LIST_UNLOCK(dialed_interfaces
);
2805 /* It is always ok to dial a Local interface. We only keep track of
2806 * which "real" interfaces have been dialed. The Local channel will
2807 * inherit this list so that if it ends up dialing a real interface,
2808 * it won't call one that has already been called. */
2809 if (strncasecmp(cur
->interface
, "Local/", 6)) {
2810 if (!(di
= ast_calloc(1, sizeof(*di
) + strlen(cur
->interface
)))) {
2812 ast_mutex_unlock(&qe
->parent
->lock
);
2814 AST_LIST_UNLOCK(&queues
);
2818 strcpy(di
->interface
, cur
->interface
);
2820 AST_LIST_LOCK(dialed_interfaces
);
2821 AST_LIST_INSERT_TAIL(dialed_interfaces
, di
, list
);
2822 AST_LIST_UNLOCK(dialed_interfaces
);
2825 tmp
->stillgoing
= -1;
2827 tmp
->oldstatus
= cur
->status
;
2828 tmp
->lastcall
= cur
->lastcall
;
2829 ast_copy_string(tmp
->interface
, cur
->interface
, sizeof(tmp
->interface
));
2830 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2831 just calculate their metric for the appropriate strategy */
2832 if (!calc_metric(qe
->parent
, cur
, x
++, qe
, tmp
)) {
2833 /* Put them in the list of outgoing thingies... We're ready now.
2834 XXX If we're forcibly removed, these outgoing calls won't get
2836 tmp
->q_next
= outgoing
;
2838 /* If this line is up, don't try anybody else */
2839 if (outgoing
->chan
&& (outgoing
->chan
->_state
== AST_STATE_UP
))
2846 if (qe
->expire
&& (!qe
->parent
->timeout
|| (qe
->expire
- now
) <= qe
->parent
->timeout
))
2847 to
= (qe
->expire
- now
) * 1000;
2849 to
= (qe
->parent
->timeout
) ? qe
->parent
->timeout
* 1000 : -1;
2851 ast_mutex_unlock(&qe
->parent
->lock
);
2852 ring_one(qe
, outgoing
, &numbusies
);
2854 AST_LIST_UNLOCK(&queues
);
2855 lpeer
= wait_for_answer(qe
, outgoing
, &to
, &digit
, numbusies
, ast_test_flag(&(bridge_config
.features_caller
), AST_FEATURE_DISCONNECT
), forwardsallowed
);
2856 /* The ast_channel_datastore_remove() function could fail here if the
2857 * datastore was moved to another channel during a masquerade. If this is
2858 * the case, don't free the datastore here because later, when the channel
2859 * to which the datastore was moved hangs up, it will attempt to free this
2860 * datastore again, causing a crash
2862 if (datastore
&& !ast_channel_datastore_remove(qe
->chan
, datastore
)) {
2863 ast_channel_datastore_free(datastore
);
2865 ast_mutex_lock(&qe
->parent
->lock
);
2866 if (qe
->parent
->strategy
== QUEUE_STRATEGY_RRMEMORY
) {
2867 store_next(qe
, outgoing
);
2869 ast_mutex_unlock(&qe
->parent
->lock
);
2870 peer
= lpeer
? lpeer
->chan
: NULL
;
2874 /* Must gotten hung up */
2877 /* User exited by pressing a digit */
2880 if (option_debug
&& res
== -1)
2881 ast_log(LOG_DEBUG
, "%s: Nobody answered.\n", qe
->chan
->name
);
2882 } else { /* peer is valid */
2883 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2884 we will always return with -1 so that it is hung up properly after the
2886 if (!strcmp(qe
->chan
->tech
->type
, "Zap"))
2887 ast_channel_setoption(qe
->chan
, AST_OPTION_TONE_VERIFY
, &nondataquality
, sizeof(nondataquality
), 0);
2888 if (!strcmp(peer
->tech
->type
, "Zap"))
2889 ast_channel_setoption(peer
, AST_OPTION_TONE_VERIFY
, &nondataquality
, sizeof(nondataquality
), 0);
2890 /* Update parameters for the queue */
2892 recalc_holdtime(qe
, (now
- qe
->start
));
2893 ast_mutex_lock(&qe
->parent
->lock
);
2894 callcompletedinsl
= ((now
- qe
->start
) <= qe
->parent
->servicelevel
);
2895 ast_mutex_unlock(&qe
->parent
->lock
);
2896 member
= lpeer
->member
;
2897 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
2899 hangupcalls(outgoing
, peer
);
2901 if (announce
|| qe
->parent
->reportholdtime
|| qe
->parent
->memberdelay
) {
2904 res2
= ast_autoservice_start(qe
->chan
);
2906 if (qe
->parent
->memberdelay
) {
2907 ast_log(LOG_NOTICE
, "Delaying member connect for %d seconds\n", qe
->parent
->memberdelay
);
2908 res2
|= ast_safe_sleep(peer
, qe
->parent
->memberdelay
* 1000);
2910 if (!res2
&& announce
) {
2911 play_file(peer
, announce
);
2913 if (!res2
&& qe
->parent
->reportholdtime
) {
2914 if (!play_file(peer
, qe
->parent
->sound_reporthold
)) {
2918 holdtime
= abs((now
- qe
->start
) / 60);
2920 play_file(peer
, qe
->parent
->sound_lessthan
);
2921 ast_say_number(peer
, 2, AST_DIGIT_ANY
, peer
->language
, NULL
);
2923 ast_say_number(peer
, holdtime
, AST_DIGIT_ANY
, peer
->language
, NULL
);
2924 play_file(peer
, qe
->parent
->sound_minutes
);
2928 res2
|= ast_autoservice_stop(qe
->chan
);
2929 if (peer
->_softhangup
) {
2930 /* Agent must have hung up */
2931 ast_log(LOG_WARNING
, "Agent on %s hungup on the customer.\n", peer
->name
);
2932 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "AGENTDUMP", "%s", "");
2933 if (qe
->parent
->eventwhencalled
)
2934 manager_event(EVENT_FLAG_AGENT
, "AgentDump",
2939 "MemberName: %s\r\n"
2941 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->interface
, member
->membername
,
2942 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
2944 ao2_ref(member
, -1);
2947 /* Caller must have hung up just before being connected*/
2948 ast_log(LOG_NOTICE
, "Caller was about to talk to agent on %s but the caller hungup.\n", peer
->name
);
2949 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "ABANDON", "%d|%d|%ld", qe
->pos
, qe
->opos
, (long)time(NULL
) - qe
->start
);
2950 record_abandoned(qe
);
2952 ao2_ref(member
, -1);
2956 /* Stop music on hold */
2957 ast_moh_stop(qe
->chan
);
2958 /* If appropriate, log that we have a destination channel */
2960 ast_cdr_setdestchan(qe
->chan
->cdr
, peer
->name
);
2961 /* Make sure channels are compatible */
2962 res
= ast_channel_make_compatible(qe
->chan
, peer
);
2964 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "SYSCOMPAT", "%s", "");
2965 ast_log(LOG_WARNING
, "Had to drop call because I couldn't make %s compatible with %s\n", qe
->chan
->name
, peer
->name
);
2966 record_abandoned(qe
);
2968 ao2_ref(member
, -1);
2972 if (qe
->parent
->setinterfacevar
)
2973 pbx_builtin_setvar_helper(qe
->chan
, "MEMBERINTERFACE", member
->interface
);
2975 /* Begin Monitoring */
2976 if (qe
->parent
->monfmt
&& *qe
->parent
->monfmt
) {
2977 if (!qe
->parent
->montype
) {
2979 ast_log(LOG_DEBUG
, "Starting Monitor as requested.\n");
2980 monitorfilename
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_FILENAME");
2981 if (pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_EXEC_ARGS"))
2985 if (monitorfilename
)
2986 ast_monitor_start(which
, qe
->parent
->monfmt
, monitorfilename
, 1 );
2987 else if (qe
->chan
->cdr
)
2988 ast_monitor_start(which
, qe
->parent
->monfmt
, qe
->chan
->cdr
->uniqueid
, 1 );
2990 /* Last ditch effort -- no CDR, make up something */
2991 snprintf(tmpid
, sizeof(tmpid
), "chan-%lx", ast_random());
2992 ast_monitor_start(which
, qe
->parent
->monfmt
, tmpid
, 1 );
2994 if (qe
->parent
->monjoin
)
2995 ast_monitor_setjoinfiles(which
, 1);
2998 ast_log(LOG_DEBUG
, "Starting MixMonitor as requested.\n");
2999 monitorfilename
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_FILENAME");
3000 if (!monitorfilename
) {
3002 ast_copy_string(tmpid
, qe
->chan
->cdr
->uniqueid
, sizeof(tmpid
)-1);
3004 snprintf(tmpid
, sizeof(tmpid
), "chan-%lx", ast_random());
3006 ast_copy_string(tmpid2
, monitorfilename
, sizeof(tmpid2
)-1);
3007 for (p
= tmpid2
; *p
; p
++) {
3008 if (*p
== '^' && *(p
+1) == '{') {
3013 memset(tmpid
, 0, sizeof(tmpid
));
3014 pbx_substitute_variables_helper(qe
->chan
, tmpid2
, tmpid
, sizeof(tmpid
) - 1);
3017 monitor_exec
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_EXEC");
3018 monitor_options
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_OPTIONS");
3021 ast_copy_string(meid2
, monitor_exec
, sizeof(meid2
)-1);
3022 for (p
= meid2
; *p
; p
++) {
3023 if (*p
== '^' && *(p
+1) == '{') {
3028 memset(meid
, 0, sizeof(meid
));
3029 pbx_substitute_variables_helper(qe
->chan
, meid2
, meid
, sizeof(meid
) - 1);
3032 snprintf(tmpid2
, sizeof(tmpid2
)-1, "%s.%s", tmpid
, qe
->parent
->monfmt
);
3034 mixmonapp
= pbx_findapp("MixMonitor");
3036 if (strchr(tmpid2
, '|')) {
3037 ast_log(LOG_WARNING
, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
3041 if (!monitor_options
)
3042 monitor_options
= "";
3044 if (strchr(monitor_options
, '|')) {
3045 ast_log(LOG_WARNING
, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
3050 if (!ast_strlen_zero(monitor_exec
))
3051 snprintf(mixmonargs
, sizeof(mixmonargs
)-1, "%s|b%s|%s", tmpid2
, monitor_options
, monitor_exec
);
3053 snprintf(mixmonargs
, sizeof(mixmonargs
)-1, "%s|b%s", tmpid2
, monitor_options
);
3056 ast_log(LOG_DEBUG
, "Arguments being passed to MixMonitor: %s\n", mixmonargs
);
3057 /* We purposely lock the CDR so that pbx_exec does not update the application data */
3059 ast_set_flag(qe
->chan
->cdr
, AST_CDR_FLAG_LOCKED
);
3060 ret
= pbx_exec(qe
->chan
, mixmonapp
, mixmonargs
);
3062 ast_clear_flag(qe
->chan
->cdr
, AST_CDR_FLAG_LOCKED
);
3065 ast_log(LOG_WARNING
, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
3069 /* Drop out of the queue at this point, to prepare for next caller */
3071 if (!ast_strlen_zero(url
) && ast_channel_supports_html(peer
)) {
3073 ast_log(LOG_DEBUG
, "app_queue: sendurl=%s.\n", url
);
3074 ast_channel_sendurl(peer
, url
);
3076 if (!ast_strlen_zero(agi
)) {
3078 ast_log(LOG_DEBUG
, "app_queue: agi=%s.\n", agi
);
3079 app
= pbx_findapp("agi");
3081 agiexec
= ast_strdupa(agi
);
3082 ret
= pbx_exec(qe
->chan
, app
, agiexec
);
3084 ast_log(LOG_WARNING
, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
3087 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "CONNECT", "%ld|%s", (long)time(NULL
) - qe
->start
, peer
->uniqueid
);
3088 if (qe
->parent
->eventwhencalled
)
3089 manager_event(EVENT_FLAG_AGENT
, "AgentConnect",
3094 "MemberName: %s\r\n"
3096 "BridgedChannel: %s\r\n"
3098 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->interface
, member
->membername
,
3099 (long)time(NULL
) - qe
->start
, peer
->uniqueid
,
3100 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
3101 ast_copy_string(oldcontext
, qe
->chan
->context
, sizeof(oldcontext
));
3102 ast_copy_string(oldexten
, qe
->chan
->exten
, sizeof(oldexten
));
3105 if (member
->status
== AST_DEVICE_NOT_INUSE
)
3106 ast_log(LOG_WARNING
, "The device state of this queue member, %s, is still 'Not in Use' when it probably should not be! Please check UPGRADE.txt for correct configuration settings.\n", member
->membername
);
3108 setup_transfer_datastore(qe
, member
, callstart
);
3109 bridge
= ast_bridge_call(qe
->chan
,peer
, &bridge_config
);
3111 if (!attended_transfer_occurred(qe
->chan
)) {
3112 if (strcasecmp(oldcontext
, qe
->chan
->context
) || strcasecmp(oldexten
, qe
->chan
->exten
)) {
3113 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "TRANSFER", "%s|%s|%ld|%ld",
3114 qe
->chan
->exten
, qe
->chan
->context
, (long) (callstart
- qe
->start
),
3115 (long) (time(NULL
) - callstart
));
3116 } else if (qe
->chan
->_softhangup
) {
3117 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "COMPLETECALLER", "%ld|%ld|%d",
3118 (long) (callstart
- qe
->start
), (long) (time(NULL
) - callstart
), qe
->opos
);
3119 if (qe
->parent
->eventwhencalled
)
3120 manager_event(EVENT_FLAG_AGENT
, "AgentComplete",
3125 "MemberName: %s\r\n"
3128 "Reason: caller\r\n"
3130 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->interface
, member
->membername
,
3131 (long)(callstart
- qe
->start
), (long)(time(NULL
) - callstart
),
3132 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
3134 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "COMPLETEAGENT", "%ld|%ld|%d",
3135 (long) (callstart
- qe
->start
), (long) (time(NULL
) - callstart
), qe
->opos
);
3136 if (qe
->parent
->eventwhencalled
)
3137 manager_event(EVENT_FLAG_AGENT
, "AgentComplete",
3141 "MemberName: %s\r\n"
3146 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->membername
, (long)(callstart
- qe
->start
),
3147 (long)(time(NULL
) - callstart
),
3148 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
3152 if (bridge
!= AST_PBX_NO_HANGUP_PEER
)
3154 update_queue(qe
->parent
, member
, callcompletedinsl
);
3155 res
= bridge
? bridge
: 1;
3156 ao2_ref(member
, -1);
3159 hangupcalls(outgoing
, NULL
);
3164 static int wait_a_bit(struct queue_ent
*qe
)
3166 /* Don't need to hold the lock while we setup the outgoing calls */
3167 int retrywait
= qe
->parent
->retry
* 1000;
3169 int res
= ast_waitfordigit(qe
->chan
, retrywait
);
3170 if (res
> 0 && !valid_exit(qe
, res
))
3176 static struct member
*interface_exists(struct call_queue
*q
, const char *interface
)
3179 struct ao2_iterator mem_iter
;
3184 mem_iter
= ao2_iterator_init(q
->members
, 0);
3185 while ((mem
= ao2_iterator_next(&mem_iter
))) {
3186 if (!strcasecmp(interface
, mem
->interface
))
3195 /* Dump all members in a specific queue to the database
3197 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3200 static void dump_queue_members(struct call_queue
*pm_queue
)
3202 struct member
*cur_member
;
3203 char value
[PM_MAX_LEN
];
3206 struct ao2_iterator mem_iter
;
3208 memset(value
, 0, sizeof(value
));
3213 mem_iter
= ao2_iterator_init(pm_queue
->members
, 0);
3214 while ((cur_member
= ao2_iterator_next(&mem_iter
))) {
3215 if (!cur_member
->dynamic
) {
3216 ao2_ref(cur_member
, -1);
3220 res
= snprintf(value
+ value_len
, sizeof(value
) - value_len
, "%s%s;%d;%d;%s",
3221 value_len
? "|" : "", cur_member
->interface
, cur_member
->penalty
, cur_member
->paused
, cur_member
->membername
);
3223 ao2_ref(cur_member
, -1);
3225 if (res
!= strlen(value
+ value_len
)) {
3226 ast_log(LOG_WARNING
, "Could not create persistent member string, out of space\n");
3232 if (value_len
&& !cur_member
) {
3233 if (ast_db_put(pm_family
, pm_queue
->name
, value
))
3234 ast_log(LOG_WARNING
, "failed to create persistent dynamic entry!\n");
3236 /* Delete the entry if the queue is empty or there is an error */
3237 ast_db_del(pm_family
, pm_queue
->name
);
3240 static int remove_from_queue(const char *queuename
, const char *interface
)
3242 struct call_queue
*q
;
3243 struct member
*mem
, tmpmem
;
3244 int res
= RES_NOSUCHQUEUE
;
3246 ast_copy_string(tmpmem
.interface
, interface
, sizeof(tmpmem
.interface
));
3248 AST_LIST_LOCK(&queues
);
3249 AST_LIST_TRAVERSE(&queues
, q
, list
) {
3250 ast_mutex_lock(&q
->lock
);
3251 if (strcmp(q
->name
, queuename
)) {
3252 ast_mutex_unlock(&q
->lock
);
3256 if ((mem
= ao2_find(q
->members
, &tmpmem
, OBJ_POINTER
))) {
3257 /* XXX future changes should beware of this assumption!! */
3258 if (!mem
->dynamic
) {
3259 res
= RES_NOT_DYNAMIC
;
3261 ast_mutex_unlock(&q
->lock
);
3265 manager_event(EVENT_FLAG_AGENT
, "QueueMemberRemoved",
3268 "MemberName: %s\r\n",
3269 q
->name
, mem
->interface
, mem
->membername
);
3270 ao2_unlink(q
->members
, mem
);
3273 if (queue_persistent_members
)
3274 dump_queue_members(q
);
3280 ast_mutex_unlock(&q
->lock
);
3284 if (res
== RES_OKAY
)
3285 remove_from_interfaces(interface
);
3287 AST_LIST_UNLOCK(&queues
);
3293 static int add_to_queue(const char *queuename
, const char *interface
, const char *membername
, int penalty
, int paused
, int dump
)
3295 struct call_queue
*q
;
3296 struct member
*new_member
, *old_member
;
3297 int res
= RES_NOSUCHQUEUE
;
3299 /* \note Ensure the appropriate realtime queue is loaded. Note that this
3300 * short-circuits if the queue is already in memory. */
3301 if (!(q
= load_realtime_queue(queuename
)))
3304 AST_LIST_LOCK(&queues
);
3306 ast_mutex_lock(&q
->lock
);
3307 if ((old_member
= interface_exists(q
, interface
)) == NULL
) {
3308 add_to_interfaces(interface
);
3309 if ((new_member
= create_queue_member(interface
, membername
, penalty
, paused
))) {
3310 new_member
->dynamic
= 1;
3311 ao2_link(q
->members
, new_member
);
3313 manager_event(EVENT_FLAG_AGENT
, "QueueMemberAdded",
3316 "MemberName: %s\r\n"
3317 "Membership: %s\r\n"
3319 "CallsTaken: %d\r\n"
3323 q
->name
, new_member
->interface
, new_member
->membername
,
3325 new_member
->penalty
, new_member
->calls
, (int) new_member
->lastcall
,
3326 new_member
->status
, new_member
->paused
);
3328 ao2_ref(new_member
, -1);
3332 dump_queue_members(q
);
3336 res
= RES_OUTOFMEMORY
;
3339 ao2_ref(old_member
, -1);
3342 ast_mutex_unlock(&q
->lock
);
3343 AST_LIST_UNLOCK(&queues
);
3348 static int set_member_paused(const char *queuename
, const char *interface
, int paused
)
3351 struct call_queue
*q
;
3354 /* Special event for when all queues are paused - individual events still generated */
3355 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
3356 if (ast_strlen_zero(queuename
))
3357 ast_queue_log("NONE", "NONE", interface
, (paused
? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
3359 AST_LIST_LOCK(&queues
);
3360 AST_LIST_TRAVERSE(&queues
, q
, list
) {
3361 ast_mutex_lock(&q
->lock
);
3362 if (ast_strlen_zero(queuename
) || !strcasecmp(q
->name
, queuename
)) {
3363 if ((mem
= interface_exists(q
, interface
))) {
3365 if (mem
->paused
== paused
)
3366 ast_log(LOG_DEBUG
, "%spausing already-%spaused queue member %s:%s\n", (paused
? "" : "un"), (paused
? "" : "un"), q
->name
, interface
);
3367 mem
->paused
= paused
;
3369 if (queue_persistent_members
)
3370 dump_queue_members(q
);
3373 update_realtime_member_field(mem
, q
->name
, "paused", paused
? "1" : "0");
3375 ast_queue_log(q
->name
, "NONE", mem
->membername
, (paused
? "PAUSE" : "UNPAUSE"), "%s", "");
3377 manager_event(EVENT_FLAG_AGENT
, "QueueMemberPaused",
3380 "MemberName: %s\r\n"
3382 q
->name
, mem
->interface
, mem
->membername
, paused
);
3386 ast_mutex_unlock(&q
->lock
);
3388 AST_LIST_UNLOCK(&queues
);
3390 return found
? RESULT_SUCCESS
: RESULT_FAILURE
;
3393 /* Reload dynamic queue members persisted into the astdb */
3394 static void reload_queue_members(void)
3400 char *membername
= NULL
;
3405 struct ast_db_entry
*db_tree
;
3406 struct ast_db_entry
*entry
;
3407 struct call_queue
*cur_queue
;
3408 char queue_data
[PM_MAX_LEN
];
3410 AST_LIST_LOCK(&queues
);
3412 /* Each key in 'pm_family' is the name of a queue */
3413 db_tree
= ast_db_gettree(pm_family
, NULL
);
3414 for (entry
= db_tree
; entry
; entry
= entry
->next
) {
3416 queue_name
= entry
->key
+ strlen(pm_family
) + 2;
3418 AST_LIST_TRAVERSE(&queues
, cur_queue
, list
) {
3419 ast_mutex_lock(&cur_queue
->lock
);
3420 if (!strcmp(queue_name
, cur_queue
->name
))
3422 ast_mutex_unlock(&cur_queue
->lock
);
3426 cur_queue
= load_realtime_queue(queue_name
);
3429 /* If the queue no longer exists, remove it from the
3431 ast_log(LOG_WARNING
, "Error loading persistent queue: '%s': it does not exist\n", queue_name
);
3432 ast_db_del(pm_family
, queue_name
);
3435 ast_mutex_unlock(&cur_queue
->lock
);
3437 if (ast_db_get(pm_family
, queue_name
, queue_data
, PM_MAX_LEN
))
3440 cur_ptr
= queue_data
;
3441 while ((member
= strsep(&cur_ptr
, "|"))) {
3442 if (ast_strlen_zero(member
))
3445 interface
= strsep(&member
, ";");
3446 penalty_tok
= strsep(&member
, ";");
3447 paused_tok
= strsep(&member
, ";");
3448 membername
= strsep(&member
, ";");
3451 ast_log(LOG_WARNING
, "Error parsing persistent member string for '%s' (penalty)\n", queue_name
);
3454 penalty
= strtol(penalty_tok
, NULL
, 10);
3455 if (errno
== ERANGE
) {
3456 ast_log(LOG_WARNING
, "Error converting penalty: %s: Out of range.\n", penalty_tok
);
3461 ast_log(LOG_WARNING
, "Error parsing persistent member string for '%s' (paused)\n", queue_name
);
3464 paused
= strtol(paused_tok
, NULL
, 10);
3465 if ((errno
== ERANGE
) || paused
< 0 || paused
> 1) {
3466 ast_log(LOG_WARNING
, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok
);
3469 if (ast_strlen_zero(membername
))
3470 membername
= interface
;
3473 ast_log(LOG_DEBUG
, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name
, interface
, membername
, penalty
, paused
);
3475 if (add_to_queue(queue_name
, interface
, membername
, penalty
, paused
, 0) == RES_OUTOFMEMORY
) {
3476 ast_log(LOG_ERROR
, "Out of Memory when reloading persistent queue member\n");
3482 AST_LIST_UNLOCK(&queues
);
3484 ast_log(LOG_NOTICE
, "Queue members successfully reloaded from database.\n");
3485 ast_db_freetree(db_tree
);
3489 static int pqm_exec(struct ast_channel
*chan
, void *data
)
3491 struct ast_module_user
*lu
;
3493 int priority_jump
= 0;
3494 AST_DECLARE_APP_ARGS(args
,
3495 AST_APP_ARG(queuename
);
3496 AST_APP_ARG(interface
);
3497 AST_APP_ARG(options
);
3500 if (ast_strlen_zero(data
)) {
3501 ast_log(LOG_WARNING
, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3505 parse
= ast_strdupa(data
);
3507 AST_STANDARD_APP_ARGS(args
, parse
);
3509 lu
= ast_module_user_add(chan
);
3512 if (strchr(args
.options
, 'j'))
3516 if (ast_strlen_zero(args
.interface
)) {
3517 ast_log(LOG_WARNING
, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3518 ast_module_user_remove(lu
);
3522 if (set_member_paused(args
.queuename
, args
.interface
, 1)) {
3523 ast_log(LOG_WARNING
, "Attempt to pause interface %s, not found\n", args
.interface
);
3524 if (priority_jump
|| ast_opt_priority_jumping
) {
3525 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101)) {
3526 pbx_builtin_setvar_helper(chan
, "PQMSTATUS", "NOTFOUND");
3527 ast_module_user_remove(lu
);
3531 ast_module_user_remove(lu
);
3532 pbx_builtin_setvar_helper(chan
, "PQMSTATUS", "NOTFOUND");
3536 ast_module_user_remove(lu
);
3537 pbx_builtin_setvar_helper(chan
, "PQMSTATUS", "PAUSED");
3542 static int upqm_exec(struct ast_channel
*chan
, void *data
)
3544 struct ast_module_user
*lu
;
3546 int priority_jump
= 0;
3547 AST_DECLARE_APP_ARGS(args
,
3548 AST_APP_ARG(queuename
);
3549 AST_APP_ARG(interface
);
3550 AST_APP_ARG(options
);
3553 if (ast_strlen_zero(data
)) {
3554 ast_log(LOG_WARNING
, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3558 parse
= ast_strdupa(data
);
3560 AST_STANDARD_APP_ARGS(args
, parse
);
3562 lu
= ast_module_user_add(chan
);
3565 if (strchr(args
.options
, 'j'))
3569 if (ast_strlen_zero(args
.interface
)) {
3570 ast_log(LOG_WARNING
, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3571 ast_module_user_remove(lu
);
3575 if (set_member_paused(args
.queuename
, args
.interface
, 0)) {
3576 ast_log(LOG_WARNING
, "Attempt to unpause interface %s, not found\n", args
.interface
);
3577 if (priority_jump
|| ast_opt_priority_jumping
) {
3578 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101)) {
3579 pbx_builtin_setvar_helper(chan
, "UPQMSTATUS", "NOTFOUND");
3580 ast_module_user_remove(lu
);
3584 ast_module_user_remove(lu
);
3585 pbx_builtin_setvar_helper(chan
, "UPQMSTATUS", "NOTFOUND");
3589 ast_module_user_remove(lu
);
3590 pbx_builtin_setvar_helper(chan
, "UPQMSTATUS", "UNPAUSED");
3595 static int rqm_exec(struct ast_channel
*chan
, void *data
)
3598 struct ast_module_user
*lu
;
3599 char *parse
, *temppos
= NULL
;
3600 int priority_jump
= 0;
3601 AST_DECLARE_APP_ARGS(args
,
3602 AST_APP_ARG(queuename
);
3603 AST_APP_ARG(interface
);
3604 AST_APP_ARG(options
);
3608 if (ast_strlen_zero(data
)) {
3609 ast_log(LOG_WARNING
, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
3613 parse
= ast_strdupa(data
);
3615 AST_STANDARD_APP_ARGS(args
, parse
);
3617 lu
= ast_module_user_add(chan
);
3619 if (ast_strlen_zero(args
.interface
)) {
3620 args
.interface
= ast_strdupa(chan
->name
);
3621 temppos
= strrchr(args
.interface
, '-');
3627 if (strchr(args
.options
, 'j'))
3631 switch (remove_from_queue(args
.queuename
, args
.interface
)) {
3633 ast_queue_log(args
.queuename
, chan
->uniqueid
, args
.interface
, "REMOVEMEMBER", "%s", "");
3634 ast_log(LOG_NOTICE
, "Removed interface '%s' from queue '%s'\n", args
.interface
, args
.queuename
);
3635 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "REMOVED");
3639 ast_log(LOG_DEBUG
, "Unable to remove interface '%s' from queue '%s': Not there\n", args
.interface
, args
.queuename
);
3640 if (priority_jump
|| ast_opt_priority_jumping
)
3641 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
3642 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "NOTINQUEUE");
3645 case RES_NOSUCHQUEUE
:
3646 ast_log(LOG_WARNING
, "Unable to remove interface from queue '%s': No such queue\n", args
.queuename
);
3647 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "NOSUCHQUEUE");
3650 case RES_NOT_DYNAMIC
:
3651 ast_log(LOG_WARNING
, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args
.queuename
, args
.interface
);
3652 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "NOTDYNAMIC");
3657 ast_module_user_remove(lu
);
3662 static int aqm_exec(struct ast_channel
*chan
, void *data
)
3665 struct ast_module_user
*lu
;
3666 char *parse
, *temppos
= NULL
;
3667 int priority_jump
= 0;
3668 AST_DECLARE_APP_ARGS(args
,
3669 AST_APP_ARG(queuename
);
3670 AST_APP_ARG(interface
);
3671 AST_APP_ARG(penalty
);
3672 AST_APP_ARG(options
);
3673 AST_APP_ARG(membername
);
3677 if (ast_strlen_zero(data
)) {
3678 ast_log(LOG_WARNING
, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
3682 parse
= ast_strdupa(data
);
3684 AST_STANDARD_APP_ARGS(args
, parse
);
3686 lu
= ast_module_user_add(chan
);
3688 if (ast_strlen_zero(args
.interface
)) {
3689 args
.interface
= ast_strdupa(chan
->name
);
3690 temppos
= strrchr(args
.interface
, '-');
3695 if (!ast_strlen_zero(args
.penalty
)) {
3696 if ((sscanf(args
.penalty
, "%d", &penalty
) != 1) || penalty
< 0) {
3697 ast_log(LOG_WARNING
, "Penalty '%s' is invalid, must be an integer >= 0\n", args
.penalty
);
3703 if (strchr(args
.options
, 'j'))
3707 switch (add_to_queue(args
.queuename
, args
.interface
, args
.membername
, penalty
, 0, queue_persistent_members
)) {
3709 ast_queue_log(args
.queuename
, chan
->uniqueid
, args
.interface
, "ADDMEMBER", "%s", "");
3710 ast_log(LOG_NOTICE
, "Added interface '%s' to queue '%s'\n", args
.interface
, args
.queuename
);
3711 pbx_builtin_setvar_helper(chan
, "AQMSTATUS", "ADDED");
3715 ast_log(LOG_WARNING
, "Unable to add interface '%s' to queue '%s': Already there\n", args
.interface
, args
.queuename
);
3716 if (priority_jump
|| ast_opt_priority_jumping
)
3717 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
3718 pbx_builtin_setvar_helper(chan
, "AQMSTATUS", "MEMBERALREADY");
3721 case RES_NOSUCHQUEUE
:
3722 ast_log(LOG_WARNING
, "Unable to add interface to queue '%s': No such queue\n", args
.queuename
);
3723 pbx_builtin_setvar_helper(chan
, "AQMSTATUS", "NOSUCHQUEUE");
3726 case RES_OUTOFMEMORY
:
3727 ast_log(LOG_ERROR
, "Out of memory adding member %s to queue %s\n", args
.interface
, args
.queuename
);
3731 ast_module_user_remove(lu
);
3736 static int ql_exec(struct ast_channel
*chan
, void *data
)
3738 struct ast_module_user
*u
;
3741 AST_DECLARE_APP_ARGS(args
,
3742 AST_APP_ARG(queuename
);
3743 AST_APP_ARG(uniqueid
);
3744 AST_APP_ARG(membername
);
3746 AST_APP_ARG(params
);
3749 if (ast_strlen_zero(data
)) {
3750 ast_log(LOG_WARNING
, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
3754 u
= ast_module_user_add(chan
);
3756 parse
= ast_strdupa(data
);
3758 AST_STANDARD_APP_ARGS(args
, parse
);
3760 if (ast_strlen_zero(args
.queuename
) || ast_strlen_zero(args
.uniqueid
)
3761 || ast_strlen_zero(args
.membername
) || ast_strlen_zero(args
.event
)) {
3762 ast_log(LOG_WARNING
, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
3763 ast_module_user_remove(u
);
3767 ast_queue_log(args
.queuename
, args
.uniqueid
, args
.membername
, args
.event
,
3768 "%s", args
.params
? args
.params
: "");
3770 ast_module_user_remove(u
);
3775 /*!\brief The starting point for all queue calls
3777 * The process involved here is to
3778 * 1. Parse the options specified in the call to Queue()
3780 * 3. Wait in a loop until it is our turn to try calling a queue member
3781 * 4. Attempt to call a queue member
3782 * 5. If 4. did not result in a bridged call, then check for between
3783 * call options such as periodic announcements etc.
3784 * 6. Try 4 again uless some condition (such as an expiration time) causes us to
3787 static int queue_exec(struct ast_channel
*chan
, void *data
)
3791 struct ast_module_user
*lu
;
3792 const char *user_priority
;
3793 const char *max_penalty_str
;
3796 enum queue_result reason
= QUEUE_UNKNOWN
;
3797 /* whether to exit Queue application after the timeout hits */
3801 AST_DECLARE_APP_ARGS(args
,
3802 AST_APP_ARG(queuename
);
3803 AST_APP_ARG(options
);
3805 AST_APP_ARG(announceoverride
);
3806 AST_APP_ARG(queuetimeoutstr
);
3809 /* Our queue entry */
3810 struct queue_ent qe
;
3812 if (ast_strlen_zero(data
)) {
3813 ast_log(LOG_WARNING
, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
3817 parse
= ast_strdupa(data
);
3818 AST_STANDARD_APP_ARGS(args
, parse
);
3820 lu
= ast_module_user_add(chan
);
3822 /* Setup our queue entry */
3823 memset(&qe
, 0, sizeof(qe
));
3824 qe
.start
= time(NULL
);
3826 /* set the expire time based on the supplied timeout; */
3827 if (!ast_strlen_zero(args
.queuetimeoutstr
))
3828 qe
.expire
= qe
.start
+ atoi(args
.queuetimeoutstr
);
3832 /* Get the priority from the variable ${QUEUE_PRIO} */
3833 user_priority
= pbx_builtin_getvar_helper(chan
, "QUEUE_PRIO");
3834 if (user_priority
) {
3835 if (sscanf(user_priority
, "%d", &prio
) == 1) {
3837 ast_log(LOG_DEBUG
, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
3840 ast_log(LOG_WARNING
, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
3841 user_priority
, chan
->name
);
3845 if (option_debug
> 2)
3846 ast_log(LOG_DEBUG
, "NO QUEUE_PRIO variable found. Using default.\n");
3850 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
3851 if ((max_penalty_str
= pbx_builtin_getvar_helper(chan
, "QUEUE_MAX_PENALTY"))) {
3852 if (sscanf(max_penalty_str
, "%d", &max_penalty
) == 1) {
3854 ast_log(LOG_DEBUG
, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
3855 chan
->name
, max_penalty
);
3857 ast_log(LOG_WARNING
, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
3858 max_penalty_str
, chan
->name
);
3865 if (args
.options
&& (strchr(args
.options
, 'r')))
3869 ast_log(LOG_DEBUG
, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
3870 args
.queuename
, args
.options
, args
.url
, args
.announceoverride
, (long)qe
.expire
, prio
);
3874 qe
.max_penalty
= max_penalty
;
3875 qe
.last_pos_said
= 0;
3877 qe
.last_periodic_announce_time
= time(NULL
);
3878 qe
.last_periodic_announce_sound
= 0;
3879 qe
.valid_digits
= 0;
3880 if (!join_queue(args
.queuename
, &qe
, &reason
)) {
3881 int makeannouncement
= 0;
3883 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args
.url
, ""),
3884 S_OR(chan
->cid
.cid_num
, ""));
3887 ast_indicate(chan
, AST_CONTROL_RINGING
);
3889 ast_moh_start(chan
, qe
.moh
, NULL
);
3892 /* This is the wait loop for callers 2 through maxlen */
3893 res
= wait_our_turn(&qe
, ringing
, &reason
);
3898 /* This is the wait loop for the head caller*/
3899 /* To exit, they may get their call answered; */
3900 /* they may dial a digit from the queue context; */
3901 /* or, they may timeout. */
3903 enum queue_member_status stat
;
3905 /* Leave if we have exceeded our queuetimeout */
3906 if (qe
.expire
&& (time(NULL
) > qe
.expire
)) {
3907 record_abandoned(&qe
);
3908 reason
= QUEUE_TIMEOUT
;
3910 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHTIMEOUT", "%d", qe
.pos
);
3914 if (makeannouncement
) {
3915 /* Make a position announcement, if enabled */
3916 if (qe
.parent
->announcefrequency
&& !ringing
)
3917 if ((res
= say_position(&qe
)))
3921 makeannouncement
= 1;
3923 /* Make a periodic announcement, if enabled */
3924 if (qe
.parent
->periodicannouncefrequency
&& !ringing
)
3925 if ((res
= say_periodic_announcement(&qe
)))
3928 /* Try calling all queue members for 'timeout' seconds */
3929 res
= try_calling(&qe
, args
.options
, args
.announceoverride
, args
.url
, &tries
, &noption
, args
.agi
);
3933 stat
= get_member_status(qe
.parent
, qe
.max_penalty
);
3935 /* exit after 'timeout' cycle if 'n' option enabled */
3936 if (noption
&& tries
>= qe
.parent
->membercount
) {
3937 if (option_verbose
> 2)
3938 ast_verbose(VERBOSE_PREFIX_3
"Exiting on time-out cycle\n");
3939 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHTIMEOUT", "%d", qe
.pos
);
3940 record_abandoned(&qe
);
3941 reason
= QUEUE_TIMEOUT
;
3946 /* leave the queue if no agents, if enabled */
3947 if (qe
.parent
->leavewhenempty
&& (stat
== QUEUE_NO_MEMBERS
)) {
3948 record_abandoned(&qe
);
3949 reason
= QUEUE_LEAVEEMPTY
;
3950 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITEMPTY", "%d|%d|%ld", qe
.pos
, qe
.opos
, (long)(time(NULL
) - qe
.start
));
3955 /* leave the queue if no reachable agents, if enabled */
3956 if ((qe
.parent
->leavewhenempty
== QUEUE_EMPTY_STRICT
) && (stat
== QUEUE_NO_REACHABLE_MEMBERS
)) {
3957 record_abandoned(&qe
);
3958 reason
= QUEUE_LEAVEUNAVAIL
;
3959 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITEMPTY", "%d|%d|%ld", qe
.pos
, qe
.opos
, (long)(time(NULL
) - qe
.start
));
3964 /* Leave if we have exceeded our queuetimeout */
3965 if (qe
.expire
&& (time(NULL
) > qe
.expire
)) {
3966 record_abandoned(&qe
);
3967 reason
= QUEUE_TIMEOUT
;
3969 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHTIMEOUT", "%d", qe
.pos
);
3973 /* If using dynamic realtime members, we should regenerate the member list for this queue */
3974 update_realtime_members(qe
.parent
);
3976 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3977 res
= wait_a_bit(&qe
);
3982 /* Since this is a priority queue and
3983 * it is not sure that we are still at the head
3984 * of the queue, go and check for our turn again.
3986 if (!is_our_turn(&qe
)) {
3988 ast_log(LOG_DEBUG
, "Darn priorities, going back in queue (%s)!\n",
3998 record_abandoned(&qe
);
3999 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "ABANDON",
4000 "%d|%d|%ld", qe
.pos
, qe
.opos
,
4001 (long) time(NULL
) - qe
.start
);
4004 } else if (qe
.valid_digits
) {
4005 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHKEY",
4006 "%s|%d", qe
.digits
, qe
.pos
);
4010 /* Don't allow return code > 0 */
4011 if (res
>= 0 && res
!= AST_PBX_KEEPALIVE
) {
4014 ast_indicate(chan
, -1);
4018 ast_stopstream(chan
);
4021 if (reason
!= QUEUE_UNKNOWN
)
4022 set_queue_result(chan
, reason
);
4024 ast_log(LOG_WARNING
, "Unable to join queue '%s'\n", args
.queuename
);
4025 set_queue_result(chan
, reason
);
4028 ast_module_user_remove(lu
);
4033 static int queue_function_qac(struct ast_channel
*chan
, char *cmd
, char *data
, char *buf
, size_t len
)
4036 struct call_queue
*q
;
4037 struct ast_module_user
*lu
;
4039 struct ao2_iterator mem_iter
;
4043 if (ast_strlen_zero(data
)) {
4044 ast_log(LOG_ERROR
, "%s requires an argument: queuename\n", cmd
);
4048 lu
= ast_module_user_add(chan
);
4050 if ((q
= load_realtime_queue(data
))) {
4051 ast_mutex_lock(&q
->lock
);
4052 mem_iter
= ao2_iterator_init(q
->members
, 0);
4053 while ((m
= ao2_iterator_next(&mem_iter
))) {
4054 /* Count the agents who are logged in and presently answering calls */
4055 if ((m
->status
!= AST_DEVICE_UNAVAILABLE
) && (m
->status
!= AST_DEVICE_INVALID
)) {
4060 ast_mutex_unlock(&q
->lock
);
4062 ast_log(LOG_WARNING
, "queue %s was not found\n", data
);
4064 snprintf(buf
, len
, "%d", count
);
4065 ast_module_user_remove(lu
);
4070 static int queue_function_queuewaitingcount(struct ast_channel
*chan
, char *cmd
, char *data
, char *buf
, size_t len
)
4073 struct call_queue
*q
;
4074 struct ast_module_user
*lu
;
4075 struct ast_variable
*var
= NULL
;
4079 if (ast_strlen_zero(data
)) {
4080 ast_log(LOG_ERROR
, "%s requires an argument: queuename\n", cmd
);
4084 lu
= ast_module_user_add(chan
);
4086 AST_LIST_LOCK(&queues
);
4087 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4088 if (!strcasecmp(q
->name
, data
)) {
4089 ast_mutex_lock(&q
->lock
);
4093 AST_LIST_UNLOCK(&queues
);
4097 ast_mutex_unlock(&q
->lock
);
4098 } else if ((var
= ast_load_realtime("queues", "name", data
, NULL
))) {
4099 /* if the queue is realtime but was not found in memory, this
4100 * means that the queue had been deleted from memory since it was
4101 * "dead." This means it has a 0 waiting count
4104 ast_variables_destroy(var
);
4106 ast_log(LOG_WARNING
, "queue %s was not found\n", data
);
4108 snprintf(buf
, len
, "%d", count
);
4109 ast_module_user_remove(lu
);
4113 static int queue_function_queuememberlist(struct ast_channel
*chan
, char *cmd
, char *data
, char *buf
, size_t len
)
4115 struct ast_module_user
*u
;
4116 struct call_queue
*q
;
4119 /* Ensure an otherwise empty list doesn't return garbage */
4122 if (ast_strlen_zero(data
)) {
4123 ast_log(LOG_ERROR
, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
4127 u
= ast_module_user_add(chan
);
4129 AST_LIST_LOCK(&queues
);
4130 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4131 if (!strcasecmp(q
->name
, data
)) {
4132 ast_mutex_lock(&q
->lock
);
4136 AST_LIST_UNLOCK(&queues
);
4139 int buflen
= 0, count
= 0;
4140 struct ao2_iterator mem_iter
= ao2_iterator_init(q
->members
, 0);
4142 while ((m
= ao2_iterator_next(&mem_iter
))) {
4143 /* strcat() is always faster than printf() */
4145 strncat(buf
+ buflen
, ",", len
- buflen
- 1);
4148 strncat(buf
+ buflen
, m
->membername
, len
- buflen
- 1);
4149 buflen
+= strlen(m
->membername
);
4150 /* Safeguard against overflow (negative length) */
4151 if (buflen
>= len
- 2) {
4153 ast_log(LOG_WARNING
, "Truncating list\n");
4158 ast_mutex_unlock(&q
->lock
);
4160 ast_log(LOG_WARNING
, "queue %s was not found\n", data
);
4162 /* We should already be terminated, but let's make sure. */
4163 buf
[len
- 1] = '\0';
4164 ast_module_user_remove(u
);
4169 static struct ast_custom_function queueagentcount_function
= {
4170 .name
= "QUEUEAGENTCOUNT",
4171 .synopsis
= "Count number of agents answering a queue",
4172 .syntax
= "QUEUEAGENTCOUNT(<queuename>)",
4174 "Returns the number of members currently associated with the specified queue.\n"
4175 "This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
4176 .read
= queue_function_qac
,
4179 static struct ast_custom_function queuemembercount_function
= {
4180 .name
= "QUEUE_MEMBER_COUNT",
4181 .synopsis
= "Count number of members answering a queue",
4182 .syntax
= "QUEUE_MEMBER_COUNT(<queuename>)",
4184 "Returns the number of members currently associated with the specified queue.\n",
4185 .read
= queue_function_qac
,
4188 static struct ast_custom_function queuewaitingcount_function
= {
4189 .name
= "QUEUE_WAITING_COUNT",
4190 .synopsis
= "Count number of calls currently waiting in a queue",
4191 .syntax
= "QUEUE_WAITING_COUNT(<queuename>)",
4193 "Returns the number of callers currently waiting in the specified queue.\n",
4194 .read
= queue_function_queuewaitingcount
,
4197 static struct ast_custom_function queuememberlist_function
= {
4198 .name
= "QUEUE_MEMBER_LIST",
4199 .synopsis
= "Returns a list of interfaces on a queue",
4200 .syntax
= "QUEUE_MEMBER_LIST(<queuename>)",
4202 "Returns a comma-separated list of members associated with the specified queue.\n",
4203 .read
= queue_function_queuememberlist
,
4206 static int reload_queues(void)
4208 struct call_queue
*q
;
4209 struct ast_config
*cfg
;
4211 struct ast_variable
*var
;
4212 struct member
*cur
, *newm
;
4213 struct ao2_iterator mem_iter
;
4215 const char *general_val
= NULL
;
4218 char *membername
= NULL
;
4220 AST_DECLARE_APP_ARGS(args
,
4221 AST_APP_ARG(interface
);
4222 AST_APP_ARG(penalty
);
4223 AST_APP_ARG(membername
);
4226 if (!(cfg
= ast_config_load("queues.conf"))) {
4227 ast_log(LOG_NOTICE
, "No call queueing config file (queues.conf), so no call queues\n");
4230 AST_LIST_LOCK(&queues
);
4232 /* Mark all non-realtime queues as dead for the moment */
4233 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4240 /* Chug through config file */
4242 while ((cat
= ast_category_browse(cfg
, cat
)) ) {
4243 if (!strcasecmp(cat
, "general")) {
4244 /* Initialize global settings */
4245 queue_persistent_members
= 0;
4246 if ((general_val
= ast_variable_retrieve(cfg
, "general", "persistentmembers")))
4247 queue_persistent_members
= ast_true(general_val
);
4248 autofill_default
= 0;
4249 if ((general_val
= ast_variable_retrieve(cfg
, "general", "autofill")))
4250 autofill_default
= ast_true(general_val
);
4251 montype_default
= 0;
4252 if ((general_val
= ast_variable_retrieve(cfg
, "general", "monitor-type")))
4253 if (!strcasecmp(general_val
, "mixmonitor"))
4254 montype_default
= 1;
4255 } else { /* Define queue */
4256 /* Look for an existing one */
4257 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4258 if (!strcmp(q
->name
, cat
))
4263 if (!(q
= alloc_queue(cat
))) {
4264 /* TODO: Handle memory allocation failure */
4271 ast_mutex_lock(&q
->lock
);
4272 /* Check if a queue with this name already exists */
4274 ast_log(LOG_WARNING
, "Queue '%s' already defined! Skipping!\n", cat
);
4276 ast_mutex_unlock(&q
->lock
);
4279 /* Re-initialize the queue, and clear statistics */
4282 mem_iter
= ao2_iterator_init(q
->members
, 0);
4283 while ((cur
= ao2_iterator_next(&mem_iter
))) {
4284 if (!cur
->dynamic
) {
4289 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4290 if (!strcasecmp(var
->name
, "member")) {
4291 struct member tmpmem
;
4294 /* Add a new member */
4295 ast_copy_string(parse
, var
->value
, sizeof(parse
));
4297 AST_NONSTANDARD_APP_ARGS(args
, parse
, ',');
4299 interface
= args
.interface
;
4300 if (!ast_strlen_zero(args
.penalty
)) {
4302 while (*tmp
&& *tmp
< 33) tmp
++;
4303 penalty
= atoi(tmp
);
4310 if (!ast_strlen_zero(args
.membername
)) {
4311 membername
= args
.membername
;
4312 while (*membername
&& *membername
< 33) membername
++;
4315 /* Find the old position in the list */
4316 ast_copy_string(tmpmem
.interface
, interface
, sizeof(tmpmem
.interface
));
4317 cur
= ao2_find(q
->members
, &tmpmem
, OBJ_POINTER
| OBJ_UNLINK
);
4319 newm
= create_queue_member(interface
, membername
, penalty
, cur
? cur
->paused
: 0);
4320 ao2_link(q
->members
, newm
);
4327 /* Add them to the master int list if necessary */
4328 add_to_interfaces(interface
);
4332 queue_set_param(q
, var
->name
, var
->value
, var
->lineno
, 1);
4336 /* Free remaining members marked as delme */
4337 mem_iter
= ao2_iterator_init(q
->members
, 0);
4338 while ((cur
= ao2_iterator_next(&mem_iter
))) {
4345 ao2_unlink(q
->members
, cur
);
4346 remove_from_interfaces(cur
->interface
);
4350 if (q
->strategy
== QUEUE_STRATEGY_ROUNDROBIN
)
4354 AST_LIST_INSERT_HEAD(&queues
, q
, list
);
4356 ast_mutex_unlock(&q
->lock
);
4360 ast_config_destroy(cfg
);
4361 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues
, q
, list
) {
4363 AST_LIST_REMOVE_CURRENT(&queues
, list
);
4367 ast_log(LOG_DEBUG
, "XXX Leaking a little memory :( XXX\n");
4369 ast_mutex_lock(&q
->lock
);
4370 mem_iter
= ao2_iterator_init(q
->members
, 0);
4371 while ((cur
= ao2_iterator_next(&mem_iter
))) {
4374 cur
->status
= ast_device_state(cur
->interface
);
4377 ast_mutex_unlock(&q
->lock
);
4380 AST_LIST_TRAVERSE_SAFE_END
;
4381 AST_LIST_UNLOCK(&queues
);
4385 static int __queues_show(struct mansession
*s
, int manager
, int fd
, int argc
, char **argv
)
4387 struct call_queue
*q
;
4388 struct queue_ent
*qe
;
4390 int pos
, queue_show
;
4396 char *term
= manager
? "\r\n" : "\n";
4397 struct ao2_iterator mem_iter
;
4405 return RESULT_SHOWUSAGE
;
4407 /* We only want to load realtime queues when a specific queue is asked for. */
4409 load_realtime_queue(argv
[2]);
4410 } else if (ast_check_realtime("queues")) {
4411 struct ast_config
*cfg
= ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL
);
4414 for (queuename
= ast_category_browse(cfg
, NULL
); !ast_strlen_zero(queuename
); queuename
= ast_category_browse(cfg
, queuename
)) {
4415 load_realtime_queue(queuename
);
4417 ast_config_destroy(cfg
);
4421 AST_LIST_LOCK(&queues
);
4422 if (AST_LIST_EMPTY(&queues
)) {
4423 AST_LIST_UNLOCK(&queues
);
4426 astman_append(s
, "No such queue: %s.%s",argv
[2], term
);
4428 ast_cli(fd
, "No such queue: %s.%s",argv
[2], term
);
4431 astman_append(s
, "No queues.%s", term
);
4433 ast_cli(fd
, "No queues.%s", term
);
4435 return RESULT_SUCCESS
;
4437 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4438 ast_mutex_lock(&q
->lock
);
4440 if (strcasecmp(q
->name
, argv
[2]) != 0) {
4441 ast_mutex_unlock(&q
->lock
);
4442 if (!AST_LIST_NEXT(q
, list
)) {
4443 ast_cli(fd
, "No such queue: %s.%s",argv
[2], term
);
4451 max_left
= sizeof(max_buf
);
4453 ast_build_string(&max
, &max_left
, "%d", q
->maxlen
);
4455 ast_build_string(&max
, &max_left
, "unlimited");
4457 if (q
->callscompleted
> 0)
4458 sl
= 100 * ((float) q
->callscompletedinsl
/ (float) q
->callscompleted
);
4460 astman_append(s
, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
4461 q
->name
, q
->count
, max_buf
, int2strat(q
->strategy
), q
->holdtime
, q
->weight
,
4462 q
->callscompleted
, q
->callsabandoned
,sl
,q
->servicelevel
, term
);
4464 ast_cli(fd
, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
4465 q
->name
, q
->count
, max_buf
, int2strat(q
->strategy
), q
->holdtime
, q
->weight
, q
->callscompleted
, q
->callsabandoned
,sl
,q
->servicelevel
, term
);
4466 if (ao2_container_count(q
->members
)) {
4468 astman_append(s
, " Members: %s", term
);
4470 ast_cli(fd
, " Members: %s", term
);
4471 mem_iter
= ao2_iterator_init(q
->members
, 0);
4472 while ((mem
= ao2_iterator_next(&mem_iter
))) {
4475 max_left
= sizeof(max_buf
);
4476 if (strcasecmp(mem
->membername
, mem
->interface
)) {
4477 ast_build_string(&max
, &max_left
, " (%s)", mem
->interface
);
4480 ast_build_string(&max
, &max_left
, " with penalty %d", mem
->penalty
);
4482 ast_build_string(&max
, &max_left
, " (dynamic)");
4484 ast_build_string(&max
, &max_left
, " (realtime)");
4486 ast_build_string(&max
, &max_left
, " (paused)");
4487 ast_build_string(&max
, &max_left
, " (%s)", devstate2str(mem
->status
));
4489 ast_build_string(&max
, &max_left
, " has taken %d calls (last was %ld secs ago)",
4490 mem
->calls
, (long) (time(NULL
) - mem
->lastcall
));
4492 ast_build_string(&max
, &max_left
, " has taken no calls yet");
4494 astman_append(s
, " %s%s%s", mem
->membername
, max_buf
, term
);
4496 ast_cli(fd
, " %s%s%s", mem
->membername
, max_buf
, term
);
4500 astman_append(s
, " No Members%s", term
);
4502 ast_cli(fd
, " No Members%s", term
);
4506 astman_append(s
, " Callers: %s", term
);
4508 ast_cli(fd
, " Callers: %s", term
);
4509 for (qe
= q
->head
; qe
; qe
= qe
->next
) {
4511 astman_append(s
, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
4512 pos
++, qe
->chan
->name
, (long) (now
- qe
->start
) / 60,
4513 (long) (now
- qe
->start
) % 60, qe
->prio
, term
);
4515 ast_cli(fd
, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos
++,
4516 qe
->chan
->name
, (long) (now
- qe
->start
) / 60,
4517 (long) (now
- qe
->start
) % 60, qe
->prio
, term
);
4520 astman_append(s
, " No Callers%s", term
);
4522 ast_cli(fd
, " No Callers%s", term
);
4524 astman_append(s
, "%s", term
);
4526 ast_cli(fd
, "%s", term
);
4527 ast_mutex_unlock(&q
->lock
);
4531 AST_LIST_UNLOCK(&queues
);
4532 return RESULT_SUCCESS
;
4535 static int queue_show(int fd
, int argc
, char **argv
)
4537 return __queues_show(NULL
, 0, fd
, argc
, argv
);
4540 static char *complete_queue(const char *line
, const char *word
, int pos
, int state
)
4542 struct call_queue
*q
;
4545 int wordlen
= strlen(word
);
4547 AST_LIST_LOCK(&queues
);
4548 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4549 if (!strncasecmp(word
, q
->name
, wordlen
) && ++which
> state
) {
4550 ret
= ast_strdup(q
->name
);
4554 AST_LIST_UNLOCK(&queues
);
4559 static char *complete_queue_show(const char *line
, const char *word
, int pos
, int state
)
4562 return complete_queue(line
, word
, pos
, state
);
4566 /*!\brief callback to display queues status in manager
4567 \addtogroup Group_AMI
4569 static int manager_queues_show(struct mansession
*s
, const struct message
*m
)
4571 char *a
[] = { "queue", "show" };
4573 __queues_show(s
, 1, -1, 2, a
);
4574 astman_append(s
, "\r\n\r\n"); /* Properly terminate Manager output */
4576 return RESULT_SUCCESS
;
4579 /* Dump queue status */
4580 static int manager_queues_status(struct mansession
*s
, const struct message
*m
)
4584 const char *id
= astman_get_header(m
,"ActionID");
4585 const char *queuefilter
= astman_get_header(m
,"Queue");
4586 const char *memberfilter
= astman_get_header(m
,"Member");
4587 char idText
[256] = "";
4588 struct call_queue
*q
;
4589 struct queue_ent
*qe
;
4592 struct ao2_iterator mem_iter
;
4594 astman_send_ack(s
, m
, "Queue status will follow");
4596 AST_LIST_LOCK(&queues
);
4597 if (!ast_strlen_zero(id
))
4598 snprintf(idText
, sizeof(idText
), "ActionID: %s\r\n", id
);
4600 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4601 ast_mutex_lock(&q
->lock
);
4603 /* List queue properties */
4604 if (ast_strlen_zero(queuefilter
) || !strcmp(q
->name
, queuefilter
)) {
4605 sl
= ((q
->callscompleted
> 0) ? 100 * ((float)q
->callscompletedinsl
/ (float)q
->callscompleted
) : 0);
4606 astman_append(s
, "Event: QueueParams\r\n"
4613 "ServiceLevel: %d\r\n"
4614 "ServicelevelPerf: %2.1f\r\n"
4618 q
->name
, q
->maxlen
, q
->count
, q
->holdtime
, q
->callscompleted
,
4619 q
->callsabandoned
, q
->servicelevel
, sl
, q
->weight
, idText
);
4620 /* List Queue Members */
4621 mem_iter
= ao2_iterator_init(q
->members
, 0);
4622 while ((mem
= ao2_iterator_next(&mem_iter
))) {
4623 if (ast_strlen_zero(memberfilter
) || !strcmp(mem
->interface
, memberfilter
)) {
4624 astman_append(s
, "Event: QueueMember\r\n"
4628 "Membership: %s\r\n"
4630 "CallsTaken: %d\r\n"
4636 q
->name
, mem
->membername
, mem
->interface
, mem
->dynamic
? "dynamic" : "static",
4637 mem
->penalty
, mem
->calls
, (int)mem
->lastcall
, mem
->status
, mem
->paused
, idText
);
4641 /* List Queue Entries */
4643 for (qe
= q
->head
; qe
; qe
= qe
->next
) {
4644 astman_append(s
, "Event: QueueEntry\r\n"
4649 "CallerIDName: %s\r\n"
4653 q
->name
, pos
++, qe
->chan
->name
,
4654 S_OR(qe
->chan
->cid
.cid_num
, "unknown"),
4655 S_OR(qe
->chan
->cid
.cid_name
, "unknown"),
4656 (long) (now
- qe
->start
), idText
);
4659 ast_mutex_unlock(&q
->lock
);
4663 "Event: QueueStatusComplete\r\n"
4667 AST_LIST_UNLOCK(&queues
);
4670 return RESULT_SUCCESS
;
4673 static int manager_add_queue_member(struct mansession
*s
, const struct message
*m
)
4675 const char *queuename
, *interface
, *penalty_s
, *paused_s
, *membername
;
4676 int paused
, penalty
= 0;
4678 queuename
= astman_get_header(m
, "Queue");
4679 interface
= astman_get_header(m
, "Interface");
4680 penalty_s
= astman_get_header(m
, "Penalty");
4681 paused_s
= astman_get_header(m
, "Paused");
4682 membername
= astman_get_header(m
, "MemberName");
4684 if (ast_strlen_zero(queuename
)) {
4685 astman_send_error(s
, m
, "'Queue' not specified.");
4689 if (ast_strlen_zero(interface
)) {
4690 astman_send_error(s
, m
, "'Interface' not specified.");
4694 if (ast_strlen_zero(penalty_s
))
4696 else if (sscanf(penalty_s
, "%d", &penalty
) != 1 || penalty
< 0)
4699 if (ast_strlen_zero(paused_s
))
4702 paused
= abs(ast_true(paused_s
));
4704 switch (add_to_queue(queuename
, interface
, membername
, penalty
, paused
, queue_persistent_members
)) {
4706 ast_queue_log(queuename
, "MANAGER", interface
, "ADDMEMBER", "%s", "");
4707 astman_send_ack(s
, m
, "Added interface to queue");
4710 astman_send_error(s
, m
, "Unable to add interface: Already there");
4712 case RES_NOSUCHQUEUE
:
4713 astman_send_error(s
, m
, "Unable to add interface to queue: No such queue");
4715 case RES_OUTOFMEMORY
:
4716 astman_send_error(s
, m
, "Out of memory");
4723 static int manager_remove_queue_member(struct mansession
*s
, const struct message
*m
)
4725 const char *queuename
, *interface
;
4727 queuename
= astman_get_header(m
, "Queue");
4728 interface
= astman_get_header(m
, "Interface");
4730 if (ast_strlen_zero(queuename
) || ast_strlen_zero(interface
)) {
4731 astman_send_error(s
, m
, "Need 'Queue' and 'Interface' parameters.");
4735 switch (remove_from_queue(queuename
, interface
)) {
4737 ast_queue_log(queuename
, "MANAGER", interface
, "REMOVEMEMBER", "%s", "");
4738 astman_send_ack(s
, m
, "Removed interface from queue");
4741 astman_send_error(s
, m
, "Unable to remove interface: Not there");
4743 case RES_NOSUCHQUEUE
:
4744 astman_send_error(s
, m
, "Unable to remove interface from queue: No such queue");
4746 case RES_OUTOFMEMORY
:
4747 astman_send_error(s
, m
, "Out of memory");
4749 case RES_NOT_DYNAMIC
:
4750 astman_send_error(s
, m
, "Member not dynamic");
4757 static int manager_pause_queue_member(struct mansession
*s
, const struct message
*m
)
4759 const char *queuename
, *interface
, *paused_s
;
4762 interface
= astman_get_header(m
, "Interface");
4763 paused_s
= astman_get_header(m
, "Paused");
4764 queuename
= astman_get_header(m
, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
4766 if (ast_strlen_zero(interface
) || ast_strlen_zero(paused_s
)) {
4767 astman_send_error(s
, m
, "Need 'Interface' and 'Paused' parameters.");
4771 paused
= abs(ast_true(paused_s
));
4773 if (set_member_paused(queuename
, interface
, paused
))
4774 astman_send_error(s
, m
, "Interface not found");
4776 astman_send_ack(s
, m
, paused
? "Interface paused successfully" : "Interface unpaused successfully");
4780 static int handle_queue_add_member(int fd
, int argc
, char *argv
[])
4782 char *queuename
, *interface
, *membername
= NULL
;
4785 if ((argc
!= 6) && (argc
!= 8) && (argc
!= 10)) {
4786 return RESULT_SHOWUSAGE
;
4787 } else if (strcmp(argv
[4], "to")) {
4788 return RESULT_SHOWUSAGE
;
4789 } else if ((argc
== 8) && strcmp(argv
[6], "penalty")) {
4790 return RESULT_SHOWUSAGE
;
4791 } else if ((argc
== 10) && strcmp(argv
[8], "as")) {
4792 return RESULT_SHOWUSAGE
;
4795 queuename
= argv
[5];
4796 interface
= argv
[3];
4798 if (sscanf(argv
[7], "%d", &penalty
) == 1) {
4800 ast_cli(fd
, "Penalty must be >= 0\n");
4804 ast_cli(fd
, "Penalty must be an integer >= 0\n");
4812 membername
= argv
[9];
4815 switch (add_to_queue(queuename
, interface
, membername
, penalty
, 0, queue_persistent_members
)) {
4817 ast_queue_log(queuename
, "CLI", interface
, "ADDMEMBER", "%s", "");
4818 ast_cli(fd
, "Added interface '%s' to queue '%s'\n", interface
, queuename
);
4819 return RESULT_SUCCESS
;
4821 ast_cli(fd
, "Unable to add interface '%s' to queue '%s': Already there\n", interface
, queuename
);
4822 return RESULT_FAILURE
;
4823 case RES_NOSUCHQUEUE
:
4824 ast_cli(fd
, "Unable to add interface to queue '%s': No such queue\n", queuename
);
4825 return RESULT_FAILURE
;
4826 case RES_OUTOFMEMORY
:
4827 ast_cli(fd
, "Out of memory\n");
4828 return RESULT_FAILURE
;
4830 return RESULT_FAILURE
;
4834 static char *complete_queue_add_member(const char *line
, const char *word
, int pos
, int state
)
4836 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
4838 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
4840 case 4: /* only one possible match, "to" */
4841 return state
== 0 ? ast_strdup("to") : NULL
;
4842 case 5: /* <queue> */
4843 return complete_queue(line
, word
, pos
, state
);
4844 case 6: /* only one possible match, "penalty" */
4845 return state
== 0 ? ast_strdup("penalty") : NULL
;
4847 if (state
< 100) { /* 0-99 */
4849 if ((num
= ast_malloc(3))) {
4850 sprintf(num
, "%d", state
);
4856 case 8: /* only one possible match, "as" */
4857 return state
== 0 ? ast_strdup("as") : NULL
;
4858 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
4865 static int handle_queue_remove_member(int fd
, int argc
, char *argv
[])
4867 char *queuename
, *interface
;
4870 return RESULT_SHOWUSAGE
;
4871 } else if (strcmp(argv
[4], "from")) {
4872 return RESULT_SHOWUSAGE
;
4875 queuename
= argv
[5];
4876 interface
= argv
[3];
4878 switch (remove_from_queue(queuename
, interface
)) {
4880 ast_queue_log(queuename
, "CLI", interface
, "REMOVEMEMBER", "%s", "");
4881 ast_cli(fd
, "Removed interface '%s' from queue '%s'\n", interface
, queuename
);
4882 return RESULT_SUCCESS
;
4884 ast_cli(fd
, "Unable to remove interface '%s' from queue '%s': Not there\n", interface
, queuename
);
4885 return RESULT_FAILURE
;
4886 case RES_NOSUCHQUEUE
:
4887 ast_cli(fd
, "Unable to remove interface from queue '%s': No such queue\n", queuename
);
4888 return RESULT_FAILURE
;
4889 case RES_OUTOFMEMORY
:
4890 ast_cli(fd
, "Out of memory\n");
4891 return RESULT_FAILURE
;
4892 case RES_NOT_DYNAMIC
:
4893 ast_cli(fd
, "Member not dynamic\n");
4894 return RESULT_FAILURE
;
4896 return RESULT_FAILURE
;
4900 static char *complete_queue_remove_member(const char *line
, const char *word
, int pos
, int state
)
4903 struct call_queue
*q
;
4905 struct ao2_iterator mem_iter
;
4907 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
4908 if (pos
> 5 || pos
< 3)
4910 if (pos
== 4) /* only one possible match, 'from' */
4911 return state
== 0 ? ast_strdup("from") : NULL
;
4913 if (pos
== 5) /* No need to duplicate code */
4914 return complete_queue(line
, word
, pos
, state
);
4916 /* here is the case for 3, <member> */
4917 if (!AST_LIST_EMPTY(&queues
)) { /* XXX unnecessary ? the traverse does that for us */
4918 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4919 ast_mutex_lock(&q
->lock
);
4920 mem_iter
= ao2_iterator_init(q
->members
, 0);
4921 while ((m
= ao2_iterator_next(&mem_iter
))) {
4922 if (++which
> state
) {
4924 ast_mutex_unlock(&q
->lock
);
4925 tmp
= ast_strdup(m
->interface
);
4931 ast_mutex_unlock(&q
->lock
);
4938 static char queue_show_usage
[] =
4939 "Usage: queue show\n"
4940 " Provides summary information on a specified queue.\n";
4942 static char qam_cmd_usage
[] =
4943 "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
4945 static char qrm_cmd_usage
[] =
4946 "Usage: queue remove member <channel> from <queue>\n";
4948 static struct ast_cli_entry cli_show_queue_deprecated
= {
4949 { "show", "queue", NULL
},
4951 NULL
, complete_queue_show
};
4953 static struct ast_cli_entry cli_add_queue_member_deprecated
= {
4954 { "add", "queue", "member", NULL
},
4955 handle_queue_add_member
, NULL
,
4956 NULL
, complete_queue_add_member
};
4958 static struct ast_cli_entry cli_remove_queue_member_deprecated
= {
4959 { "remove", "queue", "member", NULL
},
4960 handle_queue_remove_member
, NULL
,
4961 NULL
, complete_queue_remove_member
};
4963 static struct ast_cli_entry cli_queue
[] = {
4965 { { "show", "queues", NULL
},
4969 { { "queue", "show", NULL
},
4970 queue_show
, "Show status of a specified queue",
4971 queue_show_usage
, complete_queue_show
, &cli_show_queue_deprecated
},
4973 { { "queue", "add", "member", NULL
},
4974 handle_queue_add_member
, "Add a channel to a specified queue",
4975 qam_cmd_usage
, complete_queue_add_member
, &cli_add_queue_member_deprecated
},
4977 { { "queue", "remove", "member", NULL
},
4978 handle_queue_remove_member
, "Removes a channel from a specified queue",
4979 qrm_cmd_usage
, complete_queue_remove_member
, &cli_remove_queue_member_deprecated
},
4982 static int unload_module(void)
4986 if (device_state
.thread
!= AST_PTHREADT_NULL
) {
4987 device_state
.stop
= 1;
4988 ast_mutex_lock(&device_state
.lock
);
4989 ast_cond_signal(&device_state
.cond
);
4990 ast_mutex_unlock(&device_state
.lock
);
4991 pthread_join(device_state
.thread
, NULL
);
4994 ast_cli_unregister_multiple(cli_queue
, sizeof(cli_queue
) / sizeof(struct ast_cli_entry
));
4995 res
= ast_manager_unregister("QueueStatus");
4996 res
|= ast_manager_unregister("Queues");
4997 res
|= ast_manager_unregister("QueueStatus");
4998 res
|= ast_manager_unregister("QueueAdd");
4999 res
|= ast_manager_unregister("QueueRemove");
5000 res
|= ast_manager_unregister("QueuePause");
5001 res
|= ast_unregister_application(app_aqm
);
5002 res
|= ast_unregister_application(app_rqm
);
5003 res
|= ast_unregister_application(app_pqm
);
5004 res
|= ast_unregister_application(app_upqm
);
5005 res
|= ast_unregister_application(app_ql
);
5006 res
|= ast_unregister_application(app
);
5007 res
|= ast_custom_function_unregister(&queueagentcount_function
);
5008 res
|= ast_custom_function_unregister(&queuemembercount_function
);
5009 res
|= ast_custom_function_unregister(&queuememberlist_function
);
5010 res
|= ast_custom_function_unregister(&queuewaitingcount_function
);
5011 ast_devstate_del(statechange_queue
, NULL
);
5013 ast_module_user_hangup_all();
5015 clear_and_free_interfaces();
5020 static int load_module(void)
5024 if (!reload_queues())
5025 return AST_MODULE_LOAD_DECLINE
;
5027 if (queue_persistent_members
)
5028 reload_queue_members();
5030 ast_mutex_init(&device_state
.lock
);
5031 ast_cond_init(&device_state
.cond
, NULL
);
5032 ast_pthread_create(&device_state
.thread
, NULL
, device_state_thread
, NULL
);
5034 ast_cli_register_multiple(cli_queue
, sizeof(cli_queue
) / sizeof(struct ast_cli_entry
));
5035 res
= ast_register_application(app
, queue_exec
, synopsis
, descrip
);
5036 res
|= ast_register_application(app_aqm
, aqm_exec
, app_aqm_synopsis
, app_aqm_descrip
);
5037 res
|= ast_register_application(app_rqm
, rqm_exec
, app_rqm_synopsis
, app_rqm_descrip
);
5038 res
|= ast_register_application(app_pqm
, pqm_exec
, app_pqm_synopsis
, app_pqm_descrip
);
5039 res
|= ast_register_application(app_upqm
, upqm_exec
, app_upqm_synopsis
, app_upqm_descrip
);
5040 res
|= ast_register_application(app_ql
, ql_exec
, app_ql_synopsis
, app_ql_descrip
);
5041 res
|= ast_manager_register("Queues", 0, manager_queues_show
, "Queues");
5042 res
|= ast_manager_register("QueueStatus", 0, manager_queues_status
, "Queue Status");
5043 res
|= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT
, manager_add_queue_member
, "Add interface to queue.");
5044 res
|= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT
, manager_remove_queue_member
, "Remove interface from queue.");
5045 res
|= ast_manager_register("QueuePause", EVENT_FLAG_AGENT
, manager_pause_queue_member
, "Makes a queue member temporarily unavailable");
5046 res
|= ast_custom_function_register(&queueagentcount_function
);
5047 res
|= ast_custom_function_register(&queuemembercount_function
);
5048 res
|= ast_custom_function_register(&queuememberlist_function
);
5049 res
|= ast_custom_function_register(&queuewaitingcount_function
);
5050 res
|= ast_devstate_add(statechange_queue
, NULL
);
5055 static int reload(void)
5061 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "True Call Queueing",
5062 .load
= load_module
,
5063 .unload
= unload_module
,