Asterisk - The Open Source Telephony Project GIT-master-77d630f
app_queue.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2018, Digium, Inc.
5 *
6 * Mark Spencer <markster@digium.com>
7 *
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.
13 *
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.
17 */
18
19/*! \file
20 *
21 * \brief True call queues with optional send URL on answer
22 *
23 * \author Mark Spencer <markster@digium.com>
24 *
25 * \par Development notes
26 * \note 2004-11-25: Persistent Dynamic Members added by:
27 * NetNation Communications (www.netnation.com)
28 * Kevin Lindsay <kevinl@netnation.com>
29 *
30 * Each dynamic agent in each queue is now stored in the astdb.
31 * When asterisk is restarted, each agent will be automatically
32 * readded into their recorded queues. This feature can be
33 * configured with the 'persistent_members=<1|0>' setting in the
34 * '[general]' category in queues.conf. The default is on.
35 *
36 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
37 *
38 * \note These features added by David C. Troy <dave@toad.net>:
39 * - Per-queue holdtime calculation
40 * - Estimated holdtime announcement
41 * - Position announcement
42 * - Abandoned/completed call counters
43 * - Failout timer passed as optional app parameter
44 *
45 * Patch Version 1.07 2003-12-24 01
46 *
47 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
48 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
49 *
50 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
51 * by Matthew Enger <m.enger@xi.com.au>
52 *
53 * \ingroup applications
54 */
55
56/*! \li \ref app_queues.c uses configuration file \ref queues.conf
57 * \addtogroup configuration_file
58 */
59
60/*! \page queues.conf queues.conf
61 * \verbinclude queues.conf.sample
62 */
63
64/*** MODULEINFO
65 <support_level>core</support_level>
66 ***/
67
68#include "asterisk.h"
69
70#include <sys/time.h>
71#include <signal.h>
72#include <netinet/in.h>
73#include <ctype.h>
74
75#include "asterisk/lock.h"
76#include "asterisk/file.h"
77#include "asterisk/channel.h"
78#include "asterisk/pbx.h"
79#include "asterisk/app.h"
81#include "asterisk/module.h"
82#include "asterisk/translate.h"
83#include "asterisk/say.h"
84#include "asterisk/features.h"
86#include "asterisk/cli.h"
87#include "asterisk/manager.h"
88#include "asterisk/config.h"
89#include "asterisk/utils.h"
90#include "asterisk/causes.h"
91#include "asterisk/astdb.h"
94#include "asterisk/astobj2.h"
95#include "asterisk/strings.h"
97#include "asterisk/aoc.h"
98#include "asterisk/callerid.h"
99#include "asterisk/term.h"
100#include "asterisk/dial.h"
105#include "asterisk/core_local.h"
106#include "asterisk/mixmonitor.h"
109
110/*!
111 * \par Please read before modifying this file.
112 * There are three locks which are regularly used
113 * throughout this file, the queue list lock, the lock
114 * for each individual queue, and the interface list lock.
115 * Please be extra careful to always lock in the following order
116 * 1) queue list lock
117 * 2) individual queue lock
118 * 3) interface list lock
119 * This order has sort of "evolved" over the lifetime of this
120 * application, but it is now in place this way, so please adhere
121 * to this order!
122 */
123
124/*** DOCUMENTATION
125 <application name="Queue" language="en_US">
126 <since>
127 <version>0.2.0</version>
128 </since>
129 <synopsis>
130 Queue a call for a call queue.
131 </synopsis>
132 <syntax>
133 <parameter name="queuename" required="true" />
134 <parameter name="options">
135 <optionlist>
136 <option name="b" argsep="^">
137 <para>Before initiating an outgoing call, <literal>Gosub</literal> to the specified
138 location using the newly created channel. The <literal>Gosub</literal> will be
139 executed for each destination channel.</para>
140 <argument name="context" required="false" />
141 <argument name="exten" required="false" />
142 <argument name="priority" required="true" hasparams="optional" argsep="^">
143 <argument name="arg1" multiple="true" required="true" />
144 <argument name="argN" />
145 </argument>
146 </option>
147 <option name="B" argsep="^">
148 <para>Before initiating the outgoing call(s), <literal>Gosub</literal> to the
149 specified location using the current channel.</para>
150 <argument name="context" required="false" />
151 <argument name="exten" required="false" />
152 <argument name="priority" required="true" hasparams="optional" argsep="^">
153 <argument name="arg1" multiple="true" required="true" />
154 <argument name="argN" />
155 </argument>
156 </option>
157 <option name="C">
158 <para>Mark all calls as "answered elsewhere" when cancelled.</para>
159 </option>
160 <option name="c">
161 <para>Continue in the dialplan if the callee hangs up.</para>
162 </option>
163 <option name="d">
164 <para>Data-quality (modem) call (minimum delay).</para>
165 <para>This option only applies to DAHDI channels. By default,
166 DTMF is verified by muting audio TX/RX to verify the tone
167 is still present. This option disables that behavior.</para>
168 </option>
169 <option name="F" argsep="^">
170 <argument name="context" required="false" />
171 <argument name="exten" required="false" />
172 <argument name="priority" required="true" />
173 <para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
174 to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
175 <para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
176 prefixed with one or two underbars ('_').</para>
177 <para>NOTE: Using this option from a GoSub() might not make sense as there would be no return points.</para>
178 </option>
179 <option name="h">
180 <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
181 </option>
182 <option name="H">
183 <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
184 </option>
185 <option name="i">
186 <para>Ignore call forward requests from queue members and do nothing
187 when they are requested.</para>
188 </option>
189 <option name="I">
190 <para>Asterisk will ignore any connected line update requests or any redirecting party
191 update requests it may receive on this dial attempt.</para>
192 </option>
193 <option name="k">
194 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
195 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
196 </option>
197 <option name="K">
198 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
199 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
200 </option>
201 <option name="m">
202 <para>Custom music on hold class to use, which will override the music on hold class configured
203 in <filename>queues.conf</filename>, if specified.</para>
204 <para>Note that CHANNEL(musicclass), if set, will still override this option.</para>
205 </option>
206 <option name="n">
207 <para>No retries on the timeout; will exit this application and
208 go to the next step.</para>
209 </option>
210 <option name="r">
211 <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
212 </option>
213 <option name="R">
214 <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
215 </option>
216 <option name="t">
217 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
218 </option>
219 <option name="T">
220 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
221 </option>
222 <option name="x">
223 <para>Allow the <emphasis>called</emphasis> user to write the conversation
224 to disk via MixMonitor.</para>
225 </option>
226 <option name="X">
227 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
228 disk via MixMonitor.</para>
229 </option>
230 </optionlist>
231 </parameter>
232 <parameter name="URL">
233 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
234 </parameter>
235 <parameter name="announceoverride" argsep="&amp;">
236 <para>Announcement file(s) to play to agent before bridging
237 call, overriding the announcement(s) configured in
238 <filename>queues.conf</filename>, if any.</para>
239 <para>Ampersand separated list of filenames. If the filename
240 is a relative filename (it does not begin with a slash), it
241 will be searched for in the Asterisk sounds directory. If the
242 filename is able to be parsed as a URL, Asterisk will
243 download the file and then begin playback on it. To include a
244 literal <literal>&amp;</literal> in the URL you can enclose
245 the URL in single quotes.</para>
246 <argument name="announceoverride" required="true" />
247 <argument name="announceoverride2" multiple="true" />
248 </parameter>
249 <parameter name="timeout">
250 <para>Will cause the queue to fail out after a specified number of
251 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
252 <replaceable>retry</replaceable> cycle.</para>
253 </parameter>
254 <parameter name="AGI">
255 <para>Will setup an AGI script to be executed on the calling party's channel once they are
256 connected to a queue member.</para>
257 </parameter>
258 <parameter name="gosub">
259 <para>Will run a gosub on the called party's channel (the queue member)
260 once the parties are connected. The subroutine execution starts in the
261 named context at the s exten and priority 1.</para>
262 </parameter>
263 <parameter name="rule">
264 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
265 </parameter>
266 <parameter name="position">
267 <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
268 would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
269 the caller third in the queue.</para>
270 </parameter>
271 </syntax>
272 <description>
273 <para>In addition to transferring the call, a call may be parked and then picked
274 up by another user.</para>
275 <para>This application will return to the dialplan if the queue does not exist, or
276 any of the join options cause the caller to not enter the queue.</para>
277 <para>This application does not automatically answer and should be preceded
278 by an application such as Answer(), Progress(), or Ringing().</para>
279 <para>This application sets the following channel variables upon completion:</para>
280 <variablelist>
281 <variable name="QUEUESTATUS">
282 <para>The status of the call as a text string.</para>
283 <value name="TIMEOUT" />
284 <value name="FULL" />
285 <value name="JOINEMPTY" />
286 <value name="LEAVEEMPTY" />
287 <value name="JOINUNAVAIL" />
288 <value name="LEAVEUNAVAIL" />
289 <value name="CONTINUE" />
290 <value name="WITHDRAW" />
291 </variable>
292 <variable name="ABANDONED">
293 <para>If the call was not answered by an agent this variable will be TRUE.</para>
294 <value name="TRUE" />
295 </variable>
296 <variable name="DIALEDPEERNUMBER">
297 <para>Resource of the agent that was dialed set on the outbound channel.</para>
298 </variable>
299 <variable name="QUEUE_WITHDRAW_INFO">
300 <para>If the call was successfully withdrawn from the queue, and the withdraw request was provided with optional withdraw info, the withdraw info will be stored in this variable.</para>
301 </variable>
302 </variablelist>
303 </description>
304 <see-also>
305 <ref type="application">Queue</ref>
306 <ref type="application">QueueLog</ref>
307 <ref type="application">AddQueueMember</ref>
308 <ref type="application">RemoveQueueMember</ref>
309 <ref type="application">PauseQueueMember</ref>
310 <ref type="application">UnpauseQueueMember</ref>
311 <ref type="function">QUEUE_VARIABLES</ref>
312 <ref type="function">QUEUE_MEMBER</ref>
313 <ref type="function">QUEUE_EXISTS</ref>
314 <ref type="function">QUEUE_GET_CHANNEL</ref>
315 <ref type="function">QUEUE_WAITING_COUNT</ref>
316 <ref type="function">QUEUE_MEMBER_LIST</ref>
317 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
318 </see-also>
319 </application>
320 <application name="AddQueueMember" language="en_US">
321 <since>
322 <version>0.5.0</version>
323 </since>
324 <synopsis>
325 Dynamically adds queue members.
326 </synopsis>
327 <syntax>
328 <parameter name="queuename" required="true" />
329 <parameter name="interface" />
330 <parameter name="penalty" />
331 <parameter name="options">
332 <optionlist>
333 <option name="p">
334 <para>Add queue member in paused state.</para>
335 </option>
336 <option name="r">
337 <argument name="reason" required="true" />
338 <para>Specify a reason why the member is in paused state.</para>
339 </option>
340 </optionlist>
341 </parameter>
342 <parameter name="membername" />
343 <parameter name="stateinterface" />
344 <parameter name="wrapuptime" />
345 </syntax>
346 <description>
347 <para>Dynamically adds interface to an existing queue. If the interface is
348 already in the queue it will return an error.</para>
349 <para>This application sets the following channel variable upon completion:</para>
350 <variablelist>
351 <variable name="AQMSTATUS">
352 <para>The status of the attempt to add a queue member as a text string.</para>
353 <value name="ADDED" />
354 <value name="MEMBERALREADY" />
355 <value name="NOSUCHQUEUE" />
356 </variable>
357 </variablelist>
358 </description>
359 <see-also>
360 <ref type="application">Queue</ref>
361 <ref type="application">QueueLog</ref>
362 <ref type="application">AddQueueMember</ref>
363 <ref type="application">RemoveQueueMember</ref>
364 <ref type="application">PauseQueueMember</ref>
365 <ref type="application">UnpauseQueueMember</ref>
366 <ref type="function">QUEUE_VARIABLES</ref>
367 <ref type="function">QUEUE_MEMBER</ref>
368 <ref type="function">QUEUE_EXISTS</ref>
369 <ref type="function">QUEUE_GET_CHANNEL</ref>
370 <ref type="function">QUEUE_WAITING_COUNT</ref>
371 <ref type="function">QUEUE_MEMBER_LIST</ref>
372 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
373 </see-also>
374 </application>
375 <application name="RemoveQueueMember" language="en_US">
376 <since>
377 <version>0.5.0</version>
378 </since>
379 <synopsis>
380 Dynamically removes queue members.
381 </synopsis>
382 <syntax>
383 <parameter name="queuename" required="true" />
384 <parameter name="interface" />
385 </syntax>
386 <description>
387 <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
388 <para>This application sets the following channel variable upon completion:</para>
389 <variablelist>
390 <variable name="RQMSTATUS">
391 <value name="REMOVED" />
392 <value name="NOTINQUEUE" />
393 <value name="NOSUCHQUEUE" />
394 <value name="NOTDYNAMIC" />
395 </variable>
396 </variablelist>
397 <example title="Remove queue member">
398 same => n,RemoveQueueMember(techsupport,SIP/3000)
399 </example>
400 </description>
401 <see-also>
402 <ref type="application">Queue</ref>
403 <ref type="application">QueueLog</ref>
404 <ref type="application">AddQueueMember</ref>
405 <ref type="application">RemoveQueueMember</ref>
406 <ref type="application">PauseQueueMember</ref>
407 <ref type="application">UnpauseQueueMember</ref>
408 <ref type="function">QUEUE_VARIABLES</ref>
409 <ref type="function">QUEUE_MEMBER</ref>
410 <ref type="function">QUEUE_EXISTS</ref>
411 <ref type="function">QUEUE_GET_CHANNEL</ref>
412 <ref type="function">QUEUE_WAITING_COUNT</ref>
413 <ref type="function">QUEUE_MEMBER_LIST</ref>
414 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
415 </see-also>
416 </application>
417 <application name="PauseQueueMember" language="en_US">
418 <since>
419 <version>1.2.0</version>
420 </since>
421 <synopsis>
422 Pauses a queue member.
423 </synopsis>
424 <syntax>
425 <parameter name="queuename" />
426 <parameter name="interface" required="true" />
427 <parameter name="options" />
428 <parameter name="reason">
429 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
430 </parameter>
431 </syntax>
432 <description>
433 <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
434 This prevents any calls from being sent from the queue to the interface until it is
435 unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
436 the interface is paused in every queue it is a member of. The application will fail if the
437 interface is not found.</para>
438 <para>This application sets the following channel variable upon completion:</para>
439 <variablelist>
440 <variable name="PQMSTATUS">
441 <para>The status of the attempt to pause a queue member as a text string.</para>
442 <value name="PAUSED" />
443 <value name="NOTFOUND" />
444 </variable>
445 </variablelist>
446 <example title="Pause queue member">
447 same => n,PauseQueueMember(,SIP/3000)
448 </example>
449 </description>
450 <see-also>
451 <ref type="application">Queue</ref>
452 <ref type="application">QueueLog</ref>
453 <ref type="application">AddQueueMember</ref>
454 <ref type="application">RemoveQueueMember</ref>
455 <ref type="application">PauseQueueMember</ref>
456 <ref type="application">UnpauseQueueMember</ref>
457 <ref type="function">QUEUE_VARIABLES</ref>
458 <ref type="function">QUEUE_MEMBER</ref>
459 <ref type="function">QUEUE_EXISTS</ref>
460 <ref type="function">QUEUE_GET_CHANNEL</ref>
461 <ref type="function">QUEUE_WAITING_COUNT</ref>
462 <ref type="function">QUEUE_MEMBER_LIST</ref>
463 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
464 </see-also>
465 </application>
466 <application name="UnpauseQueueMember" language="en_US">
467 <since>
468 <version>1.2.0</version>
469 </since>
470 <synopsis>
471 Unpauses a queue member.
472 </synopsis>
473 <syntax>
474 <parameter name="queuename" />
475 <parameter name="interface" required="true" />
476 <parameter name="options" />
477 <parameter name="reason">
478 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
479 </parameter>
480 </syntax>
481 <description>
482 <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
483 and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
484 <para>This application sets the following channel variable upon completion:</para>
485 <variablelist>
486 <variable name="UPQMSTATUS">
487 <para>The status of the attempt to unpause a queue member as a text string.</para>
488 <value name="UNPAUSED" />
489 <value name="NOTFOUND" />
490 </variable>
491 </variablelist>
492 <example title="Unpause queue member">
493 same => n,UnpauseQueueMember(,SIP/3000)
494 </example>
495 </description>
496 <see-also>
497 <ref type="application">Queue</ref>
498 <ref type="application">QueueLog</ref>
499 <ref type="application">AddQueueMember</ref>
500 <ref type="application">RemoveQueueMember</ref>
501 <ref type="application">PauseQueueMember</ref>
502 <ref type="application">UnpauseQueueMember</ref>
503 <ref type="function">QUEUE_VARIABLES</ref>
504 <ref type="function">QUEUE_MEMBER</ref>
505 <ref type="function">QUEUE_EXISTS</ref>
506 <ref type="function">QUEUE_GET_CHANNEL</ref>
507 <ref type="function">QUEUE_WAITING_COUNT</ref>
508 <ref type="function">QUEUE_MEMBER_LIST</ref>
509 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
510 </see-also>
511 </application>
512 <application name="QueueLog" language="en_US">
513 <since>
514 <version>1.4.0</version>
515 </since>
516 <synopsis>
517 Writes to the queue_log file.
518 </synopsis>
519 <syntax>
520 <parameter name="queuename" required="true" />
521 <parameter name="uniqueid" required="true" />
522 <parameter name="agent" required="true" />
523 <parameter name="event" required="true" />
524 <parameter name="additionalinfo" />
525 </syntax>
526 <description>
527 <para>Allows you to write your own events into the queue log.</para>
528 <example title="Log custom queue event">
529 same => n,QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)
530 </example>
531 </description>
532 <see-also>
533 <ref type="application">Queue</ref>
534 <ref type="application">QueueLog</ref>
535 <ref type="application">AddQueueMember</ref>
536 <ref type="application">RemoveQueueMember</ref>
537 <ref type="application">PauseQueueMember</ref>
538 <ref type="application">UnpauseQueueMember</ref>
539 <ref type="function">QUEUE_VARIABLES</ref>
540 <ref type="function">QUEUE_MEMBER</ref>
541 <ref type="function">QUEUE_EXISTS</ref>
542 <ref type="function">QUEUE_GET_CHANNEL</ref>
543 <ref type="function">QUEUE_WAITING_COUNT</ref>
544 <ref type="function">QUEUE_MEMBER_LIST</ref>
545 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
546 </see-also>
547 </application>
548 <application name="QueueUpdate" language="en_US">
549 <since>
550 <version>15.0.0</version>
551 </since>
552 <synopsis>
553 Writes to the queue_log file for outbound calls and updates Realtime Data.
554 Is used at h extension to be able to have all the parameters.
555 </synopsis>
556 <syntax>
557 <parameter name="queuename" required="true" />
558 <parameter name="uniqueid" required="true" />
559 <parameter name="agent" required="true" />
560 <parameter name="status" required="true" />
561 <parameter name="talktime" required="true" />
562 <parameter name="params" required="false" />
563 </syntax>
564 <description>
565 <para>Allows you to write Outbound events into the queue log.</para>
566 <example title="Write outbound event into queue log">
567 exten => h,1,QueueUpdate(${QUEUE}, ${UNIQUEID}, ${AGENT}, ${DIALSTATUS}, ${ANSWEREDTIME}, ${DIALEDTIME} | ${DIALEDNUMBER})
568 </example>
569 </description>
570 </application>
571 <function name="QUEUE_VARIABLES" language="en_US">
572 <since>
573 <version>1.6.0</version>
574 </since>
575 <synopsis>
576 Return Queue information in variables.
577 </synopsis>
578 <syntax>
579 <parameter name="queuename" required="true">
580 <enumlist>
581 <enum name="QUEUEMAX">
582 <para>Maximum number of calls allowed.</para>
583 </enum>
584 <enum name="QUEUESTRATEGY">
585 <para>The strategy of the queue.</para>
586 </enum>
587 <enum name="QUEUECALLS">
588 <para>Number of calls currently in the queue.</para>
589 </enum>
590 <enum name="QUEUEHOLDTIME">
591 <para>Current average hold time.</para>
592 </enum>
593 <enum name="QUEUECOMPLETED">
594 <para>Number of completed calls for the queue.</para>
595 </enum>
596 <enum name="QUEUEABANDONED">
597 <para>Number of abandoned calls.</para>
598 </enum>
599 <enum name="QUEUESRVLEVEL">
600 <para>Queue service level.</para>
601 </enum>
602 <enum name="QUEUESRVLEVELPERF">
603 <para>Current service level performance.</para>
604 </enum>
605 </enumlist>
606 </parameter>
607 </syntax>
608 <description>
609 <para>Makes the following queue variables available.</para>
610 <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
611 </description>
612 <see-also>
613 <ref type="application">Queue</ref>
614 <ref type="application">QueueLog</ref>
615 <ref type="application">AddQueueMember</ref>
616 <ref type="application">RemoveQueueMember</ref>
617 <ref type="application">PauseQueueMember</ref>
618 <ref type="application">UnpauseQueueMember</ref>
619 <ref type="function">QUEUE_VARIABLES</ref>
620 <ref type="function">QUEUE_MEMBER</ref>
621 <ref type="function">QUEUE_EXISTS</ref>
622 <ref type="function">QUEUE_GET_CHANNEL</ref>
623 <ref type="function">QUEUE_WAITING_COUNT</ref>
624 <ref type="function">QUEUE_MEMBER_LIST</ref>
625 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
626 </see-also>
627 </function>
628 <function name="QUEUE_MEMBER" language="en_US">
629 <since>
630 <version>1.6.0</version>
631 </since>
632 <synopsis>
633 Provides a count of queue members based on the provided criteria, or updates a
634 queue member's settings.
635 </synopsis>
636 <syntax>
637 <parameter name="queuename" required="false" />
638 <parameter name="option" required="true">
639 <enumlist>
640 <enum name="logged">
641 <para>Returns the number of logged-in members for the specified queue.</para>
642 </enum>
643 <enum name="free">
644 <para>Returns the number of logged-in members for the specified queue that either can take calls or are currently wrapping up after a previous call.</para>
645 </enum>
646 <enum name="ready">
647 <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
648 </enum>
649 <enum name="count">
650 <para>Returns the total number of members for the specified queue.</para>
651 </enum>
652 <enum name="penalty">
653 <para>Gets or sets queue member penalty. If
654 <replaceable>queuename</replaceable> is not specified
655 when setting the penalty then the penalty is set in all queues
656 the interface is a member.</para>
657 </enum>
658 <enum name="paused">
659 <para>Gets or sets queue member paused status. If
660 <replaceable>queuename</replaceable> is not specified
661 when setting the paused status then the paused status is set
662 in all queues the interface is a member.</para>
663 </enum>
664 <enum name="ringinuse">
665 <para>Gets or sets queue member ringinuse. If
666 <replaceable>queuename</replaceable> is not specified
667 when setting ringinuse then ringinuse is set
668 in all queues the interface is a member.</para>
669 </enum>
670 </enumlist>
671 </parameter>
672 <parameter name="interface" required="false" />
673 </syntax>
674 <description>
675 <para>Allows access to queue counts [R] and member information [R/W].</para>
676 <para><replaceable>queuename</replaceable> is required for all read operations.</para>
677 <para><replaceable>interface</replaceable> is required for all member operations.</para>
678 </description>
679 <see-also>
680 <ref type="application">Queue</ref>
681 <ref type="application">QueueLog</ref>
682 <ref type="application">AddQueueMember</ref>
683 <ref type="application">RemoveQueueMember</ref>
684 <ref type="application">PauseQueueMember</ref>
685 <ref type="application">UnpauseQueueMember</ref>
686 <ref type="function">QUEUE_VARIABLES</ref>
687 <ref type="function">QUEUE_MEMBER</ref>
688 <ref type="function">QUEUE_EXISTS</ref>
689 <ref type="function">QUEUE_GET_CHANNEL</ref>
690 <ref type="function">QUEUE_WAITING_COUNT</ref>
691 <ref type="function">QUEUE_MEMBER_LIST</ref>
692 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
693 </see-also>
694 </function>
695 <function name="QUEUE_EXISTS" language="en_US">
696 <since>
697 <version>1.8.0</version>
698 </since>
699 <synopsis>
700 Check if a named queue exists on this server
701 </synopsis>
702 <syntax>
703 <parameter name="queuename" />
704 </syntax>
705 <description>
706 <para>Returns 1 if the specified queue exists, 0 if it does not</para>
707 </description>
708 <see-also>
709 <ref type="application">Queue</ref>
710 <ref type="application">QueueLog</ref>
711 <ref type="application">AddQueueMember</ref>
712 <ref type="application">RemoveQueueMember</ref>
713 <ref type="application">PauseQueueMember</ref>
714 <ref type="application">UnpauseQueueMember</ref>
715 <ref type="function">QUEUE_VARIABLES</ref>
716 <ref type="function">QUEUE_MEMBER</ref>
717 <ref type="function">QUEUE_EXISTS</ref>
718 <ref type="function">QUEUE_GET_CHANNEL</ref>
719 <ref type="function">QUEUE_WAITING_COUNT</ref>
720 <ref type="function">QUEUE_MEMBER_LIST</ref>
721 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
722 </see-also>
723 </function>
724 <function name="QUEUE_GET_CHANNEL" language="en_US">
725 <since>
726 <version>14.0.0</version>
727 </since>
728 <synopsis>
729 Return caller at the specified position in a queue.
730 </synopsis>
731 <syntax>
732 <parameter name="queuename" required="true" />
733 <parameter name="position" />
734 </syntax>
735 <description>
736 <para>Returns the caller channel at <replaceable>position</replaceable> in the specified <replaceable>queuename</replaceable>.</para>
737 <para>If <replaceable>position</replaceable> is unspecified the first channel is returned.</para>
738 </description>
739 <see-also>
740 <ref type="application">Queue</ref>
741 <ref type="application">QueueLog</ref>
742 <ref type="application">AddQueueMember</ref>
743 <ref type="application">RemoveQueueMember</ref>
744 <ref type="application">PauseQueueMember</ref>
745 <ref type="application">UnpauseQueueMember</ref>
746 <ref type="function">QUEUE_VARIABLES</ref>
747 <ref type="function">QUEUE_MEMBER</ref>
748 <ref type="function">QUEUE_EXISTS</ref>
749 <ref type="function">QUEUE_WAITING_COUNT</ref>
750 <ref type="function">QUEUE_MEMBER_LIST</ref>
751 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
752 </see-also>
753 </function>
754 <function name="QUEUE_WAITING_COUNT" language="en_US">
755 <since>
756 <version>1.4.0</version>
757 </since>
758 <synopsis>
759 Count number of calls currently waiting in a queue.
760 </synopsis>
761 <syntax>
762 <parameter name="queuename" />
763 </syntax>
764 <description>
765 <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
766 </description>
767 <see-also>
768 <ref type="application">Queue</ref>
769 <ref type="application">QueueLog</ref>
770 <ref type="application">AddQueueMember</ref>
771 <ref type="application">RemoveQueueMember</ref>
772 <ref type="application">PauseQueueMember</ref>
773 <ref type="application">UnpauseQueueMember</ref>
774 <ref type="function">QUEUE_VARIABLES</ref>
775 <ref type="function">QUEUE_MEMBER</ref>
776 <ref type="function">QUEUE_EXISTS</ref>
777 <ref type="function">QUEUE_GET_CHANNEL</ref>
778 <ref type="function">QUEUE_WAITING_COUNT</ref>
779 <ref type="function">QUEUE_MEMBER_LIST</ref>
780 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
781 </see-also>
782 </function>
783 <function name="QUEUE_MEMBER_LIST" language="en_US">
784 <since>
785 <version>1.4.0</version>
786 </since>
787 <synopsis>
788 Returns a list of interfaces on a queue.
789 </synopsis>
790 <syntax>
791 <parameter name="queuename" required="true" />
792 </syntax>
793 <description>
794 <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
795 </description>
796 <see-also>
797 <ref type="application">Queue</ref>
798 <ref type="application">QueueLog</ref>
799 <ref type="application">AddQueueMember</ref>
800 <ref type="application">RemoveQueueMember</ref>
801 <ref type="application">PauseQueueMember</ref>
802 <ref type="application">UnpauseQueueMember</ref>
803 <ref type="function">QUEUE_VARIABLES</ref>
804 <ref type="function">QUEUE_MEMBER</ref>
805 <ref type="function">QUEUE_EXISTS</ref>
806 <ref type="function">QUEUE_GET_CHANNEL</ref>
807 <ref type="function">QUEUE_WAITING_COUNT</ref>
808 <ref type="function">QUEUE_MEMBER_LIST</ref>
809 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
810 </see-also>
811 </function>
812 <function name="QUEUE_MEMBER_PENALTY" language="en_US">
813 <since>
814 <version>1.6.0</version>
815 </since>
816 <synopsis>
817 Gets or sets queue members penalty.
818 </synopsis>
819 <syntax>
820 <parameter name="queuename" required="true" />
821 <parameter name="interface" required="true" />
822 </syntax>
823 <description>
824 <para>Gets or sets queue members penalty.</para>
825 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
826 </description>
827 <see-also>
828 <ref type="application">Queue</ref>
829 <ref type="application">QueueLog</ref>
830 <ref type="application">AddQueueMember</ref>
831 <ref type="application">RemoveQueueMember</ref>
832 <ref type="application">PauseQueueMember</ref>
833 <ref type="application">UnpauseQueueMember</ref>
834 <ref type="function">QUEUE_VARIABLES</ref>
835 <ref type="function">QUEUE_MEMBER</ref>
836 <ref type="function">QUEUE_EXISTS</ref>
837 <ref type="function">QUEUE_GET_CHANNEL</ref>
838 <ref type="function">QUEUE_WAITING_COUNT</ref>
839 <ref type="function">QUEUE_MEMBER_LIST</ref>
840 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
841 </see-also>
842 </function>
843 <manager name="QueueStatus" language="en_US">
844 <since>
845 <version>0.5.0</version>
846 </since>
847 <synopsis>
848 Show queue status.
849 </synopsis>
850 <syntax>
851 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
852 <parameter name="Queue">
853 <para>Limit the response to the status of the specified queue.</para>
854 </parameter>
855 <parameter name="Member">
856 <para>Limit the response to the status of the specified member.</para>
857 </parameter>
858 </syntax>
859 <description>
860 <para>Check the status of one or more queues.</para>
861 </description>
862 </manager>
863 <manager name="QueueSummary" language="en_US">
864 <since>
865 <version>1.6.0</version>
866 </since>
867 <synopsis>
868 Show queue summary.
869 </synopsis>
870 <syntax>
871 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
872 <parameter name="Queue">
873 <para>Queue for which the summary is requested.</para>
874 </parameter>
875 </syntax>
876 <description>
877 <para>Request the manager to send a QueueSummary event.</para>
878 </description>
879 </manager>
880 <manager name="QueueAdd" language="en_US">
881 <since>
882 <version>1.0.0</version>
883 </since>
884 <synopsis>
885 Add interface to queue.
886 </synopsis>
887 <syntax>
888 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
889 <parameter name="Queue" required="true">
890 <para>Queue's name.</para>
891 </parameter>
892 <parameter name="Interface" required="true">
893 <para>The name of the interface (tech/name) to add to the queue.</para>
894 </parameter>
895 <parameter name="Penalty">
896 <para>A penalty (number) to apply to this member. Asterisk will distribute calls to members with higher penalties only after attempting to distribute calls to those with lower penalty.</para>
897 </parameter>
898 <parameter name="Paused">
899 <para>To pause or not the member initially (true/false or 1/0).</para>
900 </parameter>
901 <parameter name="Reason" required="false">
902 <para>Text description why the member is paused.</para>
903 </parameter>
904 <parameter name="MemberName">
905 <para>Text alias for the interface.</para>
906 </parameter>
907 <parameter name="StateInterface" />
908 </syntax>
909 <description>
910 </description>
911 </manager>
912 <manager name="QueueRemove" language="en_US">
913 <since>
914 <version>1.0.0</version>
915 </since>
916 <synopsis>
917 Remove interface from queue.
918 </synopsis>
919 <syntax>
920 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
921 <parameter name="Queue" required="true">
922 <para>The name of the queue to take action on.</para>
923 </parameter>
924 <parameter name="Interface" required="true">
925 <para>The interface (tech/name) to remove from queue.</para>
926 </parameter>
927 </syntax>
928 <description>
929 </description>
930 </manager>
931 <manager name="QueuePause" language="en_US">
932 <since>
933 <version>1.2.0</version>
934 </since>
935 <synopsis>
936 Makes a queue member temporarily unavailable.
937 </synopsis>
938 <syntax>
939 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
940 <parameter name="Interface" required="true">
941 <para>The name of the interface (tech/name) to pause or unpause.</para>
942 </parameter>
943 <parameter name="Paused" required="true">
944 <para>Pause or unpause the interface. Set to 'true' to pause the member or 'false' to unpause.</para>
945 </parameter>
946 <parameter name="Queue" required="false">
947 <para>The name of the queue in which to pause or unpause this member. If not specified, the member will be paused or unpaused in all the queues it is a member of.</para>
948 </parameter>
949 <parameter name="Reason" required="false">
950 <para>Text description, returned in the event QueueMemberPaused.</para>
951 </parameter>
952 </syntax>
953 <description>
954 <para>Pause or unpause a member in a queue.</para>
955 </description>
956 </manager>
957 <manager name="QueueLog" language="en_US">
958 <since>
959 <version>1.6.0</version>
960 </since>
961 <synopsis>
962 Adds custom entry in queue_log.
963 </synopsis>
964 <syntax>
965 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
966 <parameter name="Queue" required="true" />
967 <parameter name="Event" required="true" />
968 <parameter name="Uniqueid" />
969 <parameter name="Interface" />
970 <parameter name="Message" />
971 </syntax>
972 <description>
973 </description>
974 </manager>
975 <manager name="QueuePenalty" language="en_US">
976 <since>
977 <version>1.6.0</version>
978 </since>
979 <synopsis>
980 Set the penalty for a queue member.
981 </synopsis>
982 <syntax>
983 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
984 <parameter name="Interface" required="true">
985 <para>The interface (tech/name) of the member whose penalty to change.</para>
986 </parameter>
987 <parameter name="Penalty" required="true">
988 <para>The new penalty (number) for the member. Must be nonnegative.</para>
989 </parameter>
990 <parameter name="Queue">
991 <para>If specified, only set the penalty for the member of this queue. Otherwise, set the penalty for the member in all queues to which the member belongs.</para>
992 </parameter>
993 </syntax>
994 <description>
995 <para>Change the penalty of a queue member</para>
996 </description>
997 </manager>
998 <manager name="QueueMemberRingInUse" language="en_US">
999 <since>
1000 <version>11.0.0</version>
1001 </since>
1002 <synopsis>
1003 Set the ringinuse value for a queue member.
1004 </synopsis>
1005 <syntax>
1006 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1007 <parameter name="Interface" required="true" />
1008 <parameter name="RingInUse" required="true" />
1009 <parameter name="Queue" />
1010 </syntax>
1011 <description>
1012 </description>
1013 </manager>
1014 <manager name="QueueRule" language="en_US">
1015 <since>
1016 <version>1.6.0</version>
1017 </since>
1018 <synopsis>
1019 Queue Rules.
1020 </synopsis>
1021 <syntax>
1022 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1023 <parameter name="Rule">
1024 <para>The name of the rule in queuerules.conf whose contents to list.</para>
1025 </parameter>
1026 </syntax>
1027 <description>
1028 <para>List queue rules defined in queuerules.conf</para>
1029 </description>
1030 </manager>
1031 <manager name="QueueReload" language="en_US">
1032 <since>
1033 <version>1.6.2.0</version>
1034 </since>
1035 <synopsis>
1036 Reload a queue, queues, or any sub-section of a queue or queues.
1037 </synopsis>
1038 <syntax>
1039 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1040 <parameter name="Queue">
1041 <para>The name of the queue to take action on. If no queue name is specified, then all queues are affected.</para>
1042 </parameter>
1043 <parameter name="Members">
1044 <para>Whether to reload the queue's members.</para>
1045 <enumlist>
1046 <enum name="yes" />
1047 <enum name="no" />
1048 </enumlist>
1049 </parameter>
1050 <parameter name="Rules">
1051 <para>Whether to reload queuerules.conf</para>
1052 <enumlist>
1053 <enum name="yes" />
1054 <enum name="no" />
1055 </enumlist>
1056 </parameter>
1057 <parameter name="Parameters">
1058 <para>Whether to reload the other queue options.</para>
1059 <enumlist>
1060 <enum name="yes" />
1061 <enum name="no" />
1062 </enumlist>
1063 </parameter>
1064 </syntax>
1065 <description>
1066 </description>
1067 </manager>
1068 <manager name="QueueReset" language="en_US">
1069 <since>
1070 <version>1.6.2.0</version>
1071 </since>
1072 <synopsis>
1073 Reset queue statistics.
1074 </synopsis>
1075 <syntax>
1076 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1077 <parameter name="Queue">
1078 <para>The name of the queue on which to reset statistics.</para>
1079 </parameter>
1080 </syntax>
1081 <description>
1082 <para>Reset the statistics for a queue.</para>
1083 </description>
1084 </manager>
1085 <manager name="QueueChangePriorityCaller" language="en_US">
1086 <since>
1087 <version>15.0.0</version>
1088 </since>
1089 <synopsis>
1090 Change priority of a caller on queue.
1091 </synopsis>
1092 <syntax>
1093 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1094 <parameter name="Queue" required="true">
1095 <para>The name of the queue to take action on.</para>
1096 </parameter>
1097 <parameter name="Caller" required="true">
1098 <para>The caller (channel) to change priority on queue.</para>
1099 </parameter>
1100
1101 <parameter name="Priority" required="true">
1102 <para>Priority value for change for caller on queue.</para>
1103 </parameter>
1104 <parameter name="Immediate">
1105 <para>When set to yes will cause the priority change to be reflected immediately, causing the channel to change position within the queue.</para>
1106 </parameter>
1107 </syntax>
1108 <description>
1109 </description>
1110 </manager>
1111 <manager name="QueueWithdrawCaller" language="en_US">
1112 <since>
1113 <version>19.3.0</version>
1114 <version>18.11.0</version>
1115 <version>16.25.0</version>
1116 </since>
1117 <synopsis>
1118 Request to withdraw a caller from the queue back to the dialplan.
1119 </synopsis>
1120 <syntax>
1121 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1122 <parameter name="Queue" required="true">
1123 <para>The name of the queue to take action on.</para>
1124 </parameter>
1125 <parameter name="Caller" required="true">
1126 <para>The caller (channel) to withdraw from the queue.</para>
1127 </parameter>
1128 <parameter name="WithdrawInfo" required="false">
1129 <para>Optional info to store. If the call is successfully withdrawn from the queue, this information will be available in the QUEUE_WITHDRAW_INFO variable.</para>
1130 </parameter>
1131 </syntax>
1132 <description>
1133 </description>
1134 </manager>
1135
1136 <managerEvent language="en_US" name="QueueParams">
1137 <managerEventInstance class="EVENT_FLAG_AGENT">
1138 <since>
1139 <version>16.24.0</version>
1140 <version>18.10.0</version>
1141 <version>19.2.0</version>
1142 </since>
1143 <synopsis>Raised in response to the QueueStatus action.</synopsis>
1144 <syntax>
1145 <parameter name="Max">
1146 <para>The name of the queue.</para>
1147 </parameter>
1148 <parameter name="Strategy">
1149 <para>The strategy of the queue.</para>
1150 </parameter>
1151 <parameter name="Calls">
1152 <para>The queue member's channel technology or location.</para>
1153 </parameter>
1154 <parameter name="Holdtime">
1155 <para>The queue's hold time.</para>
1156 </parameter>
1157 <parameter name="TalkTime">
1158 <para>The queue's talk time.</para>
1159 </parameter>
1160 <parameter name="Completed">
1161 <para>The queue's completion time.</para>
1162 </parameter>
1163 <parameter name="Abandoned">
1164 <para>The queue's call abandonment metric.</para>
1165 </parameter>
1166 <parameter name="ServiceLevelPerf">
1167 <para>Primary service level performance metric.</para>
1168 </parameter>
1169 <parameter name="ServiceLevelPerf2">
1170 <para>Secondary service level performance metric.</para>
1171 </parameter>
1172 </syntax>
1173 <see-also>
1174 <ref type="managerEvent">QueueMember</ref>
1175 <ref type="managerEvent">QueueEntry</ref>
1176 </see-also>
1177 </managerEventInstance>
1178 </managerEvent>
1179 <managerEvent language="en_US" name="QueueEntry">
1180 <managerEventInstance class="EVENT_FLAG_AGENT">
1181 <since>
1182 <version>16.24.0</version>
1183 <version>18.10.0</version>
1184 <version>19.2.0</version>
1185 </since>
1186 <synopsis>Raised in response to the QueueStatus action.</synopsis>
1187 <syntax>
1188 <parameter name="Queue">
1189 <para>The name of the queue.</para>
1190 </parameter>
1191 <parameter name="Position">
1192 <para>The caller's position within the queue.</para>
1193 </parameter>
1194 <parameter name="Channel">
1195 <para>The name of the caller's channel.</para>
1196 </parameter>
1197 <parameter name="Uniqueid">
1198 <para>The unique ID of the channel.</para>
1199 </parameter>
1200 <parameter name="CallerIDNum">
1201 <para>The Caller ID number.</para>
1202 </parameter>
1203 <parameter name="CallerIDName">
1204 <para>The Caller ID name.</para>
1205 </parameter>
1206 <parameter name="ConnectedLineNum">
1207 <para>The bridged party's number.</para>
1208 </parameter>
1209 <parameter name="ConnectedLineName">
1210 <para>The bridged party's name.</para>
1211 </parameter>
1212 <parameter name="Wait">
1213 <para>The caller's wait time.</para>
1214 </parameter>
1215 <parameter name="Priority">
1216 <para>The caller's priority within the queue.</para>
1217 </parameter>
1218 </syntax>
1219 <see-also>
1220 <ref type="managerEvent">QueueParams</ref>
1221 <ref type="managerEvent">QueueMember</ref>
1222 </see-also>
1223 </managerEventInstance>
1224 </managerEvent>
1225 <managerEvent language="en_US" name="QueueMemberStatus">
1226 <managerEventInstance class="EVENT_FLAG_AGENT">
1227 <since>
1228 <version>12.0.0</version>
1229 </since>
1230 <synopsis>Raised when a Queue member's status has changed.</synopsis>
1231 <syntax>
1232 <parameter name="Queue">
1233 <para>The name of the queue.</para>
1234 </parameter>
1235 <parameter name="MemberName">
1236 <para>The name of the queue member.</para>
1237 </parameter>
1238 <parameter name="Interface">
1239 <para>The queue member's channel technology or location.</para>
1240 </parameter>
1241 <parameter name="StateInterface">
1242 <para>Channel technology or location from which to read device state changes.</para>
1243 </parameter>
1244 <parameter name="Membership">
1245 <enumlist>
1246 <enum name="dynamic"/>
1247 <enum name="realtime"/>
1248 <enum name="static"/>
1249 </enumlist>
1250 </parameter>
1251 <parameter name="Penalty">
1252 <para>The penalty associated with the queue member.</para>
1253 </parameter>
1254 <parameter name="CallsTaken">
1255 <para>The number of calls this queue member has serviced.</para>
1256 </parameter>
1257 <parameter name="LastCall">
1258 <para>The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1259 </parameter>
1260 <parameter name="LastPause">
1261 <para>The time when started last paused the queue member.</para>
1262 </parameter>
1263 <parameter name="LoginTime">
1264 <para>The time this member logged in to the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1265 </parameter>
1266 <parameter name="InCall">
1267 <para>Set to 1 if member is in call. Set to 0 after LastCall time is updated.</para>
1268 <enumlist>
1269 <enum name="0"/>
1270 <enum name="1"/>
1271 </enumlist>
1272 </parameter>
1273 <parameter name="Status">
1274 <para>The numeric device state status of the queue member.</para>
1275 <enumlist>
1276 <enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
1277 <enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
1278 <enum name="2"><para>AST_DEVICE_INUSE</para></enum>
1279 <enum name="3"><para>AST_DEVICE_BUSY</para></enum>
1280 <enum name="4"><para>AST_DEVICE_INVALID</para></enum>
1281 <enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
1282 <enum name="6"><para>AST_DEVICE_RINGING</para></enum>
1283 <enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
1284 <enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
1285 </enumlist>
1286 </parameter>
1287 <parameter name="Paused">
1288 <enumlist>
1289 <enum name="0"/>
1290 <enum name="1"/>
1291 </enumlist>
1292 </parameter>
1293 <parameter name="PausedReason">
1294 <para>If set when paused, the reason the queue member was paused.</para>
1295 </parameter>
1296 <parameter name="Ringinuse">
1297 <enumlist>
1298 <enum name="0"/>
1299 <enum name="1"/>
1300 </enumlist>
1301 </parameter>
1302 <parameter name="Wrapuptime">
1303 <para>The Wrapup Time of the queue member. If this value is set will override the wrapup time of queue.</para>
1304 </parameter>
1305 </syntax>
1306 </managerEventInstance>
1307 </managerEvent>
1308 <managerEvent language="en_US" name="QueueMemberAdded">
1309 <managerEventInstance class="EVENT_FLAG_AGENT">
1310 <since>
1311 <version>12.0.0</version>
1312 </since>
1313 <synopsis>Raised when a member is added to the queue.</synopsis>
1314 <syntax>
1315 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1316 </syntax>
1317 <see-also>
1318 <ref type="managerEvent">QueueMemberRemoved</ref>
1319 <ref type="application">AddQueueMember</ref>
1320 </see-also>
1321 </managerEventInstance>
1322 </managerEvent>
1323 <managerEvent language="en_US" name="QueueMemberRemoved">
1324 <managerEventInstance class="EVENT_FLAG_AGENT">
1325 <since>
1326 <version>12.0.0</version>
1327 </since>
1328 <synopsis>Raised when a member is removed from the queue.</synopsis>
1329 <syntax>
1330 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1331 </syntax>
1332 <see-also>
1333 <ref type="managerEvent">QueueMemberAdded</ref>
1334 <ref type="application">RemoveQueueMember</ref>
1335 </see-also>
1336 </managerEventInstance>
1337 </managerEvent>
1338 <managerEvent language="en_US" name="QueueMemberPause">
1339 <managerEventInstance class="EVENT_FLAG_AGENT">
1340 <since>
1341 <version>12.2.0</version>
1342 </since>
1343 <synopsis>Raised when a member is paused/unpaused in the queue.</synopsis>
1344 <syntax>
1345 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1346 </syntax>
1347 <see-also>
1348 <ref type="application">PauseQueueMember</ref>
1349 <ref type="application">UnpauseQueueMember</ref>
1350 </see-also>
1351 </managerEventInstance>
1352 </managerEvent>
1353 <managerEvent language="en_US" name="QueueMemberPenalty">
1354 <managerEventInstance class="EVENT_FLAG_AGENT">
1355 <since>
1356 <version>12.0.0</version>
1357 </since>
1358 <synopsis>Raised when a member's penalty is changed.</synopsis>
1359 <syntax>
1360 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1361 </syntax>
1362 <see-also>
1363 <ref type="function">QUEUE_MEMBER</ref>
1364 </see-also>
1365 </managerEventInstance>
1366 </managerEvent>
1367 <managerEvent language="en_US" name="QueueMemberRinginuse">
1368 <managerEventInstance class="EVENT_FLAG_AGENT">
1369 <since>
1370 <version>12.0.0</version>
1371 </since>
1372 <synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
1373 <syntax>
1374 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1375 </syntax>
1376 <see-also>
1377 <ref type="function">QUEUE_MEMBER</ref>
1378 </see-also>
1379 </managerEventInstance>
1380 </managerEvent>
1381 <managerEvent language="en_US" name="QueueCallerJoin">
1382 <managerEventInstance class="EVENT_FLAG_AGENT">
1383 <since>
1384 <version>12.0.0</version>
1385 </since>
1386 <synopsis>Raised when a caller joins a Queue.</synopsis>
1387 <syntax>
1388 <channel_snapshot/>
1389 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1390 <parameter name="Position">
1391 <para>This channel's current position in the queue.</para>
1392 </parameter>
1393 <parameter name="Count">
1394 <para>The total number of channels in the queue.</para>
1395 </parameter>
1396 </syntax>
1397 <see-also>
1398 <ref type="managerEvent">QueueCallerLeave</ref>
1399 <ref type="application">Queue</ref>
1400 </see-also>
1401 </managerEventInstance>
1402 </managerEvent>
1403 <managerEvent language="en_US" name="QueueCallerLeave">
1404 <managerEventInstance class="EVENT_FLAG_AGENT">
1405 <since>
1406 <version>12.0.0</version>
1407 </since>
1408 <synopsis>Raised when a caller leaves a Queue.</synopsis>
1409 <syntax>
1410 <channel_snapshot/>
1411 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1412 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Count'])" />
1413 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1414 </syntax>
1415 <see-also>
1416 <ref type="managerEvent">QueueCallerJoin</ref>
1417 </see-also>
1418 </managerEventInstance>
1419 </managerEvent>
1420 <managerEvent language="en_US" name="QueueCallerAbandon">
1421 <managerEventInstance class="EVENT_FLAG_AGENT">
1422 <since>
1423 <version>12.0.0</version>
1424 </since>
1425 <synopsis>Raised when a caller abandons the queue.</synopsis>
1426 <syntax>
1427 <channel_snapshot/>
1428 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1429 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1430 <parameter name="OriginalPosition">
1431 <para>The channel's original position in the queue.</para>
1432 </parameter>
1433 <parameter name="HoldTime">
1434 <para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1435 </parameter>
1436 </syntax>
1437 </managerEventInstance>
1438 </managerEvent>
1439 <managerEvent language="en_US" name="AgentCalled">
1440 <managerEventInstance class="EVENT_FLAG_AGENT">
1441 <since>
1442 <version>12.0.0</version>
1443 </since>
1444 <synopsis>Raised when an queue member is notified of a caller in the queue.</synopsis>
1445 <syntax>
1446 <channel_snapshot/>
1447 <channel_snapshot prefix="Dest"/>
1448 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1449 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1450 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1451 </syntax>
1452 <see-also>
1453 <ref type="managerEvent">AgentRingNoAnswer</ref>
1454 <ref type="managerEvent">AgentComplete</ref>
1455 <ref type="managerEvent">AgentConnect</ref>
1456 </see-also>
1457 </managerEventInstance>
1458 </managerEvent>
1459 <managerEvent language="en_US" name="AgentRingNoAnswer">
1460 <managerEventInstance class="EVENT_FLAG_AGENT">
1461 <since>
1462 <version>12.0.0</version>
1463 </since>
1464 <synopsis>Raised when a queue member is notified of a caller in the queue and fails to answer.</synopsis>
1465 <syntax>
1466 <channel_snapshot/>
1467 <channel_snapshot prefix="Dest"/>
1468 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1469 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1470 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1471 <parameter name="RingTime">
1472 <para>The time the queue member was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1473 </parameter>
1474 </syntax>
1475 <see-also>
1476 <ref type="managerEvent">AgentCalled</ref>
1477 </see-also>
1478 </managerEventInstance>
1479 </managerEvent>
1480 <managerEvent language="en_US" name="AgentComplete">
1481 <managerEventInstance class="EVENT_FLAG_AGENT">
1482 <since>
1483 <version>12.0.0</version>
1484 </since>
1485 <synopsis>Raised when a queue member has finished servicing a caller in the queue.</synopsis>
1486 <syntax>
1487 <channel_snapshot/>
1488 <channel_snapshot prefix="Dest"/>
1489 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1490 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1491 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1492 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1493 <parameter name="TalkTime">
1494 <para>The time the queue member talked with the caller in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1495 </parameter>
1496 <parameter name="Reason">
1497 <enumlist>
1498 <enum name="caller"/>
1499 <enum name="agent"/>
1500 <enum name="transfer"/>
1501 </enumlist>
1502 </parameter>
1503 </syntax>
1504 <see-also>
1505 <ref type="managerEvent">AgentCalled</ref>
1506 <ref type="managerEvent">AgentConnect</ref>
1507 </see-also>
1508 </managerEventInstance>
1509 </managerEvent>
1510 <managerEvent language="en_US" name="AgentDump">
1511 <managerEventInstance class="EVENT_FLAG_AGENT">
1512 <since>
1513 <version>12.0.0</version>
1514 </since>
1515 <synopsis>Raised when a queue member hangs up on a caller in the queue.</synopsis>
1516 <syntax>
1517 <channel_snapshot/>
1518 <channel_snapshot prefix="Dest"/>
1519 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1520 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1521 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1522 </syntax>
1523 <see-also>
1524 <ref type="managerEvent">AgentCalled</ref>
1525 <ref type="managerEvent">AgentConnect</ref>
1526 </see-also>
1527 </managerEventInstance>
1528 </managerEvent>
1529 <managerEvent language="en_US" name="AgentConnect">
1530 <managerEventInstance class="EVENT_FLAG_AGENT">
1531 <since>
1532 <version>12.0.0</version>
1533 </since>
1534 <synopsis>Raised when a queue member answers and is bridged to a caller in the queue.</synopsis>
1535 <syntax>
1536 <channel_snapshot/>
1537 <channel_snapshot prefix="Dest"/>
1538 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1539 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1540 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1541 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
1542 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1543 </syntax>
1544 <see-also>
1545 <ref type="managerEvent">AgentCalled</ref>
1546 <ref type="managerEvent">AgentComplete</ref>
1547 <ref type="managerEvent">AgentDump</ref>
1548 </see-also>
1549 </managerEventInstance>
1550 </managerEvent>
1551 ***/
1552
1553enum {
1555 OPT_GO_ON = (1 << 1),
1564 OPT_NO_RETRY = (1 << 10),
1565 OPT_RINGING = (1 << 11),
1576};
1577
1578enum {
1583 /* note: this entry _MUST_ be the last one in the enum */
1586
1611
1612
1614 AQMFLAG_PAUSED = (1 << 1),
1615 AQMFLAG_REASON = (1 << 2),
1616};
1617
1620 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1621};
1622
1627
1628enum {
1637};
1638
1639enum {
1644
1650};
1651
1652static const struct strategy {
1654 const char *name;
1655} strategies[] = {
1656 { QUEUE_STRATEGY_RINGALL, "ringall" },
1657 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
1658 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
1659 { QUEUE_STRATEGY_RANDOM, "random" },
1660 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
1661 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
1662 { QUEUE_STRATEGY_LINEAR, "linear" },
1663 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
1664 { QUEUE_STRATEGY_RRORDERED, "rrordered"},
1666
1667static const struct autopause {
1669 const char *name;
1670} autopausesmodes [] = {
1671 { QUEUE_AUTOPAUSE_OFF,"no" },
1672 { QUEUE_AUTOPAUSE_ON, "yes" },
1673 { QUEUE_AUTOPAUSE_ALL,"all" },
1675
1676#define DEFAULT_RETRY 5
1677#define DEFAULT_TIMEOUT 15
1678#define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
1679#define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
1680/*!
1681 * \brief The minimum number of seconds between position announcements.
1682 * \note The default value of 15 provides backwards compatibility.
1683 */
1684#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15
1685
1686#define MAX_QUEUE_BUCKETS 53
1687
1688#define RES_OKAY 0 /*!< Action completed */
1689#define RES_EXISTS (-1) /*!< Entry already exists */
1690#define RES_OUTOFMEMORY (-2) /*!< Out of memory */
1691#define RES_NOSUCHQUEUE (-3) /*!< No such queue */
1692#define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
1693#define RES_NOT_CALLER (-5) /*!< Caller not found */
1694
1695static char *app = "Queue";
1696
1697static char *app_aqm = "AddQueueMember" ;
1698
1699static char *app_rqm = "RemoveQueueMember" ;
1700
1701static char *app_pqm = "PauseQueueMember" ;
1702
1703static char *app_upqm = "UnpauseQueueMember" ;
1704
1705static char *app_ql = "QueueLog" ;
1706
1707static char *app_qupd = "QueueUpdate";
1708
1709/*! \brief Persistent Members astdb family */
1710static const char * const pm_family = "Queue/PersistentMembers";
1711
1712/*! \brief queues.conf [general] option */
1714
1715/*! \brief Records that one or more queues use weight */
1716static int use_weight;
1717
1718/*! \brief queues.conf [general] option */
1720
1721/*! \brief queues.conf [general] option */
1723
1724/*! \brief queues.conf [general] option */
1726
1727/*! \brief queuerules.conf [general] option */
1729
1730/*! \brief Subscription to device state change messages */
1732
1733/*! \brief queues.conf [general] option */
1735
1736/*! \brief queues.conf [general] option */
1738
1739/*! \brief queues.conf [general] option */
1741
1742/*! \brief queues.conf [general] option */
1744
1745/*! \brief queues.conf [general] option */
1747
1748/*! \brief name of the ringinuse field in the realtime database */
1750
1751/*! \brief does realtime backend support reason_paused */
1753
1764};
1765
1766static const struct {
1768 char *text;
1769} queue_results[] = {
1770 { QUEUE_UNKNOWN, "UNKNOWN" },
1771 { QUEUE_TIMEOUT, "TIMEOUT" },
1772 { QUEUE_JOINEMPTY,"JOINEMPTY" },
1773 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
1774 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
1775 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
1776 { QUEUE_FULL, "FULL" },
1777 { QUEUE_CONTINUE, "CONTINUE" },
1778 { QUEUE_WITHDRAW, "WITHDRAW" },
1780
1784};
1785
1786/*! \brief We define a custom "local user" structure because we
1787 * use it not only for keeping track of what is in use but
1788 * also for keeping track of who we're dialing.
1789 *
1790 * There are two "links" defined in this structure, q_next and call_next.
1791 * q_next links ALL defined callattempt structures into a linked list. call_next is
1792 * a link which allows for a subset of the callattempts to be traversed. This subset
1793 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
1794 * also is helpful so that queue logs are always accurate in the case where a call to
1795 * a member times out, especially if using the ringall strategy.
1796*/
1797
1802 char interface[256]; /*!< An Asterisk dial string (not a channel name) */
1805 /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
1807 /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
1809 /*! TRUE if the connected line update is blocked. */
1811 /*! TRUE if caller id is not available for connected line */
1812 unsigned int dial_callerid_absent:1;
1813 /*! TRUE if the call is still active */
1814 unsigned int stillgoing:1;
1816 /*! Original channel name. Must be freed. Could be NULL if allocation failed. */
1818};
1819
1820
1822 struct call_queue *parent; /*!< What queue is our parent */
1823 char moh[MAX_MUSICCLASS]; /*!< Name of musiconhold to be used */
1824 char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
1825 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
1826 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
1827 const char *predial_callee; /*!< Gosub app arguments for outgoing calls. NULL if not supplied. */
1828 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
1829 int pos; /*!< Where we are in the queue */
1830 int prio; /*!< Our priority */
1831 int last_pos_said; /*!< Last position we told the user */
1832 int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
1833 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
1834 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
1835 time_t last_pos; /*!< Last time we told the user their position */
1836 int opos; /*!< Where we started in the queue */
1837 int handled; /*!< Whether our call was handled */
1838 int pending; /*!< Non-zero if we are attempting to call a member */
1839 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
1840 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
1841 int raise_penalty; /*!< Float lower penalty members to a minimum penalty */
1842 int raise_respect_min; /*!< A switch raise_penalty should respect min_penalty not just max_penalty */
1843 int linpos; /*!< If using linear strategy, what position are we at? */
1844 int linwrapped; /*!< Is the linpos wrapped? */
1845 time_t start; /*!< When we started holding */
1846 time_t expire; /*!< When this entry should expire (time out of queue) */
1847 int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
1848 unsigned int withdraw:1; /*!< Should this call exit the queue at its next iteration? Used for QueueWithdrawCaller */
1849 char *withdraw_info; /*!< Optional info passed by the caller of QueueWithdrawCaller */
1850 struct ast_channel *chan; /*!< Our channel */
1851 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
1852 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
1853 struct queue_ent *next; /*!< The next queue entry */
1854};
1855
1856struct member {
1857 char interface[AST_CHANNEL_NAME]; /*!< Technology/Location to dial to reach this member*/
1858 char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
1859 char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
1860 char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */
1861 int state_id; /*!< Extension state callback id (if using hint) */
1862 char membername[80]; /*!< Member name to use in queue logs */
1863 int penalty; /*!< Are we a last resort? */
1864 int calls; /*!< Number of calls serviced by this member */
1865 int dynamic; /*!< Are we dynamically added? */
1866 int realtime; /*!< Is this member realtime? */
1867 int status; /*!< Status of queue member */
1868 int paused; /*!< Are we paused (not accepting calls)? */
1869 char reason_paused[80]; /*!< Reason of paused if member is paused */
1870 int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */
1871 int callcompletedinsl; /*!< Whether the current call was completed within service level */
1872 int wrapuptime; /*!< Wrapup Time */
1873 time_t starttime; /*!< The time at which the member answered the current caller. */
1874 time_t lastcall; /*!< When last successful call was hungup */
1875 time_t lastpause; /*!< When started the last pause */
1876 time_t logintime; /*!< The time when started the login */
1877 struct call_queue *lastqueue; /*!< Last queue we received a call */
1878 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
1879 unsigned int delme:1; /*!< Flag to delete entry on reload */
1880 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
1881 unsigned int ringinuse:1; /*!< Flag to ring queue members even if their status is 'inuse' */
1882};
1883
1893};
1894
1898};
1899
1900/* values used in multi-bit flags in call_queue */
1901#define ANNOUNCEHOLDTIME_ALWAYS 1
1902#define ANNOUNCEHOLDTIME_ONCE 2
1903#define QUEUE_EVENT_VARIABLES 3
1904
1906 int time; /*!< Number of seconds that need to pass before applying this rule */
1907 int max_value; /*!< The amount specified in the penalty rule for max penalty */
1908 int min_value; /*!< The amount specified in the penalty rule for min penalty */
1909 int raise_value; /*!< The amount specified in the penalty rule for min penalty */
1910 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
1911 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1912 int raise_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1913 int raise_respect_min; /*!< A switch raise_penalty should respect min_penalty not just max_penalty */
1914 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
1915};
1916
1917#define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
1918#define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
1919#define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
1920#define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
1921
1924 /*! Queue name */
1926 /*! Music on Hold class */
1928 /*! Announcement to play when call is answered */
1930 /*! Exit context */
1932 /*! Gosub to run upon member connection */
1934 /*! Default rule to use if none specified in call to Queue() */
1936 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
1938 /*! Sound file: "There are currently" (def. queue-thereare) */
1940 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
1942 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
1944 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
1946 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
1948 /*! Sound file: "minutes." (def. queue-minutes) */
1950 /*! Sound file: "minute." (def. queue-minute) */
1952 /*! Sound file: "seconds." (def. queue-seconds) */
1954 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
1956 /*! Sound file: Custom announce for caller, no default */
1958 /*! Sound file: "Hold time" (def. queue-reporthold) */
1961 /*! Sound files: Custom announce, no default */
1963 unsigned int dead:1;
1964 unsigned int ringinuse:1;
1965 unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
1966 unsigned int setinterfacevar:1;
1967 unsigned int setqueuevar:1;
1968 unsigned int setqueueentryvar:1;
1969 unsigned int reportholdtime:1;
1970 unsigned int wrapped:1;
1971 unsigned int timeoutrestart:1;
1972 unsigned int announceholdtime:2;
1973 unsigned int announceposition:3;
1974 unsigned int announceposition_only_up:1; /*!< Only announce position if it has improved */
1976 unsigned int realtime:1;
1977 unsigned int found:1;
1979 unsigned int autopausebusy:1;
1980 unsigned int autopauseunavail:1;
1983 int announcepositionlimit; /*!< How many positions we announce? */
1984 int announcefrequency; /*!< How often to announce their position */
1985 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
1986 int periodicannouncestartdelay; /*!< How long into the queue should the periodic accouncement start */
1987 int periodicannouncefrequency; /*!< How often to play periodic announcement */
1988 int numperiodicannounce; /*!< The number of periodic announcements configured */
1989 int randomperiodicannounce; /*!< Are periodic announcements randomly chosen */
1990 int roundingseconds; /*!< How many seconds do we round to? */
1991 int holdtime; /*!< Current avg holdtime, based on an exponential average */
1992 int talktime; /*!< Current avg talktime, based on the same exponential average */
1993 int callscompleted; /*!< Number of queue calls completed */
1994 int callsabandoned; /*!< Number of queue calls abandoned */
1995 int callsabandonedinsl; /*!< Number of queue calls abandoned in servicelevel */
1996 int servicelevel; /*!< seconds setting for servicelevel*/
1997 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
1998 char monfmt[8]; /*!< Format to use when recording calls */
1999 int count; /*!< How many entries */
2000 int maxlen; /*!< Max number of entries */
2001 int wrapuptime; /*!< Wrapup Time */
2002 int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
2003
2004 int retry; /*!< Retry calling everyone after this amount of time */
2005 int timeout; /*!< How long to wait for an answer */
2006 int weight; /*!< Respective weight */
2007 int autopause; /*!< Auto pause queue members if they fail to answer */
2008 int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
2009 int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
2010
2011 /* Queue strategy things */
2012 int rrpos; /*!< Round Robin - position */
2013 int memberdelay; /*!< Seconds to delay connecting member to caller */
2014 int autofill; /*!< Ignore the head call status and ring an available agent */
2015
2016 int log_restricted_caller_id:1; /*!< Whether log Restricted Caller ID */
2017
2018 struct ao2_container *members; /*!< Head of the list of members */
2019 struct queue_ent *head; /*!< Head of the list of callers */
2020 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
2021 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
2022};
2023
2025 char name[80];
2028};
2029
2031
2032static struct ao2_container *queues;
2033
2034static void update_realtime_members(struct call_queue *q);
2035static struct member *interface_exists(struct call_queue *q, const char *interface);
2036static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
2037static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime);
2038
2039static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
2040/*! \brief sets the QUEUESTATUS channel variable */
2041static void set_queue_result(struct ast_channel *chan, enum queue_result res)
2042{
2043 int i;
2044
2045 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
2046 if (queue_results[i].id == res) {
2047 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
2048 return;
2049 }
2050 }
2051}
2052
2053static const char *int2strat(int strategy)
2054{
2055 int x;
2056
2057 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2058 if (strategy == strategies[x].strategy) {
2059 return strategies[x].name;
2060 }
2061 }
2062
2063 return "<unknown>";
2064}
2065
2066static int strat2int(const char *strategy)
2067{
2068 int x;
2069
2070 for (x = 0; x < ARRAY_LEN(strategies); x++) {
2071 if (!strcasecmp(strategy, strategies[x].name)) {
2072 return strategies[x].strategy;
2073 }
2074 }
2075
2076 return -1;
2077}
2078
2079static int autopause2int(const char *autopause)
2080{
2081 int x;
2082 /*This 'double check' that default value is OFF */
2084 return QUEUE_AUTOPAUSE_OFF;
2085 }
2086
2087 /*This 'double check' is to ensure old values works */
2088 if(ast_true(autopause)) {
2089 return QUEUE_AUTOPAUSE_ON;
2090 }
2091
2092 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
2093 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
2094 return autopausesmodes[x].autopause;
2095 }
2096 }
2097
2098 /*This 'double check' that default value is OFF */
2099 return QUEUE_AUTOPAUSE_OFF;
2100}
2101
2102static int queue_hash_cb(const void *obj, const int flags)
2103{
2104 const struct call_queue *q = obj;
2105
2106 return ast_str_case_hash(q->name);
2107}
2108
2109static int queue_cmp_cb(void *obj, void *arg, int flags)
2110{
2111 struct call_queue *q = obj, *q2 = arg;
2112 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2113}
2114
2115/*!
2116 * \brief Return wrapuptime
2117 *
2118 * This function checks if wrapuptime in member is set and return this value.
2119 * Otherwise return value the wrapuptime in the queue configuration
2120 * \return integer value
2121 */
2122static int get_wrapuptime(struct call_queue *q, struct member *member)
2123{
2124 if (member->wrapuptime) {
2125 return member->wrapuptime;
2126 }
2127 return q->wrapuptime;
2128}
2129
2130/*! \internal
2131 * \brief ao2_callback, Decreases queuepos of all followers with a queuepos greater than arg.
2132 * \param obj the member being acted on
2133 * \param arg pointer to an integer containing the position value that was removed and requires reduction for anything above
2134 * \param flag unused
2135 */
2136static int queue_member_decrement_followers(void *obj, void *arg, int flag)
2137{
2138 struct member *mem = obj;
2139 int *decrement_followers_after = arg;
2140
2141 if (mem->queuepos > *decrement_followers_after) {
2142 mem->queuepos--;
2143 }
2144
2145 return 0;
2146}
2147
2148/*! \internal
2149 * \brief ao2_callback, finds members in a queue marked for deletion and in a cascading fashion runs queue_member_decrement_followers
2150 * on them. This callback should always be ran before performing mass unlinking of delmarked members from queues.
2151 * \param obj member being acted on
2152 * \param arg pointer to the queue members are being removed from
2153 * \param flag unused
2154 */
2155static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
2156{
2157 struct member *mem = obj;
2158 struct call_queue *queue = arg;
2159 int rrpos = mem->queuepos;
2160
2161 if (mem->delme) {
2163 }
2164
2165 return 0;
2166}
2167
2168/*! \internal
2169 * \brief Use this to decrement followers during removal of a member
2170 * \param queue which queue the member is being removed from
2171 * \param mem which member is being removed from the queue
2172 */
2173static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
2174{
2175 int pos = mem->queuepos;
2176
2177 /* If the position being removed is less than the current place in the queue, reduce the queue position by one so that we don't skip the member
2178 * who would have been next otherwise. */
2179 if (pos < queue->rrpos) {
2180 queue->rrpos--;
2181 }
2182
2184}
2185
2186#define queue_ref(q) ao2_bump(q)
2187#define queue_unref(q) ({ ao2_cleanup(q); NULL; })
2188#define queue_t_ref(q, tag) ao2_t_bump(q, tag)
2189#define queue_t_unref(q, tag) ({ ao2_t_cleanup(q, tag); NULL; })
2190#define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
2191#define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
2192
2193/*! \brief Set variables of queue */
2194static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
2195{
2196 char interfacevar[256]="";
2197 float sl = 0;
2198
2199 ao2_lock(q);
2200
2201 if (q->setqueuevar) {
2202 sl = 0;
2203 if (q->callscompleted > 0) {
2204 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2205 }
2206
2207 snprintf(interfacevar, sizeof(interfacevar),
2208 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2210
2211 ao2_unlock(q);
2212
2213 pbx_builtin_setvar_multiple(chan, interfacevar);
2214 } else {
2215 ao2_unlock(q);
2216 }
2217}
2218
2219/*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
2220static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
2221{
2222 struct queue_ent *cur;
2223
2224 if (!q || !new)
2225 return;
2226 if (prev) {
2227 cur = prev->next;
2228 prev->next = new;
2229 } else {
2230 cur = q->head;
2231 q->head = new;
2232 }
2233 new->next = cur;
2234
2235 /* every queue_ent must have a reference to it's parent call_queue, this
2236 * reference does not go away until the end of the queue_ent's life, meaning
2237 * that even when the queue_ent leaves the call_queue this ref must remain. */
2238 if (!new->parent) {
2239 queue_ref(q);
2240 new->parent = q;
2241 }
2242 new->pos = ++(*pos);
2243 new->opos = *pos;
2244}
2245
2247{
2249 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2250 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2251
2252 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2253 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2254 if (!channel_string || !event_string) {
2255 return NULL;
2256 }
2257
2259 "%s"
2260 "%s",
2261 ast_str_buffer(channel_string),
2262 ast_str_buffer(event_string));
2263}
2264
2266{
2267 return queue_channel_to_ami("QueueCallerJoin", message);
2268}
2269
2271{
2272 return queue_channel_to_ami("QueueCallerLeave", message);
2273}
2274
2276{
2277 return queue_channel_to_ami("QueueCallerAbandon", message);
2278}
2279
2280STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type,
2282 );
2283STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type,
2285 );
2286STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type,
2288 );
2289
2291{
2292 struct ast_json_payload *payload = stasis_message_data(message);
2293 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2294
2295 event_string = ast_manager_str_from_json_object(payload->json, NULL);
2296 if (!event_string) {
2297 return NULL;
2298 }
2299
2301 "%s",
2302 ast_str_buffer(event_string));
2303}
2304
2306{
2307 return queue_member_to_ami("QueueMemberStatus", message);
2308}
2309
2311{
2312 return queue_member_to_ami("QueueMemberAdded", message);
2313}
2314
2316{
2317 return queue_member_to_ami("QueueMemberRemoved", message);
2318}
2319
2321{
2322 return queue_member_to_ami("QueueMemberPause", message);
2323}
2324
2326{
2327 return queue_member_to_ami("QueueMemberPenalty", message);
2328}
2329
2331{
2332 return queue_member_to_ami("QueueMemberRinginuse", message);
2333}
2334
2335STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type,
2337 );
2338STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type,
2340 );
2341STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type,
2343 );
2344STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type,
2346 );
2347STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type,
2349 );
2350STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type,
2352 );
2353
2355{
2358 struct ast_channel_snapshot *agent;
2359 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2360 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2361 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2362
2364 if (caller) {
2365 caller_event_string = ast_manager_build_channel_state_string(caller);
2366 if (!caller_event_string) {
2367 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2368 return NULL;
2369 }
2370 }
2371
2372 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2373 if (agent) {
2374 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2375 if (!agent_event_string) {
2376 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2377 return NULL;
2378 }
2379 }
2380
2382 if (!event_string) {
2383 return NULL;
2384 }
2385
2387 "%s"
2388 "%s"
2389 "%s",
2390 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2391 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2392 ast_str_buffer(event_string));
2393}
2394
2396{
2397 return queue_multi_channel_to_ami("AgentCalled", message);
2398}
2399
2401{
2402 return queue_multi_channel_to_ami("AgentConnect", message);
2403}
2404
2406{
2407 return queue_multi_channel_to_ami("AgentComplete", message);
2408}
2409
2411{
2412 return queue_multi_channel_to_ami("AgentDump", message);
2413}
2414
2416{
2417 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2418}
2419
2420STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type,
2422 );
2423STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type,
2425 );
2426STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type,
2428 );
2431 );
2432STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type,
2434 );
2435
2437 struct ast_channel_snapshot *caller_snapshot,
2438 struct ast_channel_snapshot *agent_snapshot,
2439 struct stasis_message_type *type, struct ast_json *blob)
2440{
2441 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2442 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2443
2444 if (!type) {
2445 return;
2446 }
2447
2448 payload = ast_multi_channel_blob_create(blob);
2449 if (!payload) {
2450 return;
2451 }
2452
2453 if (caller_snapshot) {
2454 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2455 } else {
2456 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2457 }
2458
2459 if (agent_snapshot) {
2460 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2461 }
2462
2463 msg = stasis_message_create(type, payload);
2464 if (!msg) {
2465 return;
2466 }
2467
2468 stasis_publish(topic, msg);
2469}
2470
2471static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent,
2472 struct stasis_message_type *type, struct ast_json *blob)
2473{
2474 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2475 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2476
2477 ast_channel_lock(caller);
2478 caller_snapshot = ast_channel_snapshot_create(caller);
2479 ast_channel_unlock(caller);
2480 ast_channel_lock(agent);
2481 agent_snapshot = ast_channel_snapshot_create(agent);
2482 ast_channel_unlock(agent);
2483
2484 if (!caller_snapshot || !agent_snapshot) {
2485 return;
2486 }
2487
2489 agent_snapshot, type, blob);
2490}
2491
2492/*!
2493 * \internal
2494 * \brief Publish the member blob.
2495 * \since 12.0.0
2496 *
2497 * \param type Stasis message type to publish.
2498 * \param blob The information being published.
2499 *
2500 * \note The json blob reference is passed to this function.
2501 */
2503{
2504 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2505 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2506
2507 if (!blob || !type) {
2508 ast_json_unref(blob);
2509 return;
2510 }
2511
2512 payload = ast_json_payload_create(blob);
2513 ast_json_unref(blob);
2514 if (!payload) {
2515 return;
2516 }
2517
2518 msg = stasis_message_create(type, payload);
2519 if (!msg) {
2520 return;
2521 }
2522
2524}
2525
2526static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
2527{
2528 return ast_json_pack("{s: s, s: s, s: s, s: s, s: s, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: i, s: s, s: i, s: i}",
2529 "Queue", q->name,
2530 "MemberName", mem->membername,
2531 "Interface", mem->interface,
2532 "StateInterface", mem->state_interface,
2533 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2534 "Penalty", mem->penalty,
2535 "CallsTaken", mem->calls,
2536 "LastCall", (int)mem->lastcall,
2537 "LastPause", (int)mem->lastpause,
2538 "LoginTime", (int)mem->logintime,
2539 "InCall", mem->starttime ? 1 : 0,
2540 "Status", mem->status,
2541 "Paused", mem->paused,
2542 "PausedReason", mem->reason_paused,
2543 "Ringinuse", mem->ringinuse,
2544 "Wrapuptime", mem->wrapuptime);
2545}
2546
2547/*! \brief Check if members are available
2548 *
2549 * This function checks to see if members are available to be called. If any member
2550 * is available, the function immediately returns 0. If no members are available,
2551 * then -1 is returned.
2552 */
2553static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate, int raise_respect_min)
2554{
2555 struct member *member;
2556 struct ao2_iterator mem_iter;
2557
2558 ao2_lock(q);
2559 mem_iter = ao2_iterator_init(q->members, 0);
2560 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2561 int penalty = member->penalty;
2562 if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2563 /* Check if we should respect minimum penalty threshold */
2564 if (raise_respect_min && penalty < min_penalty) {
2565 ast_debug(4, "%s penalty %d not raised (below min %d)\n", member->membername, penalty, min_penalty);
2566 } else {
2567 ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2568 penalty = raise_penalty;
2569 }
2570 }
2571 if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2572 if (conditions & QUEUE_EMPTY_PENALTY) {
2573 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2574 continue;
2575 }
2576 }
2577
2578 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2579 case AST_DEVICE_INVALID:
2580 if (conditions & QUEUE_EMPTY_INVALID) {
2581 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2582 break;
2583 }
2584 goto default_case;
2586 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2587 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2588 break;
2589 }
2590 goto default_case;
2591 case AST_DEVICE_INUSE:
2592 if (conditions & QUEUE_EMPTY_INUSE) {
2593 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2594 break;
2595 }
2596 goto default_case;
2597 case AST_DEVICE_RINGING:
2598 if (conditions & QUEUE_EMPTY_RINGING) {
2599 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2600 break;
2601 }
2602 goto default_case;
2603 case AST_DEVICE_UNKNOWN:
2604 if (conditions & QUEUE_EMPTY_UNKNOWN) {
2605 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2606 break;
2607 }
2608 /* Fall-through */
2609 default:
2610 default_case:
2611 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2612 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2613 break;
2614 } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2615 && member->lastcall
2616 && get_wrapuptime(q, member)
2617 && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2618 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2619 member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2620 break;
2621 } else {
2622 ao2_ref(member, -1);
2623 ao2_iterator_destroy(&mem_iter);
2624 ao2_unlock(q);
2625 ast_debug(4, "%s is available.\n", member->membername);
2626 return 0;
2627 }
2628 break;
2629 }
2630 }
2631 ao2_iterator_destroy(&mem_iter);
2632 ao2_unlock(q);
2633
2634 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2635 /* member state still may be RINGING due to lag in event message - check again with device state */
2636 return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1, raise_respect_min);
2637 }
2638 return -1;
2639}
2640
2641/*
2642 * A "pool" of member objects that calls are currently pending on. If an
2643 * agent is a member of multiple queues it's possible for that agent to be
2644 * called by each of the queues at the same time. This happens because device
2645 * state is slow to notify the queue app of one of it's member's being rung.
2646 * This "pool" allows us to track which members are currently being rung while
2647 * we wait on the device state change.
2648 */
2650#define MAX_CALL_ATTEMPT_BUCKETS 353
2651
2652static int pending_members_hash(const void *obj, const int flags)
2653{
2654 const struct member *object;
2655 const char *key;
2656
2657 switch (flags & OBJ_SEARCH_MASK) {
2658 case OBJ_SEARCH_KEY:
2659 key = obj;
2660 break;
2661 case OBJ_SEARCH_OBJECT:
2662 object = obj;
2663 key = object->interface;
2664 break;
2665 default:
2666 ast_assert(0);
2667 return 0;
2668 }
2669 return ast_str_case_hash(key);
2670}
2671
2672static int pending_members_cmp(void *obj, void *arg, int flags)
2673{
2674 const struct member *object_left = obj;
2675 const struct member *object_right = arg;
2676 const char *right_key = arg;
2677 int cmp;
2678
2679 switch (flags & OBJ_SEARCH_MASK) {
2680 case OBJ_SEARCH_OBJECT:
2681 right_key = object_right->interface;
2682 /* Fall through */
2683 case OBJ_SEARCH_KEY:
2684 cmp = strcasecmp(object_left->interface, right_key);
2685 break;
2687 /* Not supported by container. */
2688 ast_assert(0);
2689 return 0;
2690 default:
2691 cmp = 0;
2692 break;
2693 }
2694 if (cmp) {
2695 return 0;
2696 }
2697 return CMP_MATCH;
2698}
2699
2700static void pending_members_remove(struct member *mem)
2701{
2702 ast_debug(3, "Removed %s from pending_members\n", mem->membername);
2704}
2705
2706/*! \brief set a member's status based on device state of that member's state_interface.
2707 *
2708 * Lock interface list find sc, iterate through each queues queue_member list for member to
2709 * update state inside queues
2710*/
2711static void update_status(struct call_queue *q, struct member *m, const int status)
2712{
2713 if (m->status != status) {
2714 /* If this member has transitioned to being available then update their queue
2715 * information. If they are currently in a call then the leg to the agent will be
2716 * considered done and the call finished.
2717 */
2720 }
2721
2722 m->status = status;
2723
2724 /* Remove the member from the pending members pool only when the status changes.
2725 * This is not done unconditionally because we can occasionally see multiple
2726 * device state notifications of not in use after a previous call has ended,
2727 * including after we have initiated a new call. This is more likely to
2728 * happen when there is latency in the connection to the member.
2729 */
2731
2732 queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2733 }
2734}
2735
2736/*!
2737 * \internal
2738 * \brief Determine if a queue member is available
2739 * \retval 1 if the member is available
2740 * \retval 0 if the member is not available
2741 */
2742static int is_member_available(struct call_queue *q, struct member *mem)
2743{
2744 int available = 0;
2745 int wrapuptime;
2746
2747 switch (mem->status) {
2748 case AST_DEVICE_INVALID:
2750 break;
2751 case AST_DEVICE_INUSE:
2752 case AST_DEVICE_BUSY:
2753 case AST_DEVICE_RINGING:
2755 case AST_DEVICE_ONHOLD:
2756 if (!mem->ringinuse) {
2757 break;
2758 }
2759 /* else fall through */
2761 case AST_DEVICE_UNKNOWN:
2762 if (!mem->paused) {
2763 available = 1;
2764 }
2765 break;
2766 }
2767
2768 /* Let wrapuptimes override device state availability */
2769 wrapuptime = get_wrapuptime(q, mem);
2770 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2771 available = 0;
2772 }
2773 return available;
2774}
2775
2776/*! \brief set a member's status based on device state of that member's interface*/
2777static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
2778{
2779 struct ao2_iterator miter, qiter;
2780 struct ast_device_state_message *dev_state;
2781 struct member *m;
2782 struct call_queue *q;
2783 char interface[80], *slash_pos;
2784 int found = 0; /* Found this member in any queue */
2785 int found_member; /* Found this member in this queue */
2786 int avail = 0; /* Found an available member in this queue */
2787
2789 return;
2790 }
2791
2792 dev_state = stasis_message_data(msg);
2793 if (dev_state->eid) {
2794 /* ignore non-aggregate states */
2795 return;
2796 }
2797
2798 qiter = ao2_iterator_init(queues, 0);
2799 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2800 ao2_lock(q);
2801
2802 avail = 0;
2803 found_member = 0;
2804 miter = ao2_iterator_init(q->members, 0);
2805 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2806 if (!found_member) {
2807 ast_copy_string(interface, m->state_interface, sizeof(interface));
2808
2809 if ((slash_pos = strchr(interface, '/'))) {
2810 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2811 *slash_pos = '\0';
2812 }
2813 }
2814
2815 if (!strcasecmp(interface, dev_state->device)) {
2816 found_member = 1;
2817 update_status(q, m, dev_state->state);
2818 }
2819 }
2820
2821 /* check every member until we find one NOT_INUSE */
2822 if (!avail) {
2823 avail = is_member_available(q, m);
2824 }
2825 if (avail && found_member) {
2826 /* early exit as we've found an available member and the member of interest */
2827 ao2_ref(m, -1);
2828 break;
2829 }
2830 }
2831
2832 if (found_member) {
2833 found = 1;
2834 if (avail) {
2836 } else {
2838 }
2839 }
2840
2841 ao2_iterator_destroy(&miter);
2842
2843 ao2_unlock(q);
2844 queue_t_unref(q, "Done with iterator");
2845 }
2846 ao2_iterator_destroy(&qiter);
2847
2848 if (found) {
2849 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2850 dev_state->device,
2851 dev_state->state,
2852 ast_devstate2str(dev_state->state));
2853 } else {
2854 ast_debug(3, "Device '%s' changed to state '%u' (%s) but we don't care because they're not a member of any queue.\n",
2855 dev_state->device,
2856 dev_state->state,
2857 ast_devstate2str(dev_state->state));
2858 }
2859
2860 return;
2861}
2862
2863/*! \brief Helper function which converts from extension state to device state values */
2865{
2866 switch (state) {
2869 break;
2872 break;
2873 case AST_EXTENSION_BUSY:
2875 break;
2878 break;
2881 break;
2884 break;
2887 break;
2890 break;
2893 default:
2895 break;
2896 }
2897
2898 return state;
2899}
2900
2901/*!
2902 * \brief Returns if one context includes another context
2903 *
2904 * \param parent Parent context to search for child
2905 * \param child Context to check for inclusion in parent
2906 *
2907 * This function recursively checks if the context child is included in the context parent.
2908 *
2909 * \retval 1 if child is included in parent
2910 * \retval 0 if not
2911 */
2912static int context_included(const char *parent, const char *child);
2913static int context_included(const char *parent, const char *child)
2914{
2915 struct ast_context *c = NULL;
2916
2917 c = ast_context_find(parent);
2918 if (!c) {
2919 /* well, if parent doesn't exist, how can the child be included in it? */
2920 return 0;
2921 }
2922 if (!strcmp(ast_get_context_name(c), parent)) {
2923 /* found the context of the hint app_queue is using. Now, see
2924 if that context includes the one that just changed state */
2925 struct ast_include *inc = NULL;
2926
2927 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2928 const char *includename = ast_get_include_name(inc);
2929 if (!strcasecmp(child, includename)) {
2930 return 1;
2931 }
2932 /* recurse on this context, for nested includes. The
2933 PBX extension parser will prevent infinite recursion. */
2934 if (context_included(includename, child)) {
2935 return 1;
2936 }
2937 }
2938 }
2939 return 0;
2940}
2941
2942static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
2943{
2944 struct ao2_iterator miter, qiter;
2945 struct member *m;
2946 struct call_queue *q;
2947 int state = info->exten_state;
2948 int found = 0, device_state = extensionstate2devicestate(state);
2949
2950 /* only interested in extension state updates involving device states */
2951 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2952 return 0;
2953 }
2954
2955 qiter = ao2_iterator_init(queues, 0);
2956 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2957 ao2_lock(q);
2958
2959 miter = ao2_iterator_init(q->members, 0);
2960 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2961 if (!strcmp(m->state_exten, exten) &&
2963 /* context could be included in m->state_context. We need to check. */
2964 found = 1;
2965 update_status(q, m, device_state);
2966 }
2967 }
2968 ao2_iterator_destroy(&miter);
2969
2970 ao2_unlock(q);
2971 queue_t_unref(q, "Done with iterator");
2972 }
2973 ao2_iterator_destroy(&qiter);
2974
2975 if (found) {
2976 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2977 } else {
2978 ast_debug(3, "Extension '%s@%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n",
2979 exten, context, device_state, ast_devstate2str(device_state));
2980 }
2981
2982 return 0;
2983}
2984
2985/*! \brief Return the current state of a member */
2986static int get_queue_member_status(struct member *cur)
2987{
2989}
2990
2991static void destroy_queue_member_cb(void *obj)
2992{
2993 struct member *mem = obj;
2994
2995 if (mem->state_id != -1) {
2997 }
2998}
2999
3000/*! \brief allocate space for new queue member and set fields based on parameters passed */
3001static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
3002{
3003 struct member *cur;
3004
3005 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
3006 cur->ringinuse = ringinuse;
3007 cur->penalty = penalty;
3008 cur->paused = paused;
3009 cur->wrapuptime = wrapuptime;
3010 if (paused) {
3011 time(&cur->lastpause); /* Update time of last pause */
3012 }
3013 time(&cur->logintime);
3014 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
3017 } else {
3019 }
3021 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
3022 } else {
3023 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
3024 }
3025 if (!strchr(cur->interface, '/')) {
3026 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
3027 }
3028 if (!strncmp(cur->state_interface, "hint:", 5)) {
3029 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
3030 char *exten = strsep(&context, "@") + 5;
3031
3032 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
3033 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
3034
3036 } else {
3037 cur->state_id = -1;
3038 }
3039 cur->status = get_queue_member_status(cur);
3040 }
3041
3042 return cur;
3043}
3044
3045
3046static int compress_char(const char c)
3047{
3048 if (c < 32) {
3049 return 0;
3050 } else if (c > 96) {
3051 return c - 64;
3052 }
3053 return c - 32;
3054}
3055
3056static int member_hash_fn(const void *obj, const int flags)
3057{
3058 const struct member *mem = obj;
3059 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
3060 const char *chname = strchr(interface, '/');
3061 int ret = 0, i;
3062
3063 if (!chname) {
3064 chname = interface;
3065 }
3066 for (i = 0; i < 5 && chname[i]; i++) {
3067 ret += compress_char(chname[i]) << (i * 6);
3068 }
3069 return ret;
3070}
3071
3072static int member_cmp_fn(void *obj1, void *obj2, int flags)
3073{
3074 struct member *mem1 = obj1;
3075 struct member *mem2 = obj2;
3076 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
3077
3078 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
3079}
3080
3081/*!
3082 * \brief Initialize Queue default values.
3083 * \note the queue's lock must be held before executing this function
3084*/
3085static void init_queue(struct call_queue *q)
3086{
3087 int i;
3088 struct penalty_rule *pr_iter;
3089
3090 q->dead = 0;
3091 q->retry = DEFAULT_RETRY;
3093 q->maxlen = 0;
3094
3095 ast_string_field_set(q, announce, "");
3097 ast_string_field_set(q, membergosub, "");
3098 ast_string_field_set(q, defaultrule, "");
3099
3100 q->announcefrequency = 0;
3102 q->announceholdtime = 1;
3104 q->announcepositionlimit = 10; /* Default 10 positions */
3105 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
3106 q->roundingseconds = 0; /* Default - don't announce seconds */
3107 q->servicelevel = 0;
3108 q->ringinuse = 1;
3110 q->setinterfacevar = 0;
3111 q->setqueuevar = 0;
3112 q->setqueueentryvar = 0;
3114 q->monfmt[0] = '\0';
3115 q->reportholdtime = 0;
3116 q->wrapuptime = 0;
3117 q->penaltymemberslimit = 0;
3118 q->joinempty = 0;
3119 q->leavewhenempty = 0;
3120 q->memberdelay = 0;
3121 q->weight = 0;
3122 q->timeoutrestart = 0;
3126 q->numperiodicannounce = 0;
3129 q->autopausebusy = 0;
3130 q->autopauseunavail = 0;
3132 q->autopausedelay = 0;
3134 if (!q->members) {
3136 /* linear strategy depends on order, so we have to place all members in a list */
3138 } else {
3141 }
3142 }
3143 q->found = 1;
3144
3145 ast_string_field_set(q, moh, "");
3146 ast_string_field_set(q, sound_next, "queue-youarenext");
3147 ast_string_field_set(q, sound_thereare, "queue-thereare");
3148 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3149 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3150 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3151 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3152 ast_string_field_set(q, sound_minutes, "queue-minutes");
3153 ast_string_field_set(q, sound_minute, "queue-minute");
3154 ast_string_field_set(q, sound_seconds, "queue-seconds");
3155 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3156 ast_string_field_set(q, sound_callerannounce, "");
3157 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3158
3159 if (!q->sound_periodicannounce[0]) {
3161 }
3162
3163 if (q->sound_periodicannounce[0]) {
3164 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3165 }
3166
3167 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3168 if (q->sound_periodicannounce[i]) {
3169 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3170 }
3171 }
3172
3173 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3174 ast_free(pr_iter);
3175 }
3176
3177 /* On restart assume no members are available.
3178 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3179 *
3180 * This seems counter intuitive, but is required to light a BLF
3181 * AST_DEVICE_INUSE indicates no members are available.
3182 * AST_DEVICE_NOT_INUSE indicates a member is available.
3183 */
3185}
3186
3187static void clear_queue(struct call_queue *q)
3188{
3189 q->holdtime = 0;
3190 q->callscompleted = 0;
3191 q->callsabandoned = 0;
3192 q->callscompletedinsl = 0;
3193 q->callsabandonedinsl = 0;
3194 q->talktime = 0;
3195
3196 if (q->members) {
3197 struct member *mem;
3198 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3199 while ((mem = ao2_iterator_next(&mem_iter))) {
3200 mem->calls = 0;
3201 mem->callcompletedinsl = 0;
3202 mem->lastcall = 0;
3203 mem->starttime = 0;
3204 ao2_ref(mem, -1);
3205 }
3206 ao2_iterator_destroy(&mem_iter);
3207 }
3208}
3209
3210/*!
3211 * \brief Change queue penalty by adding rule.
3212 *
3213 * Check rule for errors with time or formatting, see if rule is relative to rest
3214 * of queue, iterate list of rules to find correct insertion point, insert and return.
3215 * \retval -1 on failure
3216 * \retval 0 on success
3217 * \note Call this with the rule_lists locked
3218*/
3219static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
3220{
3221 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3222 struct penalty_rule *rule = NULL, *rule_iter;
3223 struct rule_list *rl_iter;
3224 int penaltychangetime, inserted = 0;
3225
3226 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3227 return -1;
3228 }
3229
3230 contentdup = ast_strdupa(content);
3231
3232 if (!(maxstr = strchr(contentdup, ','))) {
3233 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3234 ast_free(rule);
3235 return -1;
3236 }
3237
3238 *maxstr++ = '\0';
3239 if ((minstr = strchr(maxstr,','))) {
3240 *minstr++ = '\0';
3241 if ((raisestr = strchr(minstr,','))) {
3242 *raisestr++ = '\0';
3243 }
3244 } else {
3245 raisestr = NULL;
3246 }
3247
3248 timestr = contentdup;
3249 if ((penaltychangetime = atoi(timestr)) < 0) {
3250 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3251 ast_free(rule);
3252 return -1;
3253 }
3254
3255 rule->time = penaltychangetime;
3256
3257 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3258 * OR if a min penalty change is indicated but no max penalty change is */
3259 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3260 rule->max_relative = 1;
3261 }
3262
3263 rule->max_value = atoi(maxstr);
3264
3265 if (!ast_strlen_zero(minstr)) {
3266 if (*minstr == '+' || *minstr == '-') {
3267 rule->min_relative = 1;
3268 }
3269 rule->min_value = atoi(minstr);
3270 } else { /*there was no minimum specified, so assume this means no change*/
3271 rule->min_relative = 1;
3272 }
3273
3274 if (!ast_strlen_zero(raisestr)) {
3275 rule->raise_respect_min = 0; /* Initialize to 0 */
3276 if (*raisestr == 'r') {
3277 rule->raise_respect_min = 1; /* Set the flag */
3278 raisestr++;
3279 }
3280 if (*raisestr == '+' || *raisestr == '-') {
3281 rule->raise_relative = 1;
3282 }
3283 rule->raise_value = atoi(raisestr);
3284 } else { /*there was no raise specified, so assume this means no change*/
3285 rule->raise_relative = 1;
3286 }
3287
3288 /*We have the rule made, now we need to insert it where it belongs*/
3289 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3290 if (strcasecmp(rl_iter->name, list_name)) {
3291 continue;
3292 }
3293
3294 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3295 if (rule->time < rule_iter->time) {
3297 inserted = 1;
3298 break;
3299 }
3300 }
3302
3303 if (!inserted) {
3304 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3305 inserted = 1;
3306 }
3307
3308 break;
3309 }
3310
3311 if (!inserted) {
3312 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3313 ast_free(rule);
3314 return -1;
3315 }
3316 return 0;
3317}
3318
3319/*!
3320 * \brief Load queue rules from realtime.
3321 *
3322 * Check rule for errors with time or formatting, see if rule is relative to rest
3323 * of queue, iterate list of rules to find correct insertion point, insert and return.
3324 * \retval -1 on failure
3325 * \retval 0 on success
3326 * \note Call this with the rule_lists locked
3327*/
3328static int load_realtime_rules(void)
3329{
3330 struct ast_config *cfg;
3331 struct rule_list *rl_iter, *new_rl;
3332 struct penalty_rule *pr_iter;
3333 char *rulecat = NULL;
3334
3335 if (!ast_check_realtime("queue_rules")) {
3336 ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3337 return 0;
3338 }
3339 if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3340 ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3341 return 0;
3342 }
3343 while ((rulecat = ast_category_browse(cfg, rulecat))) {
3344 const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3345 int penaltychangetime, rule_exists = 0, inserted = 0;
3346 int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3347 int min_relative = 0, max_relative = 0, raise_relative = 0;
3348 struct penalty_rule *new_penalty_rule = NULL;
3349
3350 rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3351 if (ast_strlen_zero(rule_name)) {
3352 continue;
3353 }
3354
3355 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3356 if (!(strcasecmp(rl_iter->name, rule_name))) {
3357 rule_exists = 1;
3358 new_rl = rl_iter;
3359 break;
3360 }
3361 }
3362 if (!rule_exists) {
3363 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3364 ast_config_destroy(cfg);
3365 return -1;
3366 }
3367 ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3369 }
3370 timestr = ast_variable_retrieve(cfg, rulecat, "time");
3371 if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3372 ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3373 (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3374 continue;
3375 }
3376 if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3377 ast_config_destroy(cfg);
3378 return -1;
3379 }
3380 if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3381 ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3382 max_penalty = 0;
3383 max_relative = 1;
3384 } else {
3385 if (*maxstr == '+' || *maxstr == '-') {
3386 max_relative = 1;
3387 }
3388 }
3389 if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3390 ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3391 min_penalty = 0;
3392 min_relative = 1;
3393 } else {
3394 if (*minstr == '+' || *minstr == '-') {
3395 min_relative = 1;
3396 }
3397 }
3398 if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3399 ast_strlen_zero(raisestr) ) {
3400 raise_penalty = 0;
3401 raise_relative = 1;
3402 } else {
3403 if (*raisestr == 'r') {
3404 new_penalty_rule->raise_respect_min = 1;
3405 raisestr++;
3406 } else {
3407 new_penalty_rule->raise_respect_min = 0;
3408 }
3409 if (*raisestr == '+' || *raisestr == '-') {
3410 raise_relative = 1;
3411 }
3412 if (sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3413 raise_penalty = 0;
3414 raise_relative = 1;
3415 }
3416 }
3417 new_penalty_rule->time = penaltychangetime;
3418 new_penalty_rule->max_relative = max_relative;
3419 new_penalty_rule->max_value = max_penalty;
3420 new_penalty_rule->min_relative = min_relative;
3421 new_penalty_rule->min_value = min_penalty;
3422 new_penalty_rule->raise_relative = raise_relative;
3423 new_penalty_rule->raise_value = raise_penalty;
3424 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3425 if (new_penalty_rule->time < pr_iter->time) {
3426 AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3427 inserted = 1;
3428 }
3429 }
3431 if (!inserted) {
3432 AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3433 }
3434 }
3435
3436 ast_config_destroy(cfg);
3437 return 0;
3438}
3439
3440static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
3441{
3442 char *value_copy = ast_strdupa(value);
3443 char *option = NULL;
3444 while ((option = strsep(&value_copy, ","))) {
3445 if (!strcasecmp(option, "paused")) {
3446 *empty |= QUEUE_EMPTY_PAUSED;
3447 } else if (!strcasecmp(option, "penalty")) {
3448 *empty |= QUEUE_EMPTY_PENALTY;
3449 } else if (!strcasecmp(option, "inuse")) {
3450 *empty |= QUEUE_EMPTY_INUSE;
3451 } else if (!strcasecmp(option, "ringing")) {
3452 *empty |= QUEUE_EMPTY_RINGING;
3453 } else if (!strcasecmp(option, "invalid")) {
3454 *empty |= QUEUE_EMPTY_INVALID;
3455 } else if (!strcasecmp(option, "wrapup")) {
3456 *empty |= QUEUE_EMPTY_WRAPUP;
3457 } else if (!strcasecmp(option, "unavailable")) {
3458 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3459 } else if (!strcasecmp(option, "unknown")) {
3460 *empty |= QUEUE_EMPTY_UNKNOWN;
3461 } else if (!strcasecmp(option, "loose")) {
3463 } else if (!strcasecmp(option, "strict")) {
3465 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3467 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3468 *empty = 0;
3469 } else {
3470 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3471 }
3472 }
3473}
3474
3475/*! \brief Configure a queue parameter.
3476 *
3477 * The failunknown flag is set for config files (and static realtime) to show
3478 * errors for unknown parameters. It is cleared for dynamic realtime to allow
3479 * extra fields in the tables.
3480 * \note For error reporting, line number is passed for .conf static configuration,
3481 * for Realtime queues, linenum is -1.
3482*/
3483static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
3484{
3485 if (!strcasecmp(param, "musicclass") ||
3486 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3487 ast_string_field_set(q, moh, val);
3488 } else if (!strcasecmp(param, "announce")) {
3489 ast_string_field_set(q, announce, val);
3490 } else if (!strcasecmp(param, "context")) {
3492 } else if (!strcasecmp(param, "timeout")) {
3493 q->timeout = atoi(val);
3494 if (q->timeout < 0) {
3496 }
3497 } else if (!strcasecmp(param, "ringinuse")) {
3498 q->ringinuse = ast_true(val);
3499 } else if (!strcasecmp(param, "setinterfacevar")) {
3501 } else if (!strcasecmp(param, "setqueuevar")) {
3502 q->setqueuevar = ast_true(val);
3503 } else if (!strcasecmp(param, "setqueueentryvar")) {
3505 } else if (!strcasecmp(param, "monitor-format")) {
3506 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3507 } else if (!strcasecmp(param, "membergosub")) {
3508 ast_string_field_set(q, membergosub, val);
3509 } else if (!strcasecmp(param, "queue-youarenext")) {
3510 ast_string_field_set(q, sound_next, val);
3511 } else if (!strcasecmp(param, "queue-thereare")) {
3512 ast_string_field_set(q, sound_thereare, val);
3513 } else if (!strcasecmp(param, "queue-callswaiting")) {
3514 ast_string_field_set(q, sound_calls, val);
3515 } else if (!strcasecmp(param, "queue-quantity1")) {
3516 ast_string_field_set(q, queue_quantity1, val);
3517 } else if (!strcasecmp(param, "queue-quantity2")) {
3518 ast_string_field_set(q, queue_quantity2, val);
3519 } else if (!strcasecmp(param, "queue-holdtime")) {
3520 ast_string_field_set(q, sound_holdtime, val);
3521 } else if (!strcasecmp(param, "queue-minutes")) {
3522 ast_string_field_set(q, sound_minutes, val);
3523 } else if (!strcasecmp(param, "queue-minute")) {
3524 ast_string_field_set(q, sound_minute, val);
3525 } else if (!strcasecmp(param, "queue-seconds")) {
3526 ast_string_field_set(q, sound_seconds, val);
3527 } else if (!strcasecmp(param, "queue-thankyou")) {
3528 ast_string_field_set(q, sound_thanks, val);
3529 } else if (!strcasecmp(param, "queue-callerannounce")) {
3530 ast_string_field_set(q, sound_callerannounce, val);
3531 } else if (!strcasecmp(param, "queue-reporthold")) {
3532 ast_string_field_set(q, sound_reporthold, val);
3533 } else if (!strcasecmp(param, "announce-frequency")) {
3534 q->announcefrequency = atoi(val);
3535 } else if (!strcasecmp(param, "announce-to-first-user")) {
3537 } else if (!strcasecmp(param, "min-announce-frequency")) {
3538 q->minannouncefrequency = atoi(val);
3539 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3540 } else if (!strcasecmp(param, "announce-round-seconds")) {
3541 q->roundingseconds = atoi(val);
3542 /* Rounding to any other values just doesn't make sense... */
3543 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3544 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3545 if (linenum >= 0) {
3546 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3547 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3548 val, param, q->name, linenum);
3549 } else {
3550 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3551 "using 0 instead for queue '%s'\n", val, param, q->name);
3552 }
3553 q->roundingseconds=0;
3554 }
3555 } else if (!strcasecmp(param, "announce-holdtime")) {
3556 if (!strcasecmp(val, "once")) {
3558 } else if (ast_true(val)) {
3560 } else {
3561 q->announceholdtime = 0;
3562 }
3563 } else if (!strcasecmp(param, "announce-position")) {
3564 if (!strcasecmp(val, "limit")) {
3566 } else if (!strcasecmp(val, "more")) {
3568 } else if (ast_true(val)) {
3570 } else {
3572 }
3573 } else if (!strcasecmp(param, "announce-position-only-up")) {
3575 } else if (!strcasecmp(param, "announce-position-limit")) {
3576 q->announcepositionlimit = atoi(val);
3577 } else if (!strcasecmp(param, "periodic-announce")) {
3578 if (strchr(val, ',')) {
3579 char *s, *buf = ast_strdupa(val);
3580 unsigned int i = 0;
3581
3582 while ((s = strsep(&buf, ",|"))) {
3583 if (!q->sound_periodicannounce[i]) {
3585 }
3586 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3587 i++;
3588 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3589 break;
3590 }
3591 }
3592 q->numperiodicannounce = i;
3593 } else {
3594 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3595 q->numperiodicannounce = 1;
3596 }
3597 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3599 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3600 q->periodicannouncefrequency = atoi(val);
3601 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3603 } else if (!strcasecmp(param, "random-periodic-announce")) {
3605 } else if (!strcasecmp(param, "retry")) {
3606 q->retry = atoi(val);
3607 if (q->retry <= 0) {
3608 q->retry = DEFAULT_RETRY;
3609 }
3610 } else if (!strcasecmp(param, "wrapuptime")) {
3611 q->wrapuptime = atoi(val);
3612 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3613 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3614 q->penaltymemberslimit = 0;
3615 }
3616 } else if (!strcasecmp(param, "autofill")) {
3617 q->autofill = ast_true(val);
3618 } else if (!strcasecmp(param, "autopause")) {
3620 } else if (!strcasecmp(param, "autopausedelay")) {
3621 q->autopausedelay = atoi(val);
3622 } else if (!strcasecmp(param, "autopausebusy")) {
3624 } else if (!strcasecmp(param, "autopauseunavail")) {
3626 } else if (!strcasecmp(param, "maxlen")) {
3627 q->maxlen = atoi(val);
3628 if (q->maxlen < 0) {
3629 q->maxlen = 0;
3630 }
3631 } else if (!strcasecmp(param, "servicelevel")) {
3632 q->servicelevel= atoi(val);
3633 } else if (!strcasecmp(param, "strategy")) {
3634 int strategy;
3635
3636 /* We are a static queue and already have set this, no need to do it again */
3637 if (failunknown) {
3638 return;
3639 }
3641 if (strategy < 0) {
3642 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3643 val, q->name);
3645 }
3646 if (strategy == q->strategy) {
3647 return;
3648 }
3650 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3651 return;
3652 }
3653 q->strategy = strategy;
3654 } else if (!strcasecmp(param, "joinempty")) {
3656 } else if (!strcasecmp(param, "leavewhenempty")) {
3658 } else if (!strcasecmp(param, "reportholdtime")) {
3660 } else if (!strcasecmp(param, "memberdelay")) {
3661 q->memberdelay = atoi(val);
3662 } else if (!strcasecmp(param, "weight")) {
3663 q->weight = atoi(val);
3664 } else if (!strcasecmp(param, "timeoutrestart")) {
3666 } else if (!strcasecmp(param, "defaultrule")) {
3667 ast_string_field_set(q, defaultrule, val);
3668 } else if (!strcasecmp(param, "timeoutpriority")) {
3669 if (!strcasecmp(val, "conf")) {
3671 } else {
3673 }
3674 } else if (!strcasecmp(param, "log-restricted-caller-id")) {
3676 } else if (failunknown) {
3677 if (linenum >= 0) {
3678 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3679 q->name, param, linenum);
3680 } else {
3681 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3682 }
3683 }
3684}
3685
3686
3687#define QUEUE_PAUSED_DEVSTATE AST_DEVICE_INUSE
3688#define QUEUE_UNPAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3689#define QUEUE_UNKNOWN_PAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3690
3691/*! \internal
3692 * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
3693 * This adds round robin queue position data for a fresh member as well as links it.
3694 * \param queue Which queue the member is being added to
3695 * \param mem Which member is being added to the queue
3696 */
3697static void member_add_to_queue(struct call_queue *queue, struct member *mem)
3698{
3699 ao2_lock(queue->members);
3700 mem->queuepos = ao2_container_count(queue->members);
3701 ao2_link(queue->members, mem);
3703 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
3704 ao2_unlock(queue->members);
3705}
3706
3707/*! \internal
3708 * \brief If removing a single member from a queue, use this function instead of ao2_unlinking.
3709 * This will perform round robin queue position reordering for the remaining members.
3710 * \param queue Which queue the member is being removed from
3711 * \param mem Which member is being removed from the queue
3712 */
3713static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
3714{
3716 ao2_lock(queue->members);
3719 ao2_unlink(queue->members, mem);
3720 ao2_unlock(queue->members);
3721}
3722
3723/*!
3724 * \brief Find rt member record to update otherwise create one.
3725 *
3726 * Search for member in queue, if found update penalty/paused state,
3727 * if no member exists create one flag it as a RT member and add to queue member list.
3728*/
3729static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config)
3730{
3731 struct member *m;
3732 struct ao2_iterator mem_iter;
3733 int penalty = 0;
3734 int paused = 0;
3735 int found = 0;
3736 int wrapuptime = 0;
3737 int ringinuse = q->ringinuse;
3738
3739 const char *config_val;
3740 const char *interface = ast_variable_retrieve(member_config, category, "interface");
3741 const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3742 const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3743 const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3744 const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3745 const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3746 const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3747 const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
3748
3749 if (ast_strlen_zero(rt_uniqueid)) {
3750 ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3751 S_OR(membername, "NULL"));
3752 return;
3753 }
3754
3755 if (ast_strlen_zero(interface)) {
3756 ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3757 S_OR(membername, "NULL"));
3758 return;
3759 }
3760
3761 if (penalty_str) {
3762 penalty = atoi(penalty_str);
3763 if ((penalty < 0) && negative_penalty_invalid) {
3764 return;
3765 } else if (penalty < 0) {
3766 penalty = 0;
3767 }
3768 }
3769
3770 if (paused_str) {
3771 paused = atoi(paused_str);
3772 if (paused < 0) {
3773 paused = 0;
3774 }
3775 }
3776
3777 if (wrapuptime_str) {
3778 wrapuptime = atoi(wrapuptime_str);
3779 if (wrapuptime < 0) {
3780 wrapuptime = 0;
3781 }
3782 }
3783
3784 if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3785 if (ast_true(config_val)) {
3786 ringinuse = 1;
3787 } else if (ast_false(config_val)) {
3788 ringinuse = 0;
3789 } else {
3790 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3791 }
3792 }
3793
3794 /* Find member by realtime uniqueid and update */
3795 mem_iter = ao2_iterator_init(q->members, 0);
3796 while ((m = ao2_iterator_next(&mem_iter))) {
3797 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3798 m->dead = 0; /* Do not delete this one. */
3799 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3800 if (paused_str) {
3801 m->paused = paused;
3802 if (paused && m->lastpause == 0) {
3803 time(&m->lastpause); /* XXX: Should this come from realtime? */
3804 }
3806 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3807 }
3808 if (strcasecmp(state_interface, m->state_interface)) {
3809 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3810 }
3811 m->penalty = penalty;
3812 m->ringinuse = ringinuse;
3813 m->wrapuptime = wrapuptime;
3815 ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
3816 }
3817 found = 1;
3818 ao2_ref(m, -1);
3819 break;
3820 }
3821 ao2_ref(m, -1);
3822 }
3823 ao2_iterator_destroy(&mem_iter);
3824
3825 /* Create a new member */
3826 if (!found) {
3827 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3828 m->dead = 0;
3829 m->realtime = 1;
3830 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3831 if (!ast_strlen_zero(reason_paused)) {
3832 ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
3833 }
3835 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3836 } else {
3837 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3838 }
3839 member_add_to_queue(q, m);
3840 ao2_ref(m, -1);
3841 m = NULL;
3842 }
3843 }
3844}
3845
3846/*! \brief Iterate through queue's member list and delete them */
3847static void free_members(struct call_queue *q, int all)
3848{
3849 /* Free non-dynamic members */
3850 struct member *cur;
3851 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3852
3853 while ((cur = ao2_iterator_next(&mem_iter))) {
3854 if (all || !cur->dynamic) {
3856 }
3857 ao2_ref(cur, -1);
3858 }
3859 ao2_iterator_destroy(&mem_iter);
3860}
3861
3862/*! \brief Free queue's member list then its string fields */
3863static void destroy_queue(void *obj)
3864{
3865 struct call_queue *q = obj;
3866 int i;
3867
3868 free_members(q, 1);
3870 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3871 if (q->sound_periodicannounce[i]) {
3873 }
3874 }
3875 ao2_ref(q->members, -1);
3876}
3877
3878static struct call_queue *alloc_queue(const char *queuename)
3879{
3880 struct call_queue *q;
3881
3882 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3883 if (ast_string_field_init(q, 64)) {
3884 queue_t_unref(q, "String field allocation failed");
3885 return NULL;
3886 }
3887 ast_string_field_set(q, name, queuename);
3888 }
3889 return q;
3890}
3891
3892/*!
3893 * \brief Reload a single queue via realtime.
3894 *
3895 * Check for statically defined queue first, check if deleted RT queue,
3896 * check for new RT queue, if queue vars are not defined init them with defaults.
3897 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
3898 * \retval the queue,
3899 * \retval NULL if it doesn't exist.
3900 * \note Should be called with the "queues" container locked.
3901*/
3902static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
3903{
3904 struct ast_variable *v;
3905 struct call_queue *q, tmpq = {
3906 .name = queuename,
3907 };
3908 struct member *m;
3909 struct ao2_iterator mem_iter;
3910 char *category = NULL;
3911 const char *tmp_name;
3912 char *tmp;
3913 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3914
3915 /* Static queues override realtime. */
3916 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3917 ao2_lock(q);
3918 if (!q->realtime) {
3919 if (q->dead) {
3920 ao2_unlock(q);
3921 queue_t_unref(q, "Queue is dead; can't return it");
3922 return NULL;
3923 }
3924 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3925 ao2_unlock(q);
3926 return q;
3927 }
3928 } else if (!member_config) {
3929 /* Not found in the list, and it's not realtime ... */
3930 return NULL;
3931 }
3932 /* Check if queue is defined in realtime. */
3933 if (!queue_vars) {
3934 /* Delete queue from in-core list if it has been deleted in realtime. */
3935 if (q) {
3936 /*! \note Hmm, can't seem to distinguish a DB failure from a not
3937 found condition... So we might delete an in-core queue
3938 in case of DB failure. */
3939 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3940
3941 q->dead = 1;
3942 /* Delete if unused (else will be deleted when last caller leaves). */
3943 queues_t_unlink(queues, q, "Unused; removing from container");
3944 ao2_unlock(q);
3945 queue_t_unref(q, "Queue is dead; can't return it");
3946 }
3947 return NULL;
3948 }
3949
3950 /* Create a new queue if an in-core entry does not exist yet. */
3951 if (!q) {
3952 struct ast_variable *tmpvar = NULL;
3953 if (!(q = alloc_queue(queuename))) {
3954 return NULL;
3955 }
3956 ao2_lock(q);
3957 clear_queue(q);
3958 q->realtime = 1;
3959 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3960 * will allocate the members properly
3961 */
3962 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3963 if (!strcasecmp(tmpvar->name, "strategy")) {
3964 q->strategy = strat2int(tmpvar->value);
3965 if (q->strategy < 0) {
3966 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3967 tmpvar->value, q->name);
3969 }
3970 break;
3971 }
3972 }
3973 /* We traversed all variables and didn't find a strategy */
3974 if (!tmpvar) {
3976 }
3977 queues_t_link(queues, q, "Add queue to container");
3978 }
3979 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3980
3981 memset(tmpbuf, 0, sizeof(tmpbuf));
3982 for (v = queue_vars; v; v = v->next) {
3983 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3984 if (strchr(v->name, '_')) {
3985 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3986 tmp_name = tmpbuf;
3987 tmp = tmpbuf;
3988 while ((tmp = strchr(tmp, '_'))) {
3989 *tmp++ = '-';
3990 }
3991 } else {
3992 tmp_name = v->name;
3993 }
3994
3995 /* NULL values don't get returned from realtime; blank values should
3996 * still get set. If someone doesn't want a value to be set, they
3997 * should set the realtime column to NULL, not blank. */
3998 queue_set_param(q, tmp_name, v->value, -1, 0);
3999 }
4000
4001 /* Temporarily set realtime members dead so we can detect deleted ones. */
4002 mem_iter = ao2_iterator_init(q->members, 0);
4003 while ((m = ao2_iterator_next(&mem_iter))) {
4004 if (m->realtime) {
4005 m->dead = 1;
4006 }
4007 ao2_ref(m, -1);
4008 }
4009 ao2_iterator_destroy(&mem_iter);
4010
4011 while ((category = ast_category_browse(member_config, category))) {
4012 rt_handle_member_record(q, category, member_config);
4013 }
4014
4015 /* Delete all realtime members that have been deleted in DB. */
4016 mem_iter = ao2_iterator_init(q->members, 0);
4017 while ((m = ao2_iterator_next(&mem_iter))) {
4018 if (m->dead) {
4020 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4021 } else {
4022 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4023 }
4025 }
4026 ao2_ref(m, -1);
4027 }
4028 ao2_iterator_destroy(&mem_iter);
4029
4030 ao2_unlock(q);
4031
4032 return q;
4033}
4034
4035/*!
4036 * note */
4037
4038/*!
4039 * \internal
4040 * \brief Returns reference to the named queue. If the queue is realtime, it will load the queue as well.
4041 * \param queuename - name of the desired queue
4042 *
4043 * \retval the queue
4044 * \retval NULL if it doesn't exist
4045 */
4046static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
4047{
4048 struct ast_variable *queue_vars;
4049 struct ast_config *member_config = NULL;
4050 struct call_queue *q = NULL, tmpq = {
4051 .name = queuename,
4052 };
4053 int prev_weight = 0;
4054
4055 /* Find the queue in the in-core list first. */
4056 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
4057
4058 if (!q || q->realtime) {
4059 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
4060 queue operations while waiting for the DB.
4061
4062 This will be two separate database transactions, so we might
4063 see queue parameters as they were before another process
4064 changed the queue and member list as it was after the change.
4065 Thus we might see an empty member list when a queue is
4066 deleted. In practise, this is unlikely to cause a problem. */
4067
4068 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
4069 if (queue_vars) {
4070 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
4071 if (!member_config) {
4072 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
4073 member_config = ast_config_new();
4074 }
4075 }
4076 if (q) {
4077 prev_weight = q->weight ? 1 : 0;
4078 queue_t_unref(q, "Need to find realtime queue");
4079 }
4080
4081 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
4082 ast_config_destroy(member_config);
4083 ast_variables_destroy(queue_vars);
4084
4085 /* update the use_weight value if the queue's has gained or lost a weight */
4086 if (q) {
4087 if (!q->weight && prev_weight) {
4089 }
4090 if (q->weight && !prev_weight) {
4092 }
4093 }
4094 /* Other cases will end up with the proper value for use_weight */
4095 } else {
4097 }
4098 return q;
4099}
4100
4101/*!
4102 * \internal
4103 * \brief Load queues and members from realtime.
4104 *
4105 * \param queuename - name of the desired queue to load or empty if need to load all queues
4106*/
4107static void load_realtime_queues(const char *queuename)
4108{
4109 struct ast_config *cfg = NULL;
4110 char *category = NULL;
4111 const char *name = NULL;
4112 struct call_queue *q = NULL;
4113
4114 if (!ast_check_realtime("queues")) {
4115 return;
4116 }
4117
4118 if (ast_strlen_zero(queuename)) {
4119 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
4120 while ((category = ast_category_browse(cfg, category))) {
4121 name = ast_variable_retrieve(cfg, category, "name");
4123 queue_unref(q);
4124 }
4125 }
4126 ast_config_destroy(cfg);
4127 }
4128 } else {
4129 if ((q = find_load_queue_rt_friendly(queuename))) {
4130 queue_unref(q);
4131 }
4132 }
4133}
4134
4135static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
4136{
4137 int ret = -1;
4138
4139 if (ast_strlen_zero(mem->rt_uniqueid)) {
4140 return ret;
4141 }
4142
4143 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4144 ret = 0;
4145 }
4146
4147 return ret;
4148}
4149
4150
4152{
4153 struct ast_config *member_config = NULL;
4154 struct member *m;
4155 char *category = NULL;
4156 struct ao2_iterator mem_iter;
4157
4158 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4159 /* This queue doesn't have realtime members. If the queue still has any realtime
4160 * members in memory, they need to be removed.
4161 */
4162 ao2_lock(q);
4163 mem_iter = ao2_iterator_init(q->members, 0);
4164 while ((m = ao2_iterator_next(&mem_iter))) {
4165 if (m->realtime) {
4167 }
4168 ao2_ref(m, -1);
4169 }
4170 ao2_iterator_destroy(&mem_iter);
4171 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4172 ao2_unlock(q);
4173 return;
4174 }
4175
4176 ao2_lock(q);
4177
4178 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4179 mem_iter = ao2_iterator_init(q->members, 0);
4180 while ((m = ao2_iterator_next(&mem_iter))) {
4181 if (m->realtime) {
4182 m->dead = 1;
4183 }
4184 ao2_ref(m, -1);
4185 }
4186 ao2_iterator_destroy(&mem_iter);
4187
4188 while ((category = ast_category_browse(member_config, category))) {
4189 rt_handle_member_record(q, category, member_config);
4190 }
4191
4192 /* Delete all realtime members that have been deleted in DB. */
4193 mem_iter = ao2_iterator_init(q->members, 0);
4194 while ((m = ao2_iterator_next(&mem_iter))) {
4195 if (m->dead) {
4197 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4198 } else {
4199 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4200 }
4202 }
4203 ao2_ref(m, -1);
4204 }
4205 ao2_iterator_destroy(&mem_iter);
4206 ao2_unlock(q);
4207 ast_config_destroy(member_config);
4208}
4209
4210static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
4211{
4212 struct call_queue *q;
4213 struct queue_ent *cur, *prev = NULL;
4214 int res = -1;
4215 int pos = 0;
4216 int inserted = 0;
4217
4218 if (!(q = find_load_queue_rt_friendly(queuename))) {
4219 return res;
4220 }
4221 ao2_lock(q);
4222
4223 /* This is our one */
4224 if (q->joinempty) {
4225 int status = 0;
4227 *reason = QUEUE_JOINEMPTY;
4228 ao2_unlock(q);
4229 queue_t_unref(q, "Done with realtime queue");
4230 return res;
4231 }
4232 }
4233 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4234 *reason = QUEUE_FULL;
4235 } else if (*reason == QUEUE_UNKNOWN) {
4236 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4237
4238 /* There's space for us, put us at the right position inside
4239 * the queue.
4240 * Take into account the priority of the calling user */
4241 inserted = 0;
4242 prev = NULL;
4243 cur = q->head;
4244 while (cur) {
4245 /* We have higher priority than the current user, enter
4246 * before him, after all the other users with priority
4247 * higher or equal to our priority. */
4248 if ((!inserted) && (qe->prio > cur->prio)) {
4249 insert_entry(q, prev, qe, &pos);
4250 inserted = 1;
4251 }
4252 /* <= is necessary for the position comparison because it may not be possible to enter
4253 * at our desired position since higher-priority callers may have taken the position we want
4254 */
4255 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4256 insert_entry(q, prev, qe, &pos);
4257 inserted = 1;
4258 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4259 if (position < pos) {
4260 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4261 }
4262 }
4263 cur->pos = ++pos;
4264 prev = cur;
4265 cur = cur->next;
4266 }
4267 /* No luck, join at the end of the queue */
4268 if (!inserted) {
4269 insert_entry(q, prev, qe, &pos);
4270 }
4271 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4272 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4273 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4274 q->count++;
4275 if (q->count == 1) {
4277 }
4278
4279 res = 0;
4280
4281 blob = ast_json_pack("{s: s, s: i, s: i}",
4282 "Queue", q->name,
4283 "Position", qe->pos,
4284 "Count", q->count);
4285 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4286 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4287 }
4288 ao2_unlock(q);
4289 queue_t_unref(q, "Done with realtime queue");
4290
4291 return res;
4292}
4293
4294static int play_file(struct ast_channel *chan, const char *filename)
4295{
4296 int res;
4297
4298 if (ast_strlen_zero(filename)) {
4299 return 0;
4300 }
4301
4302 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4303 return 0;
4304 }
4305
4307
4308 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4309 if (!res) {
4311 }
4312
4314
4315 return res;
4316}
4317
4318/*!
4319 * \brief Check for valid exit from queue via goto
4320 * \retval 0 if failure
4321 * \retval 1 if successful
4322*/
4323static int valid_exit(struct queue_ent *qe, char digit)
4324{
4325 int digitlen = strlen(qe->digits);
4326
4327 /* Prevent possible buffer overflow */
4328 if (digitlen < sizeof(qe->digits) - 2) {
4329 qe->digits[digitlen] = digit;
4330 qe->digits[digitlen + 1] = '\0';
4331 } else {
4332 qe->digits[0] = '\0';
4333 return 0;
4334 }
4335
4336 /* If there's no context to goto, short-circuit */
4337 if (ast_strlen_zero(qe->context)) {
4338 return 0;
4339 }
4340
4341 /* If the extension is bad, then reset the digits to blank */
4342 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4344 qe->digits[0] = '\0';
4345 return 0;
4346 }
4347
4348 /* We have an exact match */
4349 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4350 qe->valid_digits = 1;
4351 /* Return 1 on a successful goto */
4352 return 1;
4353 }
4354
4355 return 0;
4356}
4357
4358static int say_position(struct queue_ent *qe, int ringing)
4359{
4360 int res = 0, say_thanks = 0;
4361 long avgholdmins, avgholdsecs;
4362 time_t now;
4363
4364 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4365 time(&now);
4366 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4367 return 0;
4368 }
4369
4370 /* If either our position has changed, or we are over the freq timer, say position */
4371 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4372 return 0;
4373 }
4374
4375 /* Only announce if the caller's queue position has improved since last time */
4376 if (qe->parent->announceposition_only_up && qe->last_pos_said > 0 && qe->last_pos_said <= qe->pos) {
4377 return 0;
4378 }
4379
4380 if (ringing) {
4381 ast_indicate(qe->chan,-1);
4382 } else {
4383 ast_moh_stop(qe->chan);
4384 }
4385
4389 qe->pos <= qe->parent->announcepositionlimit)) {
4390 say_thanks = 1;
4391 /* Say we're next, if we are */
4392 if (qe->pos == 1) {
4393 res = play_file(qe->chan, qe->parent->sound_next);
4394 if (!res) {
4395 goto posout;
4396 }
4397 /* Say there are more than N callers */
4399 res = (
4400 play_file(qe->chan, qe->parent->queue_quantity1) ||
4402 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4404 /* Say there are currently N callers waiting */
4405 } else {
4406 res = (
4407 play_file(qe->chan, qe->parent->sound_thereare) ||
4409 ast_channel_language(qe->chan), "n") || /* Needs gender */
4410 play_file(qe->chan, qe->parent->sound_calls));
4411 }
4412 if (res) {
4413 goto playout;
4414 }
4415 }
4416 /* Round hold time to nearest minute */
4417 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4418
4419 /* If they have specified a rounding then round the seconds as well */
4420 if (qe->parent->roundingseconds) {
4421 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4422 avgholdsecs *= qe->parent->roundingseconds;
4423 } else {
4424 avgholdsecs = 0;
4425 }
4426
4427 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4428
4429 /* If the hold time is >1 min, if it's enabled, and if it's not
4430 supposed to be only once and we have already said it, say it */
4431 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4434 say_thanks = 1;
4435 res = play_file(qe->chan, qe->parent->sound_holdtime);
4436 if (res) {
4437 goto playout;
4438 }
4439
4440 if (avgholdmins >= 1) {
4441 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4442 if (res) {
4443 goto playout;
4444 }
4445
4446 if (avgholdmins == 1) {
4447 res = play_file(qe->chan, qe->parent->sound_minute);
4448 if (res) {
4449 goto playout;
4450 }
4451 } else {
4452 res = play_file(qe->chan, qe->parent->sound_minutes);
4453 if (res) {
4454 goto playout;
4455 }
4456 }
4457 }
4458 if (avgholdsecs >= 1) {
4459 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4460 if (res) {
4461 goto playout;
4462 }
4463
4464 res = play_file(qe->chan, qe->parent->sound_seconds);
4465 if (res) {
4466 goto playout;
4467 }
4468 }
4469 }
4470
4471posout:
4472 if (qe->parent->announceposition) {
4473 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4474 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4475 }
4476 if (say_thanks) {
4477 res = play_file(qe->chan, qe->parent->sound_thanks);
4478 }
4479playout:
4480
4481 if ((res > 0 && !valid_exit(qe, res))) {
4482 res = 0;
4483 }
4484
4485 /* Set our last_pos indicators */
4486 qe->last_pos = now;
4487 qe->last_pos_said = qe->pos;
4488
4489 /* Don't restart music on hold if we're about to exit the caller from the queue */
4490 if (!res) {
4491 if (ringing) {
4493 } else {
4494 ast_moh_start(qe->chan, qe->moh, NULL);
4495 }
4496 }
4497 return res;
4498}
4499
4500static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
4501{
4502 int oldvalue;
4503
4504 /* Calculate holdtime using an exponential average */
4505 /* Thanks to SRT for this contribution */
4506 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4507
4508 ao2_lock(qe->parent);
4509 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4510 qe->parent->holdtime = newholdtime;
4511 } else {
4512 oldvalue = qe->parent->holdtime;
4513 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4514 }
4515 ao2_unlock(qe->parent);
4516}
4517
4518/*! \brief Caller leaving queue.
4519 *
4520 * Search the queue to find the leaving client, if found remove from queue
4521 * create manager event, move others up the queue.
4522*/
4523static void leave_queue(struct queue_ent *qe)
4524{
4525 struct call_queue *q;
4526 struct queue_ent *current, *prev = NULL;
4527 struct penalty_rule *pr_iter;
4528 int pos = 0;
4529
4530 if (!(q = qe->parent)) {
4531 return;
4532 }
4533 queue_t_ref(q, "Copy queue pointer from queue entry");
4534 ao2_lock(q);
4535
4536 prev = NULL;
4537 for (current = q->head; current; current = current->next) {
4538 if (current == qe) {
4539 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4540 char posstr[20];
4541 q->count--;
4542 if (!q->count) {
4544 }
4545
4546 blob = ast_json_pack("{s: s, s: i, s: i}",
4547 "Queue", q->name,
4548 "Position", qe->pos,
4549 "Count", q->count);
4550 ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4551 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4552 /* Take us out of the queue */
4553 if (prev) {
4554 prev->next = current->next;
4555 } else {
4556 q->head = current->next;
4557 }
4558 /* Free penalty rules */
4559 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4560 ast_free(pr_iter);
4561 }
4562 qe->pr = NULL;
4563 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4564 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4565 } else {
4566 /* Renumber the people after us in the queue based on a new count */
4567 current->pos = ++pos;
4568 prev = current;
4569 }
4570 }
4571 ao2_unlock(q);
4572
4573 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4574 if (q->realtime) {
4575 struct ast_variable *var;
4576 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4577 q->dead = 1;
4578 } else {
4580 }
4581 }
4582
4583 if (q->dead) {
4584 /* It's dead and nobody is in it, so kill it */
4585 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4586 }
4587 /* unref the explicit ref earlier in the function */
4588 queue_t_unref(q, "Expire copied reference");
4589}
4590
4591/*!
4592 * \internal
4593 * \brief Destroy the given callattempt structure and free it.
4594 * \since 1.8
4595 *
4596 * \param doomed callattempt structure to destroy.
4597 */
4598static void callattempt_free(struct callattempt *doomed)
4599{
4600 if (doomed->member) {
4601 ao2_ref(doomed->member, -1);
4602 }
4604 ast_free(doomed->orig_chan_name);
4605 ast_free(doomed);
4606}
4607
4608static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
4609{
4610 struct callattempt *cur;
4611
4612 for (cur = outgoing; cur; cur = cur->q_next) {
4613 if (cur->chan && cur->chan != exception) {
4615 }
4616 }
4617}
4618
4619/*! \brief Hang up a list of outgoing calls */
4620static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
4621{
4622 struct callattempt *oo;
4623
4624 while (outgoing) {
4625 /* If someone else answered the call we should indicate this in the CANCEL */
4626 /* Hangup any existing lines we have open */
4627 if (outgoing->chan && (outgoing->chan != exception)) {
4628 if (exception || cancel_answered_elsewhere) {
4630 }
4631 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4632
4633 /* When dialing channels it is possible that they may not ever
4634 * leave the not in use state (Local channels in particular) by
4635 * the time we cancel them. If this occurs but we know they were
4636 * dialed we explicitly remove them from the pending members
4637 * container so that subsequent call attempts occur.
4638 */
4639 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4641 }
4642
4643 ast_hangup(outgoing->chan);
4644 }
4645 oo = outgoing;
4646 outgoing = outgoing->q_next;
4648 callattempt_free(oo);
4649 }
4650}
4651
4652/*!
4653 * \brief Get the number of members available to accept a call.
4654 *
4655 * \note The queue passed in should be locked prior to this function call
4656 *
4657 * \param[in] q The queue for which we are counting the number of available members
4658 * \return Return the number of available members in queue q
4659 */
4661{
4662 struct member *mem;
4663 int avl = 0;
4664 struct ao2_iterator mem_iter;
4665
4666 mem_iter = ao2_iterator_init(q->members, 0);
4667 while ((mem = ao2_iterator_next(&mem_iter))) {
4668
4669 avl += is_member_available(q, mem);
4670 ao2_ref(mem, -1);
4671
4672 /* If autofill is not enabled or if the queue's strategy is ringall, then
4673 * we really don't care about the number of available members so much as we
4674 * do that there is at least one available.
4675 *
4676 * In fact, we purposely will return from this function stating that only
4677 * one member is available if either of those conditions hold. That way,
4678 * functions which determine what action to take based on the number of available
4679 * members will operate properly. The reasoning is that even if multiple
4680 * members are available, only the head caller can actually be serviced.
4681 */
4682 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4683 break;
4684 }
4685 }
4686 ao2_iterator_destroy(&mem_iter);
4687
4688 return avl;
4689}
4690
4691/* traverse all defined queues which have calls waiting and contain this member
4692 return 0 if no other queue has precedence (higher weight) or 1 if found */
4693static int compare_weight(struct call_queue *rq, struct member *member)
4694{
4695 struct call_queue *q;
4696 struct member *mem;
4697 int found = 0;
4698 struct ao2_iterator queue_iter;
4699
4700 queue_iter = ao2_iterator_init(queues, 0);
4701 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4702 if (q == rq) { /* don't check myself, could deadlock */
4703 queue_t_unref(q, "Done with iterator");
4704 continue;
4705 }
4706 ao2_lock(q);
4707 if (q->count && q->members) {
4708 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4709 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4710 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4711 ast_debug(1, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
4712 found = 1;
4713 }
4714 ao2_ref(mem, -1);
4715 }
4716 }
4717 ao2_unlock(q);
4718 queue_t_unref(q, "Done with iterator");
4719 if (found) {
4720 break;
4721 }
4722 }
4723 ao2_iterator_destroy(&queue_iter);
4724 return found;
4725}
4726
4727static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
4728{
4729 struct call_queue *q;
4730 struct member *mem;
4731 int is_longest_waiting = 1;
4732 struct ao2_iterator queue_iter;
4733 struct queue_ent *ch;
4734
4735 queue_iter = ao2_iterator_init(queues, 0);
4736 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4737 if (q == caller->parent) { /* don't check myself, could deadlock */
4738 queue_t_unref(q, "Done with iterator");
4739 continue;
4740 }
4741 ao2_lock(q);
4742 /*
4743 * If the other queue has equal weight, see if we should let that handle
4744 * their call first. If weights are not equal, compare_weights will step in.
4745 */
4746 if (q->weight == caller->parent->weight && q->count && q->members) {
4747 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4748 ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4749
4750 /* Does this queue have a caller that's been waiting longer? */
4751 ch = q->head;
4752 while (ch) {
4753 /* If ch->pending, the other call (which may be waiting for a longer period of time),
4754 * is already ringing at another agent. Ignore such callers; otherwise, all agents
4755 * will be unused until the first caller is picked up.
4756 */
4757 if (ch->start < caller->start && !ch->pending) {
4758 ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
4759 q->name, ch->pos, ch->start, caller->start);
4760 is_longest_waiting = 0;
4761 break;
4762 }
4763 ch = ch->next;
4764 }
4765 }
4766 }
4767 ao2_unlock(q);
4768 queue_t_unref(q, "Done with iterator");
4769 if (!is_longest_waiting) {
4770 break;
4771 }
4772 }
4773 ao2_iterator_destroy(&queue_iter);
4774 return is_longest_waiting;
4775}
4776
4777/*! \brief common hangup actions */
4778static void do_hang(struct callattempt *o)
4779{
4780 o->stillgoing = 0;
4781 ast_hangup(o->chan);
4783 o->chan = NULL;
4784}
4785
4786/*!
4787 * \internal
4788 * \brief Check if the member status is available.
4789 *
4790 * \param status Member status to check if available.
4791 *
4792 * \retval non-zero if the member status is available.
4793 */
4795{
4797}
4798
4799/*!
4800 * \internal
4801 * \brief Determine if can ring a queue entry.
4802 *
4803 * \param qe Queue entry to check.
4804 * \param call Member call attempt.
4805 *
4806 * \retval non-zero if an entry can be called.
4807 */
4808static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
4809{
4810 struct member *memberp = call->member;
4811 int wrapuptime;
4812
4813 if (memberp->paused) {
4814 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4815 return 0;
4816 }
4817
4818 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4819 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4820 return 0;
4821 }
4822
4823 if (memberp->lastqueue) {
4824 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4825 } else {
4826 wrapuptime = get_wrapuptime(qe->parent, memberp);
4827 }
4828 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4829 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4830 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4831 call->interface);
4832 return 0;
4833 }
4834
4835 if (use_weight && compare_weight(qe->parent, memberp)) {
4836 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4837 qe->parent->name, call->interface);
4838 return 0;
4839 }
4840
4842 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4843 qe->parent->name, call->interface);
4844 return 0;
4845 }
4846
4847 if (!memberp->ringinuse) {
4848 struct member *mem;
4849
4851
4852 mem = ao2_find(pending_members, memberp,
4854 if (mem) {
4855 /*
4856 * If found that means this member is currently being attempted
4857 * from another calling thread, so stop trying from this thread
4858 */
4859 ast_debug(1, "%s has another call trying, can't receive call\n",
4860 call->interface);
4861 ao2_ref(mem, -1);
4863 return 0;
4864 }
4865
4866 /*
4867 * If not found add it to the container so another queue
4868 * won't attempt to call this member at the same time.
4869 */
4870 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4871 ao2_link(pending_members, memberp);
4873
4874 /*
4875 * The queue member is available. Get current status to be sure
4876 * because the device state and extension state callbacks may
4877 * not have updated the status yet.
4878 */
4880 ast_debug(1, "%s actually not available, can't receive call\n",
4881 call->interface);
4882 pending_members_remove(memberp);
4883 return 0;
4884 }
4885 }
4886
4887 return 1;
4888}
4889
4890/*!
4891 * \brief Part 2 of ring_one
4892 *
4893 * Does error checking before attempting to request a channel and call a member.
4894 * This function is only called from ring_one().
4895 * Failure can occur if:
4896 * - Agent on call
4897 * - Agent is paused
4898 * - Wrapup time not expired
4899 * - Priority by another queue
4900 *
4901 * \retval 1 on success to reach a free agent
4902 * \retval 0 on failure to get agent.
4903 */
4904static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
4905{
4906 int res;
4907 int status;
4908 char tech[256];
4909 char *location;
4910 struct ast_format_cap *nativeformats;
4911 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4912
4913 /* on entry here, we know that tmp->chan == NULL */
4914 if (!can_ring_entry(qe, tmp)) {
4915 tmp->stillgoing = 0;
4916 ++*busies;
4917 return 0;
4918 }
4919
4920 ast_copy_string(tech, tmp->interface, sizeof(tech));
4921 if ((location = strchr(tech, '/'))) {
4922 *location++ = '\0';
4923 } else {
4924 location = "";
4925 }
4926
4928 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4930
4931 /* Request the peer */
4932 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4933 ao2_cleanup(nativeformats);
4934 if (!tmp->chan) { /* If we can't, just go on to the next call */
4935 ao2_lock(qe->parent);
4936 qe->parent->rrpos++;
4937 qe->linpos++;
4938 ao2_unlock(qe->parent);
4939
4941
4942 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4943 tmp->stillgoing = 0;
4944 ++*busies;
4945 return 0;
4946 }
4947
4948 ast_channel_lock_both(tmp->chan, qe->chan);
4949
4952 if (qe->cancel_answered_elsewhere) {
4954 }
4955 ast_channel_appl_set(tmp->chan, "AppQueue");
4956 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4957 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4958
4959 /* If the new channel has no callerid, try to guess what it should be */
4960 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4962 struct ast_party_caller caller;
4963
4965 caller.id = ast_channel_connected(qe->chan)->id;
4966 caller.ani = ast_channel_connected(qe->chan)->ani;
4967 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4968 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4970 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4972 }
4973 tmp->dial_callerid_absent = 1;
4974 }
4975
4977
4979
4981
4982 /* Inherit specially named variables from parent channel */
4986
4987 /* Presense of ADSI CPE on outgoing channel follows ours */
4989
4990 /* Inherit context and extension */
4991 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
4993
4994 /* Save the original channel name to detect call pickup masquerading in. */
4996
4999
5000 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
5001 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
5002
5003 /* PREDIAL: Run gosub on the callee's channel */
5004 if (qe->predial_callee) {
5005 ast_pre_call(tmp->chan, qe->predial_callee);
5006 }
5007
5008 /* Place the call, but don't wait on the answer */
5009 if ((res = ast_call(tmp->chan, location, 0))) {
5010 /* Again, keep going even if there's an error */
5011 ast_verb(3, "Couldn't call %s\n", tmp->interface);
5012 do_hang(tmp);
5013 ++*busies;
5014 return 0;
5015 }
5016
5017 ast_channel_lock_both(tmp->chan, qe->chan);
5018
5019 blob = ast_json_pack("{s: s, s: s, s: s}",
5020 "Queue", qe->parent->name,
5021 "Interface", tmp->interface,
5022 "MemberName", tmp->member->membername);
5023 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
5024
5026
5029
5030 ast_verb(3, "Called %s\n", tmp->interface);
5031
5032 return 1;
5033}
5034
5035/*! \brief find the entry with the best metric, or NULL */
5037{
5038 struct callattempt *best = NULL, *cur;
5039
5040 for (cur = outgoing; cur; cur = cur->q_next) {
5041 if (cur->stillgoing && /* Not already done */
5042 !cur->chan && /* Isn't already going */
5043 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
5044 best = cur;
5045 }
5046 }
5047
5048 return best;
5049}
5050
5051/*!
5052 * \brief Place a call to a queue member.
5053 *
5054 * Once metrics have been calculated for each member, this function is used
5055 * to place a call to the appropriate member (or members). The low-level
5056 * channel-handling and error detection is handled in ring_entry
5057 *
5058 * \retval 1 if a member was called successfully
5059 * \retval 0 otherwise
5060 */
5061static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
5062{
5063 int ret = 0;
5064 struct callattempt *cur;
5065
5066 if (qe->predial_callee) {
5068 for (cur = outgoing; cur; cur = cur->q_next) {
5069 if (cur->stillgoing && cur->chan) {
5071 }
5072 }
5073 }
5074
5075 while (ret == 0) {
5076 struct callattempt *best = find_best(outgoing);
5077 if (!best) {
5078 ast_debug(1, "Nobody left to try ringing in queue\n");
5079 break;
5080 }
5082 /* Ring everyone who shares this best metric (for ringall) */
5083 for (cur = outgoing; cur; cur = cur->q_next) {
5084 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
5085 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
5086 ret |= ring_entry(qe, cur, busies);
5087 if (qe->predial_callee && cur->chan) {
5089 }
5090 }
5091 }
5092 } else {
5093 /* Ring just the best channel */
5094 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
5095 ret = ring_entry(qe, best, busies);
5096 if (qe->predial_callee && best->chan) {
5098 }
5099 }
5100
5101 /* If we have timed out, break out */
5102 if (qe->expire && (time(NULL) >= qe->expire)) {
5103 ast_debug(1, "Queue timed out while ringing members.\n");
5104 ret = 0;
5105 break;
5106 }
5107 }
5108 if (qe->predial_callee) {
5109 for (cur = outgoing; cur; cur = cur->q_next) {
5110 if (cur->stillgoing && cur->chan) {
5112 }
5113 }
5115 }
5116
5117 return ret;
5118}
5119
5120/*! \brief Search for best metric and add to Round Robbin queue */
5121static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
5122{
5123 struct callattempt *best = find_best(outgoing);
5124
5125 if (best) {
5126 /* Ring just the best channel */
5127 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5128 qe->parent->rrpos = best->metric % 1000;
5129 } else {
5130 /* Just increment rrpos */
5131 if (qe->parent->wrapped) {
5132 /* No more channels, start over */
5133 qe->parent->rrpos = 0;
5134 } else {
5135 /* Prioritize next entry */
5136 qe->parent->rrpos++;
5137 }
5138 }
5139 qe->parent->wrapped = 0;
5140
5141 return 0;
5142}
5143
5144/*! \brief Search for best metric and add to Linear queue */
5145static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
5146{
5147 struct callattempt *best = find_best(outgoing);
5148
5149 if (best) {
5150 /* Ring just the best channel */
5151 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5152 qe->linpos = best->metric % 1000;
5153 } else {
5154 /* Just increment rrpos */
5155 if (qe->linwrapped) {
5156 /* No more channels, start over */
5157 qe->linpos = 0;
5158 } else {
5159 /* Prioritize next entry */
5160 qe->linpos++;
5161 }
5162 }
5163 qe->linwrapped = 0;
5164
5165 return 0;
5166}
5167
5168/*! \brief Playback announcement to queued members if period has elapsed */
5170{
5171 int res = 0;
5172 time_t now;
5173
5174 /* Get the current time */
5175 time(&now);
5176
5177 /* Check to see if it is time to announce */
5179 return 0;
5180 }
5181
5182 /* Stop the music on hold so we can play our own file */
5183 if (ringing) {
5184 ast_indicate(qe->chan,-1);
5185 } else {
5186 ast_moh_stop(qe->chan);
5187 }
5188
5189 ast_verb(3, "Playing periodic announcement\n");
5190
5192 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5196 }
5197
5198 /* play the announcement */
5200
5201 if (res > 0 && !valid_exit(qe, res)) {
5202 res = 0;
5203 }
5204
5205 /* Resume Music on Hold if the caller is going to stay in the queue */
5206 if (!res) {
5207 if (ringing) {
5209 } else {
5210 ast_moh_start(qe->chan, qe->moh, NULL);
5211 }
5212 }
5213
5214 /* update last_periodic_announce_time */
5216 time(&qe->last_periodic_announce_time);
5217 } else {
5219 }
5220
5221 /* Update the current periodic announcement to the next announcement */
5222 if (!qe->parent->randomperiodicannounce) {
5224 }
5225
5226 return res;
5227}
5228
5229/*! \brief Record that a caller gave up on waiting in queue */
5230static void record_abandoned(struct queue_ent *qe)
5231{
5232 int callabandonedinsl = 0;
5233 time_t now;
5234
5235 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5236
5237 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5238
5240 ao2_lock(qe->parent);
5241 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5242 "Queue", qe->parent->name,
5243 "Position", qe->pos,
5244 "OriginalPosition", qe->opos,
5245 "HoldTime", (int)(time(NULL) - qe->start));
5246
5247
5248 time(&now);
5249 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5250 if (callabandonedinsl) {
5252 }
5253
5254 qe->parent->callsabandoned++;
5255 ao2_unlock(qe->parent);
5256
5257 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5258}
5259
5260/*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
5261static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
5262{
5263 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5264
5265 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
5266
5267 /* Stop ringing, and resume MOH if specified */
5268 if (qe->ring_when_ringing) {
5269 ast_indicate(qe->chan, -1);
5270 ast_moh_start(qe->chan, qe->moh, NULL);
5271 }
5272
5273 blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
5274 "Queue", qe->parent->name,
5275 "Interface", interface,
5276 "MemberName", membername,
5277 "RingTime", rnatime);
5278 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
5279
5280 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
5282 if (qe->parent->autopausedelay > 0) {
5283 struct member *mem;
5284 ao2_lock(qe->parent);
5285 if ((mem = interface_exists(qe->parent, interface))) {
5286 time_t idletime = time(&idletime)-mem->lastcall;
5287 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
5288 ao2_unlock(qe->parent);
5289 ao2_ref(mem, -1);
5290 return;
5291 }
5292 ao2_ref(mem, -1);
5293 }
5294 ao2_unlock(qe->parent);
5295 }
5296 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
5297 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
5298 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
5299 interface, qe->parent->name);
5300 } else {
5301 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
5302 }
5303 } else {
5304 /* If queue autopause is mode all, just don't send any queue to stop.
5305 * the function will stop in all queues */
5306 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
5307 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
5308 interface, qe->parent->name);
5309 } else {
5310 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
5311 }
5312 }
5313 }
5314 return;
5315}
5316
5317/*!
5318 * \internal
5319 * \brief Update connected line on chan from peer.
5320 * \since 13.6.0
5321 *
5322 * \param chan Channel to get connected line updated.
5323 * \param peer Channel providing connected line information.
5324 * \param is_caller Non-zero if chan is the calling channel.
5325 */
5326static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
5327{
5328 struct ast_party_connected_line connected_caller;
5329
5330 ast_party_connected_line_init(&connected_caller);
5331
5332 ast_channel_lock(peer);
5334 ast_channel_unlock(peer);
5336 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5337 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5338 }
5339 ast_party_connected_line_free(&connected_caller);
5340}
5341
5342#define AST_MAX_WATCHERS 256
5343/*!
5344 * \brief Wait for a member to answer the call
5345 *
5346 * \param[in] qe the queue_ent corresponding to the caller in the queue
5347 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
5348 * \param[in] to the amount of time (in milliseconds) to wait for a response
5349 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
5350 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
5351 * \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
5352 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
5353 *
5354 * \todo eventually all call forward logic should be integrated into and replaced by ast_call_forward()
5355 */
5356static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
5357{
5358 const char *queue = qe->parent->name;
5359 struct callattempt *o, *start = NULL, *prev = NULL;
5360 int status;
5361 int numbusies = prebusies;
5362 int numnochan = 0;
5363 int stillgoing = 0;
5364 int orig = *to;
5365 struct ast_frame *f;
5366 struct callattempt *peer = NULL;
5367 struct ast_channel *winner;
5368 struct ast_channel *in = qe->chan;
5369 char on[80] = "";
5370 char membername[80] = "";
5371 long starttime = 0;
5372 long endtime = 0;
5373 char *inchan_name;
5374 struct timeval start_time_tv = ast_tvnow();
5375 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5376
5378 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5380
5381 starttime = (long) time(NULL);
5382
5383 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5384 int numlines, retry, pos = 1;
5385 struct ast_channel *watchers[AST_MAX_WATCHERS];
5386 watchers[0] = in;
5387 start = NULL;
5388
5389 for (retry = 0; retry < 2; retry++) {
5390 numlines = 0;
5391 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5392 if (o->stillgoing) { /* Keep track of important channels */
5393 stillgoing = 1;
5394 if (o->chan) {
5395 if (pos < AST_MAX_WATCHERS) {
5396 watchers[pos++] = o->chan;
5397 }
5398 if (!start) {
5399 start = o;
5400 } else {
5401 prev->call_next = o;
5402 }
5403 prev = o;
5404 }
5405 } else if (prev) {
5406 prev->call_next = NULL;
5407 }
5408 numlines++;
5409 }
5410 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5411 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5412 break;
5413 }
5414 /* On "ringall" strategy we only move to the next penalty level
5415 when *all* ringing phones are done in the current penalty level */
5416 ring_one(qe, outgoing, &numbusies);
5417 /* and retry... */
5418 }
5419 if (pos == 1 /* not found */) {
5420 if (numlines == (numbusies + numnochan)) {
5421 ast_debug(1, "Everyone is busy at this time\n");
5422 } else {
5423 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5424 }
5425 *to = 0;
5426 return NULL;
5427 }
5428
5429 /* Poll for events from both the incoming channel as well as any outgoing channels */
5430 winner = ast_waitfor_n(watchers, pos, to);
5431
5432 /* Service all of the outgoing channels */
5433 for (o = start; o; o = o->call_next) {
5434 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5435 * ast_strdupa in a loop like this one can cause a stack overflow
5436 */
5437 char ochan_name[AST_CHANNEL_NAME];
5438
5439 if (o->chan) {
5441 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5443 }
5444 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5445 if (!peer) {
5446 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5447 if (o->orig_chan_name
5448 && strcmp(o->orig_chan_name, ochan_name)) {
5449 /*
5450 * The channel name changed so we must generate COLP update.
5451 * Likely because a call pickup channel masqueraded in.
5452 */
5454 } else if (!o->block_connected_update) {
5455 if (o->pending_connected_update) {
5458 }
5459 } else if (!o->dial_callerid_absent) {
5461 }
5462 }
5463 if (o->aoc_s_rate_list) {
5464 size_t encoded_size;
5465 struct ast_aoc_encoded *encoded;
5466 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5467 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5468 ast_aoc_destroy_encoded(encoded);
5469 }
5470 }
5471 peer = o;
5472 }
5473 } else if (o->chan && (o->chan == winner)) {
5474
5475 ast_copy_string(on, o->member->interface, sizeof(on));
5476 ast_copy_string(membername, o->member->membername, sizeof(membername));
5477
5478 /* Before processing channel, go ahead and check for forwarding */
5479 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5480 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5482 "CANCEL", ast_channel_call_forward(o->chan));
5483 numnochan++;
5484 do_hang(o);
5485 winner = NULL;
5486 continue;
5488 struct ast_channel *original = o->chan;
5489 char forwarder[AST_CHANNEL_NAME];
5490 char tmpchan[256];
5491 char *stuff;
5492 char *tech;
5493 int failed = 0;
5494
5495 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5496 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5497 if ((stuff = strchr(tmpchan, '/'))) {
5498 *stuff++ = '\0';
5499 tech = tmpchan;
5500 } else {
5501 const char *forward_context;
5503 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5504 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5506 stuff = tmpchan;
5507 tech = "Local";
5508 }
5509 if (!strcasecmp(tech, "Local")) {
5510 /*
5511 * Drop the connected line update block for local channels since
5512 * this is going to run dialplan and the user can change his
5513 * mind about what connected line information he wants to send.
5514 */
5516 }
5517
5518 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5519 /* Setup parameters */
5521 if (!o->chan) {
5523 "Forwarding failed to create channel to dial '%s/%s'\n",
5524 tech, stuff);
5525 o->stillgoing = 0;
5526 numnochan++;
5527 } else {
5528 ast_channel_lock_both(o->chan, original);
5530 ast_channel_redirecting(original));
5532 ast_channel_unlock(original);
5533
5537 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5539
5540 if (o->pending_connected_update) {
5541 /*
5542 * Re-seed the callattempt's connected line information with
5543 * previously acquired connected line info from the queued
5544 * channel. The previously acquired connected line info could
5545 * have been set through the CONNECTED_LINE dialplan function.
5546 */
5549 }
5550
5553
5555
5558 /*
5559 * The call was not previously redirected so it is
5560 * now redirected from this number.
5561 */
5567 }
5568
5570
5575
5578 && !o->block_connected_update) {
5579 struct ast_party_redirecting redirecting;
5580
5581 /*
5582 * Redirecting updates to the caller make sense only on single
5583 * call at a time strategies.
5584 *
5585 * Need to re-evaluate if calling unlock is still required as we no longer
5586 * use macro.
5587 */
5588 ast_party_redirecting_init(&redirecting);
5591 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5592 ast_channel_update_redirecting(in, &redirecting, NULL);
5593 }
5594 ast_party_redirecting_free(&redirecting);
5595 } else {
5597 }
5598
5599 if (ast_call(o->chan, stuff, 0)) {
5600 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5601 tech, stuff);
5602 failed = 1;
5603 }
5604 }
5605
5607 "CANCEL", ast_channel_call_forward(original));
5608 if (o->chan) {
5609 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5610 }
5611
5612 if (failed) {
5613 do_hang(o);
5614 numnochan++;
5615 }
5616
5617 /* Hangup the original channel now, in case we needed it */
5618 ast_hangup(winner);
5619 continue;
5620 }
5621 f = ast_read(winner);
5622 if (f) {
5623 if (f->frametype == AST_FRAME_CONTROL) {
5624 switch (f->subclass.integer) {
5625 case AST_CONTROL_ANSWER:
5626 /* This is our guy if someone answered. */
5627 if (!peer) {
5628 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5629 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5630 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5631 if (o->orig_chan_name
5632 && strcmp(o->orig_chan_name, ochan_name)) {
5633 /*
5634 * The channel name changed so we must generate COLP update.
5635 * Likely because a call pickup channel masqueraded in.
5636 */
5638 } else if (!o->block_connected_update) {
5639 if (o->pending_connected_update) {
5642 }
5643 } else if (!o->dial_callerid_absent) {
5645 }
5646 }
5647 if (o->aoc_s_rate_list) {
5648 size_t encoded_size;
5649 struct ast_aoc_encoded *encoded;
5650 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5651 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5652 ast_aoc_destroy_encoded(encoded);
5653 }
5654 }
5655 peer = o;
5656 }
5657 break;
5658 case AST_CONTROL_BUSY:
5659 ast_verb(3, "%s is busy\n", ochan_name);
5660 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5661 endtime = (long) time(NULL);
5662 endtime -= starttime;
5663 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5664 do_hang(o);
5666 if (qe->parent->timeoutrestart) {
5667 start_time_tv = ast_tvnow();
5668 }
5669 /* Have enough time for a queue member to answer? */
5670 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5671 ring_one(qe, outgoing, &numbusies);
5672 starttime = (long) time(NULL);
5673 }
5674 }
5675 numbusies++;
5676 break;
5678 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5679 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5680 endtime = (long) time(NULL);
5681 endtime -= starttime;
5682 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5683 do_hang(o);
5685 if (qe->parent->timeoutrestart) {
5686 start_time_tv = ast_tvnow();
5687 }
5688 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5689 ring_one(qe, outgoing, &numbusies);
5690 starttime = (long) time(NULL);
5691 }
5692 }
5693 numbusies++;
5694 break;
5696 ast_verb(3, "%s is ringing\n", ochan_name);
5697
5698 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5699
5700 /* Start ring indication when the channel is ringing, if specified */
5701 if (qe->ring_when_ringing) {
5702 ast_moh_stop(qe->chan);
5704 }
5705 break;
5707 /* Ignore going off hook */
5708 break;
5710 if (o->block_connected_update) {
5711 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5712 break;
5713 }
5716
5717 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5723 break;
5724 }
5725
5726 /*
5727 * Prevent using the CallerID from the outgoing channel since we
5728 * got a connected line update from it.
5729 */
5730 o->dial_callerid_absent = 1;
5731
5732 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5734 }
5735 break;
5736 case AST_CONTROL_AOC:
5737 {
5738 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5739 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5741 o->aoc_s_rate_list = decoded;
5742 } else {
5743 ast_aoc_destroy_decoded(decoded);
5744 }
5745 }
5746 break;
5749 /*
5750 * Redirecting updates to the caller make sense only on single
5751 * call at a time strategies.
5752 */
5753 break;
5754 }
5755 if (o->block_connected_update) {
5756 ast_verb(3, "Redirecting update to %s prevented\n",
5757 inchan_name);
5758 break;
5759 }
5760 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5761 ochan_name, inchan_name);
5762 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5764 }
5765 break;
5768 break;
5769 default:
5770 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5771 break;
5772 }
5773 }
5774 ast_frfree(f);
5775 } else { /* ast_read() returned NULL */
5776 endtime = (long) time(NULL) - starttime;
5777 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5778 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5779 do_hang(o);
5781 if (qe->parent->timeoutrestart) {
5782 start_time_tv = ast_tvnow();
5783 }
5784 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5785 ring_one(qe, outgoing, &numbusies);
5786 starttime = (long) time(NULL);
5787 }
5788 }
5789 }
5790 }
5791 }
5792
5793 /* If we received an event from the caller, deal with it. */
5794 if (winner == in) {
5795 f = ast_read(in);
5796 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5797 /* Got hung up */
5798 *to = -1;
5799 if (f) {
5800 if (f->data.uint32) {
5802 }
5803 ast_frfree(f);
5804 }
5805 canceled_by_caller = 1;
5806 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5807 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5808 *to = 0;
5809 ast_frfree(f);
5810 canceled_by_caller = 1;
5811 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5812 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5813 *to = 0;
5814 *digit = f->subclass.integer;
5815 ast_frfree(f);
5816 canceled_by_caller = 1;
5817 }
5818 /* When caller hung up or pressed * or digit. */
5819 if (canceled_by_caller) {
5821 for (o = start; o; o = o->call_next) {
5822 if (o->chan) {
5823 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), o->member->membername, "RINGCANCELED", "%d", (int) ast_tvdiff_ms(ast_tvnow(), start_time_tv));
5824 }
5825 }
5826 return NULL;
5827 }
5828
5829 /* Send the frame from the in channel to all outgoing channels. */
5830 for (o = start; o; o = o->call_next) {
5831 if (!o->stillgoing || !o->chan) {
5832 /* This outgoing channel has died so don't send the frame to it. */
5833 continue;
5834 }
5835 switch (f->frametype) {
5836 case AST_FRAME_CONTROL:
5837 switch (f->subclass.integer) {
5839 if (o->block_connected_update) {
5840 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5841 break;
5842 }
5843 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5845 }
5846 break;
5848 if (o->block_connected_update) {
5849 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5850 break;
5851 }
5852 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5854 }
5855 break;
5856 default:
5857 /* We are not going to do anything with this frame. */
5858 goto skip_frame;
5859 }
5860 break;
5861 default:
5862 /* We are not going to do anything with this frame. */
5863 goto skip_frame;
5864 }
5865 }
5866skip_frame:;
5867
5868 ast_frfree(f);
5869 }
5870 }
5871
5872 if (!*to) {
5873 for (o = start; o; o = o->call_next) {
5874 if (o->chan) {
5875 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5876 }
5877 }
5878
5879 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5880 }
5881
5882 return peer;
5883}
5884
5885/*!
5886 * \brief Check if we should start attempting to call queue members.
5887 *
5888 * A simple process, really. Count the number of members who are available
5889 * to take our call and then see if we are in a position in the queue at
5890 * which a member could accept our call.
5891 *
5892 * \param[in] qe The caller who wants to know if it is his turn
5893 * \retval 0 It is not our turn
5894 * \retval 1 It is our turn
5895 */
5896static int is_our_turn(struct queue_ent *qe)
5897{
5898 struct queue_ent *ch;
5899 int res;
5900 int avl;
5901 int idx = 0;
5902 /* This needs a lock. How many members are available to be served? */
5903 ao2_lock(qe->parent);
5904
5905 avl = num_available_members(qe->parent);
5906
5907 ch = qe->parent->head;
5908
5909 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5910
5911 while ((idx < avl) && (ch) && (ch != qe)) {
5912 if (!ch->pending) {
5913 idx++;
5914 }
5915 ch = ch->next;
5916 }
5917
5918 ao2_unlock(qe->parent);
5919 /* If the queue entry is within avl [the number of available members] calls from the top ...
5920 * Autofill and position check added to support autofill=no (as only calls
5921 * from the front of the queue are valid when autofill is disabled)
5922 */
5923 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5924 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5925 res = 1;
5926 } else {
5927 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5928 res = 0;
5929 }
5930
5931 /* Update realtime members if this is the first call and number of avalable members is 0 */
5932 if (avl == 0 && qe->pos == 1) {
5934 }
5935
5936 return res;
5937}
5938
5939/*!
5940 * \brief update rules for queues
5941 *
5942 * Calculate min/max penalties making sure if relative they stay within bounds.
5943 * Update queues penalty and set dialplan vars, goto next list entry.
5944*/
5945static void update_qe_rule(struct queue_ent *qe)
5946{
5947 int max_penalty = INT_MAX;
5948
5949 if (qe->max_penalty != INT_MAX) {
5950 char max_penalty_str[20];
5951
5952 if (qe->pr->max_relative) {
5953 max_penalty = qe->max_penalty + qe->pr->max_value;
5954 } else {
5955 max_penalty = qe->pr->max_value;
5956 }
5957
5958 /* a relative change to the penalty could put it below 0 */
5959 if (max_penalty < 0) {
5960 max_penalty = 0;
5961 }
5962
5963 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5964 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5966 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5967 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5968 }
5969
5970 if (qe->min_penalty != INT_MAX) {
5971 char min_penalty_str[20];
5972 int min_penalty;
5973
5974 if (qe->pr->min_relative) {
5975 min_penalty = qe->min_penalty + qe->pr->min_value;
5976 } else {
5977 min_penalty = qe->pr->min_value;
5978 }
5979
5980 /* a relative change to the penalty could put it below 0 */
5981 if (min_penalty < 0) {
5982 min_penalty = 0;
5983 }
5984
5985 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
5987 }
5988
5989 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
5990 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
5992 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
5993 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
5994 }
5995
5996 if (qe->raise_penalty != INT_MAX) {
5997 char raise_penalty_str[20];
5998 int raise_penalty;
5999
6000 if (qe->pr->raise_relative) {
6002 } else {
6004 }
6005
6006 /* a relative change to the penalty could put it below 0 */
6007 if (raise_penalty < 0) {
6008 raise_penalty = 0;
6009 }
6010
6011 if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
6013 }
6014
6015 snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
6016 pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
6018 ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
6019 qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
6020 }
6021
6022 qe->pr = AST_LIST_NEXT(qe->pr, list);
6023}
6024
6025/*! \brief The waiting areas for callers who are not actively calling members
6026 *
6027 * This function is one large loop. This function will return if a caller
6028 * either exits the queue or it becomes that caller's turn to attempt calling
6029 * queue members. Inside the loop, we service the caller with periodic announcements,
6030 * holdtime announcements, etc. as configured in queues.conf
6031 *
6032 * \retval 0 if the caller's turn has arrived
6033 * \retval -1 if the caller should exit the queue.
6034 */
6035static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
6036{
6037 int res = 0;
6038
6039 /* This is the holding pen for callers 2 through maxlen */
6040 for (;;) {
6041
6042 /* A request to withdraw this call from the queue arrived */
6043 if (qe->withdraw) {
6044 *reason = QUEUE_WITHDRAW;
6045 res = 1;
6046 break;
6047 }
6048
6049 if (is_our_turn(qe)) {
6050 break;
6051 }
6052
6053 /* If we have timed out, break out */
6054 if (qe->expire && (time(NULL) >= qe->expire)) {
6055 *reason = QUEUE_TIMEOUT;
6056 break;
6057 }
6058
6059 if (qe->parent->leavewhenempty) {
6060 int status = 0;
6061
6063 record_abandoned(qe);
6064 *reason = QUEUE_LEAVEEMPTY;
6065 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
6066 res = -1;
6067 qe->handled = -1;
6068 break;
6069 }
6070 }
6071
6072 /* Make a position announcement, if enabled */
6073 if (qe->parent->announcefrequency &&
6074 (res = say_position(qe,ringing))) {
6075 break;
6076 }
6077
6078 /* If we have timed out, break out */
6079 if (qe->expire && (time(NULL) >= qe->expire)) {
6080 *reason = QUEUE_TIMEOUT;
6081 break;
6082 }
6083
6084 /* Make a periodic announcement, if enabled */
6087 break;
6088
6089 /* see if we need to move to the next penalty level for this queue */
6090 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
6091 update_qe_rule(qe);
6092 }
6093
6094 /* If we have timed out, break out */
6095 if (qe->expire && (time(NULL) >= qe->expire)) {
6096 *reason = QUEUE_TIMEOUT;
6097 break;
6098 }
6099
6100 /* Wait a second before checking again */
6101 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
6102 if (res > 0 && !valid_exit(qe, res)) {
6103 res = 0;
6104 } else {
6105 break;
6106 }
6107 }
6108
6109 /* If we have timed out, break out */
6110 if (qe->expire && (time(NULL) >= qe->expire)) {
6111 *reason = QUEUE_TIMEOUT;
6112 break;
6113 }
6114 }
6115
6116 return res;
6117}
6118
6119/*!
6120 * \brief update the queue status
6121 * \retval 0 always
6122*/
6123static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
6124{
6125 int oldtalktime;
6126 int newtalktime = time(NULL) - starttime;
6127 struct member *mem;
6128 struct call_queue *qtmp;
6129 struct ao2_iterator queue_iter;
6130
6131 /* It is possible for us to be called when a call has already been considered terminated
6132 * and data updated, so to ensure we only act on the call that the agent is currently in
6133 * we check when the call was bridged.
6134 */
6135 if (!starttime || (member->starttime != starttime)) {
6136 return 0;
6137 }
6138
6139 if (shared_lastcall) {
6140 queue_iter = ao2_iterator_init(queues, 0);
6141 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
6142 ao2_lock(qtmp);
6143 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
6144 time(&mem->lastcall);
6145 mem->calls++;
6146 mem->callcompletedinsl = 0;
6147 mem->starttime = 0;
6148 mem->lastqueue = q;
6149 ao2_ref(mem, -1);
6150 }
6151 ao2_unlock(qtmp);
6152 queue_t_unref(qtmp, "Done with iterator");
6153 }
6154 ao2_iterator_destroy(&queue_iter);
6155 } else {
6156 ao2_lock(q);
6157 time(&member->lastcall);
6159 member->calls++;
6160 member->starttime = 0;
6161 member->lastqueue = q;
6162 ao2_unlock(q);
6163 }
6164 /* Member might never experience any direct status change (local
6165 * channel with forwarding in particular). If that's the case,
6166 * this is the last chance to remove it from pending or subsequent
6167 * calls will not occur.
6168 */
6170
6171 ao2_lock(q);
6172 q->callscompleted++;
6173 if (callcompletedinsl) {
6174 q->callscompletedinsl++;
6175 }
6176 if (q->callscompleted == 1) {
6177 q->talktime = newtalktime;
6178 } else {
6179 /* Calculate talktime using the same exponential average as holdtime code */
6180 oldtalktime = q->talktime;
6181 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
6182 }
6183 ao2_unlock(q);
6184 return 0;
6185}
6186
6187/*! \brief Calculate the metric of each member in the outgoing callattempts
6188 *
6189 * A numeric metric is given to each member depending on the ring strategy used
6190 * by the queue. Members with lower metrics will be called before members with
6191 * higher metrics
6192 * \retval -1 if penalties are exceeded
6193 * \retval 0 otherwise
6194 */
6195static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
6196{
6197 /* disregarding penalty on too few members? */
6198 int membercount = ao2_container_count(q->members);
6199 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6200 int penalty = mem->penalty;
6201
6202 if (usepenalty) {
6203 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6204 /* Low penalty is raised up to the current minimum */
6205 penalty = qe->raise_penalty;
6206 }
6207 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6208 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6209 return -1;
6210 }
6211 } else {
6212 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6213 membercount, q->penaltymemberslimit);
6214 }
6215
6216 switch (q->strategy) {
6218 /* Everyone equal, except for penalty */
6219 tmp->metric = penalty * 1000000 * usepenalty;
6220 break;
6222 if (pos < qe->linpos) {
6223 tmp->metric = 1000 + pos;
6224 } else {
6225 if (pos > qe->linpos) {
6226 /* Indicate there is another priority */
6227 qe->linwrapped = 1;
6228 }
6229 tmp->metric = pos;
6230 }
6231 tmp->metric += penalty * 1000000 * usepenalty;
6232 break;
6235 pos = mem->queuepos;
6236 if (pos < q->rrpos) {
6237 tmp->metric = 1000 + pos;
6238 } else {
6239 if (pos > q->rrpos) {
6240 /* Indicate there is another priority */
6241 q->wrapped = 1;
6242 }
6243 tmp->metric = pos;
6244 }
6245 tmp->metric += penalty * 1000000 * usepenalty;
6246 break;
6248 tmp->metric = ast_random() % 1000;
6249 tmp->metric += penalty * 1000000 * usepenalty;
6250 break;
6252 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6253 break;
6255 tmp->metric = mem->calls;
6256 tmp->metric += penalty * 1000000 * usepenalty;
6257 break;
6259 if (!mem->lastcall) {
6260 tmp->metric = 0;
6261 } else {
6262 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6263 }
6264 tmp->metric += penalty * 1000000 * usepenalty;
6265 break;
6266 default:
6267 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6268 break;
6269 }
6270 return 0;
6271}
6272
6276 TRANSFER
6278
6279/*! \brief Send out AMI message with member call completion status information */
6280static void send_agent_complete(const char *queuename, struct ast_channel_snapshot *caller,
6281 struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart,
6282 time_t callstart, enum agent_complete_reason rsn)
6283{
6284 const char *reason = NULL; /* silence dumb compilers */
6285 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6286
6287 switch (rsn) {
6288 case CALLER:
6289 reason = "caller";
6290 break;
6291 case AGENT:
6292 reason = "agent";
6293 break;
6294 case TRANSFER:
6295 reason = "transfer";
6296 break;
6297 }
6298
6299 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6300 "Queue", queuename,
6301 "Interface", member->interface,
6302 "MemberName", member->membername,
6303 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6304 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6305 "Reason", reason ?: "");
6306
6308 queue_agent_complete_type(), blob);
6309}
6310
6311static void queue_agent_cb(void *userdata, struct stasis_subscription *sub,
6312 struct stasis_message *msg)
6313{
6314 struct ast_channel_blob *agent_blob;
6315
6316 agent_blob = stasis_message_data(msg);
6317
6319 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6320 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6321 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6323 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6324 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6325 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6326 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6327 }
6328}
6329
6330/*!
6331 * \brief Structure representing relevant data during a local channel optimization
6332 *
6333 * The reason we care about local channel optimizations is that we want to be able
6334 * to accurately report when the caller and queue member have stopped talking to
6335 * each other. A local channel optimization can cause it to appear that the conversation
6336 * has stopped immediately after it has begun. By tracking that the relevant channels
6337 * to monitor have changed due to a local channel optimization, we can give accurate
6338 * reports.
6339 *
6340 * Local channel optimizations for queues are restricted from their normal operation.
6341 * Bridges created by queues can only be the destination of local channel optimizations,
6342 * not the source. In addition, move-swap local channel optimizations are the only
6343 * permitted types of local channel optimization.
6344 *
6345 * This data is populated when we are told that a local channel optimization begin
6346 * is occurring. When we get told the optimization has ended successfully, we then
6347 * apply the data here into the queue_stasis_data.
6348 */
6350 /*! The uniqueid of the channel that will be taking the place of the caller or member */
6352 /*! Indication of whether we think there is a local channel optimization in progress */
6354 /*! The identifier for this local channel optimization */
6355 unsigned int id;
6356};
6357
6358/*!
6359 * \brief User data for stasis subscriptions used for queue calls.
6360 *
6361 * app_queue subscribes to channel and bridge events for all bridged calls.
6362 * app_queue cares about the following events:
6363 *
6364 * \li bridge enter: To determine the unique ID of the bridge created for the call.
6365 * \li blind transfer: To send an appropriate agent complete event.
6366 * \li attended transfer: To send an appropriate agent complete event.
6367 * \li local optimization: To update caller and member unique IDs for the call.
6368 * \li hangup: To send an appropriate agent complete event.
6369 *
6370 * The stasis subscriptions last until we determine that the caller and the member
6371 * are no longer bridged with each other.
6372 */
6375 /*! The unique ID of the caller's channel. */
6377 /*! The unique ID of the queue member's channel */
6379 /*! The unique ID of the bridge created by the queue */
6382 /*! The relevant queue */
6384 /*! The queue member that has answered the call */
6386 /*! The time at which the caller entered the queue. Start of the caller's hold time */
6388 /*! The time at which the member answered the call. */
6390 /*! The original position of the caller when he entered the queue */
6392 /*! Indication if the call was answered within the configured service level of the queue */
6394 /*! Indicates if the stasis subscriptions are shutting down */
6396 /*! The stasis message router for bridge events */
6398 /*! The stasis message router for channel events */
6400 /*! Local channel optimization details for the caller */
6402 /*! Local channel optimization details for the member */
6404};
6405
6406/*!
6407 * \internal
6408 * \brief Free memory for a queue_stasis_data
6409 */
6410static void queue_stasis_data_destructor(void *obj)
6411{
6412 struct queue_stasis_data *queue_data = obj;
6413
6414 /* This can only happen if refcounts for this object have got severely messed up */
6415 ast_assert(queue_data->bridge_router == NULL);
6416 ast_assert(queue_data->channel_router == NULL);
6417
6418 ao2_cleanup(queue_data->member);
6419 queue_unref(queue_data->queue);
6420 ast_string_field_free_memory(queue_data);
6421}
6422
6423/*!
6424 * \internal
6425 * \brief End all stasis subscriptions on a queue_stasis_data
6426 */
6427static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
6428{
6429 SCOPED_AO2LOCK(lock, queue_data);
6430
6431 queue_data->dying = 1;
6433 queue_data->bridge_router = NULL;
6435 queue_data->channel_router = NULL;
6436}
6437
6438/*!
6439 * \internal
6440 * \brief Allocate a queue_stasis_data and initialize its data.
6441 */
6443 struct ast_channel *peer, struct member *mem, time_t holdstart,
6444 time_t starttime, int callcompletedinsl)
6445{
6446 struct queue_stasis_data *queue_data;
6447
6448 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6449 if (!queue_data) {
6450 return NULL;
6451 }
6452
6453 if (ast_string_field_init(queue_data, 64)) {
6454 ao2_cleanup(queue_data);
6455 return NULL;
6456 }
6457
6460 queue_data->queue = queue_ref(qe->parent);
6461 queue_data->starttime = starttime;
6462 queue_data->holdstart = holdstart;
6464 queue_data->caller_pos = qe->opos;
6465 ao2_ref(mem, +1);
6466 queue_data->member = mem;
6467
6468 return queue_data;
6469}
6470
6471/*!
6472 * \internal
6473 * \brief Log an attended transfer in the queue log.
6474 *
6475 * Attended transfer queue log messages vary based on the method by which the
6476 * attended transfer was completed.
6477 *
6478 * \param queue_data Data pertaining to the particular call in the queue.
6479 * \param atxfer_msg The stasis attended transfer message data.
6480 */
6481static void log_attended_transfer(struct queue_stasis_data *queue_data,
6482 struct ast_attended_transfer_message *atxfer_msg)
6483{
6484 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6485
6486 if (!transfer_str) {
6487 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6488 return;
6489 }
6490
6491 switch (atxfer_msg->dest_type) {
6493 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6494 break;
6497 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6498 break;
6500 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6501 atxfer_msg->dest.links[1]->base->name);
6502 break;
6505 /* Threeways are headed off and should not be logged here */
6506 ast_assert(0);
6507 return;
6508 }
6509
6510 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6511 ast_str_buffer(transfer_str),
6512 (long) (queue_data->starttime - queue_data->holdstart),
6513 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6514}
6515
6516/*!
6517 * \internal
6518 * \brief Handle a stasis bridge enter event.
6519 *
6520 * We track this particular event in order to learn what bridge
6521 * was created for the queue call.
6522 *
6523 * \param userdata Data pertaining to the particular call in the queue.
6524 * \param sub The stasis subscription on which the message occurred.
6525 * \param msg The stasis message for the bridge enter event
6526 */
6527static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
6528 struct stasis_message *msg)
6529{
6530 struct queue_stasis_data *queue_data = userdata;
6531 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6532 SCOPED_AO2LOCK(lock, queue_data);
6533
6534 if (queue_data->dying) {
6535 return;
6536 }
6537
6538 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6539 return;
6540 }
6541
6542 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6543 ast_string_field_set(queue_data, bridge_uniqueid,
6544 enter_blob->bridge->uniqueid);
6545 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6546 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6547 }
6548}
6549
6550/*!
6551 * \brief Handle a blind transfer event
6552 *
6553 * This event is important in order to be able to log the end of the
6554 * call to the queue log and to stasis.
6555 *
6556 * \param userdata Data pertaining to the particular call in the queue.
6557 * \param sub The stasis subscription on which the message occurred.
6558 * \param msg The stasis message for the blind transfer event
6559 */
6560static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub,
6561 struct stasis_message *msg)
6562{
6563 struct queue_stasis_data *queue_data = userdata;
6564 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6565 const char *exten;
6566 const char *context;
6567 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6568 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6569
6570 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6571 return;
6572 }
6573
6574 ao2_lock(queue_data);
6575
6576 if (queue_data->dying) {
6577 ao2_unlock(queue_data);
6578 return;
6579 }
6580
6581 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6582 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6583 ao2_unlock(queue_data);
6584 return;
6585 }
6586
6587 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6588 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6589
6590 ao2_unlock(queue_data);
6591
6592 exten = transfer_msg->exten;
6593 context = transfer_msg->context;
6594
6595 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6596 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6597 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6598 exten, context,
6599 (long) (queue_data->starttime - queue_data->holdstart),
6600 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6601
6602 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6603 queue_data->holdstart, queue_data->starttime, TRANSFER);
6604 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6605 queue_data->starttime);
6606 remove_stasis_subscriptions(queue_data);
6607}
6608
6609/*!
6610 * \brief Handle an attended transfer event
6611 *
6612 * This event is important in order to be able to log the end of the
6613 * call to the queue log and to stasis.
6614 *
6615 * \param userdata Data pertaining to the particular call in the queue.
6616 * \param sub The stasis subscription on which the message occurred.
6617 * \param msg The stasis message for the attended transfer event.
6618 */
6619static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub,
6620 struct stasis_message *msg)
6621{
6622 struct queue_stasis_data *queue_data = userdata;
6623 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6624 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6625 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6626
6627 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6629 return;
6630 }
6631
6632 ao2_lock(queue_data);
6633
6634 if (queue_data->dying) {
6635 ao2_unlock(queue_data);
6636 return;
6637 }
6638
6639 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6640 ao2_unlock(queue_data);
6641 return;
6642 }
6643
6644 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6645 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6646 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6648 ao2_unlock(queue_data);
6649 return;
6650 }
6651
6652 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6653 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6654
6655 ao2_unlock(queue_data);
6656
6657 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6658 log_attended_transfer(queue_data, atxfer_msg);
6659
6660 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6661 queue_data->holdstart, queue_data->starttime, TRANSFER);
6662 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6663 queue_data->starttime);
6664 remove_stasis_subscriptions(queue_data);
6665}
6666
6667/*!
6668 * \internal
6669 * \brief Callback for all stasis bridge events
6670 *
6671 * Based on the event and what bridge it is on, the task is farmed out to relevant
6672 * subroutines for further processing.
6673 */
6674static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub,
6675 struct stasis_message *msg)
6676{
6678 ao2_cleanup(userdata);
6679 }
6680}
6681
6682/*!
6683 * \internal
6684 * \brief Handler for the beginning of a local channel optimization
6685 *
6686 * This method gathers data relevant to the local channel optimization and stores
6687 * it to be used once the local optimization completes.
6688 *
6689 * \param userdata Data pertaining to the particular call in the queue.
6690 * \param sub The stasis subscription on which the message occurred.
6691 * \param msg The stasis message for the local optimization begin event
6692 */
6693static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub,
6694 struct stasis_message *msg)
6695{
6696 struct queue_stasis_data *queue_data = userdata;
6697 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6698 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6699 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6700 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6701 struct local_optimization *optimization;
6702 unsigned int id;
6703 SCOPED_AO2LOCK(lock, queue_data);
6704
6705 if (queue_data->dying) {
6706 return;
6707 }
6708
6709 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6710 optimization = &queue_data->member_optimize;
6711 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6712 optimization = &queue_data->caller_optimize;
6713 } else {
6714 return;
6715 }
6716
6717 /* We only allow move-swap optimizations, so there had BETTER be a source */
6718 ast_assert(source != NULL);
6719
6720 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6721 if (!optimization->source_chan_uniqueid) {
6722 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6723 return;
6724 }
6726
6727 optimization->id = id;
6728 optimization->in_progress = 1;
6729}
6730
6731/*!
6732 * \internal
6733 * \brief Handler for the end of a local channel optimization
6734 *
6735 * This method takes the data gathered during the local channel optimization begin
6736 * event and applies it to the queue stasis data appropriately. This generally involves
6737 * updating the caller or member unique ID with the channel that is taking the place of
6738 * the previous caller or member.
6739 *
6740 * \param userdata Data pertaining to the particular call in the queue.
6741 * \param sub The stasis subscription on which the message occurred.
6742 * \param msg The stasis message for the local optimization end event
6743 */
6744static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub,
6745 struct stasis_message *msg)
6746{
6747 struct queue_stasis_data *queue_data = userdata;
6748 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6749 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6750 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6751 struct local_optimization *optimization;
6752 int is_caller;
6753 unsigned int id;
6754 SCOPED_AO2LOCK(lock, queue_data);
6755
6756 if (queue_data->dying) {
6757 return;
6758 }
6759
6760 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6761 optimization = &queue_data->member_optimize;
6762 is_caller = 0;
6763 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6764 optimization = &queue_data->caller_optimize;
6765 is_caller = 1;
6766 } else {
6767 return;
6768 }
6769
6771
6772 if (!optimization->in_progress) {
6773 ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6774 return;
6775 }
6776
6777 if (id != optimization->id) {
6778 ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6779 id, optimization->id);
6780 return;
6781 }
6782
6783 if (is_caller) {
6784 ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6785 queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6786 ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6787 } else {
6788 ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6789 queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6790 ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6791 }
6792
6793 optimization->in_progress = 0;
6794}
6795
6796/*!
6797 * \internal
6798 * \brief Handler for hangup stasis event
6799 *
6800 * This is how we determine that the caller or member has hung up and the call
6801 * has ended. An appropriate queue log and stasis message are raised in this
6802 * callback.
6803 *
6804 * \param userdata Data pertaining to the particular call in the queue.
6805 * \param sub The stasis subscription on which the message occurred.
6806 * \param msg The stasis message for the hangup event.
6807 */
6808static void handle_hangup(void *userdata, struct stasis_subscription *sub,
6809 struct stasis_message *msg)
6810{
6811 struct queue_stasis_data *queue_data = userdata;
6812 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6813 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6814 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6815 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6816 enum agent_complete_reason reason;
6817
6818 ao2_lock(queue_data);
6819
6820 if (queue_data->dying) {
6821 ao2_unlock(queue_data);
6822 return;
6823 }
6824
6825 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6826 reason = CALLER;
6827 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6828 reason = AGENT;
6829 } else {
6830 ao2_unlock(queue_data);
6831 return;
6832 }
6833
6834 chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6835 if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6836 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6837 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6838 /* Channel that is hanging up is doing it as part of a transfer.
6839 * We'll get a transfer event later
6840 */
6841 ao2_unlock(queue_data);
6842 return;
6843 }
6844
6845 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6846 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6847
6848 ao2_unlock(queue_data);
6849
6850 ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6851 channel_blob->snapshot->base->name);
6852
6853 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6854 reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6855 (long) (queue_data->starttime - queue_data->holdstart),
6856 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6857
6858 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6859 queue_data->holdstart, queue_data->starttime, reason);
6860 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6861 queue_data->starttime);
6862 remove_stasis_subscriptions(queue_data);
6863}
6864
6865static void handle_masquerade(void *userdata, struct stasis_subscription *sub,
6866 struct stasis_message *msg)
6867{
6868 struct queue_stasis_data *queue_data = userdata;
6869 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6870 const char *new_channel_id;
6871
6872 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6873
6874 ao2_lock(queue_data);
6875
6876 if (queue_data->dying) {
6877 ao2_unlock(queue_data);
6878 return;
6879 }
6880
6881 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6882 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6883 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6884 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6885 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6886 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6887 }
6888
6889 ao2_unlock(queue_data);
6890}
6891
6892/*!
6893 * \internal
6894 * \brief Callback for all stasis channel events
6895 *
6896 * Based on the event and the channels involved, the work is farmed out into
6897 * subroutines for further processing.
6898 */
6899static void queue_channel_cb(void *userdata, struct stasis_subscription *sub,
6900 struct stasis_message *msg)
6901{
6903 ao2_cleanup(userdata);
6904 }
6905}
6906
6907/*!
6908 * \internal
6909 * \brief Create stasis subscriptions for a particular call in the queue.
6910 *
6911 * These subscriptions are created once the call has been answered. The subscriptions
6912 * are put in place so that call progress may be tracked. Once the call can be determined
6913 * to have ended, then messages are logged to the queue log and stasis events are emitted.
6914 *
6915 * \param qe The queue entry representing the caller
6916 * \param peer The channel that has answered the call
6917 * \param mem The queue member that answered the call
6918 * \param holdstart The time at which the caller entered the queue
6919 * \param starttime The time at which the call was answered
6920 * \param callcompletedinsl Indicates if the call was answered within the configured service level of the queue.
6921 * \retval 0 Success
6922 * \retval non-zero Failure
6923 */
6924static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem,
6925 time_t holdstart, time_t starttime, int callcompletedinsl)
6926{
6927 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6928
6929 if (!queue_data) {
6930 return -1;
6931 }
6932
6934 if (!queue_data->bridge_router) {
6935 ao2_ref(queue_data, -1);
6936 return -1;
6937 }
6938
6940 handle_bridge_enter, queue_data);
6942 handle_blind_transfer, queue_data);
6944 handle_attended_transfer, queue_data);
6946 queue_bridge_cb, queue_data);
6947
6949 if (!queue_data->channel_router) {
6950 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6951 * thus beginning the destruction process
6952 */
6954 queue_data->bridge_router = NULL;
6955 return -1;
6956 }
6957
6958 ao2_ref(queue_data, +1);
6962 handle_local_optimization_end, queue_data);
6964 handle_hangup, queue_data);
6966 handle_masquerade, queue_data);
6968 queue_channel_cb, queue_data);
6969
6970 return 0;
6971}
6972
6974 struct call_queue *q;
6976};
6977
6978static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
6979{
6980 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6981 ao2_ref(qeb, +1);
6982 qeb->chan = originator;
6983}
6984
6985static void end_bridge_callback(void *data)
6986{
6987 struct queue_end_bridge *qeb = data;
6988 struct call_queue *q = qeb->q;
6989 struct ast_channel *chan = qeb->chan;
6990
6991 if (ao2_ref(qeb, -1) == 1) {
6992 set_queue_variables(q, chan);
6993 /* This unrefs the reference we made in try_calling when we allocated qeb */
6994 queue_t_unref(q, "Expire bridge_config reference");
6995 }
6996}
6997
6998/*!
6999 * \internal
7000 * \brief Setup the after bridge goto location on the peer.
7001 * \since 12.0.0
7002 *
7003 * \param chan Calling channel for bridge.
7004 * \param peer Peer channel for bridge.
7005 * \param opts Dialing option flags.
7006 * \param opt_args Dialing option argument strings.
7007 */
7008static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
7009{
7010 const char *context;
7011 const char *extension;
7012 int priority;
7013
7014 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
7015 ast_channel_lock(chan);
7019 ast_channel_unlock(chan);
7021 opt_args[OPT_ARG_CALLEE_GO_ON]);
7022 }
7023}
7024
7025static void escape_and_substitute(struct ast_channel *chan, const char *input,
7026 char *output, size_t size)
7027{
7028 const char *m = input;
7029 char escaped[size];
7030 char *p;
7031
7032 for (p = escaped; p < escaped + size - 1; p++, m++) {
7033 switch (*m) {
7034 case '^':
7035 if (*(m + 1) == '{') {
7036 *p = '$';
7037 }
7038 break;
7039 case ',':
7040 *p++ = '\\';
7041 /* Fall through */
7042 default:
7043 *p = *m;
7044 }
7045 if (*m == '\0')
7046 break;
7047 }
7048
7049 if (p == escaped + size) {
7050 escaped[size - 1] = '\0';
7051 }
7052
7053 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
7054}
7055
7056static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
7057{
7058 char escaped_filename[256];
7059 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
7060 char mixmonargs[1512];
7061 char escaped_monitor_exec[1024];
7062 const char *monitor_options;
7063 const char *monitor_exec;
7064
7065 escaped_monitor_exec[0] = '\0';
7066
7067 if (filename) {
7068 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
7069 } else {
7070 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
7071 }
7072
7074 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
7075 monitor_exec = ast_strdupa(monitor_exec);
7076 }
7077 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
7078 monitor_options = ast_strdupa(monitor_options);
7079 } else {
7080 monitor_options = "";
7081 }
7083
7084 if (monitor_exec) {
7085 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
7086 }
7087
7088 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
7089
7090 if (!ast_strlen_zero(escaped_monitor_exec)) {
7091 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
7092 } else {
7093 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
7094 }
7095
7096 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
7097
7098 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
7099 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
7100 }
7101}
7102
7103/*!
7104 * \internal
7105 * \brief A large function which calls members, updates statistics, and bridges the caller and a member
7106 *
7107 * Here is the process of this function
7108 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
7109 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member.
7110 * 3. Call ring_one to place a call to the appropriate member(s)
7111 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
7112 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
7113 * 6. Start the monitor or mixmonitor if the option is set
7114 * 7. Remove the caller from the queue to allow other callers to advance
7115 * 8. Bridge the call.
7116 * 9. Do any post processing after the call has disconnected.
7117 *
7118 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
7119 * \param[in] opts the options passed as the third parameter to the Queue() application
7120 * \param[in] opt_args the options passed as the third parameter to the Queue() application
7121 * \param[in] announceoverride filename to play to user when waiting
7122 * \param[in] url the url passed as the fourth parameter to the Queue() application
7123 * \param[in,out] tries the number of times we have tried calling queue members
7124 * \param[out] noption set if the call to Queue() has the 'n' option set.
7125 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
7126 * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
7127 * \param[in] ringing 1 if the 'r' option is set, otherwise 0
7128 */
7129static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *gosub, int ringing)
7130{
7131 struct member *cur;
7132 struct callattempt *outgoing = NULL; /* the list of calls we are building */
7133 int to, orig;
7134 char oldexten[AST_MAX_EXTENSION]="";
7135 char oldcontext[AST_MAX_CONTEXT]="";
7136 char queuename[256]="";
7137 struct ast_channel *peer;
7138 struct callattempt *lpeer;
7139 struct member *member;
7140 struct ast_app *application;
7141 int res = 0, bridge = 0;
7142 int numbusies = 0;
7143 int x=0;
7144 char *announce = NULL;
7145 char digit = 0;
7146 time_t now = time(NULL);
7147 struct ast_bridge_config bridge_config;
7148 char nondataquality = 1;
7149 char *agiexec = NULL;
7150 char *gosubexec = NULL;
7151 const char *monitorfilename;
7152 int forwardsallowed = 1;
7153 int block_connected_line = 0;
7154 struct ao2_iterator memi;
7156 int callcompletedinsl;
7157 time_t starttime;
7158
7159 memset(&bridge_config, 0, sizeof(bridge_config));
7160 time(&now);
7161
7162 /* If we've already exceeded our timeout, then just stop
7163 * This should be extremely rare. queue_exec will take care
7164 * of removing the caller and reporting the timeout as the reason.
7165 */
7166 if (qe->expire && now >= qe->expire) {
7167 res = 0;
7168 goto out;
7169 }
7170
7171 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
7173 }
7174 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
7176 }
7177 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
7179 }
7180 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
7182 }
7183 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
7184 nondataquality = 0;
7185 }
7186 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
7188 }
7189 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
7191 }
7192 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
7194 }
7195 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
7197 }
7198 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
7201 (*tries)++;
7202 } else {
7203 *tries = ao2_container_count(qe->parent->members);
7204 }
7205 *noption = 1;
7206 }
7207 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
7208 forwardsallowed = 0;
7209 }
7211 block_connected_line = 1;
7212 }
7215 }
7218 }
7219 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
7221 }
7222
7223 /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
7224 (this is mainly to support unreal/local channels)
7225 */
7228 }
7229
7230 ao2_lock(qe->parent);
7231 ast_debug(1, "%s is trying to call a queue member.\n",
7232 ast_channel_name(qe->chan));
7233 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
7234 if (!ast_strlen_zero(qe->announce)) {
7235 announce = qe->announce;
7236 }
7237 if (!ast_strlen_zero(announceoverride)) {
7238 announce = announceoverride;
7239 }
7240
7241 memi = ao2_iterator_init(qe->parent->members, 0);
7242 while ((cur = ao2_iterator_next(&memi))) {
7243 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
7244 if (!tmp) {
7245 ao2_ref(cur, -1);
7246 ao2_iterator_destroy(&memi);
7247 ao2_unlock(qe->parent);
7248 goto out;
7249 }
7250
7251 /*
7252 * Seed the callattempt's connected line information with previously
7253 * acquired connected line info from the queued channel. The
7254 * previously acquired connected line info could have been set
7255 * through the CONNECTED_LINE dialplan function.
7256 */
7260
7261 tmp->block_connected_update = block_connected_line;
7262 tmp->stillgoing = 1;
7263 tmp->member = cur; /* Place the reference for cur into callattempt. */
7264 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
7265 /* Calculate the metric for the appropriate strategy. */
7266 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
7267 /* Put them in the list of outgoing thingies... We're ready now.
7268 XXX If we're forcibly removed, these outgoing calls won't get
7269 hung up XXX */
7270 tmp->q_next = outgoing;
7271 outgoing = tmp;
7272 } else {
7273 callattempt_free(tmp);
7274 }
7275 }
7276 ao2_iterator_destroy(&memi);
7277
7279 /* Application arguments have higher timeout priority (behaviour for <=1.6) */
7280 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
7281 to = (qe->expire - now) * 1000;
7282 } else {
7283 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
7284 }
7285 } else {
7286 /* Config timeout is higher priority thatn application timeout */
7287 if (qe->expire && qe->expire<=now) {
7288 to = 0;
7289 } else if (qe->parent->timeout) {
7290 to = qe->parent->timeout * 1000;
7291 } else {
7292 to = -1;
7293 }
7294 }
7295 orig = to;
7296 ++qe->pending;
7297 ao2_unlock(qe->parent);
7298 /* Call the queue members with the best metric now. */
7299 ring_one(qe, outgoing, &numbusies);
7300 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
7302 forwardsallowed);
7303
7304 ao2_lock(qe->parent);
7307
7308 }
7311 }
7312 ao2_unlock(qe->parent);
7313 peer = lpeer ? lpeer->chan : NULL;
7314 if (!peer) {
7315 qe->pending = 0;
7316 if (to) {
7317 /* Must gotten hung up */
7318 res = -1;
7319 } else {
7320 /* User exited by pressing a digit */
7321 res = digit;
7322 }
7323 if (res == -1) {
7324 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
7325 }
7326 } else { /* peer is valid */
7327 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
7328 RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
7329 /* Ah ha! Someone answered within the desired timeframe. Of course after this
7330 we will always return with -1 so that it is hung up properly after the
7331 conversation. */
7332 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
7333 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7334 }
7335 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
7336 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7337 }
7338 /* Update parameters for the queue */
7339 time(&now);
7340 recalc_holdtime(qe, (now - qe->start));
7341 member = lpeer->member;
7342 ao2_lock(qe->parent);
7343 callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
7344 ao2_unlock(qe->parent);
7345 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
7346 ao2_ref(member, 1);
7348 outgoing = NULL;
7349 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
7350 int res2;
7351
7352 res2 = ast_autoservice_start(qe->chan);
7353 if (!res2) {
7354 if (qe->parent->memberdelay) {
7355 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
7356 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
7357 }
7358 if (!res2 && announce) {
7359 char *front;
7360 char *announcefiles = ast_strdupa(announce);
7361 while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
7362 if (play_file(peer, front) < 0) {
7363 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
7364 }
7365 }
7366 }
7367 if (!res2 && qe->parent->reportholdtime) {
7368 if (!play_file(peer, qe->parent->sound_reporthold)) {
7369 long holdtime, holdtimesecs;
7370
7371 time(&now);
7372 holdtime = labs((now - qe->start) / 60);
7373 holdtimesecs = labs((now - qe->start) % 60);
7374 if (holdtime > 0) {
7375 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7376 if (play_file(peer, qe->parent->sound_minutes) < 0) {
7377 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
7378 }
7379 }
7380 if (holdtimesecs > 1) {
7381 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7382 if (play_file(peer, qe->parent->sound_seconds) < 0) {
7383 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
7384 }
7385 }
7386 }
7387 }
7389 }
7390 if (ast_check_hangup(peer)) {
7391 /* Agent must have hung up */
7392 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
7393 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
7394
7395 blob = ast_json_pack("{s: s, s: s, s: s}",
7396 "Queue", queuename,
7397 "Interface", member->interface,
7398 "MemberName", member->membername);
7399 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
7400
7404 ao2_ref(member, -1);
7405 goto out;
7406 } else if (ast_check_hangup(qe->chan)) {
7407 /* Caller must have hung up just before being connected */
7408 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7409 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7410 record_abandoned(qe);
7411 qe->handled = -1;
7415 ao2_ref(member, -1);
7416 return -1;
7417 }
7418 }
7419 /* Stop music on hold */
7420 if (ringing) {
7421 ast_indicate(qe->chan,-1);
7422 } else {
7423 ast_moh_stop(qe->chan);
7424 }
7425
7426 /* Make sure channels are compatible */
7427 res = ast_channel_make_compatible(qe->chan, peer);
7428 if (res < 0) {
7429 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7430 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(qe->chan), ast_channel_name(peer));
7431 record_abandoned(qe);
7435 ao2_ref(member, -1);
7436 return -1;
7437 }
7438
7439 /* Play announcement to the caller telling it's his turn if defined */
7441 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7442 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7443 }
7444 }
7445
7446 ao2_lock(qe->parent);
7447 /* if setinterfacevar is defined, make member variables available to the channel */
7448 /* use pbx_builtin_setvar to set a load of variables with one call */
7449 if (qe->parent->setinterfacevar && interfacevar) {
7450 ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7453 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7454 }
7455
7456 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7457 /* use pbx_builtin_setvar to set a load of variables with one call */
7458 if (qe->parent->setqueueentryvar && interfacevar) {
7459 ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7460 (long) (time(NULL) - qe->start), qe->opos);
7462 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7463 }
7464
7465 ao2_unlock(qe->parent);
7466
7467 /* try to set queue variables if configured to do so*/
7469 set_queue_variables(qe->parent, peer);
7470
7471 setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7473 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7474 monitorfilename = ast_strdupa(monitorfilename);
7475 }
7477
7478 /* Begin Monitoring */
7479 if (*qe->parent->monfmt) {
7480 setup_mixmonitor(qe, monitorfilename);
7481 }
7482 /* Drop out of the queue at this point, to prepare for next caller */
7483 leave_queue(qe);
7485 ast_debug(1, "app_queue: sendurl=%s.\n", url);
7486 ast_channel_sendurl(peer, url);
7487 }
7488
7489 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7490 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7491 if (!ast_strlen_zero(gosub)) {
7492 gosubexec = ast_strdupa(gosub);
7493 } else {
7494 if (qe->parent->membergosub) {
7495 gosubexec = ast_strdupa(qe->parent->membergosub);
7496 }
7497 }
7498
7499 if (!ast_strlen_zero(gosubexec)) {
7500 char *gosub_args = NULL;
7501 char *gosub_argstart;
7502
7503 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7504
7505 gosub_argstart = strchr(gosubexec, ',');
7506 if (gosub_argstart) {
7507 const char *what_is_s = "s";
7508 *gosub_argstart = 0;
7509 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7510 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7511 what_is_s = "~~s~~";
7512 }
7513 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7514 gosub_args = NULL;
7515 }
7516 *gosub_argstart = ',';
7517 } else {
7518 const char *what_is_s = "s";
7519 if (!ast_exists_extension(peer, gosubexec, "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
7520 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7521 what_is_s = "~~s~~";
7522 }
7523 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7524 gosub_args = NULL;
7525 }
7526 }
7527 if (gosub_args) {
7528 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7529 ast_free(gosub_args);
7530 } else {
7531 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7532 }
7533 }
7534
7535 if (!ast_strlen_zero(agi)) {
7536 ast_debug(1, "app_queue: agi=%s.\n", agi);
7537 application = pbx_findapp("agi");
7538 if (application) {
7539 agiexec = ast_strdupa(agi);
7540 pbx_exec(qe->chan, application, agiexec);
7541 } else {
7542 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7543 }
7544 }
7545 qe->handled++;
7546
7547 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7548 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7549
7550 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7551 "Queue", queuename,
7552 "Interface", member->interface,
7553 "MemberName", member->membername,
7554 "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7555 "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7556 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7557
7558 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7559 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7560
7561 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7562 queue_end_bridge->q = qe->parent;
7563 queue_end_bridge->chan = qe->chan;
7567 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7568 * to make sure to increase the refcount of this queue so it cannot be freed until we
7569 * are done with it. We remove this reference in end_bridge_callback.
7570 */
7571 queue_t_ref(qe->parent, "For bridge_config reference");
7572 }
7573
7574 ao2_lock(qe->parent);
7575 time(&member->starttime);
7576 starttime = member->starttime;
7577 ao2_unlock(qe->parent);
7578 /* As a queue member may end up in multiple calls at once if a transfer occurs with
7579 * a Local channel in the mix we pass the current call information (starttime) to the
7580 * Stasis subscriptions so when they update the queue member data it becomes a noop
7581 * if this call is no longer between the caller and the queue member.
7582 */
7583 setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7584 bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7586
7587 res = bridge ? bridge : 1;
7588 ao2_ref(member, -1);
7589 }
7590out:
7592
7593 return res;
7594}
7595
7596static int wait_a_bit(struct queue_ent *qe)
7597{
7598 /* Don't need to hold the lock while we setup the outgoing calls */
7599 int retrywait = qe->parent->retry * 1000;
7600
7601 int res = ast_waitfordigit(qe->chan, retrywait);
7602 if (res > 0 && !valid_exit(qe, res)) {
7603 res = 0;
7604 }
7605
7606 return res;
7607}
7608
7609static struct member *interface_exists(struct call_queue *q, const char *interface)
7610{
7611 struct member *mem;
7612 struct ao2_iterator mem_iter;
7613
7614 if (!q) {
7615 return NULL;
7616 }
7617 mem_iter = ao2_iterator_init(q->members, 0);
7618 while ((mem = ao2_iterator_next(&mem_iter))) {
7619 if (!strcasecmp(interface, mem->interface)) {
7620 ao2_iterator_destroy(&mem_iter);
7621 return mem;
7622 }
7623 ao2_ref(mem, -1);
7624 }
7625 ao2_iterator_destroy(&mem_iter);
7626
7627 return NULL;
7628}
7629
7630
7631/*! \brief Dump all members in a specific queue to the database
7632 * \code
7633 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
7634 * \endcode
7635 */
7636static void dump_queue_members(struct call_queue *pm_queue)
7637{
7638 struct member *cur_member;
7639 struct ast_str *value;
7640 struct ao2_iterator mem_iter;
7641
7642 if (!pm_queue) {
7643 return;
7644 }
7645
7646 /* 4K is a reasonable default for most applications, but we grow to
7647 * accommodate more if necessary. */
7648 if (!(value = ast_str_create(4096))) {
7649 return;
7650 }
7651
7652 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7653 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7654 if (!cur_member->dynamic) {
7655 ao2_ref(cur_member, -1);
7656 continue;
7657 }
7658
7659 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7660 ast_str_strlen(value) ? "|" : "",
7661 cur_member->interface,
7662 cur_member->penalty,
7663 cur_member->paused,
7664 cur_member->membername,
7665 cur_member->state_interface,
7666 cur_member->reason_paused,
7667 cur_member->wrapuptime);
7668
7669 ao2_ref(cur_member, -1);
7670 }
7671 ao2_iterator_destroy(&mem_iter);
7672
7673 if (ast_str_strlen(value) && !cur_member) {
7674 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7675 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7676 }
7677 } else {
7678 /* Delete the entry if the queue is empty or there is an error */
7679 ast_db_del(pm_family, pm_queue->name);
7680 }
7681
7682 ast_free(value);
7683}
7684
7685/*! \brief Remove member from queue
7686 * \retval RES_NOT_DYNAMIC when they aren't a RT member
7687 * \retval RES_NOSUCHQUEUE queue does not exist
7688 * \retval RES_OKAY removed member from queue
7689 * \retval RES_EXISTS queue exists but no members
7690*/
7691static int remove_from_queue(const char *queuename, const char *interface)
7692{
7693 struct call_queue *q, tmpq = {
7694 .name = queuename,
7695 };
7696 struct member *mem, tmpmem;
7697 int res = RES_NOSUCHQUEUE;
7698
7699 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7700 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7701 ao2_lock(q);
7702 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7703 /* XXX future changes should beware of this assumption!! */
7704 /*Change Penalty on realtime users*/
7706 update_realtime_member_field(mem, q->name, "penalty", "-1");
7707 } else if (!mem->dynamic) {
7708 ao2_ref(mem, -1);
7709 ao2_unlock(q);
7710 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7711 return RES_NOT_DYNAMIC;
7712 }
7713 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7714
7716 ao2_ref(mem, -1);
7717
7720 }
7721
7722 if (!num_available_members(q)) {
7724 }
7725
7726 res = RES_OKAY;
7727 } else {
7728 res = RES_EXISTS;
7729 }
7730 ao2_unlock(q);
7731 queue_t_unref(q, "Expiring temporary reference");
7732 }
7733
7734 return res;
7735}
7736
7737/*! \brief Add member to queue
7738 * \retval RES_NOT_DYNAMIC when they aren't a RT member
7739 * \retval RES_NOSUCHQUEUE queue does not exist
7740 * \retval RES_OKAY added member from queue
7741 * \retval RES_EXISTS queue exists but no members
7742 * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
7743*/
7744static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
7745{
7746 struct call_queue *q;
7747 struct member *new_member, *old_member;
7748 int res = RES_NOSUCHQUEUE;
7749
7750 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7751 * short-circuits if the queue is already in memory. */
7752 if (!(q = find_load_queue_rt_friendly(queuename))) {
7753 return res;
7754 }
7755
7756 ao2_lock(q);
7757 if ((old_member = interface_exists(q, interface)) == NULL) {
7759 new_member->dynamic = 1;
7760 if (reason_paused) {
7761 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7762 }
7763 member_add_to_queue(q, new_member);
7764 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7765
7766 if (is_member_available(q, new_member)) {
7768 }
7769
7770 ao2_ref(new_member, -1);
7771 new_member = NULL;
7772
7773 if (dump) {
7775 }
7776
7777 res = RES_OKAY;
7778 } else {
7779 res = RES_OUTOFMEMORY;
7780 }
7781 } else {
7782 ao2_ref(old_member, -1);
7783 res = RES_EXISTS;
7784 }
7785 ao2_unlock(q);
7786 queue_t_unref(q, "Expiring temporary reference");
7787
7788 return res;
7789}
7790
7791
7792/*! \brief Change priority caller into a queue
7793 * \retval RES_NOSUCHQUEUE queue does not exist
7794 * \retval RES_OKAY change priority
7795 * \retval RES_NOT_CALLER queue exists but no caller
7796*/
7797static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
7798{
7799 struct call_queue *q;
7800 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7801 int res = RES_NOSUCHQUEUE;
7802
7803 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7804 * short-circuits if the queue is already in memory. */
7805 if (!(q = find_load_queue_rt_friendly(queuename))) {
7806 return res;
7807 }
7808
7809 ao2_lock(q);
7810 res = RES_NOT_CALLER;
7811 for (current = q->head; current; current = current->next) {
7812 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7813 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7814 caller, priority, queuename);
7815 current->prio = priority;
7816 if (immediate) {
7817 /* This caller is being immediately moved in the queue so remove them */
7818 if (prev) {
7819 prev->next = current->next;
7820 } else {
7821 q->head = current->next;
7822 }
7823 caller_qe = current;
7824 /* The position for all callers is not recalculated in here as it will
7825 * be updated when the moved caller is inserted back into the queue
7826 */
7827 }
7828 res = RES_OKAY;
7829 break;
7830 } else if (immediate) {
7831 prev = current;
7832 }
7833 }
7834
7835 if (caller_qe) {
7836 int inserted = 0, pos = 0;
7837
7838 /* If a caller queue entry exists, we are applying their priority immediately
7839 * and have to reinsert them at the correct position.
7840 */
7841 prev = NULL;
7842 current = q->head;
7843 while (current) {
7844 if (!inserted && (caller_qe->prio > current->prio)) {
7845 insert_entry(q, prev, caller_qe, &pos);
7846 inserted = 1;
7847 }
7848
7849 /* We always update the position as it may have changed */
7850 current->pos = ++pos;
7851
7852 /* Move to the next caller in the queue */
7853 prev = current;
7854 current = current->next;
7855 }
7856
7857 if (!inserted) {
7858 insert_entry(q, prev, caller_qe, &pos);
7859 }
7860 }
7861
7862 ao2_unlock(q);
7863 return res;
7864}
7865
7866
7867/*! \brief Request to withdraw a caller from a queue
7868 * \retval RES_NOSUCHQUEUE queue does not exist
7869 * \retval RES_OKAY withdraw request sent
7870 * \retval RES_NOT_CALLER queue exists but no caller
7871 * \retval RES_EXISTS a withdraw request was already sent for this caller (channel) and queue
7872*/
7873static int request_withdraw_caller_from_queue(const char *queuename, const char *caller, const char *withdraw_info)
7874{
7875 struct call_queue *q;
7876 struct queue_ent *qe;
7877 int res = RES_NOSUCHQUEUE;
7878
7879 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7880 * short-circuits if the queue is already in memory. */
7881 if (!(q = find_load_queue_rt_friendly(queuename))) {
7882 return res;
7883 }
7884
7885 ao2_lock(q);
7886 res = RES_NOT_CALLER;
7887 for (qe = q->head; qe; qe = qe->next) {
7888 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7889 if (qe->withdraw) {
7890 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7891 res = RES_EXISTS;
7892 } else {
7893 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7894 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7895 in this queue, so we do not need to worry about a memory leak here. */
7896 if (withdraw_info) {
7898 }
7899 qe->withdraw = 1;
7900 res = RES_OKAY;
7901 }
7902 break;
7903 }
7904 }
7905 ao2_unlock(q);
7906 queue_unref(q);
7907
7908 return res;
7909}
7910
7911
7913{
7914 struct ast_json *json_blob = queue_member_blob_create(q, member);
7915
7916 if (!json_blob) {
7917 return -1;
7918 }
7919
7920 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7921
7922 return 0;
7923}
7924
7925/*!
7926 * \internal
7927 * \brief Set the pause status of the specific queue member.
7928 *
7929 * \param q Which queue the member belongs.
7930 * \param mem Queue member being paused/unpaused.
7931 * \param reason Why is this happening (Can be NULL/empty for no reason given.)
7932 * \param paused Set to 1 if the member is being paused or 0 to unpause.
7933 *
7934 * \pre The q is locked on entry.
7935 */
7936static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
7937{
7938 if (mem->paused == paused) {
7939 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7940 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7941 if (log_unpause_on_reason_change && paused) {
7942 if (!ast_strings_equal(mem->reason_paused, reason)) {
7943 ast_queue_log(q->name, "NONE", mem->membername, "UNPAUSE", "%s", "Auto-Unpause");
7944 }
7945 }
7946 }
7947
7948 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7950 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7951 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7952 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7953 }
7954 } else {
7955 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7956 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7957 (paused ? "" : "un"), q->name, mem->interface);
7958 }
7959 }
7960 }
7961
7962 mem->paused = paused;
7963 if (paused) {
7964 time(&mem->lastpause); /* update last pause field */
7965 }
7966 if (paused && !ast_strlen_zero(reason)) {
7967 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7968 } else {
7969 /* We end up filling this in again later (temporarily) but we need it
7970 * empty for now so that the intervening code - specifically
7971 * dump_queue_members() - has the correct view of things. */
7972 mem->reason_paused[0] = '\0';
7973 }
7974
7976 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7977
7980 }
7981
7982 if (is_member_available(q, mem)) {
7984 "Queue:%s_avail", q->name);
7985 } else if (!num_available_members(q)) {
7987 "Queue:%s_avail", q->name);
7988 }
7989
7990 if (!paused && !ast_strlen_zero(reason)) {
7991 /* Because we've been unpaused with a 'reason' we need to ensure that
7992 * that reason is emitted when the subsequent PauseQueueMember event
7993 * is raised. So temporarily set it on the member and clear it out
7994 * again right after. */
7995 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7996 }
7997
7998 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
7999 "%s", mem->reason_paused);
8000
8002
8003 if (!paused) {
8004 mem->reason_paused[0] = '\0';
8005 }
8006}
8007
8008static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
8009{
8010 int found = 0;
8011 struct call_queue *q;
8012 struct ao2_iterator queue_iter;
8013
8014 if (ast_check_realtime("queues")) {
8015 load_realtime_queues(queuename);
8016 }
8017
8018 queue_iter = ao2_iterator_init(queues, 0);
8019 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
8020 ao2_lock(q);
8021 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
8022 struct member *mem;
8023
8024 if ((mem = interface_exists(q, interface))) {
8025 /*
8026 * Before we do the PAUSE/UNPAUSE, log if this was a
8027 * PAUSEALL/UNPAUSEALL but only on the first found entry.
8028 */
8029 ++found;
8030 if (found == 1
8031 && ast_strlen_zero(queuename)) {
8032 /*
8033 * XXX In all other cases, we use the queue name,
8034 * but since this affects all queues, we cannot.
8035 */
8036 ast_queue_log("NONE", "NONE", mem->membername,
8037 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
8038 }
8039
8040 set_queue_member_pause(q, mem, reason, paused);
8041 ao2_ref(mem, -1);
8042 }
8043
8044 if (!ast_strlen_zero(queuename)) {
8045 ao2_unlock(q);
8046 queue_t_unref(q, "Done with iterator");
8047 break;
8048 }
8049 }
8050
8051 ao2_unlock(q);
8052 queue_t_unref(q, "Done with iterator");
8053 }
8054 ao2_iterator_destroy(&queue_iter);
8055
8056 return found ? RESULT_SUCCESS : RESULT_FAILURE;
8057}
8058
8059/*!
8060 * \internal
8061 * \brief helper function for set_member_penalty - given a queue, sets all member penalties with the interface
8062 * \param[in] q queue which is having its member's penalty changed - must be unlocked prior to calling
8063 * \param[in] interface String of interface used to search for queue members being changed
8064 * \param[in] penalty Value penalty is being changed to for the member.
8065 * \retval 0 if the there is no member with interface belonging to q and no change is made
8066 * \retval 1 if the there is a member with interface belonging to q and changes are made
8067 */
8068static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
8069{
8070 struct member *mem;
8071 int foundinterface = 0;
8072
8073 ao2_lock(q);
8074 if ((mem = interface_exists(q, interface))) {
8075 foundinterface++;
8076 if (mem->realtime) {
8077 char rtpenalty[80];
8078
8079 sprintf(rtpenalty, "%i", penalty);
8080 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
8081 }
8082
8083 mem->penalty = penalty;
8084
8085 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
8086 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
8087 ao2_ref(mem, -1);
8088 }
8089 ao2_unlock(q);
8090
8091 return foundinterface;
8092}
8093
8094/*!
8095 * \internal
8096 * \brief Set the ringinuse value of the specific queue member.
8097 *
8098 * \param q Which queue the member belongs.
8099 * \param mem Queue member being set.
8100 * \param ringinuse Set to 1 if the member is called when inuse.
8101 *
8102 * \pre The q is locked on entry.
8103 */
8104static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
8105{
8106 if (mem->realtime) {
8108 ringinuse ? "1" : "0");
8109 }
8110
8111 mem->ringinuse = ringinuse;
8112
8113 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
8114 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
8115}
8116
8118{
8119 struct member *mem;
8120 int foundinterface = 0;
8121
8122 ao2_lock(q);
8123 if ((mem = interface_exists(q, interface))) {
8124 foundinterface++;
8126 ao2_ref(mem, -1);
8127 }
8128 ao2_unlock(q);
8129
8130 return foundinterface;
8131}
8132
8133static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
8134{
8135 switch(property) {
8136 case MEMBER_PENALTY:
8138
8139 case MEMBER_RINGINUSE:
8141
8142 default:
8143 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8144 return 0;
8145 }
8146}
8147
8148/*!
8149 * \internal
8150 * \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues.
8151 * \param[in] queuename If specified, only act on a member if it belongs to this queue
8152 * \param[in] interface Interface of queue member(s) having priority set.
8153 * \param[in] property Which queue property is being set
8154 * \param[in] value Value penalty is being changed to for each member
8155 */
8156static int set_member_value(const char *queuename, const char *interface, int property, int value)
8157{
8158 int foundinterface = 0, foundqueue = 0;
8159 struct call_queue *q;
8160 struct ast_config *queue_config = NULL;
8161 struct ao2_iterator queue_iter;
8162
8163 /* property dependent restrictions on values should be checked in this switch */
8164 switch (property) {
8165 case MEMBER_PENALTY:
8166 if (value < 0 && !negative_penalty_invalid) {
8167 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8168 return RESULT_FAILURE;
8169 }
8170 }
8171
8172 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8173 if (ast_check_realtime("queues")) {
8174 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8175 if (queue_config) {
8176 char *category = NULL;
8177 while ((category = ast_category_browse(queue_config, category))) {
8178 const char *name = ast_variable_retrieve(queue_config, category, "name");
8179 if (ast_strlen_zero(name)) {
8180 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8181 continue;
8182 }
8183 if ((q = find_load_queue_rt_friendly(name))) {
8184 foundqueue++;
8185 foundinterface += set_member_value_help_members(q, interface, property, value);
8186 queue_unref(q);
8187 }
8188 }
8189
8190 ast_config_destroy(queue_config);
8191 }
8192 }
8193
8194 /* After hitting realtime queues, go back and get the regular ones. */
8195 queue_iter = ao2_iterator_init(queues, 0);
8196 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8197 foundqueue++;
8198 foundinterface += set_member_value_help_members(q, interface, property, value);
8199 queue_unref(q);
8200 }
8201 ao2_iterator_destroy(&queue_iter);
8202 } else { /* We actually have a queuename, so we can just act on the single queue. */
8203 if ((q = find_load_queue_rt_friendly(queuename))) {
8204 foundqueue++;
8205 foundinterface += set_member_value_help_members(q, interface, property, value);
8206 queue_unref(q);
8207 }
8208 }
8209
8210 if (foundinterface) {
8211 return RESULT_SUCCESS;
8212 } else if (!foundqueue) {
8213 ast_log (LOG_ERROR, "Invalid queuename\n");
8214 } else {
8215 ast_log (LOG_ERROR, "Invalid interface\n");
8216 }
8217
8218 return RESULT_FAILURE;
8219}
8220
8221/*!
8222 * \brief Gets members penalty.
8223 * \return Return the members penalty or RESULT_FAILURE on error.
8224 */
8225static int get_member_penalty(char *queuename, char *interface)
8226{
8227 int foundqueue = 0, penalty;
8228 struct call_queue *q;
8229 struct member *mem;
8230
8231 if ((q = find_load_queue_rt_friendly(queuename))) {
8232 foundqueue = 1;
8233 ao2_lock(q);
8234 if ((mem = interface_exists(q, interface))) {
8235 penalty = mem->penalty;
8236 ao2_ref(mem, -1);
8237 ao2_unlock(q);
8238 queue_t_unref(q, "Search complete");
8239 return penalty;
8240 }
8241 ao2_unlock(q);
8242 queue_t_unref(q, "Search complete");
8243 }
8244
8245 /* some useful debugging */
8246 if (foundqueue) {
8247 ast_log (LOG_ERROR, "Invalid queuename\n");
8248 } else {
8249 ast_log (LOG_ERROR, "Invalid interface\n");
8250 }
8251
8252 return RESULT_FAILURE;
8253}
8254
8255/*! \brief Reload dynamic queue members persisted into the astdb */
8256static void reload_queue_members(void)
8257{
8258 char *cur_ptr;
8259 const char *queue_name;
8260 char *member;
8261 char *interface;
8262 char *membername = NULL;
8263 char *state_interface;
8264 char *penalty_tok;
8265 int penalty = 0;
8266 char *paused_tok;
8267 int paused = 0;
8268 char *wrapuptime_tok;
8269 int wrapuptime = 0;
8270 char *reason_paused;
8271 struct ast_db_entry *db_tree;
8272 struct ast_db_entry *entry;
8273 struct call_queue *cur_queue;
8274 char *queue_data;
8275
8276 /* Each key in 'pm_family' is the name of a queue */
8277 db_tree = ast_db_gettree(pm_family, NULL);
8278 for (entry = db_tree; entry; entry = entry->next) {
8279
8280 queue_name = entry->key + strlen(pm_family) + 2;
8281
8282 {
8283 struct call_queue tmpq = {
8284 .name = queue_name,
8285 };
8286 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8287 }
8288
8289 if (!cur_queue) {
8290 cur_queue = find_load_queue_rt_friendly(queue_name);
8291 }
8292
8293 if (!cur_queue) {
8294 /* If the queue no longer exists, remove it from the
8295 * database */
8296 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8297 ast_db_del(pm_family, queue_name);
8298 continue;
8299 }
8300
8301 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8302 queue_t_unref(cur_queue, "Expire reload reference");
8303 continue;
8304 }
8305
8306 cur_ptr = queue_data;
8307 while ((member = strsep(&cur_ptr, ",|"))) {
8308 if (ast_strlen_zero(member)) {
8309 continue;
8310 }
8311
8312 interface = strsep(&member, ";");
8313 penalty_tok = strsep(&member, ";");
8314 paused_tok = strsep(&member, ";");
8315 membername = strsep(&member, ";");
8316 state_interface = strsep(&member, ";");
8317 reason_paused = strsep(&member, ";");
8318 wrapuptime_tok = strsep(&member, ";");
8319
8320 if (!penalty_tok) {
8321 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8322 break;
8323 }
8324 penalty = strtol(penalty_tok, NULL, 10);
8325 if (errno == ERANGE) {
8326 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8327 break;
8328 }
8329
8330 if (!paused_tok) {
8331 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8332 break;
8333 }
8334 paused = strtol(paused_tok, NULL, 10);
8335 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8336 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8337 break;
8338 }
8339
8340 if (!ast_strlen_zero(wrapuptime_tok)) {
8341 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8342 if (errno == ERANGE) {
8343 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8344 break;
8345 }
8346 }
8347
8348 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8349 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8350
8351 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8352 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8353 break;
8354 }
8355 }
8356 queue_t_unref(cur_queue, "Expire reload reference");
8357 ast_free(queue_data);
8358 }
8359
8360 if (db_tree) {
8361 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8362 ast_db_freetree(db_tree);
8363 }
8364}
8365
8366/*! \brief PauseQueueMember application */
8367static int pqm_exec(struct ast_channel *chan, const char *data)
8368{
8369 char *parse;
8371 AST_APP_ARG(queuename);
8372 AST_APP_ARG(interface);
8374 AST_APP_ARG(reason);
8375 );
8376
8377 if (ast_strlen_zero(data)) {
8378 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8379 return -1;
8380 }
8381
8382 parse = ast_strdupa(data);
8383
8385
8386 if (ast_strlen_zero(args.interface)) {
8387 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8388 return -1;
8389 }
8390
8391 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8392 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8393 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8394 return 0;
8395 }
8396
8397 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8398
8399 return 0;
8400}
8401
8402/*! \brief UnpauseQueueMember application */
8403static int upqm_exec(struct ast_channel *chan, const char *data)
8404{
8405 char *parse;
8407 AST_APP_ARG(queuename);
8408 AST_APP_ARG(interface);
8410 AST_APP_ARG(reason);
8411 );
8412
8413 if (ast_strlen_zero(data)) {
8414 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8415 return -1;
8416 }
8417
8418 parse = ast_strdupa(data);
8419
8421
8422 if (ast_strlen_zero(args.interface)) {
8423 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8424 return -1;
8425 }
8426
8427 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8428 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8429 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8430 return 0;
8431 }
8432
8433 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8434
8435 return 0;
8436}
8437
8438/*! \brief RemoveQueueMember application */
8439static int rqm_exec(struct ast_channel *chan, const char *data)
8440{
8441 int res=-1;
8442 char *parse, *temppos = NULL;
8443 struct member *mem = NULL;
8444
8446 AST_APP_ARG(queuename);
8448 );
8449
8450
8451 if (ast_strlen_zero(data)) {
8452 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8453 return -1;
8454 }
8455
8456 parse = ast_strdupa(data);
8457
8459
8460 if (ast_strlen_zero(args.interface)) {
8461 args.interface = ast_strdupa(ast_channel_name(chan));
8462 temppos = strrchr(args.interface, '-');
8463 if (temppos) {
8464 *temppos = '\0';
8465 }
8466 }
8467
8468 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8469
8471 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8472 }
8473
8474 switch (remove_from_queue(args.queuename, args.interface)) {
8475 case RES_OKAY:
8476 if (!mem || ast_strlen_zero(mem->membername)) {
8477 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8478 } else {
8479 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8480 }
8481 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8482 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8483 res = 0;
8484 break;
8485 case RES_EXISTS:
8486 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8487 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8488 res = 0;
8489 break;
8490 case RES_NOSUCHQUEUE:
8491 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8492 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8493 res = 0;
8494 break;
8495 case RES_NOT_DYNAMIC:
8496 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8497 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8498 res = 0;
8499 break;
8500 }
8501
8502 if (mem) {
8503 ao2_ref(mem, -1);
8504 }
8505
8506 return res;
8507}
8508
8509/*! \brief AddQueueMember application */
8510static int aqm_exec(struct ast_channel *chan, const char *data)
8511{
8512 int res=-1;
8513 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8515 AST_APP_ARG(queuename);
8522 );
8523 int penalty = 0;
8524 int paused = 0;
8525 int wrapuptime;
8526 struct ast_flags flags = { 0 };
8527
8528 if (ast_strlen_zero(data)) {
8529 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8530 return -1;
8531 }
8532
8533 parse = ast_strdupa(data);
8534
8536
8537 if (args.options) {
8538 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8539 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8541 paused = 1;
8543 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8544 }
8545 }
8546 }
8547
8548 if (ast_strlen_zero(args.interface)) {
8549 args.interface = ast_strdupa(ast_channel_name(chan));
8550 temppos = strrchr(args.interface, '-');
8551 if (temppos) {
8552 *temppos = '\0';
8553 }
8554 }
8555
8556 if (!ast_strlen_zero(args.penalty)) {
8557 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8558 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8559 penalty = 0;
8560 }
8561 }
8562
8563 if (!ast_strlen_zero(args.wrapuptime)) {
8564 tmp = args.wrapuptime;
8565 ast_strip(tmp);
8566 wrapuptime = atoi(tmp);
8567 if (wrapuptime < 0) {
8568 wrapuptime = 0;
8569 }
8570 } else {
8571 wrapuptime = 0;
8572 }
8573
8574 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8575 case RES_OKAY:
8576 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8577 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8578 } else {
8579 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8580 }
8581 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8582 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8583 res = 0;
8584 break;
8585 case RES_EXISTS:
8586 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8587 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8588 res = 0;
8589 break;
8590 case RES_NOSUCHQUEUE:
8591 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8592 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8593 res = 0;
8594 break;
8595 case RES_OUTOFMEMORY:
8596 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8597 break;
8598 }
8599
8600 return res;
8601}
8602
8603/*! \brief QueueLog application */
8604static int ql_exec(struct ast_channel *chan, const char *data)
8605{
8606 char *parse;
8607
8609 AST_APP_ARG(queuename);
8610 AST_APP_ARG(uniqueid);
8611 AST_APP_ARG(membername);
8613 AST_APP_ARG(params);
8614 );
8615
8616 if (ast_strlen_zero(data)) {
8617 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8618 return -1;
8619 }
8620
8621 parse = ast_strdupa(data);
8622
8624
8625 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8626 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8627 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8628 return -1;
8629 }
8630
8631 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8632 "%s", args.params ? args.params : "");
8633
8634 return 0;
8635}
8636
8637/*! \brief Copy rule from global list into specified queue */
8638static void copy_rules(struct queue_ent *qe, const char *rulename)
8639{
8640 struct penalty_rule *pr_iter;
8641 struct rule_list *rl_iter;
8642 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8644 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8645 if (!strcasecmp(rl_iter->name, tmp)) {
8646 break;
8647 }
8648 }
8649 if (rl_iter) {
8650 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8651 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8652 if (!new_pr) {
8653 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8654 break;
8655 }
8656 new_pr->time = pr_iter->time;
8657 new_pr->max_value = pr_iter->max_value;
8658 new_pr->min_value = pr_iter->min_value;
8659 new_pr->raise_value = pr_iter->raise_value;
8660 new_pr->max_relative = pr_iter->max_relative;
8661 new_pr->min_relative = pr_iter->min_relative;
8662 new_pr->raise_relative = pr_iter->raise_relative;
8663 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8664 }
8665 }
8667}
8668
8669/*!\brief The starting point for all queue calls
8670 *
8671 * The process involved here is to
8672 * 1. Parse the options specified in the call to Queue()
8673 * 2. Join the queue
8674 * 3. Wait in a loop until it is our turn to try calling a queue member
8675 * 4. Attempt to call a queue member
8676 * 5. If 4. did not result in a bridged call, then check for between
8677 * call options such as periodic announcements etc.
8678 * 6. Try 4 again unless some condition (such as an expiration time) causes us to
8679 * exit the queue.
8680 */
8681static int queue_exec(struct ast_channel *chan, const char *data)
8682{
8683 int res=-1;
8684 int ringing=0;
8685 const char *user_priority;
8686 const char *max_penalty_str;
8687 const char *min_penalty_str;
8688 const char *raise_penalty_str;
8689 int prio;
8690 int qcontinue = 0;
8691 int max_penalty, min_penalty, raise_penalty;
8692 enum queue_result reason = QUEUE_UNKNOWN;
8693 /* whether to exit Queue application after the timeout hits */
8694 int tries = 0;
8695 int noption = 0;
8696 char *parse;
8697 int makeannouncement = 0;
8698 int position = 0;
8700 AST_APP_ARG(queuename);
8703 AST_APP_ARG(announceoverride);
8704 AST_APP_ARG(queuetimeoutstr);
8705 AST_APP_ARG(agi);
8706 AST_APP_ARG(gosub);
8708 AST_APP_ARG(position);
8709 );
8710 /* Our queue entry */
8711 struct queue_ent qe = { 0 };
8712 struct ast_flags opts = { 0, };
8713 char *opt_args[OPT_ARG_ARRAY_SIZE];
8714 int max_forwards;
8715 int cid_allow;
8716
8717 if (ast_strlen_zero(data)) {
8718 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,gosub[,rule[,position]]]]]]]]\n");
8719 return -1;
8720 }
8721
8722 ast_channel_lock(chan);
8724 ast_channel_unlock(chan);
8725
8726 if (max_forwards <= 0) {
8727 ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8728 return -1;
8729 }
8730
8731 parse = ast_strdupa(data);
8733
8734 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, gosub: %s, rule: %s, position: %s\n",
8735 args.queuename,
8736 S_OR(args.options, ""),
8737 S_OR(args.url, ""),
8738 S_OR(args.announceoverride, ""),
8739 S_OR(args.queuetimeoutstr, ""),
8740 S_OR(args.agi, ""),
8741 S_OR(args.gosub, ""),
8742 S_OR(args.rule, ""),
8743 S_OR(args.position, ""));
8744
8745 if (!ast_strlen_zero(args.options)) {
8746 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8747 }
8748
8749 /* Setup our queue entry */
8750 qe.start = time(NULL);
8751
8752 pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8753
8754 /* set the expire time based on the supplied timeout; */
8755 if (!ast_strlen_zero(args.queuetimeoutstr)) {
8756 qe.expire = qe.start + atoi(args.queuetimeoutstr);
8757 } else {
8758 qe.expire = 0;
8759 }
8760
8761 /* Get the priority from the variable ${QUEUE_PRIO} */
8762 ast_channel_lock(chan);
8763 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8764 if (user_priority) {
8765 if (sscanf(user_priority, "%30d", &prio) == 1) {
8766 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8767 } else {
8768 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8769 user_priority, ast_channel_name(chan));
8770 prio = 0;
8771 }
8772 } else {
8773 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8774 prio = 0;
8775 }
8776
8777 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8778
8779 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8780 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8781 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8782 } else {
8783 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8784 max_penalty_str, ast_channel_name(chan));
8785 max_penalty = INT_MAX;
8786 }
8787 } else {
8788 max_penalty = INT_MAX;
8789 }
8790
8791 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8792 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8793 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8794 } else {
8795 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8796 min_penalty_str, ast_channel_name(chan));
8797 min_penalty = INT_MAX;
8798 }
8799 } else {
8800 min_penalty = INT_MAX;
8801 }
8802
8803 if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8804 if (*raise_penalty_str == 'r') {
8805 qe.raise_respect_min = 1;
8806 raise_penalty_str++;
8807 } else {
8808 qe.raise_respect_min = 0;
8809 }
8810 if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8811 ast_debug(1, "%s: Got raise penalty %s%d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), qe.raise_respect_min ? "r" : "", raise_penalty);
8812 } else {
8813 ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8814 raise_penalty_str, ast_channel_name(chan));
8815 raise_penalty = INT_MAX;
8816 }
8817 } else {
8818 raise_penalty = INT_MAX;
8819 }
8820 ast_channel_unlock(chan);
8821
8822 if (ast_test_flag(&opts, OPT_RINGING)) {
8823 ringing = 1;
8824 }
8825
8826 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8827 qe.ring_when_ringing = 1;
8828 }
8829
8830 if (ast_test_flag(&opts, OPT_GO_ON)) {
8831 qcontinue = 1;
8832 }
8833
8834 if (args.position) {
8835 position = atoi(args.position);
8836 if (position < 0) {
8837 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8838 position = 0;
8839 }
8840 }
8841
8842 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8843 args.queuename, (long)qe.expire, prio);
8844
8845 qe.chan = chan;
8846 qe.prio = prio;
8847 qe.max_penalty = max_penalty;
8848 qe.min_penalty = min_penalty;
8849 qe.raise_penalty = raise_penalty;
8850 qe.last_pos_said = 0;
8851 qe.last_pos = 0;
8854 qe.valid_digits = 0;
8855 if (join_queue(args.queuename, &qe, &reason, position)) {
8856 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8857 set_queue_result(chan, reason);
8858 return 0;
8859 }
8860 ast_assert(qe.parent != NULL);
8861
8862 if (qe.parent->periodicannouncestartdelay >= 0) {
8865 }
8866
8868
8869 if (log_caller_id_name) {
8870 char *escaped_cidname = NULL;
8871 /* Ensure caller ID name is valid and not NULL before processing */
8872 if (cid_allow && ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
8873 escaped_cidname = ast_strdupa(ast_channel_caller(chan)->id.name.str);
8874 /* Only iterate if '|' is found */
8875 if (strchr(escaped_cidname, '|')) {
8876 for (char *p = escaped_cidname; *p; p++) {
8877 if (*p == '|') {
8878 *p = '_';
8879 }
8880 }
8881 }
8882 }
8883
8884 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d|%s",
8885 S_OR(args.url, ""),
8886 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8887 qe.opos,
8888 S_OR(escaped_cidname, ""));
8889 } else {
8890 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8891 S_OR(args.url, ""),
8892 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8893 qe.opos);
8894 }
8895
8896 /* PREDIAL: Preprocess any callee gosub arguments. */
8898 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8901 }
8902
8903 /* PREDIAL: Run gosub on the caller's channel */
8905 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8907 ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8908 }
8909
8910 /* Music on hold class override */
8913 ast_copy_string(qe.moh, opt_args[OPT_ARG_MUSICONHOLD_CLASS], sizeof(qe.moh));
8914 }
8915
8916 copy_rules(&qe, args.rule);
8917 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8918check_turns:
8919 if (ringing) {
8921 } else {
8922 ast_moh_start(chan, qe.moh, NULL);
8923 }
8924
8925 /* This is the wait loop for callers 2 through maxlen */
8926 res = wait_our_turn(&qe, ringing, &reason);
8927 if (res) {
8928 goto stop;
8929 }
8930
8931 makeannouncement = qe.parent->announce_to_first_user;
8932
8933 for (;;) {
8934 /* This is the wait loop for the head caller*/
8935 /* To exit, they may get their call answered; */
8936 /* they may dial a digit from the queue context; */
8937 /* or, they may timeout. */
8938
8939 /* A request to withdraw this call from the queue arrived */
8940 if (qe.withdraw) {
8941 reason = QUEUE_WITHDRAW;
8942 res = 1;
8943 break;
8944 }
8945
8946 /* Leave if we have exceeded our queuetimeout */
8947 if (qe.expire && (time(NULL) >= qe.expire)) {
8948 record_abandoned(&qe);
8949 reason = QUEUE_TIMEOUT;
8950 res = 0;
8951 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
8952 qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8953 break;
8954 }
8955
8956 if (makeannouncement) {
8957 /* Make a position announcement, if enabled */
8958 if (qe.parent->announcefrequency) {
8959 if ((res = say_position(&qe, ringing))) {
8960 goto stop;
8961 }
8962 }
8963 }
8964 makeannouncement = 1;
8965
8966 /* Make a periodic announcement, if enabled */
8968 if ((res = say_periodic_announcement(&qe, ringing))) {
8969 goto stop;
8970 }
8971 }
8972
8973 /* A request to withdraw this call from the queue arrived */
8974 if (qe.withdraw) {
8975 reason = QUEUE_WITHDRAW;
8976 res = 1;
8977 break;
8978 }
8979
8980 /* Leave if we have exceeded our queuetimeout */
8981 if (qe.expire && (time(NULL) >= qe.expire)) {
8982 record_abandoned(&qe);
8983 reason = QUEUE_TIMEOUT;
8984 res = 0;
8985 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8986 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8987 break;
8988 }
8989
8990 /* see if we need to move to the next penalty level for this queue */
8991 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
8992 update_qe_rule(&qe);
8993 }
8994
8995 /* Try calling all queue members for 'timeout' seconds */
8996 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.gosub, ringing);
8997 if (res) {
8998 goto stop;
8999 }
9000
9001 if (qe.parent->leavewhenempty) {
9002 int status = 0;
9004 record_abandoned(&qe);
9005 reason = QUEUE_LEAVEEMPTY;
9006 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
9007 res = 0;
9008 break;
9009 }
9010 }
9011
9012 /* exit after 'timeout' cycle if 'n' option enabled */
9013 if (noption && tries >= ao2_container_count(qe.parent->members)) {
9014 ast_verb(3, "Exiting on time-out cycle\n");
9015 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
9016 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9017 record_abandoned(&qe);
9018 reason = QUEUE_TIMEOUT;
9019 res = 0;
9020 break;
9021 }
9022
9023
9024 /* Leave if we have exceeded our queuetimeout */
9025 if (qe.expire && (time(NULL) >= qe.expire)) {
9026 record_abandoned(&qe);
9027 reason = QUEUE_TIMEOUT;
9028 res = 0;
9029 ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9030 break;
9031 }
9032
9033 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
9034 res = wait_a_bit(&qe);
9035 if (res) {
9036 goto stop;
9037 }
9038
9039 /* If using dynamic realtime members, we should regenerate the member list for this queue */
9041
9042 /* Since this is a priority queue and
9043 * it is not sure that we are still at the head
9044 * of the queue, go and check for our turn again.
9045 */
9046 if (!is_our_turn(&qe)) {
9047 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
9048 goto check_turns;
9049 }
9050 }
9051
9052stop:
9053 if (res) {
9054 if (reason == QUEUE_WITHDRAW) {
9055 record_abandoned(&qe);
9056 ast_queue_log(qe.parent->name, ast_channel_uniqueid(qe.chan), "NONE", "WITHDRAW", "%d|%d|%ld|%.40s", qe.pos, qe.opos, (long) (time(NULL) - qe.start), qe.withdraw_info ? qe.withdraw_info : "");
9057 if (qe.withdraw_info) {
9058 pbx_builtin_setvar_helper(qe.chan, "QUEUE_WITHDRAW_INFO", qe.withdraw_info);
9059 }
9060 res = 0;
9061 } else if (res < 0) {
9062 if (!qe.handled) {
9063 record_abandoned(&qe);
9064 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
9065 "%d|%d|%ld", qe.pos, qe.opos,
9066 (long) (time(NULL) - qe.start));
9067 res = -1;
9068 } else if (reason == QUEUE_LEAVEEMPTY) {
9069 /* Return back to dialplan, don't hang up */
9070 res = 0;
9071 } else if (qcontinue) {
9072 reason = QUEUE_CONTINUE;
9073 res = 0;
9074 }
9075 } else if (qe.valid_digits) {
9076 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
9077 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
9078 }
9079 }
9080
9081 /* Free the optional withdraw info if present */
9082 /* This is done here to catch all cases. e.g. if the call eventually wasn't withdrawn, e.g. answered */
9083 if (qe.withdraw_info) {
9085 qe.withdraw_info = NULL;
9086 }
9087
9088 /* Don't allow return code > 0 */
9089 if (res >= 0) {
9090 res = 0;
9091 if (ringing) {
9092 ast_indicate(chan, -1);
9093 } else {
9094 ast_moh_stop(chan);
9095 }
9096 ast_stopstream(chan);
9097 }
9098
9100
9101 leave_queue(&qe);
9102 if (reason != QUEUE_UNKNOWN)
9103 set_queue_result(chan, reason);
9104
9105 /*
9106 * every queue_ent is given a reference to it's parent
9107 * call_queue when it joins the queue. This ref must be taken
9108 * away right before the queue_ent is destroyed. In this case
9109 * the queue_ent is about to be returned on the stack
9110 */
9111 qe.parent = queue_unref(qe.parent);
9112
9113 return res;
9114}
9115
9116/*!
9117 * \brief create interface var with all queue details.
9118 * \retval 0 on success
9119 * \retval -1 on error
9120*/
9121static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9122{
9123 int res = -1;
9124 struct call_queue *q;
9125 char interfacevar[256] = "";
9126 float sl = 0;
9127
9128 if (ast_strlen_zero(data)) {
9129 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9130 return -1;
9131 }
9132
9133 if ((q = find_load_queue_rt_friendly(data))) {
9134 ao2_lock(q);
9135 if (q->setqueuevar) {
9136 sl = 0;
9137 res = 0;
9138
9139 if (q->callscompleted > 0) {
9140 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
9141 }
9142
9143 snprintf(interfacevar, sizeof(interfacevar),
9144 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
9146
9147 pbx_builtin_setvar_multiple(chan, interfacevar);
9148 }
9149
9150 ao2_unlock(q);
9151 queue_t_unref(q, "Done with QUEUE() function");
9152 } else {
9153 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9154 }
9155
9156 snprintf(buf, len, "%d", res);
9157
9158 return 0;
9159}
9160
9161/*!
9162 * \brief Check if a given queue exists
9163 *
9164 */
9165static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9166{
9167 struct call_queue *q;
9168
9169 buf[0] = '\0';
9170
9171 if (ast_strlen_zero(data)) {
9172 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9173 return -1;
9174 }
9176 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9177 if (q) {
9178 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9179 }
9180
9181 return 0;
9182}
9183
9184static struct member *get_interface_helper(struct call_queue *q, const char *interface)
9185{
9186 struct member *m;
9187
9189 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9190 return NULL;
9191 }
9192
9194 if (!m) {
9195 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9196 interface, q->name);
9197 }
9198 return m;
9199}
9200
9201/*!
9202 * \brief Get number either busy / free / ready or total members of a specific queue
9203 * \brief Get or set member properties penalty / paused / ringinuse
9204 * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ringinuse)
9205 * \retval -1 on error
9206 */
9207static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9208{
9209 int count = 0;
9210 struct member *m;
9211 struct ao2_iterator mem_iter;
9212 struct call_queue *q;
9213
9215 AST_APP_ARG(queuename);
9216 AST_APP_ARG(option);
9217 AST_APP_ARG(interface);
9218 );
9219 /* Make sure the returned value on error is zero length string. */
9220 buf[0] = '\0';
9221
9222 if (ast_strlen_zero(data)) {
9224 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9225 cmd);
9226 return -1;
9227 }
9228
9230
9231 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9233 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9234 cmd);
9235 return -1;
9236 }
9237
9238 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9239 ao2_lock(q);
9240 if (!strcasecmp(args.option, "logged")) {
9241 mem_iter = ao2_iterator_init(q->members, 0);
9242 while ((m = ao2_iterator_next(&mem_iter))) {
9243 /* Count the agents who are logged in and presently answering calls */
9244 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9245 count++;
9246 }
9247 ao2_ref(m, -1);
9248 }
9249 ao2_iterator_destroy(&mem_iter);
9250 } else if (!strcasecmp(args.option, "free")) {
9251 mem_iter = ao2_iterator_init(q->members, 0);
9252 while ((m = ao2_iterator_next(&mem_iter))) {
9253 /* Count the agents who are logged in and presently answering calls */
9254 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9255 count++;
9256 }
9257 ao2_ref(m, -1);
9258 }
9259 ao2_iterator_destroy(&mem_iter);
9260 } else if (!strcasecmp(args.option, "ready")) {
9261 time_t now;
9262 time(&now);
9263 mem_iter = ao2_iterator_init(q->members, 0);
9264 while ((m = ao2_iterator_next(&mem_iter))) {
9265 /* Count the agents who are logged in, not paused and not wrapping up */
9266 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9267 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9268 count++;
9269 }
9270 ao2_ref(m, -1);
9271 }
9272 ao2_iterator_destroy(&mem_iter);
9273 } else if (!strcasecmp(args.option, "count")) {
9275 } else if (!strcasecmp(args.option, "penalty")) {
9276 m = get_interface_helper(q, args.interface);
9277 if (m) {
9278 count = m->penalty;
9279 ao2_ref(m, -1);
9280 }
9281 } else if (!strcasecmp(args.option, "paused")) {
9282 m = get_interface_helper(q, args.interface);
9283 if (m) {
9284 count = m->paused;
9285 ao2_ref(m, -1);
9286 }
9287 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9288 || !strcasecmp(args.option, "ringinuse"))) {
9289 m = get_interface_helper(q, args.interface);
9290 if (m) {
9291 count = m->ringinuse;
9292 ao2_ref(m, -1);
9293 }
9294 } else {
9295 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9296 }
9297 ao2_unlock(q);
9298 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9299 } else {
9300 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9301 }
9302
9303 snprintf(buf, len, "%d", count);
9304
9305 return 0;
9306}
9307
9308/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. */
9309static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
9310{
9311 int memvalue;
9312
9314 AST_APP_ARG(queuename);
9315 AST_APP_ARG(option);
9316 AST_APP_ARG(interface);
9317 );
9318
9319 if (ast_strlen_zero(data)) {
9321 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9322 cmd);
9323 return -1;
9324 }
9325
9327
9328 if (ast_strlen_zero(args.option)
9329 || ast_strlen_zero(args.interface)) {
9331 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9332 cmd);
9333 return -1;
9334 }
9335
9336 /*
9337 * If queuename is empty then the option will be
9338 * set for the interface in all queues.
9339 */
9340
9341 memvalue = atoi(value);
9342 if (!strcasecmp(args.option, "penalty")) {
9343 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9344 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9345 return -1;
9346 }
9347 } else if (!strcasecmp(args.option, "paused")) {
9348 memvalue = (memvalue <= 0) ? 0 : 1;
9349 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9350 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9351 return -1;
9352 }
9353 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9354 || !strcasecmp(args.option, "ringinuse")) {
9355 memvalue = (memvalue <= 0) ? 0 : 1;
9356 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9357 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9358 return -1;
9359 }
9360 } else {
9361 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9362 return -1;
9363 }
9364 return 0;
9365}
9366
9367/*! \brief Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue */
9368static int queue_function_queuegetchannel(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9369{
9370 int position;
9371 char *parse;
9372 struct call_queue *q;
9373 struct ast_variable *var;
9374
9376 AST_APP_ARG(queuename);
9377 AST_APP_ARG(position);
9378 );
9379
9380 buf[0] = '\0';
9381
9382 if (ast_strlen_zero(data)) {
9383 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9384 return -1;
9385 }
9386
9387 parse = ast_strdupa(data);
9389
9390 if (ast_strlen_zero(args.queuename)) {
9391 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9392 return -1;
9393 }
9394
9395 if (ast_strlen_zero(args.position)) {
9396 position = 1;
9397 } else {
9398 if (sscanf(args.position, "%30d", &position) != 1) {
9399 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9400 return -1;
9401 }
9402 if (position < 1) {
9403 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9404 return -1;
9405 }
9406 }
9407
9408 {
9409 struct call_queue tmpq = {
9410 .name = args.queuename,
9411 };
9412
9413 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9414 }
9415 if (q) {
9416 ao2_lock(q);
9417 if (q->count >= position) {
9418 struct queue_ent *qe;
9419
9420 for (qe = q->head; qe; qe = qe->next) {
9421 if (qe->pos == position) {
9423 break;
9424 }
9425 }
9426 }
9427 ao2_unlock(q);
9428 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9429 return 0;
9430 }
9431
9432 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9433 if (var) {
9434 /* if the queue is realtime but was not found in memory, this
9435 * means that the queue had been deleted from memory since it was
9436 * "dead."
9437 */
9439 return 0;
9440 }
9441
9442 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9443 return 0;
9444}
9445
9446/*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
9447static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9448{
9449 int count = 0;
9450 struct call_queue *q, tmpq = {
9451 .name = data,
9452 };
9453 struct ast_variable *var = NULL;
9454
9455 buf[0] = '\0';
9456
9457 if (ast_strlen_zero(data)) {
9458 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9459 return -1;
9460 }
9461
9462 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9463 ao2_lock(q);
9464 count = q->count;
9465 ao2_unlock(q);
9466 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9467 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9468 /* if the queue is realtime but was not found in memory, this
9469 * means that the queue had been deleted from memory since it was
9470 * "dead." This means it has a 0 waiting count
9471 */
9472 count = 0;
9474 } else {
9475 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9476 }
9477
9478 snprintf(buf, len, "%d", count);
9479
9480 return 0;
9481}
9482
9483/*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
9484static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9485{
9486 struct call_queue *q;
9487 struct member *m;
9488
9489 /* Ensure an otherwise empty list doesn't return garbage */
9490 buf[0] = '\0';
9491
9492 if (ast_strlen_zero(data)) {
9493 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9494 return -1;
9495 }
9496
9497 if ((q = find_load_queue_rt_friendly(data))) {
9498 int buflen = 0, count = 0;
9499 struct ao2_iterator mem_iter;
9500
9501 ao2_lock(q);
9502 mem_iter = ao2_iterator_init(q->members, 0);
9503 while ((m = ao2_iterator_next(&mem_iter))) {
9504 /* strcat() is always faster than printf() */
9505 if (count++) {
9506 strncat(buf + buflen, ",", len - buflen - 1);
9507 buflen++;
9508 }
9509 strncat(buf + buflen, m->interface, len - buflen - 1);
9510 buflen += strlen(m->interface);
9511 /* Safeguard against overflow (negative length) */
9512 if (buflen >= len - 2) {
9513 ao2_ref(m, -1);
9514 ast_log(LOG_WARNING, "Truncating list\n");
9515 break;
9516 }
9517 ao2_ref(m, -1);
9518 }
9519 ao2_iterator_destroy(&mem_iter);
9520 ao2_unlock(q);
9521 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9522 } else
9523 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9524
9525 /* We should already be terminated, but let's make sure. */
9526 buf[len - 1] = '\0';
9527
9528 return 0;
9529}
9530
9531/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
9532static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9533{
9534 int penalty;
9536 AST_APP_ARG(queuename);
9537 AST_APP_ARG(interface);
9538 );
9539 /* Make sure the returned value on error is NULL. */
9540 buf[0] = '\0';
9541
9542 if (ast_strlen_zero(data)) {
9543 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9544 return -1;
9545 }
9546
9548
9549 if (args.argc < 2) {
9550 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9551 return -1;
9552 }
9553
9554 penalty = get_member_penalty (args.queuename, args.interface);
9555
9556 if (penalty >= 0) { /* remember that buf is already '\0' */
9557 snprintf (buf, len, "%d", penalty);
9558 }
9559
9560 return 0;
9561}
9562
9563/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
9564static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
9565{
9566 int penalty;
9568 AST_APP_ARG(queuename);
9569 AST_APP_ARG(interface);
9570 );
9571
9572 if (ast_strlen_zero(data)) {
9573 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9574 return -1;
9575 }
9576
9578
9579 if (args.argc < 2) {
9580 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9581 return -1;
9582 }
9583
9584 penalty = atoi(value);
9585
9586 if (ast_strlen_zero(args.interface)) {
9587 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9588 return -1;
9589 }
9590
9591 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9592 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9593 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9594 return -1;
9595 }
9596
9597 return 0;
9598}
9599
9601 .name = "QUEUE_EXISTS",
9602 .read = queue_function_exists,
9603};
9604
9606 .name = "QUEUE_VARIABLES",
9607 .read = queue_function_var,
9608};
9609
9611 .name = "QUEUE_MEMBER",
9613 .write = queue_function_mem_write,
9614};
9615
9617 .name = "QUEUE_GET_CHANNEL",
9619};
9620
9622 .name = "QUEUE_WAITING_COUNT",
9624};
9625
9627 .name = "QUEUE_MEMBER_LIST",
9629};
9630
9632 .name = "QUEUE_MEMBER_PENALTY",
9635};
9636
9637/*! Reset the global queue rules parameters even if there is no "general" section of queuerules.conf */
9639{
9640 realtime_rules = 0;
9641}
9642
9643/*! Set the global queue rules parameters as defined in the "general" section of queuerules.conf */
9645{
9646 const char *general_val = NULL;
9647 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9648 realtime_rules = ast_true(general_val);
9649 }
9650}
9651
9652/*! \brief Reload the rules defined in queuerules.conf
9653 *
9654 * \param reload If 1, then only process queuerules.conf if the file
9655 * has changed since the last time we inspected it.
9656 * \return Always returns AST_MODULE_LOAD_SUCCESS
9657 */
9659{
9660 struct ast_config *cfg;
9661 struct rule_list *rl_iter, *new_rl;
9662 struct penalty_rule *pr_iter;
9663 char *rulecat = NULL;
9664 struct ast_variable *rulevar = NULL;
9665 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9666
9667 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9668 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9670 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9671 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9673 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9674 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9676 }
9677
9679 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9680 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9681 ast_free(pr_iter);
9682 ast_free(rl_iter);
9683 }
9685 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9686 if (!strcasecmp(rulecat, "general")) {
9688 continue;
9689 }
9690 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9692 ast_config_destroy(cfg);
9694 } else {
9695 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9696 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9697 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9698 if(!strcasecmp(rulevar->name, "penaltychange"))
9699 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9700 else
9701 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9702 }
9703 }
9704
9705 ast_config_destroy(cfg);
9706
9710 }
9711
9714}
9715
9716/*! Always set the global queue defaults, even if there is no "general" section in queues.conf */
9718{
9720 autofill_default = 0;
9721 montype_default = 0;
9722 shared_lastcall = 0;
9727}
9728
9729/*! Set the global queue parameters as defined in the "general" section of queues.conf */
9730static void queue_set_global_params(struct ast_config *cfg)
9731{
9732 const char *general_val = NULL;
9733 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9734 queue_persistent_members = ast_true(general_val);
9735 }
9736 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9737 autofill_default = ast_true(general_val);
9738 }
9739 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9740 if (!strcasecmp(general_val, "mixmonitor"))
9741 montype_default = 1;
9742 }
9743 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9744 shared_lastcall = ast_true(general_val);
9745 }
9746 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9747 negative_penalty_invalid = ast_true(general_val);
9748 }
9749 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9750 log_membername_as_agent = ast_true(general_val);
9751 }
9752 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9754 }
9755 if ((general_val = ast_variable_retrieve(cfg, "general", "log_unpause_on_reason_change"))) {
9757 }
9758 /* Apply log-caller-id-name in the same place as other global settings */
9759 if ((general_val = ast_variable_retrieve(cfg, "general", "log-caller-id-name"))) {
9760 log_caller_id_name = ast_true(general_val);
9761 }
9762}
9763
9764/*! \brief reload information pertaining to a single member
9765 *
9766 * This function is called when a member = line is encountered in
9767 * queues.conf.
9768 *
9769 * \param memberdata The part after member = in the config file
9770 * \param q The queue to which this member belongs
9771 */
9772static void reload_single_member(const char *memberdata, struct call_queue *q)
9773{
9774 char *membername, *interface, *state_interface, *tmp;
9775 char *parse;
9776 struct member *cur, *newm;
9777 struct member tmpmem;
9778 int penalty;
9779 int ringinuse;
9780 int wrapuptime;
9781 int paused;
9790 );
9791
9792 if (ast_strlen_zero(memberdata)) {
9793 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9794 return;
9795 }
9796
9797 /* Add a new member */
9798 parse = ast_strdupa(memberdata);
9799
9801
9802 interface = args.interface;
9803 if (!ast_strlen_zero(args.penalty)) {
9804 tmp = args.penalty;
9805 ast_strip(tmp);
9806 penalty = atoi(tmp);
9807 if (penalty < 0) {
9808 penalty = 0;
9809 }
9810 } else {
9811 penalty = 0;
9812 }
9813
9814 if (!ast_strlen_zero(args.membername)) {
9815 membername = args.membername;
9816 ast_strip(membername);
9817 } else {
9818 membername = interface;
9819 }
9820
9821 if (!ast_strlen_zero(args.state_interface)) {
9822 state_interface = args.state_interface;
9823 ast_strip(state_interface);
9824 } else {
9825 state_interface = interface;
9826 }
9827
9828 if (!ast_strlen_zero(args.ringinuse)) {
9829 tmp = args.ringinuse;
9830 ast_strip(tmp);
9831 if (ast_true(tmp)) {
9832 ringinuse = 1;
9833 } else if (ast_false(tmp)) {
9834 ringinuse = 0;
9835 } else {
9836 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9837 membername, q->name);
9838 ringinuse = q->ringinuse;
9839 }
9840 } else {
9841 ringinuse = q->ringinuse;
9842 }
9843
9844 if (!ast_strlen_zero(args.wrapuptime)) {
9845 tmp = args.wrapuptime;
9846 ast_strip(tmp);
9847 wrapuptime = atoi(tmp);
9848 if (wrapuptime < 0) {
9849 wrapuptime = 0;
9850 }
9851 } else {
9852 wrapuptime = 0;
9853 }
9854
9855 if (!ast_strlen_zero(args.paused)) {
9856 tmp = args.paused;
9857 ast_strip(tmp);
9858 if (ast_true(tmp)) {
9859 paused = 1;
9860 } else if (ast_false(tmp)) {
9861 paused = 0;
9862 } else {
9863 ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername);
9864 paused = 0;
9865 }
9866 } else {
9867 paused = 0;
9868 }
9869
9870 /* Find the old position in the list */
9871 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9872 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9873
9874 if (cur) {
9875 paused = cur->paused;
9876 }
9877
9878 if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
9879 newm->wrapuptime = wrapuptime;
9880 if (cur) {
9881 ao2_lock(q->members);
9882 /* Round Robin Queue Position must be copied if this is replacing an existing member */
9883 newm->queuepos = cur->queuepos;
9884 /* Don't reset agent stats either */
9885 newm->calls = cur->calls;
9886 newm->lastcall = cur->lastcall;
9887
9888 ao2_link(q->members, newm);
9889 ao2_unlink(q->members, cur);
9890 ao2_unlock(q->members);
9891 } else {
9892 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9893 member_add_to_queue(q, newm);
9894 }
9895 ao2_ref(newm, -1);
9896 }
9897 newm = NULL;
9898
9899 if (cur) {
9900 ao2_ref(cur, -1);
9901 }
9902}
9903
9904static int mark_member_dead(void *obj, void *arg, int flags)
9905{
9906 struct member *member = obj;
9907 if (!member->dynamic && !member->realtime) {
9908 member->delme = 1;
9909 }
9910 return 0;
9911}
9912
9913static int kill_dead_members(void *obj, void *arg, int flags)
9914{
9915 struct member *member = obj;
9916
9917 if (!member->delme) {
9919 return 0;
9920 } else {
9921 return CMP_MATCH;
9922 }
9923}
9924
9925/*! \brief Reload information pertaining to a particular queue
9926 *
9927 * Once we have isolated a queue within reload_queues, we call this. This will either
9928 * reload information for the queue or if we're just reloading member information, we'll just
9929 * reload that without touching other settings within the queue
9930 *
9931 * \param cfg The configuration which we are reading
9932 * \param mask Tells us what information we need to reload
9933 * \param queuename The name of the queue we are reloading information from
9934 */
9935static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
9936{
9937 int new;
9938 struct call_queue *q = NULL;
9939 struct member *member;
9940 /*We're defining a queue*/
9941 struct call_queue tmpq = {
9942 .name = queuename,
9943 };
9944 const char *tmpvar;
9945 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9946 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
9947 int prev_weight = 0;
9948 struct ast_variable *var;
9949 struct ao2_iterator mem_iter;
9950
9951 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
9952 if (queue_reload) {
9953 /* Make one then */
9954 if (!(q = alloc_queue(queuename))) {
9955 return;
9956 }
9957 } else {
9958 /* Since we're not reloading queues, this means that we found a queue
9959 * in the configuration file which we don't know about yet. Just return.
9960 */
9961 return;
9962 }
9963 new = 1;
9964 } else {
9965 new = 0;
9966 }
9967
9968 if (!new) {
9969 ao2_lock(q);
9970 prev_weight = q->weight ? 1 : 0;
9971 }
9972 /* Check if we already found a queue with this name in the config file */
9973 if (q->found) {
9974 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
9975 if (!new) {
9976 /* It should be impossible to *not* hit this case*/
9977 ao2_unlock(q);
9978 }
9979 queue_t_unref(q, "We exist! Expiring temporary pointer");
9980 return;
9981 }
9982 /* Due to the fact that the "linear" strategy will have a different allocation
9983 * scheme for queue members, we must devise the queue's strategy before other initializations.
9984 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
9985 * container used will have only a single bucket instead of the typical number.
9986 */
9987 if (queue_reload) {
9988 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
9989 q->strategy = strat2int(tmpvar);
9990 if (q->strategy < 0) {
9991 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
9992 tmpvar, q->name);
9994 }
9995 } else {
9997 }
9998 init_queue(q);
9999 }
10000 if (member_reload) {
10002 q->found = 1;
10003 }
10004
10005 /* On the first pass we just read the parameters of the queue */
10006 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10007 if (queue_reload && strcasecmp(var->name, "member")) {
10008 queue_set_param(q, var->name, var->value, var->lineno, 1);
10009 }
10010 }
10011
10012 /* On the second pass, we read members */
10013 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
10014 if (member_reload && !strcasecmp(var->name, "member")) {
10015 reload_single_member(var->value, q);
10016 }
10017 }
10018
10019 /* Update ringinuse for dynamic members */
10020 if (member_reload) {
10021 ao2_lock(q->members);
10023 while ((member = ao2_iterator_next(&mem_iter))) {
10024 if (member->dynamic) {
10026 }
10027 ao2_ref(member, -1);
10028 }
10029 ao2_iterator_destroy(&mem_iter);
10030 ao2_unlock(q->members);
10031 }
10032
10033 /* At this point, we've determined if the queue has a weight, so update use_weight
10034 * as appropriate
10035 */
10036 if (!q->weight && prev_weight) {
10038 } else if (q->weight && !prev_weight) {
10040 }
10041
10042 /* Free remaining members marked as delme */
10043 if (member_reload) {
10044 ao2_lock(q->members);
10047 ao2_unlock(q->members);
10048 }
10049
10050 if (new) {
10051 queues_t_link(queues, q, "Add queue to container");
10052 } else {
10053 ao2_unlock(q);
10054 }
10055 queue_t_unref(q, "Expiring creation reference");
10056}
10057
10058static int mark_unfound(void *obj, void *arg, int flags)
10059{
10060 struct call_queue *q = obj;
10061 char *queuename = arg;
10062 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10063 q->found = 0;
10064 }
10065 return 0;
10066}
10067
10068static int kill_if_unfound(void *obj, void *arg, int flags)
10069{
10070 struct call_queue *q = obj;
10071 char *queuename = arg;
10072 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
10073 q->dead = 1;
10074 return CMP_MATCH;
10075 } else {
10076 return 0;
10077 }
10078}
10079
10080/*! \brief reload the queues.conf file
10081 *
10082 * This function reloads the information in the general section of the queues.conf
10083 * file and potentially more, depending on the value of mask.
10084 *
10085 * \param reload 0 if we are calling this the first time, 1 every other time
10086 * \param mask Gives flags telling us what information to actually reload
10087 * \param queuename If set to a non-zero string, then only reload information from
10088 * that particular queue. Otherwise inspect all queues
10089 * \retval -1 Failure occurred
10090 * \retval 0 All clear!
10091 */
10092static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
10093{
10094 struct ast_config *cfg;
10095 char *cat;
10096 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
10097 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
10098
10099 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
10100 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
10101 return -1;
10102 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
10103 return 0;
10104 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
10105 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
10106 return -1;
10107 }
10108
10109 /* We've made it here, so it looks like we're doing operations on all queues. */
10111
10112 /* Mark non-realtime queues not found at the beginning. */
10113 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10114
10115 /* Chug through config file. */
10116 cat = NULL;
10118 while ((cat = ast_category_browse(cfg, cat)) ) {
10119 if (!strcasecmp(cat, "general") && queue_reload) {
10121 continue;
10122 }
10123 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10124 reload_single_queue(cfg, mask, cat);
10125 }
10126
10127 ast_config_destroy(cfg);
10128 if (queue_reload) {
10129 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10131 }
10133 return 0;
10134}
10135
10136/*! \brief Facilitates resetting statistics for a queue
10137 *
10138 * This function actually does not reset any statistics, but
10139 * rather finds a call_queue struct which corresponds to the
10140 * passed-in queue name and passes that structure to the
10141 * clear_queue function. If no queuename is passed in, then
10142 * all queues will have their statistics reset.
10143 *
10144 * \param queuename The name of the queue to reset the statistics
10145 * for. If this is NULL or zero-length, then this means to reset
10146 * the statistics for all queues
10147 * \retval 0 always
10148 */
10149static int clear_stats(const char *queuename)
10150{
10151 struct call_queue *q;
10152 struct ao2_iterator queue_iter;
10153
10154 queue_iter = ao2_iterator_init(queues, 0);
10155 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10156 ao2_lock(q);
10157 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10158 clear_queue(q);
10159 ao2_unlock(q);
10160 queue_t_unref(q, "Done with iterator");
10161 }
10162 ao2_iterator_destroy(&queue_iter);
10163 return 0;
10164}
10165
10166/*! \brief The command center for all reload operations
10167 *
10168 * Whenever any piece of queue information is to be reloaded, this function
10169 * is called. It interprets the flags set in the mask parameter and acts
10170 * based on how they are set.
10171 *
10172 * \param reload True if we are reloading information, false if we are loading
10173 * information for the first time.
10174 * \param mask A bitmask which tells the handler what actions to take
10175 * \param queuename The name of the queue on which we wish to take action
10176 * \retval 0 All reloads were successful
10177 * \retval non-zero There was a failure
10178 */
10179static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
10180{
10181 int res = 0;
10182
10183 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10184 res |= reload_queue_rules(reload);
10185 }
10186 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10187 res |= clear_stats(queuename);
10188 }
10190 res |= reload_queues(reload, mask, queuename);
10191 }
10192 return res;
10193}
10194
10195/*! \brief direct output to manager or cli with proper terminator */
10196static void do_print(struct mansession *s, int fd, const char *str)
10197{
10198 if (s) {
10199 astman_append(s, "%s\r\n", str);
10200 } else {
10201 ast_cli(fd, "%s\n", str);
10202 }
10203}
10204
10205/*! \brief Print a single queue to AMI or the CLI */
10206static void print_queue(struct mansession *s, int fd, struct call_queue *q)
10207{
10208 float sl;
10209 float sl2;
10210 struct ao2_iterator mem_iter;
10211 struct ast_str *out = ast_str_alloca(512);
10212 time_t now = time(NULL);
10213
10214 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10215 if (q->maxlen) {
10216 ast_str_append(&out, 0, "%d", q->maxlen);
10217 } else {
10218 ast_str_append(&out, 0, "unlimited");
10219 }
10220 sl = 0;
10221 sl2 = 0;
10222 if (q->callscompleted > 0) {
10223 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10224 }
10225 if (q->callscompleted + q->callsabandoned > 0) {
10226 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10227 }
10228
10229 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%%, SL2:%2.1f%% within %ds",
10231 do_print(s, fd, ast_str_buffer(out));
10232 if (!ao2_container_count(q->members)) {
10233 do_print(s, fd, " No Members");
10234 } else {
10235 struct member *mem;
10236
10237 do_print(s, fd, " Members: ");
10238 mem_iter = ao2_iterator_init(q->members, 0);
10239 while ((mem = ao2_iterator_next(&mem_iter))) {
10240 ast_str_set(&out, 0, " %s", mem->membername);
10241 if (strcasecmp(mem->membername, mem->interface)) {
10242 ast_str_append(&out, 0, " (%s", mem->interface);
10244 && strcmp(mem->state_interface, mem->interface)) {
10245 ast_str_append(&out, 0, " from %s", mem->state_interface);
10246 }
10247 ast_str_append(&out, 0, ")");
10248 }
10249 if (mem->penalty) {
10250 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10251 }
10252
10253 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10254
10255 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10256 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10257 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10258 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10259
10260 if (mem->paused) {
10261 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10263 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10265 (long) (now - mem->lastpause),
10266 ast_term_reset());
10267 }
10268
10269 ast_str_append(&out, 0, " (%s%s%s)",
10274 if (mem->calls) {
10275 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10276 mem->calls, (long) (now - mem->lastcall));
10277 } else {
10278 ast_str_append(&out, 0, " has taken no calls yet");
10279 }
10280 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10282 (long) (now - mem->logintime),
10283 ast_term_reset());
10284 do_print(s, fd, ast_str_buffer(out));
10285 ao2_ref(mem, -1);
10286 }
10287 ao2_iterator_destroy(&mem_iter);
10288 }
10289 if (!q->head) {
10290 do_print(s, fd, " No Callers");
10291 } else {
10292 struct queue_ent *qe;
10293 int pos = 1;
10294
10295 do_print(s, fd, " Callers: ");
10296 for (qe = q->head; qe; qe = qe->next) {
10297 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10298 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10299 (long) (now - qe->start) % 60, qe->prio);
10300 do_print(s, fd, ast_str_buffer(out));
10301 }
10302 }
10303 do_print(s, fd, ""); /* blank line between entries */
10304}
10305
10307
10308/*!
10309 * \brief Show queue(s) status and statistics
10310 *
10311 * List the queues strategy, calls processed, members logged in,
10312 * other queue statistics such as avg hold time.
10313*/
10314static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
10315{
10316 struct call_queue *q;
10317 struct ast_str *out = ast_str_alloca(512);
10318 struct ao2_container *sorted_queues;
10319
10320 struct ao2_iterator queue_iter;
10321 int found = 0;
10322
10323 if (argc != 2 && argc != 3) {
10324 return CLI_SHOWUSAGE;
10325 }
10326
10327 if (argc == 3) { /* specific queue */
10328 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10329 ao2_lock(q);
10330 print_queue(s, fd, q);
10331 ao2_unlock(q);
10332 queue_unref(q);
10333 } else {
10334 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10335 do_print(s, fd, ast_str_buffer(out));
10336 }
10337 return CLI_SUCCESS;
10338 }
10339
10340 if (ast_check_realtime("queues")) {
10341 /* This block is to find any queues which are defined in realtime but
10342 * which have not yet been added to the in-core container
10343 */
10344 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10345 if (cfg) {
10346 char *category = NULL;
10347 while ((category = ast_category_browse(cfg, category))) {
10348 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10349 if (ast_strlen_zero(queuename)) {
10350 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10351 continue;
10352 }
10353 if ((q = find_load_queue_rt_friendly(queuename))) {
10354 queue_t_unref(q, "Done with temporary pointer");
10355 }
10356 }
10357 ast_config_destroy(cfg);
10358 }
10359 }
10360
10361 /*
10362 * Snapping a copy of the container prevents having to lock both the queues container
10363 * and the queue itself at the same time. It also allows us to sort the entries.
10364 */
10365 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10366 if (!sorted_queues) {
10367 return CLI_SUCCESS;
10368 }
10369 if (ao2_container_dup(sorted_queues, queues, 0)) {
10370 ao2_ref(sorted_queues, -1);
10371 return CLI_SUCCESS;
10372 }
10373
10374 /*
10375 * No need to lock the container since it's temporary and static.
10376 * We also unlink the entries as we use them so the container is
10377 * empty when the iterator finishes. We can then just unref the container.
10378 */
10379 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10380 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10381 struct call_queue *realtime_queue = NULL;
10382 ao2_lock(q);
10383 /* This check is to make sure we don't print information for realtime
10384 * queues which have been deleted from realtime but which have not yet
10385 * been deleted from the in-core container. Only do this if we're not
10386 * looking for a specific queue.
10387 */
10388 if (q->realtime) {
10389 realtime_queue = find_load_queue_rt_friendly(q->name);
10390 if (!realtime_queue) {
10391 ao2_unlock(q);
10392 queue_t_unref(q, "Done with iterator");
10393 continue;
10394 }
10395 queue_t_unref(realtime_queue, "Queue is already in memory");
10396 }
10397
10398 found = 1;
10399 print_queue(s, fd, q);
10400
10401 ao2_unlock(q);
10402 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10403 }
10404 ao2_iterator_destroy(&queue_iter);
10405 ao2_ref(sorted_queues, -1);
10406 if (!found) {
10407 ast_str_set(&out, 0, "No queues.");
10408 do_print(s, fd, ast_str_buffer(out));
10409 }
10410 return CLI_SUCCESS;
10411}
10412
10413/*!
10414 * \brief Check if a given word is in a space-delimited list
10415 *
10416 * \param list Space delimited list of words
10417 * \param word The word used to search the list
10418 *
10419 * \note This function will not return 1 if the word is at the very end of the
10420 * list (followed immediately by a \0, not a space) since it is used for
10421 * checking tab-completion and a word at the end is still being tab-completed.
10422 *
10423 * \retval 1 if the word is found
10424 * \retval 0 if the word is not found
10425*/
10426static int word_in_list(const char *list, const char *word) {
10427 int list_len, word_len = strlen(word);
10428 const char *find, *end_find, *end_list;
10429
10430 /* strip whitespace from front */
10431 while(isspace(*list)) {
10432 list++;
10433 }
10434
10435 while((find = strstr(list, word))) {
10436 /* beginning of find starts inside another word? */
10437 if (find != list && *(find - 1) != ' ') {
10438 list = find;
10439 /* strip word from front */
10440 while(!isspace(*list) && *list != '\0') {
10441 list++;
10442 }
10443 /* strip whitespace from front */
10444 while(isspace(*list)) {
10445 list++;
10446 }
10447 continue;
10448 }
10449
10450 /* end of find ends inside another word or at very end of list? */
10451 list_len = strlen(list);
10452 end_find = find + word_len;
10453 end_list = list + list_len;
10454 if (end_find == end_list || *end_find != ' ') {
10455 list = find;
10456 /* strip word from front */
10457 while(!isspace(*list) && *list != '\0') {
10458 list++;
10459 }
10460 /* strip whitespace from front */
10461 while(isspace(*list)) {
10462 list++;
10463 }
10464 continue;
10465 }
10466
10467 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10468 return 1;
10469 }
10470
10471 return 0;
10472}
10473
10474/*!
10475 * \brief Check if a given word is in a space-delimited list
10476 *
10477 * \param line The line as typed not including the current word being completed
10478 * \param word The word currently being completed
10479 * \param pos The number of completed words in line
10480 * \param state The nth desired completion option
10481 * \param word_list_offset Offset into the line where the list of queues begins. If non-zero, queues in the list will not be offered for further completion.
10482 *
10483 * \return Returns the queue tab-completion for the given word and state
10484*/
10485static char *complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
10486{
10487 struct call_queue *q;
10488 char *ret = NULL;
10489 int which = 0;
10490 int wordlen = strlen(word);
10491 struct ao2_iterator queue_iter;
10492 const char *word_list = NULL;
10493
10494 /* for certain commands, already completed items should be left out of
10495 * the list */
10496 if (word_list_offset && strlen(line) >= word_list_offset) {
10497 word_list = line + word_list_offset;
10498 }
10499
10500 queue_iter = ao2_iterator_init(queues, 0);
10501 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10502 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10503 && (!word_list_offset || !word_in_list(word_list, q->name))) {
10504 ret = ast_strdup(q->name);
10505 queue_t_unref(q, "Done with iterator");
10506 break;
10507 }
10508 queue_t_unref(q, "Done with iterator");
10509 }
10510 ao2_iterator_destroy(&queue_iter);
10511
10512 /* Pretend "rules" is at the end of the queues list in certain
10513 * circumstances since it is an alternate command that should be
10514 * tab-completable for "queue show" */
10515 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10516 ret = ast_strdup("rules");
10517 }
10518
10519 return ret;
10520}
10521
10522static char *complete_queue_show(const char *line, const char *word, int pos, int state)
10523{
10524 if (pos == 2) {
10525 return complete_queue(line, word, pos, state, 0);
10526 }
10527 return NULL;
10528}
10529
10530static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10531{
10532 switch ( cmd ) {
10533 case CLI_INIT:
10534 e->command = "queue show";
10535 e->usage =
10536 "Usage: queue show\n"
10537 " Provides summary information on a specified queue.\n";
10538 return NULL;
10539 case CLI_GENERATE:
10540 return complete_queue_show(a->line, a->word, a->pos, a->n);
10541 }
10542
10543 return __queues_show(NULL, a->fd, a->argc, a->argv);
10544}
10545
10546static int manager_queue_rule_show(struct mansession *s, const struct message *m)
10547{
10548 const char *rule = astman_get_header(m, "Rule");
10549 const char *id = astman_get_header(m, "ActionID");
10550 struct rule_list *rl_iter;
10551 struct penalty_rule *pr_iter;
10552
10553 astman_append(s, "Response: Success\r\n");
10554 if (!ast_strlen_zero(id)) {
10555 astman_append(s, "ActionID: %s\r\n", id);
10556 }
10557
10559 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10560 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10561 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10562 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10563 astman_append(s, "Rule: %d,%s%d,%s%d\r\n", pr_iter->time, pr_iter->max_relative && pr_iter->max_value >= 0 ? "+" : "", pr_iter->max_value, pr_iter->min_relative && pr_iter->min_value >= 0 ? "+" : "", pr_iter->min_value );
10564 }
10565 if (!ast_strlen_zero(rule)) {
10566 break;
10567 }
10568 }
10569 }
10571
10572 /*
10573 * Two blank lines instead of one because the Response and
10574 * ActionID headers used to not be present.
10575 */
10576 astman_append(s, "\r\n\r\n");
10577
10578 return RESULT_SUCCESS;
10579}
10580
10581/*! \brief Summary of queue info via the AMI */
10582static int manager_queues_summary(struct mansession *s, const struct message *m)
10583{
10584 time_t now;
10585 int qmemcount = 0;
10586 int qmemavail = 0;
10587 int qchancount = 0;
10588 int qlongestholdtime = 0;
10589 int qsummaries = 0;
10590 const char *id = astman_get_header(m, "ActionID");
10591 const char *queuefilter = astman_get_header(m, "Queue");
10592 char idText[256];
10593 struct call_queue *q;
10594 struct queue_ent *qe;
10595 struct member *mem;
10596 struct ao2_iterator queue_iter;
10597 struct ao2_iterator mem_iter;
10598
10599 if (ast_check_realtime("queues")) {
10600 load_realtime_queues(queuefilter);
10601 }
10602
10603 astman_send_listack(s, m, "Queue summary will follow", "start");
10604 time(&now);
10605 idText[0] = '\0';
10606 if (!ast_strlen_zero(id)) {
10607 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10608 }
10609 queue_iter = ao2_iterator_init(queues, 0);
10610 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10611 ao2_lock(q);
10612
10613 /* List queue properties */
10614 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10615 /* Reset the necessary local variables if no queuefilter is set*/
10616 qmemcount = 0;
10617 qmemavail = 0;
10618 qchancount = 0;
10619 qlongestholdtime = 0;
10620
10621 /* List Queue Members */
10622 mem_iter = ao2_iterator_init(q->members, 0);
10623 while ((mem = ao2_iterator_next(&mem_iter))) {
10624 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10625 ++qmemcount;
10626 if (member_status_available(mem->status) && !mem->paused) {
10627 ++qmemavail;
10628 }
10629 }
10630 ao2_ref(mem, -1);
10631 }
10632 ao2_iterator_destroy(&mem_iter);
10633 for (qe = q->head; qe; qe = qe->next) {
10634 if ((now - qe->start) > qlongestholdtime) {
10635 qlongestholdtime = now - qe->start;
10636 }
10637 ++qchancount;
10638 }
10639 astman_append(s, "Event: QueueSummary\r\n"
10640 "Queue: %s\r\n"
10641 "LoggedIn: %d\r\n"
10642 "Available: %d\r\n"
10643 "Callers: %d\r\n"
10644 "HoldTime: %d\r\n"
10645 "TalkTime: %d\r\n"
10646 "LongestHoldTime: %d\r\n"
10647 "%s"
10648 "\r\n",
10649 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10650 ++qsummaries;
10651 }
10652 ao2_unlock(q);
10653 queue_t_unref(q, "Done with iterator");
10654 }
10655 ao2_iterator_destroy(&queue_iter);
10656
10657 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10659
10660 return RESULT_SUCCESS;
10661}
10662
10663/*! \brief Queue status info via AMI */
10664static int manager_queues_status(struct mansession *s, const struct message *m)
10665{
10666 time_t now;
10667 int pos;
10668 int q_items = 0;
10669 const char *id = astman_get_header(m,"ActionID");
10670 const char *queuefilter = astman_get_header(m,"Queue");
10671 const char *memberfilter = astman_get_header(m,"Member");
10672 char idText[256];
10673 struct call_queue *q;
10674 struct queue_ent *qe;
10675 float sl = 0;
10676 float sl2 = 0;
10677 struct member *mem;
10678 struct ao2_iterator queue_iter;
10679 struct ao2_iterator mem_iter;
10680
10681 if (ast_check_realtime("queues")) {
10682 load_realtime_queues(queuefilter);
10683 }
10684
10685 astman_send_listack(s, m, "Queue status will follow", "start");
10686 time(&now);
10687 idText[0] = '\0';
10688 if (!ast_strlen_zero(id)) {
10689 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10690 }
10691
10692 queue_iter = ao2_iterator_init(queues, 0);
10693 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10694 ao2_lock(q);
10695
10696 /* List queue properties */
10697 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10698 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10699 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10700
10701 astman_append(s, "Event: QueueParams\r\n"
10702 "Queue: %s\r\n"
10703 "Max: %d\r\n"
10704 "Strategy: %s\r\n"
10705 "Calls: %d\r\n"
10706 "Holdtime: %d\r\n"
10707 "TalkTime: %d\r\n"
10708 "Completed: %d\r\n"
10709 "Abandoned: %d\r\n"
10710 "ServiceLevel: %d\r\n"
10711 "ServicelevelPerf: %2.1f\r\n"
10712 "ServicelevelPerf2: %2.1f\r\n"
10713 "Weight: %d\r\n"
10714 "%s"
10715 "\r\n",
10716 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10717 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10718 ++q_items;
10719
10720 /* List Queue Members */
10721 mem_iter = ao2_iterator_init(q->members, 0);
10722 while ((mem = ao2_iterator_next(&mem_iter))) {
10723 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10724 astman_append(s, "Event: QueueMember\r\n"
10725 "Queue: %s\r\n"
10726 "Name: %s\r\n"
10727 "Location: %s\r\n"
10728 "StateInterface: %s\r\n"
10729 "Membership: %s\r\n"
10730 "Penalty: %d\r\n"
10731 "CallsTaken: %d\r\n"
10732 "LastCall: %d\r\n"
10733 "LastPause: %d\r\n"
10734 "LoginTime: %d\r\n"
10735 "InCall: %d\r\n"
10736 "Status: %d\r\n"
10737 "Paused: %d\r\n"
10738 "PausedReason: %s\r\n"
10739 "Wrapuptime: %d\r\n"
10740 "%s"
10741 "\r\n",
10742 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10743 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10744 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10745 ++q_items;
10746 }
10747 ao2_ref(mem, -1);
10748 }
10749 ao2_iterator_destroy(&mem_iter);
10750
10751 /* List Queue Entries */
10752 pos = 1;
10753 for (qe = q->head; qe; qe = qe->next) {
10754 astman_append(s, "Event: QueueEntry\r\n"
10755 "Queue: %s\r\n"
10756 "Position: %d\r\n"
10757 "Channel: %s\r\n"
10758 "Uniqueid: %s\r\n"
10759 "CallerIDNum: %s\r\n"
10760 "CallerIDName: %s\r\n"
10761 "ConnectedLineNum: %s\r\n"
10762 "ConnectedLineName: %s\r\n"
10763 "Wait: %ld\r\n"
10764 "Priority: %d\r\n"
10765 "%s"
10766 "\r\n",
10767 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10772 (long) (now - qe->start), qe->prio, idText);
10773 ++q_items;
10774 }
10775 }
10776 ao2_unlock(q);
10777 queue_t_unref(q, "Done with iterator");
10778 }
10779 ao2_iterator_destroy(&queue_iter);
10780
10781 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10783
10784 return RESULT_SUCCESS;
10785}
10786
10787static int manager_add_queue_member(struct mansession *s, const struct message *m)
10788{
10789 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10790 int paused, penalty, wrapuptime = 0;
10791
10792 queuename = astman_get_header(m, "Queue");
10793 interface = astman_get_header(m, "Interface");
10794 penalty_s = astman_get_header(m, "Penalty");
10795 paused_s = astman_get_header(m, "Paused");
10796 reason = astman_get_header(m, "Reason"); /* Optional */
10797 membername = astman_get_header(m, "MemberName");
10798 state_interface = astman_get_header(m, "StateInterface");
10799 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10800
10801 if (ast_strlen_zero(queuename)) {
10802 astman_send_error(s, m, "'Queue' not specified.");
10803 return 0;
10804 }
10805
10806 if (ast_strlen_zero(interface)) {
10807 astman_send_error(s, m, "'Interface' not specified.");
10808 return 0;
10809 }
10810
10811 if (ast_strlen_zero(penalty_s)) {
10812 penalty = 0;
10813 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10814 penalty = 0;
10815 }
10816
10817 if (ast_strlen_zero(wrapuptime_s)) {
10818 wrapuptime = 0;
10819 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10820 wrapuptime = 0;
10821 }
10822
10823 if (ast_strlen_zero(paused_s)) {
10824 paused = 0;
10825 } else {
10826 paused = abs(ast_true(paused_s));
10827 }
10828
10829 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10830 case RES_OKAY:
10831 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10832 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10833 } else {
10834 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10835 }
10836 astman_send_ack(s, m, "Added interface to queue");
10837 break;
10838 case RES_EXISTS:
10839 astman_send_error(s, m, "Unable to add interface: Already there");
10840 break;
10841 case RES_NOSUCHQUEUE:
10842 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10843 break;
10844 case RES_OUTOFMEMORY:
10845 astman_send_error(s, m, "Out of memory");
10846 break;
10847 }
10848
10849 return 0;
10850}
10851
10852static int manager_remove_queue_member(struct mansession *s, const struct message *m)
10853{
10854 const char *queuename, *interface;
10855 struct member *mem = NULL;
10856
10857 queuename = astman_get_header(m, "Queue");
10858 interface = astman_get_header(m, "Interface");
10859
10860 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10861 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10862 return 0;
10863 }
10864
10866 mem = find_member_by_queuename_and_interface(queuename, interface);
10867 }
10868
10869 switch (remove_from_queue(queuename, interface)) {
10870 case RES_OKAY:
10871 if (!mem || ast_strlen_zero(mem->membername)) {
10872 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10873 } else {
10874 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10875 }
10876 astman_send_ack(s, m, "Removed interface from queue");
10877 break;
10878 case RES_EXISTS:
10879 astman_send_error(s, m, "Unable to remove interface: Not there");
10880 break;
10881 case RES_NOSUCHQUEUE:
10882 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10883 break;
10884 case RES_OUTOFMEMORY:
10885 astman_send_error(s, m, "Out of memory");
10886 break;
10887 case RES_NOT_DYNAMIC:
10888 astman_send_error(s, m, "Member not dynamic");
10889 break;
10890 }
10891
10892 if (mem) {
10893 ao2_ref(mem, -1);
10894 }
10895
10896 return 0;
10897}
10898
10899static int manager_pause_queue_member(struct mansession *s, const struct message *m)
10900{
10901 const char *queuename, *interface, *paused_s, *reason;
10902 int paused;
10903
10904 interface = astman_get_header(m, "Interface");
10905 paused_s = astman_get_header(m, "Paused");
10906 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10907 reason = astman_get_header(m, "Reason"); /* Optional */
10908
10909 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10910 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10911 return 0;
10912 }
10913
10914 paused = abs(ast_true(paused_s));
10915
10916 if (set_member_paused(queuename, interface, reason, paused)) {
10917 astman_send_error(s, m, "Interface not found");
10918 } else {
10919 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10920 }
10921 return 0;
10922}
10923
10924static int manager_queue_log_custom(struct mansession *s, const struct message *m)
10925{
10926 const char *queuename, *event, *message, *interface, *uniqueid;
10927
10928 queuename = astman_get_header(m, "Queue");
10929 uniqueid = astman_get_header(m, "UniqueId");
10930 interface = astman_get_header(m, "Interface");
10931 event = astman_get_header(m, "Event");
10932 message = astman_get_header(m, "Message");
10933
10934 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10935 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10936 return 0;
10937 }
10938
10939 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10940 astman_send_ack(s, m, "Event added successfully");
10941
10942 return 0;
10943}
10944
10945static int manager_queue_reload(struct mansession *s, const struct message *m)
10946{
10947 struct ast_flags mask = {0,};
10948 const char *queuename = NULL;
10949 int header_found = 0;
10950
10951 queuename = astman_get_header(m, "Queue");
10952 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10954 header_found = 1;
10955 }
10956 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10958 header_found = 1;
10959 }
10960 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10962 header_found = 1;
10963 }
10964
10965 if (!header_found) {
10967 }
10968
10969 if (!reload_handler(1, &mask, queuename)) {
10970 astman_send_ack(s, m, "Queue reloaded successfully");
10971 } else {
10972 astman_send_error(s, m, "Error encountered while reloading queue");
10973 }
10974 return 0;
10975}
10976
10977static int manager_queue_reset(struct mansession *s, const struct message *m)
10978{
10979 const char *queuename = NULL;
10980 struct ast_flags mask = {QUEUE_RESET_STATS,};
10981
10982 queuename = astman_get_header(m, "Queue");
10983
10984 if (!reload_handler(1, &mask, queuename)) {
10985 astman_send_ack(s, m, "Queue stats reset successfully");
10986 } else {
10987 astman_send_error(s, m, "Error encountered while resetting queue stats");
10988 }
10989 return 0;
10990}
10991
10992static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
10993{
10994 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10995 switch (pos) {
10996 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10997 return NULL;
10998 case 4: /* only one possible match, "to" */
10999 return state == 0 ? ast_strdup("to") : NULL;
11000 case 5: /* <queue> */
11001 return complete_queue(line, word, pos, state, 0);
11002 case 6: /* only one possible match, "penalty" */
11003 return state == 0 ? ast_strdup("penalty") : NULL;
11004 case 7:
11005 if (0 <= state && state < 100) { /* 0-99 */
11006 char *num;
11007 if ((num = ast_malloc(3))) {
11008 sprintf(num, "%d", state);
11009 }
11010 return num;
11011 } else {
11012 return NULL;
11013 }
11014 case 8: /* only one possible match, "as" */
11015 return state == 0 ? ast_strdup("as") : NULL;
11016 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
11017 return NULL;
11018 default:
11019 return NULL;
11020 }
11021}
11022
11023static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
11024{
11025 const char *queuename, *interface, *ringinuse_s;
11026 int ringinuse;
11027
11028 interface = astman_get_header(m, "Interface");
11029 ringinuse_s = astman_get_header(m, "RingInUse");
11030
11031 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
11032 queuename = astman_get_header(m, "Queue");
11033
11034 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
11035 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
11036 return 0;
11037 }
11038
11039 if (ast_true(ringinuse_s)) {
11040 ringinuse = 1;
11041 } else if (ast_false(ringinuse_s)) {
11042 ringinuse = 0;
11043 } else {
11044 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
11045 return 0;
11046 }
11047
11048 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11049 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
11050 } else {
11051 astman_send_ack(s, m, "Interface ringinuse set successfully");
11052 }
11053
11054 return 0;
11055}
11056
11057static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
11058{
11059 const char *queuename, *interface, *penalty_s;
11060 int penalty;
11061
11062 interface = astman_get_header(m, "Interface");
11063 penalty_s = astman_get_header(m, "Penalty");
11064 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
11065 queuename = astman_get_header(m, "Queue");
11066
11067 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
11068 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
11069 return 0;
11070 }
11071
11072 penalty = atoi(penalty_s);
11073
11074 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
11075 astman_send_error(s, m, "Invalid interface, queuename or penalty");
11076 } else {
11077 astman_send_ack(s, m, "Interface penalty set successfully");
11078 }
11079
11080 return 0;
11081}
11082
11083static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
11084{
11085 const char *queuename, *caller, *priority_s, *immediate_s;
11086 int priority = 0, immediate = 0;
11087
11088 queuename = astman_get_header(m, "Queue");
11089 caller = astman_get_header(m, "Caller");
11090 priority_s = astman_get_header(m, "Priority");
11091 immediate_s = astman_get_header(m, "Immediate");
11092
11093 if (ast_strlen_zero(queuename)) {
11094 astman_send_error(s, m, "'Queue' not specified.");
11095 return 0;
11096 }
11097
11098 if (ast_strlen_zero(caller)) {
11099 astman_send_error(s, m, "'Caller' not specified.");
11100 return 0;
11101 }
11102
11103 if (ast_strlen_zero(priority_s)) {
11104 astman_send_error(s, m, "'Priority' not specified.");
11105 return 0;
11106 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
11107 astman_send_error(s, m, "'Priority' need integer.");
11108 return 0;
11109 }
11110
11111 if (!ast_strlen_zero(immediate_s)) {
11112 immediate = ast_true(immediate_s);
11113 }
11114
11115 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11116 case RES_OKAY:
11117 astman_send_ack(s, m, "Priority change for caller on queue");
11118 break;
11119 case RES_NOSUCHQUEUE:
11120 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11121 break;
11122 case RES_NOT_CALLER:
11123 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11124 break;
11125 }
11126
11127 return 0;
11128}
11129
11131{
11132 const char *queuename, *caller, *withdraw_info;
11133
11134 queuename = astman_get_header(m, "Queue");
11135 caller = astman_get_header(m, "Caller");
11136 withdraw_info = astman_get_header(m, "WithdrawInfo");
11137
11138 if (ast_strlen_zero(queuename)) {
11139 astman_send_error(s, m, "'Queue' not specified.");
11140 return 0;
11141 }
11142
11143 if (ast_strlen_zero(caller)) {
11144 astman_send_error(s, m, "'Caller' not specified.");
11145 return 0;
11146 }
11147
11148 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11149 case RES_OKAY:
11150 astman_send_ack(s, m, "Withdraw requested successfully");
11151 break;
11152 case RES_NOSUCHQUEUE:
11153 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11154 break;
11155 case RES_NOT_CALLER:
11156 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11157 break;
11158 case RES_EXISTS:
11159 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11160 break;
11161 }
11162
11163 return 0;
11164}
11165
11166
11167static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11168{
11169 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11170 int penalty, paused = 0;
11171
11172 switch ( cmd ) {
11173 case CLI_INIT:
11174 e->command = "queue add member";
11175 e->usage =
11176 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11177 " Add a dial string (Such as a channel,e.g. SIP/6001) to a queue with optionally: a penalty, membername and a state_interface\n";
11178 return NULL;
11179 case CLI_GENERATE:
11180 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11181 }
11182
11183 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11184 return CLI_SHOWUSAGE;
11185 } else if (strcmp(a->argv[4], "to")) {
11186 return CLI_SHOWUSAGE;
11187 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11188 return CLI_SHOWUSAGE;
11189 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11190 return CLI_SHOWUSAGE;
11191 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11192 return CLI_SHOWUSAGE;
11193 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11194 return CLI_SHOWUSAGE;
11195 }
11196
11197 queuename = a->argv[5];
11198 interface = a->argv[3];
11199 if (a->argc >= 8) {
11200 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11201 if (penalty < 0) {
11202 ast_cli(a->fd, "Penalty must be >= 0\n");
11203 penalty = 0;
11204 }
11205 } else {
11206 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11207 penalty = 0;
11208 }
11209 } else {
11210 penalty = 0;
11211 }
11212
11213 if (a->argc >= 10) {
11214 membername = a->argv[9];
11215 }
11216
11217 if (a->argc >= 12) {
11218 state_interface = a->argv[11];
11219 }
11220
11221 if (a->argc >= 14) {
11222 paused = 1;
11223 reason = a->argv[13];
11224 }
11225
11226 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11227 case RES_OKAY:
11228 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11229 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11230 } else {
11231 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11232 }
11233 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11234 return CLI_SUCCESS;
11235 case RES_EXISTS:
11236 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11237 return CLI_FAILURE;
11238 case RES_NOSUCHQUEUE:
11239 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11240 return CLI_FAILURE;
11241 case RES_OUTOFMEMORY:
11242 ast_cli(a->fd, "Out of memory\n");
11243 return CLI_FAILURE;
11244 case RES_NOT_DYNAMIC:
11245 ast_cli(a->fd, "Member not dynamic\n");
11246 return CLI_FAILURE;
11247 default:
11248 return CLI_FAILURE;
11249 }
11250}
11251
11252static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
11253{
11254 int which = 0;
11255 struct call_queue *q;
11256 struct member *m;
11257 struct ao2_iterator queue_iter;
11258 struct ao2_iterator mem_iter;
11259 int wordlen = strlen(word);
11260
11261 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11262 if (pos > 5 || pos < 3) {
11263 return NULL;
11264 }
11265 if (pos == 4) { /* only one possible match, 'from' */
11266 return (state == 0 ? ast_strdup("from") : NULL);
11267 }
11268
11269 if (pos == 5) { /* No need to duplicate code */
11270 return complete_queue(line, word, pos, state, 0);
11271 }
11272
11273 /* here is the case for 3, <member> */
11274 queue_iter = ao2_iterator_init(queues, 0);
11275 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11276 ao2_lock(q);
11277 mem_iter = ao2_iterator_init(q->members, 0);
11278 while ((m = ao2_iterator_next(&mem_iter))) {
11279 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11280 char *tmp;
11281 tmp = ast_strdup(m->interface);
11282 ao2_ref(m, -1);
11283 ao2_iterator_destroy(&mem_iter);
11284 ao2_unlock(q);
11285 queue_t_unref(q, "Done with iterator, returning interface name");
11286 ao2_iterator_destroy(&queue_iter);
11287 return tmp;
11288 }
11289 ao2_ref(m, -1);
11290 }
11291 ao2_iterator_destroy(&mem_iter);
11292 ao2_unlock(q);
11293 queue_t_unref(q, "Done with iterator");
11294 }
11295 ao2_iterator_destroy(&queue_iter);
11296
11297 return NULL;
11298}
11299
11300static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11301{
11302 const char *queuename, *interface;
11303 struct member *mem = NULL;
11304 char *res = CLI_FAILURE;
11305
11306 switch (cmd) {
11307 case CLI_INIT:
11308 e->command = "queue remove member";
11309 e->usage =
11310 "Usage: queue remove member <channel> from <queue>\n"
11311 " Remove a specific channel from a queue.\n";
11312 return NULL;
11313 case CLI_GENERATE:
11314 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11315 }
11316
11317 if (a->argc != 6) {
11318 return CLI_SHOWUSAGE;
11319 } else if (strcmp(a->argv[4], "from")) {
11320 return CLI_SHOWUSAGE;
11321 }
11322
11323 queuename = a->argv[5];
11324 interface = a->argv[3];
11325
11327 mem = find_member_by_queuename_and_interface(queuename, interface);
11328 }
11329
11330 switch (remove_from_queue(queuename, interface)) {
11331 case RES_OKAY:
11332 if (!mem || ast_strlen_zero(mem->membername)) {
11333 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11334 } else {
11335 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11336 }
11337 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11338 res = CLI_SUCCESS;
11339 break;
11340 case RES_EXISTS:
11341 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11342 break;
11343 case RES_NOSUCHQUEUE:
11344 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11345 break;
11346 case RES_OUTOFMEMORY:
11347 ast_cli(a->fd, "Out of memory\n");
11348 break;
11349 case RES_NOT_DYNAMIC:
11350 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11351 break;
11352 }
11353
11354 if (mem) {
11355 ao2_ref(mem, -1);
11356 }
11357
11358 return res;
11359}
11360
11361
11362
11363static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11364{
11365 const char *queuename, *caller;
11366 int priority, immediate = 0;
11367 char *res = CLI_FAILURE;
11368
11369 switch (cmd) {
11370 case CLI_INIT:
11371 e->command = "queue priority caller";
11372 e->usage =
11373 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11374 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11375 return NULL;
11376 case CLI_GENERATE:
11377 return NULL;
11378 }
11379
11380 if (a->argc < 8) {
11381 return CLI_SHOWUSAGE;
11382 } else if (strcmp(a->argv[4], "on")) {
11383 return CLI_SHOWUSAGE;
11384 } else if (strcmp(a->argv[6], "to")) {
11385 return CLI_SHOWUSAGE;
11386 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11387 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11388 return CLI_SHOWUSAGE;
11389 } else if (a->argc == 9) {
11390 if (strcmp(a->argv[8], "immediate")) {
11391 return CLI_SHOWUSAGE;
11392 }
11393 immediate = 1;
11394 }
11395
11396 caller = a->argv[3];
11397 queuename = a->argv[5];
11398
11399 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11400 case RES_OKAY:
11401 res = CLI_SUCCESS;
11402 break;
11403 case RES_NOSUCHQUEUE:
11404 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11405 break;
11406 case RES_NOT_CALLER:
11407 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11408
11409 break;
11410 }
11411
11412 return res;
11413}
11414
11415
11416
11417static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
11418{
11419 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11420 switch (pos) {
11421 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11422 return NULL;
11423 case 4: /* only one possible match, "queue" */
11424 return state == 0 ? ast_strdup("queue") : NULL;
11425 case 5: /* <queue> */
11426 return complete_queue(line, word, pos, state, 0);
11427 case 6: /* "reason" */
11428 return state == 0 ? ast_strdup("reason") : NULL;
11429 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11430 return NULL;
11431 default:
11432 return NULL;
11433 }
11434}
11435
11436static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11437{
11438 const char *queuename, *interface, *reason;
11439 int paused;
11440
11441 switch (cmd) {
11442 case CLI_INIT:
11443 e->command = "queue {pause|unpause} member";
11444 e->usage =
11445 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11446 " Pause or unpause a queue member. Not specifying a particular queue\n"
11447 " will pause or unpause a member across all queues to which the member\n"
11448 " belongs.\n";
11449 return NULL;
11450 case CLI_GENERATE:
11451 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11452 }
11453
11454 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11455 return CLI_SHOWUSAGE;
11456 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11457 return CLI_SHOWUSAGE;
11458 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11459 return CLI_SHOWUSAGE;
11460 }
11461
11462
11463 interface = a->argv[3];
11464 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11465 reason = a->argc == 8 ? a->argv[7] : NULL;
11466 paused = !strcasecmp(a->argv[1], "pause");
11467
11468 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11469 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11470 if (!ast_strlen_zero(queuename)) {
11471 ast_cli(a->fd, " in queue '%s'", queuename);
11472 }
11473 if (!ast_strlen_zero(reason)) {
11474 ast_cli(a->fd, " for reason '%s'", reason);
11475 }
11476 ast_cli(a->fd, "\n");
11477 return CLI_SUCCESS;
11478 } else {
11479 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11480 if (!ast_strlen_zero(queuename)) {
11481 ast_cli(a->fd, " in queue '%s'", queuename);
11482 }
11483 if (!ast_strlen_zero(reason)) {
11484 ast_cli(a->fd, " for reason '%s'", reason);
11485 }
11486 ast_cli(a->fd, "\n");
11487 return CLI_FAILURE;
11488 }
11489}
11490
11491static char *complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
11492{
11493 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11494 switch (pos) {
11495 case 4:
11496 if (state == 0) {
11497 return ast_strdup("on");
11498 } else {
11499 return NULL;
11500 }
11501 case 6:
11502 if (state == 0) {
11503 return ast_strdup("in");
11504 } else {
11505 return NULL;
11506 }
11507 case 7:
11508 return complete_queue(line, word, pos, state, 0);
11509 default:
11510 return NULL;
11511 }
11512}
11513
11514static char *handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11515{
11516 const char *queuename = NULL, *interface;
11517 int ringinuse;
11518
11519 switch (cmd) {
11520 case CLI_INIT:
11521 e->command = "queue set ringinuse";
11522 e->usage =
11523 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11524 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11525 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11526 break;
11527 return NULL;
11528 case CLI_GENERATE:
11529 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11530 }
11531
11532 /* Sensible argument counts */
11533 if (a->argc != 6 && a->argc != 8) {
11534 return CLI_SHOWUSAGE;
11535 }
11536
11537 /* Uses proper indicational words */
11538 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11539 return CLI_SHOWUSAGE;
11540 }
11541
11542 /* Set the queue name if applicable */
11543 if (a->argc == 8) {
11544 queuename = a->argv[7];
11545 }
11546
11547 /* Interface being set */
11548 interface = a->argv[5];
11549
11550 /* Check and set the ringinuse value */
11551 if (ast_true(a->argv[3])) {
11552 ringinuse = 1;
11553 } else if (ast_false(a->argv[3])) {
11554 ringinuse = 0;
11555 } else {
11556 return CLI_SHOWUSAGE;
11557 }
11558
11559 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11560 case RESULT_SUCCESS:
11561 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11562 return CLI_SUCCESS;
11563 case RESULT_FAILURE:
11564 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11565 return CLI_FAILURE;
11566 default:
11567 return CLI_FAILURE;
11568 }
11569}
11570
11571static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11572{
11573 const char *queuename = NULL, *interface;
11574 int penalty = 0;
11575
11576 switch (cmd) {
11577 case CLI_INIT:
11578 e->command = "queue set penalty";
11579 e->usage =
11580 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11581 " Set a member's penalty in the queue specified. If no queue is specified\n"
11582 " then that interface's penalty is set in all queues to which that interface is a member\n";
11583 return NULL;
11584 case CLI_GENERATE:
11585 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11586 }
11587
11588 if (a->argc != 6 && a->argc != 8) {
11589 return CLI_SHOWUSAGE;
11590 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11591 return CLI_SHOWUSAGE;
11592 }
11593
11594 if (a->argc == 8) {
11595 queuename = a->argv[7];
11596 }
11597 interface = a->argv[5];
11598 penalty = atoi(a->argv[3]);
11599
11600 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11601 case RESULT_SUCCESS:
11602 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11603 return CLI_SUCCESS;
11604 case RESULT_FAILURE:
11605 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11606 return CLI_FAILURE;
11607 default:
11608 return CLI_FAILURE;
11609 }
11610}
11611
11612static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state)
11613{
11614 int which = 0;
11615 struct rule_list *rl_iter;
11616 int wordlen = strlen(word);
11617 char *ret = NULL;
11618 if (pos != 3) /* Wha? */ {
11619 return NULL;
11620 }
11621
11623 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11624 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11625 ret = ast_strdup(rl_iter->name);
11626 break;
11627 }
11628 }
11630
11631 return ret;
11632}
11633
11634static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11635{
11636 const char *rule;
11637 struct rule_list *rl_iter;
11638 struct penalty_rule *pr_iter;
11639 switch (cmd) {
11640 case CLI_INIT:
11641 e->command = "queue show rules";
11642 e->usage =
11643 "Usage: queue show rules [rulename]\n"
11644 " Show the list of rules associated with rulename. If no\n"
11645 " rulename is specified, list all rules defined in queuerules.conf\n";
11646 return NULL;
11647 case CLI_GENERATE:
11648 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11649 }
11650
11651 if (a->argc != 3 && a->argc != 4) {
11652 return CLI_SHOWUSAGE;
11653 }
11654
11655 rule = a->argc == 4 ? a->argv[3] : "";
11657 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11658 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11659 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11660 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11661 ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d, adjust QUEUE_MIN_PENALTY %s %d and adjust QUEUE_RAISE_PENALTY %s %d\n", pr_iter->time, pr_iter->max_relative ? "by" : "to", pr_iter->max_value, pr_iter->min_relative ? "by" : "to", pr_iter->min_value, pr_iter->raise_relative ? "by" : "to", pr_iter->raise_value);
11662 }
11663 }
11664 }
11666 return CLI_SUCCESS;
11667}
11668
11669static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11670{
11671 struct ast_flags mask = {QUEUE_RESET_STATS,};
11672 int i;
11673
11674 switch (cmd) {
11675 case CLI_INIT:
11676 e->command = "queue reset stats";
11677 e->usage =
11678 "Usage: queue reset stats [<queuenames>]\n"
11679 "\n"
11680 "Issuing this command will reset statistics for\n"
11681 "<queuenames>, or for all queues if no queue is\n"
11682 "specified.\n";
11683 return NULL;
11684 case CLI_GENERATE:
11685 if (a->pos >= 3) {
11686 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11687 } else {
11688 return NULL;
11689 }
11690 }
11691
11692 if (a->argc < 3) {
11693 return CLI_SHOWUSAGE;
11694 }
11695
11696 if (a->argc == 3) {
11697 reload_handler(1, &mask, NULL);
11698 return CLI_SUCCESS;
11699 }
11700
11701 for (i = 3; i < a->argc; ++i) {
11702 reload_handler(1, &mask, a->argv[i]);
11703 }
11704
11705 return CLI_SUCCESS;
11706}
11707
11708static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11709{
11710 struct ast_flags mask = {0,};
11711 int i;
11712
11713 switch (cmd) {
11714 case CLI_INIT:
11715 e->command = "queue reload {parameters|members|rules|all}";
11716 e->usage =
11717 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11718 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11719 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11720 "specified in order to know what information to reload. Below is an explanation\n"
11721 "of each of these qualifiers.\n"
11722 "\n"
11723 "\t'members' - reload queue members from queues.conf\n"
11724 "\t'parameters' - reload all queue options except for queue members\n"
11725 "\t'rules' - reload the queuerules.conf file\n"
11726 "\t'all' - reload queue rules, parameters, and members\n"
11727 "\n"
11728 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11729 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11730 "one queue is specified when using this command, reloading queue rules may cause\n"
11731 "other queues to be affected\n";
11732 return NULL;
11733 case CLI_GENERATE:
11734 if (a->pos >= 3) {
11735 /* find the point at which the list of queue names starts */
11736 const char *command_end = a->line + strlen("queue reload ");
11737 command_end = strchr(command_end, ' ');
11738 if (!command_end) {
11739 command_end = a->line + strlen(a->line);
11740 }
11741 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11742 } else {
11743 return NULL;
11744 }
11745 }
11746
11747 if (a->argc < 3)
11748 return CLI_SHOWUSAGE;
11749
11750 if (!strcasecmp(a->argv[2], "rules")) {
11752 } else if (!strcasecmp(a->argv[2], "members")) {
11754 } else if (!strcasecmp(a->argv[2], "parameters")) {
11756 } else if (!strcasecmp(a->argv[2], "all")) {
11758 }
11759
11760 if (a->argc == 3) {
11761 reload_handler(1, &mask, NULL);
11762 return CLI_SUCCESS;
11763 }
11764
11765 for (i = 3; i < a->argc; ++i) {
11766 reload_handler(1, &mask, a->argv[i]);
11767 }
11768
11769 return CLI_SUCCESS;
11770}
11771
11772/*!
11773 * \brief Update Queue with data of an outgoing call
11774*/
11775static int qupd_exec(struct ast_channel *chan, const char *data)
11776{
11777 int oldtalktime;
11778 char *parse;
11779 struct call_queue *q;
11780 struct member *mem;
11781 int newtalktime = 0;
11782
11784 AST_APP_ARG(queuename);
11785 AST_APP_ARG(uniqueid);
11786 AST_APP_ARG(agent);
11788 AST_APP_ARG(talktime);
11789 AST_APP_ARG(params););
11790
11791 if (ast_strlen_zero(data)) {
11792 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11793 return -1;
11794 }
11795
11796 parse = ast_strdupa(data);
11797
11799
11800 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11801 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11802 return -1;
11803 }
11804
11805 if (!ast_strlen_zero(args.talktime)) {
11806 newtalktime = atoi(args.talktime);
11807 }
11808
11809 q = find_load_queue_rt_friendly(args.queuename);
11810 if (!q) {
11811 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11812 return 0;
11813 }
11814
11815 ao2_lock(q);
11816 if (q->members) {
11817 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11818 while ((mem = ao2_iterator_next(&mem_iter))) {
11819 if (!strcasecmp(mem->membername, args.agent)) {
11820 if (!strcasecmp(args.status, "ANSWER")) {
11821 oldtalktime = q->talktime;
11822 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11823 time(&mem->lastcall);
11824 mem->calls++;
11825 mem->lastqueue = q;
11826 q->callscompleted++;
11827
11828 if (newtalktime <= q->servicelevel) {
11829 q->callscompletedinsl++;
11830 }
11831 } else {
11832
11833 time(&mem->lastcall);
11834 q->callsabandoned++;
11835 }
11836
11837 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11838 }
11839
11840 ao2_ref(mem, -1);
11841 }
11842
11843 ao2_iterator_destroy(&mem_iter);
11844 }
11845
11846 ao2_unlock(q);
11847 queue_t_unref(q, "Done with temporary pointer");
11848
11849 return 0;
11850}
11851
11852static struct ast_cli_entry cli_queue[] = {
11853 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
11854 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
11855 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
11856 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
11857 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
11858 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
11859 AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
11860 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
11861 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
11862 AST_CLI_DEFINE(handle_queue_change_priority_caller, "Change priority caller on queue"),
11863};
11864
11867
11868static int unload_module(void)
11869{
11872
11874
11875 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11876 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11877 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11878
11879 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11880 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11881 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11882 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11883 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11884 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11885
11886 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11887 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11888 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11889 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11890 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11891
11893 ast_manager_unregister("QueueStatus");
11894 ast_manager_unregister("QueueRule");
11895 ast_manager_unregister("QueueSummary");
11896 ast_manager_unregister("QueueAdd");
11897 ast_manager_unregister("QueueRemove");
11898 ast_manager_unregister("QueuePause");
11899 ast_manager_unregister("QueueLog");
11900 ast_manager_unregister("QueueUpdate");
11901 ast_manager_unregister("QueuePenalty");
11902 ast_manager_unregister("QueueReload");
11903 ast_manager_unregister("QueueReset");
11904 ast_manager_unregister("QueueMemberRingInUse");
11905 ast_manager_unregister("QueueChangePriorityCaller");
11906 ast_manager_unregister("QueueWithdrawCaller");
11921
11923
11924 ast_unload_realtime("queue_members");
11927
11928 queues = NULL;
11929 return 0;
11930}
11931
11932/*!
11933 * \brief Load the module
11934 *
11935 * Module loading including tests for configuration or dependencies.
11936 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
11937 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
11938 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
11939 * configuration file or other non-critical problem return
11940 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
11941 */
11942static int load_module(void)
11943{
11944 int err = 0;
11945 struct ast_flags mask = {AST_FLAGS_ALL, };
11946 struct ast_config *member_config;
11947 struct stasis_topic *queue_topic;
11949
11952 if (!queues) {
11954 }
11955
11958 if (!pending_members) {
11959 unload_module();
11961 }
11962
11963 use_weight = 0;
11964
11965 if (reload_handler(0, &mask, NULL)) {
11966 unload_module();
11968 }
11969
11970 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
11971
11972 /*
11973 * This section is used to determine which name for 'ringinuse' to use in realtime members
11974 * Necessary for supporting older setups.
11975 *
11976 * It also checks if 'reason_paused' exists in the realtime backend
11977 */
11978 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11979 if (!member_config) {
11980 realtime_ringinuse_field = "ringinuse";
11981 } else {
11982 const char *config_val;
11983
11984 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11985 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11986 realtime_ringinuse_field = "ringinuse";
11987 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11988 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11989 realtime_ringinuse_field = "ignorebusy";
11990 } else {
11991 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
11992 realtime_ringinuse_field = "ringinuse";
11993 }
11994
11995 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
11997 }
11998 }
11999 ast_config_destroy(member_config);
12000
12003 }
12004
12013 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
12014 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
12021 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
12022 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
12023 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
12024 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
12033
12034 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
12036 if (!device_state_sub) {
12037 err = -1;
12038 }
12041
12043 queue_topic = ast_queue_topic_all();
12044 if (!manager_topic || !queue_topic) {
12045 unload_module();
12047 }
12049 if (!topic_forwarder) {
12050 unload_module();
12052 }
12053
12056 unload_module();
12058 }
12060 if (!agent_router) {
12061 unload_module();
12063 }
12067 NULL);
12071 NULL);
12072
12073 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
12074 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
12075 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
12076
12077 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
12078 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
12079 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
12080 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
12081 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
12082 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
12083
12084 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
12085 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
12086 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
12087 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
12088 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
12089
12090 if (err) {
12091 unload_module();
12093 }
12095}
12096
12097static int reload(void)
12098{
12099 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
12100 ast_unload_realtime("queue_members");
12101 reload_handler(1, &mask, NULL);
12102 return 0;
12103}
12104
12105/*!
12106 * \brief Find a member by looking up queuename and interface.
12107 * \return member or NULL if member not found.
12108 */
12109static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface)
12110{
12111 struct member *mem = NULL;
12112 struct call_queue *q;
12113
12114 if ((q = find_load_queue_rt_friendly(queuename))) {
12115 ao2_lock(q);
12116 mem = ao2_find(q->members, interface, OBJ_KEY);
12117 ao2_unlock(q);
12118 queue_t_unref(q, "Expiring temporary reference.");
12119 }
12120 return mem;
12121}
12122
12124 .support_level = AST_MODULE_SUPPORT_CORE,
12125 .load = load_module,
12126 .unload = unload_module,
12127 .reload = reload,
12128 .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
Generic Advice of Charge encode and decode routines.
void * ast_aoc_destroy_encoded(struct ast_aoc_encoded *encoded)
free an ast_aoc_encoded object
Definition: aoc.c:322
enum ast_aoc_type ast_aoc_get_msg_type(struct ast_aoc_decoded *decoded)
get the message type, AOC-D, AOC-E, or AOC Request
Definition: aoc.c:901
struct ast_aoc_decoded * ast_aoc_decode(struct ast_aoc_encoded *encoded, size_t size, struct ast_channel *chan)
decodes an encoded aoc payload.
Definition: aoc.c:458
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:316
struct ast_aoc_encoded * ast_aoc_encode(struct ast_aoc_decoded *decoded, size_t *out_size, struct ast_channel *chan)
encodes a decoded aoc structure so it can be passed on the wire
Definition: aoc.c:659
@ AST_AOC_S
Definition: aoc.h:64
char digit
jack_status_t status
Definition: app_jack.c:149
const char * str
Definition: app_jack.c:150
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9605
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6527
static struct member * create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
allocate space for new queue member and set fields based on parameters passed
Definition: app_queue.c:3001
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3713
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4727
static void load_realtime_queues(const char *queuename)
Definition: app_queue.c:4107
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7609
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5896
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:5230
static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Get number either busy / free / ready or total members of a specific queue.
Definition: app_queue.c:9207
static char * queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10530
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:2122
static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config)
Find rt member record to update otherwise create one.
Definition: app_queue.c:3729
static int context_included(const char *parent, const char *child)
Returns if one context includes another context.
Definition: app_queue.c:2913
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2194
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10977
static struct ast_manager_event_blob * queue_member_ringinuse_to_ami(struct stasis_message *message)
Definition: app_queue.c:2330
static struct ast_manager_event_blob * queue_member_penalty_to_ami(struct stasis_message *message)
Definition: app_queue.c:2325
member_properties
Definition: app_queue.c:1895
@ MEMBER_RINGINUSE
Definition: app_queue.c:1897
@ MEMBER_PENALTY
Definition: app_queue.c:1896
#define RES_NOT_CALLER
Definition: app_queue.c:1693
STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type,.to_ami=queue_caller_join_to_ami,)
static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6924
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1919
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2672
static void queue_reset_global_params(void)
Definition: app_queue.c:9717
static int log_caller_id_name
queues.conf [general] option
Definition: app_queue.c:1743
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11612
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7636
#define QUEUE_UNPAUSED_DEVSTATE
Definition: app_queue.c:3688
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9610
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9621
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:4294
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1713
static const struct @50 queue_results[]
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1722
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9904
static char * app_pqm
Definition: app_queue.c:1701
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9626
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2246
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:8104
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1749
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6674
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7691
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10787
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1679
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3440
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8510
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:2041
static struct ast_manager_event_blob * queue_member_pause_to_ami(struct stasis_message *message)
Definition: app_queue.c:2320
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4523
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1686
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:10179
static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Check if a given queue exists.
Definition: app_queue.c:9165
static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty.
Definition: app_queue.c:9532
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11417
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4778
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:8156
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9772
static struct ast_manager_event_blob * queue_agent_ringnoanswer_to_ami(struct stasis_message *message)
Definition: app_queue.c:2415
static void send_agent_complete(const char *queuename, struct ast_channel_snapshot *caller, struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart, time_t callstart, enum agent_complete_reason rsn)
Send out AMI message with member call completion status information.
Definition: app_queue.c:6280
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:10092
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:5169
static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
Reload information pertaining to a particular queue.
Definition: app_queue.c:9935
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:7056
static struct ast_manager_event_blob * queue_member_removed_to_ami(struct stasis_message *message)
Definition: app_queue.c:2315
#define DEFAULT_RETRY
Definition: app_queue.c:1676
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition: app_queue.c:8403
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3187
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6619
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4500
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1692
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4693
static char * handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11436
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:8117
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6311
queue_timeout_priority
Definition: app_queue.c:1781
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1783
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1782
static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue.
Definition: app_queue.c:9484
static char * app_ql
Definition: app_queue.c:1705
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9730
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:8256
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8439
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:4323
aqm_flags
Definition: app_queue.c:1613
@ AQMFLAG_REASON
Definition: app_queue.c:1615
@ AQMFLAG_PAUSED
Definition: app_queue.c:1614
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2742
#define QUEUE_PAUSED_DEVSTATE
Definition: app_queue.c:3687
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1918
static char * handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11571
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6865
static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
The waiting areas for callers who are not actively calling members.
Definition: app_queue.c:6035
static void print_queue(struct mansession *s, int fd, struct call_queue *q)
Print a single queue to AMI or the CLI.
Definition: app_queue.c:10206
char * text
Definition: app_queue.c:1768
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2650
static char * app_rqm
Definition: app_queue.c:1699
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:8638
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:10546
static const struct strategy strategies[]
static int request_withdraw_caller_from_queue(const char *queuename, const char *caller, const char *withdraw_info)
Request to withdraw a caller from a queue.
Definition: app_queue.c:7873
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:8008
static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
Change priority caller into a queue.
Definition: app_queue.c:7797
static struct ao2_container * queues
Definition: app_queue.c:2032
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1734
#define AST_MAX_WATCHERS
Definition: app_queue.c:5342
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3328
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9638
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:6123
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:7025
#define RES_OUTOFMEMORY
Definition: app_queue.c:1690
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:3056
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:3072
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:2191
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1684
static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
Hang up a list of outgoing calls.
Definition: app_queue.c:4620
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:6410
static struct ast_manager_event_blob * queue_member_added_to_ami(struct stasis_message *message)
Definition: app_queue.c:2310
static struct ast_manager_event_blob * queue_agent_dump_to_ami(struct stasis_message *message)
Definition: app_queue.c:2410
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2864
#define queues_t_link(c, q, tag)
Definition: app_queue.c:2190
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2942
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10945
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8225
static int realtime_rules
queuerules.conf [general] option
Definition: app_queue.c:1728
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6693
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8367
static char * complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10485
static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate, int raise_respect_min)
Check if members are available.
Definition: app_queue.c:2553
static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
Calculate the metric of each member in the outgoing callattempts.
Definition: app_queue.c:6195
static char * handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11669
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11775
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10522
static char * handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11514
static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
create interface var with all queue details.
Definition: app_queue.c:9121
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9658
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10992
static char * handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11363
static char * handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11634
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:11023
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11491
@ OPT_CALLER_AUTOMON
Definition: app_queue.c:1572
@ OPT_CALLEE_PARK
Definition: app_queue.c:1562
@ OPT_PREDIAL_CALLER
Definition: app_queue.c:1574
@ OPT_GO_ON
Definition: app_queue.c:1555
@ OPT_IGNORE_CONNECTEDLINE
Definition: app_queue.c:1561
@ OPT_CALLEE_AUTOMON
Definition: app_queue.c:1571
@ OPT_CALLEE_TRANSFER
Definition: app_queue.c:1567
@ OPT_CALLEE_GO_ON
Definition: app_queue.c:1557
@ OPT_MARK_AS_ANSWERED
Definition: app_queue.c:1554
@ OPT_IGNORE_CALL_FW
Definition: app_queue.c:1560
@ OPT_CALLER_PARK
Definition: app_queue.c:1563
@ OPT_NO_RETRY
Definition: app_queue.c:1564
@ OPT_DATA_QUALITY
Definition: app_queue.c:1556
@ OPT_CALLER_HANGUP
Definition: app_queue.c:1559
@ OPT_MUSICONHOLD_CLASS
Definition: app_queue.c:1575
@ OPT_CALLEE_AUTOMIXMON
Definition: app_queue.c:1569
@ OPT_CALLEE_HANGUP
Definition: app_queue.c:1558
@ OPT_CALLER_AUTOMIXMON
Definition: app_queue.c:1570
@ OPT_RINGING
Definition: app_queue.c:1565
@ OPT_CALLER_TRANSFER
Definition: app_queue.c:1568
@ OPT_PREDIAL_CALLEE
Definition: app_queue.c:1573
@ OPT_RING_WHEN_RINGING
Definition: app_queue.c:1566
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4808
static const char * int2strat(int strategy)
Definition: app_queue.c:2053
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1691
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3847
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7912
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4598
static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Linear queue.
Definition: app_queue.c:5145
#define queue_t_unref(q, tag)
Definition: app_queue.c:2189
static struct callattempt * wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
Wait for a member to answer the call.
Definition: app_queue.c:5356
static void update_status(struct call_queue *q, struct member *m, const int status)
set a member's status based on device state of that member's state_interface.
Definition: app_queue.c:2711
static char * app_qupd
Definition: app_queue.c:1707
#define queue_unref(q)
Definition: app_queue.c:2187
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1901
static const struct ast_app_option queue_exec_options[128]
Definition: app_queue.c:1610
static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2471
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1725
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:11057
#define queue_t_ref(q, tag)
Definition: app_queue.c:2188
AO2_STRING_FIELD_SORT_FN(call_queue, name)
static char * __queues_show(struct mansession *s, int fd, int argc, const char *const *argv)
Show queue(s) status and statistics.
Definition: app_queue.c:10314
static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
Configure a queue parameter.
Definition: app_queue.c:3483
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1920
static char * app_upqm
Definition: app_queue.c:1703
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:10149
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9631
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7936
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:2109
queue_result
Definition: app_queue.c:1754
@ QUEUE_FULL
Definition: app_queue.c:1761
@ QUEUE_UNKNOWN
Definition: app_queue.c:1755
@ QUEUE_WITHDRAW
Definition: app_queue.c:1763
@ QUEUE_CONTINUE
Definition: app_queue.c:1762
@ QUEUE_LEAVEEMPTY
Definition: app_queue.c:1758
@ QUEUE_LEAVEUNAVAIL
Definition: app_queue.c:1760
@ QUEUE_JOINUNAVAIL
Definition: app_queue.c:1759
@ QUEUE_JOINEMPTY
Definition: app_queue.c:1757
@ QUEUE_TIMEOUT
Definition: app_queue.c:1756
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11130
static char * app
Definition: app_queue.c:1695
static int log_unpause_on_reason_change
queues.conf [general] option
Definition: app_queue.c:1746
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:8133
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:2102
static struct call_queue * find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
Reload a single queue via realtime.
Definition: app_queue.c:3902
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1710
#define queue_ref(q)
Definition: app_queue.c:2186
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1737
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5945
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:5326
static struct ast_manager_event_blob * queue_agent_called_to_ami(struct stasis_message *message)
Definition: app_queue.c:2395
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8681
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:4210
static char * handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11300
static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer.
Definition: app_queue.c:5261
static const struct ast_app_option aqm_opts[128]
Definition: app_queue.c:1626
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2991
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:3085
static struct ao2_container * pending_members
Definition: app_queue.c:2649
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2354
static struct member * find_member_by_queuename_and_interface(const char *queuename, const char *interface)
Find a member by looking up queuename and interface.
Definition: app_queue.c:12109
static int force_longest_waiting_caller
queues.conf [general] option
Definition: app_queue.c:1740
#define RES_OKAY
Definition: app_queue.c:1688
static struct ast_manager_event_blob * queue_member_status_to_ami(struct stasis_message *message)
Definition: app_queue.c:2305
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9913
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1677
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6427
static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue.
Definition: app_queue.c:9447
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2652
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1719
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10899
static void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
Insert the 'new' entry after the 'prev' entry of queue 'q'.
Definition: app_queue.c:2220
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1902
static struct ast_manager_event_blob * queue_caller_join_to_ami(struct stasis_message *message)
Definition: app_queue.c:2265
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2155
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3219
static char * handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11708
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4660
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8604
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10852
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:4135
static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
Search for best metric and add to Round Robbin queue.
Definition: app_queue.c:5121
static struct stasis_message_router * agent_router
Definition: app_queue.c:11865
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2173
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:9184
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10058
queue_reload_mask
Definition: app_queue.c:1645
@ QUEUE_RELOAD_RULES
Definition: app_queue.c:1648
@ QUEUE_RELOAD_MEMBER
Definition: app_queue.c:1647
@ QUEUE_RESET_STATS
Definition: app_queue.c:1649
@ QUEUE_RELOAD_PARAMETERS
Definition: app_queue.c:1646
static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
set a member's status based on device state of that member's interface
Definition: app_queue.c:2777
static int load_module(void)
Load the module.
Definition: app_queue.c:11942
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3697
#define RECHECK
Definition: app_queue.c:1678
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4904
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2700
static void end_bridge_callback(void *data)
Definition: app_queue.c:6985
enum queue_result id
Definition: app_queue.c:1767
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1731
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10582
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3878
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:5036
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2986
static int unload_module(void)
Definition: app_queue.c:11868
static int reload(void)
Definition: app_queue.c:12097
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3689
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4608
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10664
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6744
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:4358
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1752
static struct queue_stasis_data * queue_stasis_data_alloc(struct queue_ent *qe, struct ast_channel *peer, struct member *mem, time_t holdstart, time_t starttime, int callcompletedinsl)
Definition: app_queue.c:6442
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:4151
static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty.
Definition: app_queue.c:9564
static void queue_publish_multi_channel_snapshot_blob(struct stasis_topic *topic, struct ast_channel_snapshot *caller_snapshot, struct ast_channel_snapshot *agent_snapshot, struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2436
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface, const char *reason_paused, int wrapuptime)
Add member to queue.
Definition: app_queue.c:7744
static struct ast_manager_event_blob * queue_agent_connect_to_ami(struct stasis_message *message)
Definition: app_queue.c:2400
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6978
empty_conditions
Definition: app_queue.c:1884
@ QUEUE_EMPTY_INVALID
Definition: app_queue.c:1890
@ QUEUE_EMPTY_UNKNOWN
Definition: app_queue.c:1891
@ QUEUE_EMPTY_PENALTY
Definition: app_queue.c:1885
@ QUEUE_EMPTY_RINGING
Definition: app_queue.c:1888
@ QUEUE_EMPTY_INUSE
Definition: app_queue.c:1887
@ QUEUE_EMPTY_UNAVAILABLE
Definition: app_queue.c:1889
@ QUEUE_EMPTY_WRAPUP
Definition: app_queue.c:1892
@ QUEUE_EMPTY_PAUSED
Definition: app_queue.c:1886
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2526
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6899
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1716
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1917
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:7596
static char * app_aqm
Definition: app_queue.c:1697
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition: app_queue.c:3863
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:10068
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6808
static void do_print(struct mansession *s, int fd, const char *str)
direct output to manager or cli with proper terminator
Definition: app_queue.c:10196
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11252
static char * handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11167
#define RES_EXISTS
Definition: app_queue.c:1689
static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse.
Definition: app_queue.c:9309
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9644
static int member_status_available(int status)
Definition: app_queue.c:4794
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2136
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11852
@ QUEUE_STRATEGY_RINGALL
Definition: app_queue.c:1629
@ QUEUE_STRATEGY_RRMEMORY
Definition: app_queue.c:1633
@ QUEUE_STRATEGY_LINEAR
Definition: app_queue.c:1634
@ QUEUE_STRATEGY_LEASTRECENT
Definition: app_queue.c:1630
@ QUEUE_STRATEGY_RANDOM
Definition: app_queue.c:1632
@ QUEUE_STRATEGY_FEWESTCALLS
Definition: app_queue.c:1631
@ QUEUE_STRATEGY_RRORDERED
Definition: app_queue.c:1636
@ QUEUE_STRATEGY_WRANDOM
Definition: app_queue.c:1635
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:4046
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9616
static struct ast_manager_event_blob * queue_caller_abandon_to_ami(struct stasis_message *message)
Definition: app_queue.c:2275
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11866
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9600
aqm_args
Definition: app_queue.c:1618
@ AQM_OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1620
@ AQM_OPT_ARG_PAUSE_REASON
Definition: app_queue.c:1619
static int strat2int(const char *strategy)
Definition: app_queue.c:2066
static int queue_function_queuegetchannel(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue.
Definition: app_queue.c:9368
static struct ast_manager_event_blob * queue_agent_complete_to_ami(struct stasis_message *message)
Definition: app_queue.c:2405
static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
Definition: app_queue.c:7008
static int word_in_list(const char *list, const char *word)
Check if a given word is in a space-delimited list.
Definition: app_queue.c:10426
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6481
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:5061
@ OPT_ARG_CALLEE_GO_ON
Definition: app_queue.c:1579
@ OPT_ARG_PREDIAL_CALLEE
Definition: app_queue.c:1580
@ OPT_ARG_MUSICONHOLD_CLASS
Definition: app_queue.c:1582
@ OPT_ARG_PREDIAL_CALLER
Definition: app_queue.c:1581
@ OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1584
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6560
static const struct autopause autopausesmodes[]
agent_complete_reason
Definition: app_queue.c:6273
@ AGENT
Definition: app_queue.c:6275
@ CALLER
Definition: app_queue.c:6274
@ TRANSFER
Definition: app_queue.c:6276
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2290
@ QUEUE_AUTOPAUSE_ON
Definition: app_queue.c:1641
@ QUEUE_AUTOPAUSE_OFF
Definition: app_queue.c:1640
@ QUEUE_AUTOPAUSE_ALL
Definition: app_queue.c:1642
static int autopause2int(const char *autopause)
Definition: app_queue.c:2079
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11083
static int compress_char(const char c)
Definition: app_queue.c:3046
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2502
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10924
static struct ast_manager_event_blob * queue_caller_leave_to_ami(struct stasis_message *message)
Definition: app_queue.c:2270
static int try_calling(struct queue_ent *qe, struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *gosub, int ringing)
Definition: app_queue.c:7129
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:8068
unsigned int stop
Definition: app_sla.c:342
ast_mutex_t lock
Definition: app_sla.c:337
#define var
Definition: ast_expr2f.c:605
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1570
Persistent data storage (akin to *doze registry)
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: db.c:335
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
Definition: db.c:431
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: db.c:472
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: db.c:635
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: db.c:695
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define PATH_MAX
Definition: asterisk.h:40
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ CMP_STOP
Definition: astobj2.h:1028
#define OBJ_KEY
Definition: astobj2.h:1151
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1909
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1734
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
@ AO2_ITERATOR_UNLINK
Definition: astobj2.h:1863
@ AO2_ITERATOR_DONTLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1852
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:407
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
@ OBJ_UNLINK
Definition: astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
@ AST_BRIDGE_TRANSFER_SUCCESS
Definition: bridge.h:1104
After Bridge Execution API.
void ast_bridge_set_after_go_on(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *parseable_goto)
Set channel to go on in the dialplan after the bridge.
Definition: bridge_after.c:622
static void ringing(struct ast_channel *chan)
Helper method to send a ringing indication to a channel in a bridge.
Basic bridge subclass API.
#define AST_TRANSFERER_ROLE_NAME
Definition: bridge_basic.h:36
@ AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_TO
@ AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
int ast_channel_has_role(struct ast_channel *channel, const char *role_name)
Check if a role exists on a channel.
Definition: bridge_roles.c:394
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
#define AST_PRES_ALLOWED
Definition: callerid.h:432
@ AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER
Definition: callerid.h:554
#define AST_PRES_RESTRICTION
Definition: callerid.h:431
Internal Asterisk hangup causes.
#define AST_CAUSE_ANSWERED_ELSEWHERE
Definition: causes.h:114
enum cc_state state
Definition: ccss.c:399
static int priority
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13590
static const char type[]
Definition: chan_ooh323.c:109
static int call(void *data)
Definition: chan_pjsip.c:2403
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
Definition: channel.c:3145
const char * ast_channel_name(const struct ast_channel *chan)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
void ast_channel_appl_set(struct ast_channel *chan, const char *value)
void ast_party_redirecting_init(struct ast_party_redirecting *init)
Initialize the given redirecting structure.
Definition: channel.c:2090
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6429
int ast_channel_connected_line_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *connected_info, int frame)
Run a connected line interception subroutine and update a channel's connected line information.
Definition: channel.c:10352
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1612
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2511
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1525
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1789
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2040
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
void ast_channel_set_caller_event(struct ast_channel *chan, const struct ast_party_caller *caller, const struct ast_set_party_caller *update)
Set the caller id information in the Asterisk channel and generate an AMI event if the caller id name...
Definition: channel.c:7354
struct ast_channel * ast_waitfor_n(struct ast_channel **chan, int n, int *ms)
Waits for input on a group of channels Wait for input on an array of channels for a given # of millis...
Definition: channel.c:3127
#define ast_channel_lock(chan)
Definition: channel.h:2972
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6688
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
void ast_party_connected_line_copy(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src)
Copy the source connected line information to the destination connected line.
Definition: channel.c:1999
void ast_party_connected_line_set(struct ast_party_connected_line *dest, const struct ast_party_connected_line *src, const struct ast_set_party_connected_line *update)
Set the connected line information based on another connected line source.
Definition: channel.c:2022
int ast_channel_priority(const struct ast_channel *chan)
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2979
struct ast_party_connected_line * ast_channel_connected(struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
Definition: channel.c:2338
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6402
const char * ast_channel_context(const struct ast_channel *chan)
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4223
void ast_channel_update_connected_line(struct ast_channel *chan, const struct ast_party_connected_line *connected, const struct ast_set_party_connected_line *update)
Indicate that the connected line information has changed.
Definition: channel.c:9107
ast_channel_adsicpe
Definition: channel.h:888
void ast_party_caller_set_init(struct ast_party_caller *init, const struct ast_party_caller *guide)
Initialize the given caller structure using the given guide for a set update operation.
Definition: channel.c:1967
void ast_set_callerid(struct ast_channel *chan, const char *cid_num, const char *cid_name, const char *cid_ani)
Set caller ID number, name and ANI and generate AMI event.
Definition: channel.c:7316
int ast_channel_redirecting_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const void *redirecting_info, int is_frame)
Run a redirecting interception subroutine and update a channel's redirecting information.
Definition: channel.c:10397
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
Definition: channel.c:6744
@ AST_FEATURE_AUTOMIXMON
Definition: channel.h:1089
@ AST_FEATURE_REDIRECT
Definition: channel.h:1084
@ AST_FEATURE_PARKCALL
Definition: channel.h:1088
@ AST_FEATURE_AUTOMON
Definition: channel.h:1087
@ AST_FEATURE_DISCONNECT
Definition: channel.h:1085
struct ast_channel * ast_channel_get_by_name(const char *search)
Find a channel by name or uniqueid.
Definition: channel.c:1398
int ast_connected_line_parse_data(const unsigned char *data, size_t datalen, struct ast_party_connected_line *connected)
Parse connected line indication frame data.
Definition: channel.c:8799
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6591
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_channel_hangupcause(const struct ast_channel *chan)
struct ast_party_dialed * ast_channel_dialed(struct ast_channel *chan)
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
Indicates condition of channel, with payload.
Definition: channel.c:4621
void ast_channel_update_redirecting(struct ast_channel *chan, const struct ast_party_redirecting *redirecting, const struct ast_set_party_redirecting *update)
Indicate that the redirecting id has changed.
Definition: channel.c:10298
#define AST_CHANNEL_NAME
Definition: channel.h:173
struct timeval * ast_channel_whentohangup(struct ast_channel *chan)
void ast_party_number_free(struct ast_party_number *doomed)
Destroy the party number contents.
Definition: channel.c:1659
#define AST_MAX_CONTEXT
Definition: channel.h:135
void ast_party_connected_line_init(struct ast_party_connected_line *init)
Initialize the given connected line structure.
Definition: channel.c:1990
int ast_channel_sendurl(struct ast_channel *channel, const char *url)
Sends a URL on a given link Send URL on link.
Definition: channel.c:6603
const char * ast_channel_language(const struct ast_channel *chan)
void ast_party_redirecting_free(struct ast_party_redirecting *doomed)
Destroy the redirecting information contents.
Definition: channel.c:2147
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
Definition: channel.c:8307
void ast_channel_req_accountcodes_precious(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
Definition: channel.c:6407
const char * ast_channel_call_forward(const struct ast_channel *chan)
int ast_pre_call(struct ast_channel *chan, const char *sub_args)
Execute a Gosub call on the channel before a call is placed.
Definition: channel.c:6412
const struct ast_channel_tech * ast_channel_tech(const struct ast_channel *chan)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
Definition: channel.c:7404
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_party_connected_line_set_init(struct ast_party_connected_line *init, const struct ast_party_connected_line *guide)
Initialize the given connected line structure using the given guide for a set update operation.
Definition: channel.c:2013
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
void ast_autoservice_chan_hangup_peer(struct ast_channel *chan, struct ast_channel *peer)
Put chan into autoservice while hanging up peer.
Definition: autoservice.c:349
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
Definition: channel.c:4243
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1542
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
Definition: channel.c:6322
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2973
#define AST_MAX_EXTENSION
Definition: channel.h:134
void ast_party_redirecting_copy(struct ast_party_redirecting *dest, const struct ast_party_redirecting *src)
Copy the source redirecting information to the destination redirecting.
Definition: channel.c:2103
#define MAX_MUSICCLASS
Definition: channel.h:175
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
size_t current
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define RESULT_SUCCESS
Definition: cli.h:40
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define CLI_FAILURE
Definition: cli.h:46
#define RESULT_FAILURE
Definition: cli.h:42
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
#define SENTINEL
Definition: compiler.h:87
Local proxy channel special access.
struct stasis_message_type * ast_local_optimization_end_type(void)
Message type for when a local channel optimization completes.
struct stasis_message_type * ast_local_optimization_begin_type(void)
Message type for when a local channel optimization begins.
Device state management.
struct stasis_message_type * ast_device_state_message_type(void)
Get the Stasis message type for device state messages.
@ AST_DEVSTATE_CACHABLE
Definition: devicestate.h:70
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:513
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:240
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:671
ast_device_state
Device States.
Definition: devicestate.h:52
@ AST_DEVICE_RINGINUSE
Definition: devicestate.h:60
@ AST_DEVICE_INUSE
Definition: devicestate.h:55
@ AST_DEVICE_UNKNOWN
Definition: devicestate.h:53
@ AST_DEVICE_ONHOLD
Definition: devicestate.h:61
@ AST_DEVICE_RINGING
Definition: devicestate.h:59
@ AST_DEVICE_INVALID
Definition: devicestate.h:57
@ AST_DEVICE_BUSY
Definition: devicestate.h:56
@ AST_DEVICE_NOT_INUSE
Definition: devicestate.h:54
@ AST_DEVICE_UNAVAILABLE
Definition: devicestate.h:58
Dialing API.
const char * ast_hangup_cause_to_dial_status(int hangup_cause)
Convert a hangup cause to a publishable dial status.
Definition: dial.c:749
char connected
Definition: eagi_proxy.c:82
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define abs(x)
Definition: f2c.h:195
long int flag
Definition: f2c.h:83
Call Parking and Pickup API Includes code and algorithms from the Zapata library.
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags)
Bridge a call, and add additional flags to the bridge.
Definition: features.c:604
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_stopstream(struct ast_channel *c)
Stops a stream.
Definition: file.c:223
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1312
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1148
#define AST_DIGIT_ANY
Definition: file.h:48
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
Definition: file.c:1874
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:2024
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1982
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:2060
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:450
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2014
struct ast_str * ast_manager_str_from_json_object(struct ast_json *blob, key_exclusion_cb exclusion_cb)
Convert a JSON object into an AMI compatible string.
Definition: manager.c:551
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1643
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2068
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1903
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:182
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7698
struct stasis_message_type * ast_channel_masquerade_type(void)
Message type for when a channel is being masqueraded.
struct stasis_topic * ast_channel_topic_all(void)
A topic which publishes the events for all channels.
struct ast_multi_channel_blob * ast_multi_channel_blob_create(struct ast_json *blob)
Create a ast_multi_channel_blob suitable for a stasis_message.
struct ast_channel_snapshot * ast_multi_channel_blob_get_channel(struct ast_multi_channel_blob *obj, const char *role)
Retrieve a channel snapshot associated with a specific role from a ast_multi_channel_blob.
void ast_channel_publish_cached_blob(struct ast_channel *chan, struct stasis_message_type *type, struct ast_json *blob)
Publish a channel blob message using the latest snapshot from the cache.
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object,...
struct stasis_message_type * ast_channel_agent_logoff_type(void)
Message type for agent logoff on a channel.
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate.
void ast_channel_publish_dial(struct ast_channel *caller, struct ast_channel *peer, const char *dialstring, const char *dialstatus)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
void ast_multi_channel_blob_add_channel(struct ast_multi_channel_blob *obj, const char *role, struct ast_channel_snapshot *snapshot)
Add a ast_channel_snapshot to a ast_multi_channel_blob object.
struct stasis_message_type * ast_channel_hangup_request_type(void)
Message type for when a hangup is requested on a channel.
struct stasis_message_type * ast_channel_agent_login_type(void)
Message type for agent login on a channel.
struct ast_json * ast_multi_channel_blob_get_json(struct ast_multi_channel_blob *obj)
Retrieve the JSON blob from a ast_multi_channel_blob. Returned ast_json is still owned by obj.
void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_channel *peer, struct ast_channel *forwarded, const char *dialstring, const char *dialstatus, const char *forward)
Publish in the ast_channel_topic or ast_channel_topic_all topics a stasis message for the channels in...
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define END_OPTIONS
struct stasis_topic * ast_queue_topic(const char *queuename)
Get the Stasis Message Bus API topic for queue messages for a particular queue name.
Definition: main/app.c:3349
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define BEGIN_OPTIONS
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
struct stasis_topic * ast_queue_topic_all(void)
Get the Stasis Message Bus API topic for queue messages.
Definition: main/app.c:3344
int ast_app_exec_sub(struct ast_channel *autoservice_chan, struct ast_channel *sub_chan, const char *sub_args, int ignore_hangup)
Run a subroutine on a channel, placing an optional second channel into autoservice.
Definition: main/app.c:297
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
Definition: main/app.c:3066
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3324
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3272
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3781
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3854
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3808
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3762
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1287
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:869
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3891
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3738
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1260
@ CONFIG_FLAG_FILEUNCHANGED
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1213
#define AST_FRAME_DTMF
#define AST_OPTION_TONE_VERIFY
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_OFFHOOK
@ AST_CONTROL_BUSY
@ AST_CONTROL_REDIRECTING
@ AST_CONTROL_CONGESTION
@ AST_CONTROL_ANSWER
@ AST_CONTROL_RINGING
@ AST_CONTROL_HANGUP
@ AST_CONTROL_CONNECTED_LINE
@ AST_CONTROL_AOC
@ AST_CONTROL_PVT_CAUSE_CODE
#define ast_debug(level,...)
Log a DEBUG message.
void ast_queue_log(const char *queuename, const char *callid, const char *agent, const char *event, const char *fmt,...)
Definition: logger.c:957
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct ast_json_payload * ast_json_payload_create(struct ast_json *json)
Create an ao2 object to pass json blobs as data payloads for stasis.
Definition: json.c:756
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
Definition: json.c:283
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
Definition: json.c:407
intmax_t ast_json_integer_get(const struct ast_json *integer)
Get the value from a JSON integer.
Definition: json.c:332
AST_JSON_INT_T ast_json_int_t
Primarily used to cast when packing to an "I" type.
Definition: json.h:87
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
Definition: linkedlists.h:291
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
Definition: linkedlists.h:599
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:439
Asterisk locking-related definitions:
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:611
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:764
int errno
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct ast_str * ast_manager_build_channel_state_string(const struct ast_channel_snapshot *snapshot)
Generate the AMI message body from a channel snapshot.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
struct ast_manager_event_blob * ast_manager_event_blob_create(int event_flags, const char *manager_event, const char *extra_fields_fmt,...)
Construct a ast_manager_event_blob.
Definition: manager.c:10144
#define EVENT_FLAG_AGENT
Definition: manager.h:80
struct ast_str * ast_manager_build_channel_state_string_prefix(const struct ast_channel_snapshot *snapshot, const char *prefix)
Generate the AMI message body from a channel snapshot.
int ast_max_forwards_decrement(struct ast_channel *chan)
Decrement the max forwards count for a particular channel.
Definition: max_forwards.c:135
int ast_max_forwards_get(struct ast_channel *chan)
Get the current max forwards for a particular channel.
Definition: max_forwards.c:121
loadable MixMonitor functionality
int ast_start_mixmonitor(struct ast_channel *chan, const char *filename, const char *options)
Start a mixmonitor on a channel with the given parameters.
Definition: mixmonitor.c:74
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_DEVSTATE_CONSUMER
Definition: module.h:347
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:640
Music on hold handling.
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:7748
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7758
def info(msg)
Core PBX routines and definitions.
const struct ast_include * ast_walk_context_includes(const struct ast_context *con, const struct ast_include *inc)
Definition: pbx.c:8675
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4170
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4196
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
Definition: pbx_app.c:471
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name.
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
int pbx_builtin_setvar_multiple(struct ast_channel *chan, const char *data)
Parse and set multiple channel variables, where the pairs are separated by the ',' character,...
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
@ AST_EXTENSION_RINGING
Definition: pbx.h:68
@ AST_EXTENSION_NOT_INUSE
Definition: pbx.h:64
@ AST_EXTENSION_INUSE
Definition: pbx.h:65
@ AST_EXTENSION_UNAVAILABLE
Definition: pbx.h:67
@ AST_EXTENSION_ONHOLD
Definition: pbx.h:69
@ AST_EXTENSION_BUSY
Definition: pbx.h:66
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1562
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8806
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
Definition: pbx.c:4211
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3877
@ AST_HINT_UPDATE_DEVICE
Definition: pbx.h:91
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3844
struct ast_app * pbx_findapp(const char *app)
Look up an application.
Definition: ael_main.c:165
int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
Uses hint and devicestate callback to get the state of an extension.
Definition: pbx.c:3191
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
static char url[512]
struct stasis_forward * sub
Definition: res_corosync.c:240
static void to_ami(struct ast_sip_subscription *sub, struct ast_str **buf)
#define NULL
Definition: resample.c:96
Say numbers and dates (maybe words one day too)
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Definition: channel.c:8249
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
#define STASIS_MESSAGE_TYPE_CLEANUP(name)
Boiler-plate messaging macro for cleaning up message types.
Definition: stasis.h:1515
@ STASIS_SUBSCRIPTION_FILTER_SELECTIVE
Definition: stasis.h:297
struct stasis_forward * stasis_forward_cancel(struct stasis_forward *forward)
Definition: stasis.c:1615
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1090
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1144
#define STASIS_MESSAGE_TYPE_INIT(name)
Boiler-plate messaging macro for initializing message types.
Definition: stasis.h:1493
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
Definition: stasis.c:1241
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1201
struct stasis_message * stasis_message_create(struct stasis_message_type *type, void *data)
Create a new message.
struct stasis_forward * stasis_forward_all(struct stasis_topic *from_topic, struct stasis_topic *to_topic)
Create a subscription which forwards all messages from one topic to another.
Definition: stasis.c:1645
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1578
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
struct stasis_message_type * ast_channel_entered_bridge_type(void)
Message type for ast_channel enter bridge blob messages.
struct stasis_message_type * ast_blind_transfer_type(void)
Message type for ast_blind_transfer_message.
struct stasis_message_type * ast_attended_transfer_type(void)
Message type for ast_attended_transfer_message.
struct stasis_topic * ast_bridge_topic_all(void)
A topic which publishes the events for all bridges.
@ AST_ATTENDED_TRANSFER_DEST_FAIL
@ AST_ATTENDED_TRANSFER_DEST_BRIDGE_MERGE
@ AST_ATTENDED_TRANSFER_DEST_LOCAL_APP
@ AST_ATTENDED_TRANSFER_DEST_LINK
@ AST_ATTENDED_TRANSFER_DEST_APP
@ AST_ATTENDED_TRANSFER_DEST_THREEWAY
#define stasis_message_router_create(topic)
Create a new message router object.
void stasis_message_router_unsubscribe(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic.
int stasis_message_router_add(struct stasis_message_router *router, struct stasis_message_type *message_type, stasis_subscription_cb callback, void *data)
Add a route to a message router.
void stasis_message_router_unsubscribe_and_join(struct stasis_message_router *router)
Unsubscribe the router from the upstream topic, blocking until the final message has been processed.
#define stasis_message_router_create_pool(topic)
Create a new message router object.
int stasis_message_router_set_default(struct stasis_message_router *router, stasis_subscription_cb callback, void *data)
Sets the default route of a router.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:238
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2235
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
@ AST_STRSEP_TRIM
Definition: strings.h:256
@ AST_STRSEP_STRIP
Definition: strings.h:255
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
Definition: utils.c:2252
#define ast_str_alloca(init_len)
Definition: strings.h:848
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:730
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:1303
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
char * ast_strsep(char **s, const char sep, uint32_t flags)
Act like strsep but ignore separators inside quotes.
Definition: utils.c:1871
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
ast_app: A registered application
Definition: pbx_app.c:45
Message representing attended transfer.
enum ast_attended_transfer_dest_type dest_type
struct ast_channel_snapshot * links[2]
struct ast_bridge_channel_snapshot_pair to_transfer_target
union ast_attended_transfer_message::@289 dest
enum ast_transfer_result result
struct ast_bridge_channel_snapshot_pair to_transferee
char bridge[AST_UUID_STR_LEN]
Message published during a blind transfer.
char exten[AST_MAX_EXTENSION]
struct ast_bridge_snapshot * bridge
enum ast_transfer_result result
char context[AST_MAX_CONTEXT]
Blob of data associated with a bridge.
struct ast_bridge_snapshot * bridge
struct ast_channel_snapshot * channel
struct ast_bridge_snapshot * bridge_snapshot
bridge configuration
Definition: channel.h:1096
void * end_bridge_callback_data
Definition: channel.h:1111
struct ast_flags features_callee
Definition: channel.h:1098
struct ast_flags features_caller
Definition: channel.h:1097
void(* end_bridge_callback)(void *)
Definition: channel.h:1110
void(* end_bridge_callback_data_fixup)(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: channel.h:1115
const ast_string_field uniqueid
Definition: bridge.h:332
Blob of data associated with a channel.
struct ast_channel_snapshot * snapshot
struct ast_json * blob
const ast_string_field uniqueid
const ast_string_field name
Structure representing a snapshot of channel state.
struct ast_channel_snapshot_base * base
struct ast_channel_snapshot_caller * caller
const char *const type
Definition: channel.h:649
Main Channel structure associated with a channel.
const struct ast_channel_tech * tech
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
ast_context: An extension context
Definition: pbx.c:299
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Definition: astdb.h:31
struct ast_db_entry * next
Definition: astdb.h:32
char * key
Definition: astdb.h:33
The structure that contains device state.
Definition: devicestate.h:238
enum ast_device_state state
Definition: devicestate.h:248
const struct ast_eid * eid
The EID of the server where this message originated.
Definition: devicestate.h:246
Structure used to handle boolean flags.
Definition: utils.h:217
unsigned int flags
Definition: utils.h:218
Format capabilities structure, holds formats + preference order + etc.
Definition: format_cap.c:54
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@231 data
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
struct ast_json * json
Definition: json.h:1083
Abstract JSON element (object, array, string, int, ...).
Struct containing info for an AMI event to send out.
Definition: manager.h:503
A multi channel blob data structure for multi_channel_blob stasis messages.
Caller Party information.
Definition: channel.h:420
struct ast_party_id id
Caller party ID.
Definition: channel.h:422
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:429
Connected Line/Party information.
Definition: channel.h:458
int source
Information about the source of an update.
Definition: channel.h:484
struct ast_party_id id
Connected party ID.
Definition: channel.h:460
struct ast_party_id ani
Automatic Number Identification (ANI)
Definition: channel.h:467
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
struct ast_party_dialed::@213 number
Dialed/Called number.
int transit_network_select
Transit Network Select.
Definition: channel.h:399
struct ast_party_name name
Subscriber name.
Definition: channel.h:342
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:344
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:281
char * str
Subscriber name (Malloced)
Definition: channel.h:266
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:299
char * str
Subscriber phone number (Malloced)
Definition: channel.h:293
Redirecting Line information. RDNIS (Redirecting Directory Number Information Service) Where a call d...
Definition: channel.h:524
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
Definition: channel.h:529
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
int autopause
Definition: app_queue.c:1668
const char * name
Definition: app_queue.c:1669
unsigned int autopauseunavail
Definition: app_queue.c:1980
int talktime
Definition: app_queue.c:1992
const ast_string_field sound_thereare
Definition: app_queue.c:1960
unsigned int setinterfacevar
Definition: app_queue.c:1966
struct call_queue::@53 list
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1962
const ast_string_field sound_callerannounce
Definition: app_queue.c:1960
int announcefrequency
Definition: app_queue.c:1984
const ast_string_field sound_reporthold
Definition: app_queue.c:1960
unsigned int announceholdtime
Definition: app_queue.c:1972
const ast_string_field sound_holdtime
Definition: app_queue.c:1960
unsigned int dead
Definition: app_queue.c:1963
unsigned int reportholdtime
Definition: app_queue.c:1969
unsigned int setqueueentryvar
Definition: app_queue.c:1968
const ast_string_field sound_seconds
Definition: app_queue.c:1960
unsigned int timeoutrestart
Definition: app_queue.c:1971
struct ao2_container * members
Definition: app_queue.c:2018
int periodicannouncefrequency
Definition: app_queue.c:1987
const ast_string_field sound_thanks
Definition: app_queue.c:1960
unsigned int announceposition_only_up
Definition: app_queue.c:1974
unsigned int setqueuevar
Definition: app_queue.c:1967
int announcepositionlimit
Definition: app_queue.c:1983
unsigned int announce_to_first_user
Definition: app_queue.c:1965
int randomperiodicannounce
Definition: app_queue.c:1989
int autopause
Definition: app_queue.c:2007
int periodicannouncestartdelay
Definition: app_queue.c:1986
const ast_string_field defaultrule
Definition: app_queue.c:1960
int log_restricted_caller_id
Definition: app_queue.c:2016
struct queue_ent * head
Definition: app_queue.c:2019
struct call_queue::@54 rules
unsigned int realtime
Definition: app_queue.c:1976
const ast_string_field queue_quantity2
Definition: app_queue.c:1960
int servicelevel
Definition: app_queue.c:1996
const ast_string_field moh
Definition: app_queue.c:1960
int autofill
Definition: app_queue.c:2014
int minannouncefrequency
Definition: app_queue.c:1985
enum empty_conditions leavewhenempty
Definition: app_queue.c:1982
int penaltymemberslimit
Definition: app_queue.c:2002
unsigned int found
Definition: app_queue.c:1977
const ast_string_field context
Definition: app_queue.c:1960
const ast_string_field sound_calls
Definition: app_queue.c:1960
unsigned int ringinuse
Definition: app_queue.c:1964
int callsabandoned
Definition: app_queue.c:1994
int roundingseconds
Definition: app_queue.c:1990
int numperiodicannounce
Definition: app_queue.c:1988
int wrapuptime
Definition: app_queue.c:2001
const ast_string_field sound_minute
Definition: app_queue.c:1960
int callscompleted
Definition: app_queue.c:1993
int callsabandonedinsl
Definition: app_queue.c:1995
const ast_string_field sound_minutes
Definition: app_queue.c:1960
unsigned int announceposition
Definition: app_queue.c:1973
const ast_string_field queue_quantity1
Definition: app_queue.c:1960
const ast_string_field membergosub
Definition: app_queue.c:1960
char monfmt[8]
Definition: app_queue.c:1998
enum empty_conditions joinempty
Definition: app_queue.c:1981
unsigned int wrapped
Definition: app_queue.c:1970
int strategy
Definition: app_queue.c:1975
const ast_string_field name
Definition: app_queue.c:1960
int callscompletedinsl
Definition: app_queue.c:1997
int memberdelay
Definition: app_queue.c:2013
const ast_string_field sound_next
Definition: app_queue.c:1960
unsigned int autopausebusy
Definition: app_queue.c:1979
int holdtime
Definition: app_queue.c:1991
const ast_string_field announce
Definition: app_queue.c:1960
int autopausedelay
Definition: app_queue.c:2008
int timeoutpriority
Definition: app_queue.c:2009
unsigned int relativeperiodicannounce
Definition: app_queue.c:1978
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1798
unsigned int dial_callerid_absent
Definition: app_queue.c:1812
unsigned int block_connected_update
Definition: app_queue.c:1810
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1815
struct ast_party_connected_line connected
Definition: app_queue.c:1806
char interface[256]
Definition: app_queue.c:1802
char * orig_chan_name
Definition: app_queue.c:1817
struct callattempt * call_next
Definition: app_queue.c:1800
struct ast_channel * chan
Definition: app_queue.c:1801
unsigned int stillgoing
Definition: app_queue.c:1814
struct callattempt * q_next
Definition: app_queue.c:1799
struct member * member
Definition: app_queue.c:1804
unsigned int pending_connected_update
Definition: app_queue.c:1808
Definition: astman.c:222
structure to hold extensions
Structure representing relevant data during a local channel optimization.
Definition: app_queue.c:6349
const char * source_chan_uniqueid
Definition: app_queue.c:6351
unsigned int id
Definition: app_queue.c:6355
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:323
Channel datastore data for max forwards.
Definition: max_forwards.c:29
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1857
unsigned int dead
Definition: app_queue.c:1878
unsigned int delme
Definition: app_queue.c:1879
int queuepos
Definition: app_queue.c:1870
time_t starttime
Definition: app_queue.c:1873
time_t lastcall
Definition: app_queue.c:1874
int dynamic
Definition: app_queue.c:1865
time_t logintime
Definition: app_queue.c:1876
char membername[80]
Definition: app_queue.c:1862
char rt_uniqueid[80]
Definition: app_queue.c:1880
int calls
Definition: app_queue.c:1864
int status
Definition: app_queue.c:1867
int penalty
Definition: app_queue.c:1863
int paused
Definition: app_queue.c:1868
unsigned int ringinuse
Definition: app_queue.c:1881
int wrapuptime
Definition: app_queue.c:1872
int callcompletedinsl
Definition: app_queue.c:1871
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1858
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1859
int realtime
Definition: app_queue.c:1866
int state_id
Definition: app_queue.c:1861
time_t lastpause
Definition: app_queue.c:1875
char reason_paused[80]
Definition: app_queue.c:1869
struct call_queue * lastqueue
Definition: app_queue.c:1877
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1860
Number structure.
Definition: app_followme.c:157
int raise_respect_min
Definition: app_queue.c:1913
int raise_relative
Definition: app_queue.c:1912
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1911
int max_relative
Definition: app_queue.c:1910
struct call_queue * q
Definition: app_queue.c:6974
struct ast_channel * chan
Definition: app_queue.c:6975
int raise_respect_min
Definition: app_queue.c:1842
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1826
int valid_digits
Definition: app_queue.c:1828
time_t last_pos
Definition: app_queue.c:1835
time_t last_periodic_announce_time
Definition: app_queue.c:1833
time_t expire
Definition: app_queue.c:1846
unsigned int withdraw
Definition: app_queue.c:1848
struct penalty_rule * pr
Definition: app_queue.c:1852
int linpos
Definition: app_queue.c:1843
int max_penalty
Definition: app_queue.c:1839
int pending
Definition: app_queue.c:1838
int raise_penalty
Definition: app_queue.c:1841
struct ast_channel * chan
Definition: app_queue.c:1850
int min_penalty
Definition: app_queue.c:1840
int ring_when_ringing
Definition: app_queue.c:1832
int cancel_answered_elsewhere
Definition: app_queue.c:1847
struct queue_ent::@51 qe_rules
char announce[PATH_MAX]
Definition: app_queue.c:1824
char * withdraw_info
Definition: app_queue.c:1849
int handled
Definition: app_queue.c:1837
int linwrapped
Definition: app_queue.c:1844
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1823
int last_pos_said
Definition: app_queue.c:1831
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1825
int last_periodic_announce_sound
Definition: app_queue.c:1834
const char * predial_callee
Definition: app_queue.c:1827
time_t start
Definition: app_queue.c:1845
struct call_queue * parent
Definition: app_queue.c:1822
struct queue_ent * next
Definition: app_queue.c:1853
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:6373
const ast_string_field caller_uniqueid
Definition: app_queue.c:6381
const ast_string_field member_uniqueid
Definition: app_queue.c:6381
struct local_optimization member_optimize
Definition: app_queue.c:6403
struct stasis_message_router * channel_router
Definition: app_queue.c:6399
struct call_queue * queue
Definition: app_queue.c:6383
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6381
struct stasis_message_router * bridge_router
Definition: app_queue.c:6397
struct local_optimization caller_optimize
Definition: app_queue.c:6401
struct member * member
Definition: app_queue.c:6385
struct rule_list::@55 rules
char name[80]
Definition: app_queue.c:2025
struct rule_list::@56 list
Forwarding information.
Definition: stasis.c:1598
const char * name
Definition: app_queue.c:1654
int strategy
Definition: app_queue.c:1653
Definition: ast_expr2.c:325
int value
Definition: syslog.c:37
An API for managing task processing threads that can be shared across modules.
Handy terminal functions for vt* terms.
const char * ast_term_reset(void)
Returns the terminal reset code.
Definition: term.c:357
#define COLOR_CYAN
Definition: term.h:62
#define COLOR_MAGENTA
Definition: term.h:60
#define COLOR_BROWN
Definition: term.h:56
const char * ast_term_color(int fgcolor, int bgcolor)
Return a color sequence string.
Definition: term.c:341
#define COLOR_BLACK
Definition: term.h:50
#define COLOR_RED
Definition: term.h:52
#define COLOR_GREEN
Definition: term.h:54
const char * args
static struct test_options options
static struct test_val a
static struct test_val c
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
Definition: utils.c:2317
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Support for translation of data formats. translate.c.
FILE * out
Definition: utils/frame.c:33
FILE * in
Definition: utils/frame.c:33
Utility functions.
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:978
#define ast_assert(a)
Definition: utils.h:776
long int ast_random(void)
Definition: utils.c:2348
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:703
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2379
#define AST_FLAGS_ALL
Definition: utils.h:214