Asterisk - The Open Source Telephony Project GIT-master-f36a736
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 <synopsis>
127 Queue a call for a call queue.
128 </synopsis>
129 <syntax>
130 <parameter name="queuename" required="true" />
131 <parameter name="options">
132 <optionlist>
133 <option name="b" argsep="^">
134 <para>Before initiating an outgoing call, <literal>Gosub</literal> to the specified
135 location using the newly created channel. The <literal>Gosub</literal> will be
136 executed for each destination channel.</para>
137 <argument name="context" required="false" />
138 <argument name="exten" required="false" />
139 <argument name="priority" required="true" hasparams="optional" argsep="^">
140 <argument name="arg1" multiple="true" required="true" />
141 <argument name="argN" />
142 </argument>
143 </option>
144 <option name="B" argsep="^">
145 <para>Before initiating the outgoing call(s), <literal>Gosub</literal> to the
146 specified location using the current channel.</para>
147 <argument name="context" required="false" />
148 <argument name="exten" required="false" />
149 <argument name="priority" required="true" hasparams="optional" argsep="^">
150 <argument name="arg1" multiple="true" required="true" />
151 <argument name="argN" />
152 </argument>
153 </option>
154 <option name="C">
155 <para>Mark all calls as "answered elsewhere" when cancelled.</para>
156 </option>
157 <option name="c">
158 <para>Continue in the dialplan if the callee hangs up.</para>
159 </option>
160 <option name="d">
161 <para>Data-quality (modem) call (minimum delay).</para>
162 <para>This option only applies to DAHDI channels. By default,
163 DTMF is verified by muting audio TX/RX to verify the tone
164 is still present. This option disables that behavior.</para>
165 </option>
166 <option name="F" argsep="^">
167 <argument name="context" required="false" />
168 <argument name="exten" required="false" />
169 <argument name="priority" required="true" />
170 <para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
171 to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
172 <para>NOTE: Any channel variables you want the called channel to inherit from the caller channel must be
173 prefixed with one or two underbars ('_').</para>
174 <para>NOTE: Using this option from a GoSub() might not make sense as there would be no return points.</para>
175 </option>
176 <option name="h">
177 <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
178 </option>
179 <option name="H">
180 <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
181 </option>
182 <option name="i">
183 <para>Ignore call forward requests from queue members and do nothing
184 when they are requested.</para>
185 </option>
186 <option name="I">
187 <para>Asterisk will ignore any connected line update requests or any redirecting party
188 update requests it may receive on this dial attempt.</para>
189 </option>
190 <option name="k">
191 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
192 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
193 </option>
194 <option name="K">
195 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
196 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
197 </option>
198 <option name="m">
199 <para>Custom music on hold class to use, which will override the music on hold class configured
200 in <filename>queues.conf</filename>, if specified.</para>
201 <para>Note that CHANNEL(musicclass), if set, will still override this option.</para>
202 </option>
203 <option name="n">
204 <para>No retries on the timeout; will exit this application and
205 go to the next step.</para>
206 </option>
207 <option name="r">
208 <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
209 </option>
210 <option name="R">
211 <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
212 </option>
213 <option name="t">
214 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
215 </option>
216 <option name="T">
217 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
218 </option>
219 <option name="x">
220 <para>Allow the <emphasis>called</emphasis> user to write the conversation
221 to disk via MixMonitor.</para>
222 </option>
223 <option name="X">
224 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
225 disk via MixMonitor.</para>
226 </option>
227 </optionlist>
228 </parameter>
229 <parameter name="URL">
230 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
231 </parameter>
232 <parameter name="announceoverride" argsep="&amp;">
233 <para>Announcement file(s) to play to agent before bridging
234 call, overriding the announcement(s) configured in
235 <filename>queues.conf</filename>, if any.</para>
236 <para>Ampersand separated list of filenames. If the filename
237 is a relative filename (it does not begin with a slash), it
238 will be searched for in the Asterisk sounds directory. If the
239 filename is able to be parsed as a URL, Asterisk will
240 download the file and then begin playback on it. To include a
241 literal <literal>&amp;</literal> in the URL you can enclose
242 the URL in single quotes.</para>
243 <argument name="announceoverride" required="true" />
244 <argument name="announceoverride2" multiple="true" />
245 </parameter>
246 <parameter name="timeout">
247 <para>Will cause the queue to fail out after a specified number of
248 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
249 <replaceable>retry</replaceable> cycle.</para>
250 </parameter>
251 <parameter name="AGI">
252 <para>Will setup an AGI script to be executed on the calling party's channel once they are
253 connected to a queue member.</para>
254 </parameter>
255 <parameter name="gosub">
256 <para>Will run a gosub on the called party's channel (the queue member)
257 once the parties are connected. The subroutine execution starts in the
258 named context at the s exten and priority 1.</para>
259 </parameter>
260 <parameter name="rule">
261 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
262 </parameter>
263 <parameter name="position">
264 <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
265 would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
266 the caller third in the queue.</para>
267 </parameter>
268 </syntax>
269 <description>
270 <para>In addition to transferring the call, a call may be parked and then picked
271 up by another user.</para>
272 <para>This application will return to the dialplan if the queue does not exist, or
273 any of the join options cause the caller to not enter the queue.</para>
274 <para>This application does not automatically answer and should be preceeded
275 by an application such as Answer(), Progress(), or Ringing().</para>
276 <para>This application sets the following channel variables upon completion:</para>
277 <variablelist>
278 <variable name="QUEUESTATUS">
279 <para>The status of the call as a text string.</para>
280 <value name="TIMEOUT" />
281 <value name="FULL" />
282 <value name="JOINEMPTY" />
283 <value name="LEAVEEMPTY" />
284 <value name="JOINUNAVAIL" />
285 <value name="LEAVEUNAVAIL" />
286 <value name="CONTINUE" />
287 <value name="WITHDRAW" />
288 </variable>
289 <variable name="ABANDONED">
290 <para>If the call was not answered by an agent this variable will be TRUE.</para>
291 <value name="TRUE" />
292 </variable>
293 <variable name="DIALEDPEERNUMBER">
294 <para>Resource of the agent that was dialed set on the outbound channel.</para>
295 </variable>
296 <variable name="QUEUE_WITHDRAW_INFO">
297 <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>
298 </variable>
299 </variablelist>
300 </description>
301 <see-also>
302 <ref type="application">Queue</ref>
303 <ref type="application">QueueLog</ref>
304 <ref type="application">AddQueueMember</ref>
305 <ref type="application">RemoveQueueMember</ref>
306 <ref type="application">PauseQueueMember</ref>
307 <ref type="application">UnpauseQueueMember</ref>
308 <ref type="function">QUEUE_VARIABLES</ref>
309 <ref type="function">QUEUE_MEMBER</ref>
310 <ref type="function">QUEUE_MEMBER_COUNT</ref>
311 <ref type="function">QUEUE_EXISTS</ref>
312 <ref type="function">QUEUE_GET_CHANNEL</ref>
313 <ref type="function">QUEUE_WAITING_COUNT</ref>
314 <ref type="function">QUEUE_MEMBER_LIST</ref>
315 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
316 </see-also>
317 </application>
318 <application name="AddQueueMember" language="en_US">
319 <synopsis>
320 Dynamically adds queue members.
321 </synopsis>
322 <syntax>
323 <parameter name="queuename" required="true" />
324 <parameter name="interface" />
325 <parameter name="penalty" />
326 <parameter name="options">
327 <optionlist>
328 <option name="p">
329 <para>Add queue member in paused state.</para>
330 </option>
331 <option name="r">
332 <argument name="reason" required="true" />
333 <para>Specify a reason why the member is in paused state.</para>
334 </option>
335 </optionlist>
336 </parameter>
337 <parameter name="membername" />
338 <parameter name="stateinterface" />
339 <parameter name="wrapuptime" />
340 </syntax>
341 <description>
342 <para>Dynamically adds interface to an existing queue. If the interface is
343 already in the queue it will return an error.</para>
344 <para>This application sets the following channel variable upon completion:</para>
345 <variablelist>
346 <variable name="AQMSTATUS">
347 <para>The status of the attempt to add a queue member as a text string.</para>
348 <value name="ADDED" />
349 <value name="MEMBERALREADY" />
350 <value name="NOSUCHQUEUE" />
351 </variable>
352 </variablelist>
353 </description>
354 <see-also>
355 <ref type="application">Queue</ref>
356 <ref type="application">QueueLog</ref>
357 <ref type="application">AddQueueMember</ref>
358 <ref type="application">RemoveQueueMember</ref>
359 <ref type="application">PauseQueueMember</ref>
360 <ref type="application">UnpauseQueueMember</ref>
361 <ref type="function">QUEUE_VARIABLES</ref>
362 <ref type="function">QUEUE_MEMBER</ref>
363 <ref type="function">QUEUE_MEMBER_COUNT</ref>
364 <ref type="function">QUEUE_EXISTS</ref>
365 <ref type="function">QUEUE_GET_CHANNEL</ref>
366 <ref type="function">QUEUE_WAITING_COUNT</ref>
367 <ref type="function">QUEUE_MEMBER_LIST</ref>
368 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
369 </see-also>
370 </application>
371 <application name="RemoveQueueMember" language="en_US">
372 <synopsis>
373 Dynamically removes queue members.
374 </synopsis>
375 <syntax>
376 <parameter name="queuename" required="true" />
377 <parameter name="interface" />
378 </syntax>
379 <description>
380 <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
381 <para>This application sets the following channel variable upon completion:</para>
382 <variablelist>
383 <variable name="RQMSTATUS">
384 <value name="REMOVED" />
385 <value name="NOTINQUEUE" />
386 <value name="NOSUCHQUEUE" />
387 <value name="NOTDYNAMIC" />
388 </variable>
389 </variablelist>
390 <example title="Remove queue member">
391 same => n,RemoveQueueMember(techsupport,SIP/3000)
392 </example>
393 </description>
394 <see-also>
395 <ref type="application">Queue</ref>
396 <ref type="application">QueueLog</ref>
397 <ref type="application">AddQueueMember</ref>
398 <ref type="application">RemoveQueueMember</ref>
399 <ref type="application">PauseQueueMember</ref>
400 <ref type="application">UnpauseQueueMember</ref>
401 <ref type="function">QUEUE_VARIABLES</ref>
402 <ref type="function">QUEUE_MEMBER</ref>
403 <ref type="function">QUEUE_MEMBER_COUNT</ref>
404 <ref type="function">QUEUE_EXISTS</ref>
405 <ref type="function">QUEUE_GET_CHANNEL</ref>
406 <ref type="function">QUEUE_WAITING_COUNT</ref>
407 <ref type="function">QUEUE_MEMBER_LIST</ref>
408 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
409 </see-also>
410 </application>
411 <application name="PauseQueueMember" language="en_US">
412 <synopsis>
413 Pauses a queue member.
414 </synopsis>
415 <syntax>
416 <parameter name="queuename" />
417 <parameter name="interface" required="true" />
418 <parameter name="options" />
419 <parameter name="reason">
420 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
421 </parameter>
422 </syntax>
423 <description>
424 <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
425 This prevents any calls from being sent from the queue to the interface until it is
426 unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
427 the interface is paused in every queue it is a member of. The application will fail if the
428 interface is not found.</para>
429 <para>This application sets the following channel variable upon completion:</para>
430 <variablelist>
431 <variable name="PQMSTATUS">
432 <para>The status of the attempt to pause a queue member as a text string.</para>
433 <value name="PAUSED" />
434 <value name="NOTFOUND" />
435 </variable>
436 </variablelist>
437 <example title="Pause queue member">
438 same => n,PauseQueueMember(,SIP/3000)
439 </example>
440 </description>
441 <see-also>
442 <ref type="application">Queue</ref>
443 <ref type="application">QueueLog</ref>
444 <ref type="application">AddQueueMember</ref>
445 <ref type="application">RemoveQueueMember</ref>
446 <ref type="application">PauseQueueMember</ref>
447 <ref type="application">UnpauseQueueMember</ref>
448 <ref type="function">QUEUE_VARIABLES</ref>
449 <ref type="function">QUEUE_MEMBER</ref>
450 <ref type="function">QUEUE_MEMBER_COUNT</ref>
451 <ref type="function">QUEUE_EXISTS</ref>
452 <ref type="function">QUEUE_GET_CHANNEL</ref>
453 <ref type="function">QUEUE_WAITING_COUNT</ref>
454 <ref type="function">QUEUE_MEMBER_LIST</ref>
455 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
456 </see-also>
457 </application>
458 <application name="UnpauseQueueMember" language="en_US">
459 <synopsis>
460 Unpauses a queue member.
461 </synopsis>
462 <syntax>
463 <parameter name="queuename" />
464 <parameter name="interface" required="true" />
465 <parameter name="options" />
466 <parameter name="reason">
467 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
468 </parameter>
469 </syntax>
470 <description>
471 <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
472 and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
473 <para>This application sets the following channel variable upon completion:</para>
474 <variablelist>
475 <variable name="UPQMSTATUS">
476 <para>The status of the attempt to unpause a queue member as a text string.</para>
477 <value name="UNPAUSED" />
478 <value name="NOTFOUND" />
479 </variable>
480 </variablelist>
481 <example title="Unpause queue member">
482 same => n,UnpauseQueueMember(,SIP/3000)
483 </example>
484 </description>
485 <see-also>
486 <ref type="application">Queue</ref>
487 <ref type="application">QueueLog</ref>
488 <ref type="application">AddQueueMember</ref>
489 <ref type="application">RemoveQueueMember</ref>
490 <ref type="application">PauseQueueMember</ref>
491 <ref type="application">UnpauseQueueMember</ref>
492 <ref type="function">QUEUE_VARIABLES</ref>
493 <ref type="function">QUEUE_MEMBER</ref>
494 <ref type="function">QUEUE_MEMBER_COUNT</ref>
495 <ref type="function">QUEUE_EXISTS</ref>
496 <ref type="function">QUEUE_GET_CHANNEL</ref>
497 <ref type="function">QUEUE_WAITING_COUNT</ref>
498 <ref type="function">QUEUE_MEMBER_LIST</ref>
499 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
500 </see-also>
501 </application>
502 <application name="QueueLog" language="en_US">
503 <synopsis>
504 Writes to the queue_log file.
505 </synopsis>
506 <syntax>
507 <parameter name="queuename" required="true" />
508 <parameter name="uniqueid" required="true" />
509 <parameter name="agent" required="true" />
510 <parameter name="event" required="true" />
511 <parameter name="additionalinfo" />
512 </syntax>
513 <description>
514 <para>Allows you to write your own events into the queue log.</para>
515 <example title="Log custom queue event">
516 same => n,QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)
517 </example>
518 </description>
519 <see-also>
520 <ref type="application">Queue</ref>
521 <ref type="application">QueueLog</ref>
522 <ref type="application">AddQueueMember</ref>
523 <ref type="application">RemoveQueueMember</ref>
524 <ref type="application">PauseQueueMember</ref>
525 <ref type="application">UnpauseQueueMember</ref>
526 <ref type="function">QUEUE_VARIABLES</ref>
527 <ref type="function">QUEUE_MEMBER</ref>
528 <ref type="function">QUEUE_MEMBER_COUNT</ref>
529 <ref type="function">QUEUE_EXISTS</ref>
530 <ref type="function">QUEUE_GET_CHANNEL</ref>
531 <ref type="function">QUEUE_WAITING_COUNT</ref>
532 <ref type="function">QUEUE_MEMBER_LIST</ref>
533 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
534 </see-also>
535 </application>
536 <application name="QueueUpdate" language="en_US">
537 <synopsis>
538 Writes to the queue_log file for outbound calls and updates Realtime Data.
539 Is used at h extension to be able to have all the parameters.
540 </synopsis>
541 <syntax>
542 <parameter name="queuename" required="true" />
543 <parameter name="uniqueid" required="true" />
544 <parameter name="agent" required="true" />
545 <parameter name="status" required="true" />
546 <parameter name="talktime" required="true" />
547 <parameter name="params" required="false" />
548 </syntax>
549 <description>
550 <para>Allows you to write Outbound events into the queue log.</para>
551 <example title="Write outbound event into queue log">
552 exten => h,1,QueueUpdate(${QUEUE}, ${UNIQUEID}, ${AGENT}, ${DIALSTATUS}, ${ANSWEREDTIME}, ${DIALEDTIME} | ${DIALEDNUMBER})
553 </example>
554 </description>
555 </application>
556 <function name="QUEUE_VARIABLES" language="en_US">
557 <synopsis>
558 Return Queue information in variables.
559 </synopsis>
560 <syntax>
561 <parameter name="queuename" required="true">
562 <enumlist>
563 <enum name="QUEUEMAX">
564 <para>Maxmimum number of calls allowed.</para>
565 </enum>
566 <enum name="QUEUESTRATEGY">
567 <para>The strategy of the queue.</para>
568 </enum>
569 <enum name="QUEUECALLS">
570 <para>Number of calls currently in the queue.</para>
571 </enum>
572 <enum name="QUEUEHOLDTIME">
573 <para>Current average hold time.</para>
574 </enum>
575 <enum name="QUEUECOMPLETED">
576 <para>Number of completed calls for the queue.</para>
577 </enum>
578 <enum name="QUEUEABANDONED">
579 <para>Number of abandoned calls.</para>
580 </enum>
581 <enum name="QUEUESRVLEVEL">
582 <para>Queue service level.</para>
583 </enum>
584 <enum name="QUEUESRVLEVELPERF">
585 <para>Current service level performance.</para>
586 </enum>
587 </enumlist>
588 </parameter>
589 </syntax>
590 <description>
591 <para>Makes the following queue variables available.</para>
592 <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
593 </description>
594 <see-also>
595 <ref type="application">Queue</ref>
596 <ref type="application">QueueLog</ref>
597 <ref type="application">AddQueueMember</ref>
598 <ref type="application">RemoveQueueMember</ref>
599 <ref type="application">PauseQueueMember</ref>
600 <ref type="application">UnpauseQueueMember</ref>
601 <ref type="function">QUEUE_VARIABLES</ref>
602 <ref type="function">QUEUE_MEMBER</ref>
603 <ref type="function">QUEUE_MEMBER_COUNT</ref>
604 <ref type="function">QUEUE_EXISTS</ref>
605 <ref type="function">QUEUE_GET_CHANNEL</ref>
606 <ref type="function">QUEUE_WAITING_COUNT</ref>
607 <ref type="function">QUEUE_MEMBER_LIST</ref>
608 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
609 </see-also>
610 </function>
611 <function name="QUEUE_MEMBER" language="en_US">
612 <synopsis>
613 Provides a count of queue members based on the provided criteria, or updates a
614 queue member's settings.
615 </synopsis>
616 <syntax>
617 <parameter name="queuename" required="false" />
618 <parameter name="option" required="true">
619 <enumlist>
620 <enum name="logged">
621 <para>Returns the number of logged-in members for the specified queue.</para>
622 </enum>
623 <enum name="free">
624 <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>
625 </enum>
626 <enum name="ready">
627 <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
628 </enum>
629 <enum name="count">
630 <para>Returns the total number of members for the specified queue.</para>
631 </enum>
632 <enum name="penalty">
633 <para>Gets or sets queue member penalty. If
634 <replaceable>queuename</replaceable> is not specified
635 when setting the penalty then the penalty is set in all queues
636 the interface is a member.</para>
637 </enum>
638 <enum name="paused">
639 <para>Gets or sets queue member paused status. If
640 <replaceable>queuename</replaceable> is not specified
641 when setting the paused status then the paused status is set
642 in all queues the interface is a member.</para>
643 </enum>
644 <enum name="ringinuse">
645 <para>Gets or sets queue member ringinuse. If
646 <replaceable>queuename</replaceable> is not specified
647 when setting ringinuse then ringinuse is set
648 in all queues the interface is a member.</para>
649 </enum>
650 </enumlist>
651 </parameter>
652 <parameter name="interface" required="false" />
653 </syntax>
654 <description>
655 <para>Allows access to queue counts [R] and member information [R/W].</para>
656 <para><replaceable>queuename</replaceable> is required for all read operations.</para>
657 <para><replaceable>interface</replaceable> is required for all member operations.</para>
658 </description>
659 <see-also>
660 <ref type="application">Queue</ref>
661 <ref type="application">QueueLog</ref>
662 <ref type="application">AddQueueMember</ref>
663 <ref type="application">RemoveQueueMember</ref>
664 <ref type="application">PauseQueueMember</ref>
665 <ref type="application">UnpauseQueueMember</ref>
666 <ref type="function">QUEUE_VARIABLES</ref>
667 <ref type="function">QUEUE_MEMBER</ref>
668 <ref type="function">QUEUE_MEMBER_COUNT</ref>
669 <ref type="function">QUEUE_EXISTS</ref>
670 <ref type="function">QUEUE_GET_CHANNEL</ref>
671 <ref type="function">QUEUE_WAITING_COUNT</ref>
672 <ref type="function">QUEUE_MEMBER_LIST</ref>
673 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
674 </see-also>
675 </function>
676 <function name="QUEUE_MEMBER_COUNT" language="en_US">
677 <synopsis>
678 Count number of members answering a queue.
679 </synopsis>
680 <syntax>
681 <parameter name="queuename" required="true" />
682 </syntax>
683 <description>
684 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
685 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
686 </description>
687 <see-also>
688 <ref type="application">Queue</ref>
689 <ref type="application">QueueLog</ref>
690 <ref type="application">AddQueueMember</ref>
691 <ref type="application">RemoveQueueMember</ref>
692 <ref type="application">PauseQueueMember</ref>
693 <ref type="application">UnpauseQueueMember</ref>
694 <ref type="function">QUEUE_VARIABLES</ref>
695 <ref type="function">QUEUE_MEMBER</ref>
696 <ref type="function">QUEUE_MEMBER_COUNT</ref>
697 <ref type="function">QUEUE_EXISTS</ref>
698 <ref type="function">QUEUE_GET_CHANNEL</ref>
699 <ref type="function">QUEUE_WAITING_COUNT</ref>
700 <ref type="function">QUEUE_MEMBER_LIST</ref>
701 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
702 </see-also>
703 </function>
704 <function name="QUEUE_EXISTS" language="en_US">
705 <synopsis>
706 Check if a named queue exists on this server
707 </synopsis>
708 <syntax>
709 <parameter name="queuename" />
710 </syntax>
711 <description>
712 <para>Returns 1 if the specified queue exists, 0 if it does not</para>
713 </description>
714 <see-also>
715 <ref type="application">Queue</ref>
716 <ref type="application">QueueLog</ref>
717 <ref type="application">AddQueueMember</ref>
718 <ref type="application">RemoveQueueMember</ref>
719 <ref type="application">PauseQueueMember</ref>
720 <ref type="application">UnpauseQueueMember</ref>
721 <ref type="function">QUEUE_VARIABLES</ref>
722 <ref type="function">QUEUE_MEMBER</ref>
723 <ref type="function">QUEUE_MEMBER_COUNT</ref>
724 <ref type="function">QUEUE_EXISTS</ref>
725 <ref type="function">QUEUE_GET_CHANNEL</ref>
726 <ref type="function">QUEUE_WAITING_COUNT</ref>
727 <ref type="function">QUEUE_MEMBER_LIST</ref>
728 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
729 </see-also>
730 </function>
731 <function name="QUEUE_GET_CHANNEL" language="en_US">
732 <synopsis>
733 Return caller at the specified position in a queue.
734 </synopsis>
735 <syntax>
736 <parameter name="queuename" required="true" />
737 <parameter name="position" />
738 </syntax>
739 <description>
740 <para>Returns the caller channel at <replaceable>position</replaceable> in the specified <replaceable>queuename</replaceable>.</para>
741 <para>If <replaceable>position</replaceable> is unspecified the first channel is returned.</para>
742 </description>
743 <see-also>
744 <ref type="application">Queue</ref>
745 <ref type="application">QueueLog</ref>
746 <ref type="application">AddQueueMember</ref>
747 <ref type="application">RemoveQueueMember</ref>
748 <ref type="application">PauseQueueMember</ref>
749 <ref type="application">UnpauseQueueMember</ref>
750 <ref type="function">QUEUE_VARIABLES</ref>
751 <ref type="function">QUEUE_MEMBER</ref>
752 <ref type="function">QUEUE_MEMBER_COUNT</ref>
753 <ref type="function">QUEUE_EXISTS</ref>
754 <ref type="function">QUEUE_WAITING_COUNT</ref>
755 <ref type="function">QUEUE_MEMBER_LIST</ref>
756 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
757 </see-also>
758 </function>
759 <function name="QUEUE_WAITING_COUNT" language="en_US">
760 <synopsis>
761 Count number of calls currently waiting in a queue.
762 </synopsis>
763 <syntax>
764 <parameter name="queuename" />
765 </syntax>
766 <description>
767 <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
768 </description>
769 <see-also>
770 <ref type="application">Queue</ref>
771 <ref type="application">QueueLog</ref>
772 <ref type="application">AddQueueMember</ref>
773 <ref type="application">RemoveQueueMember</ref>
774 <ref type="application">PauseQueueMember</ref>
775 <ref type="application">UnpauseQueueMember</ref>
776 <ref type="function">QUEUE_VARIABLES</ref>
777 <ref type="function">QUEUE_MEMBER</ref>
778 <ref type="function">QUEUE_MEMBER_COUNT</ref>
779 <ref type="function">QUEUE_EXISTS</ref>
780 <ref type="function">QUEUE_GET_CHANNEL</ref>
781 <ref type="function">QUEUE_WAITING_COUNT</ref>
782 <ref type="function">QUEUE_MEMBER_LIST</ref>
783 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
784 </see-also>
785 </function>
786 <function name="QUEUE_MEMBER_LIST" language="en_US">
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_MEMBER_COUNT</ref>
806 <ref type="function">QUEUE_EXISTS</ref>
807 <ref type="function">QUEUE_GET_CHANNEL</ref>
808 <ref type="function">QUEUE_WAITING_COUNT</ref>
809 <ref type="function">QUEUE_MEMBER_LIST</ref>
810 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
811 </see-also>
812 </function>
813 <function name="QUEUE_MEMBER_PENALTY" language="en_US">
814 <synopsis>
815 Gets or sets queue members penalty.
816 </synopsis>
817 <syntax>
818 <parameter name="queuename" required="true" />
819 <parameter name="interface" required="true" />
820 </syntax>
821 <description>
822 <para>Gets or sets queue members penalty.</para>
823 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
824 </description>
825 <see-also>
826 <ref type="application">Queue</ref>
827 <ref type="application">QueueLog</ref>
828 <ref type="application">AddQueueMember</ref>
829 <ref type="application">RemoveQueueMember</ref>
830 <ref type="application">PauseQueueMember</ref>
831 <ref type="application">UnpauseQueueMember</ref>
832 <ref type="function">QUEUE_VARIABLES</ref>
833 <ref type="function">QUEUE_MEMBER</ref>
834 <ref type="function">QUEUE_MEMBER_COUNT</ref>
835 <ref type="function">QUEUE_EXISTS</ref>
836 <ref type="function">QUEUE_GET_CHANNEL</ref>
837 <ref type="function">QUEUE_WAITING_COUNT</ref>
838 <ref type="function">QUEUE_MEMBER_LIST</ref>
839 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
840 </see-also>
841 </function>
842 <manager name="QueueStatus" language="en_US">
843 <synopsis>
844 Show queue status.
845 </synopsis>
846 <syntax>
847 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
848 <parameter name="Queue">
849 <para>Limit the response to the status of the specified queue.</para>
850 </parameter>
851 <parameter name="Member">
852 <para>Limit the response to the status of the specified member.</para>
853 </parameter>
854 </syntax>
855 <description>
856 <para>Check the status of one or more queues.</para>
857 </description>
858 </manager>
859 <manager name="QueueSummary" language="en_US">
860 <synopsis>
861 Show queue summary.
862 </synopsis>
863 <syntax>
864 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
865 <parameter name="Queue">
866 <para>Queue for which the summary is requested.</para>
867 </parameter>
868 </syntax>
869 <description>
870 <para>Request the manager to send a QueueSummary event.</para>
871 </description>
872 </manager>
873 <manager name="QueueAdd" language="en_US">
874 <synopsis>
875 Add interface to queue.
876 </synopsis>
877 <syntax>
878 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
879 <parameter name="Queue" required="true">
880 <para>Queue's name.</para>
881 </parameter>
882 <parameter name="Interface" required="true">
883 <para>The name of the interface (tech/name) to add to the queue.</para>
884 </parameter>
885 <parameter name="Penalty">
886 <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>
887 </parameter>
888 <parameter name="Paused">
889 <para>To pause or not the member initially (true/false or 1/0).</para>
890 </parameter>
891 <parameter name="Reason" required="false">
892 <para>Text description why the member is paused.</para>
893 </parameter>
894 <parameter name="MemberName">
895 <para>Text alias for the interface.</para>
896 </parameter>
897 <parameter name="StateInterface" />
898 </syntax>
899 <description>
900 </description>
901 </manager>
902 <manager name="QueueRemove" language="en_US">
903 <synopsis>
904 Remove interface from queue.
905 </synopsis>
906 <syntax>
907 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
908 <parameter name="Queue" required="true">
909 <para>The name of the queue to take action on.</para>
910 </parameter>
911 <parameter name="Interface" required="true">
912 <para>The interface (tech/name) to remove from queue.</para>
913 </parameter>
914 </syntax>
915 <description>
916 </description>
917 </manager>
918 <manager name="QueuePause" language="en_US">
919 <synopsis>
920 Makes a queue member temporarily unavailable.
921 </synopsis>
922 <syntax>
923 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
924 <parameter name="Interface" required="true">
925 <para>The name of the interface (tech/name) to pause or unpause.</para>
926 </parameter>
927 <parameter name="Paused" required="true">
928 <para>Pause or unpause the interface. Set to 'true' to pause the member or 'false' to unpause.</para>
929 </parameter>
930 <parameter name="Queue" required="false">
931 <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>
932 </parameter>
933 <parameter name="Reason" required="false">
934 <para>Text description, returned in the event QueueMemberPaused.</para>
935 </parameter>
936 </syntax>
937 <description>
938 <para>Pause or unpause a member in a queue.</para>
939 </description>
940 </manager>
941 <manager name="QueueLog" language="en_US">
942 <synopsis>
943 Adds custom entry in queue_log.
944 </synopsis>
945 <syntax>
946 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
947 <parameter name="Queue" required="true" />
948 <parameter name="Event" required="true" />
949 <parameter name="Uniqueid" />
950 <parameter name="Interface" />
951 <parameter name="Message" />
952 </syntax>
953 <description>
954 </description>
955 </manager>
956 <manager name="QueuePenalty" language="en_US">
957 <synopsis>
958 Set the penalty for a queue member.
959 </synopsis>
960 <syntax>
961 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
962 <parameter name="Interface" required="true">
963 <para>The interface (tech/name) of the member whose penalty to change.</para>
964 </parameter>
965 <parameter name="Penalty" required="true">
966 <para>The new penalty (number) for the member. Must be nonnegative.</para>
967 </parameter>
968 <parameter name="Queue">
969 <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>
970 </parameter>
971 </syntax>
972 <description>
973 <para>Change the penalty of a queue member</para>
974 </description>
975 </manager>
976 <manager name="QueueMemberRingInUse" language="en_US">
977 <synopsis>
978 Set the ringinuse value for a queue member.
979 </synopsis>
980 <syntax>
981 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
982 <parameter name="Interface" required="true" />
983 <parameter name="RingInUse" required="true" />
984 <parameter name="Queue" />
985 </syntax>
986 <description>
987 </description>
988 </manager>
989 <manager name="QueueRule" language="en_US">
990 <synopsis>
991 Queue Rules.
992 </synopsis>
993 <syntax>
994 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
995 <parameter name="Rule">
996 <para>The name of the rule in queuerules.conf whose contents to list.</para>
997 </parameter>
998 </syntax>
999 <description>
1000 <para>List queue rules defined in queuerules.conf</para>
1001 </description>
1002 </manager>
1003 <manager name="QueueReload" language="en_US">
1004 <synopsis>
1005 Reload a queue, queues, or any sub-section of a queue or queues.
1006 </synopsis>
1007 <syntax>
1008 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1009 <parameter name="Queue">
1010 <para>The name of the queue to take action on. If no queue name is specified, then all queues are affected.</para>
1011 </parameter>
1012 <parameter name="Members">
1013 <para>Whether to reload the queue's members.</para>
1014 <enumlist>
1015 <enum name="yes" />
1016 <enum name="no" />
1017 </enumlist>
1018 </parameter>
1019 <parameter name="Rules">
1020 <para>Whether to reload queuerules.conf</para>
1021 <enumlist>
1022 <enum name="yes" />
1023 <enum name="no" />
1024 </enumlist>
1025 </parameter>
1026 <parameter name="Parameters">
1027 <para>Whether to reload the other queue options.</para>
1028 <enumlist>
1029 <enum name="yes" />
1030 <enum name="no" />
1031 </enumlist>
1032 </parameter>
1033 </syntax>
1034 <description>
1035 </description>
1036 </manager>
1037 <manager name="QueueReset" language="en_US">
1038 <synopsis>
1039 Reset queue statistics.
1040 </synopsis>
1041 <syntax>
1042 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1043 <parameter name="Queue">
1044 <para>The name of the queue on which to reset statistics.</para>
1045 </parameter>
1046 </syntax>
1047 <description>
1048 <para>Reset the statistics for a queue.</para>
1049 </description>
1050 </manager>
1051 <manager name="QueueChangePriorityCaller" language="en_US">
1052 <synopsis>
1053 Change priority of a caller on queue.
1054 </synopsis>
1055 <syntax>
1056 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1057 <parameter name="Queue" required="true">
1058 <para>The name of the queue to take action on.</para>
1059 </parameter>
1060 <parameter name="Caller" required="true">
1061 <para>The caller (channel) to change priority on queue.</para>
1062 </parameter>
1063
1064 <parameter name="Priority" required="true">
1065 <para>Priority value for change for caller on queue.</para>
1066 </parameter>
1067 <parameter name="Immediate">
1068 <para>When set to yes will cause the priority change to be reflected immediately, causing the channel to change position within the queue.</para>
1069 </parameter>
1070 </syntax>
1071 <description>
1072 </description>
1073 </manager>
1074 <manager name="QueueWithdrawCaller" language="en_US">
1075 <synopsis>
1076 Request to withdraw a caller from the queue back to the dialplan.
1077 </synopsis>
1078 <syntax>
1079 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
1080 <parameter name="Queue" required="true">
1081 <para>The name of the queue to take action on.</para>
1082 </parameter>
1083 <parameter name="Caller" required="true">
1084 <para>The caller (channel) to withdraw from the queue.</para>
1085 </parameter>
1086 <parameter name="WithdrawInfo" required="false">
1087 <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>
1088 </parameter>
1089 </syntax>
1090 <description>
1091 </description>
1092 </manager>
1093
1094 <managerEvent language="en_US" name="QueueParams">
1095 <managerEventInstance class="EVENT_FLAG_AGENT">
1096 <synopsis>Raised in response to the QueueStatus action.</synopsis>
1097 <syntax>
1098 <parameter name="Max">
1099 <para>The name of the queue.</para>
1100 </parameter>
1101 <parameter name="Strategy">
1102 <para>The strategy of the queue.</para>
1103 </parameter>
1104 <parameter name="Calls">
1105 <para>The queue member's channel technology or location.</para>
1106 </parameter>
1107 <parameter name="Holdtime">
1108 <para>The queue's hold time.</para>
1109 </parameter>
1110 <parameter name="TalkTime">
1111 <para>The queue's talk time.</para>
1112 </parameter>
1113 <parameter name="Completed">
1114 <para>The queue's completion time.</para>
1115 </parameter>
1116 <parameter name="Abandoned">
1117 <para>The queue's call abandonment metric.</para>
1118 </parameter>
1119 <parameter name="ServiceLevelPerf">
1120 <para>Primary service level performance metric.</para>
1121 </parameter>
1122 <parameter name="ServiceLevelPerf2">
1123 <para>Secondary service level performance metric.</para>
1124 </parameter>
1125 </syntax>
1126 <see-also>
1127 <ref type="managerEvent">QueueMember</ref>
1128 <ref type="managerEvent">QueueEntry</ref>
1129 </see-also>
1130 </managerEventInstance>
1131 </managerEvent>
1132 <managerEvent language="en_US" name="QueueEntry">
1133 <managerEventInstance class="EVENT_FLAG_AGENT">
1134 <synopsis>Raised in response to the QueueStatus action.</synopsis>
1135 <syntax>
1136 <parameter name="Queue">
1137 <para>The name of the queue.</para>
1138 </parameter>
1139 <parameter name="Position">
1140 <para>The caller's position within the queue.</para>
1141 </parameter>
1142 <parameter name="Channel">
1143 <para>The name of the caller's channel.</para>
1144 </parameter>
1145 <parameter name="Uniqueid">
1146 <para>The unique ID of the channel.</para>
1147 </parameter>
1148 <parameter name="CallerIDNum">
1149 <para>The Caller ID number.</para>
1150 </parameter>
1151 <parameter name="CallerIDName">
1152 <para>The Caller ID name.</para>
1153 </parameter>
1154 <parameter name="ConnectedLineNum">
1155 <para>The bridged party's number.</para>
1156 </parameter>
1157 <parameter name="ConnectedLineName">
1158 <para>The bridged party's name.</para>
1159 </parameter>
1160 <parameter name="Wait">
1161 <para>The caller's wait time.</para>
1162 </parameter>
1163 <parameter name="Priority">
1164 <para>The caller's priority within the queue.</para>
1165 </parameter>
1166 </syntax>
1167 <see-also>
1168 <ref type="managerEvent">QueueParams</ref>
1169 <ref type="managerEvent">QueueMember</ref>
1170 </see-also>
1171 </managerEventInstance>
1172 </managerEvent>
1173 <managerEvent language="en_US" name="QueueMemberStatus">
1174 <managerEventInstance class="EVENT_FLAG_AGENT">
1175 <synopsis>Raised when a Queue member's status has changed.</synopsis>
1176 <syntax>
1177 <parameter name="Queue">
1178 <para>The name of the queue.</para>
1179 </parameter>
1180 <parameter name="MemberName">
1181 <para>The name of the queue member.</para>
1182 </parameter>
1183 <parameter name="Interface">
1184 <para>The queue member's channel technology or location.</para>
1185 </parameter>
1186 <parameter name="StateInterface">
1187 <para>Channel technology or location from which to read device state changes.</para>
1188 </parameter>
1189 <parameter name="Membership">
1190 <enumlist>
1191 <enum name="dynamic"/>
1192 <enum name="realtime"/>
1193 <enum name="static"/>
1194 </enumlist>
1195 </parameter>
1196 <parameter name="Penalty">
1197 <para>The penalty associated with the queue member.</para>
1198 </parameter>
1199 <parameter name="CallsTaken">
1200 <para>The number of calls this queue member has serviced.</para>
1201 </parameter>
1202 <parameter name="LastCall">
1203 <para>The time this member last took a call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1204 </parameter>
1205 <parameter name="LastPause">
1206 <para>The time when started last paused the queue member.</para>
1207 </parameter>
1208 <parameter name="LoginTime">
1209 <para>The time this member logged in to the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1210 </parameter>
1211 <parameter name="InCall">
1212 <para>Set to 1 if member is in call. Set to 0 after LastCall time is updated.</para>
1213 <enumlist>
1214 <enum name="0"/>
1215 <enum name="1"/>
1216 </enumlist>
1217 </parameter>
1218 <parameter name="Status">
1219 <para>The numeric device state status of the queue member.</para>
1220 <enumlist>
1221 <enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
1222 <enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
1223 <enum name="2"><para>AST_DEVICE_INUSE</para></enum>
1224 <enum name="3"><para>AST_DEVICE_BUSY</para></enum>
1225 <enum name="4"><para>AST_DEVICE_INVALID</para></enum>
1226 <enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
1227 <enum name="6"><para>AST_DEVICE_RINGING</para></enum>
1228 <enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
1229 <enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
1230 </enumlist>
1231 </parameter>
1232 <parameter name="Paused">
1233 <enumlist>
1234 <enum name="0"/>
1235 <enum name="1"/>
1236 </enumlist>
1237 </parameter>
1238 <parameter name="PausedReason">
1239 <para>If set when paused, the reason the queue member was paused.</para>
1240 </parameter>
1241 <parameter name="Ringinuse">
1242 <enumlist>
1243 <enum name="0"/>
1244 <enum name="1"/>
1245 </enumlist>
1246 </parameter>
1247 <parameter name="Wrapuptime">
1248 <para>The Wrapup Time of the queue member. If this value is set will override the wrapup time of queue.</para>
1249 </parameter>
1250 </syntax>
1251 </managerEventInstance>
1252 </managerEvent>
1253 <managerEvent language="en_US" name="QueueMemberAdded">
1254 <managerEventInstance class="EVENT_FLAG_AGENT">
1255 <synopsis>Raised when a member is added to the queue.</synopsis>
1256 <syntax>
1257 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1258 </syntax>
1259 <see-also>
1260 <ref type="managerEvent">QueueMemberRemoved</ref>
1261 <ref type="application">AddQueueMember</ref>
1262 </see-also>
1263 </managerEventInstance>
1264 </managerEvent>
1265 <managerEvent language="en_US" name="QueueMemberRemoved">
1266 <managerEventInstance class="EVENT_FLAG_AGENT">
1267 <synopsis>Raised when a member is removed from the queue.</synopsis>
1268 <syntax>
1269 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1270 </syntax>
1271 <see-also>
1272 <ref type="managerEvent">QueueMemberAdded</ref>
1273 <ref type="application">RemoveQueueMember</ref>
1274 </see-also>
1275 </managerEventInstance>
1276 </managerEvent>
1277 <managerEvent language="en_US" name="QueueMemberPause">
1278 <managerEventInstance class="EVENT_FLAG_AGENT">
1279 <synopsis>Raised when a member is paused/unpaused in the queue.</synopsis>
1280 <syntax>
1281 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1282 </syntax>
1283 <see-also>
1284 <ref type="application">PauseQueueMember</ref>
1285 <ref type="application">UnpauseQueueMember</ref>
1286 </see-also>
1287 </managerEventInstance>
1288 </managerEvent>
1289 <managerEvent language="en_US" name="QueueMemberPenalty">
1290 <managerEventInstance class="EVENT_FLAG_AGENT">
1291 <synopsis>Raised when a member's penalty is changed.</synopsis>
1292 <syntax>
1293 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1294 </syntax>
1295 <see-also>
1296 <ref type="function">QUEUE_MEMBER</ref>
1297 </see-also>
1298 </managerEventInstance>
1299 </managerEvent>
1300 <managerEvent language="en_US" name="QueueMemberRinginuse">
1301 <managerEventInstance class="EVENT_FLAG_AGENT">
1302 <synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
1303 <syntax>
1304 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter)" />
1305 </syntax>
1306 <see-also>
1307 <ref type="function">QUEUE_MEMBER</ref>
1308 </see-also>
1309 </managerEventInstance>
1310 </managerEvent>
1311 <managerEvent language="en_US" name="QueueCallerJoin">
1312 <managerEventInstance class="EVENT_FLAG_AGENT">
1313 <synopsis>Raised when a caller joins a Queue.</synopsis>
1314 <syntax>
1315 <channel_snapshot/>
1316 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1317 <parameter name="Position">
1318 <para>This channel's current position in the queue.</para>
1319 </parameter>
1320 <parameter name="Count">
1321 <para>The total number of channels in the queue.</para>
1322 </parameter>
1323 </syntax>
1324 <see-also>
1325 <ref type="managerEvent">QueueCallerLeave</ref>
1326 <ref type="application">Queue</ref>
1327 </see-also>
1328 </managerEventInstance>
1329 </managerEvent>
1330 <managerEvent language="en_US" name="QueueCallerLeave">
1331 <managerEventInstance class="EVENT_FLAG_AGENT">
1332 <synopsis>Raised when a caller leaves a Queue.</synopsis>
1333 <syntax>
1334 <channel_snapshot/>
1335 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1336 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Count'])" />
1337 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1338 </syntax>
1339 <see-also>
1340 <ref type="managerEvent">QueueCallerJoin</ref>
1341 </see-also>
1342 </managerEventInstance>
1343 </managerEvent>
1344 <managerEvent language="en_US" name="QueueCallerAbandon">
1345 <managerEventInstance class="EVENT_FLAG_AGENT">
1346 <synopsis>Raised when a caller abandons the queue.</synopsis>
1347 <syntax>
1348 <channel_snapshot/>
1349 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1350 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerJoin']/managerEventInstance/syntax/parameter[@name='Position'])" />
1351 <parameter name="OriginalPosition">
1352 <para>The channel's original position in the queue.</para>
1353 </parameter>
1354 <parameter name="HoldTime">
1355 <para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1356 </parameter>
1357 </syntax>
1358 </managerEventInstance>
1359 </managerEvent>
1360 <managerEvent language="en_US" name="AgentCalled">
1361 <managerEventInstance class="EVENT_FLAG_AGENT">
1362 <synopsis>Raised when an queue member is notified of a caller in the queue.</synopsis>
1363 <syntax>
1364 <channel_snapshot/>
1365 <channel_snapshot prefix="Dest"/>
1366 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1367 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1368 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1369 </syntax>
1370 <see-also>
1371 <ref type="managerEvent">AgentRingNoAnswer</ref>
1372 <ref type="managerEvent">AgentComplete</ref>
1373 <ref type="managerEvent">AgentConnect</ref>
1374 </see-also>
1375 </managerEventInstance>
1376 </managerEvent>
1377 <managerEvent language="en_US" name="AgentRingNoAnswer">
1378 <managerEventInstance class="EVENT_FLAG_AGENT">
1379 <synopsis>Raised when a queue member is notified of a caller in the queue and fails to answer.</synopsis>
1380 <syntax>
1381 <channel_snapshot/>
1382 <channel_snapshot prefix="Dest"/>
1383 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1384 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1385 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1386 <parameter name="RingTime">
1387 <para>The time the queue member was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1388 </parameter>
1389 </syntax>
1390 <see-also>
1391 <ref type="managerEvent">AgentCalled</ref>
1392 </see-also>
1393 </managerEventInstance>
1394 </managerEvent>
1395 <managerEvent language="en_US" name="AgentComplete">
1396 <managerEventInstance class="EVENT_FLAG_AGENT">
1397 <synopsis>Raised when a queue member has finished servicing a caller in the queue.</synopsis>
1398 <syntax>
1399 <channel_snapshot/>
1400 <channel_snapshot prefix="Dest"/>
1401 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1402 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1403 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1404 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1405 <parameter name="TalkTime">
1406 <para>The time the queue member talked with the caller in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1407 </parameter>
1408 <parameter name="Reason">
1409 <enumlist>
1410 <enum name="caller"/>
1411 <enum name="agent"/>
1412 <enum name="transfer"/>
1413 </enumlist>
1414 </parameter>
1415 </syntax>
1416 <see-also>
1417 <ref type="managerEvent">AgentCalled</ref>
1418 <ref type="managerEvent">AgentConnect</ref>
1419 </see-also>
1420 </managerEventInstance>
1421 </managerEvent>
1422 <managerEvent language="en_US" name="AgentDump">
1423 <managerEventInstance class="EVENT_FLAG_AGENT">
1424 <synopsis>Raised when a queue member hangs up on a caller in the queue.</synopsis>
1425 <syntax>
1426 <channel_snapshot/>
1427 <channel_snapshot prefix="Dest"/>
1428 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1429 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1430 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1431 </syntax>
1432 <see-also>
1433 <ref type="managerEvent">AgentCalled</ref>
1434 <ref type="managerEvent">AgentConnect</ref>
1435 </see-also>
1436 </managerEventInstance>
1437 </managerEvent>
1438 <managerEvent language="en_US" name="AgentConnect">
1439 <managerEventInstance class="EVENT_FLAG_AGENT">
1440 <synopsis>Raised when a queue member answers and is bridged to a caller in the queue.</synopsis>
1441 <syntax>
1442 <channel_snapshot/>
1443 <channel_snapshot prefix="Dest"/>
1444 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
1445 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
1446 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Interface'])" />
1447 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
1448 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
1449 </syntax>
1450 <see-also>
1451 <ref type="managerEvent">AgentCalled</ref>
1452 <ref type="managerEvent">AgentComplete</ref>
1453 <ref type="managerEvent">AgentDump</ref>
1454 </see-also>
1455 </managerEventInstance>
1456 </managerEvent>
1457 ***/
1458
1459enum {
1461 OPT_GO_ON = (1 << 1),
1470 OPT_NO_RETRY = (1 << 10),
1471 OPT_RINGING = (1 << 11),
1482};
1483
1484enum {
1489 /* note: this entry _MUST_ be the last one in the enum */
1492
1517
1518
1520 AQMFLAG_PAUSED = (1 << 1),
1521 AQMFLAG_REASON = (1 << 2),
1522};
1523
1526 AQM_OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
1527};
1528
1533
1534enum {
1543};
1544
1545enum {
1550
1556};
1557
1558static const struct strategy {
1560 const char *name;
1561} strategies[] = {
1562 { QUEUE_STRATEGY_RINGALL, "ringall" },
1563 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
1564 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
1565 { QUEUE_STRATEGY_RANDOM, "random" },
1566 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
1567 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
1568 { QUEUE_STRATEGY_LINEAR, "linear" },
1569 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
1570 { QUEUE_STRATEGY_RRORDERED, "rrordered"},
1572
1573static const struct autopause {
1575 const char *name;
1576} autopausesmodes [] = {
1577 { QUEUE_AUTOPAUSE_OFF,"no" },
1578 { QUEUE_AUTOPAUSE_ON, "yes" },
1579 { QUEUE_AUTOPAUSE_ALL,"all" },
1581
1582#define DEFAULT_RETRY 5
1583#define DEFAULT_TIMEOUT 15
1584#define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
1585#define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
1586/*!
1587 * \brief The minimum number of seconds between position announcements.
1588 * \note The default value of 15 provides backwards compatibility.
1589 */
1590#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15
1591
1592#define MAX_QUEUE_BUCKETS 53
1593
1594#define RES_OKAY 0 /*!< Action completed */
1595#define RES_EXISTS (-1) /*!< Entry already exists */
1596#define RES_OUTOFMEMORY (-2) /*!< Out of memory */
1597#define RES_NOSUCHQUEUE (-3) /*!< No such queue */
1598#define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
1599#define RES_NOT_CALLER (-5) /*!< Caller not found */
1600
1601static char *app = "Queue";
1602
1603static char *app_aqm = "AddQueueMember" ;
1604
1605static char *app_rqm = "RemoveQueueMember" ;
1606
1607static char *app_pqm = "PauseQueueMember" ;
1608
1609static char *app_upqm = "UnpauseQueueMember" ;
1610
1611static char *app_ql = "QueueLog" ;
1612
1613static char *app_qupd = "QueueUpdate";
1614
1615/*! \brief Persistent Members astdb family */
1616static const char * const pm_family = "Queue/PersistentMembers";
1617
1618/*! \brief queues.conf [general] option */
1620
1621/*! \brief Records that one or more queues use weight */
1622static int use_weight;
1623
1624/*! \brief queues.conf [general] option */
1626
1627/*! \brief queues.conf [general] option */
1629
1630/*! \brief queues.conf [general] option */
1632
1633/*! \brief queuerules.conf [general] option */
1635
1636/*! \brief Subscription to device state change messages */
1638
1639/*! \brief queues.conf [general] option */
1641
1642/*! \brief queues.conf [general] option */
1644
1645/*! \brief queues.conf [general] option */
1647
1648/*! \brief name of the ringinuse field in the realtime database */
1650
1651/*! \brief does realtime backend support reason_paused */
1653
1664};
1665
1666static const struct {
1668 char *text;
1669} queue_results[] = {
1670 { QUEUE_UNKNOWN, "UNKNOWN" },
1671 { QUEUE_TIMEOUT, "TIMEOUT" },
1672 { QUEUE_JOINEMPTY,"JOINEMPTY" },
1673 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
1674 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
1675 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
1676 { QUEUE_FULL, "FULL" },
1677 { QUEUE_CONTINUE, "CONTINUE" },
1678 { QUEUE_WITHDRAW, "WITHDRAW" },
1680
1684};
1685
1686/*! \brief We define a custom "local user" structure because we
1687 * use it not only for keeping track of what is in use but
1688 * also for keeping track of who we're dialing.
1689 *
1690 * There are two "links" defined in this structure, q_next and call_next.
1691 * q_next links ALL defined callattempt structures into a linked list. call_next is
1692 * a link which allows for a subset of the callattempts to be traversed. This subset
1693 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
1694 * also is helpful so that queue logs are always accurate in the case where a call to
1695 * a member times out, especially if using the ringall strategy.
1696*/
1697
1702 char interface[256]; /*!< An Asterisk dial string (not a channel name) */
1705 /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
1707 /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
1709 /*! TRUE if the connected line update is blocked. */
1711 /*! TRUE if caller id is not available for connected line */
1712 unsigned int dial_callerid_absent:1;
1713 /*! TRUE if the call is still active */
1714 unsigned int stillgoing:1;
1716 /*! Original channel name. Must be freed. Could be NULL if allocation failed. */
1718};
1719
1720
1722 struct call_queue *parent; /*!< What queue is our parent */
1723 char moh[MAX_MUSICCLASS]; /*!< Name of musiconhold to be used */
1724 char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
1725 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
1726 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
1727 const char *predial_callee; /*!< Gosub app arguments for outgoing calls. NULL if not supplied. */
1728 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
1729 int pos; /*!< Where we are in the queue */
1730 int prio; /*!< Our priority */
1731 int last_pos_said; /*!< Last position we told the user */
1732 int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
1733 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
1734 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
1735 time_t last_pos; /*!< Last time we told the user their position */
1736 int opos; /*!< Where we started in the queue */
1737 int handled; /*!< Whether our call was handled */
1738 int pending; /*!< Non-zero if we are attempting to call a member */
1739 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
1740 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
1741 int raise_penalty; /*!< Float lower penalty members to a minimum penalty */
1742 int linpos; /*!< If using linear strategy, what position are we at? */
1743 int linwrapped; /*!< Is the linpos wrapped? */
1744 time_t start; /*!< When we started holding */
1745 time_t expire; /*!< When this entry should expire (time out of queue) */
1746 int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
1747 unsigned int withdraw:1; /*!< Should this call exit the queue at its next iteration? Used for QueueWithdrawCaller */
1748 char *withdraw_info; /*!< Optional info passed by the caller of QueueWithdrawCaller */
1749 struct ast_channel *chan; /*!< Our channel */
1750 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
1751 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
1752 struct queue_ent *next; /*!< The next queue entry */
1753};
1754
1755struct member {
1756 char interface[AST_CHANNEL_NAME]; /*!< Technology/Location to dial to reach this member*/
1757 char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
1758 char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
1759 char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */
1760 int state_id; /*!< Extension state callback id (if using hint) */
1761 char membername[80]; /*!< Member name to use in queue logs */
1762 int penalty; /*!< Are we a last resort? */
1763 int calls; /*!< Number of calls serviced by this member */
1764 int dynamic; /*!< Are we dynamically added? */
1765 int realtime; /*!< Is this member realtime? */
1766 int status; /*!< Status of queue member */
1767 int paused; /*!< Are we paused (not accepting calls)? */
1768 char reason_paused[80]; /*!< Reason of paused if member is paused */
1769 int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */
1770 int callcompletedinsl; /*!< Whether the current call was completed within service level */
1771 int wrapuptime; /*!< Wrapup Time */
1772 time_t starttime; /*!< The time at which the member answered the current caller. */
1773 time_t lastcall; /*!< When last successful call was hungup */
1774 time_t lastpause; /*!< When started the last pause */
1775 time_t logintime; /*!< The time when started the login */
1776 struct call_queue *lastqueue; /*!< Last queue we received a call */
1777 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
1778 unsigned int delme:1; /*!< Flag to delete entry on reload */
1779 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
1780 unsigned int ringinuse:1; /*!< Flag to ring queue members even if their status is 'inuse' */
1781};
1782
1792};
1793
1797};
1798
1799/* values used in multi-bit flags in call_queue */
1800#define ANNOUNCEHOLDTIME_ALWAYS 1
1801#define ANNOUNCEHOLDTIME_ONCE 2
1802#define QUEUE_EVENT_VARIABLES 3
1803
1805 int time; /*!< Number of seconds that need to pass before applying this rule */
1806 int max_value; /*!< The amount specified in the penalty rule for max penalty */
1807 int min_value; /*!< The amount specified in the penalty rule for min penalty */
1808 int raise_value; /*!< The amount specified in the penalty rule for min penalty */
1809 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
1810 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1811 int raise_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1812 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
1813};
1814
1815#define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
1816#define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
1817#define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
1818#define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
1819
1822 /*! Queue name */
1824 /*! Music on Hold class */
1826 /*! Announcement to play when call is answered */
1828 /*! Exit context */
1830 /*! Gosub to run upon member connection */
1832 /*! Default rule to use if none specified in call to Queue() */
1834 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
1836 /*! Sound file: "There are currently" (def. queue-thereare) */
1838 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
1840 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
1842 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
1844 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
1846 /*! Sound file: "minutes." (def. queue-minutes) */
1848 /*! Sound file: "minute." (def. queue-minute) */
1850 /*! Sound file: "seconds." (def. queue-seconds) */
1852 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
1854 /*! Sound file: Custom announce for caller, no default */
1856 /*! Sound file: "Hold time" (def. queue-reporthold) */
1859 /*! Sound files: Custom announce, no default */
1861 unsigned int dead:1;
1862 unsigned int ringinuse:1;
1863 unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
1864 unsigned int setinterfacevar:1;
1865 unsigned int setqueuevar:1;
1866 unsigned int setqueueentryvar:1;
1867 unsigned int reportholdtime:1;
1868 unsigned int wrapped:1;
1869 unsigned int timeoutrestart:1;
1870 unsigned int announceholdtime:2;
1871 unsigned int announceposition:3;
1872 unsigned int announceposition_only_up:1; /*!< Only announce position if it has improved */
1874 unsigned int realtime:1;
1875 unsigned int found:1;
1877 unsigned int autopausebusy:1;
1878 unsigned int autopauseunavail:1;
1881 int announcepositionlimit; /*!< How many positions we announce? */
1882 int announcefrequency; /*!< How often to announce their position */
1883 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
1884 int periodicannouncestartdelay; /*!< How long into the queue should the periodic accouncement start */
1885 int periodicannouncefrequency; /*!< How often to play periodic announcement */
1886 int numperiodicannounce; /*!< The number of periodic announcements configured */
1887 int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
1888 int roundingseconds; /*!< How many seconds do we round to? */
1889 int holdtime; /*!< Current avg holdtime, based on an exponential average */
1890 int talktime; /*!< Current avg talktime, based on the same exponential average */
1891 int callscompleted; /*!< Number of queue calls completed */
1892 int callsabandoned; /*!< Number of queue calls abandoned */
1893 int callsabandonedinsl; /*!< Number of queue calls abandoned in servicelevel */
1894 int servicelevel; /*!< seconds setting for servicelevel*/
1895 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
1896 char monfmt[8]; /*!< Format to use when recording calls */
1897 int count; /*!< How many entries */
1898 int maxlen; /*!< Max number of entries */
1899 int wrapuptime; /*!< Wrapup Time */
1900 int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
1901
1902 int retry; /*!< Retry calling everyone after this amount of time */
1903 int timeout; /*!< How long to wait for an answer */
1904 int weight; /*!< Respective weight */
1905 int autopause; /*!< Auto pause queue members if they fail to answer */
1906 int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
1907 int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
1908
1909 /* Queue strategy things */
1910 int rrpos; /*!< Round Robin - position */
1911 int memberdelay; /*!< Seconds to delay connecting member to caller */
1912 int autofill; /*!< Ignore the head call status and ring an available agent */
1913
1914 int log_restricted_caller_id:1; /*!< Whether log Restricted Caller ID */
1915
1916 struct ao2_container *members; /*!< Head of the list of members */
1917 struct queue_ent *head; /*!< Head of the list of callers */
1918 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
1919 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
1920};
1921
1923 char name[80];
1926};
1927
1929
1930static struct ao2_container *queues;
1931
1932static void update_realtime_members(struct call_queue *q);
1933static struct member *interface_exists(struct call_queue *q, const char *interface);
1934static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
1935static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime);
1936
1937static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
1938/*! \brief sets the QUEUESTATUS channel variable */
1939static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1940{
1941 int i;
1942
1943 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1944 if (queue_results[i].id == res) {
1945 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1946 return;
1947 }
1948 }
1949}
1950
1951static const char *int2strat(int strategy)
1952{
1953 int x;
1954
1955 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1956 if (strategy == strategies[x].strategy) {
1957 return strategies[x].name;
1958 }
1959 }
1960
1961 return "<unknown>";
1962}
1963
1964static int strat2int(const char *strategy)
1965{
1966 int x;
1967
1968 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1969 if (!strcasecmp(strategy, strategies[x].name)) {
1970 return strategies[x].strategy;
1971 }
1972 }
1973
1974 return -1;
1975}
1976
1977static int autopause2int(const char *autopause)
1978{
1979 int x;
1980 /*This 'double check' that default value is OFF */
1982 return QUEUE_AUTOPAUSE_OFF;
1983 }
1984
1985 /*This 'double check' is to ensure old values works */
1986 if(ast_true(autopause)) {
1987 return QUEUE_AUTOPAUSE_ON;
1988 }
1989
1990 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1991 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1992 return autopausesmodes[x].autopause;
1993 }
1994 }
1995
1996 /*This 'double check' that default value is OFF */
1997 return QUEUE_AUTOPAUSE_OFF;
1998}
1999
2000static int queue_hash_cb(const void *obj, const int flags)
2001{
2002 const struct call_queue *q = obj;
2003
2004 return ast_str_case_hash(q->name);
2005}
2006
2007static int queue_cmp_cb(void *obj, void *arg, int flags)
2008{
2009 struct call_queue *q = obj, *q2 = arg;
2010 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
2011}
2012
2013/*!
2014 * \brief Return wrapuptime
2015 *
2016 * This function checks if wrapuptime in member is set and return this value.
2017 * Otherwise return value the wrapuptime in the queue configuration
2018 * \return integer value
2019 */
2020static int get_wrapuptime(struct call_queue *q, struct member *member)
2021{
2022 if (member->wrapuptime) {
2023 return member->wrapuptime;
2024 }
2025 return q->wrapuptime;
2026}
2027
2028/*! \internal
2029 * \brief ao2_callback, Decreases queuepos of all followers with a queuepos greater than arg.
2030 * \param obj the member being acted on
2031 * \param arg pointer to an integer containing the position value that was removed and requires reduction for anything above
2032 * \param flag unused
2033 */
2034static int queue_member_decrement_followers(void *obj, void *arg, int flag)
2035{
2036 struct member *mem = obj;
2037 int *decrement_followers_after = arg;
2038
2039 if (mem->queuepos > *decrement_followers_after) {
2040 mem->queuepos--;
2041 }
2042
2043 return 0;
2044}
2045
2046/*! \internal
2047 * \brief ao2_callback, finds members in a queue marked for deletion and in a cascading fashion runs queue_member_decrement_followers
2048 * on them. This callback should always be ran before performing mass unlinking of delmarked members from queues.
2049 * \param obj member being acted on
2050 * \param arg pointer to the queue members are being removed from
2051 * \param flag unused
2052 */
2053static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
2054{
2055 struct member *mem = obj;
2056 struct call_queue *queue = arg;
2057 int rrpos = mem->queuepos;
2058
2059 if (mem->delme) {
2061 }
2062
2063 return 0;
2064}
2065
2066/*! \internal
2067 * \brief Use this to decrement followers during removal of a member
2068 * \param queue which queue the member is being removed from
2069 * \param mem which member is being removed from the queue
2070 */
2071static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
2072{
2073 int pos = mem->queuepos;
2074
2075 /* 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
2076 * who would have been next otherwise. */
2077 if (pos < queue->rrpos) {
2078 queue->rrpos--;
2079 }
2080
2082}
2083
2084#define queue_ref(q) ao2_bump(q)
2085#define queue_unref(q) ({ ao2_cleanup(q); NULL; })
2086#define queue_t_ref(q, tag) ao2_t_bump(q, tag)
2087#define queue_t_unref(q, tag) ({ ao2_t_cleanup(q, tag); NULL; })
2088#define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
2089#define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
2090
2091/*! \brief Set variables of queue */
2092static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
2093{
2094 char interfacevar[256]="";
2095 float sl = 0;
2096
2097 ao2_lock(q);
2098
2099 if (q->setqueuevar) {
2100 sl = 0;
2101 if (q->callscompleted > 0) {
2102 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
2103 }
2104
2105 snprintf(interfacevar, sizeof(interfacevar),
2106 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
2108
2109 ao2_unlock(q);
2110
2111 pbx_builtin_setvar_multiple(chan, interfacevar);
2112 } else {
2113 ao2_unlock(q);
2114 }
2115}
2116
2117/*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
2118static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
2119{
2120 struct queue_ent *cur;
2121
2122 if (!q || !new)
2123 return;
2124 if (prev) {
2125 cur = prev->next;
2126 prev->next = new;
2127 } else {
2128 cur = q->head;
2129 q->head = new;
2130 }
2131 new->next = cur;
2132
2133 /* every queue_ent must have a reference to it's parent call_queue, this
2134 * reference does not go away until the end of the queue_ent's life, meaning
2135 * that even when the queue_ent leaves the call_queue this ref must remain. */
2136 if (!new->parent) {
2137 queue_ref(q);
2138 new->parent = q;
2139 }
2140 new->pos = ++(*pos);
2141 new->opos = *pos;
2142}
2143
2145{
2147 RAII_VAR(struct ast_str *, channel_string, NULL, ast_free);
2148 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2149
2150 channel_string = ast_manager_build_channel_state_string(obj->snapshot);
2151 event_string = ast_manager_str_from_json_object(obj->blob, NULL);
2152 if (!channel_string || !event_string) {
2153 return NULL;
2154 }
2155
2157 "%s"
2158 "%s",
2159 ast_str_buffer(channel_string),
2160 ast_str_buffer(event_string));
2161}
2162
2164{
2165 return queue_channel_to_ami("QueueCallerJoin", message);
2166}
2167
2169{
2170 return queue_channel_to_ami("QueueCallerLeave", message);
2171}
2172
2174{
2175 return queue_channel_to_ami("QueueCallerAbandon", message);
2176}
2177
2178STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_join_type,
2180 );
2181STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_leave_type,
2183 );
2184STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_caller_abandon_type,
2186 );
2187
2189{
2190 struct ast_json_payload *payload = stasis_message_data(message);
2191 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2192
2193 event_string = ast_manager_str_from_json_object(payload->json, NULL);
2194 if (!event_string) {
2195 return NULL;
2196 }
2197
2199 "%s",
2200 ast_str_buffer(event_string));
2201}
2202
2204{
2205 return queue_member_to_ami("QueueMemberStatus", message);
2206}
2207
2209{
2210 return queue_member_to_ami("QueueMemberAdded", message);
2211}
2212
2214{
2215 return queue_member_to_ami("QueueMemberRemoved", message);
2216}
2217
2219{
2220 return queue_member_to_ami("QueueMemberPause", message);
2221}
2222
2224{
2225 return queue_member_to_ami("QueueMemberPenalty", message);
2226}
2227
2229{
2230 return queue_member_to_ami("QueueMemberRinginuse", message);
2231}
2232
2233STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_status_type,
2235 );
2236STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_added_type,
2238 );
2239STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_removed_type,
2241 );
2242STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_pause_type,
2244 );
2245STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_penalty_type,
2247 );
2248STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_member_ringinuse_type,
2250 );
2251
2253{
2256 struct ast_channel_snapshot *agent;
2257 RAII_VAR(struct ast_str *, caller_event_string, NULL, ast_free);
2258 RAII_VAR(struct ast_str *, agent_event_string, NULL, ast_free);
2259 RAII_VAR(struct ast_str *, event_string, NULL, ast_free);
2260
2262 if (caller) {
2263 caller_event_string = ast_manager_build_channel_state_string(caller);
2264 if (!caller_event_string) {
2265 ast_log(LOG_NOTICE, "No caller event string, bailing\n");
2266 return NULL;
2267 }
2268 }
2269
2270 agent = ast_multi_channel_blob_get_channel(obj, "agent");
2271 if (agent) {
2272 agent_event_string = ast_manager_build_channel_state_string_prefix(agent, "Dest");
2273 if (!agent_event_string) {
2274 ast_log(LOG_NOTICE, "No agent event string, bailing\n");
2275 return NULL;
2276 }
2277 }
2278
2280 if (!event_string) {
2281 return NULL;
2282 }
2283
2285 "%s"
2286 "%s"
2287 "%s",
2288 caller_event_string ? ast_str_buffer(caller_event_string) : "",
2289 agent_event_string ? ast_str_buffer(agent_event_string) : "",
2290 ast_str_buffer(event_string));
2291}
2292
2294{
2295 return queue_multi_channel_to_ami("AgentCalled", message);
2296}
2297
2299{
2300 return queue_multi_channel_to_ami("AgentConnect", message);
2301}
2302
2304{
2305 return queue_multi_channel_to_ami("AgentComplete", message);
2306}
2307
2309{
2310 return queue_multi_channel_to_ami("AgentDump", message);
2311}
2312
2314{
2315 return queue_multi_channel_to_ami("AgentRingNoAnswer", message);
2316}
2317
2318STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_called_type,
2320 );
2321STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_connect_type,
2323 );
2324STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_complete_type,
2326 );
2329 );
2330STASIS_MESSAGE_TYPE_DEFN_LOCAL(queue_agent_ringnoanswer_type,
2332 );
2333
2335 struct ast_channel_snapshot *caller_snapshot,
2336 struct ast_channel_snapshot *agent_snapshot,
2337 struct stasis_message_type *type, struct ast_json *blob)
2338{
2339 RAII_VAR(struct ast_multi_channel_blob *, payload, NULL, ao2_cleanup);
2340 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2341
2342 if (!type) {
2343 return;
2344 }
2345
2346 payload = ast_multi_channel_blob_create(blob);
2347 if (!payload) {
2348 return;
2349 }
2350
2351 if (caller_snapshot) {
2352 ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
2353 } else {
2354 ast_debug(1, "Empty caller_snapshot; sending incomplete event\n");
2355 }
2356
2357 if (agent_snapshot) {
2358 ast_multi_channel_blob_add_channel(payload, "agent", agent_snapshot);
2359 }
2360
2361 msg = stasis_message_create(type, payload);
2362 if (!msg) {
2363 return;
2364 }
2365
2366 stasis_publish(topic, msg);
2367}
2368
2369static void queue_publish_multi_channel_blob(struct ast_channel *caller, struct ast_channel *agent,
2370 struct stasis_message_type *type, struct ast_json *blob)
2371{
2372 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
2373 RAII_VAR(struct ast_channel_snapshot *, agent_snapshot, NULL, ao2_cleanup);
2374
2375 ast_channel_lock(caller);
2376 caller_snapshot = ast_channel_snapshot_create(caller);
2377 ast_channel_unlock(caller);
2378 ast_channel_lock(agent);
2379 agent_snapshot = ast_channel_snapshot_create(agent);
2380 ast_channel_unlock(agent);
2381
2382 if (!caller_snapshot || !agent_snapshot) {
2383 return;
2384 }
2385
2387 agent_snapshot, type, blob);
2388}
2389
2390/*!
2391 * \internal
2392 * \brief Publish the member blob.
2393 * \since 12.0.0
2394 *
2395 * \param type Stasis message type to publish.
2396 * \param blob The information being published.
2397 *
2398 * \note The json blob reference is passed to this function.
2399 */
2401{
2402 RAII_VAR(struct ast_json_payload *, payload, NULL, ao2_cleanup);
2403 RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
2404
2405 if (!blob || !type) {
2406 ast_json_unref(blob);
2407 return;
2408 }
2409
2410 payload = ast_json_payload_create(blob);
2411 ast_json_unref(blob);
2412 if (!payload) {
2413 return;
2414 }
2415
2416 msg = stasis_message_create(type, payload);
2417 if (!msg) {
2418 return;
2419 }
2420
2422}
2423
2424static struct ast_json *queue_member_blob_create(struct call_queue *q, struct member *mem)
2425{
2426 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}",
2427 "Queue", q->name,
2428 "MemberName", mem->membername,
2429 "Interface", mem->interface,
2430 "StateInterface", mem->state_interface,
2431 "Membership", (mem->dynamic ? "dynamic" : (mem->realtime ? "realtime" : "static")),
2432 "Penalty", mem->penalty,
2433 "CallsTaken", mem->calls,
2434 "LastCall", (int)mem->lastcall,
2435 "LastPause", (int)mem->lastpause,
2436 "LoginTime", (int)mem->logintime,
2437 "InCall", mem->starttime ? 1 : 0,
2438 "Status", mem->status,
2439 "Paused", mem->paused,
2440 "PausedReason", mem->reason_paused,
2441 "Ringinuse", mem->ringinuse,
2442 "Wrapuptime", mem->wrapuptime);
2443}
2444
2445/*! \brief Check if members are available
2446 *
2447 * This function checks to see if members are available to be called. If any member
2448 * is available, the function immediately returns 0. If no members are available,
2449 * then -1 is returned.
2450 */
2451static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
2452{
2453 struct member *member;
2454 struct ao2_iterator mem_iter;
2455
2456 ao2_lock(q);
2457 mem_iter = ao2_iterator_init(q->members, 0);
2458 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
2459 int penalty = member->penalty;
2460 if (raise_penalty != INT_MAX && penalty < raise_penalty) {
2461 ast_debug(4, "%s is having his penalty raised up from %d to %d\n", member->membername, penalty, raise_penalty);
2462 penalty = raise_penalty;
2463 }
2464 if ((max_penalty != INT_MAX && penalty > max_penalty) || (min_penalty != INT_MAX && penalty < min_penalty)) {
2465 if (conditions & QUEUE_EMPTY_PENALTY) {
2466 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
2467 continue;
2468 }
2469 }
2470
2471 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
2472 case AST_DEVICE_INVALID:
2473 if (conditions & QUEUE_EMPTY_INVALID) {
2474 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
2475 break;
2476 }
2477 goto default_case;
2479 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
2480 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
2481 break;
2482 }
2483 goto default_case;
2484 case AST_DEVICE_INUSE:
2485 if (conditions & QUEUE_EMPTY_INUSE) {
2486 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
2487 break;
2488 }
2489 goto default_case;
2490 case AST_DEVICE_RINGING:
2491 if (conditions & QUEUE_EMPTY_RINGING) {
2492 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
2493 break;
2494 }
2495 goto default_case;
2496 case AST_DEVICE_UNKNOWN:
2497 if (conditions & QUEUE_EMPTY_UNKNOWN) {
2498 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
2499 break;
2500 }
2501 /* Fall-through */
2502 default:
2503 default_case:
2504 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
2505 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
2506 break;
2507 } else if ((conditions & QUEUE_EMPTY_WRAPUP)
2508 && member->lastcall
2509 && get_wrapuptime(q, member)
2510 && (time(NULL) - get_wrapuptime(q, member) < member->lastcall)) {
2511 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n",
2512 member->membername, (int) (time(NULL) - member->lastcall), get_wrapuptime(q, member));
2513 break;
2514 } else {
2515 ao2_ref(member, -1);
2516 ao2_iterator_destroy(&mem_iter);
2517 ao2_unlock(q);
2518 ast_debug(4, "%s is available.\n", member->membername);
2519 return 0;
2520 }
2521 break;
2522 }
2523 }
2524 ao2_iterator_destroy(&mem_iter);
2525 ao2_unlock(q);
2526
2527 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
2528 /* member state still may be RINGING due to lag in event message - check again with device state */
2529 return get_member_status(q, max_penalty, min_penalty, raise_penalty, conditions, 1);
2530 }
2531 return -1;
2532}
2533
2534/*
2535 * A "pool" of member objects that calls are currently pending on. If an
2536 * agent is a member of multiple queues it's possible for that agent to be
2537 * called by each of the queues at the same time. This happens because device
2538 * state is slow to notify the queue app of one of it's member's being rung.
2539 * This "pool" allows us to track which members are currently being rung while
2540 * we wait on the device state change.
2541 */
2543#define MAX_CALL_ATTEMPT_BUCKETS 353
2544
2545static int pending_members_hash(const void *obj, const int flags)
2546{
2547 const struct member *object;
2548 const char *key;
2549
2550 switch (flags & OBJ_SEARCH_MASK) {
2551 case OBJ_SEARCH_KEY:
2552 key = obj;
2553 break;
2554 case OBJ_SEARCH_OBJECT:
2555 object = obj;
2556 key = object->interface;
2557 break;
2558 default:
2559 ast_assert(0);
2560 return 0;
2561 }
2562 return ast_str_case_hash(key);
2563}
2564
2565static int pending_members_cmp(void *obj, void *arg, int flags)
2566{
2567 const struct member *object_left = obj;
2568 const struct member *object_right = arg;
2569 const char *right_key = arg;
2570 int cmp;
2571
2572 switch (flags & OBJ_SEARCH_MASK) {
2573 case OBJ_SEARCH_OBJECT:
2574 right_key = object_right->interface;
2575 /* Fall through */
2576 case OBJ_SEARCH_KEY:
2577 cmp = strcasecmp(object_left->interface, right_key);
2578 break;
2580 /* Not supported by container. */
2581 ast_assert(0);
2582 return 0;
2583 default:
2584 cmp = 0;
2585 break;
2586 }
2587 if (cmp) {
2588 return 0;
2589 }
2590 return CMP_MATCH;
2591}
2592
2593static void pending_members_remove(struct member *mem)
2594{
2595 ast_debug(3, "Removed %s from pending_members\n", mem->membername);
2597}
2598
2599/*! \brief set a member's status based on device state of that member's state_interface.
2600 *
2601 * Lock interface list find sc, iterate through each queues queue_member list for member to
2602 * update state inside queues
2603*/
2604static void update_status(struct call_queue *q, struct member *m, const int status)
2605{
2606 if (m->status != status) {
2607 /* If this member has transitioned to being available then update their queue
2608 * information. If they are currently in a call then the leg to the agent will be
2609 * considered done and the call finished.
2610 */
2613 }
2614
2615 m->status = status;
2616
2617 /* Remove the member from the pending members pool only when the status changes.
2618 * This is not done unconditionally because we can occasionally see multiple
2619 * device state notifications of not in use after a previous call has ended,
2620 * including after we have initiated a new call. This is more likely to
2621 * happen when there is latency in the connection to the member.
2622 */
2624
2625 queue_publish_member_blob(queue_member_status_type(), queue_member_blob_create(q, m));
2626 }
2627}
2628
2629/*!
2630 * \internal
2631 * \brief Determine if a queue member is available
2632 * \retval 1 if the member is available
2633 * \retval 0 if the member is not available
2634 */
2635static int is_member_available(struct call_queue *q, struct member *mem)
2636{
2637 int available = 0;
2638 int wrapuptime;
2639
2640 switch (mem->status) {
2641 case AST_DEVICE_INVALID:
2643 break;
2644 case AST_DEVICE_INUSE:
2645 case AST_DEVICE_BUSY:
2646 case AST_DEVICE_RINGING:
2648 case AST_DEVICE_ONHOLD:
2649 if (!mem->ringinuse) {
2650 break;
2651 }
2652 /* else fall through */
2654 case AST_DEVICE_UNKNOWN:
2655 if (!mem->paused) {
2656 available = 1;
2657 }
2658 break;
2659 }
2660
2661 /* Let wrapuptimes override device state availability */
2662 wrapuptime = get_wrapuptime(q, mem);
2663 if (mem->lastcall && wrapuptime && (time(NULL) - wrapuptime < mem->lastcall)) {
2664 available = 0;
2665 }
2666 return available;
2667}
2668
2669/*! \brief set a member's status based on device state of that member's interface*/
2670static void device_state_cb(void *unused, struct stasis_subscription *sub, struct stasis_message *msg)
2671{
2672 struct ao2_iterator miter, qiter;
2673 struct ast_device_state_message *dev_state;
2674 struct member *m;
2675 struct call_queue *q;
2676 char interface[80], *slash_pos;
2677 int found = 0; /* Found this member in any queue */
2678 int found_member; /* Found this member in this queue */
2679 int avail = 0; /* Found an available member in this queue */
2680
2682 return;
2683 }
2684
2685 dev_state = stasis_message_data(msg);
2686 if (dev_state->eid) {
2687 /* ignore non-aggregate states */
2688 return;
2689 }
2690
2691 qiter = ao2_iterator_init(queues, 0);
2692 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
2693 ao2_lock(q);
2694
2695 avail = 0;
2696 found_member = 0;
2697 miter = ao2_iterator_init(q->members, 0);
2698 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2699 if (!found_member) {
2700 ast_copy_string(interface, m->state_interface, sizeof(interface));
2701
2702 if ((slash_pos = strchr(interface, '/'))) {
2703 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
2704 *slash_pos = '\0';
2705 }
2706 }
2707
2708 if (!strcasecmp(interface, dev_state->device)) {
2709 found_member = 1;
2710 update_status(q, m, dev_state->state);
2711 }
2712 }
2713
2714 /* check every member until we find one NOT_INUSE */
2715 if (!avail) {
2716 avail = is_member_available(q, m);
2717 }
2718 if (avail && found_member) {
2719 /* early exit as we've found an available member and the member of interest */
2720 ao2_ref(m, -1);
2721 break;
2722 }
2723 }
2724
2725 if (found_member) {
2726 found = 1;
2727 if (avail) {
2729 } else {
2731 }
2732 }
2733
2734 ao2_iterator_destroy(&miter);
2735
2736 ao2_unlock(q);
2737 queue_t_unref(q, "Done with iterator");
2738 }
2739 ao2_iterator_destroy(&qiter);
2740
2741 if (found) {
2742 ast_debug(1, "Device '%s' changed to state '%u' (%s)\n",
2743 dev_state->device,
2744 dev_state->state,
2745 ast_devstate2str(dev_state->state));
2746 } else {
2747 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",
2748 dev_state->device,
2749 dev_state->state,
2750 ast_devstate2str(dev_state->state));
2751 }
2752
2753 return;
2754}
2755
2756/*! \brief Helper function which converts from extension state to device state values */
2758{
2759 switch (state) {
2762 break;
2765 break;
2766 case AST_EXTENSION_BUSY:
2768 break;
2771 break;
2774 break;
2777 break;
2780 break;
2783 break;
2786 default:
2788 break;
2789 }
2790
2791 return state;
2792}
2793
2794/*!
2795 * \brief Returns if one context includes another context
2796 *
2797 * \param parent Parent context to search for child
2798 * \param child Context to check for inclusion in parent
2799 *
2800 * This function recursively checks if the context child is included in the context parent.
2801 *
2802 * \retval 1 if child is included in parent
2803 * \retval 0 if not
2804 */
2805static int context_included(const char *parent, const char *child);
2806static int context_included(const char *parent, const char *child)
2807{
2808 struct ast_context *c = NULL;
2809
2810 c = ast_context_find(parent);
2811 if (!c) {
2812 /* well, if parent doesn't exist, how can the child be included in it? */
2813 return 0;
2814 }
2815 if (!strcmp(ast_get_context_name(c), parent)) {
2816 /* found the context of the hint app_queue is using. Now, see
2817 if that context includes the one that just changed state */
2818 struct ast_include *inc = NULL;
2819
2820 while ((inc = (struct ast_include*) ast_walk_context_includes(c, inc))) {
2821 const char *includename = ast_get_include_name(inc);
2822 if (!strcasecmp(child, includename)) {
2823 return 1;
2824 }
2825 /* recurse on this context, for nested includes. The
2826 PBX extension parser will prevent infinite recursion. */
2827 if (context_included(includename, child)) {
2828 return 1;
2829 }
2830 }
2831 }
2832 return 0;
2833}
2834
2835static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
2836{
2837 struct ao2_iterator miter, qiter;
2838 struct member *m;
2839 struct call_queue *q;
2840 int state = info->exten_state;
2841 int found = 0, device_state = extensionstate2devicestate(state);
2842
2843 /* only interested in extension state updates involving device states */
2844 if (info->reason != AST_HINT_UPDATE_DEVICE) {
2845 return 0;
2846 }
2847
2848 qiter = ao2_iterator_init(queues, 0);
2849 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2850 ao2_lock(q);
2851
2852 miter = ao2_iterator_init(q->members, 0);
2853 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2854 if (!strcmp(m->state_exten, exten) &&
2856 /* context could be included in m->state_context. We need to check. */
2857 found = 1;
2858 update_status(q, m, device_state);
2859 }
2860 }
2861 ao2_iterator_destroy(&miter);
2862
2863 ao2_unlock(q);
2864 queue_t_unref(q, "Done with iterator");
2865 }
2866 ao2_iterator_destroy(&qiter);
2867
2868 if (found) {
2869 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2870 } else {
2871 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",
2872 exten, context, device_state, ast_devstate2str(device_state));
2873 }
2874
2875 return 0;
2876}
2877
2878/*! \brief Return the current state of a member */
2879static int get_queue_member_status(struct member *cur)
2880{
2882}
2883
2884static void destroy_queue_member_cb(void *obj)
2885{
2886 struct member *mem = obj;
2887
2888 if (mem->state_id != -1) {
2890 }
2891}
2892
2893/*! \brief allocate space for new queue member and set fields based on parameters passed */
2894static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse, int wrapuptime)
2895{
2896 struct member *cur;
2897
2898 if ((cur = ao2_alloc(sizeof(*cur), destroy_queue_member_cb))) {
2899 cur->ringinuse = ringinuse;
2900 cur->penalty = penalty;
2901 cur->paused = paused;
2902 cur->wrapuptime = wrapuptime;
2903 if (paused) {
2904 time(&cur->lastpause); /* Update time of last pause */
2905 }
2906 time(&cur->logintime);
2907 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2910 } else {
2912 }
2914 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2915 } else {
2916 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2917 }
2918 if (!strchr(cur->interface, '/')) {
2919 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2920 }
2921 if (!strncmp(cur->state_interface, "hint:", 5)) {
2922 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2923 char *exten = strsep(&context, "@") + 5;
2924
2925 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2926 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2927
2929 } else {
2930 cur->state_id = -1;
2931 }
2932 cur->status = get_queue_member_status(cur);
2933 }
2934
2935 return cur;
2936}
2937
2938
2939static int compress_char(const char c)
2940{
2941 if (c < 32) {
2942 return 0;
2943 } else if (c > 96) {
2944 return c - 64;
2945 }
2946 return c - 32;
2947}
2948
2949static int member_hash_fn(const void *obj, const int flags)
2950{
2951 const struct member *mem = obj;
2952 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2953 const char *chname = strchr(interface, '/');
2954 int ret = 0, i;
2955
2956 if (!chname) {
2957 chname = interface;
2958 }
2959 for (i = 0; i < 5 && chname[i]; i++) {
2960 ret += compress_char(chname[i]) << (i * 6);
2961 }
2962 return ret;
2963}
2964
2965static int member_cmp_fn(void *obj1, void *obj2, int flags)
2966{
2967 struct member *mem1 = obj1;
2968 struct member *mem2 = obj2;
2969 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2970
2971 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2972}
2973
2974/*!
2975 * \brief Initialize Queue default values.
2976 * \note the queue's lock must be held before executing this function
2977*/
2978static void init_queue(struct call_queue *q)
2979{
2980 int i;
2981 struct penalty_rule *pr_iter;
2982
2983 q->dead = 0;
2984 q->retry = DEFAULT_RETRY;
2986 q->maxlen = 0;
2987
2988 ast_string_field_set(q, announce, "");
2990 ast_string_field_set(q, membergosub, "");
2991 ast_string_field_set(q, defaultrule, "");
2992
2993 q->announcefrequency = 0;
2995 q->announceholdtime = 1;
2997 q->announcepositionlimit = 10; /* Default 10 positions */
2998 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2999 q->roundingseconds = 0; /* Default - don't announce seconds */
3000 q->servicelevel = 0;
3001 q->ringinuse = 1;
3003 q->setinterfacevar = 0;
3004 q->setqueuevar = 0;
3005 q->setqueueentryvar = 0;
3007 q->monfmt[0] = '\0';
3008 q->reportholdtime = 0;
3009 q->wrapuptime = 0;
3010 q->penaltymemberslimit = 0;
3011 q->joinempty = 0;
3012 q->leavewhenempty = 0;
3013 q->memberdelay = 0;
3014 q->weight = 0;
3015 q->timeoutrestart = 0;
3019 q->numperiodicannounce = 0;
3022 q->autopausebusy = 0;
3023 q->autopauseunavail = 0;
3025 q->autopausedelay = 0;
3027 if (!q->members) {
3029 /* linear strategy depends on order, so we have to place all members in a list */
3031 } else {
3034 }
3035 }
3036 q->found = 1;
3037
3038 ast_string_field_set(q, moh, "");
3039 ast_string_field_set(q, sound_next, "queue-youarenext");
3040 ast_string_field_set(q, sound_thereare, "queue-thereare");
3041 ast_string_field_set(q, sound_calls, "queue-callswaiting");
3042 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
3043 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
3044 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
3045 ast_string_field_set(q, sound_minutes, "queue-minutes");
3046 ast_string_field_set(q, sound_minute, "queue-minute");
3047 ast_string_field_set(q, sound_seconds, "queue-seconds");
3048 ast_string_field_set(q, sound_thanks, "queue-thankyou");
3049 ast_string_field_set(q, sound_callerannounce, "");
3050 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
3051
3052 if (!q->sound_periodicannounce[0]) {
3054 }
3055
3056 if (q->sound_periodicannounce[0]) {
3057 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
3058 }
3059
3060 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3061 if (q->sound_periodicannounce[i]) {
3062 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
3063 }
3064 }
3065
3066 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
3067 ast_free(pr_iter);
3068 }
3069
3070 /* On restart assume no members are available.
3071 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
3072 *
3073 * This seems counter intuitive, but is required to light a BLF
3074 * AST_DEVICE_INUSE indicates no members are available.
3075 * AST_DEVICE_NOT_INUSE indicates a member is available.
3076 */
3078}
3079
3080static void clear_queue(struct call_queue *q)
3081{
3082 q->holdtime = 0;
3083 q->callscompleted = 0;
3084 q->callsabandoned = 0;
3085 q->callscompletedinsl = 0;
3086 q->callsabandonedinsl = 0;
3087 q->talktime = 0;
3088
3089 if (q->members) {
3090 struct member *mem;
3091 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3092 while ((mem = ao2_iterator_next(&mem_iter))) {
3093 mem->calls = 0;
3094 mem->callcompletedinsl = 0;
3095 mem->lastcall = 0;
3096 mem->starttime = 0;
3097 ao2_ref(mem, -1);
3098 }
3099 ao2_iterator_destroy(&mem_iter);
3100 }
3101}
3102
3103/*!
3104 * \brief Change queue penalty by adding rule.
3105 *
3106 * Check rule for errors with time or formatting, see if rule is relative to rest
3107 * of queue, iterate list of rules to find correct insertion point, insert and return.
3108 * \retval -1 on failure
3109 * \retval 0 on success
3110 * \note Call this with the rule_lists locked
3111*/
3112static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
3113{
3114 char *timestr, *maxstr, *minstr, *raisestr, *contentdup;
3115 struct penalty_rule *rule = NULL, *rule_iter;
3116 struct rule_list *rl_iter;
3117 int penaltychangetime, inserted = 0;
3118
3119 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
3120 return -1;
3121 }
3122
3123 contentdup = ast_strdupa(content);
3124
3125 if (!(maxstr = strchr(contentdup, ','))) {
3126 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
3127 ast_free(rule);
3128 return -1;
3129 }
3130
3131 *maxstr++ = '\0';
3132 if ((minstr = strchr(maxstr,','))) {
3133 *minstr++ = '\0';
3134 if ((raisestr = strchr(minstr,','))) {
3135 *raisestr++ = '\0';
3136 }
3137 } else {
3138 raisestr = NULL;
3139 }
3140
3141 timestr = contentdup;
3142 if ((penaltychangetime = atoi(timestr)) < 0) {
3143 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
3144 ast_free(rule);
3145 return -1;
3146 }
3147
3148 rule->time = penaltychangetime;
3149
3150 /* The last check will evaluate true if either no penalty change is indicated for a given rule
3151 * OR if a min penalty change is indicated but no max penalty change is */
3152 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
3153 rule->max_relative = 1;
3154 }
3155
3156 rule->max_value = atoi(maxstr);
3157
3158 if (!ast_strlen_zero(minstr)) {
3159 if (*minstr == '+' || *minstr == '-') {
3160 rule->min_relative = 1;
3161 }
3162 rule->min_value = atoi(minstr);
3163 } else { /*there was no minimum specified, so assume this means no change*/
3164 rule->min_relative = 1;
3165 }
3166
3167 if (!ast_strlen_zero(raisestr)) {
3168 if (*raisestr == '+' || *raisestr == '-') {
3169 rule->raise_relative = 1;
3170 }
3171 rule->raise_value = atoi(raisestr);
3172 } else { /*there was no raise specified, so assume this means no change*/
3173 rule->raise_relative = 1;
3174 }
3175
3176 /*We have the rule made, now we need to insert it where it belongs*/
3177 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
3178 if (strcasecmp(rl_iter->name, list_name)) {
3179 continue;
3180 }
3181
3182 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
3183 if (rule->time < rule_iter->time) {
3185 inserted = 1;
3186 break;
3187 }
3188 }
3190
3191 if (!inserted) {
3192 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
3193 inserted = 1;
3194 }
3195
3196 break;
3197 }
3198
3199 if (!inserted) {
3200 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
3201 ast_free(rule);
3202 return -1;
3203 }
3204 return 0;
3205}
3206
3207/*!
3208 * \brief Load queue rules from realtime.
3209 *
3210 * Check rule for errors with time or formatting, see if rule is relative to rest
3211 * of queue, iterate list of rules to find correct insertion point, insert and return.
3212 * \retval -1 on failure
3213 * \retval 0 on success
3214 * \note Call this with the rule_lists locked
3215*/
3216static int load_realtime_rules(void)
3217{
3218 struct ast_config *cfg;
3219 struct rule_list *rl_iter, *new_rl;
3220 struct penalty_rule *pr_iter;
3221 char *rulecat = NULL;
3222
3223 if (!ast_check_realtime("queue_rules")) {
3224 ast_log(LOG_WARNING, "Missing \"queue_rules\" in extconfig.conf\n");
3225 return 0;
3226 }
3227 if (!(cfg = ast_load_realtime_multientry("queue_rules", "rule_name LIKE", "%", SENTINEL))) {
3228 ast_log(LOG_WARNING, "Failed to load queue rules from realtime\n");
3229 return 0;
3230 }
3231 while ((rulecat = ast_category_browse(cfg, rulecat))) {
3232 const char *timestr, *maxstr, *minstr, *raisestr, *rule_name;
3233 int penaltychangetime, rule_exists = 0, inserted = 0;
3234 int max_penalty = 0, min_penalty = 0, raise_penalty = 0;
3235 int min_relative = 0, max_relative = 0, raise_relative = 0;
3236 struct penalty_rule *new_penalty_rule = NULL;
3237
3238 rule_name = ast_variable_retrieve(cfg, rulecat, "rule_name");
3239 if (ast_strlen_zero(rule_name)) {
3240 continue;
3241 }
3242
3243 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
3244 if (!(strcasecmp(rl_iter->name, rule_name))) {
3245 rule_exists = 1;
3246 new_rl = rl_iter;
3247 break;
3248 }
3249 }
3250 if (!rule_exists) {
3251 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
3252 ast_config_destroy(cfg);
3253 return -1;
3254 }
3255 ast_copy_string(new_rl->name, rule_name, sizeof(new_rl->name));
3257 }
3258 timestr = ast_variable_retrieve(cfg, rulecat, "time");
3259 if (!(timestr) || sscanf(timestr, "%30d", &penaltychangetime) != 1) {
3260 ast_log(LOG_NOTICE, "Failed to parse time (%s) for one of the %s rules, skipping it\n",
3261 (ast_strlen_zero(timestr) ? "invalid value" : timestr), rule_name);
3262 continue;
3263 }
3264 if (!(new_penalty_rule = ast_calloc(1, sizeof(*new_penalty_rule)))) {
3265 ast_config_destroy(cfg);
3266 return -1;
3267 }
3268 if (!(maxstr = ast_variable_retrieve(cfg, rulecat, "max_penalty")) ||
3269 ast_strlen_zero(maxstr) || sscanf(maxstr, "%30d", &max_penalty) != 1) {
3270 max_penalty = 0;
3271 max_relative = 1;
3272 } else {
3273 if (*maxstr == '+' || *maxstr == '-') {
3274 max_relative = 1;
3275 }
3276 }
3277 if (!(minstr = ast_variable_retrieve(cfg, rulecat, "min_penalty")) ||
3278 ast_strlen_zero(minstr) || sscanf(minstr, "%30d", &min_penalty) != 1) {
3279 min_penalty = 0;
3280 min_relative = 1;
3281 } else {
3282 if (*minstr == '+' || *minstr == '-') {
3283 min_relative = 1;
3284 }
3285 }
3286 if (!(raisestr = ast_variable_retrieve(cfg, rulecat, "raise_penalty")) ||
3287 ast_strlen_zero(raisestr) || sscanf(raisestr, "%30d", &raise_penalty) != 1) {
3288 raise_penalty = 0;
3289 raise_relative = 1;
3290 } else {
3291 if (*raisestr == '+' || *raisestr == '-') {
3292 raise_relative = 1;
3293 }
3294 }
3295 new_penalty_rule->time = penaltychangetime;
3296 new_penalty_rule->max_relative = max_relative;
3297 new_penalty_rule->max_value = max_penalty;
3298 new_penalty_rule->min_relative = min_relative;
3299 new_penalty_rule->min_value = min_penalty;
3300 new_penalty_rule->raise_relative = raise_relative;
3301 new_penalty_rule->raise_value = raise_penalty;
3302 AST_LIST_TRAVERSE_SAFE_BEGIN(&new_rl->rules, pr_iter, list) {
3303 if (new_penalty_rule->time < pr_iter->time) {
3304 AST_LIST_INSERT_BEFORE_CURRENT(new_penalty_rule, list);
3305 inserted = 1;
3306 }
3307 }
3309 if (!inserted) {
3310 AST_LIST_INSERT_TAIL(&new_rl->rules, new_penalty_rule, list);
3311 }
3312 }
3313
3314 ast_config_destroy(cfg);
3315 return 0;
3316}
3317
3318static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
3319{
3320 char *value_copy = ast_strdupa(value);
3321 char *option = NULL;
3322 while ((option = strsep(&value_copy, ","))) {
3323 if (!strcasecmp(option, "paused")) {
3324 *empty |= QUEUE_EMPTY_PAUSED;
3325 } else if (!strcasecmp(option, "penalty")) {
3326 *empty |= QUEUE_EMPTY_PENALTY;
3327 } else if (!strcasecmp(option, "inuse")) {
3328 *empty |= QUEUE_EMPTY_INUSE;
3329 } else if (!strcasecmp(option, "ringing")) {
3330 *empty |= QUEUE_EMPTY_RINGING;
3331 } else if (!strcasecmp(option, "invalid")) {
3332 *empty |= QUEUE_EMPTY_INVALID;
3333 } else if (!strcasecmp(option, "wrapup")) {
3334 *empty |= QUEUE_EMPTY_WRAPUP;
3335 } else if (!strcasecmp(option, "unavailable")) {
3336 *empty |= QUEUE_EMPTY_UNAVAILABLE;
3337 } else if (!strcasecmp(option, "unknown")) {
3338 *empty |= QUEUE_EMPTY_UNKNOWN;
3339 } else if (!strcasecmp(option, "loose")) {
3341 } else if (!strcasecmp(option, "strict")) {
3343 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
3345 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
3346 *empty = 0;
3347 } else {
3348 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
3349 }
3350 }
3351}
3352
3353/*! \brief Configure a queue parameter.
3354 *
3355 * The failunknown flag is set for config files (and static realtime) to show
3356 * errors for unknown parameters. It is cleared for dynamic realtime to allow
3357 * extra fields in the tables.
3358 * \note For error reporting, line number is passed for .conf static configuration,
3359 * for Realtime queues, linenum is -1.
3360*/
3361static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
3362{
3363 if (!strcasecmp(param, "musicclass") ||
3364 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
3365 ast_string_field_set(q, moh, val);
3366 } else if (!strcasecmp(param, "announce")) {
3367 ast_string_field_set(q, announce, val);
3368 } else if (!strcasecmp(param, "context")) {
3370 } else if (!strcasecmp(param, "timeout")) {
3371 q->timeout = atoi(val);
3372 if (q->timeout < 0) {
3374 }
3375 } else if (!strcasecmp(param, "ringinuse")) {
3376 q->ringinuse = ast_true(val);
3377 } else if (!strcasecmp(param, "setinterfacevar")) {
3379 } else if (!strcasecmp(param, "setqueuevar")) {
3380 q->setqueuevar = ast_true(val);
3381 } else if (!strcasecmp(param, "setqueueentryvar")) {
3383 } else if (!strcasecmp(param, "monitor-format")) {
3384 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
3385 } else if (!strcasecmp(param, "membergosub")) {
3386 ast_string_field_set(q, membergosub, val);
3387 } else if (!strcasecmp(param, "queue-youarenext")) {
3388 ast_string_field_set(q, sound_next, val);
3389 } else if (!strcasecmp(param, "queue-thereare")) {
3390 ast_string_field_set(q, sound_thereare, val);
3391 } else if (!strcasecmp(param, "queue-callswaiting")) {
3392 ast_string_field_set(q, sound_calls, val);
3393 } else if (!strcasecmp(param, "queue-quantity1")) {
3394 ast_string_field_set(q, queue_quantity1, val);
3395 } else if (!strcasecmp(param, "queue-quantity2")) {
3396 ast_string_field_set(q, queue_quantity2, val);
3397 } else if (!strcasecmp(param, "queue-holdtime")) {
3398 ast_string_field_set(q, sound_holdtime, val);
3399 } else if (!strcasecmp(param, "queue-minutes")) {
3400 ast_string_field_set(q, sound_minutes, val);
3401 } else if (!strcasecmp(param, "queue-minute")) {
3402 ast_string_field_set(q, sound_minute, val);
3403 } else if (!strcasecmp(param, "queue-seconds")) {
3404 ast_string_field_set(q, sound_seconds, val);
3405 } else if (!strcasecmp(param, "queue-thankyou")) {
3406 ast_string_field_set(q, sound_thanks, val);
3407 } else if (!strcasecmp(param, "queue-callerannounce")) {
3408 ast_string_field_set(q, sound_callerannounce, val);
3409 } else if (!strcasecmp(param, "queue-reporthold")) {
3410 ast_string_field_set(q, sound_reporthold, val);
3411 } else if (!strcasecmp(param, "announce-frequency")) {
3412 q->announcefrequency = atoi(val);
3413 } else if (!strcasecmp(param, "announce-to-first-user")) {
3415 } else if (!strcasecmp(param, "min-announce-frequency")) {
3416 q->minannouncefrequency = atoi(val);
3417 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
3418 } else if (!strcasecmp(param, "announce-round-seconds")) {
3419 q->roundingseconds = atoi(val);
3420 /* Rounding to any other values just doesn't make sense... */
3421 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
3422 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
3423 if (linenum >= 0) {
3424 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3425 "using 0 instead for queue '%s' at line %d of queues.conf\n",
3426 val, param, q->name, linenum);
3427 } else {
3428 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
3429 "using 0 instead for queue '%s'\n", val, param, q->name);
3430 }
3431 q->roundingseconds=0;
3432 }
3433 } else if (!strcasecmp(param, "announce-holdtime")) {
3434 if (!strcasecmp(val, "once")) {
3436 } else if (ast_true(val)) {
3438 } else {
3439 q->announceholdtime = 0;
3440 }
3441 } else if (!strcasecmp(param, "announce-position")) {
3442 if (!strcasecmp(val, "limit")) {
3444 } else if (!strcasecmp(val, "more")) {
3446 } else if (ast_true(val)) {
3448 } else {
3450 }
3451 } else if (!strcasecmp(param, "announce-position-only-up")) {
3453 } else if (!strcasecmp(param, "announce-position-limit")) {
3454 q->announcepositionlimit = atoi(val);
3455 } else if (!strcasecmp(param, "periodic-announce")) {
3456 if (strchr(val, ',')) {
3457 char *s, *buf = ast_strdupa(val);
3458 unsigned int i = 0;
3459
3460 while ((s = strsep(&buf, ",|"))) {
3461 if (!q->sound_periodicannounce[i]) {
3463 }
3464 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
3465 i++;
3466 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
3467 break;
3468 }
3469 }
3470 q->numperiodicannounce = i;
3471 } else {
3472 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
3473 q->numperiodicannounce = 1;
3474 }
3475 } else if (!strcasecmp(param, "periodic-announce-startdelay")) {
3477 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
3478 q->periodicannouncefrequency = atoi(val);
3479 } else if (!strcasecmp(param, "relative-periodic-announce")) {
3481 } else if (!strcasecmp(param, "random-periodic-announce")) {
3483 } else if (!strcasecmp(param, "retry")) {
3484 q->retry = atoi(val);
3485 if (q->retry <= 0) {
3486 q->retry = DEFAULT_RETRY;
3487 }
3488 } else if (!strcasecmp(param, "wrapuptime")) {
3489 q->wrapuptime = atoi(val);
3490 } else if (!strcasecmp(param, "penaltymemberslimit")) {
3491 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
3492 q->penaltymemberslimit = 0;
3493 }
3494 } else if (!strcasecmp(param, "autofill")) {
3495 q->autofill = ast_true(val);
3496 } else if (!strcasecmp(param, "autopause")) {
3498 } else if (!strcasecmp(param, "autopausedelay")) {
3499 q->autopausedelay = atoi(val);
3500 } else if (!strcasecmp(param, "autopausebusy")) {
3502 } else if (!strcasecmp(param, "autopauseunavail")) {
3504 } else if (!strcasecmp(param, "maxlen")) {
3505 q->maxlen = atoi(val);
3506 if (q->maxlen < 0) {
3507 q->maxlen = 0;
3508 }
3509 } else if (!strcasecmp(param, "servicelevel")) {
3510 q->servicelevel= atoi(val);
3511 } else if (!strcasecmp(param, "strategy")) {
3512 int strategy;
3513
3514 /* We are a static queue and already have set this, no need to do it again */
3515 if (failunknown) {
3516 return;
3517 }
3519 if (strategy < 0) {
3520 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3521 val, q->name);
3523 }
3524 if (strategy == q->strategy) {
3525 return;
3526 }
3528 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
3529 return;
3530 }
3531 q->strategy = strategy;
3532 } else if (!strcasecmp(param, "joinempty")) {
3534 } else if (!strcasecmp(param, "leavewhenempty")) {
3536 } else if (!strcasecmp(param, "reportholdtime")) {
3538 } else if (!strcasecmp(param, "memberdelay")) {
3539 q->memberdelay = atoi(val);
3540 } else if (!strcasecmp(param, "weight")) {
3541 q->weight = atoi(val);
3542 } else if (!strcasecmp(param, "timeoutrestart")) {
3544 } else if (!strcasecmp(param, "defaultrule")) {
3545 ast_string_field_set(q, defaultrule, val);
3546 } else if (!strcasecmp(param, "timeoutpriority")) {
3547 if (!strcasecmp(val, "conf")) {
3549 } else {
3551 }
3552 } else if (!strcasecmp(param, "log-restricted-caller-id")) {
3554 } else if (failunknown) {
3555 if (linenum >= 0) {
3556 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
3557 q->name, param, linenum);
3558 } else {
3559 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
3560 }
3561 }
3562}
3563
3564
3565#define QUEUE_PAUSED_DEVSTATE AST_DEVICE_INUSE
3566#define QUEUE_UNPAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3567#define QUEUE_UNKNOWN_PAUSED_DEVSTATE AST_DEVICE_NOT_INUSE
3568
3569/*! \internal
3570 * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
3571 * This adds round robin queue position data for a fresh member as well as links it.
3572 * \param queue Which queue the member is being added to
3573 * \param mem Which member is being added to the queue
3574 */
3575static void member_add_to_queue(struct call_queue *queue, struct member *mem)
3576{
3577 ao2_lock(queue->members);
3578 mem->queuepos = ao2_container_count(queue->members);
3579 ao2_link(queue->members, mem);
3581 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", queue->name, mem->interface);
3582 ao2_unlock(queue->members);
3583}
3584
3585/*! \internal
3586 * \brief If removing a single member from a queue, use this function instead of ao2_unlinking.
3587 * This will perform round robin queue position reordering for the remaining members.
3588 * \param queue Which queue the member is being removed from
3589 * \param mem Which member is being removed from the queue
3590 */
3591static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
3592{
3594 ao2_lock(queue->members);
3597 ao2_unlink(queue->members, mem);
3598 ao2_unlock(queue->members);
3599}
3600
3601/*!
3602 * \brief Find rt member record to update otherwise create one.
3603 *
3604 * Search for member in queue, if found update penalty/paused state,
3605 * if no member exists create one flag it as a RT member and add to queue member list.
3606*/
3607static void rt_handle_member_record(struct call_queue *q, char *category, struct ast_config *member_config)
3608{
3609 struct member *m;
3610 struct ao2_iterator mem_iter;
3611 int penalty = 0;
3612 int paused = 0;
3613 int found = 0;
3614 int wrapuptime = 0;
3615 int ringinuse = q->ringinuse;
3616
3617 const char *config_val;
3618 const char *interface = ast_variable_retrieve(member_config, category, "interface");
3619 const char *rt_uniqueid = ast_variable_retrieve(member_config, category, "uniqueid");
3620 const char *membername = S_OR(ast_variable_retrieve(member_config, category, "membername"), interface);
3621 const char *state_interface = S_OR(ast_variable_retrieve(member_config, category, "state_interface"), interface);
3622 const char *penalty_str = ast_variable_retrieve(member_config, category, "penalty");
3623 const char *paused_str = ast_variable_retrieve(member_config, category, "paused");
3624 const char *wrapuptime_str = ast_variable_retrieve(member_config, category, "wrapuptime");
3625 const char *reason_paused = ast_variable_retrieve(member_config, category, "reason_paused");
3626
3627 if (ast_strlen_zero(rt_uniqueid)) {
3628 ast_log(LOG_WARNING, "Realtime field 'uniqueid' is empty for member %s\n",
3629 S_OR(membername, "NULL"));
3630 return;
3631 }
3632
3633 if (ast_strlen_zero(interface)) {
3634 ast_log(LOG_WARNING, "Realtime field 'interface' is empty for member %s\n",
3635 S_OR(membername, "NULL"));
3636 return;
3637 }
3638
3639 if (penalty_str) {
3640 penalty = atoi(penalty_str);
3641 if ((penalty < 0) && negative_penalty_invalid) {
3642 return;
3643 } else if (penalty < 0) {
3644 penalty = 0;
3645 }
3646 }
3647
3648 if (paused_str) {
3649 paused = atoi(paused_str);
3650 if (paused < 0) {
3651 paused = 0;
3652 }
3653 }
3654
3655 if (wrapuptime_str) {
3656 wrapuptime = atoi(wrapuptime_str);
3657 if (wrapuptime < 0) {
3658 wrapuptime = 0;
3659 }
3660 }
3661
3662 if ((config_val = ast_variable_retrieve(member_config, category, realtime_ringinuse_field))) {
3663 if (ast_true(config_val)) {
3664 ringinuse = 1;
3665 } else if (ast_false(config_val)) {
3666 ringinuse = 0;
3667 } else {
3668 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
3669 }
3670 }
3671
3672 /* Find member by realtime uniqueid and update */
3673 mem_iter = ao2_iterator_init(q->members, 0);
3674 while ((m = ao2_iterator_next(&mem_iter))) {
3675 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
3676 m->dead = 0; /* Do not delete this one. */
3677 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3678 if (paused_str) {
3679 m->paused = paused;
3680 if (paused && m->lastpause == 0) {
3681 time(&m->lastpause); /* XXX: Should this come from realtime? */
3682 }
3684 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, m->interface);
3685 }
3686 if (strcasecmp(state_interface, m->state_interface)) {
3687 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
3688 }
3689 m->penalty = penalty;
3690 m->ringinuse = ringinuse;
3691 m->wrapuptime = wrapuptime;
3693 ast_copy_string(m->reason_paused, S_OR(reason_paused, ""), sizeof(m->reason_paused));
3694 }
3695 found = 1;
3696 ao2_ref(m, -1);
3697 break;
3698 }
3699 ao2_ref(m, -1);
3700 }
3701 ao2_iterator_destroy(&mem_iter);
3702
3703 /* Create a new member */
3704 if (!found) {
3705 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
3706 m->dead = 0;
3707 m->realtime = 1;
3708 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
3709 if (!ast_strlen_zero(reason_paused)) {
3710 ast_copy_string(m->reason_paused, reason_paused, sizeof(m->reason_paused));
3711 }
3713 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3714 } else {
3715 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
3716 }
3717 member_add_to_queue(q, m);
3718 ao2_ref(m, -1);
3719 m = NULL;
3720 }
3721 }
3722}
3723
3724/*! \brief Iterate through queue's member list and delete them */
3725static void free_members(struct call_queue *q, int all)
3726{
3727 /* Free non-dynamic members */
3728 struct member *cur;
3729 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
3730
3731 while ((cur = ao2_iterator_next(&mem_iter))) {
3732 if (all || !cur->dynamic) {
3734 }
3735 ao2_ref(cur, -1);
3736 }
3737 ao2_iterator_destroy(&mem_iter);
3738}
3739
3740/*! \brief Free queue's member list then its string fields */
3741static void destroy_queue(void *obj)
3742{
3743 struct call_queue *q = obj;
3744 int i;
3745
3746 free_members(q, 1);
3748 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
3749 if (q->sound_periodicannounce[i]) {
3751 }
3752 }
3753 ao2_ref(q->members, -1);
3754}
3755
3756static struct call_queue *alloc_queue(const char *queuename)
3757{
3758 struct call_queue *q;
3759
3760 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
3761 if (ast_string_field_init(q, 64)) {
3762 queue_t_unref(q, "String field allocation failed");
3763 return NULL;
3764 }
3765 ast_string_field_set(q, name, queuename);
3766 }
3767 return q;
3768}
3769
3770/*!
3771 * \brief Reload a single queue via realtime.
3772 *
3773 * Check for statically defined queue first, check if deleted RT queue,
3774 * check for new RT queue, if queue vars are not defined init them with defaults.
3775 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
3776 * \retval the queue,
3777 * \retval NULL if it doesn't exist.
3778 * \note Should be called with the "queues" container locked.
3779*/
3780static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
3781{
3782 struct ast_variable *v;
3783 struct call_queue *q, tmpq = {
3784 .name = queuename,
3785 };
3786 struct member *m;
3787 struct ao2_iterator mem_iter;
3788 char *category = NULL;
3789 const char *tmp_name;
3790 char *tmp;
3791 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
3792
3793 /* Static queues override realtime. */
3794 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
3795 ao2_lock(q);
3796 if (!q->realtime) {
3797 if (q->dead) {
3798 ao2_unlock(q);
3799 queue_t_unref(q, "Queue is dead; can't return it");
3800 return NULL;
3801 }
3802 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
3803 ao2_unlock(q);
3804 return q;
3805 }
3806 } else if (!member_config) {
3807 /* Not found in the list, and it's not realtime ... */
3808 return NULL;
3809 }
3810 /* Check if queue is defined in realtime. */
3811 if (!queue_vars) {
3812 /* Delete queue from in-core list if it has been deleted in realtime. */
3813 if (q) {
3814 /*! \note Hmm, can't seem to distinguish a DB failure from a not
3815 found condition... So we might delete an in-core queue
3816 in case of DB failure. */
3817 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
3818
3819 q->dead = 1;
3820 /* Delete if unused (else will be deleted when last caller leaves). */
3821 queues_t_unlink(queues, q, "Unused; removing from container");
3822 ao2_unlock(q);
3823 queue_t_unref(q, "Queue is dead; can't return it");
3824 }
3825 return NULL;
3826 }
3827
3828 /* Create a new queue if an in-core entry does not exist yet. */
3829 if (!q) {
3830 struct ast_variable *tmpvar = NULL;
3831 if (!(q = alloc_queue(queuename))) {
3832 return NULL;
3833 }
3834 ao2_lock(q);
3835 clear_queue(q);
3836 q->realtime = 1;
3837 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
3838 * will allocate the members properly
3839 */
3840 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
3841 if (!strcasecmp(tmpvar->name, "strategy")) {
3842 q->strategy = strat2int(tmpvar->value);
3843 if (q->strategy < 0) {
3844 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
3845 tmpvar->value, q->name);
3847 }
3848 break;
3849 }
3850 }
3851 /* We traversed all variables and didn't find a strategy */
3852 if (!tmpvar) {
3854 }
3855 queues_t_link(queues, q, "Add queue to container");
3856 }
3857 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
3858
3859 memset(tmpbuf, 0, sizeof(tmpbuf));
3860 for (v = queue_vars; v; v = v->next) {
3861 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
3862 if (strchr(v->name, '_')) {
3863 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
3864 tmp_name = tmpbuf;
3865 tmp = tmpbuf;
3866 while ((tmp = strchr(tmp, '_'))) {
3867 *tmp++ = '-';
3868 }
3869 } else {
3870 tmp_name = v->name;
3871 }
3872
3873 /* NULL values don't get returned from realtime; blank values should
3874 * still get set. If someone doesn't want a value to be set, they
3875 * should set the realtime column to NULL, not blank. */
3876 queue_set_param(q, tmp_name, v->value, -1, 0);
3877 }
3878
3879 /* Temporarily set realtime members dead so we can detect deleted ones. */
3880 mem_iter = ao2_iterator_init(q->members, 0);
3881 while ((m = ao2_iterator_next(&mem_iter))) {
3882 if (m->realtime) {
3883 m->dead = 1;
3884 }
3885 ao2_ref(m, -1);
3886 }
3887 ao2_iterator_destroy(&mem_iter);
3888
3889 while ((category = ast_category_browse(member_config, category))) {
3890 rt_handle_member_record(q, category, member_config);
3891 }
3892
3893 /* Delete all realtime members that have been deleted in DB. */
3894 mem_iter = ao2_iterator_init(q->members, 0);
3895 while ((m = ao2_iterator_next(&mem_iter))) {
3896 if (m->dead) {
3898 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3899 } else {
3900 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3901 }
3903 }
3904 ao2_ref(m, -1);
3905 }
3906 ao2_iterator_destroy(&mem_iter);
3907
3908 ao2_unlock(q);
3909
3910 return q;
3911}
3912
3913/*!
3914 * note */
3915
3916/*!
3917 * \internal
3918 * \brief Returns reference to the named queue. If the queue is realtime, it will load the queue as well.
3919 * \param queuename - name of the desired queue
3920 *
3921 * \retval the queue
3922 * \retval NULL if it doesn't exist
3923 */
3924static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
3925{
3926 struct ast_variable *queue_vars;
3927 struct ast_config *member_config = NULL;
3928 struct call_queue *q = NULL, tmpq = {
3929 .name = queuename,
3930 };
3931 int prev_weight = 0;
3932
3933 /* Find the queue in the in-core list first. */
3934 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
3935
3936 if (!q || q->realtime) {
3937 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
3938 queue operations while waiting for the DB.
3939
3940 This will be two separate database transactions, so we might
3941 see queue parameters as they were before another process
3942 changed the queue and member list as it was after the change.
3943 Thus we might see an empty member list when a queue is
3944 deleted. In practise, this is unlikely to cause a problem. */
3945
3946 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
3947 if (queue_vars) {
3948 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
3949 if (!member_config) {
3950 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
3951 member_config = ast_config_new();
3952 }
3953 }
3954 if (q) {
3955 prev_weight = q->weight ? 1 : 0;
3956 queue_t_unref(q, "Need to find realtime queue");
3957 }
3958
3959 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
3960 ast_config_destroy(member_config);
3961 ast_variables_destroy(queue_vars);
3962
3963 /* update the use_weight value if the queue's has gained or lost a weight */
3964 if (q) {
3965 if (!q->weight && prev_weight) {
3967 }
3968 if (q->weight && !prev_weight) {
3970 }
3971 }
3972 /* Other cases will end up with the proper value for use_weight */
3973 } else {
3975 }
3976 return q;
3977}
3978
3979/*!
3980 * \internal
3981 * \brief Load queues and members from realtime.
3982 *
3983 * \param queuename - name of the desired queue to load or empty if need to load all queues
3984*/
3985static void load_realtime_queues(const char *queuename)
3986{
3987 struct ast_config *cfg = NULL;
3988 char *category = NULL;
3989 const char *name = NULL;
3990 struct call_queue *q = NULL;
3991
3992 if (!ast_check_realtime("queues")) {
3993 return;
3994 }
3995
3996 if (ast_strlen_zero(queuename)) {
3997 if ((cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL))) {
3998 while ((category = ast_category_browse(cfg, category))) {
3999 name = ast_variable_retrieve(cfg, category, "name");
4001 queue_unref(q);
4002 }
4003 }
4004 ast_config_destroy(cfg);
4005 }
4006 } else {
4007 if ((q = find_load_queue_rt_friendly(queuename))) {
4008 queue_unref(q);
4009 }
4010 }
4011}
4012
4013static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
4014{
4015 int ret = -1;
4016
4017 if (ast_strlen_zero(mem->rt_uniqueid)) {
4018 return ret;
4019 }
4020
4021 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) >= 0) {
4022 ret = 0;
4023 }
4024
4025 return ret;
4026}
4027
4028
4030{
4031 struct ast_config *member_config = NULL;
4032 struct member *m;
4033 char *category = NULL;
4034 struct ao2_iterator mem_iter;
4035
4036 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
4037 /* This queue doesn't have realtime members. If the queue still has any realtime
4038 * members in memory, they need to be removed.
4039 */
4040 ao2_lock(q);
4041 mem_iter = ao2_iterator_init(q->members, 0);
4042 while ((m = ao2_iterator_next(&mem_iter))) {
4043 if (m->realtime) {
4045 }
4046 ao2_ref(m, -1);
4047 }
4048 ao2_iterator_destroy(&mem_iter);
4049 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
4050 ao2_unlock(q);
4051 return;
4052 }
4053
4054 ao2_lock(q);
4055
4056 /* Temporarily set realtime members dead so we can detect deleted ones.*/
4057 mem_iter = ao2_iterator_init(q->members, 0);
4058 while ((m = ao2_iterator_next(&mem_iter))) {
4059 if (m->realtime) {
4060 m->dead = 1;
4061 }
4062 ao2_ref(m, -1);
4063 }
4064 ao2_iterator_destroy(&mem_iter);
4065
4066 while ((category = ast_category_browse(member_config, category))) {
4067 rt_handle_member_record(q, category, member_config);
4068 }
4069
4070 /* Delete all realtime members that have been deleted in DB. */
4071 mem_iter = ao2_iterator_init(q->members, 0);
4072 while ((m = ao2_iterator_next(&mem_iter))) {
4073 if (m->dead) {
4075 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
4076 } else {
4077 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
4078 }
4080 }
4081 ao2_ref(m, -1);
4082 }
4083 ao2_iterator_destroy(&mem_iter);
4084 ao2_unlock(q);
4085 ast_config_destroy(member_config);
4086}
4087
4088static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
4089{
4090 struct call_queue *q;
4091 struct queue_ent *cur, *prev = NULL;
4092 int res = -1;
4093 int pos = 0;
4094 int inserted = 0;
4095
4096 if (!(q = find_load_queue_rt_friendly(queuename))) {
4097 return res;
4098 }
4099 ao2_lock(q);
4100
4101 /* This is our one */
4102 if (q->joinempty) {
4103 int status = 0;
4104 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, qe->raise_penalty, q->joinempty, 0))) {
4105 *reason = QUEUE_JOINEMPTY;
4106 ao2_unlock(q);
4107 queue_t_unref(q, "Done with realtime queue");
4108 return res;
4109 }
4110 }
4111 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
4112 *reason = QUEUE_FULL;
4113 } else if (*reason == QUEUE_UNKNOWN) {
4114 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4115
4116 /* There's space for us, put us at the right position inside
4117 * the queue.
4118 * Take into account the priority of the calling user */
4119 inserted = 0;
4120 prev = NULL;
4121 cur = q->head;
4122 while (cur) {
4123 /* We have higher priority than the current user, enter
4124 * before him, after all the other users with priority
4125 * higher or equal to our priority. */
4126 if ((!inserted) && (qe->prio > cur->prio)) {
4127 insert_entry(q, prev, qe, &pos);
4128 inserted = 1;
4129 }
4130 /* <= is necessary for the position comparison because it may not be possible to enter
4131 * at our desired position since higher-priority callers may have taken the position we want
4132 */
4133 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
4134 insert_entry(q, prev, qe, &pos);
4135 inserted = 1;
4136 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
4137 if (position < pos) {
4138 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
4139 }
4140 }
4141 cur->pos = ++pos;
4142 prev = cur;
4143 cur = cur->next;
4144 }
4145 /* No luck, join at the end of the queue */
4146 if (!inserted) {
4147 insert_entry(q, prev, qe, &pos);
4148 }
4149 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
4150 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
4151 ast_copy_string(qe->context, q->context, sizeof(qe->context));
4152 q->count++;
4153 if (q->count == 1) {
4155 }
4156
4157 res = 0;
4158
4159 blob = ast_json_pack("{s: s, s: i, s: i}",
4160 "Queue", q->name,
4161 "Position", qe->pos,
4162 "Count", q->count);
4163 ast_channel_publish_cached_blob(qe->chan, queue_caller_join_type(), blob);
4164 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
4165 }
4166 ao2_unlock(q);
4167 queue_t_unref(q, "Done with realtime queue");
4168
4169 return res;
4170}
4171
4172static int play_file(struct ast_channel *chan, const char *filename)
4173{
4174 int res;
4175
4176 if (ast_strlen_zero(filename)) {
4177 return 0;
4178 }
4179
4180 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
4181 return 0;
4182 }
4183
4185
4186 res = ast_streamfile(chan, filename, ast_channel_language(chan));
4187 if (!res) {
4189 }
4190
4192
4193 return res;
4194}
4195
4196/*!
4197 * \brief Check for valid exit from queue via goto
4198 * \retval 0 if failure
4199 * \retval 1 if successful
4200*/
4201static int valid_exit(struct queue_ent *qe, char digit)
4202{
4203 int digitlen = strlen(qe->digits);
4204
4205 /* Prevent possible buffer overflow */
4206 if (digitlen < sizeof(qe->digits) - 2) {
4207 qe->digits[digitlen] = digit;
4208 qe->digits[digitlen + 1] = '\0';
4209 } else {
4210 qe->digits[0] = '\0';
4211 return 0;
4212 }
4213
4214 /* If there's no context to goto, short-circuit */
4215 if (ast_strlen_zero(qe->context)) {
4216 return 0;
4217 }
4218
4219 /* If the extension is bad, then reset the digits to blank */
4220 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
4222 qe->digits[0] = '\0';
4223 return 0;
4224 }
4225
4226 /* We have an exact match */
4227 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
4228 qe->valid_digits = 1;
4229 /* Return 1 on a successful goto */
4230 return 1;
4231 }
4232
4233 return 0;
4234}
4235
4236static int say_position(struct queue_ent *qe, int ringing)
4237{
4238 int res = 0, say_thanks = 0;
4239 long avgholdmins, avgholdsecs;
4240 time_t now;
4241
4242 /* Let minannouncefrequency seconds pass between the start of each position announcement */
4243 time(&now);
4244 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
4245 return 0;
4246 }
4247
4248 /* If either our position has changed, or we are over the freq timer, say position */
4249 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
4250 return 0;
4251 }
4252
4253 /* Only announce if the caller's queue position has improved since last time */
4254 if (qe->parent->announceposition_only_up && qe->last_pos_said <= qe->pos) {
4255 return 0;
4256 }
4257
4258 if (ringing) {
4259 ast_indicate(qe->chan,-1);
4260 } else {
4261 ast_moh_stop(qe->chan);
4262 }
4263
4267 qe->pos <= qe->parent->announcepositionlimit)) {
4268 say_thanks = 1;
4269 /* Say we're next, if we are */
4270 if (qe->pos == 1) {
4271 res = play_file(qe->chan, qe->parent->sound_next);
4272 if (!res) {
4273 goto posout;
4274 }
4275 /* Say there are more than N callers */
4277 res = (
4278 play_file(qe->chan, qe->parent->queue_quantity1) ||
4280 ast_channel_language(qe->chan), NULL) || /* Needs gender */
4282 /* Say there are currently N callers waiting */
4283 } else {
4284 res = (
4285 play_file(qe->chan, qe->parent->sound_thereare) ||
4287 ast_channel_language(qe->chan), "n") || /* Needs gender */
4288 play_file(qe->chan, qe->parent->sound_calls));
4289 }
4290 if (res) {
4291 goto playout;
4292 }
4293 }
4294 /* Round hold time to nearest minute */
4295 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
4296
4297 /* If they have specified a rounding then round the seconds as well */
4298 if (qe->parent->roundingseconds) {
4299 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
4300 avgholdsecs *= qe->parent->roundingseconds;
4301 } else {
4302 avgholdsecs = 0;
4303 }
4304
4305 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
4306
4307 /* If the hold time is >1 min, if it's enabled, and if it's not
4308 supposed to be only once and we have already said it, say it */
4309 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
4312 say_thanks = 1;
4313 res = play_file(qe->chan, qe->parent->sound_holdtime);
4314 if (res) {
4315 goto playout;
4316 }
4317
4318 if (avgholdmins >= 1) {
4319 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4320 if (res) {
4321 goto playout;
4322 }
4323
4324 if (avgholdmins == 1) {
4325 res = play_file(qe->chan, qe->parent->sound_minute);
4326 if (res) {
4327 goto playout;
4328 }
4329 } else {
4330 res = play_file(qe->chan, qe->parent->sound_minutes);
4331 if (res) {
4332 goto playout;
4333 }
4334 }
4335 }
4336 if (avgholdsecs >= 1) {
4337 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), "n");
4338 if (res) {
4339 goto playout;
4340 }
4341
4342 res = play_file(qe->chan, qe->parent->sound_seconds);
4343 if (res) {
4344 goto playout;
4345 }
4346 }
4347 }
4348
4349posout:
4350 if (qe->parent->announceposition) {
4351 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
4352 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
4353 }
4354 if (say_thanks) {
4355 res = play_file(qe->chan, qe->parent->sound_thanks);
4356 }
4357playout:
4358
4359 if ((res > 0 && !valid_exit(qe, res))) {
4360 res = 0;
4361 }
4362
4363 /* Set our last_pos indicators */
4364 qe->last_pos = now;
4365 qe->last_pos_said = qe->pos;
4366
4367 /* Don't restart music on hold if we're about to exit the caller from the queue */
4368 if (!res) {
4369 if (ringing) {
4371 } else {
4372 ast_moh_start(qe->chan, qe->moh, NULL);
4373 }
4374 }
4375 return res;
4376}
4377
4378static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
4379{
4380 int oldvalue;
4381
4382 /* Calculate holdtime using an exponential average */
4383 /* Thanks to SRT for this contribution */
4384 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
4385
4386 ao2_lock(qe->parent);
4387 if ((qe->parent->callscompleted + qe->parent->callsabandoned) == 0) {
4388 qe->parent->holdtime = newholdtime;
4389 } else {
4390 oldvalue = qe->parent->holdtime;
4391 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
4392 }
4393 ao2_unlock(qe->parent);
4394}
4395
4396/*! \brief Caller leaving queue.
4397 *
4398 * Search the queue to find the leaving client, if found remove from queue
4399 * create manager event, move others up the queue.
4400*/
4401static void leave_queue(struct queue_ent *qe)
4402{
4403 struct call_queue *q;
4404 struct queue_ent *current, *prev = NULL;
4405 struct penalty_rule *pr_iter;
4406 int pos = 0;
4407
4408 if (!(q = qe->parent)) {
4409 return;
4410 }
4411 queue_t_ref(q, "Copy queue pointer from queue entry");
4412 ao2_lock(q);
4413
4414 prev = NULL;
4415 for (current = q->head; current; current = current->next) {
4416 if (current == qe) {
4417 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4418 char posstr[20];
4419 q->count--;
4420 if (!q->count) {
4422 }
4423
4424 blob = ast_json_pack("{s: s, s: i, s: i}",
4425 "Queue", q->name,
4426 "Position", qe->pos,
4427 "Count", q->count);
4428 ast_channel_publish_cached_blob(qe->chan, queue_caller_leave_type(), blob);
4429 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
4430 /* Take us out of the queue */
4431 if (prev) {
4432 prev->next = current->next;
4433 } else {
4434 q->head = current->next;
4435 }
4436 /* Free penalty rules */
4437 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
4438 ast_free(pr_iter);
4439 }
4440 qe->pr = NULL;
4441 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
4442 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
4443 } else {
4444 /* Renumber the people after us in the queue based on a new count */
4445 current->pos = ++pos;
4446 prev = current;
4447 }
4448 }
4449 ao2_unlock(q);
4450
4451 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
4452 if (q->realtime) {
4453 struct ast_variable *var;
4454 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
4455 q->dead = 1;
4456 } else {
4458 }
4459 }
4460
4461 if (q->dead) {
4462 /* It's dead and nobody is in it, so kill it */
4463 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
4464 }
4465 /* unref the explicit ref earlier in the function */
4466 queue_t_unref(q, "Expire copied reference");
4467}
4468
4469/*!
4470 * \internal
4471 * \brief Destroy the given callattempt structure and free it.
4472 * \since 1.8
4473 *
4474 * \param doomed callattempt structure to destroy.
4475 */
4476static void callattempt_free(struct callattempt *doomed)
4477{
4478 if (doomed->member) {
4479 ao2_ref(doomed->member, -1);
4480 }
4482 ast_free(doomed->orig_chan_name);
4483 ast_free(doomed);
4484}
4485
4486static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
4487{
4488 struct callattempt *cur;
4489
4490 for (cur = outgoing; cur; cur = cur->q_next) {
4491 if (cur->chan && cur->chan != exception) {
4493 }
4494 }
4495}
4496
4497/*! \brief Hang up a list of outgoing calls */
4498static void hangupcalls(struct queue_ent *qe, struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
4499{
4500 struct callattempt *oo;
4501
4502 while (outgoing) {
4503 /* If someone else answered the call we should indicate this in the CANCEL */
4504 /* Hangup any existing lines we have open */
4505 if (outgoing->chan && (outgoing->chan != exception)) {
4506 if (exception || cancel_answered_elsewhere) {
4508 }
4509 ast_channel_publish_dial(qe->chan, outgoing->chan, outgoing->interface, "CANCEL");
4510
4511 /* When dialing channels it is possible that they may not ever
4512 * leave the not in use state (Local channels in particular) by
4513 * the time we cancel them. If this occurs but we know they were
4514 * dialed we explicitly remove them from the pending members
4515 * container so that subsequent call attempts occur.
4516 */
4517 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
4519 }
4520
4521 ast_hangup(outgoing->chan);
4522 }
4523 oo = outgoing;
4524 outgoing = outgoing->q_next;
4526 callattempt_free(oo);
4527 }
4528}
4529
4530/*!
4531 * \brief Get the number of members available to accept a call.
4532 *
4533 * \note The queue passed in should be locked prior to this function call
4534 *
4535 * \param[in] q The queue for which we are counting the number of available members
4536 * \return Return the number of available members in queue q
4537 */
4539{
4540 struct member *mem;
4541 int avl = 0;
4542 struct ao2_iterator mem_iter;
4543
4544 mem_iter = ao2_iterator_init(q->members, 0);
4545 while ((mem = ao2_iterator_next(&mem_iter))) {
4546
4547 avl += is_member_available(q, mem);
4548 ao2_ref(mem, -1);
4549
4550 /* If autofill is not enabled or if the queue's strategy is ringall, then
4551 * we really don't care about the number of available members so much as we
4552 * do that there is at least one available.
4553 *
4554 * In fact, we purposely will return from this function stating that only
4555 * one member is available if either of those conditions hold. That way,
4556 * functions which determine what action to take based on the number of available
4557 * members will operate properly. The reasoning is that even if multiple
4558 * members are available, only the head caller can actually be serviced.
4559 */
4560 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
4561 break;
4562 }
4563 }
4564 ao2_iterator_destroy(&mem_iter);
4565
4566 return avl;
4567}
4568
4569/* traverse all defined queues which have calls waiting and contain this member
4570 return 0 if no other queue has precedence (higher weight) or 1 if found */
4571static int compare_weight(struct call_queue *rq, struct member *member)
4572{
4573 struct call_queue *q;
4574 struct member *mem;
4575 int found = 0;
4576 struct ao2_iterator queue_iter;
4577
4578 queue_iter = ao2_iterator_init(queues, 0);
4579 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4580 if (q == rq) { /* don't check myself, could deadlock */
4581 queue_t_unref(q, "Done with iterator");
4582 continue;
4583 }
4584 ao2_lock(q);
4585 if (q->count && q->members) {
4586 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4587 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4588 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
4589 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);
4590 found = 1;
4591 }
4592 ao2_ref(mem, -1);
4593 }
4594 }
4595 ao2_unlock(q);
4596 queue_t_unref(q, "Done with iterator");
4597 if (found) {
4598 break;
4599 }
4600 }
4601 ao2_iterator_destroy(&queue_iter);
4602 return found;
4603}
4604
4605static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
4606{
4607 struct call_queue *q;
4608 struct member *mem;
4609 int is_longest_waiting = 1;
4610 struct ao2_iterator queue_iter;
4611 struct queue_ent *ch;
4612
4613 queue_iter = ao2_iterator_init(queues, 0);
4614 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4615 if (q == caller->parent) { /* don't check myself, could deadlock */
4616 queue_t_unref(q, "Done with iterator");
4617 continue;
4618 }
4619 ao2_lock(q);
4620 /*
4621 * If the other queue has equal weight, see if we should let that handle
4622 * their call first. If weights are not equal, compare_weights will step in.
4623 */
4624 if (q->weight == caller->parent->weight && q->count && q->members) {
4625 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
4626 ast_debug(2, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
4627
4628 /* Does this queue have a caller that's been waiting longer? */
4629 ch = q->head;
4630 while (ch) {
4631 /* If ch->pending, the other call (which may be waiting for a longer period of time),
4632 * is already ringing at another agent. Ignore such callers; otherwise, all agents
4633 * will be unused until the first caller is picked up.
4634 */
4635 if (ch->start < caller->start && !ch->pending) {
4636 ast_debug(1, "Queue %s has a call at position %i that's been waiting longer (%li vs %li)\n",
4637 q->name, ch->pos, ch->start, caller->start);
4638 is_longest_waiting = 0;
4639 break;
4640 }
4641 ch = ch->next;
4642 }
4643 }
4644 }
4645 ao2_unlock(q);
4646 queue_t_unref(q, "Done with iterator");
4647 if (!is_longest_waiting) {
4648 break;
4649 }
4650 }
4651 ao2_iterator_destroy(&queue_iter);
4652 return is_longest_waiting;
4653}
4654
4655/*! \brief common hangup actions */
4656static void do_hang(struct callattempt *o)
4657{
4658 o->stillgoing = 0;
4659 ast_hangup(o->chan);
4661 o->chan = NULL;
4662}
4663
4664/*!
4665 * \internal
4666 * \brief Check if the member status is available.
4667 *
4668 * \param status Member status to check if available.
4669 *
4670 * \retval non-zero if the member status is available.
4671 */
4673{
4675}
4676
4677/*!
4678 * \internal
4679 * \brief Determine if can ring a queue entry.
4680 *
4681 * \param qe Queue entry to check.
4682 * \param call Member call attempt.
4683 *
4684 * \retval non-zero if an entry can be called.
4685 */
4686static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
4687{
4688 struct member *memberp = call->member;
4689 int wrapuptime;
4690
4691 if (memberp->paused) {
4692 ast_debug(1, "%s paused, can't receive call\n", call->interface);
4693 return 0;
4694 }
4695
4696 if (!memberp->ringinuse && !member_status_available(memberp->status)) {
4697 ast_debug(1, "%s not available, can't receive call\n", call->interface);
4698 return 0;
4699 }
4700
4701 if (memberp->lastqueue) {
4702 wrapuptime = get_wrapuptime(memberp->lastqueue, memberp);
4703 } else {
4704 wrapuptime = get_wrapuptime(qe->parent, memberp);
4705 }
4706 if (wrapuptime && (time(NULL) - memberp->lastcall) < wrapuptime) {
4707 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
4708 (memberp->lastqueue ? memberp->lastqueue->name : qe->parent->name),
4709 call->interface);
4710 return 0;
4711 }
4712
4713 if (use_weight && compare_weight(qe->parent, memberp)) {
4714 ast_debug(1, "Priority queue delaying call to %s:%s\n",
4715 qe->parent->name, call->interface);
4716 return 0;
4717 }
4718
4720 ast_debug(1, "Another caller was waiting longer; delaying call to %s:%s\n",
4721 qe->parent->name, call->interface);
4722 return 0;
4723 }
4724
4725 if (!memberp->ringinuse) {
4726 struct member *mem;
4727
4729
4730 mem = ao2_find(pending_members, memberp,
4732 if (mem) {
4733 /*
4734 * If found that means this member is currently being attempted
4735 * from another calling thread, so stop trying from this thread
4736 */
4737 ast_debug(1, "%s has another call trying, can't receive call\n",
4738 call->interface);
4739 ao2_ref(mem, -1);
4741 return 0;
4742 }
4743
4744 /*
4745 * If not found add it to the container so another queue
4746 * won't attempt to call this member at the same time.
4747 */
4748 ast_debug(3, "Add %s to pending_members\n", memberp->membername);
4749 ao2_link(pending_members, memberp);
4751
4752 /*
4753 * The queue member is available. Get current status to be sure
4754 * because the device state and extension state callbacks may
4755 * not have updated the status yet.
4756 */
4758 ast_debug(1, "%s actually not available, can't receive call\n",
4759 call->interface);
4760 pending_members_remove(memberp);
4761 return 0;
4762 }
4763 }
4764
4765 return 1;
4766}
4767
4768/*!
4769 * \brief Part 2 of ring_one
4770 *
4771 * Does error checking before attempting to request a channel and call a member.
4772 * This function is only called from ring_one().
4773 * Failure can occur if:
4774 * - Agent on call
4775 * - Agent is paused
4776 * - Wrapup time not expired
4777 * - Priority by another queue
4778 *
4779 * \retval 1 on success to reach a free agent
4780 * \retval 0 on failure to get agent.
4781 */
4782static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
4783{
4784 int res;
4785 int status;
4786 char tech[256];
4787 char *location;
4788 struct ast_format_cap *nativeformats;
4789 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
4790
4791 /* on entry here, we know that tmp->chan == NULL */
4792 if (!can_ring_entry(qe, tmp)) {
4793 tmp->stillgoing = 0;
4794 ++*busies;
4795 return 0;
4796 }
4797
4798 ast_copy_string(tech, tmp->interface, sizeof(tech));
4799 if ((location = strchr(tech, '/'))) {
4800 *location++ = '\0';
4801 } else {
4802 location = "";
4803 }
4804
4806 nativeformats = ao2_bump(ast_channel_nativeformats(qe->chan));
4808
4809 /* Request the peer */
4810 tmp->chan = ast_request(tech, nativeformats, NULL, qe->chan, location, &status);
4811 ao2_cleanup(nativeformats);
4812 if (!tmp->chan) { /* If we can't, just go on to the next call */
4813 ao2_lock(qe->parent);
4814 qe->parent->rrpos++;
4815 qe->linpos++;
4816 ao2_unlock(qe->parent);
4817
4818 pending_members_remove(tmp->member);
4819
4820 publish_dial_end_event(qe->chan, tmp, NULL, "BUSY");
4821 tmp->stillgoing = 0;
4822 ++*busies;
4823 return 0;
4824 }
4825
4826 ast_channel_lock_both(tmp->chan, qe->chan);
4827
4830 if (qe->cancel_answered_elsewhere) {
4832 }
4833 ast_channel_appl_set(tmp->chan, "AppQueue");
4834 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
4835 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
4836
4837 /* If the new channel has no callerid, try to guess what it should be */
4838 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
4840 struct ast_party_caller caller;
4841
4843 caller.id = ast_channel_connected(qe->chan)->id;
4844 caller.ani = ast_channel_connected(qe->chan)->ani;
4845 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
4846 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
4848 } else if (!ast_strlen_zero(ast_channel_exten(qe->chan))) {
4850 }
4851 tmp->dial_callerid_absent = 1;
4852 }
4853
4855
4857
4859
4860 /* Inherit specially named variables from parent channel */
4864
4865 /* Presense of ADSI CPE on outgoing channel follows ours */
4867
4868 /* Inherit context and extension */
4869 ast_channel_dialcontext_set(tmp->chan, ast_channel_context(qe->chan));
4871
4872 /* Save the original channel name to detect call pickup masquerading in. */
4873 tmp->orig_chan_name = ast_strdup(ast_channel_name(tmp->chan));
4874
4875 ast_channel_unlock(tmp->chan);
4877
4878 /* location is tmp->interface where tech/ has been stripped, so it follow the same syntax as DIALEDPEERNUMBER in app_dial.c */
4879 pbx_builtin_setvar_helper(tmp->chan, "DIALEDPEERNUMBER", strlen(location) ? location : tmp->interface);
4880
4881 /* PREDIAL: Run gosub on the callee's channel */
4882 if (qe->predial_callee) {
4883 ast_pre_call(tmp->chan, qe->predial_callee);
4884 }
4885
4886 /* Place the call, but don't wait on the answer */
4887 if ((res = ast_call(tmp->chan, location, 0))) {
4888 /* Again, keep going even if there's an error */
4889 ast_verb(3, "Couldn't call %s\n", tmp->interface);
4890 do_hang(tmp);
4891 ++*busies;
4892 return 0;
4893 }
4894
4895 ast_channel_lock_both(tmp->chan, qe->chan);
4896
4897 blob = ast_json_pack("{s: s, s: s, s: s}",
4898 "Queue", qe->parent->name,
4899 "Interface", tmp->interface,
4900 "MemberName", tmp->member->membername);
4901 queue_publish_multi_channel_blob(qe->chan, tmp->chan, queue_agent_called_type(), blob);
4902
4903 ast_channel_publish_dial(qe->chan, tmp->chan, tmp->interface, NULL);
4904
4905 ast_channel_unlock(tmp->chan);
4907
4908 ast_verb(3, "Called %s\n", tmp->interface);
4909
4910 return 1;
4911}
4912
4913/*! \brief find the entry with the best metric, or NULL */
4915{
4916 struct callattempt *best = NULL, *cur;
4917
4918 for (cur = outgoing; cur; cur = cur->q_next) {
4919 if (cur->stillgoing && /* Not already done */
4920 !cur->chan && /* Isn't already going */
4921 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
4922 best = cur;
4923 }
4924 }
4925
4926 return best;
4927}
4928
4929/*!
4930 * \brief Place a call to a queue member.
4931 *
4932 * Once metrics have been calculated for each member, this function is used
4933 * to place a call to the appropriate member (or members). The low-level
4934 * channel-handling and error detection is handled in ring_entry
4935 *
4936 * \retval 1 if a member was called successfully
4937 * \retval 0 otherwise
4938 */
4939static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
4940{
4941 int ret = 0;
4942 struct callattempt *cur;
4943
4944 if (qe->predial_callee) {
4946 for (cur = outgoing; cur; cur = cur->q_next) {
4947 if (cur->stillgoing && cur->chan) {
4949 }
4950 }
4951 }
4952
4953 while (ret == 0) {
4954 struct callattempt *best = find_best(outgoing);
4955 if (!best) {
4956 ast_debug(1, "Nobody left to try ringing in queue\n");
4957 break;
4958 }
4960 /* Ring everyone who shares this best metric (for ringall) */
4961 for (cur = outgoing; cur; cur = cur->q_next) {
4962 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
4963 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
4964 ret |= ring_entry(qe, cur, busies);
4965 if (qe->predial_callee && cur->chan) {
4967 }
4968 }
4969 }
4970 } else {
4971 /* Ring just the best channel */
4972 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
4973 ret = ring_entry(qe, best, busies);
4974 if (qe->predial_callee && best->chan) {
4976 }
4977 }
4978
4979 /* If we have timed out, break out */
4980 if (qe->expire && (time(NULL) >= qe->expire)) {
4981 ast_debug(1, "Queue timed out while ringing members.\n");
4982 ret = 0;
4983 break;
4984 }
4985 }
4986 if (qe->predial_callee) {
4987 for (cur = outgoing; cur; cur = cur->q_next) {
4988 if (cur->stillgoing && cur->chan) {
4990 }
4991 }
4993 }
4994
4995 return ret;
4996}
4997
4998/*! \brief Search for best metric and add to Round Robbin queue */
4999static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
5000{
5001 struct callattempt *best = find_best(outgoing);
5002
5003 if (best) {
5004 /* Ring just the best channel */
5005 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5006 qe->parent->rrpos = best->metric % 1000;
5007 } else {
5008 /* Just increment rrpos */
5009 if (qe->parent->wrapped) {
5010 /* No more channels, start over */
5011 qe->parent->rrpos = 0;
5012 } else {
5013 /* Prioritize next entry */
5014 qe->parent->rrpos++;
5015 }
5016 }
5017 qe->parent->wrapped = 0;
5018
5019 return 0;
5020}
5021
5022/*! \brief Search for best metric and add to Linear queue */
5023static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
5024{
5025 struct callattempt *best = find_best(outgoing);
5026
5027 if (best) {
5028 /* Ring just the best channel */
5029 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
5030 qe->linpos = best->metric % 1000;
5031 } else {
5032 /* Just increment rrpos */
5033 if (qe->linwrapped) {
5034 /* No more channels, start over */
5035 qe->linpos = 0;
5036 } else {
5037 /* Prioritize next entry */
5038 qe->linpos++;
5039 }
5040 }
5041 qe->linwrapped = 0;
5042
5043 return 0;
5044}
5045
5046/*! \brief Playback announcement to queued members if period has elapsed */
5048{
5049 int res = 0;
5050 time_t now;
5051
5052 /* Get the current time */
5053 time(&now);
5054
5055 /* Check to see if it is time to announce */
5057 return 0;
5058 }
5059
5060 /* Stop the music on hold so we can play our own file */
5061 if (ringing) {
5062 ast_indicate(qe->chan,-1);
5063 } else {
5064 ast_moh_stop(qe->chan);
5065 }
5066
5067 ast_verb(3, "Playing periodic announcement\n");
5068
5070 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
5074 }
5075
5076 /* play the announcement */
5078
5079 if (res > 0 && !valid_exit(qe, res)) {
5080 res = 0;
5081 }
5082
5083 /* Resume Music on Hold if the caller is going to stay in the queue */
5084 if (!res) {
5085 if (ringing) {
5087 } else {
5088 ast_moh_start(qe->chan, qe->moh, NULL);
5089 }
5090 }
5091
5092 /* update last_periodic_announce_time */
5094 time(&qe->last_periodic_announce_time);
5095 } else {
5097 }
5098
5099 /* Update the current periodic announcement to the next announcement */
5100 if (!qe->parent->randomperiodicannounce) {
5102 }
5103
5104 return res;
5105}
5106
5107/*! \brief Record that a caller gave up on waiting in queue */
5108static void record_abandoned(struct queue_ent *qe)
5109{
5110 int callabandonedinsl = 0;
5111 time_t now;
5112
5113 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5114
5115 pbx_builtin_setvar_helper(qe->chan, "ABANDONED", "TRUE");
5116
5118 ao2_lock(qe->parent);
5119 blob = ast_json_pack("{s: s, s: i, s: i, s: i}",
5120 "Queue", qe->parent->name,
5121 "Position", qe->pos,
5122 "OriginalPosition", qe->opos,
5123 "HoldTime", (int)(time(NULL) - qe->start));
5124
5125
5126 time(&now);
5127 callabandonedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5128 if (callabandonedinsl) {
5130 }
5131
5132 qe->parent->callsabandoned++;
5133 ao2_unlock(qe->parent);
5134
5135 ast_channel_publish_cached_blob(qe->chan, queue_caller_abandon_type(), blob);
5136}
5137
5138/*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
5139static void rna(int rnatime, struct queue_ent *qe, struct ast_channel *peer, char *interface, char *membername, int autopause)
5140{
5141 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
5142
5143 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
5144
5145 /* Stop ringing, and resume MOH if specified */
5146 if (qe->ring_when_ringing) {
5147 ast_indicate(qe->chan, -1);
5148 ast_moh_start(qe->chan, qe->moh, NULL);
5149 }
5150
5151 blob = ast_json_pack("{s: s, s: s, s: s, s: i}",
5152 "Queue", qe->parent->name,
5153 "Interface", interface,
5154 "MemberName", membername,
5155 "RingTime", rnatime);
5156 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_ringnoanswer_type(), blob);
5157
5158 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
5160 if (qe->parent->autopausedelay > 0) {
5161 struct member *mem;
5162 ao2_lock(qe->parent);
5163 if ((mem = interface_exists(qe->parent, interface))) {
5164 time_t idletime = time(&idletime)-mem->lastcall;
5165 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
5166 ao2_unlock(qe->parent);
5167 ao2_ref(mem, -1);
5168 return;
5169 }
5170 ao2_ref(mem, -1);
5171 }
5172 ao2_unlock(qe->parent);
5173 }
5174 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
5175 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
5176 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
5177 interface, qe->parent->name);
5178 } else {
5179 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
5180 }
5181 } else {
5182 /* If queue autopause is mode all, just don't send any queue to stop.
5183 * the function will stop in all queues */
5184 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
5185 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
5186 interface, qe->parent->name);
5187 } else {
5188 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
5189 }
5190 }
5191 }
5192 return;
5193}
5194
5195/*!
5196 * \internal
5197 * \brief Update connected line on chan from peer.
5198 * \since 13.6.0
5199 *
5200 * \param chan Channel to get connected line updated.
5201 * \param peer Channel providing connected line information.
5202 * \param is_caller Non-zero if chan is the calling channel.
5203 */
5204static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
5205{
5206 struct ast_party_connected_line connected_caller;
5207
5208 ast_party_connected_line_init(&connected_caller);
5209
5210 ast_channel_lock(peer);
5212 ast_channel_unlock(peer);
5214 if (ast_channel_connected_line_sub(peer, chan, &connected_caller, 0)) {
5215 ast_channel_update_connected_line(chan, &connected_caller, NULL);
5216 }
5217 ast_party_connected_line_free(&connected_caller);
5218}
5219
5220#define AST_MAX_WATCHERS 256
5221/*!
5222 * \brief Wait for a member to answer the call
5223 *
5224 * \param[in] qe the queue_ent corresponding to the caller in the queue
5225 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
5226 * \param[in] to the amount of time (in milliseconds) to wait for a response
5227 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
5228 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
5229 * \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
5230 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
5231 *
5232 * \todo eventually all call forward logic should be integrated into and replaced by ast_call_forward()
5233 */
5234static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
5235{
5236 const char *queue = qe->parent->name;
5237 struct callattempt *o, *start = NULL, *prev = NULL;
5238 int status;
5239 int numbusies = prebusies;
5240 int numnochan = 0;
5241 int stillgoing = 0;
5242 int orig = *to;
5243 struct ast_frame *f;
5244 struct callattempt *peer = NULL;
5245 struct ast_channel *winner;
5246 struct ast_channel *in = qe->chan;
5247 char on[80] = "";
5248 char membername[80] = "";
5249 long starttime = 0;
5250 long endtime = 0;
5251 char *inchan_name;
5252 struct timeval start_time_tv = ast_tvnow();
5253 int canceled_by_caller = 0; /* 1 when caller hangs up or press digit or press * */
5254
5256 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
5258
5259 starttime = (long) time(NULL);
5260
5261 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
5262 int numlines, retry, pos = 1;
5263 struct ast_channel *watchers[AST_MAX_WATCHERS];
5264 watchers[0] = in;
5265 start = NULL;
5266
5267 for (retry = 0; retry < 2; retry++) {
5268 numlines = 0;
5269 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
5270 if (o->stillgoing) { /* Keep track of important channels */
5271 stillgoing = 1;
5272 if (o->chan) {
5273 if (pos < AST_MAX_WATCHERS) {
5274 watchers[pos++] = o->chan;
5275 }
5276 if (!start) {
5277 start = o;
5278 } else {
5279 prev->call_next = o;
5280 }
5281 prev = o;
5282 }
5283 } else if (prev) {
5284 prev->call_next = NULL;
5285 }
5286 numlines++;
5287 }
5288 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
5289 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
5290 break;
5291 }
5292 /* On "ringall" strategy we only move to the next penalty level
5293 when *all* ringing phones are done in the current penalty level */
5294 ring_one(qe, outgoing, &numbusies);
5295 /* and retry... */
5296 }
5297 if (pos == 1 /* not found */) {
5298 if (numlines == (numbusies + numnochan)) {
5299 ast_debug(1, "Everyone is busy at this time\n");
5300 } else {
5301 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
5302 }
5303 *to = 0;
5304 return NULL;
5305 }
5306
5307 /* Poll for events from both the incoming channel as well as any outgoing channels */
5308 winner = ast_waitfor_n(watchers, pos, to);
5309
5310 /* Service all of the outgoing channels */
5311 for (o = start; o; o = o->call_next) {
5312 /* We go with a fixed buffer here instead of using ast_strdupa. Using
5313 * ast_strdupa in a loop like this one can cause a stack overflow
5314 */
5315 char ochan_name[AST_CHANNEL_NAME];
5316
5317 if (o->chan) {
5319 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
5321 }
5322 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
5323 if (!peer) {
5324 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5325 if (o->orig_chan_name
5326 && strcmp(o->orig_chan_name, ochan_name)) {
5327 /*
5328 * The channel name changed so we must generate COLP update.
5329 * Likely because a call pickup channel masqueraded in.
5330 */
5332 } else if (!o->block_connected_update) {
5333 if (o->pending_connected_update) {
5336 }
5337 } else if (!o->dial_callerid_absent) {
5339 }
5340 }
5341 if (o->aoc_s_rate_list) {
5342 size_t encoded_size;
5343 struct ast_aoc_encoded *encoded;
5344 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5345 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5346 ast_aoc_destroy_encoded(encoded);
5347 }
5348 }
5349 peer = o;
5350 }
5351 } else if (o->chan && (o->chan == winner)) {
5352
5353 ast_copy_string(on, o->member->interface, sizeof(on));
5354 ast_copy_string(membername, o->member->membername, sizeof(membername));
5355
5356 /* Before processing channel, go ahead and check for forwarding */
5357 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
5358 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
5360 "CANCEL", ast_channel_call_forward(o->chan));
5361 numnochan++;
5362 do_hang(o);
5363 winner = NULL;
5364 continue;
5366 struct ast_channel *original = o->chan;
5367 char forwarder[AST_CHANNEL_NAME];
5368 char tmpchan[256];
5369 char *stuff;
5370 char *tech;
5371 int failed = 0;
5372
5373 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
5374 ast_copy_string(forwarder, ast_channel_name(o->chan), sizeof(forwarder));
5375 if ((stuff = strchr(tmpchan, '/'))) {
5376 *stuff++ = '\0';
5377 tech = tmpchan;
5378 } else {
5379 const char *forward_context;
5381 forward_context = pbx_builtin_getvar_helper(o->chan, "FORWARD_CONTEXT");
5382 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), forward_context ? forward_context : ast_channel_context(o->chan));
5384 stuff = tmpchan;
5385 tech = "Local";
5386 }
5387 if (!strcasecmp(tech, "Local")) {
5388 /*
5389 * Drop the connected line update block for local channels since
5390 * this is going to run dialplan and the user can change his
5391 * mind about what connected line information he wants to send.
5392 */
5394 }
5395
5396 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
5397 /* Setup parameters */
5399 if (!o->chan) {
5401 "Forwarding failed to create channel to dial '%s/%s'\n",
5402 tech, stuff);
5403 o->stillgoing = 0;
5404 numnochan++;
5405 } else {
5406 ast_channel_lock_both(o->chan, original);
5408 ast_channel_redirecting(original));
5410 ast_channel_unlock(original);
5411
5415 pbx_builtin_setvar_helper(o->chan, "FORWARDERNAME", forwarder);
5417
5418 if (o->pending_connected_update) {
5419 /*
5420 * Re-seed the callattempt's connected line information with
5421 * previously acquired connected line info from the queued
5422 * channel. The previously acquired connected line info could
5423 * have been set through the CONNECTED_LINE dialplan function.
5424 */
5427 }
5428
5431
5433
5436 /*
5437 * The call was not previously redirected so it is
5438 * now redirected from this number.
5439 */
5445 }
5446
5448
5453
5456 && !o->block_connected_update) {
5457 struct ast_party_redirecting redirecting;
5458
5459 /*
5460 * Redirecting updates to the caller make sense only on single
5461 * call at a time strategies.
5462 *
5463 * Need to re-evaluate if calling unlock is still required as we no longer
5464 * use macro.
5465 */
5466 ast_party_redirecting_init(&redirecting);
5469 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0)) {
5470 ast_channel_update_redirecting(in, &redirecting, NULL);
5471 }
5472 ast_party_redirecting_free(&redirecting);
5473 } else {
5475 }
5476
5477 if (ast_call(o->chan, stuff, 0)) {
5478 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
5479 tech, stuff);
5480 failed = 1;
5481 }
5482 }
5483
5485 "CANCEL", ast_channel_call_forward(original));
5486 if (o->chan) {
5487 ast_channel_publish_dial(qe->chan, o->chan, stuff, NULL);
5488 }
5489
5490 if (failed) {
5491 do_hang(o);
5492 numnochan++;
5493 }
5494
5495 /* Hangup the original channel now, in case we needed it */
5496 ast_hangup(winner);
5497 continue;
5498 }
5499 f = ast_read(winner);
5500 if (f) {
5501 if (f->frametype == AST_FRAME_CONTROL) {
5502 switch (f->subclass.integer) {
5503 case AST_CONTROL_ANSWER:
5504 /* This is our guy if someone answered. */
5505 if (!peer) {
5506 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
5507 ast_channel_publish_dial(qe->chan, o->chan, on, "ANSWER");
5508 publish_dial_end_event(qe->chan, outgoing, o->chan, "CANCEL");
5509 if (o->orig_chan_name
5510 && strcmp(o->orig_chan_name, ochan_name)) {
5511 /*
5512 * The channel name changed so we must generate COLP update.
5513 * Likely because a call pickup channel masqueraded in.
5514 */
5516 } else if (!o->block_connected_update) {
5517 if (o->pending_connected_update) {
5520 }
5521 } else if (!o->dial_callerid_absent) {
5523 }
5524 }
5525 if (o->aoc_s_rate_list) {
5526 size_t encoded_size;
5527 struct ast_aoc_encoded *encoded;
5528 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
5529 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
5530 ast_aoc_destroy_encoded(encoded);
5531 }
5532 }
5533 peer = o;
5534 }
5535 break;
5536 case AST_CONTROL_BUSY:
5537 ast_verb(3, "%s is busy\n", ochan_name);
5538 ast_channel_publish_dial(qe->chan, o->chan, on, "BUSY");
5539 endtime = (long) time(NULL);
5540 endtime -= starttime;
5541 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopausebusy);
5542 do_hang(o);
5544 if (qe->parent->timeoutrestart) {
5545 start_time_tv = ast_tvnow();
5546 }
5547 /* Have enough time for a queue member to answer? */
5548 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5549 ring_one(qe, outgoing, &numbusies);
5550 starttime = (long) time(NULL);
5551 }
5552 }
5553 numbusies++;
5554 break;
5556 ast_verb(3, "%s is circuit-busy\n", ochan_name);
5557 ast_channel_publish_dial(qe->chan, o->chan, on, "CONGESTION");
5558 endtime = (long) time(NULL);
5559 endtime -= starttime;
5560 rna(endtime * 1000, qe, o->chan, on, membername, qe->parent->autopauseunavail);
5561 do_hang(o);
5563 if (qe->parent->timeoutrestart) {
5564 start_time_tv = ast_tvnow();
5565 }
5566 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5567 ring_one(qe, outgoing, &numbusies);
5568 starttime = (long) time(NULL);
5569 }
5570 }
5571 numbusies++;
5572 break;
5574 ast_verb(3, "%s is ringing\n", ochan_name);
5575
5576 ast_channel_publish_dial(qe->chan, o->chan, on, "RINGING");
5577
5578 /* Start ring indication when the channel is ringing, if specified */
5579 if (qe->ring_when_ringing) {
5580 ast_moh_stop(qe->chan);
5582 }
5583 break;
5585 /* Ignore going off hook */
5586 break;
5588 if (o->block_connected_update) {
5589 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
5590 break;
5591 }
5594
5595 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
5601 break;
5602 }
5603
5604 /*
5605 * Prevent using the CallerID from the outgoing channel since we
5606 * got a connected line update from it.
5607 */
5608 o->dial_callerid_absent = 1;
5609
5610 if (ast_channel_connected_line_sub(o->chan, in, f, 1)) {
5612 }
5613 break;
5614 case AST_CONTROL_AOC:
5615 {
5616 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
5617 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
5619 o->aoc_s_rate_list = decoded;
5620 } else {
5621 ast_aoc_destroy_decoded(decoded);
5622 }
5623 }
5624 break;
5627 /*
5628 * Redirecting updates to the caller make sense only on single
5629 * call at a time strategies.
5630 */
5631 break;
5632 }
5633 if (o->block_connected_update) {
5634 ast_verb(3, "Redirecting update to %s prevented\n",
5635 inchan_name);
5636 break;
5637 }
5638 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
5639 ochan_name, inchan_name);
5640 if (ast_channel_redirecting_sub(o->chan, in, f, 1)) {
5642 }
5643 break;
5646 break;
5647 default:
5648 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
5649 break;
5650 }
5651 }
5652 ast_frfree(f);
5653 } else { /* ast_read() returned NULL */
5654 endtime = (long) time(NULL) - starttime;
5655 ast_channel_publish_dial(qe->chan, o->chan, on, "NOANSWER");
5656 rna(endtime * 1000, qe, o->chan, on, membername, 1);
5657 do_hang(o);
5659 if (qe->parent->timeoutrestart) {
5660 start_time_tv = ast_tvnow();
5661 }
5662 if (ast_remaining_ms(start_time_tv, orig) > 500) {
5663 ring_one(qe, outgoing, &numbusies);
5664 starttime = (long) time(NULL);
5665 }
5666 }
5667 }
5668 }
5669 }
5670
5671 /* If we received an event from the caller, deal with it. */
5672 if (winner == in) {
5673 f = ast_read(in);
5674 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
5675 /* Got hung up */
5676 *to = -1;
5677 if (f) {
5678 if (f->data.uint32) {
5680 }
5681 ast_frfree(f);
5682 }
5683 canceled_by_caller = 1;
5684 } else if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
5685 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
5686 *to = 0;
5687 ast_frfree(f);
5688 canceled_by_caller = 1;
5689 } else if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
5690 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
5691 *to = 0;
5692 *digit = f->subclass.integer;
5693 ast_frfree(f);
5694 canceled_by_caller = 1;
5695 }
5696 /* When caller hung up or pressed * or digit. */
5697 if (canceled_by_caller) {
5699 for (o = start; o; o = o->call_next) {
5700 if (o->chan) {
5701 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));
5702 }
5703 }
5704 return NULL;
5705 }
5706
5707 /* Send the frame from the in channel to all outgoing channels. */
5708 for (o = start; o; o = o->call_next) {
5709 if (!o->stillgoing || !o->chan) {
5710 /* This outgoing channel has died so don't send the frame to it. */
5711 continue;
5712 }
5713 switch (f->frametype) {
5714 case AST_FRAME_CONTROL:
5715 switch (f->subclass.integer) {
5717 if (o->block_connected_update) {
5718 ast_verb(3, "Connected line update to %s prevented.\n", ast_channel_name(o->chan));
5719 break;
5720 }
5721 if (ast_channel_connected_line_sub(in, o->chan, f, 1)) {
5723 }
5724 break;
5726 if (o->block_connected_update) {
5727 ast_verb(3, "Redirecting update to %s prevented.\n", ast_channel_name(o->chan));
5728 break;
5729 }
5730 if (ast_channel_redirecting_sub(in, o->chan, f, 1)) {
5732 }
5733 break;
5734 default:
5735 /* We are not going to do anything with this frame. */
5736 goto skip_frame;
5737 }
5738 break;
5739 default:
5740 /* We are not going to do anything with this frame. */
5741 goto skip_frame;
5742 }
5743 }
5744skip_frame:;
5745
5746 ast_frfree(f);
5747 }
5748 }
5749
5750 if (!*to) {
5751 for (o = start; o; o = o->call_next) {
5752 if (o->chan) {
5753 rna(orig, qe, o->chan, o->interface, o->member->membername, 1);
5754 }
5755 }
5756
5757 publish_dial_end_event(qe->chan, outgoing, NULL, "NOANSWER");
5758 }
5759
5760 return peer;
5761}
5762
5763/*!
5764 * \brief Check if we should start attempting to call queue members.
5765 *
5766 * A simple process, really. Count the number of members who are available
5767 * to take our call and then see if we are in a position in the queue at
5768 * which a member could accept our call.
5769 *
5770 * \param[in] qe The caller who wants to know if it is his turn
5771 * \retval 0 It is not our turn
5772 * \retval 1 It is our turn
5773 */
5774static int is_our_turn(struct queue_ent *qe)
5775{
5776 struct queue_ent *ch;
5777 int res;
5778 int avl;
5779 int idx = 0;
5780 /* This needs a lock. How many members are available to be served? */
5781 ao2_lock(qe->parent);
5782
5783 avl = num_available_members(qe->parent);
5784
5785 ch = qe->parent->head;
5786
5787 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
5788
5789 while ((idx < avl) && (ch) && (ch != qe)) {
5790 if (!ch->pending) {
5791 idx++;
5792 }
5793 ch = ch->next;
5794 }
5795
5796 ao2_unlock(qe->parent);
5797 /* If the queue entry is within avl [the number of available members] calls from the top ...
5798 * Autofill and position check added to support autofill=no (as only calls
5799 * from the front of the queue are valid when autofill is disabled)
5800 */
5801 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
5802 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
5803 res = 1;
5804 } else {
5805 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
5806 res = 0;
5807 }
5808
5809 /* Update realtime members if this is the first call and number of avalable members is 0 */
5810 if (avl == 0 && qe->pos == 1) {
5812 }
5813
5814 return res;
5815}
5816
5817/*!
5818 * \brief update rules for queues
5819 *
5820 * Calculate min/max penalties making sure if relative they stay within bounds.
5821 * Update queues penalty and set dialplan vars, goto next list entry.
5822*/
5823static void update_qe_rule(struct queue_ent *qe)
5824{
5825 int max_penalty = INT_MAX;
5826
5827 if (qe->max_penalty != INT_MAX) {
5828 char max_penalty_str[20];
5829
5830 if (qe->pr->max_relative) {
5831 max_penalty = qe->max_penalty + qe->pr->max_value;
5832 } else {
5833 max_penalty = qe->pr->max_value;
5834 }
5835
5836 /* a relative change to the penalty could put it below 0 */
5837 if (max_penalty < 0) {
5838 max_penalty = 0;
5839 }
5840
5841 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
5842 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
5844 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
5845 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
5846 }
5847
5848 if (qe->min_penalty != INT_MAX) {
5849 char min_penalty_str[20];
5850 int min_penalty;
5851
5852 if (qe->pr->min_relative) {
5853 min_penalty = qe->min_penalty + qe->pr->min_value;
5854 } else {
5855 min_penalty = qe->pr->min_value;
5856 }
5857
5858 /* a relative change to the penalty could put it below 0 */
5859 if (min_penalty < 0) {
5860 min_penalty = 0;
5861 }
5862
5863 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
5865 }
5866
5867 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
5868 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
5870 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
5871 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
5872 }
5873
5874 if (qe->raise_penalty != INT_MAX) {
5875 char raise_penalty_str[20];
5876 int raise_penalty;
5877
5878 if (qe->pr->raise_relative) {
5880 } else {
5882 }
5883
5884 /* a relative change to the penalty could put it below 0 */
5885 if (raise_penalty < 0) {
5886 raise_penalty = 0;
5887 }
5888
5889 if (max_penalty != INT_MAX && raise_penalty > max_penalty) {
5891 }
5892
5893 snprintf(raise_penalty_str, sizeof(raise_penalty_str), "%d", raise_penalty);
5894 pbx_builtin_setvar_helper(qe->chan, "QUEUE_RAISE_PENALTY", raise_penalty_str);
5896 ast_debug(3, "Setting raised penalty to %d for caller %s since %d seconds have elapsed\n",
5897 qe->raise_penalty, ast_channel_name(qe->chan), qe->pr->time);
5898 }
5899
5900 qe->pr = AST_LIST_NEXT(qe->pr, list);
5901}
5902
5903/*! \brief The waiting areas for callers who are not actively calling members
5904 *
5905 * This function is one large loop. This function will return if a caller
5906 * either exits the queue or it becomes that caller's turn to attempt calling
5907 * queue members. Inside the loop, we service the caller with periodic announcements,
5908 * holdtime announcements, etc. as configured in queues.conf
5909 *
5910 * \retval 0 if the caller's turn has arrived
5911 * \retval -1 if the caller should exit the queue.
5912 */
5913static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
5914{
5915 int res = 0;
5916
5917 /* This is the holding pen for callers 2 through maxlen */
5918 for (;;) {
5919
5920 /* A request to withdraw this call from the queue arrived */
5921 if (qe->withdraw) {
5922 *reason = QUEUE_WITHDRAW;
5923 res = 1;
5924 break;
5925 }
5926
5927 if (is_our_turn(qe)) {
5928 break;
5929 }
5930
5931 /* If we have timed out, break out */
5932 if (qe->expire && (time(NULL) >= qe->expire)) {
5933 *reason = QUEUE_TIMEOUT;
5934 break;
5935 }
5936
5937 if (qe->parent->leavewhenempty) {
5938 int status = 0;
5939
5941 record_abandoned(qe);
5942 *reason = QUEUE_LEAVEEMPTY;
5943 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));
5944 res = -1;
5945 qe->handled = -1;
5946 break;
5947 }
5948 }
5949
5950 /* Make a position announcement, if enabled */
5951 if (qe->parent->announcefrequency &&
5952 (res = say_position(qe,ringing))) {
5953 break;
5954 }
5955
5956 /* If we have timed out, break out */
5957 if (qe->expire && (time(NULL) >= qe->expire)) {
5958 *reason = QUEUE_TIMEOUT;
5959 break;
5960 }
5961
5962 /* Make a periodic announcement, if enabled */
5965 break;
5966
5967 /* see if we need to move to the next penalty level for this queue */
5968 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
5969 update_qe_rule(qe);
5970 }
5971
5972 /* If we have timed out, break out */
5973 if (qe->expire && (time(NULL) >= qe->expire)) {
5974 *reason = QUEUE_TIMEOUT;
5975 break;
5976 }
5977
5978 /* Wait a second before checking again */
5979 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
5980 if (res > 0 && !valid_exit(qe, res)) {
5981 res = 0;
5982 } else {
5983 break;
5984 }
5985 }
5986
5987 /* If we have timed out, break out */
5988 if (qe->expire && (time(NULL) >= qe->expire)) {
5989 *reason = QUEUE_TIMEOUT;
5990 break;
5991 }
5992 }
5993
5994 return res;
5995}
5996
5997/*!
5998 * \brief update the queue status
5999 * \retval 0 always
6000*/
6001static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
6002{
6003 int oldtalktime;
6004 int newtalktime = time(NULL) - starttime;
6005 struct member *mem;
6006 struct call_queue *qtmp;
6007 struct ao2_iterator queue_iter;
6008
6009 /* It is possible for us to be called when a call has already been considered terminated
6010 * and data updated, so to ensure we only act on the call that the agent is currently in
6011 * we check when the call was bridged.
6012 */
6013 if (!starttime || (member->starttime != starttime)) {
6014 return 0;
6015 }
6016
6017 if (shared_lastcall) {
6018 queue_iter = ao2_iterator_init(queues, 0);
6019 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
6020 ao2_lock(qtmp);
6021 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
6022 time(&mem->lastcall);
6023 mem->calls++;
6024 mem->callcompletedinsl = 0;
6025 mem->starttime = 0;
6026 mem->lastqueue = q;
6027 ao2_ref(mem, -1);
6028 }
6029 ao2_unlock(qtmp);
6030 queue_t_unref(qtmp, "Done with iterator");
6031 }
6032 ao2_iterator_destroy(&queue_iter);
6033 } else {
6034 ao2_lock(q);
6035 time(&member->lastcall);
6037 member->calls++;
6038 member->starttime = 0;
6039 member->lastqueue = q;
6040 ao2_unlock(q);
6041 }
6042 /* Member might never experience any direct status change (local
6043 * channel with forwarding in particular). If that's the case,
6044 * this is the last chance to remove it from pending or subsequent
6045 * calls will not occur.
6046 */
6048
6049 ao2_lock(q);
6050 q->callscompleted++;
6051 if (callcompletedinsl) {
6052 q->callscompletedinsl++;
6053 }
6054 if (q->callscompleted == 1) {
6055 q->talktime = newtalktime;
6056 } else {
6057 /* Calculate talktime using the same exponential average as holdtime code */
6058 oldtalktime = q->talktime;
6059 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
6060 }
6061 ao2_unlock(q);
6062 return 0;
6063}
6064
6065/*! \brief Calculate the metric of each member in the outgoing callattempts
6066 *
6067 * A numeric metric is given to each member depending on the ring strategy used
6068 * by the queue. Members with lower metrics will be called before members with
6069 * higher metrics
6070 * \retval -1 if penalties are exceeded
6071 * \retval 0 otherwise
6072 */
6073static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
6074{
6075 /* disregarding penalty on too few members? */
6076 int membercount = ao2_container_count(q->members);
6077 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
6078 int penalty = mem->penalty;
6079
6080 if (usepenalty) {
6081 if (qe->raise_penalty != INT_MAX && penalty < qe->raise_penalty) {
6082 /* Low penalty is raised up to the current minimum */
6083 penalty = qe->raise_penalty;
6084 }
6085 if ((qe->max_penalty != INT_MAX && penalty > qe->max_penalty) ||
6086 (qe->min_penalty != INT_MAX && penalty < qe->min_penalty)) {
6087 return -1;
6088 }
6089 } else {
6090 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
6091 membercount, q->penaltymemberslimit);
6092 }
6093
6094 switch (q->strategy) {
6096 /* Everyone equal, except for penalty */
6097 tmp->metric = penalty * 1000000 * usepenalty;
6098 break;
6100 if (pos < qe->linpos) {
6101 tmp->metric = 1000 + pos;
6102 } else {
6103 if (pos > qe->linpos) {
6104 /* Indicate there is another priority */
6105 qe->linwrapped = 1;
6106 }
6107 tmp->metric = pos;
6108 }
6109 tmp->metric += penalty * 1000000 * usepenalty;
6110 break;
6113 pos = mem->queuepos;
6114 if (pos < q->rrpos) {
6115 tmp->metric = 1000 + pos;
6116 } else {
6117 if (pos > q->rrpos) {
6118 /* Indicate there is another priority */
6119 q->wrapped = 1;
6120 }
6121 tmp->metric = pos;
6122 }
6123 tmp->metric += penalty * 1000000 * usepenalty;
6124 break;
6126 tmp->metric = ast_random() % 1000;
6127 tmp->metric += penalty * 1000000 * usepenalty;
6128 break;
6130 tmp->metric = ast_random() % ((1 + penalty) * 1000);
6131 break;
6133 tmp->metric = mem->calls;
6134 tmp->metric += penalty * 1000000 * usepenalty;
6135 break;
6137 if (!mem->lastcall) {
6138 tmp->metric = 0;
6139 } else {
6140 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
6141 }
6142 tmp->metric += penalty * 1000000 * usepenalty;
6143 break;
6144 default:
6145 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
6146 break;
6147 }
6148 return 0;
6149}
6150
6154 TRANSFER
6156
6157/*! \brief Send out AMI message with member call completion status information */
6158static void send_agent_complete(const char *queuename, struct ast_channel_snapshot *caller,
6159 struct ast_channel_snapshot *peer, const struct member *member, time_t holdstart,
6160 time_t callstart, enum agent_complete_reason rsn)
6161{
6162 const char *reason = NULL; /* silence dumb compilers */
6163 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
6164
6165 switch (rsn) {
6166 case CALLER:
6167 reason = "caller";
6168 break;
6169 case AGENT:
6170 reason = "agent";
6171 break;
6172 case TRANSFER:
6173 reason = "transfer";
6174 break;
6175 }
6176
6177 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I, s: s}",
6178 "Queue", queuename,
6179 "Interface", member->interface,
6180 "MemberName", member->membername,
6181 "HoldTime", (ast_json_int_t)(callstart - holdstart),
6182 "TalkTime", (ast_json_int_t)(time(NULL) - callstart),
6183 "Reason", reason ?: "");
6184
6186 queue_agent_complete_type(), blob);
6187}
6188
6189static void queue_agent_cb(void *userdata, struct stasis_subscription *sub,
6190 struct stasis_message *msg)
6191{
6192 struct ast_channel_blob *agent_blob;
6193
6194 agent_blob = stasis_message_data(msg);
6195
6197 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6198 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6199 "AGENTLOGIN", "%s", agent_blob->snapshot->base->name);
6201 ast_queue_log("NONE", agent_blob->snapshot->base->uniqueid,
6202 ast_json_string_get(ast_json_object_get(agent_blob->blob, "agent")),
6203 "AGENTLOGOFF", "%s|%ld", agent_blob->snapshot->base->name,
6204 (long) ast_json_integer_get(ast_json_object_get(agent_blob->blob, "logintime")));
6205 }
6206}
6207
6208/*!
6209 * \brief Structure representing relevant data during a local channel optimization
6210 *
6211 * The reason we care about local channel optimizations is that we want to be able
6212 * to accurately report when the caller and queue member have stopped talking to
6213 * each other. A local channel optimization can cause it to appear that the conversation
6214 * has stopped immediately after it has begun. By tracking that the relevant channels
6215 * to monitor have changed due to a local channel optimization, we can give accurate
6216 * reports.
6217 *
6218 * Local channel optimizations for queues are restricted from their normal operation.
6219 * Bridges created by queues can only be the destination of local channel optimizations,
6220 * not the source. In addition, move-swap local channel optimizations are the only
6221 * permitted types of local channel optimization.
6222 *
6223 * This data is populated when we are told that a local channel optimization begin
6224 * is occurring. When we get told the optimization has ended successfully, we then
6225 * apply the data here into the queue_stasis_data.
6226 */
6228 /*! The uniqueid of the channel that will be taking the place of the caller or member */
6230 /*! Indication of whether we think there is a local channel optimization in progress */
6232 /*! The identifier for this local channel optimization */
6233 unsigned int id;
6234};
6235
6236/*!
6237 * \brief User data for stasis subscriptions used for queue calls.
6238 *
6239 * app_queue subscribes to channel and bridge events for all bridged calls.
6240 * app_queue cares about the following events:
6241 *
6242 * \li bridge enter: To determine the unique ID of the bridge created for the call.
6243 * \li blind transfer: To send an appropriate agent complete event.
6244 * \li attended transfer: To send an appropriate agent complete event.
6245 * \li local optimization: To update caller and member unique IDs for the call.
6246 * \li hangup: To send an appropriate agent complete event.
6247 *
6248 * The stasis subscriptions last until we determine that the caller and the member
6249 * are no longer bridged with each other.
6250 */
6253 /*! The unique ID of the caller's channel. */
6255 /*! The unique ID of the queue member's channel */
6257 /*! The unique ID of the bridge created by the queue */
6260 /*! The relevant queue */
6262 /*! The queue member that has answered the call */
6264 /*! The time at which the caller entered the queue. Start of the caller's hold time */
6266 /*! The time at which the member answered the call. */
6268 /*! The original position of the caller when he entered the queue */
6270 /*! Indication if the call was answered within the configured service level of the queue */
6272 /*! Indicates if the stasis subscriptions are shutting down */
6274 /*! The stasis message router for bridge events */
6276 /*! The stasis message router for channel events */
6278 /*! Local channel optimization details for the caller */
6280 /*! Local channel optimization details for the member */
6282};
6283
6284/*!
6285 * \internal
6286 * \brief Free memory for a queue_stasis_data
6287 */
6288static void queue_stasis_data_destructor(void *obj)
6289{
6290 struct queue_stasis_data *queue_data = obj;
6291
6292 /* This can only happen if refcounts for this object have got severely messed up */
6293 ast_assert(queue_data->bridge_router == NULL);
6294 ast_assert(queue_data->channel_router == NULL);
6295
6296 ao2_cleanup(queue_data->member);
6297 queue_unref(queue_data->queue);
6298 ast_string_field_free_memory(queue_data);
6299}
6300
6301/*!
6302 * \internal
6303 * \brief End all stasis subscriptions on a queue_stasis_data
6304 */
6305static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
6306{
6307 SCOPED_AO2LOCK(lock, queue_data);
6308
6309 queue_data->dying = 1;
6311 queue_data->bridge_router = NULL;
6313 queue_data->channel_router = NULL;
6314}
6315
6316/*!
6317 * \internal
6318 * \brief Allocate a queue_stasis_data and initialize its data.
6319 */
6321 struct ast_channel *peer, struct member *mem, time_t holdstart,
6322 time_t starttime, int callcompletedinsl)
6323{
6324 struct queue_stasis_data *queue_data;
6325
6326 queue_data = ao2_alloc(sizeof(*queue_data), queue_stasis_data_destructor);
6327 if (!queue_data) {
6328 return NULL;
6329 }
6330
6331 if (ast_string_field_init(queue_data, 64)) {
6332 ao2_cleanup(queue_data);
6333 return NULL;
6334 }
6335
6338 queue_data->queue = queue_ref(qe->parent);
6339 queue_data->starttime = starttime;
6340 queue_data->holdstart = holdstart;
6342 queue_data->caller_pos = qe->opos;
6343 ao2_ref(mem, +1);
6344 queue_data->member = mem;
6345
6346 return queue_data;
6347}
6348
6349/*!
6350 * \internal
6351 * \brief Log an attended transfer in the queue log.
6352 *
6353 * Attended transfer queue log messages vary based on the method by which the
6354 * attended transfer was completed.
6355 *
6356 * \param queue_data Data pertaining to the particular call in the queue.
6357 * \param atxfer_msg The stasis attended transfer message data.
6358 */
6359static void log_attended_transfer(struct queue_stasis_data *queue_data,
6360 struct ast_attended_transfer_message *atxfer_msg)
6361{
6362 RAII_VAR(struct ast_str *, transfer_str, ast_str_create(32), ast_free);
6363
6364 if (!transfer_str) {
6365 ast_log(LOG_WARNING, "Unable to log attended transfer to queue log\n");
6366 return;
6367 }
6368
6369 switch (atxfer_msg->dest_type) {
6371 ast_str_set(&transfer_str, 0, "BRIDGE|%s", atxfer_msg->dest.bridge);
6372 break;
6375 ast_str_set(&transfer_str, 0, "APP|%s", atxfer_msg->dest.app);
6376 break;
6378 ast_str_set(&transfer_str, 0, "LINK|%s|%s", atxfer_msg->dest.links[0]->base->name,
6379 atxfer_msg->dest.links[1]->base->name);
6380 break;
6383 /* Threeways are headed off and should not be logged here */
6384 ast_assert(0);
6385 return;
6386 }
6387
6388 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername, "ATTENDEDTRANSFER", "%s|%ld|%ld|%d",
6389 ast_str_buffer(transfer_str),
6390 (long) (queue_data->starttime - queue_data->holdstart),
6391 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6392}
6393
6394/*!
6395 * \internal
6396 * \brief Handle a stasis bridge enter event.
6397 *
6398 * We track this particular event in order to learn what bridge
6399 * was created for the queue call.
6400 *
6401 * \param userdata Data pertaining to the particular call in the queue.
6402 * \param sub The stasis subscription on which the message occurred.
6403 * \param msg The stasis message for the bridge enter event
6404 */
6405static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub,
6406 struct stasis_message *msg)
6407{
6408 struct queue_stasis_data *queue_data = userdata;
6409 struct ast_bridge_blob *enter_blob = stasis_message_data(msg);
6410 SCOPED_AO2LOCK(lock, queue_data);
6411
6412 if (queue_data->dying) {
6413 return;
6414 }
6415
6416 if (!ast_strlen_zero(queue_data->bridge_uniqueid)) {
6417 return;
6418 }
6419
6420 if (!strcmp(enter_blob->channel->base->uniqueid, queue_data->caller_uniqueid)) {
6421 ast_string_field_set(queue_data, bridge_uniqueid,
6422 enter_blob->bridge->uniqueid);
6423 ast_debug(3, "Detected entry of caller channel %s into bridge %s\n",
6424 enter_blob->channel->base->name, queue_data->bridge_uniqueid);
6425 }
6426}
6427
6428/*!
6429 * \brief Handle a blind transfer event
6430 *
6431 * This event is important in order to be able to log the end of the
6432 * call to the queue log and to stasis.
6433 *
6434 * \param userdata Data pertaining to the particular call in the queue.
6435 * \param sub The stasis subscription on which the message occurred.
6436 * \param msg The stasis message for the blind transfer event
6437 */
6438static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub,
6439 struct stasis_message *msg)
6440{
6441 struct queue_stasis_data *queue_data = userdata;
6442 struct ast_blind_transfer_message *transfer_msg = stasis_message_data(msg);
6443 const char *exten;
6444 const char *context;
6445 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6446 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6447
6448 if (transfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS) {
6449 return;
6450 }
6451
6452 ao2_lock(queue_data);
6453
6454 if (queue_data->dying) {
6455 ao2_unlock(queue_data);
6456 return;
6457 }
6458
6459 if (ast_strlen_zero(queue_data->bridge_uniqueid) ||
6460 strcmp(queue_data->bridge_uniqueid, transfer_msg->bridge->uniqueid)) {
6461 ao2_unlock(queue_data);
6462 return;
6463 }
6464
6465 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6466 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6467
6468 ao2_unlock(queue_data);
6469
6470 exten = transfer_msg->exten;
6471 context = transfer_msg->context;
6472
6473 ast_debug(3, "Detected blind transfer in queue %s\n", queue_data->queue->name);
6474 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6475 "BLINDTRANSFER", "%s|%s|%ld|%ld|%d",
6476 exten, context,
6477 (long) (queue_data->starttime - queue_data->holdstart),
6478 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6479
6480 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6481 queue_data->holdstart, queue_data->starttime, TRANSFER);
6482 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6483 queue_data->starttime);
6484 remove_stasis_subscriptions(queue_data);
6485}
6486
6487/*!
6488 * \brief Handle an attended transfer event
6489 *
6490 * This event is important in order to be able to log the end of the
6491 * call to the queue log and to stasis.
6492 *
6493 * \param userdata Data pertaining to the particular call in the queue.
6494 * \param sub The stasis subscription on which the message occurred.
6495 * \param msg The stasis message for the attended transfer event.
6496 */
6497static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub,
6498 struct stasis_message *msg)
6499{
6500 struct queue_stasis_data *queue_data = userdata;
6501 struct ast_attended_transfer_message *atxfer_msg = stasis_message_data(msg);
6502 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6503 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6504
6505 if (atxfer_msg->result != AST_BRIDGE_TRANSFER_SUCCESS ||
6507 return;
6508 }
6509
6510 ao2_lock(queue_data);
6511
6512 if (queue_data->dying) {
6513 ao2_unlock(queue_data);
6514 return;
6515 }
6516
6517 if (ast_strlen_zero(queue_data->bridge_uniqueid)) {
6518 ao2_unlock(queue_data);
6519 return;
6520 }
6521
6522 if ((!atxfer_msg->to_transferee.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6523 atxfer_msg->to_transferee.bridge_snapshot->uniqueid)) &&
6524 (!atxfer_msg->to_transfer_target.bridge_snapshot || strcmp(queue_data->bridge_uniqueid,
6526 ao2_unlock(queue_data);
6527 return;
6528 }
6529
6530 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6531 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6532
6533 ao2_unlock(queue_data);
6534
6535 ast_debug(3, "Detected attended transfer in queue %s\n", queue_data->queue->name);
6536 log_attended_transfer(queue_data, atxfer_msg);
6537
6538 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6539 queue_data->holdstart, queue_data->starttime, TRANSFER);
6540 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6541 queue_data->starttime);
6542 remove_stasis_subscriptions(queue_data);
6543}
6544
6545/*!
6546 * \internal
6547 * \brief Callback for all stasis bridge events
6548 *
6549 * Based on the event and what bridge it is on, the task is farmed out to relevant
6550 * subroutines for further processing.
6551 */
6552static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub,
6553 struct stasis_message *msg)
6554{
6556 ao2_cleanup(userdata);
6557 }
6558}
6559
6560/*!
6561 * \internal
6562 * \brief Handler for the beginning of a local channel optimization
6563 *
6564 * This method gathers data relevant to the local channel optimization and stores
6565 * it to be used once the local optimization completes.
6566 *
6567 * \param userdata Data pertaining to the particular call in the queue.
6568 * \param sub The stasis subscription on which the message occurred.
6569 * \param msg The stasis message for the local optimization begin event
6570 */
6571static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub,
6572 struct stasis_message *msg)
6573{
6574 struct queue_stasis_data *queue_data = userdata;
6575 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6576 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6577 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6578 struct ast_channel_snapshot *source = ast_multi_channel_blob_get_channel(optimization_blob, "source");
6579 struct local_optimization *optimization;
6580 unsigned int id;
6581 SCOPED_AO2LOCK(lock, queue_data);
6582
6583 if (queue_data->dying) {
6584 return;
6585 }
6586
6587 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6588 optimization = &queue_data->member_optimize;
6589 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6590 optimization = &queue_data->caller_optimize;
6591 } else {
6592 return;
6593 }
6594
6595 /* We only allow move-swap optimizations, so there had BETTER be a source */
6596 ast_assert(source != NULL);
6597
6598 optimization->source_chan_uniqueid = ast_strdup(source->base->uniqueid);
6599 if (!optimization->source_chan_uniqueid) {
6600 ast_log(LOG_ERROR, "Unable to track local channel optimization for channel %s. Expect further errors\n", local_one->base->name);
6601 return;
6602 }
6604
6605 optimization->id = id;
6606 optimization->in_progress = 1;
6607}
6608
6609/*!
6610 * \internal
6611 * \brief Handler for the end of a local channel optimization
6612 *
6613 * This method takes the data gathered during the local channel optimization begin
6614 * event and applies it to the queue stasis data appropriately. This generally involves
6615 * updating the caller or member unique ID with the channel that is taking the place of
6616 * the previous caller or member.
6617 *
6618 * \param userdata Data pertaining to the particular call in the queue.
6619 * \param sub The stasis subscription on which the message occurred.
6620 * \param msg The stasis message for the local optimization end event
6621 */
6622static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub,
6623 struct stasis_message *msg)
6624{
6625 struct queue_stasis_data *queue_data = userdata;
6626 struct ast_multi_channel_blob *optimization_blob = stasis_message_data(msg);
6627 struct ast_channel_snapshot *local_one = ast_multi_channel_blob_get_channel(optimization_blob, "1");
6628 struct ast_channel_snapshot *local_two = ast_multi_channel_blob_get_channel(optimization_blob, "2");
6629 struct local_optimization *optimization;
6630 int is_caller;
6631 unsigned int id;
6632 SCOPED_AO2LOCK(lock, queue_data);
6633
6634 if (queue_data->dying) {
6635 return;
6636 }
6637
6638 if (!strcmp(local_one->base->uniqueid, queue_data->member_uniqueid)) {
6639 optimization = &queue_data->member_optimize;
6640 is_caller = 0;
6641 } else if (!strcmp(local_two->base->uniqueid, queue_data->caller_uniqueid)) {
6642 optimization = &queue_data->caller_optimize;
6643 is_caller = 1;
6644 } else {
6645 return;
6646 }
6647
6649
6650 if (!optimization->in_progress) {
6651 ast_log(LOG_WARNING, "Told of a local optimization end when we had no previous begin\n");
6652 return;
6653 }
6654
6655 if (id != optimization->id) {
6656 ast_log(LOG_WARNING, "Local optimization end event ID does not match begin (%u != %u)\n",
6657 id, optimization->id);
6658 return;
6659 }
6660
6661 if (is_caller) {
6662 ast_debug(3, "Local optimization: Changing queue caller uniqueid from %s to %s\n",
6663 queue_data->caller_uniqueid, optimization->source_chan_uniqueid);
6664 ast_string_field_set(queue_data, caller_uniqueid, optimization->source_chan_uniqueid);
6665 } else {
6666 ast_debug(3, "Local optimization: Changing queue member uniqueid from %s to %s\n",
6667 queue_data->member_uniqueid, optimization->source_chan_uniqueid);
6668 ast_string_field_set(queue_data, member_uniqueid, optimization->source_chan_uniqueid);
6669 }
6670
6671 optimization->in_progress = 0;
6672}
6673
6674/*!
6675 * \internal
6676 * \brief Handler for hangup stasis event
6677 *
6678 * This is how we determine that the caller or member has hung up and the call
6679 * has ended. An appropriate queue log and stasis message are raised in this
6680 * callback.
6681 *
6682 * \param userdata Data pertaining to the particular call in the queue.
6683 * \param sub The stasis subscription on which the message occurred.
6684 * \param msg The stasis message for the hangup event.
6685 */
6686static void handle_hangup(void *userdata, struct stasis_subscription *sub,
6687 struct stasis_message *msg)
6688{
6689 struct queue_stasis_data *queue_data = userdata;
6690 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6691 RAII_VAR(struct ast_channel_snapshot *, caller_snapshot, NULL, ao2_cleanup);
6692 RAII_VAR(struct ast_channel_snapshot *, member_snapshot, NULL, ao2_cleanup);
6693 RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
6694 enum agent_complete_reason reason;
6695
6696 ao2_lock(queue_data);
6697
6698 if (queue_data->dying) {
6699 ao2_unlock(queue_data);
6700 return;
6701 }
6702
6703 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6704 reason = CALLER;
6705 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6706 reason = AGENT;
6707 } else {
6708 ao2_unlock(queue_data);
6709 return;
6710 }
6711
6712 chan = ast_channel_get_by_name(channel_blob->snapshot->base->name);
6713 if (chan && (ast_channel_has_role(chan, AST_TRANSFERER_ROLE_NAME) ||
6714 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER")) ||
6715 !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER")))) {
6716 /* Channel that is hanging up is doing it as part of a transfer.
6717 * We'll get a transfer event later
6718 */
6719 ao2_unlock(queue_data);
6720 return;
6721 }
6722
6723 caller_snapshot = ast_channel_snapshot_get_latest(queue_data->caller_uniqueid);
6724 member_snapshot = ast_channel_snapshot_get_latest(queue_data->member_uniqueid);
6725
6726 ao2_unlock(queue_data);
6727
6728 ast_debug(3, "Detected hangup of queue %s channel %s\n", reason == CALLER ? "caller" : "member",
6729 channel_blob->snapshot->base->name);
6730
6731 ast_queue_log(queue_data->queue->name, queue_data->caller_uniqueid, queue_data->member->membername,
6732 reason == CALLER ? "COMPLETECALLER" : "COMPLETEAGENT", "%ld|%ld|%d",
6733 (long) (queue_data->starttime - queue_data->holdstart),
6734 (long) (time(NULL) - queue_data->starttime), queue_data->caller_pos);
6735
6736 send_agent_complete(queue_data->queue->name, caller_snapshot, member_snapshot, queue_data->member,
6737 queue_data->holdstart, queue_data->starttime, reason);
6738 update_queue(queue_data->queue, queue_data->member, queue_data->callcompletedinsl,
6739 queue_data->starttime);
6740 remove_stasis_subscriptions(queue_data);
6741}
6742
6743static void handle_masquerade(void *userdata, struct stasis_subscription *sub,
6744 struct stasis_message *msg)
6745{
6746 struct queue_stasis_data *queue_data = userdata;
6747 struct ast_channel_blob *channel_blob = stasis_message_data(msg);
6748 const char *new_channel_id;
6749
6750 new_channel_id = ast_json_string_get(ast_json_object_get(channel_blob->blob, "newchanneluniqueid"));
6751
6752 ao2_lock(queue_data);
6753
6754 if (queue_data->dying) {
6755 ao2_unlock(queue_data);
6756 return;
6757 }
6758
6759 if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->caller_uniqueid)) {
6760 ast_debug(1, "Replacing caller channel %s with %s due to masquerade\n", queue_data->caller_uniqueid, new_channel_id);
6761 ast_string_field_set(queue_data, caller_uniqueid, new_channel_id);
6762 } else if (!strcmp(channel_blob->snapshot->base->uniqueid, queue_data->member_uniqueid)) {
6763 ast_debug(1, "Replacing member channel %s with %s due to masquerade\n", queue_data->member_uniqueid, new_channel_id);
6764 ast_string_field_set(queue_data, member_uniqueid, new_channel_id);
6765 }
6766
6767 ao2_unlock(queue_data);
6768}
6769
6770/*!
6771 * \internal
6772 * \brief Callback for all stasis channel events
6773 *
6774 * Based on the event and the channels involved, the work is farmed out into
6775 * subroutines for further processing.
6776 */
6777static void queue_channel_cb(void *userdata, struct stasis_subscription *sub,
6778 struct stasis_message *msg)
6779{
6781 ao2_cleanup(userdata);
6782 }
6783}
6784
6785/*!
6786 * \internal
6787 * \brief Create stasis subscriptions for a particular call in the queue.
6788 *
6789 * These subscriptions are created once the call has been answered. The subscriptions
6790 * are put in place so that call progress may be tracked. Once the call can be determined
6791 * to have ended, then messages are logged to the queue log and stasis events are emitted.
6792 *
6793 * \param qe The queue entry representing the caller
6794 * \param peer The channel that has answered the call
6795 * \param mem The queue member that answered the call
6796 * \param holdstart The time at which the caller entered the queue
6797 * \param starttime The time at which the call was answered
6798 * \param callcompletedinsl Indicates if the call was answered within the configured service level of the queue.
6799 * \retval 0 Success
6800 * \retval non-zero Failure
6801 */
6802static int setup_stasis_subs(struct queue_ent *qe, struct ast_channel *peer, struct member *mem,
6803 time_t holdstart, time_t starttime, int callcompletedinsl)
6804{
6805 struct queue_stasis_data *queue_data = queue_stasis_data_alloc(qe, peer, mem, holdstart, starttime, callcompletedinsl);
6806
6807 if (!queue_data) {
6808 return -1;
6809 }
6810
6812 if (!queue_data->bridge_router) {
6813 ao2_ref(queue_data, -1);
6814 return -1;
6815 }
6816
6818 handle_bridge_enter, queue_data);
6820 handle_blind_transfer, queue_data);
6822 handle_attended_transfer, queue_data);
6824 queue_bridge_cb, queue_data);
6825
6827 if (!queue_data->channel_router) {
6828 /* Unsubscribing from the bridge router will remove the only ref of queue_data,
6829 * thus beginning the destruction process
6830 */
6832 queue_data->bridge_router = NULL;
6833 return -1;
6834 }
6835
6836 ao2_ref(queue_data, +1);
6840 handle_local_optimization_end, queue_data);
6842 handle_hangup, queue_data);
6844 handle_masquerade, queue_data);
6846 queue_channel_cb, queue_data);
6847
6848 return 0;
6849}
6850
6852 struct call_queue *q;
6854};
6855
6856static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
6857{
6858 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
6859 ao2_ref(qeb, +1);
6860 qeb->chan = originator;
6861}
6862
6863static void end_bridge_callback(void *data)
6864{
6865 struct queue_end_bridge *qeb = data;
6866 struct call_queue *q = qeb->q;
6867 struct ast_channel *chan = qeb->chan;
6868
6869 if (ao2_ref(qeb, -1) == 1) {
6870 set_queue_variables(q, chan);
6871 /* This unrefs the reference we made in try_calling when we allocated qeb */
6872 queue_t_unref(q, "Expire bridge_config reference");
6873 }
6874}
6875
6876/*!
6877 * \internal
6878 * \brief Setup the after bridge goto location on the peer.
6879 * \since 12.0.0
6880 *
6881 * \param chan Calling channel for bridge.
6882 * \param peer Peer channel for bridge.
6883 * \param opts Dialing option flags.
6884 * \param opt_args Dialing option argument strings.
6885 */
6886static void setup_peer_after_bridge_goto(struct ast_channel *chan, struct ast_channel *peer, struct ast_flags *opts, char *opt_args[])
6887{
6888 const char *context;
6889 const char *extension;
6890 int priority;
6891
6892 if (ast_test_flag(opts, OPT_CALLEE_GO_ON)) {
6893 ast_channel_lock(chan);
6897 ast_channel_unlock(chan);
6899 opt_args[OPT_ARG_CALLEE_GO_ON]);
6900 }
6901}
6902
6903static void escape_and_substitute(struct ast_channel *chan, const char *input,
6904 char *output, size_t size)
6905{
6906 const char *m = input;
6907 char escaped[size];
6908 char *p;
6909
6910 for (p = escaped; p < escaped + size - 1; p++, m++) {
6911 switch (*m) {
6912 case '^':
6913 if (*(m + 1) == '{') {
6914 *p = '$';
6915 }
6916 break;
6917 case ',':
6918 *p++ = '\\';
6919 /* Fall through */
6920 default:
6921 *p = *m;
6922 }
6923 if (*m == '\0')
6924 break;
6925 }
6926
6927 if (p == escaped + size) {
6928 escaped[size - 1] = '\0';
6929 }
6930
6931 pbx_substitute_variables_helper(chan, escaped, output, size - 1);
6932}
6933
6934static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
6935{
6936 char escaped_filename[256];
6937 char file_with_ext[sizeof(escaped_filename) + sizeof(qe->parent->monfmt)];
6938 char mixmonargs[1512];
6939 char escaped_monitor_exec[1024];
6940 const char *monitor_options;
6941 const char *monitor_exec;
6942
6943 escaped_monitor_exec[0] = '\0';
6944
6945 if (filename) {
6946 escape_and_substitute(qe->chan, filename, escaped_filename, sizeof(escaped_filename));
6947 } else {
6948 ast_copy_string(escaped_filename, ast_channel_uniqueid(qe->chan), sizeof(escaped_filename));
6949 }
6950
6952 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
6953 monitor_exec = ast_strdupa(monitor_exec);
6954 }
6955 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
6956 monitor_options = ast_strdupa(monitor_options);
6957 } else {
6958 monitor_options = "";
6959 }
6961
6962 if (monitor_exec) {
6963 escape_and_substitute(qe->chan, monitor_exec, escaped_monitor_exec, sizeof(escaped_monitor_exec));
6964 }
6965
6966 snprintf(file_with_ext, sizeof(file_with_ext), "%s.%s", escaped_filename, qe->parent->monfmt);
6967
6968 if (!ast_strlen_zero(escaped_monitor_exec)) {
6969 snprintf(mixmonargs, sizeof(mixmonargs), "b%s,%s", monitor_options, escaped_monitor_exec);
6970 } else {
6971 snprintf(mixmonargs, sizeof(mixmonargs), "b%s", monitor_options);
6972 }
6973
6974 ast_debug(1, "Arguments being passed to MixMonitor: %s,%s\n", file_with_ext, mixmonargs);
6975
6976 if (ast_start_mixmonitor(qe->chan, file_with_ext, mixmonargs)) {
6977 ast_log(LOG_WARNING, "Unable to start mixmonitor. Is the MixMonitor app loaded?\n");
6978 }
6979}
6980
6981/*!
6982 * \internal
6983 * \brief A large function which calls members, updates statistics, and bridges the caller and a member
6984 *
6985 * Here is the process of this function
6986 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
6987 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member.
6988 * 3. Call ring_one to place a call to the appropriate member(s)
6989 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
6990 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
6991 * 6. Start the monitor or mixmonitor if the option is set
6992 * 7. Remove the caller from the queue to allow other callers to advance
6993 * 8. Bridge the call.
6994 * 9. Do any post processing after the call has disconnected.
6995 *
6996 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
6997 * \param[in] opts the options passed as the third parameter to the Queue() application
6998 * \param[in] opt_args the options passed as the third parameter to the Queue() application
6999 * \param[in] announceoverride filename to play to user when waiting
7000 * \param[in] url the url passed as the fourth parameter to the Queue() application
7001 * \param[in,out] tries the number of times we have tried calling queue members
7002 * \param[out] noption set if the call to Queue() has the 'n' option set.
7003 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
7004 * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
7005 * \param[in] ringing 1 if the 'r' option is set, otherwise 0
7006 */
7007static 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)
7008{
7009 struct member *cur;
7010 struct callattempt *outgoing = NULL; /* the list of calls we are building */
7011 int to, orig;
7012 char oldexten[AST_MAX_EXTENSION]="";
7013 char oldcontext[AST_MAX_CONTEXT]="";
7014 char queuename[256]="";
7015 struct ast_channel *peer;
7016 struct callattempt *lpeer;
7017 struct member *member;
7018 struct ast_app *application;
7019 int res = 0, bridge = 0;
7020 int numbusies = 0;
7021 int x=0;
7022 char *announce = NULL;
7023 char digit = 0;
7024 time_t now = time(NULL);
7025 struct ast_bridge_config bridge_config;
7026 char nondataquality = 1;
7027 char *agiexec = NULL;
7028 char *gosubexec = NULL;
7029 const char *monitorfilename;
7030 int forwardsallowed = 1;
7031 int block_connected_line = 0;
7032 struct ao2_iterator memi;
7034 int callcompletedinsl;
7035 time_t starttime;
7036
7037 memset(&bridge_config, 0, sizeof(bridge_config));
7038 time(&now);
7039
7040 /* If we've already exceeded our timeout, then just stop
7041 * This should be extremely rare. queue_exec will take care
7042 * of removing the caller and reporting the timeout as the reason.
7043 */
7044 if (qe->expire && now >= qe->expire) {
7045 res = 0;
7046 goto out;
7047 }
7048
7049 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
7051 }
7052 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
7054 }
7055 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
7057 }
7058 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
7060 }
7061 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
7062 nondataquality = 0;
7063 }
7064 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
7066 }
7067 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
7069 }
7070 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
7072 }
7073 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
7075 }
7076 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
7079 (*tries)++;
7080 } else {
7081 *tries = ao2_container_count(qe->parent->members);
7082 }
7083 *noption = 1;
7084 }
7085 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
7086 forwardsallowed = 0;
7087 }
7089 block_connected_line = 1;
7090 }
7093 }
7096 }
7097 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
7099 }
7100
7101 /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
7102 (this is mainly to support unreal/local channels)
7103 */
7106 }
7107
7108 ao2_lock(qe->parent);
7109 ast_debug(1, "%s is trying to call a queue member.\n",
7110 ast_channel_name(qe->chan));
7111 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
7112 if (!ast_strlen_zero(qe->announce)) {
7113 announce = qe->announce;
7114 }
7115 if (!ast_strlen_zero(announceoverride)) {
7116 announce = announceoverride;
7117 }
7118
7119 memi = ao2_iterator_init(qe->parent->members, 0);
7120 while ((cur = ao2_iterator_next(&memi))) {
7121 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
7122 if (!tmp) {
7123 ao2_ref(cur, -1);
7124 ao2_iterator_destroy(&memi);
7125 ao2_unlock(qe->parent);
7126 goto out;
7127 }
7128
7129 /*
7130 * Seed the callattempt's connected line information with previously
7131 * acquired connected line info from the queued channel. The
7132 * previously acquired connected line info could have been set
7133 * through the CONNECTED_LINE dialplan function.
7134 */
7138
7139 tmp->block_connected_update = block_connected_line;
7140 tmp->stillgoing = 1;
7141 tmp->member = cur; /* Place the reference for cur into callattempt. */
7142 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
7143 /* Calculate the metric for the appropriate strategy. */
7144 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
7145 /* Put them in the list of outgoing thingies... We're ready now.
7146 XXX If we're forcibly removed, these outgoing calls won't get
7147 hung up XXX */
7148 tmp->q_next = outgoing;
7149 outgoing = tmp;
7150 } else {
7152 }
7153 }
7154 ao2_iterator_destroy(&memi);
7155
7157 /* Application arguments have higher timeout priority (behaviour for <=1.6) */
7158 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
7159 to = (qe->expire - now) * 1000;
7160 } else {
7161 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
7162 }
7163 } else {
7164 /* Config timeout is higher priority thatn application timeout */
7165 if (qe->expire && qe->expire<=now) {
7166 to = 0;
7167 } else if (qe->parent->timeout) {
7168 to = qe->parent->timeout * 1000;
7169 } else {
7170 to = -1;
7171 }
7172 }
7173 orig = to;
7174 ++qe->pending;
7175 ao2_unlock(qe->parent);
7176 /* Call the queue members with the best metric now. */
7177 ring_one(qe, outgoing, &numbusies);
7178 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
7180 forwardsallowed);
7181
7182 ao2_lock(qe->parent);
7185
7186 }
7189 }
7190 ao2_unlock(qe->parent);
7191 peer = lpeer ? lpeer->chan : NULL;
7192 if (!peer) {
7193 qe->pending = 0;
7194 if (to) {
7195 /* Must gotten hung up */
7196 res = -1;
7197 } else {
7198 /* User exited by pressing a digit */
7199 res = digit;
7200 }
7201 if (res == -1) {
7202 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
7203 }
7204 } else { /* peer is valid */
7205 RAII_VAR(struct ast_json *, blob, NULL, ast_json_unref);
7206 RAII_VAR(struct ast_str *, interfacevar, ast_str_create(325), ast_free);
7207 /* Ah ha! Someone answered within the desired timeframe. Of course after this
7208 we will always return with -1 so that it is hung up properly after the
7209 conversation. */
7210 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
7211 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7212 }
7213 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
7214 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
7215 }
7216 /* Update parameters for the queue */
7217 time(&now);
7218 recalc_holdtime(qe, (now - qe->start));
7219 member = lpeer->member;
7220 ao2_lock(qe->parent);
7221 callcompletedinsl = member->callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
7222 ao2_unlock(qe->parent);
7223 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
7224 ao2_ref(member, 1);
7226 outgoing = NULL;
7227 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
7228 int res2;
7229
7230 res2 = ast_autoservice_start(qe->chan);
7231 if (!res2) {
7232 if (qe->parent->memberdelay) {
7233 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
7234 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
7235 }
7236 if (!res2 && announce) {
7237 char *front;
7238 char *announcefiles = ast_strdupa(announce);
7239 while ((front = ast_strsep(&announcefiles, '&', AST_STRSEP_STRIP | AST_STRSEP_TRIM))) {
7240 if (play_file(peer, front) < 0) {
7241 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", front, ast_channel_name(peer));
7242 }
7243 }
7244 }
7245 if (!res2 && qe->parent->reportholdtime) {
7246 if (!play_file(peer, qe->parent->sound_reporthold)) {
7247 long holdtime, holdtimesecs;
7248
7249 time(&now);
7250 holdtime = labs((now - qe->start) / 60);
7251 holdtimesecs = labs((now - qe->start) % 60);
7252 if (holdtime > 0) {
7253 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7254 if (play_file(peer, qe->parent->sound_minutes) < 0) {
7255 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
7256 }
7257 }
7258 if (holdtimesecs > 1) {
7259 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), "n");
7260 if (play_file(peer, qe->parent->sound_seconds) < 0) {
7261 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
7262 }
7263 }
7264 }
7265 }
7267 }
7268 if (ast_check_hangup(peer)) {
7269 /* Agent must have hung up */
7270 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
7271 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
7272
7273 blob = ast_json_pack("{s: s, s: s, s: s}",
7274 "Queue", queuename,
7275 "Interface", member->interface,
7276 "MemberName", member->membername);
7277 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_dump_type(), blob);
7278
7282 ao2_ref(member, -1);
7283 goto out;
7284 } else if (ast_check_hangup(qe->chan)) {
7285 /* Caller must have hung up just before being connected */
7286 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
7287 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
7288 record_abandoned(qe);
7289 qe->handled = -1;
7293 ao2_ref(member, -1);
7294 return -1;
7295 }
7296 }
7297 /* Stop music on hold */
7298 if (ringing) {
7299 ast_indicate(qe->chan,-1);
7300 } else {
7301 ast_moh_stop(qe->chan);
7302 }
7303
7304 /* Make sure channels are compatible */
7305 res = ast_channel_make_compatible(qe->chan, peer);
7306 if (res < 0) {
7307 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
7308 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));
7309 record_abandoned(qe);
7313 ao2_ref(member, -1);
7314 return -1;
7315 }
7316
7317 /* Play announcement to the caller telling it's his turn if defined */
7319 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
7320 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
7321 }
7322 }
7323
7324 ao2_lock(qe->parent);
7325 /* if setinterfacevar is defined, make member variables available to the channel */
7326 /* use pbx_builtin_setvar to set a load of variables with one call */
7327 if (qe->parent->setinterfacevar && interfacevar) {
7328 ast_str_set(&interfacevar, 0, "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
7331 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7332 }
7333
7334 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
7335 /* use pbx_builtin_setvar to set a load of variables with one call */
7336 if (qe->parent->setqueueentryvar && interfacevar) {
7337 ast_str_set(&interfacevar, 0, "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
7338 (long) (time(NULL) - qe->start), qe->opos);
7340 pbx_builtin_setvar_multiple(peer, ast_str_buffer(interfacevar));
7341 }
7342
7343 ao2_unlock(qe->parent);
7344
7345 /* try to set queue variables if configured to do so*/
7347 set_queue_variables(qe->parent, peer);
7348
7349 setup_peer_after_bridge_goto(qe->chan, peer, &opts, opt_args);
7351 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
7352 monitorfilename = ast_strdupa(monitorfilename);
7353 }
7355
7356 /* Begin Monitoring */
7357 if (*qe->parent->monfmt) {
7358 setup_mixmonitor(qe, monitorfilename);
7359 }
7360 /* Drop out of the queue at this point, to prepare for next caller */
7361 leave_queue(qe);
7363 ast_debug(1, "app_queue: sendurl=%s.\n", url);
7364 ast_channel_sendurl(peer, url);
7365 }
7366
7367 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
7368 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
7369 if (!ast_strlen_zero(gosub)) {
7370 gosubexec = ast_strdupa(gosub);
7371 } else {
7372 if (qe->parent->membergosub) {
7373 gosubexec = ast_strdupa(qe->parent->membergosub);
7374 }
7375 }
7376
7377 if (!ast_strlen_zero(gosubexec)) {
7378 char *gosub_args = NULL;
7379 char *gosub_argstart;
7380
7381 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
7382
7383 gosub_argstart = strchr(gosubexec, ',');
7384 if (gosub_argstart) {
7385 const char *what_is_s = "s";
7386 *gosub_argstart = 0;
7387 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)) &&
7388 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7389 what_is_s = "~~s~~";
7390 }
7391 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
7392 gosub_args = NULL;
7393 }
7394 *gosub_argstart = ',';
7395 } else {
7396 const char *what_is_s = "s";
7397 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)) &&
7398 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
7399 what_is_s = "~~s~~";
7400 }
7401 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
7402 gosub_args = NULL;
7403 }
7404 }
7405 if (gosub_args) {
7406 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
7407 ast_free(gosub_args);
7408 } else {
7409 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
7410 }
7411 }
7412
7413 if (!ast_strlen_zero(agi)) {
7414 ast_debug(1, "app_queue: agi=%s.\n", agi);
7415 application = pbx_findapp("agi");
7416 if (application) {
7417 agiexec = ast_strdupa(agi);
7418 pbx_exec(qe->chan, application, agiexec);
7419 } else {
7420 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
7421 }
7422 }
7423 qe->handled++;
7424
7425 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
7426 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
7427
7428 blob = ast_json_pack("{s: s, s: s, s: s, s: I, s: I}",
7429 "Queue", queuename,
7430 "Interface", member->interface,
7431 "MemberName", member->membername,
7432 "HoldTime", (ast_json_int_t)(time(NULL) - qe->start),
7433 "RingTime", (ast_json_int_t)(orig - to > 0 ? (orig - to) / 1000 : 0));
7434 queue_publish_multi_channel_blob(qe->chan, peer, queue_agent_connect_type(), blob);
7435
7436 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
7437 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
7438
7439 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
7440 queue_end_bridge->q = qe->parent;
7441 queue_end_bridge->chan = qe->chan;
7445 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
7446 * to make sure to increase the refcount of this queue so it cannot be freed until we
7447 * are done with it. We remove this reference in end_bridge_callback.
7448 */
7449 queue_t_ref(qe->parent, "For bridge_config reference");
7450 }
7451
7452 ao2_lock(qe->parent);
7453 time(&member->starttime);
7454 starttime = member->starttime;
7455 ao2_unlock(qe->parent);
7456 /* As a queue member may end up in multiple calls at once if a transfer occurs with
7457 * a Local channel in the mix we pass the current call information (starttime) to the
7458 * Stasis subscriptions so when they update the queue member data it becomes a noop
7459 * if this call is no longer between the caller and the queue member.
7460 */
7461 setup_stasis_subs(qe, peer, member, qe->start, starttime, callcompletedinsl);
7462 bridge = ast_bridge_call_with_flags(qe->chan, peer, &bridge_config,
7464
7465 res = bridge ? bridge : 1;
7466 ao2_ref(member, -1);
7467 }
7468out:
7470
7471 return res;
7472}
7473
7474static int wait_a_bit(struct queue_ent *qe)
7475{
7476 /* Don't need to hold the lock while we setup the outgoing calls */
7477 int retrywait = qe->parent->retry * 1000;
7478
7479 int res = ast_waitfordigit(qe->chan, retrywait);
7480 if (res > 0 && !valid_exit(qe, res)) {
7481 res = 0;
7482 }
7483
7484 return res;
7485}
7486
7487static struct member *interface_exists(struct call_queue *q, const char *interface)
7488{
7489 struct member *mem;
7490 struct ao2_iterator mem_iter;
7491
7492 if (!q) {
7493 return NULL;
7494 }
7495 mem_iter = ao2_iterator_init(q->members, 0);
7496 while ((mem = ao2_iterator_next(&mem_iter))) {
7497 if (!strcasecmp(interface, mem->interface)) {
7498 ao2_iterator_destroy(&mem_iter);
7499 return mem;
7500 }
7501 ao2_ref(mem, -1);
7502 }
7503 ao2_iterator_destroy(&mem_iter);
7504
7505 return NULL;
7506}
7507
7508
7509/*! \brief Dump all members in a specific queue to the database
7510 * \code
7511 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
7512 * \endcode
7513 */
7514static void dump_queue_members(struct call_queue *pm_queue)
7515{
7516 struct member *cur_member;
7517 struct ast_str *value;
7518 struct ao2_iterator mem_iter;
7519
7520 if (!pm_queue) {
7521 return;
7522 }
7523
7524 /* 4K is a reasonable default for most applications, but we grow to
7525 * accommodate more if necessary. */
7526 if (!(value = ast_str_create(4096))) {
7527 return;
7528 }
7529
7530 mem_iter = ao2_iterator_init(pm_queue->members, 0);
7531 while ((cur_member = ao2_iterator_next(&mem_iter))) {
7532 if (!cur_member->dynamic) {
7533 ao2_ref(cur_member, -1);
7534 continue;
7535 }
7536
7537 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s;%s;%d",
7538 ast_str_strlen(value) ? "|" : "",
7539 cur_member->interface,
7540 cur_member->penalty,
7541 cur_member->paused,
7542 cur_member->membername,
7543 cur_member->state_interface,
7544 cur_member->reason_paused,
7545 cur_member->wrapuptime);
7546
7547 ao2_ref(cur_member, -1);
7548 }
7549 ao2_iterator_destroy(&mem_iter);
7550
7551 if (ast_str_strlen(value) && !cur_member) {
7552 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
7553 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
7554 }
7555 } else {
7556 /* Delete the entry if the queue is empty or there is an error */
7557 ast_db_del(pm_family, pm_queue->name);
7558 }
7559
7560 ast_free(value);
7561}
7562
7563/*! \brief Remove member from queue
7564 * \retval RES_NOT_DYNAMIC when they aren't a RT member
7565 * \retval RES_NOSUCHQUEUE queue does not exist
7566 * \retval RES_OKAY removed member from queue
7567 * \retval RES_EXISTS queue exists but no members
7568*/
7569static int remove_from_queue(const char *queuename, const char *interface)
7570{
7571 struct call_queue *q, tmpq = {
7572 .name = queuename,
7573 };
7574 struct member *mem, tmpmem;
7575 int res = RES_NOSUCHQUEUE;
7576
7577 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
7578 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
7579 ao2_lock(q);
7580 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
7581 /* XXX future changes should beware of this assumption!! */
7582 /*Change Penalty on realtime users*/
7584 update_realtime_member_field(mem, q->name, "penalty", "-1");
7585 } else if (!mem->dynamic) {
7586 ao2_ref(mem, -1);
7587 ao2_unlock(q);
7588 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
7589 return RES_NOT_DYNAMIC;
7590 }
7591 queue_publish_member_blob(queue_member_removed_type(), queue_member_blob_create(q, mem));
7592
7594 ao2_ref(mem, -1);
7595
7598 }
7599
7600 if (!num_available_members(q)) {
7602 }
7603
7604 res = RES_OKAY;
7605 } else {
7606 res = RES_EXISTS;
7607 }
7608 ao2_unlock(q);
7609 queue_t_unref(q, "Expiring temporary reference");
7610 }
7611
7612 return res;
7613}
7614
7615/*! \brief Add member to queue
7616 * \retval RES_NOT_DYNAMIC when they aren't a RT member
7617 * \retval RES_NOSUCHQUEUE queue does not exist
7618 * \retval RES_OKAY added member from queue
7619 * \retval RES_EXISTS queue exists but no members
7620 * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
7621*/
7622static 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)
7623{
7624 struct call_queue *q;
7625 struct member *new_member, *old_member;
7626 int res = RES_NOSUCHQUEUE;
7627
7628 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7629 * short-circuits if the queue is already in memory. */
7630 if (!(q = find_load_queue_rt_friendly(queuename))) {
7631 return res;
7632 }
7633
7634 ao2_lock(q);
7635 if ((old_member = interface_exists(q, interface)) == NULL) {
7637 new_member->dynamic = 1;
7638 if (reason_paused) {
7639 ast_copy_string(new_member->reason_paused, reason_paused, sizeof(new_member->reason_paused));
7640 }
7641 member_add_to_queue(q, new_member);
7642 queue_publish_member_blob(queue_member_added_type(), queue_member_blob_create(q, new_member));
7643
7644 if (is_member_available(q, new_member)) {
7646 }
7647
7648 ao2_ref(new_member, -1);
7649 new_member = NULL;
7650
7651 if (dump) {
7653 }
7654
7655 res = RES_OKAY;
7656 } else {
7657 res = RES_OUTOFMEMORY;
7658 }
7659 } else {
7660 ao2_ref(old_member, -1);
7661 res = RES_EXISTS;
7662 }
7663 ao2_unlock(q);
7664 queue_t_unref(q, "Expiring temporary reference");
7665
7666 return res;
7667}
7668
7669
7670/*! \brief Change priority caller into a queue
7671 * \retval RES_NOSUCHQUEUE queue does not exist
7672 * \retval RES_OKAY change priority
7673 * \retval RES_NOT_CALLER queue exists but no caller
7674*/
7675static int change_priority_caller_on_queue(const char *queuename, const char *caller, int priority, int immediate)
7676{
7677 struct call_queue *q;
7678 struct queue_ent *current, *prev = NULL, *caller_qe = NULL;
7679 int res = RES_NOSUCHQUEUE;
7680
7681 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7682 * short-circuits if the queue is already in memory. */
7683 if (!(q = find_load_queue_rt_friendly(queuename))) {
7684 return res;
7685 }
7686
7687 ao2_lock(q);
7688 res = RES_NOT_CALLER;
7689 for (current = q->head; current; current = current->next) {
7690 if (strcmp(ast_channel_name(current->chan), caller) == 0) {
7691 ast_debug(1, "%s Caller new priority %d in queue %s\n",
7692 caller, priority, queuename);
7693 current->prio = priority;
7694 if (immediate) {
7695 /* This caller is being immediately moved in the queue so remove them */
7696 if (prev) {
7697 prev->next = current->next;
7698 } else {
7699 q->head = current->next;
7700 }
7701 caller_qe = current;
7702 /* The position for all callers is not recalculated in here as it will
7703 * be updated when the moved caller is inserted back into the queue
7704 */
7705 }
7706 res = RES_OKAY;
7707 break;
7708 } else if (immediate) {
7709 prev = current;
7710 }
7711 }
7712
7713 if (caller_qe) {
7714 int inserted = 0, pos = 0;
7715
7716 /* If a caller queue entry exists, we are applying their priority immediately
7717 * and have to reinsert them at the correct position.
7718 */
7719 prev = NULL;
7720 current = q->head;
7721 while (current) {
7722 if (!inserted && (caller_qe->prio > current->prio)) {
7723 insert_entry(q, prev, caller_qe, &pos);
7724 inserted = 1;
7725 }
7726
7727 /* We always update the position as it may have changed */
7728 current->pos = ++pos;
7729
7730 /* Move to the next caller in the queue */
7731 prev = current;
7732 current = current->next;
7733 }
7734
7735 if (!inserted) {
7736 insert_entry(q, prev, caller_qe, &pos);
7737 }
7738 }
7739
7740 ao2_unlock(q);
7741 return res;
7742}
7743
7744
7745/*! \brief Request to withdraw a caller from a queue
7746 * \retval RES_NOSUCHQUEUE queue does not exist
7747 * \retval RES_OKAY withdraw request sent
7748 * \retval RES_NOT_CALLER queue exists but no caller
7749 * \retval RES_EXISTS a withdraw request was already sent for this caller (channel) and queue
7750*/
7751static int request_withdraw_caller_from_queue(const char *queuename, const char *caller, const char *withdraw_info)
7752{
7753 struct call_queue *q;
7754 struct queue_ent *qe;
7755 int res = RES_NOSUCHQUEUE;
7756
7757 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
7758 * short-circuits if the queue is already in memory. */
7759 if (!(q = find_load_queue_rt_friendly(queuename))) {
7760 return res;
7761 }
7762
7763 ao2_lock(q);
7764 res = RES_NOT_CALLER;
7765 for (qe = q->head; qe; qe = qe->next) {
7766 if (!strcmp(ast_channel_name(qe->chan), caller)) {
7767 if (qe->withdraw) {
7768 ast_debug(1, "Ignoring duplicate withdraw request of caller %s from queue %s\n", caller, queuename);
7769 res = RES_EXISTS;
7770 } else {
7771 ast_debug(1, "Requested withdraw of caller %s from queue %s\n", caller, queuename);
7772 /* It is not possible to change the withdraw info by further withdraw requests for this caller (channel)
7773 in this queue, so we do not need to worry about a memory leak here. */
7774 if (withdraw_info) {
7776 }
7777 qe->withdraw = 1;
7778 res = RES_OKAY;
7779 }
7780 break;
7781 }
7782 }
7783 ao2_unlock(q);
7784 queue_unref(q);
7785
7786 return res;
7787}
7788
7789
7791{
7792 struct ast_json *json_blob = queue_member_blob_create(q, member);
7793
7794 if (!json_blob) {
7795 return -1;
7796 }
7797
7798 queue_publish_member_blob(queue_member_pause_type(), json_blob);
7799
7800 return 0;
7801}
7802
7803/*!
7804 * \internal
7805 * \brief Set the pause status of the specific queue member.
7806 *
7807 * \param q Which queue the member belongs.
7808 * \param mem Queue member being paused/unpaused.
7809 * \param reason Why is this happening (Can be NULL/empty for no reason given.)
7810 * \param paused Set to 1 if the member is being paused or 0 to unpause.
7811 *
7812 * \pre The q is locked on entry.
7813 */
7814static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
7815{
7816 if (mem->paused == paused) {
7817 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
7818 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
7819 }
7820
7821 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid)) {
7823 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "reason_paused", S_OR(reason, ""), "paused", paused ? "1" : "0", SENTINEL) < 0) {
7824 ast_log(LOG_WARNING, "Failed update of realtime queue member %s:%s %spause and reason '%s'\n",
7825 q->name, mem->interface, (paused ? "" : "un"), S_OR(reason, ""));
7826 }
7827 } else {
7828 if (ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, "paused", paused ? "1" : "0", SENTINEL) < 0) {
7829 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
7830 (paused ? "" : "un"), q->name, mem->interface);
7831 }
7832 }
7833 }
7834
7835 mem->paused = paused;
7836 if (paused) {
7837 time(&mem->lastpause); /* update last pause field */
7838 }
7839 if (paused && !ast_strlen_zero(reason)) {
7840 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7841 } else {
7842 /* We end up filling this in again later (temporarily) but we need it
7843 * empty for now so that the intervening code - specifically
7844 * dump_queue_members() - has the correct view of things. */
7845 mem->reason_paused[0] = '\0';
7846 }
7847
7849 AST_DEVSTATE_CACHABLE, "Queue:%s_pause_%s", q->name, mem->interface);
7850
7853 }
7854
7855 if (is_member_available(q, mem)) {
7857 "Queue:%s_avail", q->name);
7858 } else if (!num_available_members(q)) {
7860 "Queue:%s_avail", q->name);
7861 }
7862
7863 if (!paused && !ast_strlen_zero(reason)) {
7864 /* Because we've been unpaused with a 'reason' we need to ensure that
7865 * that reason is emitted when the subsequent PauseQueueMember event
7866 * is raised. So temporarily set it on the member and clear it out
7867 * again right after. */
7868 ast_copy_string(mem->reason_paused, reason, sizeof(mem->reason_paused));
7869 }
7870
7871 ast_queue_log(q->name, "NONE", mem->membername, paused ? "PAUSE" : "UNPAUSE",
7872 "%s", mem->reason_paused);
7873
7875
7876 if (!paused) {
7877 mem->reason_paused[0] = '\0';
7878 }
7879}
7880
7881static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
7882{
7883 int found = 0;
7884 struct call_queue *q;
7885 struct ao2_iterator queue_iter;
7886
7887 if (ast_check_realtime("queues")) {
7888 load_realtime_queues(queuename);
7889 }
7890
7891 queue_iter = ao2_iterator_init(queues, 0);
7892 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
7893 ao2_lock(q);
7894 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
7895 struct member *mem;
7896
7897 if ((mem = interface_exists(q, interface))) {
7898 /*
7899 * Before we do the PAUSE/UNPAUSE, log if this was a
7900 * PAUSEALL/UNPAUSEALL but only on the first found entry.
7901 */
7902 ++found;
7903 if (found == 1
7904 && ast_strlen_zero(queuename)) {
7905 /*
7906 * XXX In all other cases, we use the queue name,
7907 * but since this affects all queues, we cannot.
7908 */
7909 ast_queue_log("NONE", "NONE", mem->membername,
7910 (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", S_OR(reason, ""));
7911 }
7912
7913 set_queue_member_pause(q, mem, reason, paused);
7914 ao2_ref(mem, -1);
7915 }
7916
7917 if (!ast_strlen_zero(queuename)) {
7918 ao2_unlock(q);
7919 queue_t_unref(q, "Done with iterator");
7920 break;
7921 }
7922 }
7923
7924 ao2_unlock(q);
7925 queue_t_unref(q, "Done with iterator");
7926 }
7927 ao2_iterator_destroy(&queue_iter);
7928
7929 return found ? RESULT_SUCCESS : RESULT_FAILURE;
7930}
7931
7932/*!
7933 * \internal
7934 * \brief helper function for set_member_penalty - given a queue, sets all member penalties with the interface
7935 * \param[in] q queue which is having its member's penalty changed - must be unlocked prior to calling
7936 * \param[in] interface String of interface used to search for queue members being changed
7937 * \param[in] penalty Value penalty is being changed to for the member.
7938 * \retval 0 if the there is no member with interface belonging to q and no change is made
7939 * \retval 1 if the there is a member with interface belonging to q and changes are made
7940 */
7941static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
7942{
7943 struct member *mem;
7944 int foundinterface = 0;
7945
7946 ao2_lock(q);
7947 if ((mem = interface_exists(q, interface))) {
7948 foundinterface++;
7949 if (mem->realtime) {
7950 char rtpenalty[80];
7951
7952 sprintf(rtpenalty, "%i", penalty);
7953 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
7954 }
7955
7956 mem->penalty = penalty;
7957
7958 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
7959 queue_publish_member_blob(queue_member_penalty_type(), queue_member_blob_create(q, mem));
7960 ao2_ref(mem, -1);
7961 }
7962 ao2_unlock(q);
7963
7964 return foundinterface;
7965}
7966
7967/*!
7968 * \internal
7969 * \brief Set the ringinuse value of the specific queue member.
7970 *
7971 * \param q Which queue the member belongs.
7972 * \param mem Queue member being set.
7973 * \param ringinuse Set to 1 if the member is called when inuse.
7974 *
7975 * \pre The q is locked on entry.
7976 */
7977static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
7978{
7979 if (mem->realtime) {
7981 ringinuse ? "1" : "0");
7982 }
7983
7984 mem->ringinuse = ringinuse;
7985
7986 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
7987 queue_publish_member_blob(queue_member_ringinuse_type(), queue_member_blob_create(q, mem));
7988}
7989
7991{
7992 struct member *mem;
7993 int foundinterface = 0;
7994
7995 ao2_lock(q);
7996 if ((mem = interface_exists(q, interface))) {
7997 foundinterface++;
7999 ao2_ref(mem, -1);
8000 }
8001 ao2_unlock(q);
8002
8003 return foundinterface;
8004}
8005
8006static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
8007{
8008 switch(property) {
8009 case MEMBER_PENALTY:
8011
8012 case MEMBER_RINGINUSE:
8014
8015 default:
8016 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
8017 return 0;
8018 }
8019}
8020
8021/*!
8022 * \internal
8023 * \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues.
8024 * \param[in] queuename If specified, only act on a member if it belongs to this queue
8025 * \param[in] interface Interface of queue member(s) having priority set.
8026 * \param[in] property Which queue property is being set
8027 * \param[in] value Value penalty is being changed to for each member
8028 */
8029static int set_member_value(const char *queuename, const char *interface, int property, int value)
8030{
8031 int foundinterface = 0, foundqueue = 0;
8032 struct call_queue *q;
8033 struct ast_config *queue_config = NULL;
8034 struct ao2_iterator queue_iter;
8035
8036 /* property dependent restrictions on values should be checked in this switch */
8037 switch (property) {
8038 case MEMBER_PENALTY:
8039 if (value < 0 && !negative_penalty_invalid) {
8040 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
8041 return RESULT_FAILURE;
8042 }
8043 }
8044
8045 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
8046 if (ast_check_realtime("queues")) {
8047 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8048 if (queue_config) {
8049 char *category = NULL;
8050 while ((category = ast_category_browse(queue_config, category))) {
8051 const char *name = ast_variable_retrieve(queue_config, category, "name");
8052 if (ast_strlen_zero(name)) {
8053 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
8054 continue;
8055 }
8056 if ((q = find_load_queue_rt_friendly(name))) {
8057 foundqueue++;
8058 foundinterface += set_member_value_help_members(q, interface, property, value);
8059 queue_unref(q);
8060 }
8061 }
8062
8063 ast_config_destroy(queue_config);
8064 }
8065 }
8066
8067 /* After hitting realtime queues, go back and get the regular ones. */
8068 queue_iter = ao2_iterator_init(queues, 0);
8069 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8070 foundqueue++;
8071 foundinterface += set_member_value_help_members(q, interface, property, value);
8072 queue_unref(q);
8073 }
8074 ao2_iterator_destroy(&queue_iter);
8075 } else { /* We actually have a queuename, so we can just act on the single queue. */
8076 if ((q = find_load_queue_rt_friendly(queuename))) {
8077 foundqueue++;
8078 foundinterface += set_member_value_help_members(q, interface, property, value);
8079 queue_unref(q);
8080 }
8081 }
8082
8083 if (foundinterface) {
8084 return RESULT_SUCCESS;
8085 } else if (!foundqueue) {
8086 ast_log (LOG_ERROR, "Invalid queuename\n");
8087 } else {
8088 ast_log (LOG_ERROR, "Invalid interface\n");
8089 }
8090
8091 return RESULT_FAILURE;
8092}
8093
8094/*!
8095 * \brief Gets members penalty.
8096 * \return Return the members penalty or RESULT_FAILURE on error.
8097 */
8098static int get_member_penalty(char *queuename, char *interface)
8099{
8100 int foundqueue = 0, penalty;
8101 struct call_queue *q;
8102 struct member *mem;
8103
8104 if ((q = find_load_queue_rt_friendly(queuename))) {
8105 foundqueue = 1;
8106 ao2_lock(q);
8107 if ((mem = interface_exists(q, interface))) {
8108 penalty = mem->penalty;
8109 ao2_ref(mem, -1);
8110 ao2_unlock(q);
8111 queue_t_unref(q, "Search complete");
8112 return penalty;
8113 }
8114 ao2_unlock(q);
8115 queue_t_unref(q, "Search complete");
8116 }
8117
8118 /* some useful debugging */
8119 if (foundqueue) {
8120 ast_log (LOG_ERROR, "Invalid queuename\n");
8121 } else {
8122 ast_log (LOG_ERROR, "Invalid interface\n");
8123 }
8124
8125 return RESULT_FAILURE;
8126}
8127
8128/*! \brief Reload dynamic queue members persisted into the astdb */
8129static void reload_queue_members(void)
8130{
8131 char *cur_ptr;
8132 const char *queue_name;
8133 char *member;
8134 char *interface;
8135 char *membername = NULL;
8136 char *state_interface;
8137 char *penalty_tok;
8138 int penalty = 0;
8139 char *paused_tok;
8140 int paused = 0;
8141 char *wrapuptime_tok;
8142 int wrapuptime = 0;
8143 char *reason_paused;
8144 struct ast_db_entry *db_tree;
8145 struct ast_db_entry *entry;
8146 struct call_queue *cur_queue;
8147 char *queue_data;
8148
8149 /* Each key in 'pm_family' is the name of a queue */
8150 db_tree = ast_db_gettree(pm_family, NULL);
8151 for (entry = db_tree; entry; entry = entry->next) {
8152
8153 queue_name = entry->key + strlen(pm_family) + 2;
8154
8155 {
8156 struct call_queue tmpq = {
8157 .name = queue_name,
8158 };
8159 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
8160 }
8161
8162 if (!cur_queue) {
8163 cur_queue = find_load_queue_rt_friendly(queue_name);
8164 }
8165
8166 if (!cur_queue) {
8167 /* If the queue no longer exists, remove it from the
8168 * database */
8169 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
8170 ast_db_del(pm_family, queue_name);
8171 continue;
8172 }
8173
8174 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
8175 queue_t_unref(cur_queue, "Expire reload reference");
8176 continue;
8177 }
8178
8179 cur_ptr = queue_data;
8180 while ((member = strsep(&cur_ptr, ",|"))) {
8181 if (ast_strlen_zero(member)) {
8182 continue;
8183 }
8184
8185 interface = strsep(&member, ";");
8186 penalty_tok = strsep(&member, ";");
8187 paused_tok = strsep(&member, ";");
8188 membername = strsep(&member, ";");
8189 state_interface = strsep(&member, ";");
8190 reason_paused = strsep(&member, ";");
8191 wrapuptime_tok = strsep(&member, ";");
8192
8193 if (!penalty_tok) {
8194 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
8195 break;
8196 }
8197 penalty = strtol(penalty_tok, NULL, 10);
8198 if (errno == ERANGE) {
8199 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
8200 break;
8201 }
8202
8203 if (!paused_tok) {
8204 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
8205 break;
8206 }
8207 paused = strtol(paused_tok, NULL, 10);
8208 if ((errno == ERANGE) || paused < 0 || paused > 1) {
8209 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
8210 break;
8211 }
8212
8213 if (!ast_strlen_zero(wrapuptime_tok)) {
8214 wrapuptime = strtol(wrapuptime_tok, NULL, 10);
8215 if (errno == ERANGE) {
8216 ast_log(LOG_WARNING, "Error converting wrapuptime: %s: Out of range.\n", wrapuptime_tok);
8217 break;
8218 }
8219 }
8220
8221 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d ReasonPause: %s Wrapuptime: %d\n",
8222 queue_name, interface, membername, penalty, paused, reason_paused, wrapuptime);
8223
8224 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface, reason_paused, wrapuptime) == RES_OUTOFMEMORY) {
8225 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
8226 break;
8227 }
8228 }
8229 queue_t_unref(cur_queue, "Expire reload reference");
8230 ast_free(queue_data);
8231 }
8232
8233 if (db_tree) {
8234 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
8235 ast_db_freetree(db_tree);
8236 }
8237}
8238
8239/*! \brief PauseQueueMember application */
8240static int pqm_exec(struct ast_channel *chan, const char *data)
8241{
8242 char *parse;
8244 AST_APP_ARG(queuename);
8245 AST_APP_ARG(interface);
8247 AST_APP_ARG(reason);
8248 );
8249
8250 if (ast_strlen_zero(data)) {
8251 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
8252 return -1;
8253 }
8254
8255 parse = ast_strdupa(data);
8256
8258
8259 if (ast_strlen_zero(args.interface)) {
8260 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
8261 return -1;
8262 }
8263
8264 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
8265 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
8266 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
8267 return 0;
8268 }
8269
8270 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
8271
8272 return 0;
8273}
8274
8275/*! \brief UnpauseQueueMember application */
8276static int upqm_exec(struct ast_channel *chan, const char *data)
8277{
8278 char *parse;
8280 AST_APP_ARG(queuename);
8281 AST_APP_ARG(interface);
8283 AST_APP_ARG(reason);
8284 );
8285
8286 if (ast_strlen_zero(data)) {
8287 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
8288 return -1;
8289 }
8290
8291 parse = ast_strdupa(data);
8292
8294
8295 if (ast_strlen_zero(args.interface)) {
8296 ast_log(LOG_WARNING, "Missing interface argument to UnpauseQueueMember ([queuename],interface[,options[,reason]])\n");
8297 return -1;
8298 }
8299
8300 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
8301 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
8302 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
8303 return 0;
8304 }
8305
8306 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
8307
8308 return 0;
8309}
8310
8311/*! \brief RemoveQueueMember application */
8312static int rqm_exec(struct ast_channel *chan, const char *data)
8313{
8314 int res=-1;
8315 char *parse, *temppos = NULL;
8316 struct member *mem = NULL;
8317
8319 AST_APP_ARG(queuename);
8321 );
8322
8323
8324 if (ast_strlen_zero(data)) {
8325 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
8326 return -1;
8327 }
8328
8329 parse = ast_strdupa(data);
8330
8332
8333 if (ast_strlen_zero(args.interface)) {
8334 args.interface = ast_strdupa(ast_channel_name(chan));
8335 temppos = strrchr(args.interface, '-');
8336 if (temppos) {
8337 *temppos = '\0';
8338 }
8339 }
8340
8341 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
8342
8344 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
8345 }
8346
8347 switch (remove_from_queue(args.queuename, args.interface)) {
8348 case RES_OKAY:
8349 if (!mem || ast_strlen_zero(mem->membername)) {
8350 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
8351 } else {
8352 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
8353 }
8354 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
8355 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
8356 res = 0;
8357 break;
8358 case RES_EXISTS:
8359 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
8360 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
8361 res = 0;
8362 break;
8363 case RES_NOSUCHQUEUE:
8364 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
8365 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
8366 res = 0;
8367 break;
8368 case RES_NOT_DYNAMIC:
8369 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
8370 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
8371 res = 0;
8372 break;
8373 }
8374
8375 if (mem) {
8376 ao2_ref(mem, -1);
8377 }
8378
8379 return res;
8380}
8381
8382/*! \brief AddQueueMember application */
8383static int aqm_exec(struct ast_channel *chan, const char *data)
8384{
8385 int res=-1;
8386 char *parse, *tmp, *temppos = NULL, *reason = NULL;
8388 AST_APP_ARG(queuename);
8395 );
8396 int penalty = 0;
8397 int paused = 0;
8398 int wrapuptime;
8399 struct ast_flags flags = { 0 };
8400
8401 if (ast_strlen_zero(data)) {
8402 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface][,wrapuptime]]]]])\n");
8403 return -1;
8404 }
8405
8406 parse = ast_strdupa(data);
8407
8409
8410 if (args.options) {
8411 char *opts[AQM_OPT_ARG_ARRAY_SIZE] = { NULL, };
8412 ast_app_parse_options(aqm_opts, &flags, opts, args.options);
8414 paused = 1;
8416 reason = ast_strdupa(opts[AQM_OPT_ARG_PAUSE_REASON]);
8417 }
8418 }
8419 }
8420
8421 if (ast_strlen_zero(args.interface)) {
8422 args.interface = ast_strdupa(ast_channel_name(chan));
8423 temppos = strrchr(args.interface, '-');
8424 if (temppos) {
8425 *temppos = '\0';
8426 }
8427 }
8428
8429 if (!ast_strlen_zero(args.penalty)) {
8430 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
8431 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
8432 penalty = 0;
8433 }
8434 }
8435
8436 if (!ast_strlen_zero(args.wrapuptime)) {
8437 tmp = args.wrapuptime;
8438 ast_strip(tmp);
8439 wrapuptime = atoi(tmp);
8440 if (wrapuptime < 0) {
8441 wrapuptime = 0;
8442 }
8443 } else {
8444 wrapuptime = 0;
8445 }
8446
8447 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, paused, queue_persistent_members, args.state_interface, reason, wrapuptime)) {
8448 case RES_OKAY:
8449 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
8450 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8451 } else {
8452 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
8453 }
8454 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
8455 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
8456 res = 0;
8457 break;
8458 case RES_EXISTS:
8459 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
8460 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
8461 res = 0;
8462 break;
8463 case RES_NOSUCHQUEUE:
8464 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
8465 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
8466 res = 0;
8467 break;
8468 case RES_OUTOFMEMORY:
8469 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
8470 break;
8471 }
8472
8473 return res;
8474}
8475
8476/*! \brief QueueLog application */
8477static int ql_exec(struct ast_channel *chan, const char *data)
8478{
8479 char *parse;
8480
8482 AST_APP_ARG(queuename);
8483 AST_APP_ARG(uniqueid);
8484 AST_APP_ARG(membername);
8486 AST_APP_ARG(params);
8487 );
8488
8489 if (ast_strlen_zero(data)) {
8490 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
8491 return -1;
8492 }
8493
8494 parse = ast_strdupa(data);
8495
8497
8498 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
8499 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
8500 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
8501 return -1;
8502 }
8503
8504 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
8505 "%s", args.params ? args.params : "");
8506
8507 return 0;
8508}
8509
8510/*! \brief Copy rule from global list into specified queue */
8511static void copy_rules(struct queue_ent *qe, const char *rulename)
8512{
8513 struct penalty_rule *pr_iter;
8514 struct rule_list *rl_iter;
8515 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
8517 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8518 if (!strcasecmp(rl_iter->name, tmp)) {
8519 break;
8520 }
8521 }
8522 if (rl_iter) {
8523 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8524 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
8525 if (!new_pr) {
8526 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
8527 break;
8528 }
8529 new_pr->time = pr_iter->time;
8530 new_pr->max_value = pr_iter->max_value;
8531 new_pr->min_value = pr_iter->min_value;
8532 new_pr->raise_value = pr_iter->raise_value;
8533 new_pr->max_relative = pr_iter->max_relative;
8534 new_pr->min_relative = pr_iter->min_relative;
8535 new_pr->raise_relative = pr_iter->raise_relative;
8536 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
8537 }
8538 }
8540}
8541
8542/*!\brief The starting point for all queue calls
8543 *
8544 * The process involved here is to
8545 * 1. Parse the options specified in the call to Queue()
8546 * 2. Join the queue
8547 * 3. Wait in a loop until it is our turn to try calling a queue member
8548 * 4. Attempt to call a queue member
8549 * 5. If 4. did not result in a bridged call, then check for between
8550 * call options such as periodic announcements etc.
8551 * 6. Try 4 again unless some condition (such as an expiration time) causes us to
8552 * exit the queue.
8553 */
8554static int queue_exec(struct ast_channel *chan, const char *data)
8555{
8556 int res=-1;
8557 int ringing=0;
8558 const char *user_priority;
8559 const char *max_penalty_str;
8560 const char *min_penalty_str;
8561 const char *raise_penalty_str;
8562 int prio;
8563 int qcontinue = 0;
8564 int max_penalty, min_penalty, raise_penalty;
8565 enum queue_result reason = QUEUE_UNKNOWN;
8566 /* whether to exit Queue application after the timeout hits */
8567 int tries = 0;
8568 int noption = 0;
8569 char *parse;
8570 int makeannouncement = 0;
8571 int position = 0;
8573 AST_APP_ARG(queuename);
8576 AST_APP_ARG(announceoverride);
8577 AST_APP_ARG(queuetimeoutstr);
8578 AST_APP_ARG(agi);
8579 AST_APP_ARG(gosub);
8581 AST_APP_ARG(position);
8582 );
8583 /* Our queue entry */
8584 struct queue_ent qe = { 0 };
8585 struct ast_flags opts = { 0, };
8586 char *opt_args[OPT_ARG_ARRAY_SIZE];
8587 int max_forwards;
8588 int cid_allow;
8589
8590 if (ast_strlen_zero(data)) {
8591 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,gosub[,rule[,position]]]]]]]]\n");
8592 return -1;
8593 }
8594
8595 ast_channel_lock(chan);
8597 ast_channel_unlock(chan);
8598
8599 if (max_forwards <= 0) {
8600 ast_log(LOG_WARNING, "Channel '%s' cannot enter queue. Max forwards exceeded\n", ast_channel_name(chan));
8601 return -1;
8602 }
8603
8604 parse = ast_strdupa(data);
8606
8607 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, gosub: %s, rule: %s, position: %s\n",
8608 args.queuename,
8609 S_OR(args.options, ""),
8610 S_OR(args.url, ""),
8611 S_OR(args.announceoverride, ""),
8612 S_OR(args.queuetimeoutstr, ""),
8613 S_OR(args.agi, ""),
8614 S_OR(args.gosub, ""),
8615 S_OR(args.rule, ""),
8616 S_OR(args.position, ""));
8617
8618 if (!ast_strlen_zero(args.options)) {
8619 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
8620 }
8621
8622 /* Setup our queue entry */
8623 qe.start = time(NULL);
8624
8625 pbx_builtin_setvar_helper(chan, "ABANDONED", NULL);
8626
8627 /* set the expire time based on the supplied timeout; */
8628 if (!ast_strlen_zero(args.queuetimeoutstr)) {
8629 qe.expire = qe.start + atoi(args.queuetimeoutstr);
8630 } else {
8631 qe.expire = 0;
8632 }
8633
8634 /* Get the priority from the variable ${QUEUE_PRIO} */
8635 ast_channel_lock(chan);
8636 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
8637 if (user_priority) {
8638 if (sscanf(user_priority, "%30d", &prio) == 1) {
8639 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
8640 } else {
8641 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
8642 user_priority, ast_channel_name(chan));
8643 prio = 0;
8644 }
8645 } else {
8646 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
8647 prio = 0;
8648 }
8649
8650 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
8651
8652 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
8653 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
8654 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
8655 } else {
8656 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
8657 max_penalty_str, ast_channel_name(chan));
8658 max_penalty = INT_MAX;
8659 }
8660 } else {
8661 max_penalty = INT_MAX;
8662 }
8663
8664 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
8665 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
8666 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
8667 } else {
8668 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
8669 min_penalty_str, ast_channel_name(chan));
8670 min_penalty = INT_MAX;
8671 }
8672 } else {
8673 min_penalty = INT_MAX;
8674 }
8675
8676 if ((raise_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_RAISE_PENALTY"))) {
8677 if (sscanf(raise_penalty_str, "%30d", &raise_penalty) == 1) {
8678 ast_debug(1, "%s: Got raise penalty %d from ${QUEUE_RAISE_PENALTY}.\n", ast_channel_name(chan), raise_penalty);
8679 } else {
8680 ast_log(LOG_WARNING, "${QUEUE_RAISE_PENALTY}: Invalid value (%s), channel %s.\n",
8681 raise_penalty_str, ast_channel_name(chan));
8682 raise_penalty = INT_MAX;
8683 }
8684 } else {
8685 raise_penalty = INT_MAX;
8686 }
8687 ast_channel_unlock(chan);
8688
8689 if (ast_test_flag(&opts, OPT_RINGING)) {
8690 ringing = 1;
8691 }
8692
8693 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
8694 qe.ring_when_ringing = 1;
8695 }
8696
8697 if (ast_test_flag(&opts, OPT_GO_ON)) {
8698 qcontinue = 1;
8699 }
8700
8701 if (args.position) {
8702 position = atoi(args.position);
8703 if (position < 0) {
8704 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
8705 position = 0;
8706 }
8707 }
8708
8709 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
8710 args.queuename, (long)qe.expire, prio);
8711
8712 qe.chan = chan;
8713 qe.prio = prio;
8714 qe.max_penalty = max_penalty;
8715 qe.min_penalty = min_penalty;
8716 qe.raise_penalty = raise_penalty;
8717 qe.last_pos_said = 0;
8718 qe.last_pos = 0;
8721 qe.valid_digits = 0;
8722 if (join_queue(args.queuename, &qe, &reason, position)) {
8723 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
8724 set_queue_result(chan, reason);
8725 return 0;
8726 }
8727 ast_assert(qe.parent != NULL);
8728
8729 if (qe.parent->periodicannouncestartdelay >= 0) {
8732 }
8733
8735
8736 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
8737 S_OR(args.url, ""),
8738 S_COR(cid_allow && ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
8739 qe.opos);
8740
8741 /* PREDIAL: Preprocess any callee gosub arguments. */
8743 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLEE])) {
8746 }
8747
8748 /* PREDIAL: Run gosub on the caller's channel */
8750 && !ast_strlen_zero(opt_args[OPT_ARG_PREDIAL_CALLER])) {
8752 ast_app_exec_sub(NULL, chan, opt_args[OPT_ARG_PREDIAL_CALLER], 0);
8753 }
8754
8755 /* Music on hold class override */
8758 ast_copy_string(qe.moh, opt_args[OPT_ARG_MUSICONHOLD_CLASS], sizeof(qe.moh));
8759 }
8760
8761 copy_rules(&qe, args.rule);
8762 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
8763check_turns:
8764 if (ringing) {
8766 } else {
8767 ast_moh_start(chan, qe.moh, NULL);
8768 }
8769
8770 /* This is the wait loop for callers 2 through maxlen */
8771 res = wait_our_turn(&qe, ringing, &reason);
8772 if (res) {
8773 goto stop;
8774 }
8775
8776 makeannouncement = qe.parent->announce_to_first_user;
8777
8778 for (;;) {
8779 /* This is the wait loop for the head caller*/
8780 /* To exit, they may get their call answered; */
8781 /* they may dial a digit from the queue context; */
8782 /* or, they may timeout. */
8783
8784 /* A request to withdraw this call from the queue arrived */
8785 if (qe.withdraw) {
8786 reason = QUEUE_WITHDRAW;
8787 res = 1;
8788 break;
8789 }
8790
8791 /* Leave if we have exceeded our queuetimeout */
8792 if (qe.expire && (time(NULL) >= qe.expire)) {
8793 record_abandoned(&qe);
8794 reason = QUEUE_TIMEOUT;
8795 res = 0;
8796 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
8797 qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8798 break;
8799 }
8800
8801 if (makeannouncement) {
8802 /* Make a position announcement, if enabled */
8803 if (qe.parent->announcefrequency) {
8804 if ((res = say_position(&qe, ringing))) {
8805 goto stop;
8806 }
8807 }
8808 }
8809 makeannouncement = 1;
8810
8811 /* Make a periodic announcement, if enabled */
8813 if ((res = say_periodic_announcement(&qe, ringing))) {
8814 goto stop;
8815 }
8816 }
8817
8818 /* A request to withdraw this call from the queue arrived */
8819 if (qe.withdraw) {
8820 reason = QUEUE_WITHDRAW;
8821 res = 1;
8822 break;
8823 }
8824
8825 /* Leave if we have exceeded our queuetimeout */
8826 if (qe.expire && (time(NULL) >= qe.expire)) {
8827 record_abandoned(&qe);
8828 reason = QUEUE_TIMEOUT;
8829 res = 0;
8830 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8831 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8832 break;
8833 }
8834
8835 /* see if we need to move to the next penalty level for this queue */
8836 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
8837 update_qe_rule(&qe);
8838 }
8839
8840 /* Try calling all queue members for 'timeout' seconds */
8841 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.gosub, ringing);
8842 if (res) {
8843 goto stop;
8844 }
8845
8846 if (qe.parent->leavewhenempty) {
8847 int status = 0;
8849 record_abandoned(&qe);
8850 reason = QUEUE_LEAVEEMPTY;
8851 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
8852 res = 0;
8853 break;
8854 }
8855 }
8856
8857 /* exit after 'timeout' cycle if 'n' option enabled */
8858 if (noption && tries >= ao2_container_count(qe.parent->members)) {
8859 ast_verb(3, "Exiting on time-out cycle\n");
8860 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
8861 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8862 record_abandoned(&qe);
8863 reason = QUEUE_TIMEOUT;
8864 res = 0;
8865 break;
8866 }
8867
8868
8869 /* Leave if we have exceeded our queuetimeout */
8870 if (qe.expire && (time(NULL) >= qe.expire)) {
8871 record_abandoned(&qe);
8872 reason = QUEUE_TIMEOUT;
8873 res = 0;
8874 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));
8875 break;
8876 }
8877
8878 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
8879 res = wait_a_bit(&qe);
8880 if (res) {
8881 goto stop;
8882 }
8883
8884 /* If using dynamic realtime members, we should regenerate the member list for this queue */
8886
8887 /* Since this is a priority queue and
8888 * it is not sure that we are still at the head
8889 * of the queue, go and check for our turn again.
8890 */
8891 if (!is_our_turn(&qe)) {
8892 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
8893 goto check_turns;
8894 }
8895 }
8896
8897stop:
8898 if (res) {
8899 if (reason == QUEUE_WITHDRAW) {
8900 record_abandoned(&qe);
8901 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 : "");
8902 if (qe.withdraw_info) {
8903 pbx_builtin_setvar_helper(qe.chan, "QUEUE_WITHDRAW_INFO", qe.withdraw_info);
8904 }
8905 res = 0;
8906 } else if (res < 0) {
8907 if (!qe.handled) {
8908 record_abandoned(&qe);
8909 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
8910 "%d|%d|%ld", qe.pos, qe.opos,
8911 (long) (time(NULL) - qe.start));
8912 res = -1;
8913 } else if (reason == QUEUE_LEAVEEMPTY) {
8914 /* Return back to dialplan, don't hang up */
8915 res = 0;
8916 } else if (qcontinue) {
8917 reason = QUEUE_CONTINUE;
8918 res = 0;
8919 }
8920 } else if (qe.valid_digits) {
8921 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
8922 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
8923 }
8924 }
8925
8926 /* Free the optional withdraw info if present */
8927 /* This is done here to catch all cases. e.g. if the call eventually wasn't withdrawn, e.g. answered */
8928 if (qe.withdraw_info) {
8930 qe.withdraw_info = NULL;
8931 }
8932
8933 /* Don't allow return code > 0 */
8934 if (res >= 0) {
8935 res = 0;
8936 if (ringing) {
8937 ast_indicate(chan, -1);
8938 } else {
8939 ast_moh_stop(chan);
8940 }
8941 ast_stopstream(chan);
8942 }
8943
8945
8946 leave_queue(&qe);
8947 if (reason != QUEUE_UNKNOWN)
8948 set_queue_result(chan, reason);
8949
8950 /*
8951 * every queue_ent is given a reference to it's parent
8952 * call_queue when it joins the queue. This ref must be taken
8953 * away right before the queue_ent is destroyed. In this case
8954 * the queue_ent is about to be returned on the stack
8955 */
8956 qe.parent = queue_unref(qe.parent);
8957
8958 return res;
8959}
8960
8961/*!
8962 * \brief create interface var with all queue details.
8963 * \retval 0 on success
8964 * \retval -1 on error
8965*/
8966static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
8967{
8968 int res = -1;
8969 struct call_queue *q;
8970 char interfacevar[256] = "";
8971 float sl = 0;
8972
8973 if (ast_strlen_zero(data)) {
8974 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
8975 return -1;
8976 }
8977
8978 if ((q = find_load_queue_rt_friendly(data))) {
8979 ao2_lock(q);
8980 if (q->setqueuevar) {
8981 sl = 0;
8982 res = 0;
8983
8984 if (q->callscompleted > 0) {
8985 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
8986 }
8987
8988 snprintf(interfacevar, sizeof(interfacevar),
8989 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
8991
8992 pbx_builtin_setvar_multiple(chan, interfacevar);
8993 }
8994
8995 ao2_unlock(q);
8996 queue_t_unref(q, "Done with QUEUE() function");
8997 } else {
8998 ast_log(LOG_WARNING, "queue %s was not found\n", data);
8999 }
9000
9001 snprintf(buf, len, "%d", res);
9002
9003 return 0;
9004}
9005
9006/*!
9007 * \brief Check if a given queue exists
9008 *
9009 */
9010static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9011{
9012 struct call_queue *q;
9013
9014 buf[0] = '\0';
9015
9016 if (ast_strlen_zero(data)) {
9017 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9018 return -1;
9019 }
9021 snprintf(buf, len, "%d", q != NULL? 1 : 0);
9022 if (q) {
9023 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
9024 }
9025
9026 return 0;
9027}
9028
9029static struct member *get_interface_helper(struct call_queue *q, const char *interface)
9030{
9031 struct member *m;
9032
9034 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
9035 return NULL;
9036 }
9037
9039 if (!m) {
9040 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
9041 interface, q->name);
9042 }
9043 return m;
9044}
9045
9046/*!
9047 * \brief Get number either busy / free / ready or total members of a specific queue
9048 * \brief Get or set member properties penalty / paused / ringinuse
9049 * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ringinuse)
9050 * \retval -1 on error
9051 */
9052static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9053{
9054 int count = 0;
9055 struct member *m;
9056 struct ao2_iterator mem_iter;
9057 struct call_queue *q;
9058
9060 AST_APP_ARG(queuename);
9061 AST_APP_ARG(option);
9062 AST_APP_ARG(interface);
9063 );
9064 /* Make sure the returned value on error is zero length string. */
9065 buf[0] = '\0';
9066
9067 if (ast_strlen_zero(data)) {
9069 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9070 cmd);
9071 return -1;
9072 }
9073
9075
9076 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
9078 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
9079 cmd);
9080 return -1;
9081 }
9082
9083 if ((q = find_load_queue_rt_friendly(args.queuename))) {
9084 ao2_lock(q);
9085 if (!strcasecmp(args.option, "logged")) {
9086 mem_iter = ao2_iterator_init(q->members, 0);
9087 while ((m = ao2_iterator_next(&mem_iter))) {
9088 /* Count the agents who are logged in and presently answering calls */
9089 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9090 count++;
9091 }
9092 ao2_ref(m, -1);
9093 }
9094 ao2_iterator_destroy(&mem_iter);
9095 } else if (!strcasecmp(args.option, "free")) {
9096 mem_iter = ao2_iterator_init(q->members, 0);
9097 while ((m = ao2_iterator_next(&mem_iter))) {
9098 /* Count the agents who are logged in and presently answering calls */
9099 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
9100 count++;
9101 }
9102 ao2_ref(m, -1);
9103 }
9104 ao2_iterator_destroy(&mem_iter);
9105 } else if (!strcasecmp(args.option, "ready")) {
9106 time_t now;
9107 time(&now);
9108 mem_iter = ao2_iterator_init(q->members, 0);
9109 while ((m = ao2_iterator_next(&mem_iter))) {
9110 /* Count the agents who are logged in, not paused and not wrapping up */
9111 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
9112 !(m->lastcall && get_wrapuptime(q, m) && ((now - get_wrapuptime(q, m)) < m->lastcall))) {
9113 count++;
9114 }
9115 ao2_ref(m, -1);
9116 }
9117 ao2_iterator_destroy(&mem_iter);
9118 } else if (!strcasecmp(args.option, "count")) {
9120 } else if (!strcasecmp(args.option, "penalty")) {
9121 m = get_interface_helper(q, args.interface);
9122 if (m) {
9123 count = m->penalty;
9124 ao2_ref(m, -1);
9125 }
9126 } else if (!strcasecmp(args.option, "paused")) {
9127 m = get_interface_helper(q, args.interface);
9128 if (m) {
9129 count = m->paused;
9130 ao2_ref(m, -1);
9131 }
9132 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9133 || !strcasecmp(args.option, "ringinuse"))) {
9134 m = get_interface_helper(q, args.interface);
9135 if (m) {
9136 count = m->ringinuse;
9137 ao2_ref(m, -1);
9138 }
9139 } else {
9140 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9141 }
9142 ao2_unlock(q);
9143 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
9144 } else {
9145 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9146 }
9147
9148 snprintf(buf, len, "%d", count);
9149
9150 return 0;
9151}
9152
9153/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. */
9154static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
9155{
9156 int memvalue;
9157
9159 AST_APP_ARG(queuename);
9160 AST_APP_ARG(option);
9161 AST_APP_ARG(interface);
9162 );
9163
9164 if (ast_strlen_zero(data)) {
9166 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9167 cmd);
9168 return -1;
9169 }
9170
9172
9173 if (ast_strlen_zero(args.option)
9174 || ast_strlen_zero(args.interface)) {
9176 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
9177 cmd);
9178 return -1;
9179 }
9180
9181 /*
9182 * If queuename is empty then the option will be
9183 * set for the interface in all queues.
9184 */
9185
9186 memvalue = atoi(value);
9187 if (!strcasecmp(args.option, "penalty")) {
9188 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
9189 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
9190 return -1;
9191 }
9192 } else if (!strcasecmp(args.option, "paused")) {
9193 memvalue = (memvalue <= 0) ? 0 : 1;
9194 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
9195 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9196 return -1;
9197 }
9198 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
9199 || !strcasecmp(args.option, "ringinuse")) {
9200 memvalue = (memvalue <= 0) ? 0 : 1;
9201 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
9202 ast_log(LOG_ERROR, "Invalid interface or queue\n");
9203 return -1;
9204 }
9205 } else {
9206 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
9207 return -1;
9208 }
9209 return 0;
9210}
9211
9212/*!
9213 * \brief Get the total number of members in a specific queue (Deprecated)
9214 * \retval number of members
9215 * \retval -1 on error
9216*/
9217static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9218{
9219 int count = 0;
9220 struct member *m;
9221 struct call_queue *q;
9222 struct ao2_iterator mem_iter;
9223 static int depflag = 1;
9224
9225 if (depflag) {
9226 depflag = 0;
9227 ast_log(LOG_NOTICE, "The function QUEUE_MEMBER_COUNT has been deprecated in favor of the QUEUE_MEMBER function and will not be in further releases.\n");
9228 }
9229
9230 if (ast_strlen_zero(data)) {
9231 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
9232 return -1;
9233 }
9234
9235 if ((q = find_load_queue_rt_friendly(data))) {
9236 ao2_lock(q);
9237 mem_iter = ao2_iterator_init(q->members, 0);
9238 while ((m = ao2_iterator_next(&mem_iter))) {
9239 /* Count the agents who are logged in and presently answering calls */
9240 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
9241 count++;
9242 }
9243 ao2_ref(m, -1);
9244 }
9245 ao2_iterator_destroy(&mem_iter);
9246 ao2_unlock(q);
9247 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
9248 } else {
9249 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9250 }
9251
9252 snprintf(buf, len, "%d", count);
9253
9254 return 0;
9255}
9256
9257/*! \brief Dialplan function QUEUE_GET_CHANNEL() Get caller channel waiting at specified position in the queue */
9258static int queue_function_queuegetchannel(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9259{
9260 int position;
9261 char *parse;
9262 struct call_queue *q;
9263 struct ast_variable *var;
9264
9266 AST_APP_ARG(queuename);
9267 AST_APP_ARG(position);
9268 );
9269
9270 buf[0] = '\0';
9271
9272 if (ast_strlen_zero(data)) {
9273 ast_log(LOG_ERROR, "Missing argument. QUEUE_GET_CHANNEL(<queuename>,<position>)\n");
9274 return -1;
9275 }
9276
9277 parse = ast_strdupa(data);
9279
9280 if (ast_strlen_zero(args.queuename)) {
9281 ast_log (LOG_ERROR, "The <queuename> parameter is required.\n");
9282 return -1;
9283 }
9284
9285 if (ast_strlen_zero(args.position)) {
9286 position = 1;
9287 } else {
9288 if (sscanf(args.position, "%30d", &position) != 1) {
9289 ast_log (LOG_ERROR, "<position> parameter must be an integer.\n");
9290 return -1;
9291 }
9292 if (position < 1) {
9293 ast_log (LOG_ERROR, "<position> parameter must be an integer greater than zero.\n");
9294 return -1;
9295 }
9296 }
9297
9298 {
9299 struct call_queue tmpq = {
9300 .name = args.queuename,
9301 };
9302
9303 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_GET_CHANNEL()");
9304 }
9305 if (q) {
9306 ao2_lock(q);
9307 if (q->count >= position) {
9308 struct queue_ent *qe;
9309
9310 for (qe = q->head; qe; qe = qe->next) {
9311 if (qe->pos == position) {
9313 break;
9314 }
9315 }
9316 }
9317 ao2_unlock(q);
9318 queue_t_unref(q, "Done with reference in QUEUE_GET_CHANNEL()");
9319 return 0;
9320 }
9321
9322 var = ast_load_realtime("queues", "name", args.queuename, SENTINEL);
9323 if (var) {
9324 /* if the queue is realtime but was not found in memory, this
9325 * means that the queue had been deleted from memory since it was
9326 * "dead."
9327 */
9329 return 0;
9330 }
9331
9332 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
9333 return 0;
9334}
9335
9336/*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
9337static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9338{
9339 int count = 0;
9340 struct call_queue *q, tmpq = {
9341 .name = data,
9342 };
9343 struct ast_variable *var = NULL;
9344
9345 buf[0] = '\0';
9346
9347 if (ast_strlen_zero(data)) {
9348 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
9349 return -1;
9350 }
9351
9352 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
9353 ao2_lock(q);
9354 count = q->count;
9355 ao2_unlock(q);
9356 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
9357 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
9358 /* if the queue is realtime but was not found in memory, this
9359 * means that the queue had been deleted from memory since it was
9360 * "dead." This means it has a 0 waiting count
9361 */
9362 count = 0;
9364 } else {
9365 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9366 }
9367
9368 snprintf(buf, len, "%d", count);
9369
9370 return 0;
9371}
9372
9373/*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
9374static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9375{
9376 struct call_queue *q;
9377 struct member *m;
9378
9379 /* Ensure an otherwise empty list doesn't return garbage */
9380 buf[0] = '\0';
9381
9382 if (ast_strlen_zero(data)) {
9383 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
9384 return -1;
9385 }
9386
9387 if ((q = find_load_queue_rt_friendly(data))) {
9388 int buflen = 0, count = 0;
9389 struct ao2_iterator mem_iter;
9390
9391 ao2_lock(q);
9392 mem_iter = ao2_iterator_init(q->members, 0);
9393 while ((m = ao2_iterator_next(&mem_iter))) {
9394 /* strcat() is always faster than printf() */
9395 if (count++) {
9396 strncat(buf + buflen, ",", len - buflen - 1);
9397 buflen++;
9398 }
9399 strncat(buf + buflen, m->interface, len - buflen - 1);
9400 buflen += strlen(m->interface);
9401 /* Safeguard against overflow (negative length) */
9402 if (buflen >= len - 2) {
9403 ao2_ref(m, -1);
9404 ast_log(LOG_WARNING, "Truncating list\n");
9405 break;
9406 }
9407 ao2_ref(m, -1);
9408 }
9409 ao2_iterator_destroy(&mem_iter);
9410 ao2_unlock(q);
9411 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
9412 } else
9413 ast_log(LOG_WARNING, "queue %s was not found\n", data);
9414
9415 /* We should already be terminated, but let's make sure. */
9416 buf[len - 1] = '\0';
9417
9418 return 0;
9419}
9420
9421/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
9422static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
9423{
9424 int penalty;
9426 AST_APP_ARG(queuename);
9427 AST_APP_ARG(interface);
9428 );
9429 /* Make sure the returned value on error is NULL. */
9430 buf[0] = '\0';
9431
9432 if (ast_strlen_zero(data)) {
9433 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9434 return -1;
9435 }
9436
9438
9439 if (args.argc < 2) {
9440 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9441 return -1;
9442 }
9443
9444 penalty = get_member_penalty (args.queuename, args.interface);
9445
9446 if (penalty >= 0) { /* remember that buf is already '\0' */
9447 snprintf (buf, len, "%d", penalty);
9448 }
9449
9450 return 0;
9451}
9452
9453/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
9454static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
9455{
9456 int penalty;
9458 AST_APP_ARG(queuename);
9459 AST_APP_ARG(interface);
9460 );
9461
9462 if (ast_strlen_zero(data)) {
9463 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9464 return -1;
9465 }
9466
9468
9469 if (args.argc < 2) {
9470 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
9471 return -1;
9472 }
9473
9474 penalty = atoi(value);
9475
9476 if (ast_strlen_zero(args.interface)) {
9477 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
9478 return -1;
9479 }
9480
9481 /* if queuename = NULL then penalty will be set for interface in all the queues. */
9482 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
9483 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
9484 return -1;
9485 }
9486
9487 return 0;
9488}
9489
9491 .name = "QUEUE_EXISTS",
9492 .read = queue_function_exists,
9493};
9494
9496 .name = "QUEUE_VARIABLES",
9497 .read = queue_function_var,
9498};
9499
9501 .name = "QUEUE_MEMBER",
9503 .write = queue_function_mem_write,
9504};
9505
9507 .name = "QUEUE_MEMBER_COUNT",
9508 .read = queue_function_qac_dep,
9509};
9510
9512 .name = "QUEUE_GET_CHANNEL",
9514};
9515
9517 .name = "QUEUE_WAITING_COUNT",
9519};
9520
9522 .name = "QUEUE_MEMBER_LIST",
9524};
9525
9527 .name = "QUEUE_MEMBER_PENALTY",
9530};
9531
9532/*! Reset the global queue rules parameters even if there is no "general" section of queuerules.conf */
9534{
9535 realtime_rules = 0;
9536}
9537
9538/*! Set the global queue rules parameters as defined in the "general" section of queuerules.conf */
9540{
9541 const char *general_val = NULL;
9542 if ((general_val = ast_variable_retrieve(cfg, "general", "realtime_rules"))) {
9543 realtime_rules = ast_true(general_val);
9544 }
9545}
9546
9547/*! \brief Reload the rules defined in queuerules.conf
9548 *
9549 * \param reload If 1, then only process queuerules.conf if the file
9550 * has changed since the last time we inspected it.
9551 * \return Always returns AST_MODULE_LOAD_SUCCESS
9552 */
9554{
9555 struct ast_config *cfg;
9556 struct rule_list *rl_iter, *new_rl;
9557 struct penalty_rule *pr_iter;
9558 char *rulecat = NULL;
9559 struct ast_variable *rulevar = NULL;
9560 struct ast_flags config_flags = { (reload && !realtime_rules) ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9561
9562 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
9563 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
9565 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9566 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
9568 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9569 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
9571 }
9572
9574 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
9575 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
9576 ast_free(pr_iter);
9577 ast_free(rl_iter);
9578 }
9580 while ((rulecat = ast_category_browse(cfg, rulecat))) {
9581 if (!strcasecmp(rulecat, "general")) {
9583 continue;
9584 }
9585 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
9587 ast_config_destroy(cfg);
9589 } else {
9590 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
9591 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
9592 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
9593 if(!strcasecmp(rulevar->name, "penaltychange"))
9594 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
9595 else
9596 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
9597 }
9598 }
9599
9600 ast_config_destroy(cfg);
9601
9605 }
9606
9609}
9610
9611/*! Always set the global queue defaults, even if there is no "general" section in queues.conf */
9613{
9615 autofill_default = 0;
9616 montype_default = 0;
9617 shared_lastcall = 0;
9621}
9622
9623/*! Set the global queue parameters as defined in the "general" section of queues.conf */
9624static void queue_set_global_params(struct ast_config *cfg)
9625{
9626 const char *general_val = NULL;
9627 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
9628 queue_persistent_members = ast_true(general_val);
9629 }
9630 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
9631 autofill_default = ast_true(general_val);
9632 }
9633 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
9634 if (!strcasecmp(general_val, "mixmonitor"))
9635 montype_default = 1;
9636 }
9637 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
9638 shared_lastcall = ast_true(general_val);
9639 }
9640 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
9641 negative_penalty_invalid = ast_true(general_val);
9642 }
9643 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
9644 log_membername_as_agent = ast_true(general_val);
9645 }
9646 if ((general_val = ast_variable_retrieve(cfg, "general", "force_longest_waiting_caller"))) {
9648 }
9649}
9650
9651/*! \brief reload information pertaining to a single member
9652 *
9653 * This function is called when a member = line is encountered in
9654 * queues.conf.
9655 *
9656 * \param memberdata The part after member = in the config file
9657 * \param q The queue to which this member belongs
9658 */
9659static void reload_single_member(const char *memberdata, struct call_queue *q)
9660{
9661 char *membername, *interface, *state_interface, *tmp;
9662 char *parse;
9663 struct member *cur, *newm;
9664 struct member tmpmem;
9665 int penalty;
9666 int ringinuse;
9667 int wrapuptime;
9668 int paused;
9677 );
9678
9679 if (ast_strlen_zero(memberdata)) {
9680 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
9681 return;
9682 }
9683
9684 /* Add a new member */
9685 parse = ast_strdupa(memberdata);
9686
9688
9689 interface = args.interface;
9690 if (!ast_strlen_zero(args.penalty)) {
9691 tmp = args.penalty;
9692 ast_strip(tmp);
9693 penalty = atoi(tmp);
9694 if (penalty < 0) {
9695 penalty = 0;
9696 }
9697 } else {
9698 penalty = 0;
9699 }
9700
9701 if (!ast_strlen_zero(args.membername)) {
9702 membername = args.membername;
9703 ast_strip(membername);
9704 } else {
9705 membername = interface;
9706 }
9707
9708 if (!ast_strlen_zero(args.state_interface)) {
9709 state_interface = args.state_interface;
9710 ast_strip(state_interface);
9711 } else {
9712 state_interface = interface;
9713 }
9714
9715 if (!ast_strlen_zero(args.ringinuse)) {
9716 tmp = args.ringinuse;
9717 ast_strip(tmp);
9718 if (ast_true(tmp)) {
9719 ringinuse = 1;
9720 } else if (ast_false(tmp)) {
9721 ringinuse = 0;
9722 } else {
9723 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
9724 membername, q->name);
9725 ringinuse = q->ringinuse;
9726 }
9727 } else {
9728 ringinuse = q->ringinuse;
9729 }
9730
9731 if (!ast_strlen_zero(args.wrapuptime)) {
9732 tmp = args.wrapuptime;
9733 ast_strip(tmp);
9734 wrapuptime = atoi(tmp);
9735 if (wrapuptime < 0) {
9736 wrapuptime = 0;
9737 }
9738 } else {
9739 wrapuptime = 0;
9740 }
9741
9742 if (!ast_strlen_zero(args.paused)) {
9743 tmp = args.paused;
9744 ast_strip(tmp);
9745 if (ast_true(tmp)) {
9746 paused = 1;
9747 } else if (ast_false(tmp)) {
9748 paused = 0;
9749 } else {
9750 ast_log(LOG_ERROR, "Member %s has an invalid paused value.\n", membername);
9751 paused = 0;
9752 }
9753 } else {
9754 paused = 0;
9755 }
9756
9757 /* Find the old position in the list */
9758 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
9759 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
9760
9761 if (cur) {
9762 paused = cur->paused;
9763 }
9764
9765 if ((newm = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse, wrapuptime))) {
9766 newm->wrapuptime = wrapuptime;
9767 if (cur) {
9768 ao2_lock(q->members);
9769 /* Round Robin Queue Position must be copied if this is replacing an existing member */
9770 newm->queuepos = cur->queuepos;
9771 /* Don't reset agent stats either */
9772 newm->calls = cur->calls;
9773 newm->lastcall = cur->lastcall;
9774
9775 ao2_link(q->members, newm);
9776 ao2_unlink(q->members, cur);
9777 ao2_unlock(q->members);
9778 } else {
9779 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
9780 member_add_to_queue(q, newm);
9781 }
9782 ao2_ref(newm, -1);
9783 }
9784 newm = NULL;
9785
9786 if (cur) {
9787 ao2_ref(cur, -1);
9788 }
9789}
9790
9791static int mark_member_dead(void *obj, void *arg, int flags)
9792{
9793 struct member *member = obj;
9794 if (!member->dynamic && !member->realtime) {
9795 member->delme = 1;
9796 }
9797 return 0;
9798}
9799
9800static int kill_dead_members(void *obj, void *arg, int flags)
9801{
9802 struct member *member = obj;
9803
9804 if (!member->delme) {
9806 return 0;
9807 } else {
9808 return CMP_MATCH;
9809 }
9810}
9811
9812/*! \brief Reload information pertaining to a particular queue
9813 *
9814 * Once we have isolated a queue within reload_queues, we call this. This will either
9815 * reload information for the queue or if we're just reloading member information, we'll just
9816 * reload that without touching other settings within the queue
9817 *
9818 * \param cfg The configuration which we are reading
9819 * \param mask Tells us what information we need to reload
9820 * \param queuename The name of the queue we are reloading information from
9821 */
9822static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
9823{
9824 int new;
9825 struct call_queue *q = NULL;
9826 struct member *member;
9827 /*We're defining a queue*/
9828 struct call_queue tmpq = {
9829 .name = queuename,
9830 };
9831 const char *tmpvar;
9832 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9833 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
9834 int prev_weight = 0;
9835 struct ast_variable *var;
9836 struct ao2_iterator mem_iter;
9837
9838 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
9839 if (queue_reload) {
9840 /* Make one then */
9841 if (!(q = alloc_queue(queuename))) {
9842 return;
9843 }
9844 } else {
9845 /* Since we're not reloading queues, this means that we found a queue
9846 * in the configuration file which we don't know about yet. Just return.
9847 */
9848 return;
9849 }
9850 new = 1;
9851 } else {
9852 new = 0;
9853 }
9854
9855 if (!new) {
9856 ao2_lock(q);
9857 prev_weight = q->weight ? 1 : 0;
9858 }
9859 /* Check if we already found a queue with this name in the config file */
9860 if (q->found) {
9861 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
9862 if (!new) {
9863 /* It should be impossible to *not* hit this case*/
9864 ao2_unlock(q);
9865 }
9866 queue_t_unref(q, "We exist! Expiring temporary pointer");
9867 return;
9868 }
9869 /* Due to the fact that the "linear" strategy will have a different allocation
9870 * scheme for queue members, we must devise the queue's strategy before other initializations.
9871 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
9872 * container used will have only a single bucket instead of the typical number.
9873 */
9874 if (queue_reload) {
9875 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
9876 q->strategy = strat2int(tmpvar);
9877 if (q->strategy < 0) {
9878 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
9879 tmpvar, q->name);
9881 }
9882 } else {
9884 }
9885 init_queue(q);
9886 }
9887 if (member_reload) {
9889 q->found = 1;
9890 }
9891
9892 /* On the first pass we just read the parameters of the queue */
9893 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9894 if (queue_reload && strcasecmp(var->name, "member")) {
9895 queue_set_param(q, var->name, var->value, var->lineno, 1);
9896 }
9897 }
9898
9899 /* On the second pass, we read members */
9900 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
9901 if (member_reload && !strcasecmp(var->name, "member")) {
9902 reload_single_member(var->value, q);
9903 }
9904 }
9905
9906 /* Update ringinuse for dynamic members */
9907 if (member_reload) {
9908 ao2_lock(q->members);
9910 while ((member = ao2_iterator_next(&mem_iter))) {
9911 if (member->dynamic) {
9913 }
9914 ao2_ref(member, -1);
9915 }
9916 ao2_iterator_destroy(&mem_iter);
9917 ao2_unlock(q->members);
9918 }
9919
9920 /* At this point, we've determined if the queue has a weight, so update use_weight
9921 * as appropriate
9922 */
9923 if (!q->weight && prev_weight) {
9925 } else if (q->weight && !prev_weight) {
9927 }
9928
9929 /* Free remaining members marked as delme */
9930 if (member_reload) {
9931 ao2_lock(q->members);
9934 ao2_unlock(q->members);
9935 }
9936
9937 if (new) {
9938 queues_t_link(queues, q, "Add queue to container");
9939 } else {
9940 ao2_unlock(q);
9941 }
9942 queue_t_unref(q, "Expiring creation reference");
9943}
9944
9945static int mark_unfound(void *obj, void *arg, int flags)
9946{
9947 struct call_queue *q = obj;
9948 char *queuename = arg;
9949 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9950 q->found = 0;
9951 }
9952 return 0;
9953}
9954
9955static int kill_if_unfound(void *obj, void *arg, int flags)
9956{
9957 struct call_queue *q = obj;
9958 char *queuename = arg;
9959 if (!q->realtime && !q->found && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
9960 q->dead = 1;
9961 return CMP_MATCH;
9962 } else {
9963 return 0;
9964 }
9965}
9966
9967/*! \brief reload the queues.conf file
9968 *
9969 * This function reloads the information in the general section of the queues.conf
9970 * file and potentially more, depending on the value of mask.
9971 *
9972 * \param reload 0 if we are calling this the first time, 1 every other time
9973 * \param mask Gives flags telling us what information to actually reload
9974 * \param queuename If set to a non-zero string, then only reload information from
9975 * that particular queue. Otherwise inspect all queues
9976 * \retval -1 Failure occurred
9977 * \retval 0 All clear!
9978 */
9979static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
9980{
9981 struct ast_config *cfg;
9982 char *cat;
9983 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
9984 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
9985
9986 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
9987 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
9988 return -1;
9989 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
9990 return 0;
9991 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
9992 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
9993 return -1;
9994 }
9995
9996 /* We've made it here, so it looks like we're doing operations on all queues. */
9998
9999 /* Mark non-realtime queues not found at the beginning. */
10000 ao2_callback(queues, OBJ_NODATA, mark_unfound, (char *) queuename);
10001
10002 /* Chug through config file. */
10003 cat = NULL;
10005 while ((cat = ast_category_browse(cfg, cat)) ) {
10006 if (!strcasecmp(cat, "general") && queue_reload) {
10008 continue;
10009 }
10010 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
10011 reload_single_queue(cfg, mask, cat);
10012 }
10013
10014 ast_config_destroy(cfg);
10015 if (queue_reload) {
10016 /* Unlink and mark dead all non-realtime queues that were not found in the configuration file. */
10018 }
10020 return 0;
10021}
10022
10023/*! \brief Facilitates resetting statistics for a queue
10024 *
10025 * This function actually does not reset any statistics, but
10026 * rather finds a call_queue struct which corresponds to the
10027 * passed-in queue name and passes that structure to the
10028 * clear_queue function. If no queuename is passed in, then
10029 * all queues will have their statistics reset.
10030 *
10031 * \param queuename The name of the queue to reset the statistics
10032 * for. If this is NULL or zero-length, then this means to reset
10033 * the statistics for all queues
10034 * \retval 0 always
10035 */
10036static int clear_stats(const char *queuename)
10037{
10038 struct call_queue *q;
10039 struct ao2_iterator queue_iter;
10040
10041 queue_iter = ao2_iterator_init(queues, 0);
10042 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10043 ao2_lock(q);
10044 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
10045 clear_queue(q);
10046 ao2_unlock(q);
10047 queue_t_unref(q, "Done with iterator");
10048 }
10049 ao2_iterator_destroy(&queue_iter);
10050 return 0;
10051}
10052
10053/*! \brief The command center for all reload operations
10054 *
10055 * Whenever any piece of queue information is to be reloaded, this function
10056 * is called. It interprets the flags set in the mask parameter and acts
10057 * based on how they are set.
10058 *
10059 * \param reload True if we are reloading information, false if we are loading
10060 * information for the first time.
10061 * \param mask A bitmask which tells the handler what actions to take
10062 * \param queuename The name of the queue on which we wish to take action
10063 * \retval 0 All reloads were successful
10064 * \retval non-zero There was a failure
10065 */
10066static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
10067{
10068 int res = 0;
10069
10070 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
10071 res |= reload_queue_rules(reload);
10072 }
10073 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
10074 res |= clear_stats(queuename);
10075 }
10077 res |= reload_queues(reload, mask, queuename);
10078 }
10079 return res;
10080}
10081
10082/*! \brief direct output to manager or cli with proper terminator */
10083static void do_print(struct mansession *s, int fd, const char *str)
10084{
10085 if (s) {
10086 astman_append(s, "%s\r\n", str);
10087 } else {
10088 ast_cli(fd, "%s\n", str);
10089 }
10090}
10091
10092/*! \brief Print a single queue to AMI or the CLI */
10093static void print_queue(struct mansession *s, int fd, struct call_queue *q)
10094{
10095 float sl;
10096 float sl2;
10097 struct ao2_iterator mem_iter;
10098 struct ast_str *out = ast_str_alloca(512);
10099 time_t now = time(NULL);
10100
10101 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
10102 if (q->maxlen) {
10103 ast_str_append(&out, 0, "%d", q->maxlen);
10104 } else {
10105 ast_str_append(&out, 0, "unlimited");
10106 }
10107 sl = 0;
10108 sl2 = 0;
10109 if (q->callscompleted > 0) {
10110 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
10111 }
10112 if (q->callscompleted + q->callsabandoned > 0) {
10113 sl2 =100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted));
10114 }
10115
10116 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",
10118 do_print(s, fd, ast_str_buffer(out));
10119 if (!ao2_container_count(q->members)) {
10120 do_print(s, fd, " No Members");
10121 } else {
10122 struct member *mem;
10123
10124 do_print(s, fd, " Members: ");
10125 mem_iter = ao2_iterator_init(q->members, 0);
10126 while ((mem = ao2_iterator_next(&mem_iter))) {
10127 ast_str_set(&out, 0, " %s", mem->membername);
10128 if (strcasecmp(mem->membername, mem->interface)) {
10129 ast_str_append(&out, 0, " (%s", mem->interface);
10131 && strcmp(mem->state_interface, mem->interface)) {
10132 ast_str_append(&out, 0, " from %s", mem->state_interface);
10133 }
10134 ast_str_append(&out, 0, ")");
10135 }
10136 if (mem->penalty) {
10137 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
10138 }
10139
10140 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
10141
10142 ast_str_append(&out, 0, "%s%s%s%s%s%s%s%s%s",
10143 mem->dynamic ? ast_term_color(COLOR_CYAN, COLOR_BLACK) : "", mem->dynamic ? " (dynamic)" : "", ast_term_reset(),
10144 mem->realtime ? ast_term_color(COLOR_MAGENTA, COLOR_BLACK) : "", mem->realtime ? " (realtime)" : "", ast_term_reset(),
10145 mem->starttime ? ast_term_color(COLOR_BROWN, COLOR_BLACK) : "", mem->starttime ? " (in call)" : "", ast_term_reset());
10146
10147 if (mem->paused) {
10148 ast_str_append(&out, 0, " %s(paused%s%s was %ld secs ago)%s",
10150 ast_strlen_zero(mem->reason_paused) ? "" : ":",
10152 (long) (now - mem->lastpause),
10153 ast_term_reset());
10154 }
10155
10156 ast_str_append(&out, 0, " (%s%s%s)",
10161 if (mem->calls) {
10162 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
10163 mem->calls, (long) (now - mem->lastcall));
10164 } else {
10165 ast_str_append(&out, 0, " has taken no calls yet");
10166 }
10167 ast_str_append(&out, 0, " %s(login was %ld secs ago)%s",
10169 (long) (now - mem->logintime),
10170 ast_term_reset());
10171 do_print(s, fd, ast_str_buffer(out));
10172 ao2_ref(mem, -1);
10173 }
10174 ao2_iterator_destroy(&mem_iter);
10175 }
10176 if (!q->head) {
10177 do_print(s, fd, " No Callers");
10178 } else {
10179 struct queue_ent *qe;
10180 int pos = 1;
10181
10182 do_print(s, fd, " Callers: ");
10183 for (qe = q->head; qe; qe = qe->next) {
10184 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
10185 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
10186 (long) (now - qe->start) % 60, qe->prio);
10187 do_print(s, fd, ast_str_buffer(out));
10188 }
10189 }
10190 do_print(s, fd, ""); /* blank line between entries */
10191}
10192
10194
10195/*!
10196 * \brief Show queue(s) status and statistics
10197 *
10198 * List the queues strategy, calls processed, members logged in,
10199 * other queue statistics such as avg hold time.
10200*/
10201static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
10202{
10203 struct call_queue *q;
10204 struct ast_str *out = ast_str_alloca(512);
10205 struct ao2_container *sorted_queues;
10206
10207 struct ao2_iterator queue_iter;
10208 int found = 0;
10209
10210 if (argc != 2 && argc != 3) {
10211 return CLI_SHOWUSAGE;
10212 }
10213
10214 if (argc == 3) { /* specific queue */
10215 if ((q = find_load_queue_rt_friendly(argv[2]))) {
10216 ao2_lock(q);
10217 print_queue(s, fd, q);
10218 ao2_unlock(q);
10219 queue_unref(q);
10220 } else {
10221 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
10222 do_print(s, fd, ast_str_buffer(out));
10223 }
10224 return CLI_SUCCESS;
10225 }
10226
10227 if (ast_check_realtime("queues")) {
10228 /* This block is to find any queues which are defined in realtime but
10229 * which have not yet been added to the in-core container
10230 */
10231 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10232 if (cfg) {
10233 char *category = NULL;
10234 while ((category = ast_category_browse(cfg, category))) {
10235 const char *queuename = ast_variable_retrieve(cfg, category, "name");
10236 if (ast_strlen_zero(queuename)) {
10237 ast_log(LOG_WARNING, "Ignoring realtime queue with a NULL or empty 'name.'\n");
10238 continue;
10239 }
10240 if ((q = find_load_queue_rt_friendly(queuename))) {
10241 queue_t_unref(q, "Done with temporary pointer");
10242 }
10243 }
10244 ast_config_destroy(cfg);
10245 }
10246 }
10247
10248 /*
10249 * Snapping a copy of the container prevents having to lock both the queues container
10250 * and the queue itself at the same time. It also allows us to sort the entries.
10251 */
10252 sorted_queues = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, call_queue_sort_fn, NULL);
10253 if (!sorted_queues) {
10254 return CLI_SUCCESS;
10255 }
10256 if (ao2_container_dup(sorted_queues, queues, 0)) {
10257 ao2_ref(sorted_queues, -1);
10258 return CLI_SUCCESS;
10259 }
10260
10261 /*
10262 * No need to lock the container since it's temporary and static.
10263 * We also unlink the entries as we use them so the container is
10264 * empty when the iterator finishes. We can then just unref the container.
10265 */
10266 queue_iter = ao2_iterator_init(sorted_queues, AO2_ITERATOR_DONTLOCK | AO2_ITERATOR_UNLINK);
10267 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10268 struct call_queue *realtime_queue = NULL;
10269 ao2_lock(q);
10270 /* This check is to make sure we don't print information for realtime
10271 * queues which have been deleted from realtime but which have not yet
10272 * been deleted from the in-core container. Only do this if we're not
10273 * looking for a specific queue.
10274 */
10275 if (q->realtime) {
10276 realtime_queue = find_load_queue_rt_friendly(q->name);
10277 if (!realtime_queue) {
10278 ao2_unlock(q);
10279 queue_t_unref(q, "Done with iterator");
10280 continue;
10281 }
10282 queue_t_unref(realtime_queue, "Queue is already in memory");
10283 }
10284
10285 found = 1;
10286 print_queue(s, fd, q);
10287
10288 ao2_unlock(q);
10289 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
10290 }
10291 ao2_iterator_destroy(&queue_iter);
10292 ao2_ref(sorted_queues, -1);
10293 if (!found) {
10294 ast_str_set(&out, 0, "No queues.");
10295 do_print(s, fd, ast_str_buffer(out));
10296 }
10297 return CLI_SUCCESS;
10298}
10299
10300/*!
10301 * \brief Check if a given word is in a space-delimited list
10302 *
10303 * \param list Space delimited list of words
10304 * \param word The word used to search the list
10305 *
10306 * \note This function will not return 1 if the word is at the very end of the
10307 * list (followed immediately by a \0, not a space) since it is used for
10308 * checking tab-completion and a word at the end is still being tab-completed.
10309 *
10310 * \retval 1 if the word is found
10311 * \retval 0 if the word is not found
10312*/
10313static int word_in_list(const char *list, const char *word) {
10314 int list_len, word_len = strlen(word);
10315 const char *find, *end_find, *end_list;
10316
10317 /* strip whitespace from front */
10318 while(isspace(*list)) {
10319 list++;
10320 }
10321
10322 while((find = strstr(list, word))) {
10323 /* beginning of find starts inside another word? */
10324 if (find != list && *(find - 1) != ' ') {
10325 list = find;
10326 /* strip word from front */
10327 while(!isspace(*list) && *list != '\0') {
10328 list++;
10329 }
10330 /* strip whitespace from front */
10331 while(isspace(*list)) {
10332 list++;
10333 }
10334 continue;
10335 }
10336
10337 /* end of find ends inside another word or at very end of list? */
10338 list_len = strlen(list);
10339 end_find = find + word_len;
10340 end_list = list + list_len;
10341 if (end_find == end_list || *end_find != ' ') {
10342 list = find;
10343 /* strip word from front */
10344 while(!isspace(*list) && *list != '\0') {
10345 list++;
10346 }
10347 /* strip whitespace from front */
10348 while(isspace(*list)) {
10349 list++;
10350 }
10351 continue;
10352 }
10353
10354 /* terminating conditions satisfied, word at beginning or separated by ' ' */
10355 return 1;
10356 }
10357
10358 return 0;
10359}
10360
10361/*!
10362 * \brief Check if a given word is in a space-delimited list
10363 *
10364 * \param line The line as typed not including the current word being completed
10365 * \param word The word currently being completed
10366 * \param pos The number of completed words in line
10367 * \param state The nth desired completion option
10368 * \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.
10369 *
10370 * \return Returns the queue tab-completion for the given word and state
10371*/
10372static char *complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
10373{
10374 struct call_queue *q;
10375 char *ret = NULL;
10376 int which = 0;
10377 int wordlen = strlen(word);
10378 struct ao2_iterator queue_iter;
10379 const char *word_list = NULL;
10380
10381 /* for certain commands, already completed items should be left out of
10382 * the list */
10383 if (word_list_offset && strlen(line) >= word_list_offset) {
10384 word_list = line + word_list_offset;
10385 }
10386
10387 queue_iter = ao2_iterator_init(queues, 0);
10388 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10389 if (!strncasecmp(word, q->name, wordlen) && ++which > state
10390 && (!word_list_offset || !word_in_list(word_list, q->name))) {
10391 ret = ast_strdup(q->name);
10392 queue_t_unref(q, "Done with iterator");
10393 break;
10394 }
10395 queue_t_unref(q, "Done with iterator");
10396 }
10397 ao2_iterator_destroy(&queue_iter);
10398
10399 /* Pretend "rules" is at the end of the queues list in certain
10400 * circumstances since it is an alternate command that should be
10401 * tab-completable for "queue show" */
10402 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
10403 ret = ast_strdup("rules");
10404 }
10405
10406 return ret;
10407}
10408
10409static char *complete_queue_show(const char *line, const char *word, int pos, int state)
10410{
10411 if (pos == 2) {
10412 return complete_queue(line, word, pos, state, 0);
10413 }
10414 return NULL;
10415}
10416
10417static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
10418{
10419 switch ( cmd ) {
10420 case CLI_INIT:
10421 e->command = "queue show";
10422 e->usage =
10423 "Usage: queue show\n"
10424 " Provides summary information on a specified queue.\n";
10425 return NULL;
10426 case CLI_GENERATE:
10427 return complete_queue_show(a->line, a->word, a->pos, a->n);
10428 }
10429
10430 return __queues_show(NULL, a->fd, a->argc, a->argv);
10431}
10432
10433static int manager_queue_rule_show(struct mansession *s, const struct message *m)
10434{
10435 const char *rule = astman_get_header(m, "Rule");
10436 const char *id = astman_get_header(m, "ActionID");
10437 struct rule_list *rl_iter;
10438 struct penalty_rule *pr_iter;
10439
10440 astman_append(s, "Response: Success\r\n");
10441 if (!ast_strlen_zero(id)) {
10442 astman_append(s, "ActionID: %s\r\n", id);
10443 }
10444
10446 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
10447 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
10448 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
10449 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
10450 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 );
10451 }
10452 if (!ast_strlen_zero(rule)) {
10453 break;
10454 }
10455 }
10456 }
10458
10459 /*
10460 * Two blank lines instead of one because the Response and
10461 * ActionID headers used to not be present.
10462 */
10463 astman_append(s, "\r\n\r\n");
10464
10465 return RESULT_SUCCESS;
10466}
10467
10468/*! \brief Summary of queue info via the AMI */
10469static int manager_queues_summary(struct mansession *s, const struct message *m)
10470{
10471 time_t now;
10472 int qmemcount = 0;
10473 int qmemavail = 0;
10474 int qchancount = 0;
10475 int qlongestholdtime = 0;
10476 int qsummaries = 0;
10477 const char *id = astman_get_header(m, "ActionID");
10478 const char *queuefilter = astman_get_header(m, "Queue");
10479 char idText[256];
10480 struct call_queue *q;
10481 struct queue_ent *qe;
10482 struct member *mem;
10483 struct ao2_iterator queue_iter;
10484 struct ao2_iterator mem_iter;
10485
10486 if (ast_check_realtime("queues")) {
10487 load_realtime_queues(queuefilter);
10488 }
10489
10490 astman_send_listack(s, m, "Queue summary will follow", "start");
10491 time(&now);
10492 idText[0] = '\0';
10493 if (!ast_strlen_zero(id)) {
10494 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10495 }
10496 queue_iter = ao2_iterator_init(queues, 0);
10497 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10498 ao2_lock(q);
10499
10500 /* List queue properties */
10501 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10502 /* Reset the necessary local variables if no queuefilter is set*/
10503 qmemcount = 0;
10504 qmemavail = 0;
10505 qchancount = 0;
10506 qlongestholdtime = 0;
10507
10508 /* List Queue Members */
10509 mem_iter = ao2_iterator_init(q->members, 0);
10510 while ((mem = ao2_iterator_next(&mem_iter))) {
10511 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
10512 ++qmemcount;
10513 if (member_status_available(mem->status) && !mem->paused) {
10514 ++qmemavail;
10515 }
10516 }
10517 ao2_ref(mem, -1);
10518 }
10519 ao2_iterator_destroy(&mem_iter);
10520 for (qe = q->head; qe; qe = qe->next) {
10521 if ((now - qe->start) > qlongestholdtime) {
10522 qlongestholdtime = now - qe->start;
10523 }
10524 ++qchancount;
10525 }
10526 astman_append(s, "Event: QueueSummary\r\n"
10527 "Queue: %s\r\n"
10528 "LoggedIn: %d\r\n"
10529 "Available: %d\r\n"
10530 "Callers: %d\r\n"
10531 "HoldTime: %d\r\n"
10532 "TalkTime: %d\r\n"
10533 "LongestHoldTime: %d\r\n"
10534 "%s"
10535 "\r\n",
10536 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
10537 ++qsummaries;
10538 }
10539 ao2_unlock(q);
10540 queue_t_unref(q, "Done with iterator");
10541 }
10542 ao2_iterator_destroy(&queue_iter);
10543
10544 astman_send_list_complete_start(s, m, "QueueSummaryComplete", qsummaries);
10546
10547 return RESULT_SUCCESS;
10548}
10549
10550/*! \brief Queue status info via AMI */
10551static int manager_queues_status(struct mansession *s, const struct message *m)
10552{
10553 time_t now;
10554 int pos;
10555 int q_items = 0;
10556 const char *id = astman_get_header(m,"ActionID");
10557 const char *queuefilter = astman_get_header(m,"Queue");
10558 const char *memberfilter = astman_get_header(m,"Member");
10559 char idText[256];
10560 struct call_queue *q;
10561 struct queue_ent *qe;
10562 float sl = 0;
10563 float sl2 = 0;
10564 struct member *mem;
10565 struct ao2_iterator queue_iter;
10566 struct ao2_iterator mem_iter;
10567
10568 if (ast_check_realtime("queues")) {
10569 load_realtime_queues(queuefilter);
10570 }
10571
10572 astman_send_listack(s, m, "Queue status will follow", "start");
10573 time(&now);
10574 idText[0] = '\0';
10575 if (!ast_strlen_zero(id)) {
10576 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
10577 }
10578
10579 queue_iter = ao2_iterator_init(queues, 0);
10580 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
10581 ao2_lock(q);
10582
10583 /* List queue properties */
10584 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
10585 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
10586 sl2 = (((q->callscompleted + q->callsabandoned) > 0) ? 100 * (((float)q->callsabandonedinsl + (float)q->callscompletedinsl) / ((float)q->callsabandoned + (float)q->callscompleted)) : 0);
10587
10588 astman_append(s, "Event: QueueParams\r\n"
10589 "Queue: %s\r\n"
10590 "Max: %d\r\n"
10591 "Strategy: %s\r\n"
10592 "Calls: %d\r\n"
10593 "Holdtime: %d\r\n"
10594 "TalkTime: %d\r\n"
10595 "Completed: %d\r\n"
10596 "Abandoned: %d\r\n"
10597 "ServiceLevel: %d\r\n"
10598 "ServicelevelPerf: %2.1f\r\n"
10599 "ServicelevelPerf2: %2.1f\r\n"
10600 "Weight: %d\r\n"
10601 "%s"
10602 "\r\n",
10603 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
10604 q->callsabandoned, q->servicelevel, sl, sl2, q->weight, idText);
10605 ++q_items;
10606
10607 /* List Queue Members */
10608 mem_iter = ao2_iterator_init(q->members, 0);
10609 while ((mem = ao2_iterator_next(&mem_iter))) {
10610 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
10611 astman_append(s, "Event: QueueMember\r\n"
10612 "Queue: %s\r\n"
10613 "Name: %s\r\n"
10614 "Location: %s\r\n"
10615 "StateInterface: %s\r\n"
10616 "Membership: %s\r\n"
10617 "Penalty: %d\r\n"
10618 "CallsTaken: %d\r\n"
10619 "LastCall: %d\r\n"
10620 "LastPause: %d\r\n"
10621 "LoginTime: %d\r\n"
10622 "InCall: %d\r\n"
10623 "Status: %d\r\n"
10624 "Paused: %d\r\n"
10625 "PausedReason: %s\r\n"
10626 "Wrapuptime: %d\r\n"
10627 "%s"
10628 "\r\n",
10629 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
10630 mem->penalty, mem->calls, (int)mem->lastcall, (int)mem->lastpause, (int)mem->logintime, mem->starttime ? 1 : 0, mem->status,
10631 mem->paused, mem->reason_paused, mem->wrapuptime, idText);
10632 ++q_items;
10633 }
10634 ao2_ref(mem, -1);
10635 }
10636 ao2_iterator_destroy(&mem_iter);
10637
10638 /* List Queue Entries */
10639 pos = 1;
10640 for (qe = q->head; qe; qe = qe->next) {
10641 astman_append(s, "Event: QueueEntry\r\n"
10642 "Queue: %s\r\n"
10643 "Position: %d\r\n"
10644 "Channel: %s\r\n"
10645 "Uniqueid: %s\r\n"
10646 "CallerIDNum: %s\r\n"
10647 "CallerIDName: %s\r\n"
10648 "ConnectedLineNum: %s\r\n"
10649 "ConnectedLineName: %s\r\n"
10650 "Wait: %ld\r\n"
10651 "Priority: %d\r\n"
10652 "%s"
10653 "\r\n",
10654 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
10659 (long) (now - qe->start), qe->prio, idText);
10660 ++q_items;
10661 }
10662 }
10663 ao2_unlock(q);
10664 queue_t_unref(q, "Done with iterator");
10665 }
10666 ao2_iterator_destroy(&queue_iter);
10667
10668 astman_send_list_complete_start(s, m, "QueueStatusComplete", q_items);
10670
10671 return RESULT_SUCCESS;
10672}
10673
10674static int manager_add_queue_member(struct mansession *s, const struct message *m)
10675{
10676 const char *queuename, *interface, *penalty_s, *paused_s, *reason, *membername, *state_interface, *wrapuptime_s;
10677 int paused, penalty, wrapuptime = 0;
10678
10679 queuename = astman_get_header(m, "Queue");
10680 interface = astman_get_header(m, "Interface");
10681 penalty_s = astman_get_header(m, "Penalty");
10682 paused_s = astman_get_header(m, "Paused");
10683 reason = astman_get_header(m, "Reason"); /* Optional */
10684 membername = astman_get_header(m, "MemberName");
10685 state_interface = astman_get_header(m, "StateInterface");
10686 wrapuptime_s = astman_get_header(m, "Wrapuptime");
10687
10688 if (ast_strlen_zero(queuename)) {
10689 astman_send_error(s, m, "'Queue' not specified.");
10690 return 0;
10691 }
10692
10693 if (ast_strlen_zero(interface)) {
10694 astman_send_error(s, m, "'Interface' not specified.");
10695 return 0;
10696 }
10697
10698 if (ast_strlen_zero(penalty_s)) {
10699 penalty = 0;
10700 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
10701 penalty = 0;
10702 }
10703
10704 if (ast_strlen_zero(wrapuptime_s)) {
10705 wrapuptime = 0;
10706 } else if (sscanf(wrapuptime_s, "%30d", &wrapuptime) != 1 || wrapuptime < 0) {
10707 wrapuptime = 0;
10708 }
10709
10710 if (ast_strlen_zero(paused_s)) {
10711 paused = 0;
10712 } else {
10713 paused = abs(ast_true(paused_s));
10714 }
10715
10716 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, wrapuptime)) {
10717 case RES_OKAY:
10718 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
10719 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10720 } else {
10721 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
10722 }
10723 astman_send_ack(s, m, "Added interface to queue");
10724 break;
10725 case RES_EXISTS:
10726 astman_send_error(s, m, "Unable to add interface: Already there");
10727 break;
10728 case RES_NOSUCHQUEUE:
10729 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
10730 break;
10731 case RES_OUTOFMEMORY:
10732 astman_send_error(s, m, "Out of memory");
10733 break;
10734 }
10735
10736 return 0;
10737}
10738
10739static int manager_remove_queue_member(struct mansession *s, const struct message *m)
10740{
10741 const char *queuename, *interface;
10742 struct member *mem = NULL;
10743
10744 queuename = astman_get_header(m, "Queue");
10745 interface = astman_get_header(m, "Interface");
10746
10747 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
10748 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
10749 return 0;
10750 }
10751
10753 mem = find_member_by_queuename_and_interface(queuename, interface);
10754 }
10755
10756 switch (remove_from_queue(queuename, interface)) {
10757 case RES_OKAY:
10758 if (!mem || ast_strlen_zero(mem->membername)) {
10759 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
10760 } else {
10761 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
10762 }
10763 astman_send_ack(s, m, "Removed interface from queue");
10764 break;
10765 case RES_EXISTS:
10766 astman_send_error(s, m, "Unable to remove interface: Not there");
10767 break;
10768 case RES_NOSUCHQUEUE:
10769 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
10770 break;
10771 case RES_OUTOFMEMORY:
10772 astman_send_error(s, m, "Out of memory");
10773 break;
10774 case RES_NOT_DYNAMIC:
10775 astman_send_error(s, m, "Member not dynamic");
10776 break;
10777 }
10778
10779 if (mem) {
10780 ao2_ref(mem, -1);
10781 }
10782
10783 return 0;
10784}
10785
10786static int manager_pause_queue_member(struct mansession *s, const struct message *m)
10787{
10788 const char *queuename, *interface, *paused_s, *reason;
10789 int paused;
10790
10791 interface = astman_get_header(m, "Interface");
10792 paused_s = astman_get_header(m, "Paused");
10793 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
10794 reason = astman_get_header(m, "Reason"); /* Optional */
10795
10796 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
10797 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
10798 return 0;
10799 }
10800
10801 paused = abs(ast_true(paused_s));
10802
10803 if (set_member_paused(queuename, interface, reason, paused)) {
10804 astman_send_error(s, m, "Interface not found");
10805 } else {
10806 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
10807 }
10808 return 0;
10809}
10810
10811static int manager_queue_log_custom(struct mansession *s, const struct message *m)
10812{
10813 const char *queuename, *event, *message, *interface, *uniqueid;
10814
10815 queuename = astman_get_header(m, "Queue");
10816 uniqueid = astman_get_header(m, "UniqueId");
10817 interface = astman_get_header(m, "Interface");
10818 event = astman_get_header(m, "Event");
10819 message = astman_get_header(m, "Message");
10820
10821 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
10822 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
10823 return 0;
10824 }
10825
10826 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
10827 astman_send_ack(s, m, "Event added successfully");
10828
10829 return 0;
10830}
10831
10832static int manager_queue_reload(struct mansession *s, const struct message *m)
10833{
10834 struct ast_flags mask = {0,};
10835 const char *queuename = NULL;
10836 int header_found = 0;
10837
10838 queuename = astman_get_header(m, "Queue");
10839 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
10841 header_found = 1;
10842 }
10843 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
10845 header_found = 1;
10846 }
10847 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
10849 header_found = 1;
10850 }
10851
10852 if (!header_found) {
10854 }
10855
10856 if (!reload_handler(1, &mask, queuename)) {
10857 astman_send_ack(s, m, "Queue reloaded successfully");
10858 } else {
10859 astman_send_error(s, m, "Error encountered while reloading queue");
10860 }
10861 return 0;
10862}
10863
10864static int manager_queue_reset(struct mansession *s, const struct message *m)
10865{
10866 const char *queuename = NULL;
10867 struct ast_flags mask = {QUEUE_RESET_STATS,};
10868
10869 queuename = astman_get_header(m, "Queue");
10870
10871 if (!reload_handler(1, &mask, queuename)) {
10872 astman_send_ack(s, m, "Queue stats reset successfully");
10873 } else {
10874 astman_send_error(s, m, "Error encountered while resetting queue stats");
10875 }
10876 return 0;
10877}
10878
10879static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
10880{
10881 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
10882 switch (pos) {
10883 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
10884 return NULL;
10885 case 4: /* only one possible match, "to" */
10886 return state == 0 ? ast_strdup("to") : NULL;
10887 case 5: /* <queue> */
10888 return complete_queue(line, word, pos, state, 0);
10889 case 6: /* only one possible match, "penalty" */
10890 return state == 0 ? ast_strdup("penalty") : NULL;
10891 case 7:
10892 if (0 <= state && state < 100) { /* 0-99 */
10893 char *num;
10894 if ((num = ast_malloc(3))) {
10895 sprintf(num, "%d", state);
10896 }
10897 return num;
10898 } else {
10899 return NULL;
10900 }
10901 case 8: /* only one possible match, "as" */
10902 return state == 0 ? ast_strdup("as") : NULL;
10903 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
10904 return NULL;
10905 default:
10906 return NULL;
10907 }
10908}
10909
10910static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
10911{
10912 const char *queuename, *interface, *ringinuse_s;
10913 int ringinuse;
10914
10915 interface = astman_get_header(m, "Interface");
10916 ringinuse_s = astman_get_header(m, "RingInUse");
10917
10918 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
10919 queuename = astman_get_header(m, "Queue");
10920
10921 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
10922 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
10923 return 0;
10924 }
10925
10926 if (ast_true(ringinuse_s)) {
10927 ringinuse = 1;
10928 } else if (ast_false(ringinuse_s)) {
10929 ringinuse = 0;
10930 } else {
10931 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
10932 return 0;
10933 }
10934
10935 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
10936 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
10937 } else {
10938 astman_send_ack(s, m, "Interface ringinuse set successfully");
10939 }
10940
10941 return 0;
10942}
10943
10944static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
10945{
10946 const char *queuename, *interface, *penalty_s;
10947 int penalty;
10948
10949 interface = astman_get_header(m, "Interface");
10950 penalty_s = astman_get_header(m, "Penalty");
10951 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
10952 queuename = astman_get_header(m, "Queue");
10953
10954 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
10955 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
10956 return 0;
10957 }
10958
10959 penalty = atoi(penalty_s);
10960
10961 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
10962 astman_send_error(s, m, "Invalid interface, queuename or penalty");
10963 } else {
10964 astman_send_ack(s, m, "Interface penalty set successfully");
10965 }
10966
10967 return 0;
10968}
10969
10970static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
10971{
10972 const char *queuename, *caller, *priority_s, *immediate_s;
10973 int priority = 0, immediate = 0;
10974
10975 queuename = astman_get_header(m, "Queue");
10976 caller = astman_get_header(m, "Caller");
10977 priority_s = astman_get_header(m, "Priority");
10978 immediate_s = astman_get_header(m, "Immediate");
10979
10980 if (ast_strlen_zero(queuename)) {
10981 astman_send_error(s, m, "'Queue' not specified.");
10982 return 0;
10983 }
10984
10985 if (ast_strlen_zero(caller)) {
10986 astman_send_error(s, m, "'Caller' not specified.");
10987 return 0;
10988 }
10989
10990 if (ast_strlen_zero(priority_s)) {
10991 astman_send_error(s, m, "'Priority' not specified.");
10992 return 0;
10993 } else if (sscanf(priority_s, "%30d", &priority) != 1) {
10994 astman_send_error(s, m, "'Priority' need integer.");
10995 return 0;
10996 }
10997
10998 if (!ast_strlen_zero(immediate_s)) {
10999 immediate = ast_true(immediate_s);
11000 }
11001
11002 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11003 case RES_OKAY:
11004 astman_send_ack(s, m, "Priority change for caller on queue");
11005 break;
11006 case RES_NOSUCHQUEUE:
11007 astman_send_error(s, m, "Unable to change priority caller on queue: No such queue");
11008 break;
11009 case RES_NOT_CALLER:
11010 astman_send_error(s, m, "Unable to change priority caller on queue: No such caller");
11011 break;
11012 }
11013
11014 return 0;
11015}
11016
11018{
11019 const char *queuename, *caller, *withdraw_info;
11020
11021 queuename = astman_get_header(m, "Queue");
11022 caller = astman_get_header(m, "Caller");
11023 withdraw_info = astman_get_header(m, "WithdrawInfo");
11024
11025 if (ast_strlen_zero(queuename)) {
11026 astman_send_error(s, m, "'Queue' not specified.");
11027 return 0;
11028 }
11029
11030 if (ast_strlen_zero(caller)) {
11031 astman_send_error(s, m, "'Caller' not specified.");
11032 return 0;
11033 }
11034
11035 switch (request_withdraw_caller_from_queue(queuename, caller, withdraw_info)) {
11036 case RES_OKAY:
11037 astman_send_ack(s, m, "Withdraw requested successfully");
11038 break;
11039 case RES_NOSUCHQUEUE:
11040 astman_send_error(s, m, "Unable to request withdraw from queue: No such queue");
11041 break;
11042 case RES_NOT_CALLER:
11043 astman_send_error(s, m, "Unable to request withdraw from queue: No such caller");
11044 break;
11045 case RES_EXISTS:
11046 astman_send_error(s, m, "Unable to request withdraw from queue: Already requested");
11047 break;
11048 }
11049
11050 return 0;
11051}
11052
11053
11054static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11055{
11056 const char *queuename, *interface, *membername = NULL, *state_interface = NULL, *reason = NULL;
11057 int penalty, paused = 0;
11058
11059 switch ( cmd ) {
11060 case CLI_INIT:
11061 e->command = "queue add member";
11062 e->usage =
11063 "Usage: queue add member <dial string> to <queue> [penalty <penalty> [as <membername> [state_interface <interface> [paused <reason>]]]]\n"
11064 " 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";
11065 return NULL;
11066 case CLI_GENERATE:
11067 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
11068 }
11069
11070 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12) && (a->argc != 14)) {
11071 return CLI_SHOWUSAGE;
11072 } else if (strcmp(a->argv[4], "to")) {
11073 return CLI_SHOWUSAGE;
11074 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
11075 return CLI_SHOWUSAGE;
11076 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
11077 return CLI_SHOWUSAGE;
11078 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
11079 return CLI_SHOWUSAGE;
11080 } else if ((a->argc == 14) && strcmp(a->argv[12], "paused")) {
11081 return CLI_SHOWUSAGE;
11082 }
11083
11084 queuename = a->argv[5];
11085 interface = a->argv[3];
11086 if (a->argc >= 8) {
11087 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
11088 if (penalty < 0) {
11089 ast_cli(a->fd, "Penalty must be >= 0\n");
11090 penalty = 0;
11091 }
11092 } else {
11093 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
11094 penalty = 0;
11095 }
11096 } else {
11097 penalty = 0;
11098 }
11099
11100 if (a->argc >= 10) {
11101 membername = a->argv[9];
11102 }
11103
11104 if (a->argc >= 12) {
11105 state_interface = a->argv[11];
11106 }
11107
11108 if (a->argc >= 14) {
11109 paused = 1;
11110 reason = a->argv[13];
11111 }
11112
11113 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface, reason, 0)) {
11114 case RES_OKAY:
11115 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
11116 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11117 } else {
11118 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
11119 }
11120 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
11121 return CLI_SUCCESS;
11122 case RES_EXISTS:
11123 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
11124 return CLI_FAILURE;
11125 case RES_NOSUCHQUEUE:
11126 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
11127 return CLI_FAILURE;
11128 case RES_OUTOFMEMORY:
11129 ast_cli(a->fd, "Out of memory\n");
11130 return CLI_FAILURE;
11131 case RES_NOT_DYNAMIC:
11132 ast_cli(a->fd, "Member not dynamic\n");
11133 return CLI_FAILURE;
11134 default:
11135 return CLI_FAILURE;
11136 }
11137}
11138
11139static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
11140{
11141 int which = 0;
11142 struct call_queue *q;
11143 struct member *m;
11144 struct ao2_iterator queue_iter;
11145 struct ao2_iterator mem_iter;
11146 int wordlen = strlen(word);
11147
11148 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
11149 if (pos > 5 || pos < 3) {
11150 return NULL;
11151 }
11152 if (pos == 4) { /* only one possible match, 'from' */
11153 return (state == 0 ? ast_strdup("from") : NULL);
11154 }
11155
11156 if (pos == 5) { /* No need to duplicate code */
11157 return complete_queue(line, word, pos, state, 0);
11158 }
11159
11160 /* here is the case for 3, <member> */
11161 queue_iter = ao2_iterator_init(queues, 0);
11162 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
11163 ao2_lock(q);
11164 mem_iter = ao2_iterator_init(q->members, 0);
11165 while ((m = ao2_iterator_next(&mem_iter))) {
11166 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
11167 char *tmp;
11168 tmp = ast_strdup(m->interface);
11169 ao2_ref(m, -1);
11170 ao2_iterator_destroy(&mem_iter);
11171 ao2_unlock(q);
11172 queue_t_unref(q, "Done with iterator, returning interface name");
11173 ao2_iterator_destroy(&queue_iter);
11174 return tmp;
11175 }
11176 ao2_ref(m, -1);
11177 }
11178 ao2_iterator_destroy(&mem_iter);
11179 ao2_unlock(q);
11180 queue_t_unref(q, "Done with iterator");
11181 }
11182 ao2_iterator_destroy(&queue_iter);
11183
11184 return NULL;
11185}
11186
11187static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11188{
11189 const char *queuename, *interface;
11190 struct member *mem = NULL;
11191 char *res = CLI_FAILURE;
11192
11193 switch (cmd) {
11194 case CLI_INIT:
11195 e->command = "queue remove member";
11196 e->usage =
11197 "Usage: queue remove member <channel> from <queue>\n"
11198 " Remove a specific channel from a queue.\n";
11199 return NULL;
11200 case CLI_GENERATE:
11201 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
11202 }
11203
11204 if (a->argc != 6) {
11205 return CLI_SHOWUSAGE;
11206 } else if (strcmp(a->argv[4], "from")) {
11207 return CLI_SHOWUSAGE;
11208 }
11209
11210 queuename = a->argv[5];
11211 interface = a->argv[3];
11212
11214 mem = find_member_by_queuename_and_interface(queuename, interface);
11215 }
11216
11217 switch (remove_from_queue(queuename, interface)) {
11218 case RES_OKAY:
11219 if (!mem || ast_strlen_zero(mem->membername)) {
11220 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
11221 } else {
11222 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
11223 }
11224 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
11225 res = CLI_SUCCESS;
11226 break;
11227 case RES_EXISTS:
11228 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
11229 break;
11230 case RES_NOSUCHQUEUE:
11231 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
11232 break;
11233 case RES_OUTOFMEMORY:
11234 ast_cli(a->fd, "Out of memory\n");
11235 break;
11236 case RES_NOT_DYNAMIC:
11237 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
11238 break;
11239 }
11240
11241 if (mem) {
11242 ao2_ref(mem, -1);
11243 }
11244
11245 return res;
11246}
11247
11248
11249
11250static char *handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11251{
11252 const char *queuename, *caller;
11253 int priority, immediate = 0;
11254 char *res = CLI_FAILURE;
11255
11256 switch (cmd) {
11257 case CLI_INIT:
11258 e->command = "queue priority caller";
11259 e->usage =
11260 "Usage: queue priority caller <channel> on <queue> to <priority> [immediate]\n"
11261 " Change the priority of a channel on a queue, optionally applying the change in relation to existing callers.\n";
11262 return NULL;
11263 case CLI_GENERATE:
11264 return NULL;
11265 }
11266
11267 if (a->argc < 8) {
11268 return CLI_SHOWUSAGE;
11269 } else if (strcmp(a->argv[4], "on")) {
11270 return CLI_SHOWUSAGE;
11271 } else if (strcmp(a->argv[6], "to")) {
11272 return CLI_SHOWUSAGE;
11273 } else if (sscanf(a->argv[7], "%30d", &priority) != 1) {
11274 ast_log (LOG_ERROR, "<priority> parameter must be an integer.\n");
11275 return CLI_SHOWUSAGE;
11276 } else if (a->argc == 9) {
11277 if (strcmp(a->argv[8], "immediate")) {
11278 return CLI_SHOWUSAGE;
11279 }
11280 immediate = 1;
11281 }
11282
11283 caller = a->argv[3];
11284 queuename = a->argv[5];
11285
11286 switch (change_priority_caller_on_queue(queuename, caller, priority, immediate)) {
11287 case RES_OKAY:
11288 res = CLI_SUCCESS;
11289 break;
11290 case RES_NOSUCHQUEUE:
11291 ast_cli(a->fd, "Unable change priority caller %s on queue '%s': No such queue\n", caller, queuename);
11292 break;
11293 case RES_NOT_CALLER:
11294 ast_cli(a->fd, "Unable to change priority caller '%s' on queue '%s': Not there\n", caller, queuename);
11295
11296 break;
11297 }
11298
11299 return res;
11300}
11301
11302
11303
11304static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
11305{
11306 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
11307 switch (pos) {
11308 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
11309 return NULL;
11310 case 4: /* only one possible match, "queue" */
11311 return state == 0 ? ast_strdup("queue") : NULL;
11312 case 5: /* <queue> */
11313 return complete_queue(line, word, pos, state, 0);
11314 case 6: /* "reason" */
11315 return state == 0 ? ast_strdup("reason") : NULL;
11316 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
11317 return NULL;
11318 default:
11319 return NULL;
11320 }
11321}
11322
11323static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11324{
11325 const char *queuename, *interface, *reason;
11326 int paused;
11327
11328 switch (cmd) {
11329 case CLI_INIT:
11330 e->command = "queue {pause|unpause} member";
11331 e->usage =
11332 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
11333 " Pause or unpause a queue member. Not specifying a particular queue\n"
11334 " will pause or unpause a member across all queues to which the member\n"
11335 " belongs.\n";
11336 return NULL;
11337 case CLI_GENERATE:
11338 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
11339 }
11340
11341 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
11342 return CLI_SHOWUSAGE;
11343 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
11344 return CLI_SHOWUSAGE;
11345 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
11346 return CLI_SHOWUSAGE;
11347 }
11348
11349
11350 interface = a->argv[3];
11351 queuename = a->argc >= 6 ? a->argv[5] : NULL;
11352 reason = a->argc == 8 ? a->argv[7] : NULL;
11353 paused = !strcasecmp(a->argv[1], "pause");
11354
11355 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
11356 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
11357 if (!ast_strlen_zero(queuename)) {
11358 ast_cli(a->fd, " in queue '%s'", queuename);
11359 }
11360 if (!ast_strlen_zero(reason)) {
11361 ast_cli(a->fd, " for reason '%s'", reason);
11362 }
11363 ast_cli(a->fd, "\n");
11364 return CLI_SUCCESS;
11365 } else {
11366 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
11367 if (!ast_strlen_zero(queuename)) {
11368 ast_cli(a->fd, " in queue '%s'", queuename);
11369 }
11370 if (!ast_strlen_zero(reason)) {
11371 ast_cli(a->fd, " for reason '%s'", reason);
11372 }
11373 ast_cli(a->fd, "\n");
11374 return CLI_FAILURE;
11375 }
11376}
11377
11378static char *complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
11379{
11380 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
11381 switch (pos) {
11382 case 4:
11383 if (state == 0) {
11384 return ast_strdup("on");
11385 } else {
11386 return NULL;
11387 }
11388 case 6:
11389 if (state == 0) {
11390 return ast_strdup("in");
11391 } else {
11392 return NULL;
11393 }
11394 case 7:
11395 return complete_queue(line, word, pos, state, 0);
11396 default:
11397 return NULL;
11398 }
11399}
11400
11401static char *handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11402{
11403 const char *queuename = NULL, *interface;
11404 int ringinuse;
11405
11406 switch (cmd) {
11407 case CLI_INIT:
11408 e->command = "queue set ringinuse";
11409 e->usage =
11410 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
11411 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
11412 " then that interface's penalty is set in all queues to which that interface is a member.\n";
11413 break;
11414 return NULL;
11415 case CLI_GENERATE:
11416 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11417 }
11418
11419 /* Sensible argument counts */
11420 if (a->argc != 6 && a->argc != 8) {
11421 return CLI_SHOWUSAGE;
11422 }
11423
11424 /* Uses proper indicational words */
11425 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11426 return CLI_SHOWUSAGE;
11427 }
11428
11429 /* Set the queue name if applicable */
11430 if (a->argc == 8) {
11431 queuename = a->argv[7];
11432 }
11433
11434 /* Interface being set */
11435 interface = a->argv[5];
11436
11437 /* Check and set the ringinuse value */
11438 if (ast_true(a->argv[3])) {
11439 ringinuse = 1;
11440 } else if (ast_false(a->argv[3])) {
11441 ringinuse = 0;
11442 } else {
11443 return CLI_SHOWUSAGE;
11444 }
11445
11446 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
11447 case RESULT_SUCCESS:
11448 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11449 return CLI_SUCCESS;
11450 case RESULT_FAILURE:
11451 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
11452 return CLI_FAILURE;
11453 default:
11454 return CLI_FAILURE;
11455 }
11456}
11457
11458static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11459{
11460 const char *queuename = NULL, *interface;
11461 int penalty = 0;
11462
11463 switch (cmd) {
11464 case CLI_INIT:
11465 e->command = "queue set penalty";
11466 e->usage =
11467 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
11468 " Set a member's penalty in the queue specified. If no queue is specified\n"
11469 " then that interface's penalty is set in all queues to which that interface is a member\n";
11470 return NULL;
11471 case CLI_GENERATE:
11472 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
11473 }
11474
11475 if (a->argc != 6 && a->argc != 8) {
11476 return CLI_SHOWUSAGE;
11477 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
11478 return CLI_SHOWUSAGE;
11479 }
11480
11481 if (a->argc == 8) {
11482 queuename = a->argv[7];
11483 }
11484 interface = a->argv[5];
11485 penalty = atoi(a->argv[3]);
11486
11487 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
11488 case RESULT_SUCCESS:
11489 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11490 return CLI_SUCCESS;
11491 case RESULT_FAILURE:
11492 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
11493 return CLI_FAILURE;
11494 default:
11495 return CLI_FAILURE;
11496 }
11497}
11498
11499static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state)
11500{
11501 int which = 0;
11502 struct rule_list *rl_iter;
11503 int wordlen = strlen(word);
11504 char *ret = NULL;
11505 if (pos != 3) /* Wha? */ {
11506 return NULL;
11507 }
11508
11510 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11511 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
11512 ret = ast_strdup(rl_iter->name);
11513 break;
11514 }
11515 }
11517
11518 return ret;
11519}
11520
11521static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11522{
11523 const char *rule;
11524 struct rule_list *rl_iter;
11525 struct penalty_rule *pr_iter;
11526 switch (cmd) {
11527 case CLI_INIT:
11528 e->command = "queue show rules";
11529 e->usage =
11530 "Usage: queue show rules [rulename]\n"
11531 " Show the list of rules associated with rulename. If no\n"
11532 " rulename is specified, list all rules defined in queuerules.conf\n";
11533 return NULL;
11534 case CLI_GENERATE:
11535 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
11536 }
11537
11538 if (a->argc != 3 && a->argc != 4) {
11539 return CLI_SHOWUSAGE;
11540 }
11541
11542 rule = a->argc == 4 ? a->argv[3] : "";
11544 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
11545 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
11546 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
11547 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
11548 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);
11549 }
11550 }
11551 }
11553 return CLI_SUCCESS;
11554}
11555
11556static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11557{
11558 struct ast_flags mask = {QUEUE_RESET_STATS,};
11559 int i;
11560
11561 switch (cmd) {
11562 case CLI_INIT:
11563 e->command = "queue reset stats";
11564 e->usage =
11565 "Usage: queue reset stats [<queuenames>]\n"
11566 "\n"
11567 "Issuing this command will reset statistics for\n"
11568 "<queuenames>, or for all queues if no queue is\n"
11569 "specified.\n";
11570 return NULL;
11571 case CLI_GENERATE:
11572 if (a->pos >= 3) {
11573 return complete_queue(a->line, a->word, a->pos, a->n, 17);
11574 } else {
11575 return NULL;
11576 }
11577 }
11578
11579 if (a->argc < 3) {
11580 return CLI_SHOWUSAGE;
11581 }
11582
11583 if (a->argc == 3) {
11584 reload_handler(1, &mask, NULL);
11585 return CLI_SUCCESS;
11586 }
11587
11588 for (i = 3; i < a->argc; ++i) {
11589 reload_handler(1, &mask, a->argv[i]);
11590 }
11591
11592 return CLI_SUCCESS;
11593}
11594
11595static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
11596{
11597 struct ast_flags mask = {0,};
11598 int i;
11599
11600 switch (cmd) {
11601 case CLI_INIT:
11602 e->command = "queue reload {parameters|members|rules|all}";
11603 e->usage =
11604 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
11605 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
11606 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
11607 "specified in order to know what information to reload. Below is an explanation\n"
11608 "of each of these qualifiers.\n"
11609 "\n"
11610 "\t'members' - reload queue members from queues.conf\n"
11611 "\t'parameters' - reload all queue options except for queue members\n"
11612 "\t'rules' - reload the queuerules.conf file\n"
11613 "\t'all' - reload queue rules, parameters, and members\n"
11614 "\n"
11615 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
11616 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
11617 "one queue is specified when using this command, reloading queue rules may cause\n"
11618 "other queues to be affected\n";
11619 return NULL;
11620 case CLI_GENERATE:
11621 if (a->pos >= 3) {
11622 /* find the point at which the list of queue names starts */
11623 const char *command_end = a->line + strlen("queue reload ");
11624 command_end = strchr(command_end, ' ');
11625 if (!command_end) {
11626 command_end = a->line + strlen(a->line);
11627 }
11628 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
11629 } else {
11630 return NULL;
11631 }
11632 }
11633
11634 if (a->argc < 3)
11635 return CLI_SHOWUSAGE;
11636
11637 if (!strcasecmp(a->argv[2], "rules")) {
11639 } else if (!strcasecmp(a->argv[2], "members")) {
11641 } else if (!strcasecmp(a->argv[2], "parameters")) {
11643 } else if (!strcasecmp(a->argv[2], "all")) {
11645 }
11646
11647 if (a->argc == 3) {
11648 reload_handler(1, &mask, NULL);
11649 return CLI_SUCCESS;
11650 }
11651
11652 for (i = 3; i < a->argc; ++i) {
11653 reload_handler(1, &mask, a->argv[i]);
11654 }
11655
11656 return CLI_SUCCESS;
11657}
11658
11659/*!
11660 * \brief Update Queue with data of an outgoing call
11661*/
11662static int qupd_exec(struct ast_channel *chan, const char *data)
11663{
11664 int oldtalktime;
11665 char *parse;
11666 struct call_queue *q;
11667 struct member *mem;
11668 int newtalktime = 0;
11669
11671 AST_APP_ARG(queuename);
11672 AST_APP_ARG(uniqueid);
11673 AST_APP_ARG(agent);
11675 AST_APP_ARG(talktime);
11676 AST_APP_ARG(params););
11677
11678 if (ast_strlen_zero(data)) {
11679 ast_log(LOG_WARNING, "QueueUpdate requires arguments (queuename,uniqueid,agent,status,talktime,params[totaltime,callednumber])\n");
11680 return -1;
11681 }
11682
11683 parse = ast_strdupa(data);
11684
11686
11687 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid) || ast_strlen_zero(args.agent) || ast_strlen_zero(args.status)) {
11688 ast_log(LOG_WARNING, "Missing argument to QueueUpdate (queuename,uniqueid,agent,status,talktime,params[totaltime|callednumber])\n");
11689 return -1;
11690 }
11691
11692 if (!ast_strlen_zero(args.talktime)) {
11693 newtalktime = atoi(args.talktime);
11694 }
11695
11696 q = find_load_queue_rt_friendly(args.queuename);
11697 if (!q) {
11698 ast_log(LOG_WARNING, "QueueUpdate could not find requested queue '%s'\n", args.queuename);
11699 return 0;
11700 }
11701
11702 ao2_lock(q);
11703 if (q->members) {
11704 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
11705 while ((mem = ao2_iterator_next(&mem_iter))) {
11706 if (!strcasecmp(mem->membername, args.agent)) {
11707 if (!strcasecmp(args.status, "ANSWER")) {
11708 oldtalktime = q->talktime;
11709 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
11710 time(&mem->lastcall);
11711 mem->calls++;
11712 mem->lastqueue = q;
11713 q->callscompleted++;
11714
11715 if (newtalktime <= q->servicelevel) {
11716 q->callscompletedinsl++;
11717 }
11718 } else {
11719
11720 time(&mem->lastcall);
11721 q->callsabandoned++;
11722 }
11723
11724 ast_queue_log(args.queuename, args.uniqueid, args.agent, "OUTCALL", "%s|%s|%s", args.status, args.talktime, args.params);
11725 }
11726
11727 ao2_ref(mem, -1);
11728 }
11729
11730 ao2_iterator_destroy(&mem_iter);
11731 }
11732
11733 ao2_unlock(q);
11734 queue_t_unref(q, "Done with temporary pointer");
11735
11736 return 0;
11737}
11738
11739static struct ast_cli_entry cli_queue[] = {
11740 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
11741 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
11742 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
11743 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
11744 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
11745 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
11746 AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
11747 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
11748 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
11749 AST_CLI_DEFINE(handle_queue_change_priority_caller, "Change priority caller on queue"),
11750};
11751
11754
11755static int unload_module(void)
11756{
11759
11761
11762 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_join_type);
11763 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_leave_type);
11764 STASIS_MESSAGE_TYPE_CLEANUP(queue_caller_abandon_type);
11765
11766 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_status_type);
11767 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_added_type);
11768 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_removed_type);
11769 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_pause_type);
11770 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_penalty_type);
11771 STASIS_MESSAGE_TYPE_CLEANUP(queue_member_ringinuse_type);
11772
11773 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_called_type);
11774 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_connect_type);
11775 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_complete_type);
11776 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_dump_type);
11777 STASIS_MESSAGE_TYPE_CLEANUP(queue_agent_ringnoanswer_type);
11778
11780 ast_manager_unregister("QueueStatus");
11781 ast_manager_unregister("QueueRule");
11782 ast_manager_unregister("QueueSummary");
11783 ast_manager_unregister("QueueAdd");
11784 ast_manager_unregister("QueueRemove");
11785 ast_manager_unregister("QueuePause");
11786 ast_manager_unregister("QueueLog");
11787 ast_manager_unregister("QueueUpdate");
11788 ast_manager_unregister("QueuePenalty");
11789 ast_manager_unregister("QueueReload");
11790 ast_manager_unregister("QueueReset");
11791 ast_manager_unregister("QueueMemberRingInUse");
11792 ast_manager_unregister("QueueChangePriorityCaller");
11793 ast_manager_unregister("QueueWithdrawCaller");
11809
11811
11812 ast_unload_realtime("queue_members");
11815
11816 queues = NULL;
11817 return 0;
11818}
11819
11820/*!
11821 * \brief Load the module
11822 *
11823 * Module loading including tests for configuration or dependencies.
11824 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
11825 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
11826 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
11827 * configuration file or other non-critical problem return
11828 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
11829 */
11830static int load_module(void)
11831{
11832 int err = 0;
11833 struct ast_flags mask = {AST_FLAGS_ALL, };
11834 struct ast_config *member_config;
11835 struct stasis_topic *queue_topic;
11837
11840 if (!queues) {
11842 }
11843
11846 if (!pending_members) {
11847 unload_module();
11849 }
11850
11851 use_weight = 0;
11852
11853 if (reload_handler(0, &mask, NULL)) {
11854 unload_module();
11856 }
11857
11858 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, "reason_paused", RQ_CHAR, 80, SENTINEL);
11859
11860 /*
11861 * This section is used to determine which name for 'ringinuse' to use in realtime members
11862 * Necessary for supporting older setups.
11863 *
11864 * It also checks if 'reason_paused' exists in the realtime backend
11865 */
11866 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
11867 if (!member_config) {
11868 realtime_ringinuse_field = "ringinuse";
11869 } else {
11870 const char *config_val;
11871
11872 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
11873 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
11874 realtime_ringinuse_field = "ringinuse";
11875 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
11876 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
11877 realtime_ringinuse_field = "ignorebusy";
11878 } else {
11879 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
11880 realtime_ringinuse_field = "ringinuse";
11881 }
11882
11883 if (ast_variable_retrieve(member_config, NULL, "reason_paused")) {
11885 }
11886 }
11887 ast_config_destroy(member_config);
11888
11891 }
11892
11901 err |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
11902 err |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
11909 err |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
11910 err |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
11911 err |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
11912 err |= ast_manager_register_xml("QueueChangePriorityCaller", 0, manager_change_priority_caller_on_queue);
11922
11923 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
11925 if (!device_state_sub) {
11926 err = -1;
11927 }
11930
11932 queue_topic = ast_queue_topic_all();
11933 if (!manager_topic || !queue_topic) {
11934 unload_module();
11936 }
11938 if (!topic_forwarder) {
11939 unload_module();
11941 }
11942
11945 unload_module();
11947 }
11949 if (!agent_router) {
11950 unload_module();
11952 }
11956 NULL);
11960 NULL);
11961
11962 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_join_type);
11963 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_leave_type);
11964 err |= STASIS_MESSAGE_TYPE_INIT(queue_caller_abandon_type);
11965
11966 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_status_type);
11967 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_added_type);
11968 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_removed_type);
11969 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_pause_type);
11970 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_penalty_type);
11971 err |= STASIS_MESSAGE_TYPE_INIT(queue_member_ringinuse_type);
11972
11973 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_called_type);
11974 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_connect_type);
11975 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_complete_type);
11976 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_dump_type);
11977 err |= STASIS_MESSAGE_TYPE_INIT(queue_agent_ringnoanswer_type);
11978
11979 if (err) {
11980 unload_module();
11982 }
11984}
11985
11986static int reload(void)
11987{
11988 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
11989 ast_unload_realtime("queue_members");
11990 reload_handler(1, &mask, NULL);
11991 return 0;
11992}
11993
11994/*!
11995 * \brief Find a member by looking up queuename and interface.
11996 * \return member or NULL if member not found.
11997 */
11998static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface)
11999{
12000 struct member *mem = NULL;
12001 struct call_queue *q;
12002
12003 if ((q = find_load_queue_rt_friendly(queuename))) {
12004 ao2_lock(q);
12005 mem = ao2_find(q->members, interface, OBJ_KEY);
12006 ao2_unlock(q);
12007 queue_t_unref(q, "Expiring temporary reference.");
12008 }
12009 return mem;
12010}
12011
12013 .support_level = AST_MODULE_SUPPORT_CORE,
12014 .load = load_module,
12015 .unload = unload_module,
12016 .reload = reload,
12017 .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:313
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:892
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:449
void * ast_aoc_destroy_decoded(struct ast_aoc_decoded *decoded)
free an ast_aoc_decoded object
Definition: aoc.c:307
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:650
@ AST_AOC_S
Definition: aoc.h:64
char digit
jack_status_t status
Definition: app_jack.c:146
const char * str
Definition: app_jack.c:147
static struct ast_custom_function queuevar_function
Definition: app_queue.c:9495
static void handle_bridge_enter(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6405
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:2894
static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3591
static int is_longest_waiting_caller(struct queue_ent *caller, struct member *member)
Definition: app_queue.c:4605
static void load_realtime_queues(const char *queuename)
Definition: app_queue.c:3985
static struct member * interface_exists(struct call_queue *q, const char *interface)
Definition: app_queue.c:7487
static int is_our_turn(struct queue_ent *qe)
Check if we should start attempting to call queue members.
Definition: app_queue.c:5774
static void record_abandoned(struct queue_ent *qe)
Record that a caller gave up on waiting in queue.
Definition: app_queue.c:5108
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:9052
static char * queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:10417
static int get_wrapuptime(struct call_queue *q, struct member *member)
Return wrapuptime.
Definition: app_queue.c:2020
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:3607
static int context_included(const char *parent, const char *child)
Returns if one context includes another context.
Definition: app_queue.c:2806
static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
Set variables of queue.
Definition: app_queue.c:2092
static int manager_queue_reset(struct mansession *s, const struct message *m)
Definition: app_queue.c:10864
static struct ast_manager_event_blob * queue_member_ringinuse_to_ami(struct stasis_message *message)
Definition: app_queue.c:2228
static struct ast_manager_event_blob * queue_member_penalty_to_ami(struct stasis_message *message)
Definition: app_queue.c:2223
member_properties
Definition: app_queue.c:1794
@ MEMBER_RINGINUSE
Definition: app_queue.c:1796
@ MEMBER_PENALTY
Definition: app_queue.c:1795
#define RES_NOT_CALLER
Definition: app_queue.c:1599
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:6802
#define ANNOUNCEPOSITION_MORE_THAN
Definition: app_queue.c:1817
static int pending_members_cmp(void *obj, void *arg, int flags)
Definition: app_queue.c:2565
static void queue_reset_global_params(void)
Definition: app_queue.c:9612
static char * complete_queue_rule_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11499
static void dump_queue_members(struct call_queue *pm_queue)
Dump all members in a specific queue to the database.
Definition: app_queue.c:7514
#define QUEUE_UNPAUSED_DEVSTATE
Definition: app_queue.c:3566
static struct ast_custom_function queuemembercount_function
Definition: app_queue.c:9500
static struct ast_custom_function queuewaitingcount_function
Definition: app_queue.c:9516
static int play_file(struct ast_channel *chan, const char *filename)
Definition: app_queue.c:4172
static int queue_persistent_members
queues.conf [general] option
Definition: app_queue.c:1619
static const struct @50 queue_results[]
static int montype_default
queues.conf [general] option
Definition: app_queue.c:1628
static int mark_member_dead(void *obj, void *arg, int flags)
Definition: app_queue.c:9791
static char * app_pqm
Definition: app_queue.c:1607
static struct ast_custom_function queuememberlist_function
Definition: app_queue.c:9521
static struct ast_manager_event_blob * queue_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2144
static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
Definition: app_queue.c:7977
static char * realtime_ringinuse_field
name of the ringinuse field in the realtime database
Definition: app_queue.c:1649
static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, int raise_penalty, enum empty_conditions conditions, int devstate)
Check if members are available.
Definition: app_queue.c:2451
static void queue_bridge_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6552
static int remove_from_queue(const char *queuename, const char *interface)
Remove member from queue.
Definition: app_queue.c:7569
static int manager_add_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10674
#define MAX_PERIODIC_ANNOUNCEMENTS
Definition: app_queue.c:1585
static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
Definition: app_queue.c:3318
static int aqm_exec(struct ast_channel *chan, const char *data)
AddQueueMember application.
Definition: app_queue.c:8383
static void set_queue_result(struct ast_channel *chan, enum queue_result res)
sets the QUEUESTATUS channel variable
Definition: app_queue.c:1939
static struct ast_manager_event_blob * queue_member_pause_to_ami(struct stasis_message *message)
Definition: app_queue.c:2218
static void leave_queue(struct queue_ent *qe)
Caller leaving queue.
Definition: app_queue.c:4401
#define MAX_QUEUE_BUCKETS
Definition: app_queue.c:1592
static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
The command center for all reload operations.
Definition: app_queue.c:10066
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:9010
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:9422
static char * complete_queue_pause_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11304
static void do_hang(struct callattempt *o)
common hangup actions
Definition: app_queue.c:4656
static int set_member_value(const char *queuename, const char *interface, int property, int value)
Definition: app_queue.c:8029
static void reload_single_member(const char *memberdata, struct call_queue *q)
reload information pertaining to a single member
Definition: app_queue.c:9659
static struct ast_manager_event_blob * queue_agent_ringnoanswer_to_ami(struct stasis_message *message)
Definition: app_queue.c:2313
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:6158
static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
reload the queues.conf file
Definition: app_queue.c:9979
static int say_periodic_announcement(struct queue_ent *qe, int ringing)
Playback announcement to queued members if period has elapsed.
Definition: app_queue.c:5047
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:9822
static void setup_mixmonitor(struct queue_ent *qe, const char *filename)
Definition: app_queue.c:6934
static struct ast_manager_event_blob * queue_member_removed_to_ami(struct stasis_message *message)
Definition: app_queue.c:2213
#define DEFAULT_RETRY
Definition: app_queue.c:1582
static int upqm_exec(struct ast_channel *chan, const char *data)
UnpauseQueueMember application.
Definition: app_queue.c:8276
static void clear_queue(struct call_queue *q)
Definition: app_queue.c:3080
static void handle_attended_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle an attended transfer event.
Definition: app_queue.c:6497
static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
Definition: app_queue.c:4378
#define RES_NOT_DYNAMIC
Definition: app_queue.c:1598
static int compare_weight(struct call_queue *rq, struct member *member)
Definition: app_queue.c:4571
static char * handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11323
static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
Definition: app_queue.c:7990
static void queue_agent_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6189
queue_timeout_priority
Definition: app_queue.c:1681
@ TIMEOUT_PRIORITY_CONF
Definition: app_queue.c:1683
@ TIMEOUT_PRIORITY_APP
Definition: app_queue.c:1682
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:9374
static char * app_ql
Definition: app_queue.c:1611
static void queue_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9624
static void reload_queue_members(void)
Reload dynamic queue members persisted into the astdb.
Definition: app_queue.c:8129
static int rqm_exec(struct ast_channel *chan, const char *data)
RemoveQueueMember application.
Definition: app_queue.c:8312
static int valid_exit(struct queue_ent *qe, char digit)
Check for valid exit from queue via goto.
Definition: app_queue.c:4201
aqm_flags
Definition: app_queue.c:1519
@ AQMFLAG_REASON
Definition: app_queue.c:1521
@ AQMFLAG_PAUSED
Definition: app_queue.c:1520
static int is_member_available(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2635
#define QUEUE_PAUSED_DEVSTATE
Definition: app_queue.c:3565
#define ANNOUNCEPOSITION_NO
Definition: app_queue.c:1816
static char * handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11458
static void handle_masquerade(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6743
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:5913
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:10093
char * text
Definition: app_queue.c:1668
#define MAX_CALL_ATTEMPT_BUCKETS
Definition: app_queue.c:2543
static char * app_rqm
Definition: app_queue.c:1605
static void copy_rules(struct queue_ent *qe, const char *rulename)
Copy rule from global list into specified queue.
Definition: app_queue.c:8511
static int manager_queue_rule_show(struct mansession *s, const struct message *m)
Definition: app_queue.c:10433
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:7751
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
Definition: app_queue.c:7881
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:7675
static struct ao2_container * queues
Definition: app_queue.c:1930
static int negative_penalty_invalid
queues.conf [general] option
Definition: app_queue.c:1640
#define AST_MAX_WATCHERS
Definition: app_queue.c:5220
static int load_realtime_rules(void)
Load queue rules from realtime.
Definition: app_queue.c:3216
static void queue_rules_reset_global_params(void)
Definition: app_queue.c:9533
static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, time_t starttime)
update the queue status
Definition: app_queue.c:6001
static void escape_and_substitute(struct ast_channel *chan, const char *input, char *output, size_t size)
Definition: app_queue.c:6903
#define RES_OUTOFMEMORY
Definition: app_queue.c:1596
static int member_hash_fn(const void *obj, const int flags)
Definition: app_queue.c:2949
static int member_cmp_fn(void *obj1, void *obj2, int flags)
Definition: app_queue.c:2965
#define queues_t_unlink(c, q, tag)
Definition: app_queue.c:2089
#define DEFAULT_MIN_ANNOUNCE_FREQUENCY
The minimum number of seconds between position announcements.
Definition: app_queue.c:1590
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:4498
static void queue_stasis_data_destructor(void *obj)
Definition: app_queue.c:6288
static struct ast_manager_event_blob * queue_member_added_to_ami(struct stasis_message *message)
Definition: app_queue.c:2208
static struct ast_manager_event_blob * queue_agent_dump_to_ami(struct stasis_message *message)
Definition: app_queue.c:2308
static int extensionstate2devicestate(int state)
Helper function which converts from extension state to device state values.
Definition: app_queue.c:2757
#define queues_t_link(c, q, tag)
Definition: app_queue.c:2088
static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Definition: app_queue.c:2835
static int manager_queue_reload(struct mansession *s, const struct message *m)
Definition: app_queue.c:10832
static int get_member_penalty(char *queuename, char *interface)
Gets members penalty.
Definition: app_queue.c:8098
static int realtime_rules
queuerules.conf [general] option
Definition: app_queue.c:1634
static void handle_local_optimization_begin(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6571
static int pqm_exec(struct ast_channel *chan, const char *data)
PauseQueueMember application.
Definition: app_queue.c:8240
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:10372
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:6073
static char * handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11556
static int qupd_exec(struct ast_channel *chan, const char *data)
Update Queue with data of an outgoing call.
Definition: app_queue.c:11662
static char * complete_queue_show(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10409
static char * handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11401
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:8966
static int reload_queue_rules(int reload)
Reload the rules defined in queuerules.conf.
Definition: app_queue.c:9553
static char * complete_queue_add_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:10879
static char * handle_queue_change_priority_caller(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11250
static char * handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11521
static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
Definition: app_queue.c:10910
static char * complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11378
@ OPT_CALLER_AUTOMON
Definition: app_queue.c:1478
@ OPT_CALLEE_PARK
Definition: app_queue.c:1468
@ OPT_PREDIAL_CALLER
Definition: app_queue.c:1480
@ OPT_GO_ON
Definition: app_queue.c:1461
@ OPT_IGNORE_CONNECTEDLINE
Definition: app_queue.c:1467
@ OPT_CALLEE_AUTOMON
Definition: app_queue.c:1477
@ OPT_CALLEE_TRANSFER
Definition: app_queue.c:1473
@ OPT_CALLEE_GO_ON
Definition: app_queue.c:1463
@ OPT_MARK_AS_ANSWERED
Definition: app_queue.c:1460
@ OPT_IGNORE_CALL_FW
Definition: app_queue.c:1466
@ OPT_CALLER_PARK
Definition: app_queue.c:1469
@ OPT_NO_RETRY
Definition: app_queue.c:1470
@ OPT_DATA_QUALITY
Definition: app_queue.c:1462
@ OPT_CALLER_HANGUP
Definition: app_queue.c:1465
@ OPT_MUSICONHOLD_CLASS
Definition: app_queue.c:1481
@ OPT_CALLEE_AUTOMIXMON
Definition: app_queue.c:1475
@ OPT_CALLEE_HANGUP
Definition: app_queue.c:1464
@ OPT_CALLER_AUTOMIXMON
Definition: app_queue.c:1476
@ OPT_RINGING
Definition: app_queue.c:1471
@ OPT_CALLER_TRANSFER
Definition: app_queue.c:1474
@ OPT_PREDIAL_CALLEE
Definition: app_queue.c:1479
@ OPT_RING_WHEN_RINGING
Definition: app_queue.c:1472
static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
Definition: app_queue.c:4686
static const char * int2strat(int strategy)
Definition: app_queue.c:1951
#define RES_NOSUCHQUEUE
Definition: app_queue.c:1597
static void free_members(struct call_queue *q, int all)
Iterate through queue's member list and delete them.
Definition: app_queue.c:3725
static int publish_queue_member_pause(struct call_queue *q, struct member *member)
Definition: app_queue.c:7790
static void callattempt_free(struct callattempt *doomed)
Definition: app_queue.c:4476
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:5023
#define queue_t_unref(q, tag)
Definition: app_queue.c:2087
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:5234
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:2604
static char * app_qupd
Definition: app_queue.c:1613
#define queue_unref(q)
Definition: app_queue.c:2085
#define ANNOUNCEHOLDTIME_ALWAYS
Definition: app_queue.c:1800
static const struct ast_app_option queue_exec_options[128]
Definition: app_queue.c:1516
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:2369
static int shared_lastcall
queues.conf [general] option
Definition: app_queue.c:1631
static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
Definition: app_queue.c:10944
#define queue_t_ref(q, tag)
Definition: app_queue.c:2086
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:10201
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:3361
#define ANNOUNCEPOSITION_LIMIT
Definition: app_queue.c:1818
static char * app_upqm
Definition: app_queue.c:1609
static int clear_stats(const char *queuename)
Facilitates resetting statistics for a queue.
Definition: app_queue.c:10036
static struct ast_custom_function queuememberpenalty_function
Definition: app_queue.c:9526
static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
Definition: app_queue.c:7814
static int queue_cmp_cb(void *obj, void *arg, int flags)
Definition: app_queue.c:2007
queue_result
Definition: app_queue.c:1654
@ QUEUE_FULL
Definition: app_queue.c:1661
@ QUEUE_UNKNOWN
Definition: app_queue.c:1655
@ QUEUE_WITHDRAW
Definition: app_queue.c:1663
@ QUEUE_CONTINUE
Definition: app_queue.c:1662
@ QUEUE_LEAVEEMPTY
Definition: app_queue.c:1658
@ QUEUE_LEAVEUNAVAIL
Definition: app_queue.c:1660
@ QUEUE_JOINUNAVAIL
Definition: app_queue.c:1659
@ QUEUE_JOINEMPTY
Definition: app_queue.c:1657
@ QUEUE_TIMEOUT
Definition: app_queue.c:1656
static int manager_request_withdraw_caller_from_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:11017
static char * app
Definition: app_queue.c:1601
static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
Definition: app_queue.c:8006
static int queue_hash_cb(const void *obj, const int flags)
Definition: app_queue.c:2000
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:3780
static const char *const pm_family
Persistent Members astdb family.
Definition: app_queue.c:1616
#define queue_ref(q)
Definition: app_queue.c:2084
static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Get the total number of members in a specific queue (Deprecated)
Definition: app_queue.c:9217
static int log_membername_as_agent
queues.conf [general] option
Definition: app_queue.c:1643
static void update_qe_rule(struct queue_ent *qe)
update rules for queues
Definition: app_queue.c:5823
static void update_connected_line_from_peer(struct ast_channel *chan, struct ast_channel *peer, int is_caller)
Definition: app_queue.c:5204
static struct ast_manager_event_blob * queue_agent_called_to_ami(struct stasis_message *message)
Definition: app_queue.c:2293
static int queue_exec(struct ast_channel *chan, const char *data)
The starting point for all queue calls.
Definition: app_queue.c:8554
static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
Definition: app_queue.c:4088
static char * handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11187
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:5139
static const struct ast_app_option aqm_opts[128]
Definition: app_queue.c:1532
static void destroy_queue_member_cb(void *obj)
Definition: app_queue.c:2884
static void init_queue(struct call_queue *q)
Initialize Queue default values.
Definition: app_queue.c:2978
static struct ao2_container * pending_members
Definition: app_queue.c:2542
static struct ast_manager_event_blob * queue_multi_channel_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2252
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:11998
static int force_longest_waiting_caller
queues.conf [general] option
Definition: app_queue.c:1646
#define RES_OKAY
Definition: app_queue.c:1594
static struct ast_manager_event_blob * queue_member_status_to_ami(struct stasis_message *message)
Definition: app_queue.c:2203
static int kill_dead_members(void *obj, void *arg, int flags)
Definition: app_queue.c:9800
#define DEFAULT_TIMEOUT
Definition: app_queue.c:1583
static void remove_stasis_subscriptions(struct queue_stasis_data *queue_data)
Definition: app_queue.c:6305
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:9337
static int pending_members_hash(const void *obj, const int flags)
Definition: app_queue.c:2545
static int autofill_default
queues.conf [general] option
Definition: app_queue.c:1625
static int manager_pause_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10786
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:2118
#define ANNOUNCEHOLDTIME_ONCE
Definition: app_queue.c:1801
static struct ast_manager_event_blob * queue_caller_join_to_ami(struct stasis_message *message)
Definition: app_queue.c:2163
static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2053
static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
Change queue penalty by adding rule.
Definition: app_queue.c:3112
static char * handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11595
static int num_available_members(struct call_queue *q)
Get the number of members available to accept a call.
Definition: app_queue.c:4538
static int ql_exec(struct ast_channel *chan, const char *data)
QueueLog application.
Definition: app_queue.c:8477
static int manager_remove_queue_member(struct mansession *s, const struct message *m)
Definition: app_queue.c:10739
static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
Definition: app_queue.c:4013
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:4999
static struct stasis_message_router * agent_router
Definition: app_queue.c:11752
static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:2071
static struct member * get_interface_helper(struct call_queue *q, const char *interface)
Definition: app_queue.c:9029
static int mark_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9945
queue_reload_mask
Definition: app_queue.c:1551
@ QUEUE_RELOAD_RULES
Definition: app_queue.c:1554
@ QUEUE_RELOAD_MEMBER
Definition: app_queue.c:1553
@ QUEUE_RESET_STATS
Definition: app_queue.c:1555
@ QUEUE_RELOAD_PARAMETERS
Definition: app_queue.c:1552
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:2670
static int load_module(void)
Load the module.
Definition: app_queue.c:11830
static void member_add_to_queue(struct call_queue *queue, struct member *mem)
Definition: app_queue.c:3575
#define RECHECK
Definition: app_queue.c:1584
static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
Part 2 of ring_one.
Definition: app_queue.c:4782
static void pending_members_remove(struct member *mem)
Definition: app_queue.c:2593
static void end_bridge_callback(void *data)
Definition: app_queue.c:6863
enum queue_result id
Definition: app_queue.c:1667
static struct stasis_subscription * device_state_sub
Subscription to device state change messages.
Definition: app_queue.c:1637
static int manager_queues_summary(struct mansession *s, const struct message *m)
Summary of queue info via the AMI.
Definition: app_queue.c:10469
static struct call_queue * alloc_queue(const char *queuename)
Definition: app_queue.c:3756
static struct callattempt * find_best(struct callattempt *outgoing)
find the entry with the best metric, or NULL
Definition: app_queue.c:4914
static int get_queue_member_status(struct member *cur)
Return the current state of a member.
Definition: app_queue.c:2879
static int unload_module(void)
Definition: app_queue.c:11755
static int reload(void)
Definition: app_queue.c:11986
#define QUEUE_UNKNOWN_PAUSED_DEVSTATE
Definition: app_queue.c:3567
static void publish_dial_end_event(struct ast_channel *in, struct callattempt *outgoing, struct ast_channel *exception, const char *status)
Definition: app_queue.c:4486
static int manager_queues_status(struct mansession *s, const struct message *m)
Queue status info via AMI.
Definition: app_queue.c:10551
static void handle_local_optimization_end(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6622
static int say_position(struct queue_ent *qe, int ringing)
Definition: app_queue.c:4236
static int realtime_reason_paused
does realtime backend support reason_paused
Definition: app_queue.c:1652
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:6320
static void update_realtime_members(struct call_queue *q)
Definition: app_queue.c:4029
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:9454
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:2334
static struct ast_custom_function queuemembercount_dep
Definition: app_queue.c:9506
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:7622
static struct ast_manager_event_blob * queue_agent_connect_to_ami(struct stasis_message *message)
Definition: app_queue.c:2298
static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
Definition: app_queue.c:6856
empty_conditions
Definition: app_queue.c:1783
@ QUEUE_EMPTY_INVALID
Definition: app_queue.c:1789
@ QUEUE_EMPTY_UNKNOWN
Definition: app_queue.c:1790
@ QUEUE_EMPTY_PENALTY
Definition: app_queue.c:1784
@ QUEUE_EMPTY_RINGING
Definition: app_queue.c:1787
@ QUEUE_EMPTY_INUSE
Definition: app_queue.c:1786
@ QUEUE_EMPTY_UNAVAILABLE
Definition: app_queue.c:1788
@ QUEUE_EMPTY_WRAPUP
Definition: app_queue.c:1791
@ QUEUE_EMPTY_PAUSED
Definition: app_queue.c:1785
static struct ast_json * queue_member_blob_create(struct call_queue *q, struct member *mem)
Definition: app_queue.c:2424
static void queue_channel_cb(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6777
static int use_weight
Records that one or more queues use weight.
Definition: app_queue.c:1622
#define ANNOUNCEPOSITION_YES
Definition: app_queue.c:1815
static int wait_a_bit(struct queue_ent *qe)
Definition: app_queue.c:7474
static char * app_aqm
Definition: app_queue.c:1603
static void destroy_queue(void *obj)
Free queue's member list then its string fields.
Definition: app_queue.c:3741
static int kill_if_unfound(void *obj, void *arg, int flags)
Definition: app_queue.c:9955
static void handle_hangup(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Definition: app_queue.c:6686
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:10083
static char * complete_queue_remove_member(const char *line, const char *word, int pos, int state)
Definition: app_queue.c:11139
static char * handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: app_queue.c:11054
#define RES_EXISTS
Definition: app_queue.c:1595
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:9154
static void queue_rules_set_global_params(struct ast_config *cfg)
Definition: app_queue.c:9539
static int member_status_available(int status)
Definition: app_queue.c:4672
static int queue_member_decrement_followers(void *obj, void *arg, int flag)
Definition: app_queue.c:2034
static struct ast_cli_entry cli_queue[]
Definition: app_queue.c:11739
@ QUEUE_STRATEGY_RINGALL
Definition: app_queue.c:1535
@ QUEUE_STRATEGY_RRMEMORY
Definition: app_queue.c:1539
@ QUEUE_STRATEGY_LINEAR
Definition: app_queue.c:1540
@ QUEUE_STRATEGY_LEASTRECENT
Definition: app_queue.c:1536
@ QUEUE_STRATEGY_RANDOM
Definition: app_queue.c:1538
@ QUEUE_STRATEGY_FEWESTCALLS
Definition: app_queue.c:1537
@ QUEUE_STRATEGY_RRORDERED
Definition: app_queue.c:1542
@ QUEUE_STRATEGY_WRANDOM
Definition: app_queue.c:1541
static struct call_queue * find_load_queue_rt_friendly(const char *queuename)
Definition: app_queue.c:3924
static struct ast_custom_function queuegetchannel_function
Definition: app_queue.c:9511
static struct ast_manager_event_blob * queue_caller_abandon_to_ami(struct stasis_message *message)
Definition: app_queue.c:2173
static struct stasis_forward * topic_forwarder
Definition: app_queue.c:11753
static struct ast_custom_function queueexists_function
Definition: app_queue.c:9490
aqm_args
Definition: app_queue.c:1524
@ AQM_OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1526
@ AQM_OPT_ARG_PAUSE_REASON
Definition: app_queue.c:1525
static int strat2int(const char *strategy)
Definition: app_queue.c:1964
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:9258
static struct ast_manager_event_blob * queue_agent_complete_to_ami(struct stasis_message *message)
Definition: app_queue.c:2303
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:6886
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:10313
static void log_attended_transfer(struct queue_stasis_data *queue_data, struct ast_attended_transfer_message *atxfer_msg)
Definition: app_queue.c:6359
static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
Place a call to a queue member.
Definition: app_queue.c:4939
@ OPT_ARG_CALLEE_GO_ON
Definition: app_queue.c:1485
@ OPT_ARG_PREDIAL_CALLEE
Definition: app_queue.c:1486
@ OPT_ARG_MUSICONHOLD_CLASS
Definition: app_queue.c:1488
@ OPT_ARG_PREDIAL_CALLER
Definition: app_queue.c:1487
@ OPT_ARG_ARRAY_SIZE
Definition: app_queue.c:1490
static void handle_blind_transfer(void *userdata, struct stasis_subscription *sub, struct stasis_message *msg)
Handle a blind transfer event.
Definition: app_queue.c:6438
static const struct autopause autopausesmodes[]
agent_complete_reason
Definition: app_queue.c:6151
@ AGENT
Definition: app_queue.c:6153
@ CALLER
Definition: app_queue.c:6152
@ TRANSFER
Definition: app_queue.c:6154
static struct ast_manager_event_blob * queue_member_to_ami(const char *type, struct stasis_message *message)
Definition: app_queue.c:2188
@ QUEUE_AUTOPAUSE_ON
Definition: app_queue.c:1547
@ QUEUE_AUTOPAUSE_OFF
Definition: app_queue.c:1546
@ QUEUE_AUTOPAUSE_ALL
Definition: app_queue.c:1548
static int autopause2int(const char *autopause)
Definition: app_queue.c:1977
static int manager_change_priority_caller_on_queue(struct mansession *s, const struct message *m)
Definition: app_queue.c:10970
static int compress_char(const char c)
Definition: app_queue.c:2939
static void queue_publish_member_blob(struct stasis_message_type *type, struct ast_json *blob)
Definition: app_queue.c:2400
static int manager_queue_log_custom(struct mansession *s, const struct message *m)
Definition: app_queue.c:10811
static struct ast_manager_event_blob * queue_caller_leave_to_ami(struct stasis_message *message)
Definition: app_queue.c:2168
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:7007
static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
Definition: app_queue.c:7941
unsigned int stop
Definition: app_sla.c:336
ast_mutex_t lock
Definition: app_sla.c:331
#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: main/db.c:341
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: main/db.c:437
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:478
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:641
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:701
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:1100
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
static int tmp()
Definition: bt_open.c:389
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:393
static int priority
static int available(struct dahdi_pvt **pvt, int is_specific_channel)
Definition: chan_dahdi.c:13477
static const char type[]
Definition: chan_ooh323.c:109
static int call(void *data)
Definition: chan_pjsip.c:2394
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:3194
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:2141
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
Definition: channel.c:6480
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:10360
void ast_party_number_init(struct ast_party_number *init)
Initialize the given number structure.
Definition: channel.c:1663
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Definition: channel.c:2560
@ AST_CHANNEL_REQUESTOR_BRIDGE_PEER
Definition: channel.h:1523
int ast_party_id_presentation(const struct ast_party_id *id)
Determine the overall presentation value for the given party.
Definition: channel.c:1840
void ast_party_connected_line_free(struct ast_party_connected_line *doomed)
Destroy the connected line information contents.
Definition: channel.c:2091
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:7394
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:3176
#define ast_channel_lock(chan)
Definition: channel.h:2968
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
Make the frame formats of two channels compatible.
Definition: channel.c:6739
struct ast_format_cap * ast_channel_nativeformats(const struct ast_channel *chan)
void ast_channel_data_set(struct ast_channel *chan, const char *value)
@ 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_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:2050
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:2073
int ast_channel_priority(const struct ast_channel *chan)
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
Definition: channel.h:2975
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:2387
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:6453
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:4276
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:9115
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:2018
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:7356
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:10405
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:6790
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:8807
int ast_channel_supports_html(struct ast_channel *channel)
Checks for HTML support on a channel.
Definition: channel.c:6642
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:4672
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:10306
#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:1710
#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:2041
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:6654
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:2198
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:8315
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:6458
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:6463
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:7444
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:2064
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
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Definition: channel.c:1473
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:4296
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1593
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:6373
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
Definition: channel.h:2969
#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:2154
#define MAX_MUSICCLASS
Definition: channel.h:175
ast_channel_state
ast_channel states
Definition: channelstate.h:35
@ AST_STATE_UP
Definition: channelstate.h:42
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:510
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
struct stasis_topic * ast_device_state_topic_all(void)
Get the Stasis topic for device state messages.
Definition: devicestate.c:668
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:595
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:222
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
Definition: file.c:1293
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1129
#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:1840
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:2011
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:1969
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:2047
struct stasis_topic * ast_manager_get_topic(void)
Get the Stasis Message Bus API topic for AMI.
Definition: manager.c:453
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Definition: manager.c:2001
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:554
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2055
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1890
static struct stasis_topic * manager_topic
A stasis_topic that all topics AMI cares about will be forwarded to.
Definition: manager.c:185
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7608
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
char * strsep(char **str, const char *delims)
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:3326
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
Definition: extconf.c:3274
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Definition: main/config.c:3564
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: main/config.c:3637
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Definition: main/config.c:3591
#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:3545
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
Definition: main/config.c:784
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
Definition: main/config.c:3674
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3521
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1215
@ CONFIG_FLAG_FILEUNCHANGED
#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:965
#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:604
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:757
size_t current
Definition: main/cli.c:113
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:191
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:10128
#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:7788
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7798
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:8650
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4172
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:4175
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:1558
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
Definition: pbx.c:8781
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:4190
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:3856
@ 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:3823
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:3170
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:8257
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:1549
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:1024
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:1078
#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:1175
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1135
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:1579
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic's subscribers.
Definition: stasis.c:1512
#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
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:2199
#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:2216
#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:1835
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.
union ast_attended_transfer_message::@284 dest
enum ast_attended_transfer_dest_type dest_type
struct ast_channel_snapshot * links[2]
struct ast_bridge_channel_snapshot_pair to_transfer_target
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:328
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:284
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Definition: astdb.h:31
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:199
unsigned int flags
Definition: utils.h:200
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
union ast_frame::@226 data
enum ast_frame_type frametype
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:502
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
struct ast_party_dialed::@208 number
Dialed/Called number.
char * str
Subscriber phone number (Malloced)
Definition: channel.h:388
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:1574
const char * name
Definition: app_queue.c:1575
unsigned int autopauseunavail
Definition: app_queue.c:1878
int talktime
Definition: app_queue.c:1890
const ast_string_field sound_thereare
Definition: app_queue.c:1858
unsigned int setinterfacevar
Definition: app_queue.c:1864
struct call_queue::@53 list
struct ast_str * sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS]
Definition: app_queue.c:1860
const ast_string_field sound_callerannounce
Definition: app_queue.c:1858
int announcefrequency
Definition: app_queue.c:1882
const ast_string_field sound_reporthold
Definition: app_queue.c:1858
unsigned int announceholdtime
Definition: app_queue.c:1870
const ast_string_field sound_holdtime
Definition: app_queue.c:1858
unsigned int dead
Definition: app_queue.c:1861
unsigned int reportholdtime
Definition: app_queue.c:1867
unsigned int setqueueentryvar
Definition: app_queue.c:1866
const ast_string_field sound_seconds
Definition: app_queue.c:1858
unsigned int timeoutrestart
Definition: app_queue.c:1869
struct ao2_container * members
Definition: app_queue.c:1916
int periodicannouncefrequency
Definition: app_queue.c:1885
const ast_string_field sound_thanks
Definition: app_queue.c:1858
unsigned int announceposition_only_up
Definition: app_queue.c:1872
unsigned int setqueuevar
Definition: app_queue.c:1865
int announcepositionlimit
Definition: app_queue.c:1881
unsigned int announce_to_first_user
Definition: app_queue.c:1863
int randomperiodicannounce
Definition: app_queue.c:1887
int autopause
Definition: app_queue.c:1905
int periodicannouncestartdelay
Definition: app_queue.c:1884
const ast_string_field defaultrule
Definition: app_queue.c:1858
int log_restricted_caller_id
Definition: app_queue.c:1914
struct queue_ent * head
Definition: app_queue.c:1917
struct call_queue::@54 rules
unsigned int realtime
Definition: app_queue.c:1874
const ast_string_field queue_quantity2
Definition: app_queue.c:1858
int servicelevel
Definition: app_queue.c:1894
const ast_string_field moh
Definition: app_queue.c:1858
int autofill
Definition: app_queue.c:1912
int minannouncefrequency
Definition: app_queue.c:1883
enum empty_conditions leavewhenempty
Definition: app_queue.c:1880
int penaltymemberslimit
Definition: app_queue.c:1900
unsigned int found
Definition: app_queue.c:1875
const ast_string_field context
Definition: app_queue.c:1858
const ast_string_field sound_calls
Definition: app_queue.c:1858
unsigned int ringinuse
Definition: app_queue.c:1862
int callsabandoned
Definition: app_queue.c:1892
int roundingseconds
Definition: app_queue.c:1888
int numperiodicannounce
Definition: app_queue.c:1886
int wrapuptime
Definition: app_queue.c:1899
const ast_string_field sound_minute
Definition: app_queue.c:1858
int callscompleted
Definition: app_queue.c:1891
int callsabandonedinsl
Definition: app_queue.c:1893
const ast_string_field sound_minutes
Definition: app_queue.c:1858
unsigned int announceposition
Definition: app_queue.c:1871
const ast_string_field queue_quantity1
Definition: app_queue.c:1858
const ast_string_field membergosub
Definition: app_queue.c:1858
char monfmt[8]
Definition: app_queue.c:1896
enum empty_conditions joinempty
Definition: app_queue.c:1879
unsigned int wrapped
Definition: app_queue.c:1868
int strategy
Definition: app_queue.c:1873
const ast_string_field name
Definition: app_queue.c:1858
int callscompletedinsl
Definition: app_queue.c:1895
int memberdelay
Definition: app_queue.c:1911
const ast_string_field sound_next
Definition: app_queue.c:1858
unsigned int autopausebusy
Definition: app_queue.c:1877
int holdtime
Definition: app_queue.c:1889
const ast_string_field announce
Definition: app_queue.c:1858
int autopausedelay
Definition: app_queue.c:1906
int timeoutpriority
Definition: app_queue.c:1907
unsigned int relativeperiodicannounce
Definition: app_queue.c:1876
We define a custom "local user" structure because we use it not only for keeping track of what is in ...
Definition: app_queue.c:1698
unsigned int dial_callerid_absent
Definition: app_queue.c:1712
unsigned int block_connected_update
Definition: app_queue.c:1710
struct ast_aoc_decoded * aoc_s_rate_list
Definition: app_queue.c:1715
struct ast_party_connected_line connected
Definition: app_queue.c:1706
char interface[256]
Definition: app_queue.c:1702
char * orig_chan_name
Definition: app_queue.c:1717
struct callattempt * call_next
Definition: app_queue.c:1700
struct ast_channel * chan
Definition: app_queue.c:1701
unsigned int stillgoing
Definition: app_queue.c:1714
struct callattempt * q_next
Definition: app_queue.c:1699
struct member * member
Definition: app_queue.c:1704
unsigned int pending_connected_update
Definition: app_queue.c:1708
Definition: search.h:40
char * key
Definition: search.h:41
Definition: astman.c:222
structure to hold extensions
Structure representing relevant data during a local channel optimization.
Definition: app_queue.c:6227
const char * source_chan_uniqueid
Definition: app_queue.c:6229
unsigned int id
Definition: app_queue.c:6233
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:326
Channel datastore data for max forwards.
Definition: max_forwards.c:29
char interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1756
unsigned int dead
Definition: app_queue.c:1777
unsigned int delme
Definition: app_queue.c:1778
int queuepos
Definition: app_queue.c:1769
time_t starttime
Definition: app_queue.c:1772
time_t lastcall
Definition: app_queue.c:1773
int dynamic
Definition: app_queue.c:1764
time_t logintime
Definition: app_queue.c:1775
char membername[80]
Definition: app_queue.c:1761
char rt_uniqueid[80]
Definition: app_queue.c:1779
int calls
Definition: app_queue.c:1763
int status
Definition: app_queue.c:1766
int penalty
Definition: app_queue.c:1762
int paused
Definition: app_queue.c:1767
unsigned int ringinuse
Definition: app_queue.c:1780
int wrapuptime
Definition: app_queue.c:1771
int callcompletedinsl
Definition: app_queue.c:1770
char state_exten[AST_MAX_EXTENSION]
Definition: app_queue.c:1757
char state_context[AST_MAX_CONTEXT]
Definition: app_queue.c:1758
int realtime
Definition: app_queue.c:1765
int state_id
Definition: app_queue.c:1760
time_t lastpause
Definition: app_queue.c:1774
char reason_paused[80]
Definition: app_queue.c:1768
struct call_queue * lastqueue
Definition: app_queue.c:1776
char state_interface[AST_CHANNEL_NAME]
Definition: app_queue.c:1759
Number structure.
Definition: app_followme.c:154
int raise_relative
Definition: app_queue.c:1811
struct penalty_rule::@52 list
int min_relative
Definition: app_queue.c:1810
int max_relative
Definition: app_queue.c:1809
struct call_queue * q
Definition: app_queue.c:6852
struct ast_channel * chan
Definition: app_queue.c:6853
char digits[AST_MAX_EXTENSION]
Definition: app_queue.c:1726
int valid_digits
Definition: app_queue.c:1728
time_t last_pos
Definition: app_queue.c:1735
time_t last_periodic_announce_time
Definition: app_queue.c:1733
time_t expire
Definition: app_queue.c:1745
unsigned int withdraw
Definition: app_queue.c:1747
struct penalty_rule * pr
Definition: app_queue.c:1751
int linpos
Definition: app_queue.c:1742
int max_penalty
Definition: app_queue.c:1739
int pending
Definition: app_queue.c:1738
int raise_penalty
Definition: app_queue.c:1741
struct ast_channel * chan
Definition: app_queue.c:1749
int min_penalty
Definition: app_queue.c:1740
int ring_when_ringing
Definition: app_queue.c:1732
int cancel_answered_elsewhere
Definition: app_queue.c:1746
struct queue_ent::@51 qe_rules
char announce[PATH_MAX]
Definition: app_queue.c:1724
char * withdraw_info
Definition: app_queue.c:1748
int handled
Definition: app_queue.c:1737
int linwrapped
Definition: app_queue.c:1743
char moh[MAX_MUSICCLASS]
Definition: app_queue.c:1723
int last_pos_said
Definition: app_queue.c:1731
char context[AST_MAX_CONTEXT]
Definition: app_queue.c:1725
int last_periodic_announce_sound
Definition: app_queue.c:1734
const char * predial_callee
Definition: app_queue.c:1727
time_t start
Definition: app_queue.c:1744
struct call_queue * parent
Definition: app_queue.c:1722
struct queue_ent * next
Definition: app_queue.c:1752
User data for stasis subscriptions used for queue calls.
Definition: app_queue.c:6251
const ast_string_field caller_uniqueid
Definition: app_queue.c:6259
const ast_string_field member_uniqueid
Definition: app_queue.c:6259
struct local_optimization member_optimize
Definition: app_queue.c:6281
struct stasis_message_router * channel_router
Definition: app_queue.c:6277
struct call_queue * queue
Definition: app_queue.c:6261
const ast_string_field bridge_uniqueid
Definition: app_queue.c:6259
struct stasis_message_router * bridge_router
Definition: app_queue.c:6275
struct local_optimization caller_optimize
Definition: app_queue.c:6279
struct member * member
Definition: app_queue.c:6263
struct rule_list::@55 rules
char name[80]
Definition: app_queue.c:1923
struct rule_list::@56 list
Forwarding information.
Definition: stasis.c:1532
const char * name
Definition: app_queue.c:1560
int strategy
Definition: app_queue.c:1559
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:2281
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:941
#define ast_assert(a)
Definition: utils.h:739
long int ast_random(void)
Definition: utils.c:2312
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define ARRAY_LEN(a)
Definition: utils.h:666
void ast_replace_subargument_delimiter(char *s)
Replace '^' in a string with ','.
Definition: utils.c:2343
#define AST_FLAGS_ALL
Definition: utils.h:196