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 AST_LIST_INSERT_HEAD(&queues
, q
, list
);
1234 init_queue(q
); /* Ensure defaults for all parameters not set explicitly. */
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
);
2592 ast_channel_datastore_free(datastore
);
2595 /*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
2597 * When a caller is atxferred, then the queue_transfer_info datastore
2598 * is removed from the channel. If it's still there after the bridge is
2599 * broken, then the caller was not atxferred.
2601 static int attended_transfer_occurred(struct ast_channel
*chan
)
2603 return ast_channel_datastore_find(chan
, &queue_transfer_info
, NULL
) ? 0 : 1;
2606 /*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
2608 static void setup_transfer_datastore(struct queue_ent
*qe
, struct member
*member
, int starttime
)
2610 struct ast_datastore
*ds
;
2611 struct queue_transfer_ds
*qtds
= ast_calloc(1, sizeof(*qtds
));
2614 ast_log(LOG_WARNING
, "Memory allocation error!\n");
2618 ast_channel_lock(qe
->chan
);
2619 if (!(ds
= ast_channel_datastore_alloc(&queue_transfer_info
, NULL
))) {
2620 ast_channel_unlock(qe
->chan
);
2621 ast_log(LOG_WARNING
, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
2626 /* This member is refcounted in try_calling, so no need to add it here, too */
2627 qtds
->member
= member
;
2628 qtds
->starttime
= starttime
;
2630 ast_channel_datastore_add(qe
->chan
, ds
);
2631 ast_channel_unlock(qe
->chan
);
2635 /*! \brief A large function which calls members, updates statistics, and bridges the caller and a member
2637 * Here is the process of this function
2638 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
2639 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
2640 * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
2641 * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
2642 * during each iteration, we call calc_metric to determine which members should be rung when.
2643 * 3. Call ring_one to place a call to the appropriate member(s)
2644 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
2645 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
2646 * 6. Start the monitor or mixmonitor if the option is set
2647 * 7. Remove the caller from the queue to allow other callers to advance
2648 * 8. Bridge the call.
2649 * 9. Do any post processing after the call has disconnected.
2651 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
2652 * \param[in] options the options passed as the third parameter to the Queue() application
2653 * \param[in] url the url passed as the fourth parameter to the Queue() application
2654 * \param[in,out] tries the number of times we have tried calling queue members
2655 * \param[out] noption set if the call to Queue() has the 'n' option set.
2656 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
2659 static int try_calling(struct queue_ent
*qe
, const char *options
, char *announceoverride
, const char *url
, int *tries
, int *noption
, const char *agi
)
2662 struct callattempt
*outgoing
= NULL
; /* the list of calls we are building */
2664 char oldexten
[AST_MAX_EXTENSION
]="";
2665 char oldcontext
[AST_MAX_CONTEXT
]="";
2666 char queuename
[256]="";
2667 struct ast_channel
*peer
;
2668 struct ast_channel
*which
;
2669 struct callattempt
*lpeer
;
2670 struct member
*member
;
2671 struct ast_app
*app
;
2672 int res
= 0, bridge
= 0;
2675 char *announce
= NULL
;
2678 time_t now
= time(NULL
);
2679 struct ast_bridge_config bridge_config
;
2680 char nondataquality
= 1;
2681 char *agiexec
= NULL
;
2683 const char *monitorfilename
;
2684 const char *monitor_exec
;
2685 const char *monitor_options
;
2686 char tmpid
[256], tmpid2
[256];
2687 char meid
[1024], meid2
[1024];
2688 char mixmonargs
[1512];
2689 struct ast_app
*mixmonapp
= NULL
;
2692 int forwardsallowed
= 1;
2693 int callcompletedinsl
;
2694 struct ao2_iterator memi
;
2695 struct ast_datastore
*datastore
;
2697 ast_channel_lock(qe
->chan
);
2698 datastore
= ast_channel_datastore_find(qe
->chan
, &dialed_interface_info
, NULL
);
2699 ast_channel_unlock(qe
->chan
);
2701 memset(&bridge_config
, 0, sizeof(bridge_config
));
2704 for (; options
&& *options
; options
++)
2707 ast_set_flag(&(bridge_config
.features_callee
), AST_FEATURE_REDIRECT
);
2710 ast_set_flag(&(bridge_config
.features_caller
), AST_FEATURE_REDIRECT
);
2713 ast_set_flag(&(bridge_config
.features_callee
), AST_FEATURE_AUTOMON
);
2716 ast_set_flag(&(bridge_config
.features_caller
), AST_FEATURE_AUTOMON
);
2722 ast_set_flag(&(bridge_config
.features_callee
), AST_FEATURE_DISCONNECT
);
2725 ast_set_flag(&(bridge_config
.features_caller
), AST_FEATURE_DISCONNECT
);
2728 if (qe
->parent
->strategy
== QUEUE_STRATEGY_ROUNDROBIN
|| qe
->parent
->strategy
== QUEUE_STRATEGY_RRMEMORY
)
2731 *tries
= qe
->parent
->membercount
;
2735 forwardsallowed
= 0;
2739 /* Hold the lock while we setup the outgoing calls */
2741 AST_LIST_LOCK(&queues
);
2742 ast_mutex_lock(&qe
->parent
->lock
);
2744 ast_log(LOG_DEBUG
, "%s is trying to call a queue member.\n",
2746 ast_copy_string(queuename
, qe
->parent
->name
, sizeof(queuename
));
2747 if (!ast_strlen_zero(qe
->announce
))
2748 announce
= qe
->announce
;
2749 if (!ast_strlen_zero(announceoverride
))
2750 announce
= announceoverride
;
2752 memi
= ao2_iterator_init(qe
->parent
->members
, 0);
2753 while ((cur
= ao2_iterator_next(&memi
))) {
2754 struct callattempt
*tmp
= ast_calloc(1, sizeof(*tmp
));
2755 struct ast_dialed_interface
*di
;
2756 AST_LIST_HEAD(, ast_dialed_interface
) *dialed_interfaces
;
2759 ast_mutex_unlock(&qe
->parent
->lock
);
2761 AST_LIST_UNLOCK(&queues
);
2765 if (!(datastore
= ast_channel_datastore_alloc(&dialed_interface_info
, NULL
))) {
2767 ast_mutex_unlock(&qe
->parent
->lock
);
2769 AST_LIST_UNLOCK(&queues
);
2773 datastore
->inheritance
= DATASTORE_INHERIT_FOREVER
;
2774 if (!(dialed_interfaces
= ast_calloc(1, sizeof(*dialed_interfaces
)))) {
2776 ast_mutex_unlock(&qe
->parent
->lock
);
2778 AST_LIST_UNLOCK(&queues
);
2782 datastore
->data
= dialed_interfaces
;
2783 AST_LIST_HEAD_INIT(dialed_interfaces
);
2785 ast_channel_lock(qe
->chan
);
2786 ast_channel_datastore_add(qe
->chan
, datastore
);
2787 ast_channel_unlock(qe
->chan
);
2789 dialed_interfaces
= datastore
->data
;
2791 AST_LIST_LOCK(dialed_interfaces
);
2792 AST_LIST_TRAVERSE(dialed_interfaces
, di
, list
) {
2793 if (!strcasecmp(cur
->interface
, di
->interface
)) {
2794 ast_log(LOG_DEBUG
, "Skipping dialing interface '%s' since it has already been dialed\n",
2799 AST_LIST_UNLOCK(dialed_interfaces
);
2806 /* It is always ok to dial a Local interface. We only keep track of
2807 * which "real" interfaces have been dialed. The Local channel will
2808 * inherit this list so that if it ends up dialing a real interface,
2809 * it won't call one that has already been called. */
2810 if (strncasecmp(cur
->interface
, "Local/", 6)) {
2811 if (!(di
= ast_calloc(1, sizeof(*di
) + strlen(cur
->interface
)))) {
2813 ast_mutex_unlock(&qe
->parent
->lock
);
2815 AST_LIST_UNLOCK(&queues
);
2819 strcpy(di
->interface
, cur
->interface
);
2821 AST_LIST_LOCK(dialed_interfaces
);
2822 AST_LIST_INSERT_TAIL(dialed_interfaces
, di
, list
);
2823 AST_LIST_UNLOCK(dialed_interfaces
);
2826 tmp
->stillgoing
= -1;
2828 tmp
->oldstatus
= cur
->status
;
2829 tmp
->lastcall
= cur
->lastcall
;
2830 ast_copy_string(tmp
->interface
, cur
->interface
, sizeof(tmp
->interface
));
2831 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2832 just calculate their metric for the appropriate strategy */
2833 if (!calc_metric(qe
->parent
, cur
, x
++, qe
, tmp
)) {
2834 /* Put them in the list of outgoing thingies... We're ready now.
2835 XXX If we're forcibly removed, these outgoing calls won't get
2837 tmp
->q_next
= outgoing
;
2839 /* If this line is up, don't try anybody else */
2840 if (outgoing
->chan
&& (outgoing
->chan
->_state
== AST_STATE_UP
))
2847 if (qe
->expire
&& (!qe
->parent
->timeout
|| (qe
->expire
- now
) <= qe
->parent
->timeout
))
2848 to
= (qe
->expire
- now
) * 1000;
2850 to
= (qe
->parent
->timeout
) ? qe
->parent
->timeout
* 1000 : -1;
2852 ast_mutex_unlock(&qe
->parent
->lock
);
2853 ring_one(qe
, outgoing
, &numbusies
);
2855 AST_LIST_UNLOCK(&queues
);
2856 lpeer
= wait_for_answer(qe
, outgoing
, &to
, &digit
, numbusies
, ast_test_flag(&(bridge_config
.features_caller
), AST_FEATURE_DISCONNECT
), forwardsallowed
);
2857 /* The ast_channel_datastore_remove() function could fail here if the
2858 * datastore was moved to another channel during a masquerade. If this is
2859 * the case, don't free the datastore here because later, when the channel
2860 * to which the datastore was moved hangs up, it will attempt to free this
2861 * datastore again, causing a crash
2863 if (datastore
&& !ast_channel_datastore_remove(qe
->chan
, datastore
)) {
2864 ast_channel_datastore_free(datastore
);
2866 ast_mutex_lock(&qe
->parent
->lock
);
2867 if (qe
->parent
->strategy
== QUEUE_STRATEGY_RRMEMORY
) {
2868 store_next(qe
, outgoing
);
2870 ast_mutex_unlock(&qe
->parent
->lock
);
2871 peer
= lpeer
? lpeer
->chan
: NULL
;
2875 /* Must gotten hung up */
2878 /* User exited by pressing a digit */
2881 if (option_debug
&& res
== -1)
2882 ast_log(LOG_DEBUG
, "%s: Nobody answered.\n", qe
->chan
->name
);
2883 } else { /* peer is valid */
2884 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2885 we will always return with -1 so that it is hung up properly after the
2887 if (!strcmp(qe
->chan
->tech
->type
, "Zap"))
2888 ast_channel_setoption(qe
->chan
, AST_OPTION_TONE_VERIFY
, &nondataquality
, sizeof(nondataquality
), 0);
2889 if (!strcmp(peer
->tech
->type
, "Zap"))
2890 ast_channel_setoption(peer
, AST_OPTION_TONE_VERIFY
, &nondataquality
, sizeof(nondataquality
), 0);
2891 /* Update parameters for the queue */
2893 recalc_holdtime(qe
, (now
- qe
->start
));
2894 ast_mutex_lock(&qe
->parent
->lock
);
2895 callcompletedinsl
= ((now
- qe
->start
) <= qe
->parent
->servicelevel
);
2896 ast_mutex_unlock(&qe
->parent
->lock
);
2897 member
= lpeer
->member
;
2898 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
2900 hangupcalls(outgoing
, peer
);
2902 if (announce
|| qe
->parent
->reportholdtime
|| qe
->parent
->memberdelay
) {
2905 res2
= ast_autoservice_start(qe
->chan
);
2907 if (qe
->parent
->memberdelay
) {
2908 ast_log(LOG_NOTICE
, "Delaying member connect for %d seconds\n", qe
->parent
->memberdelay
);
2909 res2
|= ast_safe_sleep(peer
, qe
->parent
->memberdelay
* 1000);
2911 if (!res2
&& announce
) {
2912 play_file(peer
, announce
);
2914 if (!res2
&& qe
->parent
->reportholdtime
) {
2915 if (!play_file(peer
, qe
->parent
->sound_reporthold
)) {
2919 holdtime
= abs((now
- qe
->start
) / 60);
2921 play_file(peer
, qe
->parent
->sound_lessthan
);
2922 ast_say_number(peer
, 2, AST_DIGIT_ANY
, peer
->language
, NULL
);
2924 ast_say_number(peer
, holdtime
, AST_DIGIT_ANY
, peer
->language
, NULL
);
2925 play_file(peer
, qe
->parent
->sound_minutes
);
2929 res2
|= ast_autoservice_stop(qe
->chan
);
2930 if (peer
->_softhangup
) {
2931 /* Agent must have hung up */
2932 ast_log(LOG_WARNING
, "Agent on %s hungup on the customer.\n", peer
->name
);
2933 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "AGENTDUMP", "%s", "");
2934 if (qe
->parent
->eventwhencalled
)
2935 manager_event(EVENT_FLAG_AGENT
, "AgentDump",
2940 "MemberName: %s\r\n"
2942 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->interface
, member
->membername
,
2943 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
2945 ao2_ref(member
, -1);
2948 /* Caller must have hung up just before being connected*/
2949 ast_log(LOG_NOTICE
, "Caller was about to talk to agent on %s but the caller hungup.\n", peer
->name
);
2950 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "ABANDON", "%d|%d|%ld", qe
->pos
, qe
->opos
, (long)time(NULL
) - qe
->start
);
2951 record_abandoned(qe
);
2953 ao2_ref(member
, -1);
2957 /* Stop music on hold */
2958 ast_moh_stop(qe
->chan
);
2959 /* If appropriate, log that we have a destination channel */
2961 ast_cdr_setdestchan(qe
->chan
->cdr
, peer
->name
);
2962 /* Make sure channels are compatible */
2963 res
= ast_channel_make_compatible(qe
->chan
, peer
);
2965 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "SYSCOMPAT", "%s", "");
2966 ast_log(LOG_WARNING
, "Had to drop call because I couldn't make %s compatible with %s\n", qe
->chan
->name
, peer
->name
);
2967 record_abandoned(qe
);
2969 ao2_ref(member
, -1);
2973 if (qe
->parent
->setinterfacevar
)
2974 pbx_builtin_setvar_helper(qe
->chan
, "MEMBERINTERFACE", member
->interface
);
2976 /* Begin Monitoring */
2977 if (qe
->parent
->monfmt
&& *qe
->parent
->monfmt
) {
2978 if (!qe
->parent
->montype
) {
2980 ast_log(LOG_DEBUG
, "Starting Monitor as requested.\n");
2981 monitorfilename
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_FILENAME");
2982 if (pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_EXEC_ARGS"))
2986 if (monitorfilename
)
2987 ast_monitor_start(which
, qe
->parent
->monfmt
, monitorfilename
, 1 );
2988 else if (qe
->chan
->cdr
)
2989 ast_monitor_start(which
, qe
->parent
->monfmt
, qe
->chan
->cdr
->uniqueid
, 1 );
2991 /* Last ditch effort -- no CDR, make up something */
2992 snprintf(tmpid
, sizeof(tmpid
), "chan-%lx", ast_random());
2993 ast_monitor_start(which
, qe
->parent
->monfmt
, tmpid
, 1 );
2995 if (qe
->parent
->monjoin
)
2996 ast_monitor_setjoinfiles(which
, 1);
2999 ast_log(LOG_DEBUG
, "Starting MixMonitor as requested.\n");
3000 monitorfilename
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_FILENAME");
3001 if (!monitorfilename
) {
3003 ast_copy_string(tmpid
, qe
->chan
->cdr
->uniqueid
, sizeof(tmpid
)-1);
3005 snprintf(tmpid
, sizeof(tmpid
), "chan-%lx", ast_random());
3007 ast_copy_string(tmpid2
, monitorfilename
, sizeof(tmpid2
)-1);
3008 for (p
= tmpid2
; *p
; p
++) {
3009 if (*p
== '^' && *(p
+1) == '{') {
3014 memset(tmpid
, 0, sizeof(tmpid
));
3015 pbx_substitute_variables_helper(qe
->chan
, tmpid2
, tmpid
, sizeof(tmpid
) - 1);
3018 monitor_exec
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_EXEC");
3019 monitor_options
= pbx_builtin_getvar_helper(qe
->chan
, "MONITOR_OPTIONS");
3022 ast_copy_string(meid2
, monitor_exec
, sizeof(meid2
)-1);
3023 for (p
= meid2
; *p
; p
++) {
3024 if (*p
== '^' && *(p
+1) == '{') {
3029 memset(meid
, 0, sizeof(meid
));
3030 pbx_substitute_variables_helper(qe
->chan
, meid2
, meid
, sizeof(meid
) - 1);
3033 snprintf(tmpid2
, sizeof(tmpid2
)-1, "%s.%s", tmpid
, qe
->parent
->monfmt
);
3035 mixmonapp
= pbx_findapp("MixMonitor");
3037 if (strchr(tmpid2
, '|')) {
3038 ast_log(LOG_WARNING
, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
3042 if (!monitor_options
)
3043 monitor_options
= "";
3045 if (strchr(monitor_options
, '|')) {
3046 ast_log(LOG_WARNING
, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
3051 if (!ast_strlen_zero(monitor_exec
))
3052 snprintf(mixmonargs
, sizeof(mixmonargs
)-1, "%s|b%s|%s", tmpid2
, monitor_options
, monitor_exec
);
3054 snprintf(mixmonargs
, sizeof(mixmonargs
)-1, "%s|b%s", tmpid2
, monitor_options
);
3057 ast_log(LOG_DEBUG
, "Arguments being passed to MixMonitor: %s\n", mixmonargs
);
3058 /* We purposely lock the CDR so that pbx_exec does not update the application data */
3060 ast_set_flag(qe
->chan
->cdr
, AST_CDR_FLAG_LOCKED
);
3061 ret
= pbx_exec(qe
->chan
, mixmonapp
, mixmonargs
);
3063 ast_clear_flag(qe
->chan
->cdr
, AST_CDR_FLAG_LOCKED
);
3066 ast_log(LOG_WARNING
, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
3070 /* Drop out of the queue at this point, to prepare for next caller */
3072 if (!ast_strlen_zero(url
) && ast_channel_supports_html(peer
)) {
3074 ast_log(LOG_DEBUG
, "app_queue: sendurl=%s.\n", url
);
3075 ast_channel_sendurl(peer
, url
);
3077 if (!ast_strlen_zero(agi
)) {
3079 ast_log(LOG_DEBUG
, "app_queue: agi=%s.\n", agi
);
3080 app
= pbx_findapp("agi");
3082 agiexec
= ast_strdupa(agi
);
3083 ret
= pbx_exec(qe
->chan
, app
, agiexec
);
3085 ast_log(LOG_WARNING
, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
3088 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "CONNECT", "%ld|%s", (long)time(NULL
) - qe
->start
, peer
->uniqueid
);
3089 if (qe
->parent
->eventwhencalled
)
3090 manager_event(EVENT_FLAG_AGENT
, "AgentConnect",
3095 "MemberName: %s\r\n"
3097 "BridgedChannel: %s\r\n"
3099 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->interface
, member
->membername
,
3100 (long)time(NULL
) - qe
->start
, peer
->uniqueid
,
3101 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
3102 ast_copy_string(oldcontext
, qe
->chan
->context
, sizeof(oldcontext
));
3103 ast_copy_string(oldexten
, qe
->chan
->exten
, sizeof(oldexten
));
3106 if (member
->status
== AST_DEVICE_NOT_INUSE
)
3107 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
);
3109 setup_transfer_datastore(qe
, member
, callstart
);
3110 bridge
= ast_bridge_call(qe
->chan
,peer
, &bridge_config
);
3112 if (!attended_transfer_occurred(qe
->chan
)) {
3113 struct ast_datastore
*transfer_ds
;
3114 if (strcasecmp(oldcontext
, qe
->chan
->context
) || strcasecmp(oldexten
, qe
->chan
->exten
)) {
3115 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "TRANSFER", "%s|%s|%ld|%ld",
3116 qe
->chan
->exten
, qe
->chan
->context
, (long) (callstart
- qe
->start
),
3117 (long) (time(NULL
) - callstart
));
3118 } else if (qe
->chan
->_softhangup
) {
3119 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "COMPLETECALLER", "%ld|%ld|%d",
3120 (long) (callstart
- qe
->start
), (long) (time(NULL
) - callstart
), qe
->opos
);
3121 if (qe
->parent
->eventwhencalled
)
3122 manager_event(EVENT_FLAG_AGENT
, "AgentComplete",
3127 "MemberName: %s\r\n"
3130 "Reason: caller\r\n"
3132 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->interface
, member
->membername
,
3133 (long)(callstart
- qe
->start
), (long)(time(NULL
) - callstart
),
3134 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
3136 ast_queue_log(queuename
, qe
->chan
->uniqueid
, member
->membername
, "COMPLETEAGENT", "%ld|%ld|%d",
3137 (long) (callstart
- qe
->start
), (long) (time(NULL
) - callstart
), qe
->opos
);
3138 if (qe
->parent
->eventwhencalled
)
3139 manager_event(EVENT_FLAG_AGENT
, "AgentComplete",
3143 "MemberName: %s\r\n"
3148 queuename
, qe
->chan
->uniqueid
, peer
->name
, member
->membername
, (long)(callstart
- qe
->start
),
3149 (long)(time(NULL
) - callstart
),
3150 qe
->parent
->eventwhencalled
== QUEUE_EVENT_VARIABLES
? vars2manager(qe
->chan
, vars
, sizeof(vars
)) : "");
3152 ast_channel_lock(qe
->chan
);
3153 transfer_ds
= ast_channel_datastore_find(qe
->chan
, &queue_transfer_info
, NULL
);
3155 ast_channel_datastore_remove(qe
->chan
, transfer_ds
);
3156 ast_channel_datastore_free(transfer_ds
);
3158 ast_channel_unlock(qe
->chan
);
3161 if (bridge
!= AST_PBX_NO_HANGUP_PEER
)
3163 update_queue(qe
->parent
, member
, callcompletedinsl
);
3164 res
= bridge
? bridge
: 1;
3165 ao2_ref(member
, -1);
3168 hangupcalls(outgoing
, NULL
);
3173 static int wait_a_bit(struct queue_ent
*qe
)
3175 /* Don't need to hold the lock while we setup the outgoing calls */
3176 int retrywait
= qe
->parent
->retry
* 1000;
3178 int res
= ast_waitfordigit(qe
->chan
, retrywait
);
3179 if (res
> 0 && !valid_exit(qe
, res
))
3185 static struct member
*interface_exists(struct call_queue
*q
, const char *interface
)
3188 struct ao2_iterator mem_iter
;
3193 mem_iter
= ao2_iterator_init(q
->members
, 0);
3194 while ((mem
= ao2_iterator_next(&mem_iter
))) {
3195 if (!strcasecmp(interface
, mem
->interface
))
3204 /* Dump all members in a specific queue to the database
3206 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3209 static void dump_queue_members(struct call_queue
*pm_queue
)
3211 struct member
*cur_member
;
3212 char value
[PM_MAX_LEN
];
3215 struct ao2_iterator mem_iter
;
3217 memset(value
, 0, sizeof(value
));
3222 mem_iter
= ao2_iterator_init(pm_queue
->members
, 0);
3223 while ((cur_member
= ao2_iterator_next(&mem_iter
))) {
3224 if (!cur_member
->dynamic
) {
3225 ao2_ref(cur_member
, -1);
3229 res
= snprintf(value
+ value_len
, sizeof(value
) - value_len
, "%s%s;%d;%d;%s",
3230 value_len
? "|" : "", cur_member
->interface
, cur_member
->penalty
, cur_member
->paused
, cur_member
->membername
);
3232 ao2_ref(cur_member
, -1);
3234 if (res
!= strlen(value
+ value_len
)) {
3235 ast_log(LOG_WARNING
, "Could not create persistent member string, out of space\n");
3241 if (value_len
&& !cur_member
) {
3242 if (ast_db_put(pm_family
, pm_queue
->name
, value
))
3243 ast_log(LOG_WARNING
, "failed to create persistent dynamic entry!\n");
3245 /* Delete the entry if the queue is empty or there is an error */
3246 ast_db_del(pm_family
, pm_queue
->name
);
3249 static int remove_from_queue(const char *queuename
, const char *interface
)
3251 struct call_queue
*q
;
3252 struct member
*mem
, tmpmem
;
3253 int res
= RES_NOSUCHQUEUE
;
3255 ast_copy_string(tmpmem
.interface
, interface
, sizeof(tmpmem
.interface
));
3257 AST_LIST_LOCK(&queues
);
3258 AST_LIST_TRAVERSE(&queues
, q
, list
) {
3259 ast_mutex_lock(&q
->lock
);
3260 if (strcmp(q
->name
, queuename
)) {
3261 ast_mutex_unlock(&q
->lock
);
3265 if ((mem
= ao2_find(q
->members
, &tmpmem
, OBJ_POINTER
))) {
3266 /* XXX future changes should beware of this assumption!! */
3267 if (!mem
->dynamic
) {
3268 res
= RES_NOT_DYNAMIC
;
3270 ast_mutex_unlock(&q
->lock
);
3274 manager_event(EVENT_FLAG_AGENT
, "QueueMemberRemoved",
3277 "MemberName: %s\r\n",
3278 q
->name
, mem
->interface
, mem
->membername
);
3279 ao2_unlink(q
->members
, mem
);
3282 if (queue_persistent_members
)
3283 dump_queue_members(q
);
3289 ast_mutex_unlock(&q
->lock
);
3293 if (res
== RES_OKAY
)
3294 remove_from_interfaces(interface
);
3296 AST_LIST_UNLOCK(&queues
);
3302 static int add_to_queue(const char *queuename
, const char *interface
, const char *membername
, int penalty
, int paused
, int dump
)
3304 struct call_queue
*q
;
3305 struct member
*new_member
, *old_member
;
3306 int res
= RES_NOSUCHQUEUE
;
3308 /* \note Ensure the appropriate realtime queue is loaded. Note that this
3309 * short-circuits if the queue is already in memory. */
3310 if (!(q
= load_realtime_queue(queuename
)))
3313 AST_LIST_LOCK(&queues
);
3315 ast_mutex_lock(&q
->lock
);
3316 if ((old_member
= interface_exists(q
, interface
)) == NULL
) {
3317 add_to_interfaces(interface
);
3318 if ((new_member
= create_queue_member(interface
, membername
, penalty
, paused
))) {
3319 new_member
->dynamic
= 1;
3320 ao2_link(q
->members
, new_member
);
3322 manager_event(EVENT_FLAG_AGENT
, "QueueMemberAdded",
3325 "MemberName: %s\r\n"
3326 "Membership: %s\r\n"
3328 "CallsTaken: %d\r\n"
3332 q
->name
, new_member
->interface
, new_member
->membername
,
3334 new_member
->penalty
, new_member
->calls
, (int) new_member
->lastcall
,
3335 new_member
->status
, new_member
->paused
);
3337 ao2_ref(new_member
, -1);
3341 dump_queue_members(q
);
3345 res
= RES_OUTOFMEMORY
;
3348 ao2_ref(old_member
, -1);
3351 ast_mutex_unlock(&q
->lock
);
3352 AST_LIST_UNLOCK(&queues
);
3357 static int set_member_paused(const char *queuename
, const char *interface
, int paused
)
3360 struct call_queue
*q
;
3363 /* Special event for when all queues are paused - individual events still generated */
3364 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
3365 if (ast_strlen_zero(queuename
))
3366 ast_queue_log("NONE", "NONE", interface
, (paused
? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
3368 AST_LIST_LOCK(&queues
);
3369 AST_LIST_TRAVERSE(&queues
, q
, list
) {
3370 ast_mutex_lock(&q
->lock
);
3371 if (ast_strlen_zero(queuename
) || !strcasecmp(q
->name
, queuename
)) {
3372 if ((mem
= interface_exists(q
, interface
))) {
3374 if (mem
->paused
== paused
)
3375 ast_log(LOG_DEBUG
, "%spausing already-%spaused queue member %s:%s\n", (paused
? "" : "un"), (paused
? "" : "un"), q
->name
, interface
);
3376 mem
->paused
= paused
;
3378 if (queue_persistent_members
)
3379 dump_queue_members(q
);
3382 update_realtime_member_field(mem
, q
->name
, "paused", paused
? "1" : "0");
3384 ast_queue_log(q
->name
, "NONE", mem
->membername
, (paused
? "PAUSE" : "UNPAUSE"), "%s", "");
3386 manager_event(EVENT_FLAG_AGENT
, "QueueMemberPaused",
3389 "MemberName: %s\r\n"
3391 q
->name
, mem
->interface
, mem
->membername
, paused
);
3395 ast_mutex_unlock(&q
->lock
);
3397 AST_LIST_UNLOCK(&queues
);
3399 return found
? RESULT_SUCCESS
: RESULT_FAILURE
;
3402 /* Reload dynamic queue members persisted into the astdb */
3403 static void reload_queue_members(void)
3409 char *membername
= NULL
;
3414 struct ast_db_entry
*db_tree
;
3415 struct ast_db_entry
*entry
;
3416 struct call_queue
*cur_queue
;
3417 char queue_data
[PM_MAX_LEN
];
3419 AST_LIST_LOCK(&queues
);
3421 /* Each key in 'pm_family' is the name of a queue */
3422 db_tree
= ast_db_gettree(pm_family
, NULL
);
3423 for (entry
= db_tree
; entry
; entry
= entry
->next
) {
3425 queue_name
= entry
->key
+ strlen(pm_family
) + 2;
3427 AST_LIST_TRAVERSE(&queues
, cur_queue
, list
) {
3428 ast_mutex_lock(&cur_queue
->lock
);
3429 if (!strcmp(queue_name
, cur_queue
->name
))
3431 ast_mutex_unlock(&cur_queue
->lock
);
3435 cur_queue
= load_realtime_queue(queue_name
);
3438 /* If the queue no longer exists, remove it from the
3440 ast_log(LOG_WARNING
, "Error loading persistent queue: '%s': it does not exist\n", queue_name
);
3441 ast_db_del(pm_family
, queue_name
);
3444 ast_mutex_unlock(&cur_queue
->lock
);
3446 if (ast_db_get(pm_family
, queue_name
, queue_data
, PM_MAX_LEN
))
3449 cur_ptr
= queue_data
;
3450 while ((member
= strsep(&cur_ptr
, "|"))) {
3451 if (ast_strlen_zero(member
))
3454 interface
= strsep(&member
, ";");
3455 penalty_tok
= strsep(&member
, ";");
3456 paused_tok
= strsep(&member
, ";");
3457 membername
= strsep(&member
, ";");
3460 ast_log(LOG_WARNING
, "Error parsing persistent member string for '%s' (penalty)\n", queue_name
);
3463 penalty
= strtol(penalty_tok
, NULL
, 10);
3464 if (errno
== ERANGE
) {
3465 ast_log(LOG_WARNING
, "Error converting penalty: %s: Out of range.\n", penalty_tok
);
3470 ast_log(LOG_WARNING
, "Error parsing persistent member string for '%s' (paused)\n", queue_name
);
3473 paused
= strtol(paused_tok
, NULL
, 10);
3474 if ((errno
== ERANGE
) || paused
< 0 || paused
> 1) {
3475 ast_log(LOG_WARNING
, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok
);
3478 if (ast_strlen_zero(membername
))
3479 membername
= interface
;
3482 ast_log(LOG_DEBUG
, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name
, interface
, membername
, penalty
, paused
);
3484 if (add_to_queue(queue_name
, interface
, membername
, penalty
, paused
, 0) == RES_OUTOFMEMORY
) {
3485 ast_log(LOG_ERROR
, "Out of Memory when reloading persistent queue member\n");
3491 AST_LIST_UNLOCK(&queues
);
3493 ast_log(LOG_NOTICE
, "Queue members successfully reloaded from database.\n");
3494 ast_db_freetree(db_tree
);
3498 static int pqm_exec(struct ast_channel
*chan
, void *data
)
3500 struct ast_module_user
*lu
;
3502 int priority_jump
= 0;
3503 AST_DECLARE_APP_ARGS(args
,
3504 AST_APP_ARG(queuename
);
3505 AST_APP_ARG(interface
);
3506 AST_APP_ARG(options
);
3509 if (ast_strlen_zero(data
)) {
3510 ast_log(LOG_WARNING
, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3514 parse
= ast_strdupa(data
);
3516 AST_STANDARD_APP_ARGS(args
, parse
);
3518 lu
= ast_module_user_add(chan
);
3521 if (strchr(args
.options
, 'j'))
3525 if (ast_strlen_zero(args
.interface
)) {
3526 ast_log(LOG_WARNING
, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3527 ast_module_user_remove(lu
);
3531 if (set_member_paused(args
.queuename
, args
.interface
, 1)) {
3532 ast_log(LOG_WARNING
, "Attempt to pause interface %s, not found\n", args
.interface
);
3533 if (priority_jump
|| ast_opt_priority_jumping
) {
3534 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101)) {
3535 pbx_builtin_setvar_helper(chan
, "PQMSTATUS", "NOTFOUND");
3536 ast_module_user_remove(lu
);
3540 ast_module_user_remove(lu
);
3541 pbx_builtin_setvar_helper(chan
, "PQMSTATUS", "NOTFOUND");
3545 ast_module_user_remove(lu
);
3546 pbx_builtin_setvar_helper(chan
, "PQMSTATUS", "PAUSED");
3551 static int upqm_exec(struct ast_channel
*chan
, void *data
)
3553 struct ast_module_user
*lu
;
3555 int priority_jump
= 0;
3556 AST_DECLARE_APP_ARGS(args
,
3557 AST_APP_ARG(queuename
);
3558 AST_APP_ARG(interface
);
3559 AST_APP_ARG(options
);
3562 if (ast_strlen_zero(data
)) {
3563 ast_log(LOG_WARNING
, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
3567 parse
= ast_strdupa(data
);
3569 AST_STANDARD_APP_ARGS(args
, parse
);
3571 lu
= ast_module_user_add(chan
);
3574 if (strchr(args
.options
, 'j'))
3578 if (ast_strlen_zero(args
.interface
)) {
3579 ast_log(LOG_WARNING
, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
3580 ast_module_user_remove(lu
);
3584 if (set_member_paused(args
.queuename
, args
.interface
, 0)) {
3585 ast_log(LOG_WARNING
, "Attempt to unpause interface %s, not found\n", args
.interface
);
3586 if (priority_jump
|| ast_opt_priority_jumping
) {
3587 if (ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101)) {
3588 pbx_builtin_setvar_helper(chan
, "UPQMSTATUS", "NOTFOUND");
3589 ast_module_user_remove(lu
);
3593 ast_module_user_remove(lu
);
3594 pbx_builtin_setvar_helper(chan
, "UPQMSTATUS", "NOTFOUND");
3598 ast_module_user_remove(lu
);
3599 pbx_builtin_setvar_helper(chan
, "UPQMSTATUS", "UNPAUSED");
3604 static int rqm_exec(struct ast_channel
*chan
, void *data
)
3607 struct ast_module_user
*lu
;
3608 char *parse
, *temppos
= NULL
;
3609 int priority_jump
= 0;
3610 AST_DECLARE_APP_ARGS(args
,
3611 AST_APP_ARG(queuename
);
3612 AST_APP_ARG(interface
);
3613 AST_APP_ARG(options
);
3617 if (ast_strlen_zero(data
)) {
3618 ast_log(LOG_WARNING
, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
3622 parse
= ast_strdupa(data
);
3624 AST_STANDARD_APP_ARGS(args
, parse
);
3626 lu
= ast_module_user_add(chan
);
3628 if (ast_strlen_zero(args
.interface
)) {
3629 args
.interface
= ast_strdupa(chan
->name
);
3630 temppos
= strrchr(args
.interface
, '-');
3636 if (strchr(args
.options
, 'j'))
3640 switch (remove_from_queue(args
.queuename
, args
.interface
)) {
3642 ast_queue_log(args
.queuename
, chan
->uniqueid
, args
.interface
, "REMOVEMEMBER", "%s", "");
3643 ast_log(LOG_NOTICE
, "Removed interface '%s' from queue '%s'\n", args
.interface
, args
.queuename
);
3644 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "REMOVED");
3648 ast_log(LOG_DEBUG
, "Unable to remove interface '%s' from queue '%s': Not there\n", args
.interface
, args
.queuename
);
3649 if (priority_jump
|| ast_opt_priority_jumping
)
3650 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
3651 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "NOTINQUEUE");
3654 case RES_NOSUCHQUEUE
:
3655 ast_log(LOG_WARNING
, "Unable to remove interface from queue '%s': No such queue\n", args
.queuename
);
3656 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "NOSUCHQUEUE");
3659 case RES_NOT_DYNAMIC
:
3660 ast_log(LOG_WARNING
, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args
.queuename
, args
.interface
);
3661 pbx_builtin_setvar_helper(chan
, "RQMSTATUS", "NOTDYNAMIC");
3666 ast_module_user_remove(lu
);
3671 static int aqm_exec(struct ast_channel
*chan
, void *data
)
3674 struct ast_module_user
*lu
;
3675 char *parse
, *temppos
= NULL
;
3676 int priority_jump
= 0;
3677 AST_DECLARE_APP_ARGS(args
,
3678 AST_APP_ARG(queuename
);
3679 AST_APP_ARG(interface
);
3680 AST_APP_ARG(penalty
);
3681 AST_APP_ARG(options
);
3682 AST_APP_ARG(membername
);
3686 if (ast_strlen_zero(data
)) {
3687 ast_log(LOG_WARNING
, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
3691 parse
= ast_strdupa(data
);
3693 AST_STANDARD_APP_ARGS(args
, parse
);
3695 lu
= ast_module_user_add(chan
);
3697 if (ast_strlen_zero(args
.interface
)) {
3698 args
.interface
= ast_strdupa(chan
->name
);
3699 temppos
= strrchr(args
.interface
, '-');
3704 if (!ast_strlen_zero(args
.penalty
)) {
3705 if ((sscanf(args
.penalty
, "%d", &penalty
) != 1) || penalty
< 0) {
3706 ast_log(LOG_WARNING
, "Penalty '%s' is invalid, must be an integer >= 0\n", args
.penalty
);
3712 if (strchr(args
.options
, 'j'))
3716 switch (add_to_queue(args
.queuename
, args
.interface
, args
.membername
, penalty
, 0, queue_persistent_members
)) {
3718 ast_queue_log(args
.queuename
, chan
->uniqueid
, args
.interface
, "ADDMEMBER", "%s", "");
3719 ast_log(LOG_NOTICE
, "Added interface '%s' to queue '%s'\n", args
.interface
, args
.queuename
);
3720 pbx_builtin_setvar_helper(chan
, "AQMSTATUS", "ADDED");
3724 ast_log(LOG_WARNING
, "Unable to add interface '%s' to queue '%s': Already there\n", args
.interface
, args
.queuename
);
3725 if (priority_jump
|| ast_opt_priority_jumping
)
3726 ast_goto_if_exists(chan
, chan
->context
, chan
->exten
, chan
->priority
+ 101);
3727 pbx_builtin_setvar_helper(chan
, "AQMSTATUS", "MEMBERALREADY");
3730 case RES_NOSUCHQUEUE
:
3731 ast_log(LOG_WARNING
, "Unable to add interface to queue '%s': No such queue\n", args
.queuename
);
3732 pbx_builtin_setvar_helper(chan
, "AQMSTATUS", "NOSUCHQUEUE");
3735 case RES_OUTOFMEMORY
:
3736 ast_log(LOG_ERROR
, "Out of memory adding member %s to queue %s\n", args
.interface
, args
.queuename
);
3740 ast_module_user_remove(lu
);
3745 static int ql_exec(struct ast_channel
*chan
, void *data
)
3747 struct ast_module_user
*u
;
3750 AST_DECLARE_APP_ARGS(args
,
3751 AST_APP_ARG(queuename
);
3752 AST_APP_ARG(uniqueid
);
3753 AST_APP_ARG(membername
);
3755 AST_APP_ARG(params
);
3758 if (ast_strlen_zero(data
)) {
3759 ast_log(LOG_WARNING
, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
3763 u
= ast_module_user_add(chan
);
3765 parse
= ast_strdupa(data
);
3767 AST_STANDARD_APP_ARGS(args
, parse
);
3769 if (ast_strlen_zero(args
.queuename
) || ast_strlen_zero(args
.uniqueid
)
3770 || ast_strlen_zero(args
.membername
) || ast_strlen_zero(args
.event
)) {
3771 ast_log(LOG_WARNING
, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
3772 ast_module_user_remove(u
);
3776 ast_queue_log(args
.queuename
, args
.uniqueid
, args
.membername
, args
.event
,
3777 "%s", args
.params
? args
.params
: "");
3779 ast_module_user_remove(u
);
3784 /*!\brief The starting point for all queue calls
3786 * The process involved here is to
3787 * 1. Parse the options specified in the call to Queue()
3789 * 3. Wait in a loop until it is our turn to try calling a queue member
3790 * 4. Attempt to call a queue member
3791 * 5. If 4. did not result in a bridged call, then check for between
3792 * call options such as periodic announcements etc.
3793 * 6. Try 4 again uless some condition (such as an expiration time) causes us to
3796 static int queue_exec(struct ast_channel
*chan
, void *data
)
3800 struct ast_module_user
*lu
;
3801 const char *user_priority
;
3802 const char *max_penalty_str
;
3805 enum queue_result reason
= QUEUE_UNKNOWN
;
3806 /* whether to exit Queue application after the timeout hits */
3810 AST_DECLARE_APP_ARGS(args
,
3811 AST_APP_ARG(queuename
);
3812 AST_APP_ARG(options
);
3814 AST_APP_ARG(announceoverride
);
3815 AST_APP_ARG(queuetimeoutstr
);
3818 /* Our queue entry */
3819 struct queue_ent qe
;
3821 if (ast_strlen_zero(data
)) {
3822 ast_log(LOG_WARNING
, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
3826 parse
= ast_strdupa(data
);
3827 AST_STANDARD_APP_ARGS(args
, parse
);
3829 lu
= ast_module_user_add(chan
);
3831 /* Setup our queue entry */
3832 memset(&qe
, 0, sizeof(qe
));
3833 qe
.start
= time(NULL
);
3835 /* set the expire time based on the supplied timeout; */
3836 if (!ast_strlen_zero(args
.queuetimeoutstr
))
3837 qe
.expire
= qe
.start
+ atoi(args
.queuetimeoutstr
);
3841 /* Get the priority from the variable ${QUEUE_PRIO} */
3842 user_priority
= pbx_builtin_getvar_helper(chan
, "QUEUE_PRIO");
3843 if (user_priority
) {
3844 if (sscanf(user_priority
, "%d", &prio
) == 1) {
3846 ast_log(LOG_DEBUG
, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
3849 ast_log(LOG_WARNING
, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
3850 user_priority
, chan
->name
);
3854 if (option_debug
> 2)
3855 ast_log(LOG_DEBUG
, "NO QUEUE_PRIO variable found. Using default.\n");
3859 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
3860 if ((max_penalty_str
= pbx_builtin_getvar_helper(chan
, "QUEUE_MAX_PENALTY"))) {
3861 if (sscanf(max_penalty_str
, "%d", &max_penalty
) == 1) {
3863 ast_log(LOG_DEBUG
, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
3864 chan
->name
, max_penalty
);
3866 ast_log(LOG_WARNING
, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
3867 max_penalty_str
, chan
->name
);
3874 if (args
.options
&& (strchr(args
.options
, 'r')))
3878 ast_log(LOG_DEBUG
, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
3879 args
.queuename
, args
.options
, args
.url
, args
.announceoverride
, (long)qe
.expire
, prio
);
3883 qe
.max_penalty
= max_penalty
;
3884 qe
.last_pos_said
= 0;
3886 qe
.last_periodic_announce_time
= time(NULL
);
3887 qe
.last_periodic_announce_sound
= 0;
3888 qe
.valid_digits
= 0;
3889 if (!join_queue(args
.queuename
, &qe
, &reason
)) {
3890 int makeannouncement
= 0;
3892 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args
.url
, ""),
3893 S_OR(chan
->cid
.cid_num
, ""));
3896 ast_indicate(chan
, AST_CONTROL_RINGING
);
3898 ast_moh_start(chan
, qe
.moh
, NULL
);
3901 /* This is the wait loop for callers 2 through maxlen */
3902 res
= wait_our_turn(&qe
, ringing
, &reason
);
3907 /* This is the wait loop for the head caller*/
3908 /* To exit, they may get their call answered; */
3909 /* they may dial a digit from the queue context; */
3910 /* or, they may timeout. */
3912 enum queue_member_status stat
;
3914 /* Leave if we have exceeded our queuetimeout */
3915 if (qe
.expire
&& (time(NULL
) > qe
.expire
)) {
3916 record_abandoned(&qe
);
3917 reason
= QUEUE_TIMEOUT
;
3919 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHTIMEOUT", "%d", qe
.pos
);
3923 if (makeannouncement
) {
3924 /* Make a position announcement, if enabled */
3925 if (qe
.parent
->announcefrequency
&& !ringing
)
3926 if ((res
= say_position(&qe
)))
3930 makeannouncement
= 1;
3932 /* Make a periodic announcement, if enabled */
3933 if (qe
.parent
->periodicannouncefrequency
&& !ringing
)
3934 if ((res
= say_periodic_announcement(&qe
)))
3937 /* Try calling all queue members for 'timeout' seconds */
3938 res
= try_calling(&qe
, args
.options
, args
.announceoverride
, args
.url
, &tries
, &noption
, args
.agi
);
3942 stat
= get_member_status(qe
.parent
, qe
.max_penalty
);
3944 /* exit after 'timeout' cycle if 'n' option enabled */
3945 if (noption
&& tries
>= qe
.parent
->membercount
) {
3946 if (option_verbose
> 2)
3947 ast_verbose(VERBOSE_PREFIX_3
"Exiting on time-out cycle\n");
3948 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHTIMEOUT", "%d", qe
.pos
);
3949 record_abandoned(&qe
);
3950 reason
= QUEUE_TIMEOUT
;
3955 /* leave the queue if no agents, if enabled */
3956 if (qe
.parent
->leavewhenempty
&& (stat
== QUEUE_NO_MEMBERS
)) {
3957 record_abandoned(&qe
);
3958 reason
= QUEUE_LEAVEEMPTY
;
3959 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITEMPTY", "%d|%d|%ld", qe
.pos
, qe
.opos
, (long)(time(NULL
) - qe
.start
));
3964 /* leave the queue if no reachable agents, if enabled */
3965 if ((qe
.parent
->leavewhenempty
== QUEUE_EMPTY_STRICT
) && (stat
== QUEUE_NO_REACHABLE_MEMBERS
)) {
3966 record_abandoned(&qe
);
3967 reason
= QUEUE_LEAVEUNAVAIL
;
3968 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITEMPTY", "%d|%d|%ld", qe
.pos
, qe
.opos
, (long)(time(NULL
) - qe
.start
));
3973 /* Leave if we have exceeded our queuetimeout */
3974 if (qe
.expire
&& (time(NULL
) > qe
.expire
)) {
3975 record_abandoned(&qe
);
3976 reason
= QUEUE_TIMEOUT
;
3978 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHTIMEOUT", "%d", qe
.pos
);
3982 /* If using dynamic realtime members, we should regenerate the member list for this queue */
3983 update_realtime_members(qe
.parent
);
3985 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3986 res
= wait_a_bit(&qe
);
3991 /* Since this is a priority queue and
3992 * it is not sure that we are still at the head
3993 * of the queue, go and check for our turn again.
3995 if (!is_our_turn(&qe
)) {
3997 ast_log(LOG_DEBUG
, "Darn priorities, going back in queue (%s)!\n",
4007 record_abandoned(&qe
);
4008 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "ABANDON",
4009 "%d|%d|%ld", qe
.pos
, qe
.opos
,
4010 (long) time(NULL
) - qe
.start
);
4013 } else if (qe
.valid_digits
) {
4014 ast_queue_log(args
.queuename
, chan
->uniqueid
, "NONE", "EXITWITHKEY",
4015 "%s|%d", qe
.digits
, qe
.pos
);
4019 /* Don't allow return code > 0 */
4020 if (res
>= 0 && res
!= AST_PBX_KEEPALIVE
) {
4023 ast_indicate(chan
, -1);
4027 ast_stopstream(chan
);
4030 if (reason
!= QUEUE_UNKNOWN
)
4031 set_queue_result(chan
, reason
);
4033 ast_log(LOG_WARNING
, "Unable to join queue '%s'\n", args
.queuename
);
4034 set_queue_result(chan
, reason
);
4037 ast_module_user_remove(lu
);
4042 static int queue_function_qac(struct ast_channel
*chan
, char *cmd
, char *data
, char *buf
, size_t len
)
4045 struct call_queue
*q
;
4046 struct ast_module_user
*lu
;
4048 struct ao2_iterator mem_iter
;
4052 if (ast_strlen_zero(data
)) {
4053 ast_log(LOG_ERROR
, "%s requires an argument: queuename\n", cmd
);
4057 lu
= ast_module_user_add(chan
);
4059 if ((q
= load_realtime_queue(data
))) {
4060 ast_mutex_lock(&q
->lock
);
4061 mem_iter
= ao2_iterator_init(q
->members
, 0);
4062 while ((m
= ao2_iterator_next(&mem_iter
))) {
4063 /* Count the agents who are logged in and presently answering calls */
4064 if ((m
->status
!= AST_DEVICE_UNAVAILABLE
) && (m
->status
!= AST_DEVICE_INVALID
)) {
4069 ast_mutex_unlock(&q
->lock
);
4071 ast_log(LOG_WARNING
, "queue %s was not found\n", data
);
4073 snprintf(buf
, len
, "%d", count
);
4074 ast_module_user_remove(lu
);
4079 static int queue_function_queuewaitingcount(struct ast_channel
*chan
, char *cmd
, char *data
, char *buf
, size_t len
)
4082 struct call_queue
*q
;
4083 struct ast_module_user
*lu
;
4084 struct ast_variable
*var
= NULL
;
4088 if (ast_strlen_zero(data
)) {
4089 ast_log(LOG_ERROR
, "%s requires an argument: queuename\n", cmd
);
4093 lu
= ast_module_user_add(chan
);
4095 AST_LIST_LOCK(&queues
);
4096 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4097 if (!strcasecmp(q
->name
, data
)) {
4098 ast_mutex_lock(&q
->lock
);
4102 AST_LIST_UNLOCK(&queues
);
4106 ast_mutex_unlock(&q
->lock
);
4107 } else if ((var
= ast_load_realtime("queues", "name", data
, NULL
))) {
4108 /* if the queue is realtime but was not found in memory, this
4109 * means that the queue had been deleted from memory since it was
4110 * "dead." This means it has a 0 waiting count
4113 ast_variables_destroy(var
);
4115 ast_log(LOG_WARNING
, "queue %s was not found\n", data
);
4117 snprintf(buf
, len
, "%d", count
);
4118 ast_module_user_remove(lu
);
4122 static int queue_function_queuememberlist(struct ast_channel
*chan
, char *cmd
, char *data
, char *buf
, size_t len
)
4124 struct ast_module_user
*u
;
4125 struct call_queue
*q
;
4128 /* Ensure an otherwise empty list doesn't return garbage */
4131 if (ast_strlen_zero(data
)) {
4132 ast_log(LOG_ERROR
, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
4136 u
= ast_module_user_add(chan
);
4138 AST_LIST_LOCK(&queues
);
4139 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4140 if (!strcasecmp(q
->name
, data
)) {
4141 ast_mutex_lock(&q
->lock
);
4145 AST_LIST_UNLOCK(&queues
);
4148 int buflen
= 0, count
= 0;
4149 struct ao2_iterator mem_iter
= ao2_iterator_init(q
->members
, 0);
4151 while ((m
= ao2_iterator_next(&mem_iter
))) {
4152 /* strcat() is always faster than printf() */
4154 strncat(buf
+ buflen
, ",", len
- buflen
- 1);
4157 strncat(buf
+ buflen
, m
->membername
, len
- buflen
- 1);
4158 buflen
+= strlen(m
->membername
);
4159 /* Safeguard against overflow (negative length) */
4160 if (buflen
>= len
- 2) {
4162 ast_log(LOG_WARNING
, "Truncating list\n");
4167 ast_mutex_unlock(&q
->lock
);
4169 ast_log(LOG_WARNING
, "queue %s was not found\n", data
);
4171 /* We should already be terminated, but let's make sure. */
4172 buf
[len
- 1] = '\0';
4173 ast_module_user_remove(u
);
4178 static struct ast_custom_function queueagentcount_function
= {
4179 .name
= "QUEUEAGENTCOUNT",
4180 .synopsis
= "Count number of agents answering a queue",
4181 .syntax
= "QUEUEAGENTCOUNT(<queuename>)",
4183 "Returns the number of members currently associated with the specified queue.\n"
4184 "This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
4185 .read
= queue_function_qac
,
4188 static struct ast_custom_function queuemembercount_function
= {
4189 .name
= "QUEUE_MEMBER_COUNT",
4190 .synopsis
= "Count number of members answering a queue",
4191 .syntax
= "QUEUE_MEMBER_COUNT(<queuename>)",
4193 "Returns the number of members currently associated with the specified queue.\n",
4194 .read
= queue_function_qac
,
4197 static struct ast_custom_function queuewaitingcount_function
= {
4198 .name
= "QUEUE_WAITING_COUNT",
4199 .synopsis
= "Count number of calls currently waiting in a queue",
4200 .syntax
= "QUEUE_WAITING_COUNT(<queuename>)",
4202 "Returns the number of callers currently waiting in the specified queue.\n",
4203 .read
= queue_function_queuewaitingcount
,
4206 static struct ast_custom_function queuememberlist_function
= {
4207 .name
= "QUEUE_MEMBER_LIST",
4208 .synopsis
= "Returns a list of interfaces on a queue",
4209 .syntax
= "QUEUE_MEMBER_LIST(<queuename>)",
4211 "Returns a comma-separated list of members associated with the specified queue.\n",
4212 .read
= queue_function_queuememberlist
,
4215 static int reload_queues(void)
4217 struct call_queue
*q
;
4218 struct ast_config
*cfg
;
4220 struct ast_variable
*var
;
4221 struct member
*cur
, *newm
;
4222 struct ao2_iterator mem_iter
;
4224 const char *general_val
= NULL
;
4227 char *membername
= NULL
;
4229 AST_DECLARE_APP_ARGS(args
,
4230 AST_APP_ARG(interface
);
4231 AST_APP_ARG(penalty
);
4232 AST_APP_ARG(membername
);
4235 if (!(cfg
= ast_config_load("queues.conf"))) {
4236 ast_log(LOG_NOTICE
, "No call queueing config file (queues.conf), so no call queues\n");
4239 AST_LIST_LOCK(&queues
);
4241 /* Mark all non-realtime queues as dead for the moment */
4242 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4249 /* Chug through config file */
4251 while ((cat
= ast_category_browse(cfg
, cat
)) ) {
4252 if (!strcasecmp(cat
, "general")) {
4253 /* Initialize global settings */
4254 queue_persistent_members
= 0;
4255 if ((general_val
= ast_variable_retrieve(cfg
, "general", "persistentmembers")))
4256 queue_persistent_members
= ast_true(general_val
);
4257 autofill_default
= 0;
4258 if ((general_val
= ast_variable_retrieve(cfg
, "general", "autofill")))
4259 autofill_default
= ast_true(general_val
);
4260 montype_default
= 0;
4261 if ((general_val
= ast_variable_retrieve(cfg
, "general", "monitor-type")))
4262 if (!strcasecmp(general_val
, "mixmonitor"))
4263 montype_default
= 1;
4264 } else { /* Define queue */
4265 /* Look for an existing one */
4266 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4267 if (!strcmp(q
->name
, cat
))
4272 if (!(q
= alloc_queue(cat
))) {
4273 /* TODO: Handle memory allocation failure */
4280 ast_mutex_lock(&q
->lock
);
4281 /* Check if a queue with this name already exists */
4283 ast_log(LOG_WARNING
, "Queue '%s' already defined! Skipping!\n", cat
);
4285 ast_mutex_unlock(&q
->lock
);
4288 /* Re-initialize the queue, and clear statistics */
4291 mem_iter
= ao2_iterator_init(q
->members
, 0);
4292 while ((cur
= ao2_iterator_next(&mem_iter
))) {
4293 if (!cur
->dynamic
) {
4298 for (var
= ast_variable_browse(cfg
, cat
); var
; var
= var
->next
) {
4299 if (!strcasecmp(var
->name
, "member")) {
4300 struct member tmpmem
;
4303 /* Add a new member */
4304 ast_copy_string(parse
, var
->value
, sizeof(parse
));
4306 AST_NONSTANDARD_APP_ARGS(args
, parse
, ',');
4308 interface
= args
.interface
;
4309 if (!ast_strlen_zero(args
.penalty
)) {
4311 while (*tmp
&& *tmp
< 33) tmp
++;
4312 penalty
= atoi(tmp
);
4319 if (!ast_strlen_zero(args
.membername
)) {
4320 membername
= args
.membername
;
4321 while (*membername
&& *membername
< 33) membername
++;
4324 /* Find the old position in the list */
4325 ast_copy_string(tmpmem
.interface
, interface
, sizeof(tmpmem
.interface
));
4326 cur
= ao2_find(q
->members
, &tmpmem
, OBJ_POINTER
| OBJ_UNLINK
);
4328 newm
= create_queue_member(interface
, membername
, penalty
, cur
? cur
->paused
: 0);
4329 ao2_link(q
->members
, newm
);
4336 /* Add them to the master int list if necessary */
4337 add_to_interfaces(interface
);
4341 queue_set_param(q
, var
->name
, var
->value
, var
->lineno
, 1);
4345 /* Free remaining members marked as delme */
4346 mem_iter
= ao2_iterator_init(q
->members
, 0);
4347 while ((cur
= ao2_iterator_next(&mem_iter
))) {
4354 ao2_unlink(q
->members
, cur
);
4355 remove_from_interfaces(cur
->interface
);
4359 if (q
->strategy
== QUEUE_STRATEGY_ROUNDROBIN
)
4363 AST_LIST_INSERT_HEAD(&queues
, q
, list
);
4365 ast_mutex_unlock(&q
->lock
);
4369 ast_config_destroy(cfg
);
4370 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues
, q
, list
) {
4372 AST_LIST_REMOVE_CURRENT(&queues
, list
);
4376 ast_log(LOG_DEBUG
, "XXX Leaking a little memory :( XXX\n");
4378 ast_mutex_lock(&q
->lock
);
4379 mem_iter
= ao2_iterator_init(q
->members
, 0);
4380 while ((cur
= ao2_iterator_next(&mem_iter
))) {
4383 cur
->status
= ast_device_state(cur
->interface
);
4386 ast_mutex_unlock(&q
->lock
);
4389 AST_LIST_TRAVERSE_SAFE_END
;
4390 AST_LIST_UNLOCK(&queues
);
4394 static int __queues_show(struct mansession
*s
, int manager
, int fd
, int argc
, char **argv
)
4396 struct call_queue
*q
;
4397 struct queue_ent
*qe
;
4399 int pos
, queue_show
;
4405 char *term
= manager
? "\r\n" : "\n";
4406 struct ao2_iterator mem_iter
;
4414 return RESULT_SHOWUSAGE
;
4416 /* We only want to load realtime queues when a specific queue is asked for. */
4418 load_realtime_queue(argv
[2]);
4419 } else if (ast_check_realtime("queues")) {
4420 struct ast_config
*cfg
= ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL
);
4423 for (queuename
= ast_category_browse(cfg
, NULL
); !ast_strlen_zero(queuename
); queuename
= ast_category_browse(cfg
, queuename
)) {
4424 load_realtime_queue(queuename
);
4426 ast_config_destroy(cfg
);
4430 AST_LIST_LOCK(&queues
);
4431 if (AST_LIST_EMPTY(&queues
)) {
4432 AST_LIST_UNLOCK(&queues
);
4435 astman_append(s
, "No such queue: %s.%s",argv
[2], term
);
4437 ast_cli(fd
, "No such queue: %s.%s",argv
[2], term
);
4440 astman_append(s
, "No queues.%s", term
);
4442 ast_cli(fd
, "No queues.%s", term
);
4444 return RESULT_SUCCESS
;
4446 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4447 ast_mutex_lock(&q
->lock
);
4449 if (strcasecmp(q
->name
, argv
[2]) != 0) {
4450 ast_mutex_unlock(&q
->lock
);
4451 if (!AST_LIST_NEXT(q
, list
)) {
4452 ast_cli(fd
, "No such queue: %s.%s",argv
[2], term
);
4460 max_left
= sizeof(max_buf
);
4462 ast_build_string(&max
, &max_left
, "%d", q
->maxlen
);
4464 ast_build_string(&max
, &max_left
, "unlimited");
4466 if (q
->callscompleted
> 0)
4467 sl
= 100 * ((float) q
->callscompletedinsl
/ (float) q
->callscompleted
);
4469 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",
4470 q
->name
, q
->count
, max_buf
, int2strat(q
->strategy
), q
->holdtime
, q
->weight
,
4471 q
->callscompleted
, q
->callsabandoned
,sl
,q
->servicelevel
, term
);
4473 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",
4474 q
->name
, q
->count
, max_buf
, int2strat(q
->strategy
), q
->holdtime
, q
->weight
, q
->callscompleted
, q
->callsabandoned
,sl
,q
->servicelevel
, term
);
4475 if (ao2_container_count(q
->members
)) {
4477 astman_append(s
, " Members: %s", term
);
4479 ast_cli(fd
, " Members: %s", term
);
4480 mem_iter
= ao2_iterator_init(q
->members
, 0);
4481 while ((mem
= ao2_iterator_next(&mem_iter
))) {
4484 max_left
= sizeof(max_buf
);
4485 if (strcasecmp(mem
->membername
, mem
->interface
)) {
4486 ast_build_string(&max
, &max_left
, " (%s)", mem
->interface
);
4489 ast_build_string(&max
, &max_left
, " with penalty %d", mem
->penalty
);
4491 ast_build_string(&max
, &max_left
, " (dynamic)");
4493 ast_build_string(&max
, &max_left
, " (realtime)");
4495 ast_build_string(&max
, &max_left
, " (paused)");
4496 ast_build_string(&max
, &max_left
, " (%s)", devstate2str(mem
->status
));
4498 ast_build_string(&max
, &max_left
, " has taken %d calls (last was %ld secs ago)",
4499 mem
->calls
, (long) (time(NULL
) - mem
->lastcall
));
4501 ast_build_string(&max
, &max_left
, " has taken no calls yet");
4503 astman_append(s
, " %s%s%s", mem
->membername
, max_buf
, term
);
4505 ast_cli(fd
, " %s%s%s", mem
->membername
, max_buf
, term
);
4509 astman_append(s
, " No Members%s", term
);
4511 ast_cli(fd
, " No Members%s", term
);
4515 astman_append(s
, " Callers: %s", term
);
4517 ast_cli(fd
, " Callers: %s", term
);
4518 for (qe
= q
->head
; qe
; qe
= qe
->next
) {
4520 astman_append(s
, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
4521 pos
++, qe
->chan
->name
, (long) (now
- qe
->start
) / 60,
4522 (long) (now
- qe
->start
) % 60, qe
->prio
, term
);
4524 ast_cli(fd
, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos
++,
4525 qe
->chan
->name
, (long) (now
- qe
->start
) / 60,
4526 (long) (now
- qe
->start
) % 60, qe
->prio
, term
);
4529 astman_append(s
, " No Callers%s", term
);
4531 ast_cli(fd
, " No Callers%s", term
);
4533 astman_append(s
, "%s", term
);
4535 ast_cli(fd
, "%s", term
);
4536 ast_mutex_unlock(&q
->lock
);
4540 AST_LIST_UNLOCK(&queues
);
4541 return RESULT_SUCCESS
;
4544 static int queue_show(int fd
, int argc
, char **argv
)
4546 return __queues_show(NULL
, 0, fd
, argc
, argv
);
4549 static char *complete_queue(const char *line
, const char *word
, int pos
, int state
)
4551 struct call_queue
*q
;
4554 int wordlen
= strlen(word
);
4556 AST_LIST_LOCK(&queues
);
4557 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4558 if (!strncasecmp(word
, q
->name
, wordlen
) && ++which
> state
) {
4559 ret
= ast_strdup(q
->name
);
4563 AST_LIST_UNLOCK(&queues
);
4568 static char *complete_queue_show(const char *line
, const char *word
, int pos
, int state
)
4571 return complete_queue(line
, word
, pos
, state
);
4575 /*!\brief callback to display queues status in manager
4576 \addtogroup Group_AMI
4578 static int manager_queues_show(struct mansession
*s
, const struct message
*m
)
4580 char *a
[] = { "queue", "show" };
4582 __queues_show(s
, 1, -1, 2, a
);
4583 astman_append(s
, "\r\n\r\n"); /* Properly terminate Manager output */
4585 return RESULT_SUCCESS
;
4588 /* Dump queue status */
4589 static int manager_queues_status(struct mansession
*s
, const struct message
*m
)
4593 const char *id
= astman_get_header(m
,"ActionID");
4594 const char *queuefilter
= astman_get_header(m
,"Queue");
4595 const char *memberfilter
= astman_get_header(m
,"Member");
4596 char idText
[256] = "";
4597 struct call_queue
*q
;
4598 struct queue_ent
*qe
;
4601 struct ao2_iterator mem_iter
;
4603 astman_send_ack(s
, m
, "Queue status will follow");
4605 AST_LIST_LOCK(&queues
);
4606 if (!ast_strlen_zero(id
))
4607 snprintf(idText
, sizeof(idText
), "ActionID: %s\r\n", id
);
4609 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4610 ast_mutex_lock(&q
->lock
);
4612 /* List queue properties */
4613 if (ast_strlen_zero(queuefilter
) || !strcmp(q
->name
, queuefilter
)) {
4614 sl
= ((q
->callscompleted
> 0) ? 100 * ((float)q
->callscompletedinsl
/ (float)q
->callscompleted
) : 0);
4615 astman_append(s
, "Event: QueueParams\r\n"
4622 "ServiceLevel: %d\r\n"
4623 "ServicelevelPerf: %2.1f\r\n"
4627 q
->name
, q
->maxlen
, q
->count
, q
->holdtime
, q
->callscompleted
,
4628 q
->callsabandoned
, q
->servicelevel
, sl
, q
->weight
, idText
);
4629 /* List Queue Members */
4630 mem_iter
= ao2_iterator_init(q
->members
, 0);
4631 while ((mem
= ao2_iterator_next(&mem_iter
))) {
4632 if (ast_strlen_zero(memberfilter
) || !strcmp(mem
->interface
, memberfilter
)) {
4633 astman_append(s
, "Event: QueueMember\r\n"
4637 "Membership: %s\r\n"
4639 "CallsTaken: %d\r\n"
4645 q
->name
, mem
->membername
, mem
->interface
, mem
->dynamic
? "dynamic" : "static",
4646 mem
->penalty
, mem
->calls
, (int)mem
->lastcall
, mem
->status
, mem
->paused
, idText
);
4650 /* List Queue Entries */
4652 for (qe
= q
->head
; qe
; qe
= qe
->next
) {
4653 astman_append(s
, "Event: QueueEntry\r\n"
4658 "CallerIDName: %s\r\n"
4662 q
->name
, pos
++, qe
->chan
->name
,
4663 S_OR(qe
->chan
->cid
.cid_num
, "unknown"),
4664 S_OR(qe
->chan
->cid
.cid_name
, "unknown"),
4665 (long) (now
- qe
->start
), idText
);
4668 ast_mutex_unlock(&q
->lock
);
4672 "Event: QueueStatusComplete\r\n"
4676 AST_LIST_UNLOCK(&queues
);
4679 return RESULT_SUCCESS
;
4682 static int manager_add_queue_member(struct mansession
*s
, const struct message
*m
)
4684 const char *queuename
, *interface
, *penalty_s
, *paused_s
, *membername
;
4685 int paused
, penalty
= 0;
4687 queuename
= astman_get_header(m
, "Queue");
4688 interface
= astman_get_header(m
, "Interface");
4689 penalty_s
= astman_get_header(m
, "Penalty");
4690 paused_s
= astman_get_header(m
, "Paused");
4691 membername
= astman_get_header(m
, "MemberName");
4693 if (ast_strlen_zero(queuename
)) {
4694 astman_send_error(s
, m
, "'Queue' not specified.");
4698 if (ast_strlen_zero(interface
)) {
4699 astman_send_error(s
, m
, "'Interface' not specified.");
4703 if (ast_strlen_zero(penalty_s
))
4705 else if (sscanf(penalty_s
, "%d", &penalty
) != 1 || penalty
< 0)
4708 if (ast_strlen_zero(paused_s
))
4711 paused
= abs(ast_true(paused_s
));
4713 switch (add_to_queue(queuename
, interface
, membername
, penalty
, paused
, queue_persistent_members
)) {
4715 ast_queue_log(queuename
, "MANAGER", interface
, "ADDMEMBER", "%s", "");
4716 astman_send_ack(s
, m
, "Added interface to queue");
4719 astman_send_error(s
, m
, "Unable to add interface: Already there");
4721 case RES_NOSUCHQUEUE
:
4722 astman_send_error(s
, m
, "Unable to add interface to queue: No such queue");
4724 case RES_OUTOFMEMORY
:
4725 astman_send_error(s
, m
, "Out of memory");
4732 static int manager_remove_queue_member(struct mansession
*s
, const struct message
*m
)
4734 const char *queuename
, *interface
;
4736 queuename
= astman_get_header(m
, "Queue");
4737 interface
= astman_get_header(m
, "Interface");
4739 if (ast_strlen_zero(queuename
) || ast_strlen_zero(interface
)) {
4740 astman_send_error(s
, m
, "Need 'Queue' and 'Interface' parameters.");
4744 switch (remove_from_queue(queuename
, interface
)) {
4746 ast_queue_log(queuename
, "MANAGER", interface
, "REMOVEMEMBER", "%s", "");
4747 astman_send_ack(s
, m
, "Removed interface from queue");
4750 astman_send_error(s
, m
, "Unable to remove interface: Not there");
4752 case RES_NOSUCHQUEUE
:
4753 astman_send_error(s
, m
, "Unable to remove interface from queue: No such queue");
4755 case RES_OUTOFMEMORY
:
4756 astman_send_error(s
, m
, "Out of memory");
4758 case RES_NOT_DYNAMIC
:
4759 astman_send_error(s
, m
, "Member not dynamic");
4766 static int manager_pause_queue_member(struct mansession
*s
, const struct message
*m
)
4768 const char *queuename
, *interface
, *paused_s
;
4771 interface
= astman_get_header(m
, "Interface");
4772 paused_s
= astman_get_header(m
, "Paused");
4773 queuename
= astman_get_header(m
, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
4775 if (ast_strlen_zero(interface
) || ast_strlen_zero(paused_s
)) {
4776 astman_send_error(s
, m
, "Need 'Interface' and 'Paused' parameters.");
4780 paused
= abs(ast_true(paused_s
));
4782 if (set_member_paused(queuename
, interface
, paused
))
4783 astman_send_error(s
, m
, "Interface not found");
4785 astman_send_ack(s
, m
, paused
? "Interface paused successfully" : "Interface unpaused successfully");
4789 static int handle_queue_add_member(int fd
, int argc
, char *argv
[])
4791 char *queuename
, *interface
, *membername
= NULL
;
4794 if ((argc
!= 6) && (argc
!= 8) && (argc
!= 10)) {
4795 return RESULT_SHOWUSAGE
;
4796 } else if (strcmp(argv
[4], "to")) {
4797 return RESULT_SHOWUSAGE
;
4798 } else if ((argc
== 8) && strcmp(argv
[6], "penalty")) {
4799 return RESULT_SHOWUSAGE
;
4800 } else if ((argc
== 10) && strcmp(argv
[8], "as")) {
4801 return RESULT_SHOWUSAGE
;
4804 queuename
= argv
[5];
4805 interface
= argv
[3];
4807 if (sscanf(argv
[7], "%d", &penalty
) == 1) {
4809 ast_cli(fd
, "Penalty must be >= 0\n");
4813 ast_cli(fd
, "Penalty must be an integer >= 0\n");
4821 membername
= argv
[9];
4824 switch (add_to_queue(queuename
, interface
, membername
, penalty
, 0, queue_persistent_members
)) {
4826 ast_queue_log(queuename
, "CLI", interface
, "ADDMEMBER", "%s", "");
4827 ast_cli(fd
, "Added interface '%s' to queue '%s'\n", interface
, queuename
);
4828 return RESULT_SUCCESS
;
4830 ast_cli(fd
, "Unable to add interface '%s' to queue '%s': Already there\n", interface
, queuename
);
4831 return RESULT_FAILURE
;
4832 case RES_NOSUCHQUEUE
:
4833 ast_cli(fd
, "Unable to add interface to queue '%s': No such queue\n", queuename
);
4834 return RESULT_FAILURE
;
4835 case RES_OUTOFMEMORY
:
4836 ast_cli(fd
, "Out of memory\n");
4837 return RESULT_FAILURE
;
4839 return RESULT_FAILURE
;
4843 static char *complete_queue_add_member(const char *line
, const char *word
, int pos
, int state
)
4845 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
4847 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
4849 case 4: /* only one possible match, "to" */
4850 return state
== 0 ? ast_strdup("to") : NULL
;
4851 case 5: /* <queue> */
4852 return complete_queue(line
, word
, pos
, state
);
4853 case 6: /* only one possible match, "penalty" */
4854 return state
== 0 ? ast_strdup("penalty") : NULL
;
4856 if (state
< 100) { /* 0-99 */
4858 if ((num
= ast_malloc(3))) {
4859 sprintf(num
, "%d", state
);
4865 case 8: /* only one possible match, "as" */
4866 return state
== 0 ? ast_strdup("as") : NULL
;
4867 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
4874 static int handle_queue_remove_member(int fd
, int argc
, char *argv
[])
4876 char *queuename
, *interface
;
4879 return RESULT_SHOWUSAGE
;
4880 } else if (strcmp(argv
[4], "from")) {
4881 return RESULT_SHOWUSAGE
;
4884 queuename
= argv
[5];
4885 interface
= argv
[3];
4887 switch (remove_from_queue(queuename
, interface
)) {
4889 ast_queue_log(queuename
, "CLI", interface
, "REMOVEMEMBER", "%s", "");
4890 ast_cli(fd
, "Removed interface '%s' from queue '%s'\n", interface
, queuename
);
4891 return RESULT_SUCCESS
;
4893 ast_cli(fd
, "Unable to remove interface '%s' from queue '%s': Not there\n", interface
, queuename
);
4894 return RESULT_FAILURE
;
4895 case RES_NOSUCHQUEUE
:
4896 ast_cli(fd
, "Unable to remove interface from queue '%s': No such queue\n", queuename
);
4897 return RESULT_FAILURE
;
4898 case RES_OUTOFMEMORY
:
4899 ast_cli(fd
, "Out of memory\n");
4900 return RESULT_FAILURE
;
4901 case RES_NOT_DYNAMIC
:
4902 ast_cli(fd
, "Member not dynamic\n");
4903 return RESULT_FAILURE
;
4905 return RESULT_FAILURE
;
4909 static char *complete_queue_remove_member(const char *line
, const char *word
, int pos
, int state
)
4912 struct call_queue
*q
;
4914 struct ao2_iterator mem_iter
;
4916 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
4917 if (pos
> 5 || pos
< 3)
4919 if (pos
== 4) /* only one possible match, 'from' */
4920 return state
== 0 ? ast_strdup("from") : NULL
;
4922 if (pos
== 5) /* No need to duplicate code */
4923 return complete_queue(line
, word
, pos
, state
);
4925 /* here is the case for 3, <member> */
4926 if (!AST_LIST_EMPTY(&queues
)) { /* XXX unnecessary ? the traverse does that for us */
4927 AST_LIST_TRAVERSE(&queues
, q
, list
) {
4928 ast_mutex_lock(&q
->lock
);
4929 mem_iter
= ao2_iterator_init(q
->members
, 0);
4930 while ((m
= ao2_iterator_next(&mem_iter
))) {
4931 if (++which
> state
) {
4933 ast_mutex_unlock(&q
->lock
);
4934 tmp
= ast_strdup(m
->interface
);
4940 ast_mutex_unlock(&q
->lock
);
4947 static char queue_show_usage
[] =
4948 "Usage: queue show\n"
4949 " Provides summary information on a specified queue.\n";
4951 static char qam_cmd_usage
[] =
4952 "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
4954 static char qrm_cmd_usage
[] =
4955 "Usage: queue remove member <channel> from <queue>\n";
4957 static struct ast_cli_entry cli_show_queue_deprecated
= {
4958 { "show", "queue", NULL
},
4960 NULL
, complete_queue_show
};
4962 static struct ast_cli_entry cli_add_queue_member_deprecated
= {
4963 { "add", "queue", "member", NULL
},
4964 handle_queue_add_member
, NULL
,
4965 NULL
, complete_queue_add_member
};
4967 static struct ast_cli_entry cli_remove_queue_member_deprecated
= {
4968 { "remove", "queue", "member", NULL
},
4969 handle_queue_remove_member
, NULL
,
4970 NULL
, complete_queue_remove_member
};
4972 static struct ast_cli_entry cli_queue
[] = {
4974 { { "show", "queues", NULL
},
4978 { { "queue", "show", NULL
},
4979 queue_show
, "Show status of a specified queue",
4980 queue_show_usage
, complete_queue_show
, &cli_show_queue_deprecated
},
4982 { { "queue", "add", "member", NULL
},
4983 handle_queue_add_member
, "Add a channel to a specified queue",
4984 qam_cmd_usage
, complete_queue_add_member
, &cli_add_queue_member_deprecated
},
4986 { { "queue", "remove", "member", NULL
},
4987 handle_queue_remove_member
, "Removes a channel from a specified queue",
4988 qrm_cmd_usage
, complete_queue_remove_member
, &cli_remove_queue_member_deprecated
},
4991 static int unload_module(void)
4995 if (device_state
.thread
!= AST_PTHREADT_NULL
) {
4996 device_state
.stop
= 1;
4997 ast_mutex_lock(&device_state
.lock
);
4998 ast_cond_signal(&device_state
.cond
);
4999 ast_mutex_unlock(&device_state
.lock
);
5000 pthread_join(device_state
.thread
, NULL
);
5003 ast_cli_unregister_multiple(cli_queue
, sizeof(cli_queue
) / sizeof(struct ast_cli_entry
));
5004 res
= ast_manager_unregister("QueueStatus");
5005 res
|= ast_manager_unregister("Queues");
5006 res
|= ast_manager_unregister("QueueStatus");
5007 res
|= ast_manager_unregister("QueueAdd");
5008 res
|= ast_manager_unregister("QueueRemove");
5009 res
|= ast_manager_unregister("QueuePause");
5010 res
|= ast_unregister_application(app_aqm
);
5011 res
|= ast_unregister_application(app_rqm
);
5012 res
|= ast_unregister_application(app_pqm
);
5013 res
|= ast_unregister_application(app_upqm
);
5014 res
|= ast_unregister_application(app_ql
);
5015 res
|= ast_unregister_application(app
);
5016 res
|= ast_custom_function_unregister(&queueagentcount_function
);
5017 res
|= ast_custom_function_unregister(&queuemembercount_function
);
5018 res
|= ast_custom_function_unregister(&queuememberlist_function
);
5019 res
|= ast_custom_function_unregister(&queuewaitingcount_function
);
5020 ast_devstate_del(statechange_queue
, NULL
);
5022 ast_module_user_hangup_all();
5024 clear_and_free_interfaces();
5029 static int load_module(void)
5033 if (!reload_queues())
5034 return AST_MODULE_LOAD_DECLINE
;
5036 if (queue_persistent_members
)
5037 reload_queue_members();
5039 ast_mutex_init(&device_state
.lock
);
5040 ast_cond_init(&device_state
.cond
, NULL
);
5041 ast_pthread_create(&device_state
.thread
, NULL
, device_state_thread
, NULL
);
5043 ast_cli_register_multiple(cli_queue
, sizeof(cli_queue
) / sizeof(struct ast_cli_entry
));
5044 res
= ast_register_application(app
, queue_exec
, synopsis
, descrip
);
5045 res
|= ast_register_application(app_aqm
, aqm_exec
, app_aqm_synopsis
, app_aqm_descrip
);
5046 res
|= ast_register_application(app_rqm
, rqm_exec
, app_rqm_synopsis
, app_rqm_descrip
);
5047 res
|= ast_register_application(app_pqm
, pqm_exec
, app_pqm_synopsis
, app_pqm_descrip
);
5048 res
|= ast_register_application(app_upqm
, upqm_exec
, app_upqm_synopsis
, app_upqm_descrip
);
5049 res
|= ast_register_application(app_ql
, ql_exec
, app_ql_synopsis
, app_ql_descrip
);
5050 res
|= ast_manager_register("Queues", 0, manager_queues_show
, "Queues");
5051 res
|= ast_manager_register("QueueStatus", 0, manager_queues_status
, "Queue Status");
5052 res
|= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT
, manager_add_queue_member
, "Add interface to queue.");
5053 res
|= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT
, manager_remove_queue_member
, "Remove interface from queue.");
5054 res
|= ast_manager_register("QueuePause", EVENT_FLAG_AGENT
, manager_pause_queue_member
, "Makes a queue member temporarily unavailable");
5055 res
|= ast_custom_function_register(&queueagentcount_function
);
5056 res
|= ast_custom_function_register(&queuemembercount_function
);
5057 res
|= ast_custom_function_register(&queuememberlist_function
);
5058 res
|= ast_custom_function_register(&queuewaitingcount_function
);
5059 res
|= ast_devstate_add(statechange_queue
, NULL
);
5064 static int reload(void)
5070 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "True Call Queueing",
5071 .load
= load_module
,
5072 .unload
= unload_module
,