· 9 years ago · Jan 14, 2017, 12:20 PM
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 1999 - 2006, 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 * \arg Config in \ref Config_qu queues.conf
26 *
27 * \par Development notes
28 * \note 2004-11-25: Persistent Dynamic Members added by:
29 * NetNation Communications (www.netnation.com)
30 * Kevin Lindsay <kevinl@netnation.com>
31 *
32 * Each dynamic agent in each queue is now stored in the astdb.
33 * When asterisk is restarted, each agent will be automatically
34 * readded into their recorded queues. This feature can be
35 * configured with the 'persistent_members=<1|0>' setting in the
36 * '[general]' category in queues.conf. The default is on.
37 *
38 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
39 *
40 * \note These features added by David C. Troy <dave@toad.net>:
41 * - Per-queue holdtime calculation
42 * - Estimated holdtime announcement
43 * - Position announcement
44 * - Abandoned/completed call counters
45 * - Failout timer passed as optional app parameter
46 * - Optional monitoring of calls, started when call is answered
47 *
48 * Patch Version 1.07 2003-12-24 01
49 *
50 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
52 *
53 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54 * by Matthew Enger <m.enger@xi.com.au>
55 *
56 * \ingroup applications
57 */
58
59/*** MODULEINFO
60 <use type="module">res_monitor</use>
61 <support_level>core</support_level>
62 ***/
63
64#include "asterisk.h"
65
66ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
67
68#include <sys/time.h>
69#include <sys/signal.h>
70#include <netinet/in.h>
71#include <ctype.h>
72
73#include "asterisk/lock.h"
74#include "asterisk/file.h"
75#include "asterisk/channel.h"
76#include "asterisk/pbx.h"
77#include "asterisk/app.h"
78#include "asterisk/linkedlists.h"
79#include "asterisk/module.h"
80#include "asterisk/translate.h"
81#include "asterisk/say.h"
82#include "asterisk/features.h"
83#include "asterisk/musiconhold.h"
84#include "asterisk/cli.h"
85#include "asterisk/manager.h"
86#include "asterisk/config.h"
87#include "asterisk/monitor.h"
88#include "asterisk/utils.h"
89#include "asterisk/causes.h"
90#include "asterisk/astdb.h"
91#include "asterisk/devicestate.h"
92#include "asterisk/stringfields.h"
93#include "asterisk/event.h"
94#include "asterisk/astobj2.h"
95#include "asterisk/strings.h"
96#include "asterisk/global_datastores.h"
97#include "asterisk/taskprocessor.h"
98#include "asterisk/aoc.h"
99#include "asterisk/callerid.h"
100#include "asterisk/cel.h"
101#include "asterisk/data.h"
102
103/*!
104 * \par Please read before modifying this file.
105 * There are three locks which are regularly used
106 * throughout this file, the queue list lock, the lock
107 * for each individual queue, and the interface list lock.
108 * Please be extra careful to always lock in the following order
109 * 1) queue list lock
110 * 2) individual queue lock
111 * 3) interface list lock
112 * This order has sort of "evolved" over the lifetime of this
113 * application, but it is now in place this way, so please adhere
114 * to this order!
115 */
116
117/*** DOCUMENTATION
118 <application name="Queue" language="en_US">
119 <synopsis>
120 Queue a call for a call queue.
121 </synopsis>
122 <syntax>
123 <parameter name="queuename" required="true" />
124 <parameter name="options">
125 <optionlist>
126 <option name="C">
127 <para>Mark all calls as "answered elsewhere" when cancelled.</para>
128 </option>
129 <option name="c">
130 <para>Continue in the dialplan if the callee hangs up.</para>
131 </option>
132 <option name="d">
133 <para>data-quality (modem) call (minimum delay).</para>
134 </option>
135 <option name="F" argsep="^">
136 <argument name="context" required="false" />
137 <argument name="exten" required="false" />
138 <argument name="priority" required="true" />
139 <para>When the caller hangs up, transfer the <emphasis>called member</emphasis>
140 to the specified destination and <emphasis>start</emphasis> execution at that location.</para>
141 <note>
142 <para>Any channel variables you want the called channel to inherit from the caller channel must be
143 prefixed with one or two underbars ('_').</para>
144 </note>
145 </option>
146 <option name="F">
147 <para>When the caller hangs up, transfer the <emphasis>called member</emphasis> to the next priority of
148 the current extension and <emphasis>start</emphasis> execution at that location.</para>
149 <note>
150 <para>Any channel variables you want the called channel to inherit from the caller channel must be
151 prefixed with one or two underbars ('_').</para>
152 </note>
153 <note>
154 <para>Using this option from a Macro() or GoSub() might not make sense as there would be no return points.</para>
155 </note>
156 </option>
157 <option name="h">
158 <para>Allow <emphasis>callee</emphasis> to hang up by pressing <literal>*</literal>.</para>
159 </option>
160 <option name="H">
161 <para>Allow <emphasis>caller</emphasis> to hang up by pressing <literal>*</literal>.</para>
162 </option>
163 <option name="n">
164 <para>No retries on the timeout; will exit this application and
165 go to the next step.</para>
166 </option>
167 <option name="i">
168 <para>Ignore call forward requests from queue members and do nothing
169 when they are requested.</para>
170 </option>
171 <option name="I">
172 <para>Asterisk will ignore any connected line update requests or any redirecting party
173 update requests it may receive on this dial attempt.</para>
174 </option>
175 <option name="r">
176 <para>Ring instead of playing MOH. Periodic Announcements are still made, if applicable.</para>
177 </option>
178 <option name="R">
179 <para>Ring instead of playing MOH when a member channel is actually ringing.</para>
180 </option>
181 <option name="t">
182 <para>Allow the <emphasis>called</emphasis> user to transfer the calling user.</para>
183 </option>
184 <option name="T">
185 <para>Allow the <emphasis>calling</emphasis> user to transfer the call.</para>
186 </option>
187 <option name="w">
188 <para>Allow the <emphasis>called</emphasis> user to write the conversation to
189 disk via Monitor.</para>
190 </option>
191 <option name="W">
192 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
193 disk via Monitor.</para>
194 </option>
195 <option name="k">
196 <para>Allow the <emphasis>called</emphasis> party to enable parking of the call by sending
197 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
198 </option>
199 <option name="K">
200 <para>Allow the <emphasis>calling</emphasis> party to enable parking of the call by sending
201 the DTMF sequence defined for call parking in <filename>features.conf</filename>.</para>
202 </option>
203 <option name="x">
204 <para>Allow the <emphasis>called</emphasis> user to write the conversation
205 to disk via MixMonitor.</para>
206 </option>
207 <option name="X">
208 <para>Allow the <emphasis>calling</emphasis> user to write the conversation to
209 disk via MixMonitor.</para>
210 </option>
211 </optionlist>
212 </parameter>
213 <parameter name="URL">
214 <para><replaceable>URL</replaceable> will be sent to the called party if the channel supports it.</para>
215 </parameter>
216 <parameter name="announceoverride" />
217 <parameter name="timeout">
218 <para>Will cause the queue to fail out after a specified number of
219 seconds, checked between each <filename>queues.conf</filename> <replaceable>timeout</replaceable> and
220 <replaceable>retry</replaceable> cycle.</para>
221 </parameter>
222 <parameter name="AGI">
223 <para>Will setup an AGI script to be executed on the calling party's channel once they are
224 connected to a queue member.</para>
225 </parameter>
226 <parameter name="macro">
227 <para>Will run a macro on the called party's channel (the queue member) once the parties are connected.</para>
228 </parameter>
229 <parameter name="gosub">
230 <para>Will run a gosub on the called party's channel (the queue member) once the parties are connected.</para>
231 </parameter>
232 <parameter name="rule">
233 <para>Will cause the queue's defaultrule to be overridden by the rule specified.</para>
234 </parameter>
235 <parameter name="position">
236 <para>Attempt to enter the caller into the queue at the numerical position specified. <literal>1</literal>
237 would attempt to enter the caller at the head of the queue, and <literal>3</literal> would attempt to place
238 the caller third in the queue.</para>
239 </parameter>
240 </syntax>
241 <description>
242 <para>In addition to transferring the call, a call may be parked and then picked
243 up by another user.</para>
244 <para>This application will return to the dialplan if the queue does not exist, or
245 any of the join options cause the caller to not enter the queue.</para>
246 <para>This application does not automatically answer and should be preceeded
247 by an application such as Answer(), Progress(), or Ringing().</para>
248 <para>This application sets the following channel variable upon completion:</para>
249 <variablelist>
250 <variable name="QUEUESTATUS">
251 <para>The status of the call as a text string.</para>
252 <value name="TIMEOUT" />
253 <value name="FULL" />
254 <value name="JOINEMPTY" />
255 <value name="LEAVEEMPTY" />
256 <value name="JOINUNAVAIL" />
257 <value name="LEAVEUNAVAIL" />
258 <value name="CONTINUE" />
259 </variable>
260 </variablelist>
261 </description>
262 <see-also>
263 <ref type="application">Queue</ref>
264 <ref type="application">QueueLog</ref>
265 <ref type="application">AddQueueMember</ref>
266 <ref type="application">RemoveQueueMember</ref>
267 <ref type="application">PauseQueueMember</ref>
268 <ref type="application">UnpauseQueueMember</ref>
269 <ref type="function">QUEUE_VARIABLES</ref>
270 <ref type="function">QUEUE_MEMBER</ref>
271 <ref type="function">QUEUE_MEMBER_COUNT</ref>
272 <ref type="function">QUEUE_EXISTS</ref>
273 <ref type="function">QUEUE_WAITING_COUNT</ref>
274 <ref type="function">QUEUE_MEMBER_LIST</ref>
275 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
276 </see-also>
277 </application>
278 <application name="AddQueueMember" language="en_US">
279 <synopsis>
280 Dynamically adds queue members.
281 </synopsis>
282 <syntax>
283 <parameter name="queuename" required="true" />
284 <parameter name="interface" />
285 <parameter name="penalty" />
286 <parameter name="options" />
287 <parameter name="membername" />
288 <parameter name="stateinterface" />
289 </syntax>
290 <description>
291 <para>Dynamically adds interface to an existing queue. If the interface is
292 already in the queue it will return an error.</para>
293 <para>This application sets the following channel variable upon completion:</para>
294 <variablelist>
295 <variable name="AQMSTATUS">
296 <para>The status of the attempt to add a queue member as a text string.</para>
297 <value name="ADDED" />
298 <value name="MEMBERALREADY" />
299 <value name="NOSUCHQUEUE" />
300 </variable>
301 </variablelist>
302 </description>
303 <see-also>
304 <ref type="application">Queue</ref>
305 <ref type="application">QueueLog</ref>
306 <ref type="application">AddQueueMember</ref>
307 <ref type="application">RemoveQueueMember</ref>
308 <ref type="application">PauseQueueMember</ref>
309 <ref type="application">UnpauseQueueMember</ref>
310 <ref type="function">QUEUE_VARIABLES</ref>
311 <ref type="function">QUEUE_MEMBER</ref>
312 <ref type="function">QUEUE_MEMBER_COUNT</ref>
313 <ref type="function">QUEUE_EXISTS</ref>
314 <ref type="function">QUEUE_WAITING_COUNT</ref>
315 <ref type="function">QUEUE_MEMBER_LIST</ref>
316 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
317 </see-also>
318 </application>
319 <application name="RemoveQueueMember" language="en_US">
320 <synopsis>
321 Dynamically removes queue members.
322 </synopsis>
323 <syntax>
324 <parameter name="queuename" required="true" />
325 <parameter name="interface" />
326 </syntax>
327 <description>
328 <para>If the interface is <emphasis>NOT</emphasis> in the queue it will return an error.</para>
329 <para>This application sets the following channel variable upon completion:</para>
330 <variablelist>
331 <variable name="RQMSTATUS">
332 <value name="REMOVED" />
333 <value name="NOTINQUEUE" />
334 <value name="NOSUCHQUEUE" />
335 <value name="NOTDYNAMIC" />
336 </variable>
337 </variablelist>
338 <para>Example: RemoveQueueMember(techsupport,SIP/3000)</para>
339 </description>
340 <see-also>
341 <ref type="application">Queue</ref>
342 <ref type="application">QueueLog</ref>
343 <ref type="application">AddQueueMember</ref>
344 <ref type="application">RemoveQueueMember</ref>
345 <ref type="application">PauseQueueMember</ref>
346 <ref type="application">UnpauseQueueMember</ref>
347 <ref type="function">QUEUE_VARIABLES</ref>
348 <ref type="function">QUEUE_MEMBER</ref>
349 <ref type="function">QUEUE_MEMBER_COUNT</ref>
350 <ref type="function">QUEUE_EXISTS</ref>
351 <ref type="function">QUEUE_WAITING_COUNT</ref>
352 <ref type="function">QUEUE_MEMBER_LIST</ref>
353 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
354 </see-also>
355 </application>
356 <application name="PauseQueueMember" language="en_US">
357 <synopsis>
358 Pauses a queue member.
359 </synopsis>
360 <syntax>
361 <parameter name="queuename" />
362 <parameter name="interface" required="true" />
363 <parameter name="options" />
364 <parameter name="reason">
365 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
366 </parameter>
367 </syntax>
368 <description>
369 <para>Pauses (blocks calls for) a queue member. The given interface will be paused in the given queue.
370 This prevents any calls from being sent from the queue to the interface until it is
371 unpaused with UnpauseQueueMember or the manager interface. If no queuename is given,
372 the interface is paused in every queue it is a member of. The application will fail if the
373 interface is not found.</para>
374 <para>This application sets the following channel variable upon completion:</para>
375 <variablelist>
376 <variable name="PQMSTATUS">
377 <para>The status of the attempt to pause a queue member as a text string.</para>
378 <value name="PAUSED" />
379 <value name="NOTFOUND" />
380 </variable>
381 </variablelist>
382 <para>Example: PauseQueueMember(,SIP/3000)</para>
383 </description>
384 <see-also>
385 <ref type="application">Queue</ref>
386 <ref type="application">QueueLog</ref>
387 <ref type="application">AddQueueMember</ref>
388 <ref type="application">RemoveQueueMember</ref>
389 <ref type="application">PauseQueueMember</ref>
390 <ref type="application">UnpauseQueueMember</ref>
391 <ref type="function">QUEUE_VARIABLES</ref>
392 <ref type="function">QUEUE_MEMBER</ref>
393 <ref type="function">QUEUE_MEMBER_COUNT</ref>
394 <ref type="function">QUEUE_EXISTS</ref>
395 <ref type="function">QUEUE_WAITING_COUNT</ref>
396 <ref type="function">QUEUE_MEMBER_LIST</ref>
397 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
398 </see-also>
399 </application>
400 <application name="UnpauseQueueMember" language="en_US">
401 <synopsis>
402 Unpauses a queue member.
403 </synopsis>
404 <syntax>
405 <parameter name="queuename" />
406 <parameter name="interface" required="true" />
407 <parameter name="options" />
408 <parameter name="reason">
409 <para>Is used to add extra information to the appropriate queue_log entries and manager events.</para>
410 </parameter>
411 </syntax>
412 <description>
413 <para>Unpauses (resumes calls to) a queue member. This is the counterpart to <literal>PauseQueueMember()</literal>
414 and operates exactly the same way, except it unpauses instead of pausing the given interface.</para>
415 <para>This application sets the following channel variable upon completion:</para>
416 <variablelist>
417 <variable name="UPQMSTATUS">
418 <para>The status of the attempt to unpause a queue member as a text string.</para>
419 <value name="UNPAUSED" />
420 <value name="NOTFOUND" />
421 </variable>
422 </variablelist>
423 <para>Example: UnpauseQueueMember(,SIP/3000)</para>
424 </description>
425 <see-also>
426 <ref type="application">Queue</ref>
427 <ref type="application">QueueLog</ref>
428 <ref type="application">AddQueueMember</ref>
429 <ref type="application">RemoveQueueMember</ref>
430 <ref type="application">PauseQueueMember</ref>
431 <ref type="application">UnpauseQueueMember</ref>
432 <ref type="function">QUEUE_VARIABLES</ref>
433 <ref type="function">QUEUE_MEMBER</ref>
434 <ref type="function">QUEUE_MEMBER_COUNT</ref>
435 <ref type="function">QUEUE_EXISTS</ref>
436 <ref type="function">QUEUE_WAITING_COUNT</ref>
437 <ref type="function">QUEUE_MEMBER_LIST</ref>
438 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
439 </see-also>
440 </application>
441 <application name="QueueLog" language="en_US">
442 <synopsis>
443 Writes to the queue_log file.
444 </synopsis>
445 <syntax>
446 <parameter name="queuename" required="true" />
447 <parameter name="uniqueid" required="true" />
448 <parameter name="agent" required="true" />
449 <parameter name="event" required="true" />
450 <parameter name="additionalinfo" />
451 </syntax>
452 <description>
453 <para>Allows you to write your own events into the queue log.</para>
454 <para>Example: QueueLog(101,${UNIQUEID},${AGENT},WENTONBREAK,600)</para>
455 </description>
456 <see-also>
457 <ref type="application">Queue</ref>
458 <ref type="application">QueueLog</ref>
459 <ref type="application">AddQueueMember</ref>
460 <ref type="application">RemoveQueueMember</ref>
461 <ref type="application">PauseQueueMember</ref>
462 <ref type="application">UnpauseQueueMember</ref>
463 <ref type="function">QUEUE_VARIABLES</ref>
464 <ref type="function">QUEUE_MEMBER</ref>
465 <ref type="function">QUEUE_MEMBER_COUNT</ref>
466 <ref type="function">QUEUE_EXISTS</ref>
467 <ref type="function">QUEUE_WAITING_COUNT</ref>
468 <ref type="function">QUEUE_MEMBER_LIST</ref>
469 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
470 </see-also>
471 </application>
472 <function name="QUEUE_VARIABLES" language="en_US">
473 <synopsis>
474 Return Queue information in variables.
475 </synopsis>
476 <syntax>
477 <parameter name="queuename" required="true">
478 <enumlist>
479 <enum name="QUEUEMAX">
480 <para>Maxmimum number of calls allowed.</para>
481 </enum>
482 <enum name="QUEUESTRATEGY">
483 <para>The strategy of the queue.</para>
484 </enum>
485 <enum name="QUEUECALLS">
486 <para>Number of calls currently in the queue.</para>
487 </enum>
488 <enum name="QUEUEHOLDTIME">
489 <para>Current average hold time.</para>
490 </enum>
491 <enum name="QUEUECOMPLETED">
492 <para>Number of completed calls for the queue.</para>
493 </enum>
494 <enum name="QUEUEABANDONED">
495 <para>Number of abandoned calls.</para>
496 </enum>
497 <enum name="QUEUESRVLEVEL">
498 <para>Queue service level.</para>
499 </enum>
500 <enum name="QUEUESRVLEVELPERF">
501 <para>Current service level performance.</para>
502 </enum>
503 </enumlist>
504 </parameter>
505 </syntax>
506 <description>
507 <para>Makes the following queue variables available.</para>
508 <para>Returns <literal>0</literal> if queue is found and setqueuevar is defined, <literal>-1</literal> otherwise.</para>
509 </description>
510 <see-also>
511 <ref type="application">Queue</ref>
512 <ref type="application">QueueLog</ref>
513 <ref type="application">AddQueueMember</ref>
514 <ref type="application">RemoveQueueMember</ref>
515 <ref type="application">PauseQueueMember</ref>
516 <ref type="application">UnpauseQueueMember</ref>
517 <ref type="function">QUEUE_VARIABLES</ref>
518 <ref type="function">QUEUE_MEMBER</ref>
519 <ref type="function">QUEUE_MEMBER_COUNT</ref>
520 <ref type="function">QUEUE_EXISTS</ref>
521 <ref type="function">QUEUE_WAITING_COUNT</ref>
522 <ref type="function">QUEUE_MEMBER_LIST</ref>
523 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
524 </see-also>
525 </function>
526 <function name="QUEUE_MEMBER" language="en_US">
527 <synopsis>
528 Count number of members answering a queue.
529 </synopsis>
530 <syntax>
531 <parameter name="queuename" required="false" />
532 <parameter name="option" required="true">
533 <enumlist>
534 <enum name="logged">
535 <para>Returns the number of logged-in members for the specified queue.</para>
536 </enum>
537 <enum name="free">
538 <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>
539 </enum>
540 <enum name="ready">
541 <para>Returns the number of logged-in members for the specified queue that are immediately available to answer a call.</para>
542 </enum>
543 <enum name="count">
544 <para>Returns the total number of members for the specified queue.</para>
545 </enum>
546 <enum name="penalty">
547 <para>Gets or sets queue member penalty. If
548 <replaceable>queuename</replaceable> is not specified
549 when setting the penalty then the penalty is set in all queues
550 the interface is a member.</para>
551 </enum>
552 <enum name="paused">
553 <para>Gets or sets queue member paused status. If
554 <replaceable>queuename</replaceable> is not specified
555 when setting the paused status then the paused status is set
556 in all queues the interface is a member.</para>
557 </enum>
558 <enum name="ringinuse">
559 <para>Gets or sets queue member ringinuse. If
560 <replaceable>queuename</replaceable> is not specified
561 when setting ringinuse then ringinuse is set
562 in all queues the interface is a member.</para>
563 </enum>
564 </enumlist>
565 </parameter>
566 <parameter name="interface" required="false" />
567 </syntax>
568 <description>
569 <para>Allows access to queue counts [R] and member information [R/W].</para>
570 <para><replaceable>queuename</replaceable> is required for all read operations.</para>
571 <para><replaceable>interface</replaceable> is required for all member operations.</para>
572 </description>
573 <see-also>
574 <ref type="application">Queue</ref>
575 <ref type="application">QueueLog</ref>
576 <ref type="application">AddQueueMember</ref>
577 <ref type="application">RemoveQueueMember</ref>
578 <ref type="application">PauseQueueMember</ref>
579 <ref type="application">UnpauseQueueMember</ref>
580 <ref type="function">QUEUE_VARIABLES</ref>
581 <ref type="function">QUEUE_MEMBER</ref>
582 <ref type="function">QUEUE_MEMBER_COUNT</ref>
583 <ref type="function">QUEUE_EXISTS</ref>
584 <ref type="function">QUEUE_WAITING_COUNT</ref>
585 <ref type="function">QUEUE_MEMBER_LIST</ref>
586 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
587 </see-also>
588 </function>
589 <function name="QUEUE_MEMBER_COUNT" language="en_US">
590 <synopsis>
591 Count number of members answering a queue.
592 </synopsis>
593 <syntax>
594 <parameter name="queuename" required="true" />
595 </syntax>
596 <description>
597 <para>Returns the number of members currently associated with the specified <replaceable>queuename</replaceable>.</para>
598 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
599 </description>
600 <see-also>
601 <ref type="application">Queue</ref>
602 <ref type="application">QueueLog</ref>
603 <ref type="application">AddQueueMember</ref>
604 <ref type="application">RemoveQueueMember</ref>
605 <ref type="application">PauseQueueMember</ref>
606 <ref type="application">UnpauseQueueMember</ref>
607 <ref type="function">QUEUE_VARIABLES</ref>
608 <ref type="function">QUEUE_MEMBER</ref>
609 <ref type="function">QUEUE_MEMBER_COUNT</ref>
610 <ref type="function">QUEUE_EXISTS</ref>
611 <ref type="function">QUEUE_WAITING_COUNT</ref>
612 <ref type="function">QUEUE_MEMBER_LIST</ref>
613 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
614 </see-also>
615 </function>
616 <function name="QUEUE_EXISTS" language="en_US">
617 <synopsis>
618 Check if a named queue exists on this server
619 </synopsis>
620 <syntax>
621 <parameter name="queuename" />
622 </syntax>
623 <description>
624 <para>Returns 1 if the specified queue exists, 0 if it does not</para>
625 </description>
626 <see-also>
627 <ref type="application">Queue</ref>
628 <ref type="application">QueueLog</ref>
629 <ref type="application">AddQueueMember</ref>
630 <ref type="application">RemoveQueueMember</ref>
631 <ref type="application">PauseQueueMember</ref>
632 <ref type="application">UnpauseQueueMember</ref>
633 <ref type="function">QUEUE_VARIABLES</ref>
634 <ref type="function">QUEUE_MEMBER</ref>
635 <ref type="function">QUEUE_MEMBER_COUNT</ref>
636 <ref type="function">QUEUE_EXISTS</ref>
637 <ref type="function">QUEUE_WAITING_COUNT</ref>
638 <ref type="function">QUEUE_MEMBER_LIST</ref>
639 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
640 </see-also>
641 </function>
642 <function name="QUEUE_WAITING_COUNT" language="en_US">
643 <synopsis>
644 Count number of calls currently waiting in a queue.
645 </synopsis>
646 <syntax>
647 <parameter name="queuename" />
648 </syntax>
649 <description>
650 <para>Returns the number of callers currently waiting in the specified <replaceable>queuename</replaceable>.</para>
651 </description>
652 <see-also>
653 <ref type="application">Queue</ref>
654 <ref type="application">QueueLog</ref>
655 <ref type="application">AddQueueMember</ref>
656 <ref type="application">RemoveQueueMember</ref>
657 <ref type="application">PauseQueueMember</ref>
658 <ref type="application">UnpauseQueueMember</ref>
659 <ref type="function">QUEUE_VARIABLES</ref>
660 <ref type="function">QUEUE_MEMBER</ref>
661 <ref type="function">QUEUE_MEMBER_COUNT</ref>
662 <ref type="function">QUEUE_EXISTS</ref>
663 <ref type="function">QUEUE_WAITING_COUNT</ref>
664 <ref type="function">QUEUE_MEMBER_LIST</ref>
665 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
666 </see-also>
667 </function>
668 <function name="QUEUE_MEMBER_LIST" language="en_US">
669 <synopsis>
670 Returns a list of interfaces on a queue.
671 </synopsis>
672 <syntax>
673 <parameter name="queuename" required="true" />
674 </syntax>
675 <description>
676 <para>Returns a comma-separated list of members associated with the specified <replaceable>queuename</replaceable>.</para>
677 </description>
678 <see-also>
679 <ref type="application">Queue</ref>
680 <ref type="application">QueueLog</ref>
681 <ref type="application">AddQueueMember</ref>
682 <ref type="application">RemoveQueueMember</ref>
683 <ref type="application">PauseQueueMember</ref>
684 <ref type="application">UnpauseQueueMember</ref>
685 <ref type="function">QUEUE_VARIABLES</ref>
686 <ref type="function">QUEUE_MEMBER</ref>
687 <ref type="function">QUEUE_MEMBER_COUNT</ref>
688 <ref type="function">QUEUE_EXISTS</ref>
689 <ref type="function">QUEUE_WAITING_COUNT</ref>
690 <ref type="function">QUEUE_MEMBER_LIST</ref>
691 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
692 </see-also>
693 </function>
694 <function name="QUEUE_MEMBER_PENALTY" language="en_US">
695 <synopsis>
696 Gets or sets queue members penalty.
697 </synopsis>
698 <syntax>
699 <parameter name="queuename" required="true" />
700 <parameter name="interface" required="true" />
701 </syntax>
702 <description>
703 <para>Gets or sets queue members penalty.</para>
704 <warning><para>This function has been deprecated in favor of the <literal>QUEUE_MEMBER()</literal> function</para></warning>
705 </description>
706 <see-also>
707 <ref type="application">Queue</ref>
708 <ref type="application">QueueLog</ref>
709 <ref type="application">AddQueueMember</ref>
710 <ref type="application">RemoveQueueMember</ref>
711 <ref type="application">PauseQueueMember</ref>
712 <ref type="application">UnpauseQueueMember</ref>
713 <ref type="function">QUEUE_VARIABLES</ref>
714 <ref type="function">QUEUE_MEMBER</ref>
715 <ref type="function">QUEUE_MEMBER_COUNT</ref>
716 <ref type="function">QUEUE_EXISTS</ref>
717 <ref type="function">QUEUE_WAITING_COUNT</ref>
718 <ref type="function">QUEUE_MEMBER_LIST</ref>
719 <ref type="function">QUEUE_MEMBER_PENALTY</ref>
720 </see-also>
721 </function>
722 <manager name="Queues" language="en_US">
723 <synopsis>
724 Queues.
725 </synopsis>
726 <syntax>
727 </syntax>
728 <description>
729 <para>Show queues information.</para>
730 </description>
731 </manager>
732 <manager name="QueueStatus" language="en_US">
733 <synopsis>
734 Show queue status.
735 </synopsis>
736 <syntax>
737 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
738 <parameter name="Queue">
739 <para>Limit the response to the status of the specified queue.</para>
740 </parameter>
741 <parameter name="Member">
742 <para>Limit the response to the status of the specified member.</para>
743 </parameter>
744 </syntax>
745 <description>
746 <para>Check the status of one or more queues.</para>
747 </description>
748 </manager>
749 <manager name="QueueSummary" language="en_US">
750 <synopsis>
751 Show queue summary.
752 </synopsis>
753 <syntax>
754 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
755 <parameter name="Queue">
756 <para>Queue for which the summary is requested.</para>
757 </parameter>
758 </syntax>
759 <description>
760 <para>Request the manager to send a QueueSummary event.</para>
761 </description>
762 </manager>
763 <manager name="QueueAdd" language="en_US">
764 <synopsis>
765 Add interface to queue.
766 </synopsis>
767 <syntax>
768 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
769 <parameter name="Queue" required="true">
770 <para>Queue's name.</para>
771 </parameter>
772 <parameter name="Interface" required="true">
773 <para>The name of the interface (tech/name) to add to the queue.</para>
774 </parameter>
775 <parameter name="Penalty">
776 <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>
777 </parameter>
778 <parameter name="Paused">
779 <para>To pause or not the member initially (true/false or 1/0).</para>
780 </parameter>
781 <parameter name="MemberName">
782 <para>Text alias for the interface.</para>
783 </parameter>
784 <parameter name="StateInterface" />
785 </syntax>
786 <description>
787 </description>
788 </manager>
789 <manager name="QueueRemove" language="en_US">
790 <synopsis>
791 Remove interface from queue.
792 </synopsis>
793 <syntax>
794 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
795 <parameter name="Queue" required="true">
796 <para>The name of the queue to take action on.</para>
797 </parameter>
798 <parameter name="Interface" required="true">
799 <para>The interface (tech/name) to remove from queue.</para>
800 </parameter>
801 </syntax>
802 <description>
803 </description>
804 </manager>
805 <manager name="QueuePause" language="en_US">
806 <synopsis>
807 Makes a queue member temporarily unavailable.
808 </synopsis>
809 <syntax>
810 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
811 <parameter name="Interface" required="true">
812 <para>The name of the interface (tech/name) to pause or unpause.</para>
813 </parameter>
814 <parameter name="Paused" required="true">
815 <para>Pause or unpause the interface. Set to 'true' to pause the member or 'false' to unpause.</para>
816 </parameter>
817 <parameter name="Queue">
818 <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>
819 </parameter>
820 <parameter name="Reason">
821 <para>Text description, returned in the event QueueMemberPaused.</para>
822 </parameter>
823 </syntax>
824 <description>
825 <para>Pause or unpause a member in a queue.</para>
826 </description>
827 </manager>
828 <manager name="QueueLog" language="en_US">
829 <synopsis>
830 Adds custom entry in queue_log.
831 </synopsis>
832 <syntax>
833 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
834 <parameter name="Queue" required="true" />
835 <parameter name="Event" required="true" />
836 <parameter name="Uniqueid" />
837 <parameter name="Interface" />
838 <parameter name="Message" />
839 </syntax>
840 <description>
841 </description>
842 </manager>
843 <manager name="QueuePenalty" language="en_US">
844 <synopsis>
845 Set the penalty for a queue member.
846 </synopsis>
847 <syntax>
848 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
849 <parameter name="Interface" required="true">
850 <para>The interface (tech/name) of the member whose penalty to change.</para>
851 </parameter>
852 <parameter name="Penalty" required="true">
853 <para>The new penalty (number) for the member. Must be nonnegative.</para>
854 </parameter>
855 <parameter name="Queue">
856 <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>
857 </parameter>
858 </syntax>
859 <description>
860 <para>Change the penalty of a queue member</para>
861 </description>
862 </manager>
863
864 <manager name="QueueMemberRingInUse" language="en_US">
865 <synopsis>
866 Set the ringinuse value for a queue member.
867 </synopsis>
868 <syntax>
869 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
870 <parameter name="Interface" required="true" />
871 <parameter name="RingInUse" required="true" />
872 <parameter name="Queue" />
873 </syntax>
874 <description>
875 </description>
876 </manager>
877
878 <manager name="QueueRule" language="en_US">
879 <synopsis>
880 Queue Rules.
881 </synopsis>
882 <syntax>
883 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
884 <parameter name="Rule">
885 <para>The name of the rule in queuerules.conf whose contents to list.</para>
886 </parameter>
887 </syntax>
888 <description>
889 <para>List queue rules defined in queuerules.conf</para>
890 </description>
891 </manager>
892 <manager name="QueueReload" language="en_US">
893 <synopsis>
894 Reload a queue, queues, or any sub-section of a queue or queues.
895 </synopsis>
896 <syntax>
897 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
898 <parameter name="Queue">
899 <para>The name of the queue to take action on. If no queue name is specified, then all queues are affected.</para>
900 </parameter>
901 <parameter name="Members">
902 <para>Whether to reload the queue's members.</para>
903 <enumlist>
904 <enum name="yes" />
905 <enum name="no" />
906 </enumlist>
907 </parameter>
908 <parameter name="Rules">
909 <para>Whether to reload queuerules.conf</para>
910 <enumlist>
911 <enum name="yes" />
912 <enum name="no" />
913 </enumlist>
914 </parameter>
915 <parameter name="Parameters">
916 <para>Whether to reload the other queue options.</para>
917 <enumlist>
918 <enum name="yes" />
919 <enum name="no" />
920 </enumlist>
921 </parameter>
922 </syntax>
923 <description>
924 </description>
925 </manager>
926 <manager name="QueueReset" language="en_US">
927 <synopsis>
928 Reset queue statistics.
929 </synopsis>
930 <syntax>
931 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
932 <parameter name="Queue">
933 <para>The name of the queue on which to reset statistics.</para>
934 </parameter>
935 </syntax>
936 <description>
937 <para>Reset the statistics for a queue.</para>
938 </description>
939 </manager>
940 ***/
941
942enum {
943 OPT_MARK_AS_ANSWERED = (1 << 0),
944 OPT_GO_ON = (1 << 1),
945 OPT_DATA_QUALITY = (1 << 2),
946 OPT_CALLEE_GO_ON = (1 << 3),
947 OPT_CALLEE_HANGUP = (1 << 4),
948 OPT_CALLER_HANGUP = (1 << 5),
949 OPT_IGNORE_CALL_FW = (1 << 6),
950 OPT_IGNORE_CONNECTEDLINE = (1 << 7),
951 OPT_CALLEE_PARK = (1 << 8),
952 OPT_CALLER_PARK = (1 << 9),
953 OPT_NO_RETRY = (1 << 10),
954 OPT_RINGING = (1 << 11),
955 OPT_RING_WHEN_RINGING = (1 << 12),
956 OPT_CALLEE_TRANSFER = (1 << 13),
957 OPT_CALLER_TRANSFER = (1 << 14),
958 OPT_CALLEE_AUTOMIXMON = (1 << 15),
959 OPT_CALLER_AUTOMIXMON = (1 << 16),
960 OPT_CALLEE_AUTOMON = (1 << 17),
961 OPT_CALLER_AUTOMON = (1 << 18),
962};
963
964enum {
965 OPT_ARG_CALLEE_GO_ON = 0,
966 /* note: this entry _MUST_ be the last one in the enum */
967 OPT_ARG_ARRAY_SIZE
968};
969
970AST_APP_OPTIONS(queue_exec_options, BEGIN_OPTIONS
971 AST_APP_OPTION('C', OPT_MARK_AS_ANSWERED),
972 AST_APP_OPTION('c', OPT_GO_ON),
973 AST_APP_OPTION('d', OPT_DATA_QUALITY),
974 AST_APP_OPTION_ARG('F', OPT_CALLEE_GO_ON, OPT_ARG_CALLEE_GO_ON),
975 AST_APP_OPTION('h', OPT_CALLEE_HANGUP),
976 AST_APP_OPTION('H', OPT_CALLER_HANGUP),
977 AST_APP_OPTION('i', OPT_IGNORE_CALL_FW),
978 AST_APP_OPTION('I', OPT_IGNORE_CONNECTEDLINE),
979 AST_APP_OPTION('k', OPT_CALLEE_PARK),
980 AST_APP_OPTION('K', OPT_CALLER_PARK),
981 AST_APP_OPTION('n', OPT_NO_RETRY),
982 AST_APP_OPTION('r', OPT_RINGING),
983 AST_APP_OPTION('R', OPT_RING_WHEN_RINGING),
984 AST_APP_OPTION('t', OPT_CALLEE_TRANSFER),
985 AST_APP_OPTION('T', OPT_CALLER_TRANSFER),
986 AST_APP_OPTION('x', OPT_CALLEE_AUTOMIXMON),
987 AST_APP_OPTION('X', OPT_CALLER_AUTOMIXMON),
988 AST_APP_OPTION('w', OPT_CALLEE_AUTOMON),
989 AST_APP_OPTION('W', OPT_CALLER_AUTOMON),
990END_OPTIONS);
991
992enum {
993 QUEUE_STRATEGY_RINGALL = 0,
994 QUEUE_STRATEGY_LEASTRECENT,
995 QUEUE_STRATEGY_FEWESTCALLS,
996 QUEUE_STRATEGY_RANDOM,
997 QUEUE_STRATEGY_RRMEMORY,
998 QUEUE_STRATEGY_LINEAR,
999 QUEUE_STRATEGY_WRANDOM,
1000 QUEUE_STRATEGY_RRORDERED,
1001};
1002
1003enum {
1004 QUEUE_AUTOPAUSE_OFF = 0,
1005 QUEUE_AUTOPAUSE_ON,
1006 QUEUE_AUTOPAUSE_ALL
1007};
1008
1009enum queue_reload_mask {
1010 QUEUE_RELOAD_PARAMETERS = (1 << 0),
1011 QUEUE_RELOAD_MEMBER = (1 << 1),
1012 QUEUE_RELOAD_RULES = (1 << 2),
1013 QUEUE_RESET_STATS = (1 << 3),
1014};
1015
1016static const struct strategy {
1017 int strategy;
1018 const char *name;
1019} strategies[] = {
1020 { QUEUE_STRATEGY_RINGALL, "ringall" },
1021 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
1022 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
1023 { QUEUE_STRATEGY_RANDOM, "random" },
1024 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
1025 { QUEUE_STRATEGY_RRMEMORY, "roundrobin" },
1026 { QUEUE_STRATEGY_LINEAR, "linear" },
1027 { QUEUE_STRATEGY_WRANDOM, "wrandom"},
1028 { QUEUE_STRATEGY_RRORDERED, "rrordered"},
1029};
1030
1031static const struct autopause {
1032 int autopause;
1033 const char *name;
1034} autopausesmodes [] = {
1035 { QUEUE_AUTOPAUSE_OFF,"no" },
1036 { QUEUE_AUTOPAUSE_ON, "yes" },
1037 { QUEUE_AUTOPAUSE_ALL,"all" },
1038};
1039
1040
1041static struct ast_taskprocessor *devicestate_tps;
1042
1043#define DEFAULT_RETRY 5
1044#define DEFAULT_TIMEOUT 15
1045#define RECHECK 1 /*!< Recheck every second to see we we're at the top yet */
1046#define MAX_PERIODIC_ANNOUNCEMENTS 10 /*!< The maximum periodic announcements we can have */
1047#define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /*!< The minimum number of seconds between position announcements \
1048 The default value of 15 provides backwards compatibility */
1049#define MAX_QUEUE_BUCKETS 53
1050
1051#define RES_OKAY 0 /*!< Action completed */
1052#define RES_EXISTS (-1) /*!< Entry already exists */
1053#define RES_OUTOFMEMORY (-2) /*!< Out of memory */
1054#define RES_NOSUCHQUEUE (-3) /*!< No such queue */
1055#define RES_NOT_DYNAMIC (-4) /*!< Member is not dynamic */
1056
1057static char *app = "Queue";
1058
1059static char *app_aqm = "AddQueueMember" ;
1060
1061static char *app_rqm = "RemoveQueueMember" ;
1062
1063static char *app_pqm = "PauseQueueMember" ;
1064
1065static char *app_upqm = "UnpauseQueueMember" ;
1066
1067static char *app_ql = "QueueLog" ;
1068
1069/*! \brief Persistent Members astdb family */
1070static const char * const pm_family = "Queue/PersistentMembers";
1071
1072/*! \brief queues.conf [general] option */
1073static int queue_persistent_members = 0;
1074
1075/*! \brief queues.conf per-queue weight option */
1076static int use_weight = 0;
1077
1078/*! \brief queues.conf [general] option */
1079static int autofill_default = 1;
1080
1081/*! \brief queues.conf [general] option */
1082static int montype_default = 0;
1083
1084/*! \brief queues.conf [general] option */
1085static int shared_lastcall = 1;
1086
1087/*! \brief Subscription to device state change events */
1088static struct ast_event_sub *device_state_sub;
1089
1090/*! \brief queues.conf [general] option */
1091static int update_cdr = 0;
1092
1093/*! \brief queues.conf [general] option */
1094static int negative_penalty_invalid = 0;
1095
1096/*! \brief queues.conf [general] option */
1097static int log_membername_as_agent = 0;
1098
1099/*! \brief name of the ringinuse field in the realtime database */
1100static char *realtime_ringinuse_field;
1101
1102enum queue_result {
1103 QUEUE_UNKNOWN = 0,
1104 QUEUE_TIMEOUT = 1,
1105 QUEUE_JOINEMPTY = 2,
1106 QUEUE_LEAVEEMPTY = 3,
1107 QUEUE_JOINUNAVAIL = 4,
1108 QUEUE_LEAVEUNAVAIL = 5,
1109 QUEUE_FULL = 6,
1110 QUEUE_CONTINUE = 7,
1111};
1112
1113static const struct {
1114 enum queue_result id;
1115 char *text;
1116} queue_results[] = {
1117 { QUEUE_UNKNOWN, "UNKNOWN" },
1118 { QUEUE_TIMEOUT, "TIMEOUT" },
1119 { QUEUE_JOINEMPTY,"JOINEMPTY" },
1120 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
1121 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
1122 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
1123 { QUEUE_FULL, "FULL" },
1124 { QUEUE_CONTINUE, "CONTINUE" },
1125};
1126
1127enum queue_timeout_priority {
1128 TIMEOUT_PRIORITY_APP,
1129 TIMEOUT_PRIORITY_CONF,
1130};
1131
1132/*! \brief We define a custom "local user" structure because we
1133 * use it not only for keeping track of what is in use but
1134 * also for keeping track of who we're dialing.
1135 *
1136 * There are two "links" defined in this structure, q_next and call_next.
1137 * q_next links ALL defined callattempt structures into a linked list. call_next is
1138 * a link which allows for a subset of the callattempts to be traversed. This subset
1139 * is used in wait_for_answer so that irrelevant callattempts are not traversed. This
1140 * also is helpful so that queue logs are always accurate in the case where a call to
1141 * a member times out, especially if using the ringall strategy.
1142*/
1143
1144struct callattempt {
1145 struct callattempt *q_next;
1146 struct callattempt *call_next;
1147 struct ast_channel *chan;
1148 char interface[256]; /*!< An Asterisk dial string (not a channel name) */
1149 int metric;
1150 time_t lastcall;
1151 struct call_queue *lastqueue;
1152 struct member *member;
1153 /*! Saved connected party info from an AST_CONTROL_CONNECTED_LINE. */
1154 struct ast_party_connected_line connected;
1155 /*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
1156 unsigned int pending_connected_update:1;
1157 /*! TRUE if the connected line update is blocked. */
1158 unsigned int block_connected_update:1;
1159 /*! TRUE if caller id is not available for connected line */
1160 unsigned int dial_callerid_absent:1;
1161 /*! TRUE if the call is still active */
1162 unsigned int stillgoing:1;
1163 struct ast_aoc_decoded *aoc_s_rate_list;
1164};
1165
1166
1167struct queue_ent {
1168 struct call_queue *parent; /*!< What queue is our parent */
1169 char moh[MAX_MUSICCLASS]; /*!< Name of musiconhold to be used */
1170 char announce[PATH_MAX]; /*!< Announcement to play for member when call is answered */
1171 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
1172 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
1173 int valid_digits; /*!< Digits entered correspond to valid extension. Exited */
1174 int pos; /*!< Where we are in the queue */
1175 int prio; /*!< Our priority */
1176 int last_pos_said; /*!< Last position we told the user */
1177 int ring_when_ringing; /*!< Should we only use ring indication when a channel is ringing? */
1178 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
1179 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
1180 time_t last_pos; /*!< Last time we told the user their position */
1181 int opos; /*!< Where we started in the queue */
1182 int handled; /*!< Whether our call was handled */
1183 int pending; /*!< Non-zero if we are attempting to call a member */
1184 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
1185 int min_penalty; /*!< Limit the members that can take this call to this penalty or higher */
1186 int linpos; /*!< If using linear strategy, what position are we at? */
1187 int linwrapped; /*!< Is the linpos wrapped? */
1188 time_t start; /*!< When we started holding */
1189 time_t expire; /*!< When this entry should expire (time out of queue) */
1190 int cancel_answered_elsewhere; /*!< Whether we should force the CAE flag on this call (C) option*/
1191 struct ast_channel *chan; /*!< Our channel */
1192 AST_LIST_HEAD_NOLOCK(,penalty_rule) qe_rules; /*!< Local copy of the queue's penalty rules */
1193 struct penalty_rule *pr; /*!< Pointer to the next penalty rule to implement */
1194 struct queue_ent *next; /*!< The next queue entry */
1195};
1196
1197struct member {
1198 char interface[AST_CHANNEL_NAME]; /*!< Technology/Location to dial to reach this member*/
1199 char state_exten[AST_MAX_EXTENSION]; /*!< Extension to get state from (if using hint) */
1200 char state_context[AST_MAX_CONTEXT]; /*!< Context to use when getting state (if using hint) */
1201 char state_interface[AST_CHANNEL_NAME]; /*!< Technology/Location from which to read devicestate changes */
1202 char membername[80]; /*!< Member name to use in queue logs */
1203 int penalty; /*!< Are we a last resort? */
1204 int calls; /*!< Number of calls serviced by this member */
1205 int dynamic; /*!< Are we dynamically added? */
1206 int realtime; /*!< Is this member realtime? */
1207 int status; /*!< Status of queue member */
1208 int paused; /*!< Are we paused (not accepting calls)? */
1209 int queuepos; /*!< In what order (pertains to certain strategies) should this member be called? */
1210 time_t lastcall; /*!< When last successful call was hungup */
1211 unsigned int in_call:1; /*!< True if member is still in call. (so lastcall is not actual) */
1212 struct call_queue *lastqueue; /*!< Last queue we received a call */
1213 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
1214 unsigned int delme:1; /*!< Flag to delete entry on reload */
1215 char rt_uniqueid[80]; /*!< Unique id of realtime member entry */
1216 unsigned int ringinuse:1; /*!< Flag to ring queue members even if their status is 'inuse' */
1217};
1218
1219enum empty_conditions {
1220 QUEUE_EMPTY_PENALTY = (1 << 0),
1221 QUEUE_EMPTY_PAUSED = (1 << 1),
1222 QUEUE_EMPTY_INUSE = (1 << 2),
1223 QUEUE_EMPTY_RINGING = (1 << 3),
1224 QUEUE_EMPTY_UNAVAILABLE = (1 << 4),
1225 QUEUE_EMPTY_INVALID = (1 << 5),
1226 QUEUE_EMPTY_UNKNOWN = (1 << 6),
1227 QUEUE_EMPTY_WRAPUP = (1 << 7),
1228};
1229
1230enum member_properties {
1231 MEMBER_PENALTY = 0,
1232 MEMBER_RINGINUSE = 1,
1233};
1234
1235/* values used in multi-bit flags in call_queue */
1236#define ANNOUNCEHOLDTIME_ALWAYS 1
1237#define ANNOUNCEHOLDTIME_ONCE 2
1238#define QUEUE_EVENT_VARIABLES 3
1239
1240struct penalty_rule {
1241 int time; /*!< Number of seconds that need to pass before applying this rule */
1242 int max_value; /*!< The amount specified in the penalty rule for max penalty */
1243 int min_value; /*!< The amount specified in the penalty rule for min penalty */
1244 int max_relative; /*!< Is the max adjustment relative? 1 for relative, 0 for absolute */
1245 int min_relative; /*!< Is the min adjustment relative? 1 for relative, 0 for absolute */
1246 AST_LIST_ENTRY(penalty_rule) list; /*!< Next penalty_rule */
1247};
1248
1249#define ANNOUNCEPOSITION_YES 1 /*!< We announce position */
1250#define ANNOUNCEPOSITION_NO 2 /*!< We don't announce position */
1251#define ANNOUNCEPOSITION_MORE_THAN 3 /*!< We say "Currently there are more than <limit>" */
1252#define ANNOUNCEPOSITION_LIMIT 4 /*!< We not announce position more than <limit> */
1253
1254struct call_queue {
1255 AST_DECLARE_STRING_FIELDS(
1256 /*! Queue name */
1257 AST_STRING_FIELD(name);
1258 /*! Music on Hold class */
1259 AST_STRING_FIELD(moh);
1260 /*! Announcement to play when call is answered */
1261 AST_STRING_FIELD(announce);
1262 /*! Exit context */
1263 AST_STRING_FIELD(context);
1264 /*! Macro to run upon member connection */
1265 AST_STRING_FIELD(membermacro);
1266 /*! Gosub to run upon member connection */
1267 AST_STRING_FIELD(membergosub);
1268 /*! Default rule to use if none specified in call to Queue() */
1269 AST_STRING_FIELD(defaultrule);
1270 /*! Sound file: "Your call is now first in line" (def. queue-youarenext) */
1271 AST_STRING_FIELD(sound_next);
1272 /*! Sound file: "There are currently" (def. queue-thereare) */
1273 AST_STRING_FIELD(sound_thereare);
1274 /*! Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting) */
1275 AST_STRING_FIELD(sound_calls);
1276 /*! Sound file: "Currently there are more than" (def. queue-quantity1) */
1277 AST_STRING_FIELD(queue_quantity1);
1278 /*! Sound file: "callers waiting to speak with a representative" (def. queue-quantity2) */
1279 AST_STRING_FIELD(queue_quantity2);
1280 /*! Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
1281 AST_STRING_FIELD(sound_holdtime);
1282 /*! Sound file: "minutes." (def. queue-minutes) */
1283 AST_STRING_FIELD(sound_minutes);
1284 /*! Sound file: "minute." (def. queue-minute) */
1285 AST_STRING_FIELD(sound_minute);
1286 /*! Sound file: "seconds." (def. queue-seconds) */
1287 AST_STRING_FIELD(sound_seconds);
1288 /*! Sound file: "Thank you for your patience." (def. queue-thankyou) */
1289 AST_STRING_FIELD(sound_thanks);
1290 /*! Sound file: Custom announce for caller, no default */
1291 AST_STRING_FIELD(sound_callerannounce);
1292 /*! Sound file: "Hold time" (def. queue-reporthold) */
1293 AST_STRING_FIELD(sound_reporthold);
1294 );
1295 /*! Sound files: Custom announce, no default */
1296 struct ast_str *sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS];
1297 unsigned int dead:1;
1298 unsigned int eventwhencalled:2;
1299 unsigned int ringinuse:1;
1300 unsigned int announce_to_first_user:1; /*!< Whether or not we announce to the first user in a queue */
1301 unsigned int setinterfacevar:1;
1302 unsigned int setqueuevar:1;
1303 unsigned int setqueueentryvar:1;
1304 unsigned int reportholdtime:1;
1305 unsigned int wrapped:1;
1306 unsigned int timeoutrestart:1;
1307 unsigned int announceholdtime:2;
1308 unsigned int announceposition:3;
1309 int strategy:4;
1310 unsigned int maskmemberstatus:1;
1311 unsigned int realtime:1;
1312 unsigned int found:1;
1313 unsigned int relativeperiodicannounce:1;
1314 unsigned int autopausebusy:1;
1315 unsigned int autopauseunavail:1;
1316 enum empty_conditions joinempty;
1317 enum empty_conditions leavewhenempty;
1318 int announcepositionlimit; /*!< How many positions we announce? */
1319 int announcefrequency; /*!< How often to announce their position */
1320 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
1321 int periodicannouncefrequency; /*!< How often to play periodic announcement */
1322 int numperiodicannounce; /*!< The number of periodic announcements configured */
1323 int randomperiodicannounce; /*!< Are periodic announcments randomly chosen */
1324 int roundingseconds; /*!< How many seconds do we round to? */
1325 int holdtime; /*!< Current avg holdtime, based on an exponential average */
1326 int talktime; /*!< Current avg talktime, based on the same exponential average */
1327 int callscompleted; /*!< Number of queue calls completed */
1328 int callsabandoned; /*!< Number of queue calls abandoned */
1329 int servicelevel; /*!< seconds setting for servicelevel*/
1330 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
1331 char monfmt[8]; /*!< Format to use when recording calls */
1332 int montype; /*!< Monitor type Monitor vs. MixMonitor */
1333 int count; /*!< How many entries */
1334 int maxlen; /*!< Max number of entries */
1335 int wrapuptime; /*!< Wrapup Time */
1336 int penaltymemberslimit; /*!< Disregard penalty when queue has fewer than this many members */
1337
1338 int retry; /*!< Retry calling everyone after this amount of time */
1339 int timeout; /*!< How long to wait for an answer */
1340 int weight; /*!< Respective weight */
1341 int autopause; /*!< Auto pause queue members if they fail to answer */
1342 int autopausedelay; /*!< Delay auto pause for autopausedelay seconds since last call */
1343 int timeoutpriority; /*!< Do we allow a fraction of the timeout to occur for a ring? */
1344
1345 /* Queue strategy things */
1346 int rrpos; /*!< Round Robin - position */
1347 int memberdelay; /*!< Seconds to delay connecting member to caller */
1348 int autofill; /*!< Ignore the head call status and ring an available agent */
1349
1350 struct ao2_container *members; /*!< Head of the list of members */
1351 struct queue_ent *head; /*!< Head of the list of callers */
1352 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
1353 AST_LIST_HEAD_NOLOCK(, penalty_rule) rules; /*!< The list of penalty rules to invoke */
1354};
1355
1356struct rule_list {
1357 char name[80];
1358 AST_LIST_HEAD_NOLOCK(,penalty_rule) rules;
1359 AST_LIST_ENTRY(rule_list) list;
1360};
1361
1362static AST_LIST_HEAD_STATIC(rule_lists, rule_list);
1363
1364static struct ao2_container *queues;
1365
1366static void update_realtime_members(struct call_queue *q);
1367static struct member *interface_exists(struct call_queue *q, const char *interface);
1368static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
1369
1370static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
1371
1372static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface);
1373/*! \brief sets the QUEUESTATUS channel variable */
1374static void set_queue_result(struct ast_channel *chan, enum queue_result res)
1375{
1376 int i;
1377
1378 for (i = 0; i < ARRAY_LEN(queue_results); i++) {
1379 if (queue_results[i].id == res) {
1380 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
1381 return;
1382 }
1383 }
1384}
1385
1386static const char *int2strat(int strategy)
1387{
1388 int x;
1389
1390 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1391 if (strategy == strategies[x].strategy) {
1392 return strategies[x].name;
1393 }
1394 }
1395
1396 return "<unknown>";
1397}
1398
1399static int strat2int(const char *strategy)
1400{
1401 int x;
1402
1403 for (x = 0; x < ARRAY_LEN(strategies); x++) {
1404 if (!strcasecmp(strategy, strategies[x].name)) {
1405 return strategies[x].strategy;
1406 }
1407 }
1408
1409 return -1;
1410}
1411
1412static int autopause2int(const char *autopause)
1413{
1414 int x;
1415 /*This 'double check' that default value is OFF */
1416 if (ast_strlen_zero(autopause)) {
1417 return QUEUE_AUTOPAUSE_OFF;
1418 }
1419
1420 /*This 'double check' is to ensure old values works */
1421 if(ast_true(autopause)) {
1422 return QUEUE_AUTOPAUSE_ON;
1423 }
1424
1425 for (x = 0; x < ARRAY_LEN(autopausesmodes); x++) {
1426 if (!strcasecmp(autopause, autopausesmodes[x].name)) {
1427 return autopausesmodes[x].autopause;
1428 }
1429 }
1430
1431 /*This 'double check' that default value is OFF */
1432 return QUEUE_AUTOPAUSE_OFF;
1433}
1434
1435static int queue_hash_cb(const void *obj, const int flags)
1436{
1437 const struct call_queue *q = obj;
1438
1439 return ast_str_case_hash(q->name);
1440}
1441
1442static int queue_cmp_cb(void *obj, void *arg, int flags)
1443{
1444 struct call_queue *q = obj, *q2 = arg;
1445 return !strcasecmp(q->name, q2->name) ? CMP_MATCH | CMP_STOP : 0;
1446}
1447
1448/*! \internal
1449 * \brief ao2_callback, Decreases queuepos of all followers with a queuepos greater than arg.
1450 * \param obj the member being acted on
1451 * \param arg pointer to an integer containing the position value that was removed and requires reduction for anything above
1452 */
1453static int queue_member_decrement_followers(void *obj, void *arg, int flag)
1454{
1455 struct member *mem = obj;
1456 int *decrement_followers_after = arg;
1457
1458 if (mem->queuepos > *decrement_followers_after) {
1459 mem->queuepos--;
1460 }
1461
1462 return 0;
1463}
1464
1465/*! \internal
1466 * \brief ao2_callback, finds members in a queue marked for deletion and in a cascading fashion runs queue_member_decrement_followers
1467 * on them. This callback should always be ran before performing mass unlinking of delmarked members from queues.
1468 * \param obj member being acted on
1469 * \param arg pointer to the queue members are being removed from
1470 */
1471static int queue_delme_members_decrement_followers(void *obj, void *arg, int flag)
1472{
1473 struct member *mem = obj;
1474 struct call_queue *queue = arg;
1475 int rrpos = mem->queuepos;
1476
1477 if (mem->delme) {
1478 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &rrpos);
1479 }
1480
1481 return 0;
1482}
1483
1484/*! \internal
1485 * \brief Use this to decrement followers during removal of a member
1486 * \param queue which queue the member is being removed from
1487 * \param mem which member is being removed from the queue
1488 */
1489static void queue_member_follower_removal(struct call_queue *queue, struct member *mem)
1490{
1491 int pos = mem->queuepos;
1492
1493 /* 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
1494 * who would have been next otherwise. */
1495 if (pos < queue->rrpos) {
1496 queue->rrpos--;
1497 }
1498
1499 ao2_callback(queue->members, OBJ_NODATA | OBJ_MULTIPLE, queue_member_decrement_followers, &pos);
1500}
1501
1502#ifdef REF_DEBUG
1503#define queue_ref(q) _queue_ref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
1504#define queue_unref(q) _queue_unref(q, "", __FILE__, __LINE__, __PRETTY_FUNCTION__)
1505#define queue_t_ref(q, tag) _queue_ref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1506#define queue_t_unref(q, tag) _queue_unref(q, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1507#define queues_t_link(c, q, tag) __ao2_link_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1508#define queues_t_unlink(c, q, tag) __ao2_unlink_debug(c, q, 0, tag, __FILE__, __LINE__, __PRETTY_FUNCTION__)
1509
1510static inline struct call_queue *_queue_ref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
1511{
1512 __ao2_ref_debug(q, 1, tag, file, line, filename);
1513 return q;
1514}
1515
1516static inline struct call_queue *_queue_unref(struct call_queue *q, const char *tag, const char *file, int line, const char *filename)
1517{
1518 __ao2_ref_debug(q, -1, tag, file, line, filename);
1519 return NULL;
1520}
1521
1522#else
1523
1524#define queue_t_ref(q, tag) queue_ref(q)
1525#define queue_t_unref(q, tag) queue_unref(q)
1526#define queues_t_link(c, q, tag) ao2_t_link(c, q, tag)
1527#define queues_t_unlink(c, q, tag) ao2_t_unlink(c, q, tag)
1528
1529static inline struct call_queue *queue_ref(struct call_queue *q)
1530{
1531 ao2_ref(q, 1);
1532 return q;
1533}
1534
1535static inline struct call_queue *queue_unref(struct call_queue *q)
1536{
1537 ao2_ref(q, -1);
1538 return NULL;
1539}
1540#endif
1541
1542/*! \brief Set variables of queue */
1543static void set_queue_variables(struct call_queue *q, struct ast_channel *chan)
1544{
1545 char interfacevar[256]="";
1546 float sl = 0;
1547
1548 ao2_lock(q);
1549
1550 if (q->setqueuevar) {
1551 sl = 0;
1552 if (q->callscompleted > 0) {
1553 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
1554 }
1555
1556 snprintf(interfacevar, sizeof(interfacevar),
1557 "QUEUENAME=%s,QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
1558 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
1559
1560 ao2_unlock(q);
1561
1562 pbx_builtin_setvar_multiple(chan, interfacevar);
1563 } else {
1564 ao2_unlock(q);
1565 }
1566}
1567
1568/*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
1569static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
1570{
1571 struct queue_ent *cur;
1572
1573 if (!q || !new)
1574 return;
1575 if (prev) {
1576 cur = prev->next;
1577 prev->next = new;
1578 } else {
1579 cur = q->head;
1580 q->head = new;
1581 }
1582 new->next = cur;
1583
1584 /* every queue_ent must have a reference to it's parent call_queue, this
1585 * reference does not go away until the end of the queue_ent's life, meaning
1586 * that even when the queue_ent leaves the call_queue this ref must remain. */
1587 queue_ref(q);
1588 new->parent = q;
1589 new->pos = ++(*pos);
1590 new->opos = *pos;
1591}
1592
1593/*! \brief Check if members are available
1594 *
1595 * This function checks to see if members are available to be called. If any member
1596 * is available, the function immediately returns 0. If no members are available,
1597 * then -1 is returned.
1598 */
1599static int get_member_status(struct call_queue *q, int max_penalty, int min_penalty, enum empty_conditions conditions, int devstate)
1600{
1601 struct member *member;
1602 struct ao2_iterator mem_iter;
1603
1604 ao2_lock(q);
1605 mem_iter = ao2_iterator_init(q->members, 0);
1606 for (; (member = ao2_iterator_next(&mem_iter)); ao2_ref(member, -1)) {
1607 if ((max_penalty != INT_MAX && member->penalty > max_penalty) || (min_penalty != INT_MAX && member->penalty < min_penalty)) {
1608 if (conditions & QUEUE_EMPTY_PENALTY) {
1609 ast_debug(4, "%s is unavailable because his penalty is not between %d and %d\n", member->membername, min_penalty, max_penalty);
1610 continue;
1611 }
1612 }
1613
1614 switch (devstate ? ast_device_state(member->state_interface) : member->status) {
1615 case AST_DEVICE_INVALID:
1616 if (conditions & QUEUE_EMPTY_INVALID) {
1617 ast_debug(4, "%s is unavailable because his device state is 'invalid'\n", member->membername);
1618 break;
1619 }
1620 goto default_case;
1621 case AST_DEVICE_UNAVAILABLE:
1622 if (conditions & QUEUE_EMPTY_UNAVAILABLE) {
1623 ast_debug(4, "%s is unavailable because his device state is 'unavailable'\n", member->membername);
1624 break;
1625 }
1626 goto default_case;
1627 case AST_DEVICE_INUSE:
1628 if (conditions & QUEUE_EMPTY_INUSE) {
1629 ast_debug(4, "%s is unavailable because his device state is 'inuse'\n", member->membername);
1630 break;
1631 }
1632 goto default_case;
1633 case AST_DEVICE_RINGING:
1634 if (conditions & QUEUE_EMPTY_RINGING) {
1635 ast_debug(4, "%s is unavailable because his device state is 'ringing'\n", member->membername);
1636 break;
1637 }
1638 goto default_case;
1639 case AST_DEVICE_UNKNOWN:
1640 if (conditions & QUEUE_EMPTY_UNKNOWN) {
1641 ast_debug(4, "%s is unavailable because his device state is 'unknown'\n", member->membername);
1642 break;
1643 }
1644 /* Fall-through */
1645 default:
1646 default_case:
1647 if (member->paused && (conditions & QUEUE_EMPTY_PAUSED)) {
1648 ast_debug(4, "%s is unavailable because he is paused'\n", member->membername);
1649 break;
1650 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->in_call && q->wrapuptime) {
1651 ast_debug(4, "%s is unavailable because still in call, so we can`t check "
1652 "wrapuptime (%d)\n", member->membername, q->wrapuptime);
1653 break;
1654 } else if ((conditions & QUEUE_EMPTY_WRAPUP) && member->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < member->lastcall)) {
1655 ast_debug(4, "%s is unavailable because it has only been %d seconds since his last call (wrapup time is %d)\n", member->membername, (int) (time(NULL) - member->lastcall), q->wrapuptime);
1656 break;
1657 } else {
1658 ao2_ref(member, -1);
1659 ao2_iterator_destroy(&mem_iter);
1660 ao2_unlock(q);
1661 ast_debug(4, "%s is available.\n", member->membername);
1662 return 0;
1663 }
1664 break;
1665 }
1666 }
1667 ao2_iterator_destroy(&mem_iter);
1668 ao2_unlock(q);
1669
1670 if (!devstate && (conditions & QUEUE_EMPTY_RINGING)) {
1671 /* member state still may be RINGING due to lag in event message - check again with device state */
1672 return get_member_status(q, max_penalty, min_penalty, conditions, 1);
1673 }
1674 return -1;
1675}
1676
1677/*
1678 * A "pool" of member objects that calls are currently pending on. If an
1679 * agent is a member of multiple queues it's possible for that agent to be
1680 * called by each of the queues at the same time. This happens because device
1681 * state is slow to notify the queue app of one of it's member's being rung.
1682 * This "pool" allows us to track which members are currently being rung while
1683 * we wait on the device state change.
1684 */
1685static struct ao2_container *pending_members;
1686#define MAX_CALL_ATTEMPT_BUCKETS 353
1687
1688static int pending_members_hash(const void *obj, const int flags)
1689{
1690 const struct member *object = obj;
1691 const char *key = (flags & OBJ_KEY) ? obj : object->interface;
1692 return ast_str_case_hash(key);
1693}
1694
1695static int pending_members_cmp(void *obj, void *arg, int flags)
1696{
1697 const struct member *object_left = obj;
1698 const struct member *object_right = arg;
1699 const char *right_key = (flags & OBJ_KEY) ? arg : object_right->interface;
1700
1701 return strcasecmp(object_left->interface, right_key) ? 0 : CMP_MATCH;
1702}
1703
1704static void pending_members_remove(struct member *mem)
1705{
1706 ao2_find(pending_members, mem, OBJ_POINTER | OBJ_NODATA | OBJ_UNLINK);
1707}
1708
1709struct statechange {
1710 AST_LIST_ENTRY(statechange) entry;
1711 int state;
1712 char dev[0];
1713};
1714
1715/*! \brief set a member's status based on device state of that member's state_interface.
1716 *
1717 * Lock interface list find sc, iterate through each queues queue_member list for member to
1718 * update state inside queues
1719*/
1720static int update_status(struct call_queue *q, struct member *m, const int status)
1721{
1722 if (m->status != status) {
1723 m->status = status;
1724
1725 /* Remove the member from the pending members pool only when the status changes.
1726 * This is not done unconditionally because we can occasionally see multiple
1727 * device state notifications of not in use after a previous call has ended,
1728 * including after we have initiated a new call. This is more likely to
1729 * happen when there is latency in the connection to the member.
1730 */
1731 pending_members_remove(m);
1732 }
1733
1734 if (q->maskmemberstatus) {
1735 return 0;
1736 }
1737
1738 /*** DOCUMENTATION
1739 <managerEventInstance>
1740 <synopsis>Raised when a Queue member's status has changed.</synopsis>
1741 <syntax>
1742 <parameter name="Queue">
1743 <para>The name of the queue.</para>
1744 </parameter>
1745 <parameter name="Location">
1746 <para>The queue member's channel technology or location.</para>
1747 </parameter>
1748 <parameter name="MemberName">
1749 <para>The name of the queue member.</para>
1750 </parameter>
1751 <parameter name="StateInterface">
1752 <para>Channel technology or location from which to read device state changes.</para>
1753 </parameter>
1754 <parameter name="Membership">
1755 <enumlist>
1756 <enum name="dynamic"/>
1757 <enum name="realtime"/>
1758 <enum name="static"/>
1759 </enumlist>
1760 </parameter>
1761 <parameter name="Penalty">
1762 <para>The penalty associated with the queue member.</para>
1763 </parameter>
1764 <parameter name="CallsTaken">
1765 <para>The number of calls this queue member has serviced.</para>
1766 </parameter>
1767 <parameter name="LastCall">
1768 <para>The time this member last took call, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
1769 </parameter>
1770 <parameter name="InCall">
1771 <para>Set to 1 if member is in call. Set to 0 after LastCall time is updated.</para>
1772 <enumlist>
1773 <enum name="0"/>
1774 <enum name="1"/>
1775 </enumlist>
1776 </parameter>
1777 <parameter name="Status">
1778 <para>The numeric device state status of the queue member.</para>
1779 <enumlist>
1780 <enum name="0"><para>AST_DEVICE_UNKNOWN</para></enum>
1781 <enum name="1"><para>AST_DEVICE_NOT_INUSE</para></enum>
1782 <enum name="2"><para>AST_DEVICE_INUSE</para></enum>
1783 <enum name="3"><para>AST_DEVICE_BUSY</para></enum>
1784 <enum name="4"><para>AST_DEVICE_INVALID</para></enum>
1785 <enum name="5"><para>AST_DEVICE_UNAVAILABLE</para></enum>
1786 <enum name="6"><para>AST_DEVICE_RINGING</para></enum>
1787 <enum name="7"><para>AST_DEVICE_RINGINUSE</para></enum>
1788 <enum name="8"><para>AST_DEVICE_ONHOLD</para></enum>
1789 </enumlist>
1790 </parameter>
1791 <parameter name="Paused">
1792 <enumlist>
1793 <enum name="0"/>
1794 <enum name="1"/>
1795 </enumlist>
1796 </parameter>
1797 </syntax>
1798 </managerEventInstance>
1799 ***/
1800 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1801 "Queue: %s\r\n"
1802 "Location: %s\r\n"
1803 "MemberName: %s\r\n"
1804 "StateInterface: %s\r\n"
1805 "Membership: %s\r\n"
1806 "Penalty: %d\r\n"
1807 "CallsTaken: %d\r\n"
1808 "LastCall: %d\r\n"
1809 "InCall: %d\r\n"
1810 "Status: %d\r\n"
1811 "Paused: %d\r\n",
1812 q->name, m->interface, m->membername, m->state_interface, m->dynamic ? "dynamic" : m->realtime ? "realtime" : "static",
1813 m->penalty, m->calls, (int)m->lastcall, m->in_call, m->status, m->paused
1814 );
1815
1816 return 0;
1817}
1818
1819/*!
1820 * \internal \brief Determine if a queue member is available
1821 * \retval 1 if the member is available
1822 * \retval 0 if the member is not available
1823 */
1824static int is_member_available(struct call_queue *q, struct member *mem)
1825{
1826 int available = 0;
1827
1828 switch (mem->status) {
1829 case AST_DEVICE_INVALID:
1830 case AST_DEVICE_UNAVAILABLE:
1831 break;
1832 case AST_DEVICE_INUSE:
1833 case AST_DEVICE_BUSY:
1834 case AST_DEVICE_RINGING:
1835 case AST_DEVICE_RINGINUSE:
1836 case AST_DEVICE_ONHOLD:
1837 if (!mem->ringinuse) {
1838 break;
1839 }
1840 /* else fall through */
1841 case AST_DEVICE_NOT_INUSE:
1842 case AST_DEVICE_UNKNOWN:
1843 if (!mem->paused) {
1844 available = 1;
1845 }
1846 break;
1847 }
1848
1849 /* Let wrapuptimes override device state availability */
1850 if (q->wrapuptime && mem->in_call) {
1851 available = 0; /* member is still in call, cant check wrapuptime to lastcall time */
1852 }
1853 if (mem->lastcall && q->wrapuptime && (time(NULL) - q->wrapuptime < mem->lastcall)) {
1854 available = 0;
1855 }
1856 return available;
1857}
1858
1859/*! \brief set a member's status based on device state of that member's interface*/
1860static int handle_statechange(void *datap)
1861{
1862 struct statechange *sc = datap;
1863 struct ao2_iterator miter, qiter;
1864 struct member *m;
1865 struct call_queue *q;
1866 char interface[80], *slash_pos;
1867 int found = 0; /* Found this member in any queue */
1868 int found_member; /* Found this member in this queue */
1869 int avail = 0; /* Found an available member in this queue */
1870
1871 qiter = ao2_iterator_init(queues, 0);
1872 while ((q = ao2_t_iterator_next(&qiter, "Iterate over queues"))) {
1873 ao2_lock(q);
1874
1875 avail = 0;
1876 found_member = 0;
1877 miter = ao2_iterator_init(q->members, 0);
1878 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
1879 if (!found_member) {
1880 ast_copy_string(interface, m->state_interface, sizeof(interface));
1881
1882 if ((slash_pos = strchr(interface, '/'))) {
1883 if (!strncasecmp(interface, "Local/", 6) && (slash_pos = strchr(slash_pos + 1, '/'))) {
1884 *slash_pos = '\0';
1885 }
1886 }
1887
1888 if (!strcasecmp(interface, sc->dev)) {
1889 found_member = 1;
1890 update_status(q, m, sc->state);
1891 }
1892 }
1893
1894 /* check every member until we find one NOT_INUSE */
1895 if (!avail) {
1896 avail = is_member_available(q, m);
1897 }
1898 if (avail && found_member) {
1899 /* early exit as we've found an available member and the member of interest */
1900 ao2_ref(m, -1);
1901 break;
1902 }
1903 }
1904
1905 if (found_member) {
1906 found = 1;
1907 if (avail) {
1908 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
1909 } else {
1910 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
1911 }
1912 }
1913
1914 ao2_iterator_destroy(&miter);
1915
1916 ao2_unlock(q);
1917 queue_t_unref(q, "Done with iterator");
1918 }
1919 ao2_iterator_destroy(&qiter);
1920
1921 if (found) {
1922 ast_debug(1, "Device '%s' changed to state '%d' (%s)\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1923 } else {
1924 ast_debug(3, "Device '%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", sc->dev, sc->state, ast_devstate2str(sc->state));
1925 }
1926
1927 ast_free(sc);
1928 return 0;
1929}
1930
1931static void device_state_cb(const struct ast_event *event, void *unused)
1932{
1933 enum ast_device_state state;
1934 const char *device;
1935 struct statechange *sc;
1936 size_t datapsize;
1937
1938 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
1939 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
1940
1941 if (ast_strlen_zero(device)) {
1942 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
1943 return;
1944 }
1945 datapsize = sizeof(*sc) + strlen(device) + 1;
1946 if (!(sc = ast_calloc(1, datapsize))) {
1947 ast_log(LOG_ERROR, "failed to calloc a state change struct\n");
1948 return;
1949 }
1950 sc->state = state;
1951 strcpy(sc->dev, device);
1952 if (ast_taskprocessor_push(devicestate_tps, handle_statechange, sc) < 0) {
1953 ast_free(sc);
1954 }
1955}
1956
1957/*! \brief Helper function which converts from extension state to device state values */
1958static int extensionstate2devicestate(int state)
1959{
1960 switch (state) {
1961 case AST_EXTENSION_NOT_INUSE:
1962 state = AST_DEVICE_NOT_INUSE;
1963 break;
1964 case AST_EXTENSION_INUSE:
1965 state = AST_DEVICE_INUSE;
1966 break;
1967 case AST_EXTENSION_BUSY:
1968 state = AST_DEVICE_BUSY;
1969 break;
1970 case AST_EXTENSION_RINGING:
1971 state = AST_DEVICE_RINGING;
1972 break;
1973 case AST_EXTENSION_ONHOLD:
1974 state = AST_DEVICE_ONHOLD;
1975 break;
1976 case AST_EXTENSION_UNAVAILABLE:
1977 state = AST_DEVICE_UNAVAILABLE;
1978 break;
1979 case AST_EXTENSION_REMOVED:
1980 case AST_EXTENSION_DEACTIVATED:
1981 default:
1982 state = AST_DEVICE_INVALID;
1983 break;
1984 }
1985
1986 return state;
1987}
1988
1989static int extension_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
1990{
1991 struct ao2_iterator miter, qiter;
1992 struct member *m;
1993 struct call_queue *q;
1994 int state = info->exten_state;
1995 int found = 0, device_state = extensionstate2devicestate(state);
1996
1997 /* only interested in extension state updates involving device states */
1998 if (info->reason != AST_HINT_UPDATE_DEVICE) {
1999 return 0;
2000 }
2001
2002 qiter = ao2_iterator_init(queues, 0);
2003 while ((q = ao2_t_iterator_next(&qiter, "Iterate through queues"))) {
2004 ao2_lock(q);
2005
2006 miter = ao2_iterator_init(q->members, 0);
2007 for (; (m = ao2_iterator_next(&miter)); ao2_ref(m, -1)) {
2008 if (!strcmp(m->state_context, context) && !strcmp(m->state_exten, exten)) {
2009 update_status(q, m, device_state);
2010 ao2_ref(m, -1);
2011 found = 1;
2012 break;
2013 }
2014 }
2015 ao2_iterator_destroy(&miter);
2016
2017 ao2_unlock(q);
2018 queue_t_unref(q, "Done with iterator");
2019 }
2020 ao2_iterator_destroy(&qiter);
2021
2022 if (found) {
2023 ast_debug(1, "Extension '%s@%s' changed to state '%d' (%s)\n", exten, context, device_state, ast_devstate2str(device_state));
2024 } else {
2025 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",
2026 exten, context, device_state, ast_devstate2str(device_state));
2027 }
2028
2029 return 0;
2030}
2031
2032/*! \brief Return the current state of a member */
2033static int get_queue_member_status(struct member *cur)
2034{
2035 return ast_strlen_zero(cur->state_exten) ? ast_device_state(cur->state_interface) : extensionstate2devicestate(ast_extension_state(NULL, cur->state_context, cur->state_exten));
2036}
2037
2038/*! \brief allocate space for new queue member and set fields based on parameters passed */
2039static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface, int ringinuse)
2040{
2041 struct member *cur;
2042
2043 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
2044 cur->ringinuse = ringinuse;
2045 cur->penalty = penalty;
2046 cur->paused = paused;
2047 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
2048 if (!ast_strlen_zero(state_interface)) {
2049 ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));
2050 } else {
2051 ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));
2052 }
2053 if (!ast_strlen_zero(membername)) {
2054 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
2055 } else {
2056 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
2057 }
2058 if (!strchr(cur->interface, '/')) {
2059 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
2060 }
2061 if (!strncmp(cur->state_interface, "hint:", 5)) {
2062 char *tmp = ast_strdupa(cur->state_interface), *context = tmp;
2063 char *exten = strsep(&context, "@") + 5;
2064
2065 ast_copy_string(cur->state_exten, exten, sizeof(cur->state_exten));
2066 ast_copy_string(cur->state_context, S_OR(context, "default"), sizeof(cur->state_context));
2067 }
2068 cur->status = get_queue_member_status(cur);
2069 }
2070
2071 return cur;
2072}
2073
2074
2075static int compress_char(const char c)
2076{
2077 if (c < 32) {
2078 return 0;
2079 } else if (c > 96) {
2080 return c - 64;
2081 }
2082 return c - 32;
2083}
2084
2085static int member_hash_fn(const void *obj, const int flags)
2086{
2087 const struct member *mem = obj;
2088 const char *interface = (flags & OBJ_KEY) ? obj : mem->interface;
2089 const char *chname = strchr(interface, '/');
2090 int ret = 0, i;
2091
2092 if (!chname) {
2093 chname = interface;
2094 }
2095 for (i = 0; i < 5 && chname[i]; i++) {
2096 ret += compress_char(chname[i]) << (i * 6);
2097 }
2098 return ret;
2099}
2100
2101static int member_cmp_fn(void *obj1, void *obj2, int flags)
2102{
2103 struct member *mem1 = obj1;
2104 struct member *mem2 = obj2;
2105 const char *interface = (flags & OBJ_KEY) ? obj2 : mem2->interface;
2106
2107 return strcasecmp(mem1->interface, interface) ? 0 : CMP_MATCH | CMP_STOP;
2108}
2109
2110/*!
2111 * \brief Initialize Queue default values.
2112 * \note the queue's lock must be held before executing this function
2113*/
2114static void init_queue(struct call_queue *q)
2115{
2116 int i;
2117 struct penalty_rule *pr_iter;
2118
2119 q->dead = 0;
2120 q->retry = DEFAULT_RETRY;
2121 q->timeout = DEFAULT_TIMEOUT;
2122 q->maxlen = 0;
2123
2124 ast_string_field_set(q, context, "");
2125
2126 q->announcefrequency = 0;
2127 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
2128 q->announceholdtime = 1;
2129 q->announcepositionlimit = 10; /* Default 10 positions */
2130 q->announceposition = ANNOUNCEPOSITION_YES; /* Default yes */
2131 q->roundingseconds = 0; /* Default - don't announce seconds */
2132 q->servicelevel = 0;
2133 q->ringinuse = 1;
2134 q->announce_to_first_user = 0;
2135 q->setinterfacevar = 0;
2136 q->setqueuevar = 0;
2137 q->setqueueentryvar = 0;
2138 q->autofill = autofill_default;
2139 q->montype = montype_default;
2140 q->monfmt[0] = '\0';
2141 q->reportholdtime = 0;
2142 q->wrapuptime = 0;
2143 q->penaltymemberslimit = 0;
2144 q->joinempty = 0;
2145 q->leavewhenempty = 0;
2146 q->memberdelay = 0;
2147 q->maskmemberstatus = 0;
2148 q->eventwhencalled = 0;
2149 q->weight = 0;
2150 q->timeoutrestart = 0;
2151 q->periodicannouncefrequency = 0;
2152 q->randomperiodicannounce = 0;
2153 q->numperiodicannounce = 0;
2154 q->autopause = QUEUE_AUTOPAUSE_OFF;
2155 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
2156 q->autopausedelay = 0;
2157 if (!q->members) {
2158 if (q->strategy == QUEUE_STRATEGY_LINEAR || q->strategy == QUEUE_STRATEGY_RRORDERED) {
2159 /* linear strategy depends on order, so we have to place all members in a single bucket */
2160 q->members = ao2_container_alloc(1, member_hash_fn, member_cmp_fn);
2161 } else {
2162 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
2163 }
2164 }
2165 q->found = 1;
2166
2167 ast_string_field_set(q, sound_next, "queue-youarenext");
2168 ast_string_field_set(q, sound_thereare, "queue-thereare");
2169 ast_string_field_set(q, sound_calls, "queue-callswaiting");
2170 ast_string_field_set(q, queue_quantity1, "queue-quantity1");
2171 ast_string_field_set(q, queue_quantity2, "queue-quantity2");
2172 ast_string_field_set(q, sound_holdtime, "queue-holdtime");
2173 ast_string_field_set(q, sound_minutes, "queue-minutes");
2174 ast_string_field_set(q, sound_minute, "queue-minute");
2175 ast_string_field_set(q, sound_seconds, "queue-seconds");
2176 ast_string_field_set(q, sound_thanks, "queue-thankyou");
2177 ast_string_field_set(q, sound_reporthold, "queue-reporthold");
2178
2179 if (!q->sound_periodicannounce[0]) {
2180 q->sound_periodicannounce[0] = ast_str_create(32);
2181 }
2182
2183 if (q->sound_periodicannounce[0]) {
2184 ast_str_set(&q->sound_periodicannounce[0], 0, "queue-periodic-announce");
2185 }
2186
2187 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
2188 if (q->sound_periodicannounce[i]) {
2189 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", "");
2190 }
2191 }
2192
2193 while ((pr_iter = AST_LIST_REMOVE_HEAD(&q->rules,list))) {
2194 ast_free(pr_iter);
2195 }
2196
2197 /* On restart assume no members are available.
2198 * The queue_avail hint is a boolean state to indicate whether a member is available or not.
2199 *
2200 * This seems counter intuitive, but is required to light a BLF
2201 * AST_DEVICE_INUSE indicates no members are available.
2202 * AST_DEVICE_NOT_INUSE indicates a member is available.
2203 */
2204 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
2205}
2206
2207static void clear_queue(struct call_queue *q)
2208{
2209 q->holdtime = 0;
2210 q->callscompleted = 0;
2211 q->callsabandoned = 0;
2212 q->callscompletedinsl = 0;
2213 q->talktime = 0;
2214
2215 if (q->members) {
2216 struct member *mem;
2217 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
2218 while ((mem = ao2_iterator_next(&mem_iter))) {
2219 mem->calls = 0;
2220 mem->lastcall = 0;
2221 mem->in_call = 0;
2222 ao2_ref(mem, -1);
2223 }
2224 ao2_iterator_destroy(&mem_iter);
2225 }
2226}
2227
2228/*!
2229 * \brief Change queue penalty by adding rule.
2230 *
2231 * Check rule for errors with time or fomatting, see if rule is relative to rest
2232 * of queue, iterate list of rules to find correct insertion point, insert and return.
2233 * \retval -1 on failure
2234 * \retval 0 on success
2235 * \note Call this with the rule_lists locked
2236*/
2237static int insert_penaltychange(const char *list_name, const char *content, const int linenum)
2238{
2239 char *timestr, *maxstr, *minstr, *contentdup;
2240 struct penalty_rule *rule = NULL, *rule_iter;
2241 struct rule_list *rl_iter;
2242 int penaltychangetime, inserted = 0;
2243
2244 if (!(rule = ast_calloc(1, sizeof(*rule)))) {
2245 return -1;
2246 }
2247
2248 contentdup = ast_strdupa(content);
2249
2250 if (!(maxstr = strchr(contentdup, ','))) {
2251 ast_log(LOG_WARNING, "Improperly formatted penaltychange rule at line %d. Ignoring.\n", linenum);
2252 ast_free(rule);
2253 return -1;
2254 }
2255
2256 *maxstr++ = '\0';
2257 timestr = contentdup;
2258
2259 if ((penaltychangetime = atoi(timestr)) < 0) {
2260 ast_log(LOG_WARNING, "Improper time parameter specified for penaltychange rule at line %d. Ignoring.\n", linenum);
2261 ast_free(rule);
2262 return -1;
2263 }
2264
2265 rule->time = penaltychangetime;
2266
2267 if ((minstr = strchr(maxstr,','))) {
2268 *minstr++ = '\0';
2269 }
2270
2271 /* The last check will evaluate true if either no penalty change is indicated for a given rule
2272 * OR if a min penalty change is indicated but no max penalty change is */
2273 if (*maxstr == '+' || *maxstr == '-' || *maxstr == '\0') {
2274 rule->max_relative = 1;
2275 }
2276
2277 rule->max_value = atoi(maxstr);
2278
2279 if (!ast_strlen_zero(minstr)) {
2280 if (*minstr == '+' || *minstr == '-') {
2281 rule->min_relative = 1;
2282 }
2283 rule->min_value = atoi(minstr);
2284 } else { /*there was no minimum specified, so assume this means no change*/
2285 rule->min_relative = 1;
2286 }
2287
2288 /*We have the rule made, now we need to insert it where it belongs*/
2289 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list){
2290 if (strcasecmp(rl_iter->name, list_name)) {
2291 continue;
2292 }
2293
2294 AST_LIST_TRAVERSE_SAFE_BEGIN(&rl_iter->rules, rule_iter, list) {
2295 if (rule->time < rule_iter->time) {
2296 AST_LIST_INSERT_BEFORE_CURRENT(rule, list);
2297 inserted = 1;
2298 break;
2299 }
2300 }
2301 AST_LIST_TRAVERSE_SAFE_END;
2302
2303 if (!inserted) {
2304 AST_LIST_INSERT_TAIL(&rl_iter->rules, rule, list);
2305 inserted = 1;
2306 }
2307
2308 break;
2309 }
2310
2311 if (!inserted) {
2312 ast_log(LOG_WARNING, "Unknown rule list name %s; ignoring.\n", list_name);
2313 ast_free(rule);
2314 return -1;
2315 }
2316 return 0;
2317}
2318
2319static void parse_empty_options(const char *value, enum empty_conditions *empty, int joinempty)
2320{
2321 char *value_copy = ast_strdupa(value);
2322 char *option = NULL;
2323 while ((option = strsep(&value_copy, ","))) {
2324 if (!strcasecmp(option, "paused")) {
2325 *empty |= QUEUE_EMPTY_PAUSED;
2326 } else if (!strcasecmp(option, "penalty")) {
2327 *empty |= QUEUE_EMPTY_PENALTY;
2328 } else if (!strcasecmp(option, "inuse")) {
2329 *empty |= QUEUE_EMPTY_INUSE;
2330 } else if (!strcasecmp(option, "ringing")) {
2331 *empty |= QUEUE_EMPTY_RINGING;
2332 } else if (!strcasecmp(option, "invalid")) {
2333 *empty |= QUEUE_EMPTY_INVALID;
2334 } else if (!strcasecmp(option, "wrapup")) {
2335 *empty |= QUEUE_EMPTY_WRAPUP;
2336 } else if (!strcasecmp(option, "unavailable")) {
2337 *empty |= QUEUE_EMPTY_UNAVAILABLE;
2338 } else if (!strcasecmp(option, "unknown")) {
2339 *empty |= QUEUE_EMPTY_UNKNOWN;
2340 } else if (!strcasecmp(option, "loose")) {
2341 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID);
2342 } else if (!strcasecmp(option, "strict")) {
2343 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED | QUEUE_EMPTY_UNAVAILABLE);
2344 } else if ((ast_false(option) && joinempty) || (ast_true(option) && !joinempty)) {
2345 *empty = (QUEUE_EMPTY_PENALTY | QUEUE_EMPTY_INVALID | QUEUE_EMPTY_PAUSED);
2346 } else if ((ast_false(option) && !joinempty) || (ast_true(option) && joinempty)) {
2347 *empty = 0;
2348 } else {
2349 ast_log(LOG_WARNING, "Unknown option %s for '%s'\n", option, joinempty ? "joinempty" : "leavewhenempty");
2350 }
2351 }
2352}
2353
2354/*! \brief Configure a queue parameter.
2355 *
2356 * The failunknown flag is set for config files (and static realtime) to show
2357 * errors for unknown parameters. It is cleared for dynamic realtime to allow
2358 * extra fields in the tables.
2359 * \note For error reporting, line number is passed for .conf static configuration,
2360 * for Realtime queues, linenum is -1.
2361*/
2362static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
2363{
2364 if (!strcasecmp(param, "musicclass") ||
2365 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
2366 ast_string_field_set(q, moh, val);
2367 } else if (!strcasecmp(param, "announce")) {
2368 ast_string_field_set(q, announce, val);
2369 } else if (!strcasecmp(param, "context")) {
2370 ast_string_field_set(q, context, val);
2371 } else if (!strcasecmp(param, "timeout")) {
2372 q->timeout = atoi(val);
2373 if (q->timeout < 0) {
2374 q->timeout = DEFAULT_TIMEOUT;
2375 }
2376 } else if (!strcasecmp(param, "ringinuse")) {
2377 q->ringinuse = ast_true(val);
2378 } else if (!strcasecmp(param, "setinterfacevar")) {
2379 q->setinterfacevar = ast_true(val);
2380 } else if (!strcasecmp(param, "setqueuevar")) {
2381 q->setqueuevar = ast_true(val);
2382 } else if (!strcasecmp(param, "setqueueentryvar")) {
2383 q->setqueueentryvar = ast_true(val);
2384 } else if (!strcasecmp(param, "monitor-format")) {
2385 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
2386 } else if (!strcasecmp(param, "membermacro")) {
2387 ast_string_field_set(q, membermacro, val);
2388 } else if (!strcasecmp(param, "membergosub")) {
2389 ast_string_field_set(q, membergosub, val);
2390 } else if (!strcasecmp(param, "queue-youarenext")) {
2391 ast_string_field_set(q, sound_next, val);
2392 } else if (!strcasecmp(param, "queue-thereare")) {
2393 ast_string_field_set(q, sound_thereare, val);
2394 } else if (!strcasecmp(param, "queue-callswaiting")) {
2395 ast_string_field_set(q, sound_calls, val);
2396 } else if (!strcasecmp(param, "queue-quantity1")) {
2397 ast_string_field_set(q, queue_quantity1, val);
2398 } else if (!strcasecmp(param, "queue-quantity2")) {
2399 ast_string_field_set(q, queue_quantity2, val);
2400 } else if (!strcasecmp(param, "queue-holdtime")) {
2401 ast_string_field_set(q, sound_holdtime, val);
2402 } else if (!strcasecmp(param, "queue-minutes")) {
2403 ast_string_field_set(q, sound_minutes, val);
2404 } else if (!strcasecmp(param, "queue-minute")) {
2405 ast_string_field_set(q, sound_minute, val);
2406 } else if (!strcasecmp(param, "queue-seconds")) {
2407 ast_string_field_set(q, sound_seconds, val);
2408 } else if (!strcasecmp(param, "queue-thankyou")) {
2409 ast_string_field_set(q, sound_thanks, val);
2410 } else if (!strcasecmp(param, "queue-callerannounce")) {
2411 ast_string_field_set(q, sound_callerannounce, val);
2412 } else if (!strcasecmp(param, "queue-reporthold")) {
2413 ast_string_field_set(q, sound_reporthold, val);
2414 } else if (!strcasecmp(param, "announce-frequency")) {
2415 q->announcefrequency = atoi(val);
2416 } else if (!strcasecmp(param, "announce-to-first-user")) {
2417 q->announce_to_first_user = ast_true(val);
2418 } else if (!strcasecmp(param, "min-announce-frequency")) {
2419 q->minannouncefrequency = atoi(val);
2420 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
2421 } else if (!strcasecmp(param, "announce-round-seconds")) {
2422 q->roundingseconds = atoi(val);
2423 /* Rounding to any other values just doesn't make sense... */
2424 if (!(q->roundingseconds == 0 || q->roundingseconds == 5 || q->roundingseconds == 10
2425 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
2426 if (linenum >= 0) {
2427 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
2428 "using 0 instead for queue '%s' at line %d of queues.conf\n",
2429 val, param, q->name, linenum);
2430 } else {
2431 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
2432 "using 0 instead for queue '%s'\n", val, param, q->name);
2433 }
2434 q->roundingseconds=0;
2435 }
2436 } else if (!strcasecmp(param, "announce-holdtime")) {
2437 if (!strcasecmp(val, "once")) {
2438 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
2439 } else if (ast_true(val)) {
2440 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
2441 } else {
2442 q->announceholdtime = 0;
2443 }
2444 } else if (!strcasecmp(param, "announce-position")) {
2445 if (!strcasecmp(val, "limit")) {
2446 q->announceposition = ANNOUNCEPOSITION_LIMIT;
2447 } else if (!strcasecmp(val, "more")) {
2448 q->announceposition = ANNOUNCEPOSITION_MORE_THAN;
2449 } else if (ast_true(val)) {
2450 q->announceposition = ANNOUNCEPOSITION_YES;
2451 } else {
2452 q->announceposition = ANNOUNCEPOSITION_NO;
2453 }
2454 } else if (!strcasecmp(param, "announce-position-limit")) {
2455 q->announcepositionlimit = atoi(val);
2456 } else if (!strcasecmp(param, "periodic-announce")) {
2457 if (strchr(val, ',')) {
2458 char *s, *buf = ast_strdupa(val);
2459 unsigned int i = 0;
2460
2461 while ((s = strsep(&buf, ",|"))) {
2462 if (!q->sound_periodicannounce[i]) {
2463 q->sound_periodicannounce[i] = ast_str_create(16);
2464 }
2465 ast_str_set(&q->sound_periodicannounce[i], 0, "%s", s);
2466 i++;
2467 if (i == MAX_PERIODIC_ANNOUNCEMENTS) {
2468 break;
2469 }
2470 }
2471 q->numperiodicannounce = i;
2472 } else {
2473 ast_str_set(&q->sound_periodicannounce[0], 0, "%s", val);
2474 q->numperiodicannounce = 1;
2475 }
2476 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
2477 q->periodicannouncefrequency = atoi(val);
2478 } else if (!strcasecmp(param, "relative-periodic-announce")) {
2479 q->relativeperiodicannounce = ast_true(val);
2480 } else if (!strcasecmp(param, "random-periodic-announce")) {
2481 q->randomperiodicannounce = ast_true(val);
2482 } else if (!strcasecmp(param, "retry")) {
2483 q->retry = atoi(val);
2484 if (q->retry <= 0) {
2485 q->retry = DEFAULT_RETRY;
2486 }
2487 } else if (!strcasecmp(param, "wrapuptime")) {
2488 q->wrapuptime = atoi(val);
2489 } else if (!strcasecmp(param, "penaltymemberslimit")) {
2490 if ((sscanf(val, "%10d", &q->penaltymemberslimit) != 1)) {
2491 q->penaltymemberslimit = 0;
2492 }
2493 } else if (!strcasecmp(param, "autofill")) {
2494 q->autofill = ast_true(val);
2495 } else if (!strcasecmp(param, "monitor-type")) {
2496 if (!strcasecmp(val, "mixmonitor")) {
2497 q->montype = 1;
2498 }
2499 } else if (!strcasecmp(param, "autopause")) {
2500 q->autopause = autopause2int(val);
2501 } else if (!strcasecmp(param, "autopausedelay")) {
2502 q->autopausedelay = atoi(val);
2503 } else if (!strcasecmp(param, "autopausebusy")) {
2504 q->autopausebusy = ast_true(val);
2505 } else if (!strcasecmp(param, "autopauseunavail")) {
2506 q->autopauseunavail = ast_true(val);
2507 } else if (!strcasecmp(param, "maxlen")) {
2508 q->maxlen = atoi(val);
2509 if (q->maxlen < 0) {
2510 q->maxlen = 0;
2511 }
2512 } else if (!strcasecmp(param, "servicelevel")) {
2513 q->servicelevel= atoi(val);
2514 } else if (!strcasecmp(param, "strategy")) {
2515 int strategy;
2516
2517 /* We are a static queue and already have set this, no need to do it again */
2518 if (failunknown) {
2519 return;
2520 }
2521 strategy = strat2int(val);
2522 if (strategy < 0) {
2523 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2524 val, q->name);
2525 q->strategy = QUEUE_STRATEGY_RINGALL;
2526 }
2527 if (strategy == q->strategy) {
2528 return;
2529 }
2530 if (strategy == QUEUE_STRATEGY_LINEAR) {
2531 ast_log(LOG_WARNING, "Changing to the linear strategy currently requires asterisk to be restarted.\n");
2532 return;
2533 }
2534 q->strategy = strategy;
2535 } else if (!strcasecmp(param, "joinempty")) {
2536 parse_empty_options(val, &q->joinempty, 1);
2537 } else if (!strcasecmp(param, "leavewhenempty")) {
2538 parse_empty_options(val, &q->leavewhenempty, 0);
2539 } else if (!strcasecmp(param, "eventmemberstatus")) {
2540 q->maskmemberstatus = !ast_true(val);
2541 } else if (!strcasecmp(param, "eventwhencalled")) {
2542 if (!strcasecmp(val, "vars")) {
2543 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
2544 } else {
2545 q->eventwhencalled = ast_true(val) ? 1 : 0;
2546 }
2547 } else if (!strcasecmp(param, "reportholdtime")) {
2548 q->reportholdtime = ast_true(val);
2549 } else if (!strcasecmp(param, "memberdelay")) {
2550 q->memberdelay = atoi(val);
2551 } else if (!strcasecmp(param, "weight")) {
2552 q->weight = atoi(val);
2553 } else if (!strcasecmp(param, "timeoutrestart")) {
2554 q->timeoutrestart = ast_true(val);
2555 } else if (!strcasecmp(param, "defaultrule")) {
2556 ast_string_field_set(q, defaultrule, val);
2557 } else if (!strcasecmp(param, "timeoutpriority")) {
2558 if (!strcasecmp(val, "conf")) {
2559 q->timeoutpriority = TIMEOUT_PRIORITY_CONF;
2560 } else {
2561 q->timeoutpriority = TIMEOUT_PRIORITY_APP;
2562 }
2563 } else if (failunknown) {
2564 if (linenum >= 0) {
2565 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
2566 q->name, param, linenum);
2567 } else {
2568 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
2569 }
2570 }
2571}
2572
2573/*! \internal
2574 * \brief If adding a single new member to a queue, use this function instead of ao2_linking.
2575 * This adds round robin queue position data for a fresh member as well as links it.
2576 * \param queue Which queue the member is being added to
2577 * \param mem Which member is being added to the queue
2578 */
2579static void member_add_to_queue(struct call_queue *queue, struct member *mem)
2580{
2581 ao2_lock(queue->members);
2582 mem->queuepos = ao2_container_count(queue->members);
2583 ao2_link(queue->members, mem);
2584 ao2_unlock(queue->members);
2585}
2586
2587/*! \internal
2588 * \brief If removing a single member from a queue, use this function instead of ao2_unlinking.
2589 * This will perform round robin queue position reordering for the remaining members.
2590 * \param queue Which queue the member is being removed from
2591 * \param member Which member is being removed from the queue
2592 */
2593static void member_remove_from_queue(struct call_queue *queue, struct member *mem)
2594{
2595 pending_members_remove(mem);
2596 ao2_lock(queue->members);
2597 queue_member_follower_removal(queue, mem);
2598 ao2_unlink(queue->members, mem);
2599 ao2_unlock(queue->members);
2600}
2601
2602/*!
2603 * \brief Find rt member record to update otherwise create one.
2604 *
2605 * Search for member in queue, if found update penalty/paused state,
2606 * if no member exists create one flag it as a RT member and add to queue member list.
2607*/
2608static void rt_handle_member_record(struct call_queue *q, char *interface, struct ast_config *member_config)
2609{
2610 struct member *m;
2611 struct ao2_iterator mem_iter;
2612 int penalty = 0;
2613 int paused = 0;
2614 int found = 0;
2615 int ringinuse = q->ringinuse;
2616
2617 const char *config_val;
2618 const char *rt_uniqueid = ast_variable_retrieve(member_config, interface, "uniqueid");
2619 const char *membername = S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface);
2620 const char *state_interface = S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface);
2621 const char *penalty_str = ast_variable_retrieve(member_config, interface, "penalty");
2622 const char *paused_str = ast_variable_retrieve(member_config, interface, "paused");
2623
2624 if (ast_strlen_zero(rt_uniqueid)) {
2625 ast_log(LOG_WARNING, "Realtime field uniqueid is empty for member %s\n", S_OR(membername, "NULL"));
2626 return;
2627 }
2628
2629 if (penalty_str) {
2630 penalty = atoi(penalty_str);
2631 if ((penalty < 0) && negative_penalty_invalid) {
2632 return;
2633 } else if (penalty < 0) {
2634 penalty = 0;
2635 }
2636 }
2637
2638 if (paused_str) {
2639 paused = atoi(paused_str);
2640 if (paused < 0) {
2641 paused = 0;
2642 }
2643 }
2644
2645 if ((config_val = ast_variable_retrieve(member_config, interface, realtime_ringinuse_field))) {
2646 if (ast_true(config_val)) {
2647 ringinuse = 1;
2648 } else if (ast_false(config_val)) {
2649 ringinuse = 0;
2650 } else {
2651 ast_log(LOG_WARNING, "Invalid value of '%s' field for %s in queue '%s'\n", realtime_ringinuse_field, interface, q->name);
2652 }
2653 }
2654
2655 /* Find member by realtime uniqueid and update */
2656 mem_iter = ao2_iterator_init(q->members, 0);
2657 while ((m = ao2_iterator_next(&mem_iter))) {
2658 if (!strcasecmp(m->rt_uniqueid, rt_uniqueid)) {
2659 m->dead = 0; /* Do not delete this one. */
2660 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
2661 if (paused_str) {
2662 m->paused = paused;
2663 }
2664 if (strcasecmp(state_interface, m->state_interface)) {
2665 ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));
2666 }
2667 m->penalty = penalty;
2668 m->ringinuse = ringinuse;
2669 found = 1;
2670 ao2_ref(m, -1);
2671 break;
2672 }
2673 ao2_ref(m, -1);
2674 }
2675 ao2_iterator_destroy(&mem_iter);
2676
2677 /* Create a new member */
2678 if (!found) {
2679 if ((m = create_queue_member(interface, membername, penalty, paused, state_interface, ringinuse))) {
2680 m->dead = 0;
2681 m->realtime = 1;
2682 ast_copy_string(m->rt_uniqueid, rt_uniqueid, sizeof(m->rt_uniqueid));
2683 if (!log_membername_as_agent) {
2684 ast_queue_log(q->name, "REALTIME", m->interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
2685 } else {
2686 ast_queue_log(q->name, "REALTIME", m->membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
2687 }
2688 member_add_to_queue(q, m);
2689 ao2_ref(m, -1);
2690 m = NULL;
2691 }
2692 }
2693}
2694
2695/*! \brief Iterate through queue's member list and delete them */
2696static void free_members(struct call_queue *q, int all)
2697{
2698 /* Free non-dynamic members */
2699 struct member *cur;
2700 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
2701
2702 while ((cur = ao2_iterator_next(&mem_iter))) {
2703 if (all || !cur->dynamic) {
2704 member_remove_from_queue(q, cur);
2705 }
2706 ao2_ref(cur, -1);
2707 }
2708 ao2_iterator_destroy(&mem_iter);
2709}
2710
2711/*! \brief Free queue's member list then its string fields */
2712static void destroy_queue(void *obj)
2713{
2714 struct call_queue *q = obj;
2715 int i;
2716
2717 free_members(q, 1);
2718 ast_string_field_free_memory(q);
2719 for (i = 0; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
2720 if (q->sound_periodicannounce[i]) {
2721 free(q->sound_periodicannounce[i]);
2722 }
2723 }
2724 ao2_ref(q->members, -1);
2725}
2726
2727static struct call_queue *alloc_queue(const char *queuename)
2728{
2729 struct call_queue *q;
2730
2731 if ((q = ao2_t_alloc(sizeof(*q), destroy_queue, "Allocate queue"))) {
2732 if (ast_string_field_init(q, 64)) {
2733 queue_t_unref(q, "String field allocation failed");
2734 return NULL;
2735 }
2736 ast_string_field_set(q, name, queuename);
2737 }
2738 return q;
2739}
2740
2741/*!
2742 * \brief Reload a single queue via realtime.
2743 *
2744 * Check for statically defined queue first, check if deleted RT queue,
2745 * check for new RT queue, if queue vars are not defined init them with defaults.
2746 * reload RT queue vars, set RT queue members dead and reload them, return finished queue.
2747 * \retval the queue,
2748 * \retval NULL if it doesn't exist.
2749 * \note Should be called with the "queues" container locked.
2750*/
2751static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
2752{
2753 struct ast_variable *v;
2754 struct call_queue *q, tmpq = {
2755 .name = queuename,
2756 };
2757 struct member *m;
2758 struct ao2_iterator mem_iter;
2759 char *interface = NULL;
2760 const char *tmp_name;
2761 char *tmp;
2762 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
2763
2764 /* Static queues override realtime. */
2765 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Check if static queue exists"))) {
2766 ao2_lock(q);
2767 if (!q->realtime) {
2768 if (q->dead) {
2769 ao2_unlock(q);
2770 queue_t_unref(q, "Queue is dead; can't return it");
2771 return NULL;
2772 }
2773 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
2774 ao2_unlock(q);
2775 return q;
2776 }
2777 } else if (!member_config) {
2778 /* Not found in the list, and it's not realtime ... */
2779 return NULL;
2780 }
2781 /* Check if queue is defined in realtime. */
2782 if (!queue_vars) {
2783 /* Delete queue from in-core list if it has been deleted in realtime. */
2784 if (q) {
2785 /*! \note Hmm, can't seem to distinguish a DB failure from a not
2786 found condition... So we might delete an in-core queue
2787 in case of DB failure. */
2788 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
2789
2790 q->dead = 1;
2791 /* Delete if unused (else will be deleted when last caller leaves). */
2792 queues_t_unlink(queues, q, "Unused; removing from container");
2793 ao2_unlock(q);
2794 queue_t_unref(q, "Queue is dead; can't return it");
2795 }
2796 return NULL;
2797 }
2798
2799 /* Create a new queue if an in-core entry does not exist yet. */
2800 if (!q) {
2801 struct ast_variable *tmpvar = NULL;
2802 if (!(q = alloc_queue(queuename))) {
2803 return NULL;
2804 }
2805 ao2_lock(q);
2806 clear_queue(q);
2807 q->realtime = 1;
2808 /*Before we initialize the queue, we need to set the strategy, so that linear strategy
2809 * will allocate the members properly
2810 */
2811 for (tmpvar = queue_vars; tmpvar; tmpvar = tmpvar->next) {
2812 if (!strcasecmp(tmpvar->name, "strategy")) {
2813 q->strategy = strat2int(tmpvar->value);
2814 if (q->strategy < 0) {
2815 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
2816 tmpvar->value, q->name);
2817 q->strategy = QUEUE_STRATEGY_RINGALL;
2818 }
2819 break;
2820 }
2821 }
2822 /* We traversed all variables and didn't find a strategy */
2823 if (!tmpvar) {
2824 q->strategy = QUEUE_STRATEGY_RINGALL;
2825 }
2826 queues_t_link(queues, q, "Add queue to container");
2827 }
2828 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
2829
2830 memset(tmpbuf, 0, sizeof(tmpbuf));
2831 for (v = queue_vars; v; v = v->next) {
2832 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
2833 if (strchr(v->name, '_')) {
2834 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
2835 tmp_name = tmpbuf;
2836 tmp = tmpbuf;
2837 while ((tmp = strchr(tmp, '_'))) {
2838 *tmp++ = '-';
2839 }
2840 } else {
2841 tmp_name = v->name;
2842 }
2843
2844 /* NULL values don't get returned from realtime; blank values should
2845 * still get set. If someone doesn't want a value to be set, they
2846 * should set the realtime column to NULL, not blank. */
2847 queue_set_param(q, tmp_name, v->value, -1, 0);
2848 }
2849
2850 /* Temporarily set realtime members dead so we can detect deleted ones. */
2851 mem_iter = ao2_iterator_init(q->members, 0);
2852 while ((m = ao2_iterator_next(&mem_iter))) {
2853 if (m->realtime) {
2854 m->dead = 1;
2855 }
2856 ao2_ref(m, -1);
2857 }
2858 ao2_iterator_destroy(&mem_iter);
2859
2860 while ((interface = ast_category_browse(member_config, interface))) {
2861 rt_handle_member_record(q, interface, member_config);
2862 }
2863
2864 /* Delete all realtime members that have been deleted in DB. */
2865 mem_iter = ao2_iterator_init(q->members, 0);
2866 while ((m = ao2_iterator_next(&mem_iter))) {
2867 if (m->dead) {
2868 if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
2869 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
2870 } else {
2871 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
2872 }
2873 member_remove_from_queue(q, m);
2874 }
2875 ao2_ref(m, -1);
2876 }
2877 ao2_iterator_destroy(&mem_iter);
2878
2879 ao2_unlock(q);
2880
2881 return q;
2882}
2883
2884/*!
2885 * note */
2886
2887/*!
2888 * \internal
2889 * \brief Returns reference to the named queue. If the queue is realtime, it will load the queue as well.
2890 * \param queuename - name of the desired queue
2891 *
2892 * \retval the queue
2893 * \retval NULL if it doesn't exist
2894 */
2895static struct call_queue *find_load_queue_rt_friendly(const char *queuename)
2896{
2897 struct ast_variable *queue_vars;
2898 struct ast_config *member_config = NULL;
2899 struct call_queue *q = NULL, tmpq = {
2900 .name = queuename,
2901 };
2902 int prev_weight = 0;
2903
2904 /* Find the queue in the in-core list first. */
2905 q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Look for queue in memory first");
2906
2907 if (!q || q->realtime) {
2908 /*! \note Load from realtime before taking the "queues" container lock, to avoid blocking all
2909 queue operations while waiting for the DB.
2910
2911 This will be two separate database transactions, so we might
2912 see queue parameters as they were before another process
2913 changed the queue and member list as it was after the change.
2914 Thus we might see an empty member list when a queue is
2915 deleted. In practise, this is unlikely to cause a problem. */
2916
2917 queue_vars = ast_load_realtime("queues", "name", queuename, SENTINEL);
2918 if (queue_vars) {
2919 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, SENTINEL);
2920 if (!member_config) {
2921 ast_debug(1, "No queue_members defined in config extconfig.conf\n");
2922 member_config = ast_config_new();
2923 }
2924 }
2925 if (q) {
2926 prev_weight = q->weight ? 1 : 0;
2927 queue_t_unref(q, "Need to find realtime queue");
2928 }
2929
2930 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
2931 ast_config_destroy(member_config);
2932 ast_variables_destroy(queue_vars);
2933
2934 /* update the use_weight value if the queue's has gained or lost a weight */
2935 if (q) {
2936 if (!q->weight && prev_weight) {
2937 ast_atomic_fetchadd_int(&use_weight, -1);
2938 }
2939 if (q->weight && !prev_weight) {
2940 ast_atomic_fetchadd_int(&use_weight, +1);
2941 }
2942 }
2943 /* Other cases will end up with the proper value for use_weight */
2944 } else {
2945 update_realtime_members(q);
2946 }
2947 return q;
2948}
2949
2950static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
2951{
2952 int ret = -1;
2953
2954 if (ast_strlen_zero(mem->rt_uniqueid)) {
2955 return ret;
2956 }
2957
2958 if ((ast_update_realtime("queue_members", "uniqueid", mem->rt_uniqueid, field, value, SENTINEL)) > 0) {
2959 ret = 0;
2960 }
2961
2962 return ret;
2963}
2964
2965
2966static void update_realtime_members(struct call_queue *q)
2967{
2968 struct ast_config *member_config = NULL;
2969 struct member *m;
2970 char *interface = NULL;
2971 struct ao2_iterator mem_iter;
2972
2973 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , SENTINEL))) {
2974 /* This queue doesn't have realtime members. If the queue still has any realtime
2975 * members in memory, they need to be removed.
2976 */
2977 ao2_lock(q);
2978 mem_iter = ao2_iterator_init(q->members, 0);
2979 while ((m = ao2_iterator_next(&mem_iter))) {
2980 if (m->realtime) {
2981 member_remove_from_queue(q, m);
2982 }
2983 ao2_ref(m, -1);
2984 }
2985 ao2_iterator_destroy(&mem_iter);
2986 ast_debug(3, "Queue %s has no realtime members defined. No need for update\n", q->name);
2987 ao2_unlock(q);
2988 return;
2989 }
2990
2991 ao2_lock(q);
2992
2993 /* Temporarily set realtime members dead so we can detect deleted ones.*/
2994 mem_iter = ao2_iterator_init(q->members, 0);
2995 while ((m = ao2_iterator_next(&mem_iter))) {
2996 if (m->realtime) {
2997 m->dead = 1;
2998 }
2999 ao2_ref(m, -1);
3000 }
3001 ao2_iterator_destroy(&mem_iter);
3002
3003 while ((interface = ast_category_browse(member_config, interface))) {
3004 rt_handle_member_record(q, interface, member_config);
3005 }
3006
3007 /* Delete all realtime members that have been deleted in DB. */
3008 mem_iter = ao2_iterator_init(q->members, 0);
3009 while ((m = ao2_iterator_next(&mem_iter))) {
3010 if (m->dead) {
3011 if (ast_strlen_zero(m->membername) || !log_membername_as_agent) {
3012 ast_queue_log(q->name, "REALTIME", m->interface, "REMOVEMEMBER", "%s", "");
3013 } else {
3014 ast_queue_log(q->name, "REALTIME", m->membername, "REMOVEMEMBER", "%s", "");
3015 }
3016 member_remove_from_queue(q, m);
3017 }
3018 ao2_ref(m, -1);
3019 }
3020 ao2_iterator_destroy(&mem_iter);
3021 ao2_unlock(q);
3022 ast_config_destroy(member_config);
3023}
3024
3025static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason, int position)
3026{
3027 struct call_queue *q;
3028 struct queue_ent *cur, *prev = NULL;
3029 int res = -1;
3030 int pos = 0;
3031 int inserted = 0;
3032
3033 if (!(q = find_load_queue_rt_friendly(queuename))) {
3034 return res;
3035 }
3036 ao2_lock(q);
3037
3038 /* This is our one */
3039 if (q->joinempty) {
3040 int status = 0;
3041 if ((status = get_member_status(q, qe->max_penalty, qe->min_penalty, q->joinempty, 0))) {
3042 *reason = QUEUE_JOINEMPTY;
3043 ao2_unlock(q);
3044 queue_t_unref(q, "Done with realtime queue");
3045 return res;
3046 }
3047 }
3048 if (*reason == QUEUE_UNKNOWN && q->maxlen && (q->count >= q->maxlen)) {
3049 *reason = QUEUE_FULL;
3050 } else if (*reason == QUEUE_UNKNOWN) {
3051 /* There's space for us, put us at the right position inside
3052 * the queue.
3053 * Take into account the priority of the calling user */
3054 inserted = 0;
3055 prev = NULL;
3056 cur = q->head;
3057 while (cur) {
3058 /* We have higher priority than the current user, enter
3059 * before him, after all the other users with priority
3060 * higher or equal to our priority. */
3061 if ((!inserted) && (qe->prio > cur->prio)) {
3062 insert_entry(q, prev, qe, &pos);
3063 inserted = 1;
3064 }
3065 /* <= is necessary for the position comparison because it may not be possible to enter
3066 * at our desired position since higher-priority callers may have taken the position we want
3067 */
3068 if (!inserted && (qe->prio >= cur->prio) && position && (position <= pos + 1)) {
3069 insert_entry(q, prev, qe, &pos);
3070 inserted = 1;
3071 /*pos is incremented inside insert_entry, so don't need to add 1 here*/
3072 if (position < pos) {
3073 ast_log(LOG_NOTICE, "Asked to be inserted at position %d but forced into position %d due to higher priority callers\n", position, pos);
3074 }
3075 }
3076 cur->pos = ++pos;
3077 prev = cur;
3078 cur = cur->next;
3079 }
3080 /* No luck, join at the end of the queue */
3081 if (!inserted) {
3082 insert_entry(q, prev, qe, &pos);
3083 }
3084 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
3085 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
3086 ast_copy_string(qe->context, q->context, sizeof(qe->context));
3087 q->count++;
3088 if (q->count == 1) {
3089 ast_devstate_changed(AST_DEVICE_RINGING, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
3090 }
3091
3092 res = 0;
3093 /*** DOCUMENTATION
3094 <managerEventInstance>
3095 <synopsis>Raised when a channel joins a Queue.</synopsis>
3096 <syntax>
3097 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
3098 <parameter name="Position">
3099 <para>This channel's current position in the queue.</para>
3100 </parameter>
3101 <parameter name="Count">
3102 <para>The total number of channels in the queue.</para>
3103 </parameter>
3104 </syntax>
3105 <see-also>
3106 <ref type="managerEvent">Leave</ref>
3107 <ref type="application">Queue</ref>
3108 </see-also>
3109 </managerEventInstance>
3110 ***/
3111 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Join",
3112 "Channel: %s\r\n"
3113 "CallerIDNum: %s\r\n"
3114 "CallerIDName: %s\r\n"
3115 "ConnectedLineNum: %s\r\n"
3116 "ConnectedLineName: %s\r\n"
3117 "Queue: %s\r\n"
3118 "Position: %d\r\n"
3119 "Count: %d\r\n"
3120 "Uniqueid: %s\r\n",
3121 ast_channel_name(qe->chan),
3122 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
3123 S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
3124 S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),/* XXX somewhere else it is <unknown> */
3125 S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
3126 q->name, qe->pos, q->count, ast_channel_uniqueid(qe->chan));
3127 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, ast_channel_name(qe->chan), qe->pos );
3128 }
3129 ao2_unlock(q);
3130 queue_t_unref(q, "Done with realtime queue");
3131
3132 return res;
3133}
3134
3135static int play_file(struct ast_channel *chan, const char *filename)
3136{
3137 int res;
3138
3139 if (ast_strlen_zero(filename)) {
3140 return 0;
3141 }
3142
3143 if (!ast_fileexists(filename, NULL, ast_channel_language(chan))) {
3144 return 0;
3145 }
3146
3147 ast_stopstream(chan);
3148
3149 res = ast_streamfile(chan, filename, ast_channel_language(chan));
3150 if (!res) {
3151 res = ast_waitstream(chan, AST_DIGIT_ANY);
3152 }
3153
3154 ast_stopstream(chan);
3155
3156 return res;
3157}
3158
3159/*!
3160 * \brief Check for valid exit from queue via goto
3161 * \retval 0 if failure
3162 * \retval 1 if successful
3163*/
3164static int valid_exit(struct queue_ent *qe, char digit)
3165{
3166 int digitlen = strlen(qe->digits);
3167
3168 /* Prevent possible buffer overflow */
3169 if (digitlen < sizeof(qe->digits) - 2) {
3170 qe->digits[digitlen] = digit;
3171 qe->digits[digitlen + 1] = '\0';
3172 } else {
3173 qe->digits[0] = '\0';
3174 return 0;
3175 }
3176
3177 /* If there's no context to goto, short-circuit */
3178 if (ast_strlen_zero(qe->context)) {
3179 return 0;
3180 }
3181
3182 /* If the extension is bad, then reset the digits to blank */
3183 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1,
3184 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, NULL))) {
3185 qe->digits[0] = '\0';
3186 return 0;
3187 }
3188
3189 /* We have an exact match */
3190 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
3191 qe->valid_digits = 1;
3192 /* Return 1 on a successful goto */
3193 return 1;
3194 }
3195
3196 return 0;
3197}
3198
3199static int say_position(struct queue_ent *qe, int ringing)
3200{
3201 int res = 0, announceposition = 0;
3202 long avgholdmins, avgholdsecs;
3203 int say_thanks = 1;
3204 time_t now;
3205
3206 /* Let minannouncefrequency seconds pass between the start of each position announcement */
3207 time(&now);
3208 if ((now - qe->last_pos) < qe->parent->minannouncefrequency) {
3209 return 0;
3210 }
3211
3212 /* If either our position has changed, or we are over the freq timer, say position */
3213 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency)) {
3214 return 0;
3215 }
3216
3217 if (ringing) {
3218 ast_indicate(qe->chan,-1);
3219 } else {
3220 ast_moh_stop(qe->chan);
3221 }
3222
3223 if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
3224 qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
3225 (qe->parent->announceposition == ANNOUNCEPOSITION_LIMIT &&
3226 qe->pos <= qe->parent->announcepositionlimit)) {
3227 announceposition = 1;
3228 }
3229
3230
3231 if (announceposition == 1) {
3232 /* Say we're next, if we are */
3233 if (qe->pos == 1) {
3234 res = play_file(qe->chan, qe->parent->sound_next);
3235 if (res) {
3236 goto playout;
3237 }
3238 goto posout;
3239 } else {
3240 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
3241 /* More than Case*/
3242 res = play_file(qe->chan, qe->parent->queue_quantity1);
3243 if (res) {
3244 goto playout;
3245 }
3246 res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL); /* Needs gender */
3247 if (res) {
3248 goto playout;
3249 }
3250 } else {
3251 /* Normal Case */
3252 res = play_file(qe->chan, qe->parent->sound_thereare);
3253 if (res) {
3254 goto playout;
3255 }
3256 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL); /* Needs gender */
3257 if (res) {
3258 goto playout;
3259 }
3260 }
3261 if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
3262 /* More than Case*/
3263 res = play_file(qe->chan, qe->parent->queue_quantity2);
3264 if (res) {
3265 goto playout;
3266 }
3267 } else {
3268 res = play_file(qe->chan, qe->parent->sound_calls);
3269 if (res) {
3270 goto playout;
3271 }
3272 }
3273 }
3274 }
3275 /* Round hold time to nearest minute */
3276 avgholdmins = labs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
3277
3278 /* If they have specified a rounding then round the seconds as well */
3279 if (qe->parent->roundingseconds) {
3280 avgholdsecs = (labs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
3281 avgholdsecs *= qe->parent->roundingseconds;
3282 } else {
3283 avgholdsecs = 0;
3284 }
3285
3286 ast_verb(3, "Hold time for %s is %ld minute(s) %ld seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
3287
3288 /* If the hold time is >1 min, if it's enabled, and if it's not
3289 supposed to be only once and we have already said it, say it */
3290 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
3291 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
3292 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
3293 res = play_file(qe->chan, qe->parent->sound_holdtime);
3294 if (res) {
3295 goto playout;
3296 }
3297
3298 if (avgholdmins >= 1) {
3299 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
3300 if (res) {
3301 goto playout;
3302 }
3303
3304 if (avgholdmins == 1) {
3305 res = play_file(qe->chan, qe->parent->sound_minute);
3306 if (res) {
3307 goto playout;
3308 }
3309 } else {
3310 res = play_file(qe->chan, qe->parent->sound_minutes);
3311 if (res) {
3312 goto playout;
3313 }
3314 }
3315 }
3316 if (avgholdsecs >= 1) {
3317 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, ast_channel_language(qe->chan), NULL);
3318 if (res) {
3319 goto playout;
3320 }
3321
3322 res = play_file(qe->chan, qe->parent->sound_seconds);
3323 if (res) {
3324 goto playout;
3325 }
3326 }
3327 } else if (qe->parent->announceholdtime && !qe->parent->announceposition) {
3328 say_thanks = 0;
3329 }
3330
3331posout:
3332 if (qe->parent->announceposition) {
3333 ast_verb(3, "Told %s in %s their queue position (which was %d)\n",
3334 ast_channel_name(qe->chan), qe->parent->name, qe->pos);
3335 }
3336 if (say_thanks) {
3337 res = play_file(qe->chan, qe->parent->sound_thanks);
3338 }
3339playout:
3340
3341 if ((res > 0 && !valid_exit(qe, res))) {
3342 res = 0;
3343 }
3344
3345 /* Set our last_pos indicators */
3346 qe->last_pos = now;
3347 qe->last_pos_said = qe->pos;
3348
3349 /* Don't restart music on hold if we're about to exit the caller from the queue */
3350 if (!res) {
3351 if (ringing) {
3352 ast_indicate(qe->chan, AST_CONTROL_RINGING);
3353 } else {
3354 ast_moh_start(qe->chan, qe->moh, NULL);
3355 }
3356 }
3357 return res;
3358}
3359
3360static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
3361{
3362 int oldvalue;
3363
3364 /* Calculate holdtime using an exponential average */
3365 /* Thanks to SRT for this contribution */
3366 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
3367
3368 ao2_lock(qe->parent);
3369 oldvalue = qe->parent->holdtime;
3370 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
3371 ao2_unlock(qe->parent);
3372}
3373
3374/*! \brief Caller leaving queue.
3375 *
3376 * Search the queue to find the leaving client, if found remove from queue
3377 * create manager event, move others up the queue.
3378*/
3379static void leave_queue(struct queue_ent *qe)
3380{
3381 struct call_queue *q;
3382 struct queue_ent *current, *prev = NULL;
3383 struct penalty_rule *pr_iter;
3384 int pos = 0;
3385
3386 if (!(q = qe->parent)) {
3387 return;
3388 }
3389 queue_t_ref(q, "Copy queue pointer from queue entry");
3390 ao2_lock(q);
3391
3392 prev = NULL;
3393 for (current = q->head; current; current = current->next) {
3394 if (current == qe) {
3395 char posstr[20];
3396 q->count--;
3397 if (!q->count) {
3398 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s", q->name);
3399 }
3400
3401 /* Take us out of the queue */
3402 /*** DOCUMENTATION
3403 <managerEventInstance>
3404 <synopsis>Raised when a channel leaves a Queue.</synopsis>
3405 <syntax>
3406 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
3407 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Join']/managerEventInstance/syntax/parameter[@name='Count'])" />
3408 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Join']/managerEventInstance/syntax/parameter[@name='Position'])" />
3409 </syntax>
3410 <see-also>
3411 <ref type="managerEvent">Join</ref>
3412 </see-also>
3413 </managerEventInstance>
3414 ***/
3415 ast_manager_event(qe->chan, EVENT_FLAG_CALL, "Leave",
3416 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nPosition: %d\r\nUniqueid: %s\r\n",
3417 ast_channel_name(qe->chan), q->name, q->count, qe->pos, ast_channel_uniqueid(qe->chan));
3418 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, ast_channel_name(qe->chan));
3419 /* Take us out of the queue */
3420 if (prev) {
3421 prev->next = current->next;
3422 } else {
3423 q->head = current->next;
3424 }
3425 /* Free penalty rules */
3426 while ((pr_iter = AST_LIST_REMOVE_HEAD(&qe->qe_rules, list))) {
3427 ast_free(pr_iter);
3428 }
3429 qe->pr = NULL;
3430 snprintf(posstr, sizeof(posstr), "%d", qe->pos);
3431 pbx_builtin_setvar_helper(qe->chan, "QUEUEPOSITION", posstr);
3432 } else {
3433 /* Renumber the people after us in the queue based on a new count */
3434 current->pos = ++pos;
3435 prev = current;
3436 }
3437 }
3438 ao2_unlock(q);
3439
3440 /*If the queue is a realtime queue, check to see if it's still defined in real time*/
3441 if (q->realtime) {
3442 struct ast_variable *var;
3443 if (!(var = ast_load_realtime("queues", "name", q->name, SENTINEL))) {
3444 q->dead = 1;
3445 } else {
3446 ast_variables_destroy(var);
3447 }
3448 }
3449
3450 if (q->dead) {
3451 /* It's dead and nobody is in it, so kill it */
3452 queues_t_unlink(queues, q, "Queue is now dead; remove it from the container");
3453 }
3454 /* unref the explicit ref earlier in the function */
3455 queue_t_unref(q, "Expire copied reference");
3456}
3457
3458/*!
3459 * \internal
3460 * \brief Destroy the given callattempt structure and free it.
3461 * \since 1.8
3462 *
3463 * \param doomed callattempt structure to destroy.
3464 *
3465 * \return Nothing
3466 */
3467static void callattempt_free(struct callattempt *doomed)
3468{
3469 if (doomed->member) {
3470 ao2_ref(doomed->member, -1);
3471 }
3472 ast_party_connected_line_free(&doomed->connected);
3473 ast_free(doomed);
3474}
3475
3476/*! \brief Hang up a list of outgoing calls */
3477static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception, int cancel_answered_elsewhere)
3478{
3479 struct callattempt *oo;
3480
3481 while (outgoing) {
3482 /* If someone else answered the call we should indicate this in the CANCEL */
3483 /* Hangup any existing lines we have open */
3484 if (outgoing->chan && (outgoing->chan != exception)) {
3485 if (exception || cancel_answered_elsewhere) {
3486 ast_channel_hangupcause_set(outgoing->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
3487 }
3488 /* When dialing channels it is possible that they may not ever
3489 * leave the not in use state (Local channels in particular) by
3490 * the time we cancel them. If this occurs but we know they were
3491 * dialed we explicitly remove them from the pending members
3492 * container so that subsequent call attempts occur.
3493 */
3494 if (outgoing->member->status == AST_DEVICE_NOT_INUSE) {
3495 pending_members_remove(outgoing->member);
3496 }
3497
3498 ast_hangup(outgoing->chan);
3499 }
3500 oo = outgoing;
3501 outgoing = outgoing->q_next;
3502 ast_aoc_destroy_decoded(oo->aoc_s_rate_list);
3503 callattempt_free(oo);
3504 }
3505}
3506
3507/*!
3508 * \brief Get the number of members available to accept a call.
3509 *
3510 * \note The queue passed in should be locked prior to this function call
3511 *
3512 * \param[in] q The queue for which we are couting the number of available members
3513 * \return Return the number of available members in queue q
3514 */
3515static int num_available_members(struct call_queue *q)
3516{
3517 struct member *mem;
3518 int avl = 0;
3519 struct ao2_iterator mem_iter;
3520
3521 mem_iter = ao2_iterator_init(q->members, 0);
3522 while ((mem = ao2_iterator_next(&mem_iter))) {
3523
3524 avl += is_member_available(q, mem);
3525 ao2_ref(mem, -1);
3526
3527 /* If autofill is not enabled or if the queue's strategy is ringall, then
3528 * we really don't care about the number of available members so much as we
3529 * do that there is at least one available.
3530 *
3531 * In fact, we purposely will return from this function stating that only
3532 * one member is available if either of those conditions hold. That way,
3533 * functions which determine what action to take based on the number of available
3534 * members will operate properly. The reasoning is that even if multiple
3535 * members are available, only the head caller can actually be serviced.
3536 */
3537 if ((!q->autofill || q->strategy == QUEUE_STRATEGY_RINGALL) && avl) {
3538 break;
3539 }
3540 }
3541 ao2_iterator_destroy(&mem_iter);
3542
3543 return avl;
3544}
3545
3546/* traverse all defined queues which have calls waiting and contain this member
3547 return 0 if no other queue has precedence (higher weight) or 1 if found */
3548static int compare_weight(struct call_queue *rq, struct member *member)
3549{
3550 struct call_queue *q;
3551 struct member *mem;
3552 int found = 0;
3553 struct ao2_iterator queue_iter;
3554
3555 queue_iter = ao2_iterator_init(queues, 0);
3556 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
3557 if (q == rq) { /* don't check myself, could deadlock */
3558 queue_t_unref(q, "Done with iterator");
3559 continue;
3560 }
3561 ao2_lock(q);
3562 if (q->count && q->members) {
3563 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
3564 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
3565 if (q->weight > rq->weight && q->count >= num_available_members(q)) {
3566 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);
3567 found = 1;
3568 }
3569 ao2_ref(mem, -1);
3570 }
3571 }
3572 ao2_unlock(q);
3573 queue_t_unref(q, "Done with iterator");
3574 if (found) {
3575 break;
3576 }
3577 }
3578 ao2_iterator_destroy(&queue_iter);
3579 return found;
3580}
3581
3582/*! \brief common hangup actions */
3583static void do_hang(struct callattempt *o)
3584{
3585 o->stillgoing = 0;
3586 ast_hangup(o->chan);
3587 o->chan = NULL;
3588}
3589
3590/*! \brief convert "\n" to "\nVariable: " ready for manager to use */
3591static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
3592{
3593 struct ast_str *buf = ast_str_thread_get(&ast_str_thread_global_buf, len + 1);
3594 const char *tmp;
3595
3596 if (pbx_builtin_serialize_variables(chan, &buf)) {
3597 int i, j;
3598
3599 /* convert "\n" to "\nVariable: " */
3600 strcpy(vars, "Variable: ");
3601 tmp = ast_str_buffer(buf);
3602
3603 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
3604 vars[j] = tmp[i];
3605
3606 if (tmp[i + 1] == '\0') {
3607 break;
3608 }
3609 if (tmp[i] == '\n') {
3610 vars[j++] = '\r';
3611 vars[j++] = '\n';
3612
3613 ast_copy_string(&(vars[j]), "Variable: ", len - j);
3614 j += 9;
3615 }
3616 }
3617 if (j > len - 3) {
3618 j = len - 3;
3619 }
3620 vars[j++] = '\r';
3621 vars[j++] = '\n';
3622 vars[j] = '\0';
3623 } else {
3624 /* there are no channel variables; leave it blank */
3625 *vars = '\0';
3626 }
3627 return vars;
3628}
3629
3630/*!
3631 * \internal
3632 * \brief Check if the member status is available.
3633 *
3634 * \param status Member status to check if available.
3635 *
3636 * \retval non-zero if the member status is available.
3637 */
3638static int member_status_available(int status)
3639{
3640 return status == AST_DEVICE_NOT_INUSE || status == AST_DEVICE_UNKNOWN;
3641}
3642
3643/*!
3644 * \internal
3645 * \brief Determine if can ring a queue entry.
3646 *
3647 * \param qe Queue entry to check.
3648 * \param call Member call attempt.
3649 *
3650 * \retval non-zero if an entry can be called.
3651 */
3652static int can_ring_entry(struct queue_ent *qe, struct callattempt *call)
3653{
3654 if (call->member->paused) {
3655 ast_debug(1, "%s paused, can't receive call\n", call->interface);
3656 return 0;
3657 }
3658
3659 if (!call->member->ringinuse && !member_status_available(call->member->status)) {
3660 ast_debug(1, "%s not available, can't receive call\n", call->interface);
3661 return 0;
3662 }
3663
3664 if (call->member->in_call && call->lastqueue && call->lastqueue->wrapuptime) {
3665 ast_debug(1, "%s is in call, so not available (wrapuptime %d)\n",
3666 call->interface, call->lastqueue->wrapuptime);
3667 return 0;
3668 }
3669
3670 if ((call->lastqueue && call->lastqueue->wrapuptime && (time(NULL) - call->lastcall < call->lastqueue->wrapuptime))
3671 || (!call->lastqueue && qe->parent->wrapuptime && (time(NULL) - call->lastcall < qe->parent->wrapuptime))) {
3672 ast_debug(1, "Wrapuptime not yet expired on queue %s for %s\n",
3673 (call->lastqueue ? call->lastqueue->name : qe->parent->name),
3674 call->interface);
3675 return 0;
3676 }
3677
3678 if (use_weight && compare_weight(qe->parent, call->member)) {
3679 ast_debug(1, "Priority queue delaying call to %s:%s\n",
3680 qe->parent->name, call->interface);
3681 return 0;
3682 }
3683
3684 if (!call->member->ringinuse) {
3685 struct member *mem;
3686
3687 ao2_lock(pending_members);
3688
3689 mem = ao2_find(pending_members, call->member, OBJ_POINTER | OBJ_NOLOCK);
3690 if (mem) {
3691 /*
3692 * If found that means this member is currently being attempted
3693 * from another calling thread, so stop trying from this thread
3694 */
3695 ast_debug(1, "%s has another call trying, can't receive call\n",
3696 call->interface);
3697 ao2_ref(mem, -1);
3698 ao2_unlock(pending_members);
3699 return 0;
3700 }
3701
3702 /*
3703 * If not found add it to the container so another queue
3704 * won't attempt to call this member at the same time.
3705 */
3706 ao2_link(pending_members, call->member);
3707 ao2_unlock(pending_members);
3708
3709 /*
3710 * The queue member is available. Get current status to be sure
3711 * because the device state and extension state callbacks may
3712 * not have updated the status yet.
3713 */
3714 if (!member_status_available(get_queue_member_status(call->member))) {
3715 ast_debug(1, "%s actually not available, can't receive call\n",
3716 call->interface);
3717 pending_members_remove(call->member);
3718 return 0;
3719 }
3720 }
3721
3722 return 1;
3723}
3724
3725/*!
3726 * \brief Part 2 of ring_one
3727 *
3728 * Does error checking before attempting to request a channel and call a member.
3729 * This function is only called from ring_one().
3730 * Failure can occur if:
3731 * - Agent on call
3732 * - Agent is paused
3733 * - Wrapup time not expired
3734 * - Priority by another queue
3735 *
3736 * \retval 1 on success to reach a free agent
3737 * \retval 0 on failure to get agent.
3738 */
3739static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
3740{
3741 int res;
3742 int status;
3743 char tech[256];
3744 char *location;
3745 const char *macrocontext, *macroexten;
3746
3747 /* on entry here, we know that tmp->chan == NULL */
3748 if (!can_ring_entry(qe, tmp)) {
3749 if (ast_channel_cdr(qe->chan)) {
3750 ast_cdr_busy(ast_channel_cdr(qe->chan));
3751 }
3752 tmp->stillgoing = 0;
3753 ++*busies;
3754 return 0;
3755 }
3756
3757 ast_copy_string(tech, tmp->interface, sizeof(tech));
3758 if ((location = strchr(tech, '/'))) {
3759 *location++ = '\0';
3760 } else {
3761 location = "";
3762 }
3763
3764 /* Request the peer */
3765 tmp->chan = ast_request(tech, ast_channel_nativeformats(qe->chan), qe->chan, location, &status);
3766 if (!tmp->chan) { /* If we can't, just go on to the next call */
3767 ao2_lock(qe->parent);
3768 qe->parent->rrpos++;
3769 qe->linpos++;
3770 ao2_unlock(qe->parent);
3771
3772 pending_members_remove(tmp->member);
3773
3774 if (ast_channel_cdr(qe->chan)) {
3775 ast_cdr_busy(ast_channel_cdr(qe->chan));
3776 }
3777 tmp->stillgoing = 0;
3778 ++*busies;
3779 return 0;
3780 }
3781
3782 ast_channel_lock_both(tmp->chan, qe->chan);
3783
3784 if (qe->cancel_answered_elsewhere) {
3785 ast_channel_hangupcause_set(tmp->chan, AST_CAUSE_ANSWERED_ELSEWHERE);
3786 }
3787 ast_channel_appl_set(tmp->chan, "AppQueue");
3788 ast_channel_data_set(tmp->chan, "(Outgoing Line)");
3789 memset(ast_channel_whentohangup(tmp->chan), 0, sizeof(*ast_channel_whentohangup(tmp->chan)));
3790
3791 /* If the new channel has no callerid, try to guess what it should be */
3792 if (!ast_channel_caller(tmp->chan)->id.number.valid) {
3793 if (ast_channel_connected(qe->chan)->id.number.valid) {
3794 struct ast_party_caller caller;
3795
3796 ast_party_caller_set_init(&caller, ast_channel_caller(tmp->chan));
3797 caller.id = ast_channel_connected(qe->chan)->id;
3798 caller.ani = ast_channel_connected(qe->chan)->ani;
3799 ast_channel_set_caller_event(tmp->chan, &caller, NULL);
3800 } else if (!ast_strlen_zero(ast_channel_dialed(qe->chan)->number.str)) {
3801 ast_set_callerid(tmp->chan, ast_channel_dialed(qe->chan)->number.str, NULL, NULL);
3802 } else if (!ast_strlen_zero(S_OR(ast_channel_macroexten(qe->chan), ast_channel_exten(qe->chan)))) {
3803 ast_set_callerid(tmp->chan, S_OR(ast_channel_macroexten(qe->chan), ast_channel_exten(qe->chan)), NULL, NULL);
3804 }
3805 tmp->dial_callerid_absent = 1;
3806 }
3807
3808 ast_party_redirecting_copy(ast_channel_redirecting(tmp->chan), ast_channel_redirecting(qe->chan));
3809
3810 ast_channel_dialed(tmp->chan)->transit_network_select = ast_channel_dialed(qe->chan)->transit_network_select;
3811
3812 ast_connected_line_copy_from_caller(ast_channel_connected(tmp->chan), ast_channel_caller(qe->chan));
3813
3814 /* Inherit specially named variables from parent channel */
3815 ast_channel_inherit_variables(qe->chan, tmp->chan);
3816 ast_channel_datastore_inherit(qe->chan, tmp->chan);
3817
3818 /* Presense of ADSI CPE on outgoing channel follows ours */
3819 ast_channel_adsicpe_set(tmp->chan, ast_channel_adsicpe(qe->chan));
3820
3821 /* Inherit context and extension */
3822 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
3823 ast_channel_dialcontext_set(tmp->chan, ast_strlen_zero(macrocontext) ? ast_channel_context(qe->chan) : macrocontext);
3824 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
3825 if (!ast_strlen_zero(macroexten)) {
3826 ast_channel_exten_set(tmp->chan, macroexten);
3827 } else {
3828 ast_channel_exten_set(tmp->chan, ast_channel_exten(qe->chan));
3829 }
3830 if (ast_cdr_isset_unanswered()) {
3831 /* they want to see the unanswered dial attempts! */
3832 /* set up the CDR fields on all the CDRs to give sensical information */
3833 ast_cdr_setdestchan(ast_channel_cdr(tmp->chan), ast_channel_name(tmp->chan));
3834 strcpy(ast_channel_cdr(tmp->chan)->clid, ast_channel_cdr(qe->chan)->clid);
3835 strcpy(ast_channel_cdr(tmp->chan)->channel, ast_channel_cdr(qe->chan)->channel);
3836 strcpy(ast_channel_cdr(tmp->chan)->src, ast_channel_cdr(qe->chan)->src);
3837 strcpy(ast_channel_cdr(tmp->chan)->dst, ast_channel_exten(qe->chan));
3838 strcpy(ast_channel_cdr(tmp->chan)->dcontext, ast_channel_context(qe->chan));
3839 strcpy(ast_channel_cdr(tmp->chan)->lastapp, ast_channel_cdr(qe->chan)->lastapp);
3840 strcpy(ast_channel_cdr(tmp->chan)->lastdata, ast_channel_cdr(qe->chan)->lastdata);
3841 ast_channel_cdr(tmp->chan)->amaflags = ast_channel_cdr(qe->chan)->amaflags;
3842 strcpy(ast_channel_cdr(tmp->chan)->accountcode, ast_channel_cdr(qe->chan)->accountcode);
3843 strcpy(ast_channel_cdr(tmp->chan)->userfield, ast_channel_cdr(qe->chan)->userfield);
3844 }
3845
3846 ast_channel_unlock(tmp->chan);
3847 ast_channel_unlock(qe->chan);
3848
3849 /* Place the call, but don't wait on the answer */
3850 if ((res = ast_call(tmp->chan, location, 0))) {
3851 /* Again, keep going even if there's an error */
3852 ast_verb(3, "Couldn't call %s\n", tmp->interface);
3853 do_hang(tmp);
3854 pending_members_remove(tmp->member);
3855 ++*busies;
3856 return 0;
3857 }
3858
3859 if (qe->parent->eventwhencalled) {
3860 char vars[2048];
3861
3862 ast_channel_lock_both(tmp->chan, qe->chan);
3863
3864 /*** DOCUMENTATION
3865 <managerEventInstance>
3866 <synopsis>Raised when an Agent is notified of a member in the queue.</synopsis>
3867 <syntax>
3868 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
3869 <parameter name="AgentCalled">
3870 <para>The agent's technology or location.</para>
3871 </parameter>
3872 <parameter name="AgentName">
3873 <para>The name of the agent.</para>
3874 </parameter>
3875 <parameter name="Variable" required="no" multiple="yes">
3876 <para>Optional channel variables from the ChannelCalling channel</para>
3877 </parameter>
3878 </syntax>
3879 <see-also>
3880 <ref type="managerEvent">AgentRingNoAnswer</ref>
3881 <ref type="managerEvent">AgentComplete</ref>
3882 <ref type="managerEvent">AgentConnect</ref>
3883 </see-also>
3884 </managerEventInstance>
3885 ***/
3886 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
3887 "Queue: %s\r\n"
3888 "AgentCalled: %s\r\n"
3889 "AgentName: %s\r\n"
3890 "ChannelCalling: %s\r\n"
3891 "DestinationChannel: %s\r\n"
3892 "CallerIDNum: %s\r\n"
3893 "CallerIDName: %s\r\n"
3894 "ConnectedLineNum: %s\r\n"
3895 "ConnectedLineName: %s\r\n"
3896 "Context: %s\r\n"
3897 "Extension: %s\r\n"
3898 "Priority: %d\r\n"
3899 "Uniqueid: %s\r\n"
3900 "%s",
3901 qe->parent->name, tmp->interface, tmp->member->membername, ast_channel_name(qe->chan), ast_channel_name(tmp->chan),
3902 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),
3903 S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
3904 S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),
3905 S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
3906 ast_channel_context(qe->chan), ast_channel_exten(qe->chan), ast_channel_priority(qe->chan), ast_channel_uniqueid(qe->chan),
3907 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
3908
3909 ast_channel_unlock(tmp->chan);
3910 ast_channel_unlock(qe->chan);
3911
3912 ast_verb(3, "Called %s\n", tmp->interface);
3913 }
3914
3915 return 1;
3916}
3917
3918/*! \brief find the entry with the best metric, or NULL */
3919static struct callattempt *find_best(struct callattempt *outgoing)
3920{
3921 struct callattempt *best = NULL, *cur;
3922
3923 for (cur = outgoing; cur; cur = cur->q_next) {
3924 if (cur->stillgoing && /* Not already done */
3925 !cur->chan && /* Isn't already going */
3926 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
3927 best = cur;
3928 }
3929 }
3930
3931 return best;
3932}
3933
3934/*!
3935 * \brief Place a call to a queue member.
3936 *
3937 * Once metrics have been calculated for each member, this function is used
3938 * to place a call to the appropriate member (or members). The low-level
3939 * channel-handling and error detection is handled in ring_entry
3940 *
3941 * \retval 1 if a member was called successfully
3942 * \retval 0 otherwise
3943 */
3944static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
3945{
3946 int ret = 0;
3947
3948 while (ret == 0) {
3949 struct callattempt *best = find_best(outgoing);
3950 if (!best) {
3951 ast_debug(1, "Nobody left to try ringing in queue\n");
3952 break;
3953 }
3954 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
3955 struct callattempt *cur;
3956 /* Ring everyone who shares this best metric (for ringall) */
3957 for (cur = outgoing; cur; cur = cur->q_next) {
3958 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
3959 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
3960 ret |= ring_entry(qe, cur, busies);
3961 }
3962 }
3963 } else {
3964 /* Ring just the best channel */
3965 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
3966 ret = ring_entry(qe, best, busies);
3967 }
3968
3969 /* If we have timed out, break out */
3970 if (qe->expire && (time(NULL) >= qe->expire)) {
3971 ast_debug(1, "Queue timed out while ringing members.\n");
3972 ret = 0;
3973 break;
3974 }
3975 }
3976
3977 return ret;
3978}
3979
3980/*! \brief Search for best metric and add to Round Robbin queue */
3981static int store_next_rr(struct queue_ent *qe, struct callattempt *outgoing)
3982{
3983 struct callattempt *best = find_best(outgoing);
3984
3985 if (best) {
3986 /* Ring just the best channel */
3987 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
3988 qe->parent->rrpos = best->metric % 1000;
3989 } else {
3990 /* Just increment rrpos */
3991 if (qe->parent->wrapped) {
3992 /* No more channels, start over */
3993 qe->parent->rrpos = 0;
3994 } else {
3995 /* Prioritize next entry */
3996 qe->parent->rrpos++;
3997 }
3998 }
3999 qe->parent->wrapped = 0;
4000
4001 return 0;
4002}
4003
4004/*! \brief Search for best metric and add to Linear queue */
4005static int store_next_lin(struct queue_ent *qe, struct callattempt *outgoing)
4006{
4007 struct callattempt *best = find_best(outgoing);
4008
4009 if (best) {
4010 /* Ring just the best channel */
4011 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
4012 qe->linpos = best->metric % 1000;
4013 } else {
4014 /* Just increment rrpos */
4015 if (qe->linwrapped) {
4016 /* No more channels, start over */
4017 qe->linpos = 0;
4018 } else {
4019 /* Prioritize next entry */
4020 qe->linpos++;
4021 }
4022 }
4023 qe->linwrapped = 0;
4024
4025 return 0;
4026}
4027
4028/*! \brief Playback announcement to queued members if period has elapsed */
4029static int say_periodic_announcement(struct queue_ent *qe, int ringing)
4030{
4031 int res = 0;
4032 time_t now;
4033
4034 /* Get the current time */
4035 time(&now);
4036
4037 /* Check to see if it is time to announce */
4038 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency) {
4039 return 0;
4040 }
4041
4042 /* Stop the music on hold so we can play our own file */
4043 if (ringing) {
4044 ast_indicate(qe->chan,-1);
4045 } else {
4046 ast_moh_stop(qe->chan);
4047 }
4048
4049 ast_verb(3, "Playing periodic announcement\n");
4050
4051 if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) {
4052 qe->last_periodic_announce_sound = ((unsigned long) ast_random()) % qe->parent->numperiodicannounce;
4053 } else if (qe->last_periodic_announce_sound >= qe->parent->numperiodicannounce ||
4054 ast_str_strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]) == 0) {
4055 qe->last_periodic_announce_sound = 0;
4056 }
4057
4058 /* play the announcement */
4059 res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
4060
4061 if (res > 0 && !valid_exit(qe, res)) {
4062 res = 0;
4063 }
4064
4065 /* Resume Music on Hold if the caller is going to stay in the queue */
4066 if (!res) {
4067 if (ringing) {
4068 ast_indicate(qe->chan, AST_CONTROL_RINGING);
4069 } else {
4070 ast_moh_start(qe->chan, qe->moh, NULL);
4071 }
4072 }
4073
4074 /* update last_periodic_announce_time */
4075 if (qe->parent->relativeperiodicannounce) {
4076 time(&qe->last_periodic_announce_time);
4077 } else {
4078 qe->last_periodic_announce_time = now;
4079 }
4080
4081 /* Update the current periodic announcement to the next announcement */
4082 if (!qe->parent->randomperiodicannounce) {
4083 qe->last_periodic_announce_sound++;
4084 }
4085
4086 return res;
4087}
4088
4089/*! \brief Record that a caller gave up on waiting in queue */
4090static void record_abandoned(struct queue_ent *qe)
4091{
4092 set_queue_variables(qe->parent, qe->chan);
4093 ao2_lock(qe->parent);
4094 /*** DOCUMENTATION
4095 <managerEventInstance>
4096 <synopsis>Raised when an caller abandons the queue.</synopsis>
4097 <syntax>
4098 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
4099 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Join']/managerEventInstance/syntax/parameter[@name='Position'])" />
4100 <parameter name="OriginalPosition">
4101 <para>The channel's original position in the queue.</para>
4102 </parameter>
4103 <parameter name="HoldTime">
4104 <para>The time the channel was in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
4105 </parameter>
4106 </syntax>
4107 </managerEventInstance>
4108 ***/
4109 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
4110 "Queue: %s\r\n"
4111 "Uniqueid: %s\r\n"
4112 "Position: %d\r\n"
4113 "OriginalPosition: %d\r\n"
4114 "HoldTime: %d\r\n",
4115 qe->parent->name, ast_channel_uniqueid(qe->chan), qe->pos, qe->opos, (int)(time(NULL) - qe->start));
4116
4117 qe->parent->callsabandoned++;
4118 ao2_unlock(qe->parent);
4119}
4120
4121/*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
4122static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int autopause)
4123{
4124 ast_verb(3, "Nobody picked up in %d ms\n", rnatime);
4125
4126 /* Stop ringing, and resume MOH if specified */
4127 if (qe->ring_when_ringing) {
4128 ast_indicate(qe->chan, -1);
4129 ast_moh_start(qe->chan, qe->moh, NULL);
4130 }
4131
4132 if (qe->parent->eventwhencalled) {
4133 char vars[2048];
4134 /*** DOCUMENTATION
4135 <managerEventInstance>
4136 <synopsis>Raised when an agent is notified of a member in the queue and fails to answer.</synopsis>
4137 <syntax>
4138 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
4139 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
4140 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
4141 <parameter name="Member">
4142 <para>The queue member's channel technology or location.</para>
4143 </parameter>
4144 <parameter name="RingTime">
4145 <para>The time the agent was rung, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
4146 </parameter>
4147 </syntax>
4148 <see-also>
4149 <ref type="managerEvent">AgentCalled</ref>
4150 </see-also>
4151 </managerEventInstance>
4152 ***/
4153 manager_event(EVENT_FLAG_AGENT, "AgentRingNoAnswer",
4154 "Queue: %s\r\n"
4155 "Uniqueid: %s\r\n"
4156 "Channel: %s\r\n"
4157 "Member: %s\r\n"
4158 "MemberName: %s\r\n"
4159 "RingTime: %d\r\n"
4160 "%s",
4161 qe->parent->name,
4162 ast_channel_uniqueid(qe->chan),
4163 ast_channel_name(qe->chan),
4164 interface,
4165 membername,
4166 rnatime,
4167 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
4168 }
4169 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), membername, "RINGNOANSWER", "%d", rnatime);
4170 if (qe->parent->autopause != QUEUE_AUTOPAUSE_OFF && autopause) {
4171 if (qe->parent->autopausedelay > 0) {
4172 struct member *mem;
4173 ao2_lock(qe->parent);
4174 if ((mem = interface_exists(qe->parent, interface))) {
4175 time_t idletime = time(&idletime)-mem->lastcall;
4176 if ((mem->lastcall != 0) && (qe->parent->autopausedelay > idletime)) {
4177 ao2_unlock(qe->parent);
4178 ao2_ref(mem, -1);
4179 return;
4180 }
4181 ao2_ref(mem, -1);
4182 }
4183 ao2_unlock(qe->parent);
4184 }
4185 if (qe->parent->autopause == QUEUE_AUTOPAUSE_ON) {
4186 if (!set_member_paused(qe->parent->name, interface, "Auto-Pause", 1)) {
4187 ast_verb(3, "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n",
4188 interface, qe->parent->name);
4189 } else {
4190 ast_verb(3, "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
4191 }
4192 } else {
4193 /* If queue autopause is mode all, just don't send any queue to stop.
4194 * the function will stop in all queues */
4195 if (!set_member_paused("", interface, "Auto-Pause", 1)) {
4196 ast_verb(3, "Auto-Pausing Queue Member %s in all queues since they failed to answer on queue %s.\n",
4197 interface, qe->parent->name);
4198 } else {
4199 ast_verb(3, "Failed to pause Queue Member %s in all queues!\n", interface);
4200 }
4201 }
4202 }
4203 return;
4204}
4205
4206#define AST_MAX_WATCHERS 256
4207/*!
4208 * \brief Wait for a member to answer the call
4209 *
4210 * \param[in] qe the queue_ent corresponding to the caller in the queue
4211 * \param[in] outgoing the list of callattempts. Relevant ones will have their chan and stillgoing parameters non-zero
4212 * \param[in] to the amount of time (in milliseconds) to wait for a response
4213 * \param[out] digit if a user presses a digit to exit the queue, this is the digit the caller pressed
4214 * \param[in] prebusies number of busy members calculated prior to calling wait_for_answer
4215 * \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
4216 * \param[in] forwardsallowed used to detect if we should allow call forwarding, based on the 'i' option to Queue()
4217 *
4218 * \todo eventually all call forward logic should be intergerated into and replaced by ast_call_forward()
4219 */
4220static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed, int ringing)
4221{
4222 const char *queue = qe->parent->name;
4223 struct callattempt *o, *start = NULL, *prev = NULL;
4224 int status;
4225 int numbusies = prebusies;
4226 int numnochan = 0;
4227 int stillgoing = 0;
4228 int orig = *to;
4229 struct ast_frame *f;
4230 struct callattempt *peer = NULL;
4231 struct ast_channel *winner;
4232 struct ast_channel *in = qe->chan;
4233 char on[80] = "";
4234 char membername[80] = "";
4235 long starttime = 0;
4236 long endtime = 0;
4237#ifdef HAVE_EPOLL
4238 struct callattempt *epollo;
4239#endif
4240 struct ast_party_connected_line connected_caller;
4241 char *inchan_name;
4242 struct timeval start_time_tv = ast_tvnow();
4243
4244 ast_party_connected_line_init(&connected_caller);
4245
4246 ast_channel_lock(qe->chan);
4247 inchan_name = ast_strdupa(ast_channel_name(qe->chan));
4248 ast_channel_unlock(qe->chan);
4249
4250 starttime = (long) time(NULL);
4251#ifdef HAVE_EPOLL
4252 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
4253 if (epollo->chan) {
4254 ast_poll_channel_add(in, epollo->chan);
4255 }
4256 }
4257#endif
4258
4259 while ((*to = ast_remaining_ms(start_time_tv, orig)) && !peer) {
4260 int numlines, retry, pos = 1;
4261 struct ast_channel *watchers[AST_MAX_WATCHERS];
4262 watchers[0] = in;
4263 start = NULL;
4264
4265 for (retry = 0; retry < 2; retry++) {
4266 numlines = 0;
4267 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
4268 if (o->stillgoing) { /* Keep track of important channels */
4269 stillgoing = 1;
4270 if (o->chan) {
4271 if (pos < AST_MAX_WATCHERS) {
4272 watchers[pos++] = o->chan;
4273 }
4274 if (!start) {
4275 start = o;
4276 } else {
4277 prev->call_next = o;
4278 }
4279 prev = o;
4280 }
4281 }
4282 numlines++;
4283 }
4284 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
4285 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */) {
4286 break;
4287 }
4288 /* On "ringall" strategy we only move to the next penalty level
4289 when *all* ringing phones are done in the current penalty level */
4290 ring_one(qe, outgoing, &numbusies);
4291 /* and retry... */
4292 }
4293 if (pos == 1 /* not found */) {
4294 if (numlines == (numbusies + numnochan)) {
4295 ast_debug(1, "Everyone is busy at this time\n");
4296 } else {
4297 ast_debug(3, "No one is answering queue '%s' (%d numlines / %d busies / %d failed channels)\n", queue, numlines, numbusies, numnochan);
4298 }
4299 *to = 0;
4300 return NULL;
4301 }
4302
4303 /* Poll for events from both the incoming channel as well as any outgoing channels */
4304 winner = ast_waitfor_n(watchers, pos, to);
4305
4306 /* Service all of the outgoing channels */
4307 for (o = start; o; o = o->call_next) {
4308 /* We go with a fixed buffer here instead of using ast_strdupa. Using
4309 * ast_strdupa in a loop like this one can cause a stack overflow
4310 */
4311 char ochan_name[AST_CHANNEL_NAME];
4312
4313 if (o->chan) {
4314 ast_channel_lock(o->chan);
4315 ast_copy_string(ochan_name, ast_channel_name(o->chan), sizeof(ochan_name));
4316 ast_channel_unlock(o->chan);
4317 }
4318 if (o->stillgoing && (o->chan) && (ast_channel_state(o->chan) == AST_STATE_UP)) {
4319 if (!peer) {
4320 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
4321 if (!o->block_connected_update) {
4322 if (o->pending_connected_update) {
4323 if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
4324 ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
4325 ast_channel_update_connected_line(in, &o->connected, NULL);
4326 }
4327 } else if (!o->dial_callerid_absent) {
4328 ast_channel_lock(o->chan);
4329 ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(o->chan));
4330 ast_channel_unlock(o->chan);
4331 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
4332 if (ast_channel_connected_line_sub(o->chan, in, &connected_caller, 0) &&
4333 ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
4334 ast_channel_update_connected_line(in, &connected_caller, NULL);
4335 }
4336 ast_party_connected_line_free(&connected_caller);
4337 }
4338 }
4339 if (o->aoc_s_rate_list) {
4340 size_t encoded_size;
4341 struct ast_aoc_encoded *encoded;
4342 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
4343 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
4344 ast_aoc_destroy_encoded(encoded);
4345 }
4346 }
4347 peer = o;
4348 }
4349 } else if (o->chan && (o->chan == winner)) {
4350
4351 ast_copy_string(on, o->member->interface, sizeof(on));
4352 ast_copy_string(membername, o->member->membername, sizeof(membername));
4353
4354 /* Before processing channel, go ahead and check for forwarding */
4355 if (!ast_strlen_zero(ast_channel_call_forward(o->chan)) && !forwardsallowed) {
4356 ast_verb(3, "Forwarding %s to '%s' prevented.\n", inchan_name, ast_channel_call_forward(o->chan));
4357 numnochan++;
4358 do_hang(o);
4359 winner = NULL;
4360 continue;
4361 } else if (!ast_strlen_zero(ast_channel_call_forward(o->chan))) {
4362 struct ast_channel *original = o->chan;
4363 char tmpchan[256];
4364 char *stuff;
4365 char *tech;
4366
4367 ast_copy_string(tmpchan, ast_channel_call_forward(o->chan), sizeof(tmpchan));
4368 if ((stuff = strchr(tmpchan, '/'))) {
4369 *stuff++ = '\0';
4370 tech = tmpchan;
4371 } else {
4372 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", ast_channel_call_forward(o->chan), ast_channel_context(o->chan));
4373 stuff = tmpchan;
4374 tech = "Local";
4375 }
4376 if (!strcasecmp(tech, "Local")) {
4377 /*
4378 * Drop the connected line update block for local channels since
4379 * this is going to run dialplan and the user can change his
4380 * mind about what connected line information he wants to send.
4381 */
4382 o->block_connected_update = 0;
4383 }
4384
4385 ast_cel_report_event(in, AST_CEL_FORWARD, NULL, ast_channel_call_forward(o->chan), NULL);
4386
4387 ast_verb(3, "Now forwarding %s to '%s/%s' (thanks to %s)\n", inchan_name, tech, stuff, ochan_name);
4388 /* Setup parameters */
4389 o->chan = ast_request(tech, ast_channel_nativeformats(in), in, stuff, &status);
4390 if (!o->chan) {
4391 ast_log(LOG_NOTICE,
4392 "Forwarding failed to create channel to dial '%s/%s'\n",
4393 tech, stuff);
4394 o->stillgoing = 0;
4395 numnochan++;
4396 } else {
4397 ast_channel_lock_both(o->chan, original);
4398 ast_party_redirecting_copy(ast_channel_redirecting(o->chan),
4399 ast_channel_redirecting(original));
4400 ast_channel_unlock(o->chan);
4401 ast_channel_unlock(original);
4402
4403 ast_channel_lock_both(o->chan, in);
4404 ast_channel_inherit_variables(in, o->chan);
4405 ast_channel_datastore_inherit(in, o->chan);
4406
4407 if (o->pending_connected_update) {
4408 /*
4409 * Re-seed the callattempt's connected line information with
4410 * previously acquired connected line info from the queued
4411 * channel. The previously acquired connected line info could
4412 * have been set through the CONNECTED_LINE dialplan function.
4413 */
4414 o->pending_connected_update = 0;
4415 ast_party_connected_line_copy(&o->connected, ast_channel_connected(in));
4416 }
4417
4418 ast_channel_accountcode_set(o->chan, ast_channel_accountcode(in));
4419
4420 if (!ast_channel_redirecting(o->chan)->from.number.valid
4421 || ast_strlen_zero(ast_channel_redirecting(o->chan)->from.number.str)) {
4422 /*
4423 * The call was not previously redirected so it is
4424 * now redirected from this number.
4425 */
4426 ast_party_number_free(&ast_channel_redirecting(o->chan)->from.number);
4427 ast_party_number_init(&ast_channel_redirecting(o->chan)->from.number);
4428 ast_channel_redirecting(o->chan)->from.number.valid = 1;
4429 ast_channel_redirecting(o->chan)->from.number.str =
4430 ast_strdup(S_OR(ast_channel_macroexten(in), ast_channel_exten(in)));
4431 }
4432
4433 ast_channel_dialed(o->chan)->transit_network_select = ast_channel_dialed(in)->transit_network_select;
4434
4435 o->dial_callerid_absent = !ast_channel_caller(o->chan)->id.number.valid
4436 || ast_strlen_zero(ast_channel_caller(o->chan)->id.number.str);
4437 ast_connected_line_copy_from_caller(ast_channel_connected(o->chan),
4438 ast_channel_caller(in));
4439
4440 ast_channel_unlock(in);
4441 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL
4442 && !o->block_connected_update) {
4443 struct ast_party_redirecting redirecting;
4444
4445 /*
4446 * Redirecting updates to the caller make sense only on single
4447 * call at a time strategies.
4448 *
4449 * We must unlock o->chan before calling
4450 * ast_channel_redirecting_macro, because we put o->chan into
4451 * autoservice there. That is pretty much a guaranteed
4452 * deadlock. This is why the handling of o->chan's lock may
4453 * seem a bit unusual here.
4454 */
4455 ast_party_redirecting_init(&redirecting);
4456 ast_party_redirecting_copy(&redirecting, ast_channel_redirecting(o->chan));
4457 ast_channel_unlock(o->chan);
4458 if (ast_channel_redirecting_sub(o->chan, in, &redirecting, 0) &&
4459 ast_channel_redirecting_macro(o->chan, in, &redirecting, 1, 0)) {
4460 ast_channel_update_redirecting(in, &redirecting, NULL);
4461 }
4462 ast_party_redirecting_free(&redirecting);
4463 } else {
4464 ast_channel_unlock(o->chan);
4465 }
4466
4467 if (ast_call(o->chan, stuff, 0)) {
4468 ast_log(LOG_NOTICE, "Forwarding failed to dial '%s/%s'\n",
4469 tech, stuff);
4470 do_hang(o);
4471 numnochan++;
4472 }
4473 }
4474 /* Hangup the original channel now, in case we needed it */
4475 ast_hangup(winner);
4476 continue;
4477 }
4478 f = ast_read(winner);
4479 if (f) {
4480 if (f->frametype == AST_FRAME_CONTROL) {
4481 switch (f->subclass.integer) {
4482 case AST_CONTROL_ANSWER:
4483 /* This is our guy if someone answered. */
4484 if (!peer) {
4485 ast_verb(3, "%s answered %s\n", ochan_name, inchan_name);
4486 if (!o->block_connected_update) {
4487 if (o->pending_connected_update) {
4488 if (ast_channel_connected_line_sub(o->chan, in, &o->connected, 0) &&
4489 ast_channel_connected_line_macro(o->chan, in, &o->connected, 1, 0)) {
4490 ast_channel_update_connected_line(in, &o->connected, NULL);
4491 }
4492 } else if (!o->dial_callerid_absent) {
4493 ast_channel_lock(o->chan);
4494 ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(o->chan));
4495 ast_channel_unlock(o->chan);
4496 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
4497 if (ast_channel_connected_line_sub(o->chan, in, &connected_caller, 0) &&
4498 ast_channel_connected_line_macro(o->chan, in, &connected_caller, 1, 0)) {
4499 ast_channel_update_connected_line(in, &connected_caller, NULL);
4500 }
4501 ast_party_connected_line_free(&connected_caller);
4502 }
4503 }
4504 if (o->aoc_s_rate_list) {
4505 size_t encoded_size;
4506 struct ast_aoc_encoded *encoded;
4507 if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
4508 ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
4509 ast_aoc_destroy_encoded(encoded);
4510 }
4511 }
4512 peer = o;
4513 }
4514 break;
4515 case AST_CONTROL_BUSY:
4516 ast_verb(3, "%s is busy\n", ochan_name);
4517 if (ast_channel_cdr(in)) {
4518 ast_cdr_busy(ast_channel_cdr(in));
4519 }
4520 do_hang(o);
4521 endtime = (long) time(NULL);
4522 endtime -= starttime;
4523 rna(endtime * 1000, qe, on, membername, qe->parent->autopausebusy);
4524 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
4525 if (qe->parent->timeoutrestart) {
4526 start_time_tv = ast_tvnow();
4527 }
4528 /* Have enough time for a queue member to answer? */
4529 if (ast_remaining_ms(start_time_tv, orig) > 500) {
4530 ring_one(qe, outgoing, &numbusies);
4531 starttime = (long) time(NULL);
4532 }
4533 }
4534 numbusies++;
4535 break;
4536 case AST_CONTROL_CONGESTION:
4537 ast_verb(3, "%s is circuit-busy\n", ochan_name);
4538 if (ast_channel_cdr(in)) {
4539 ast_cdr_busy(ast_channel_cdr(in));
4540 }
4541 endtime = (long) time(NULL);
4542 endtime -= starttime;
4543 rna(endtime * 1000, qe, on, membername, qe->parent->autopauseunavail);
4544 do_hang(o);
4545 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
4546 if (qe->parent->timeoutrestart) {
4547 start_time_tv = ast_tvnow();
4548 }
4549 if (ast_remaining_ms(start_time_tv, orig) > 500) {
4550 ring_one(qe, outgoing, &numbusies);
4551 starttime = (long) time(NULL);
4552 }
4553 }
4554 numbusies++;
4555 break;
4556 case AST_CONTROL_RINGING:
4557 ast_verb(3, "%s is ringing\n", ochan_name);
4558
4559 /* Start ring indication when the channel is ringing, if specified */
4560 if (qe->ring_when_ringing) {
4561 ast_moh_stop(qe->chan);
4562 ast_indicate(qe->chan, AST_CONTROL_RINGING);
4563 }
4564 break;
4565 case AST_CONTROL_OFFHOOK:
4566 /* Ignore going off hook */
4567 break;
4568 case AST_CONTROL_CONNECTED_LINE:
4569 if (o->block_connected_update) {
4570 ast_verb(3, "Connected line update to %s prevented.\n", inchan_name);
4571 break;
4572 }
4573 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
4574 struct ast_party_connected_line connected;
4575
4576 ast_verb(3, "%s connected line has changed. Saving it until answer for %s\n", ochan_name, inchan_name);
4577 ast_party_connected_line_set_init(&connected, &o->connected);
4578 ast_connected_line_parse_data(f->data.ptr, f->datalen, &connected);
4579 ast_party_connected_line_set(&o->connected, &connected, NULL);
4580 ast_party_connected_line_free(&connected);
4581 o->pending_connected_update = 1;
4582 break;
4583 }
4584
4585 /*
4586 * Prevent using the CallerID from the outgoing channel since we
4587 * got a connected line update from it.
4588 */
4589 o->dial_callerid_absent = 1;
4590
4591 if (ast_channel_connected_line_sub(o->chan, in, f, 1) &&
4592 ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
4593 ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
4594 }
4595 break;
4596 case AST_CONTROL_AOC:
4597 {
4598 struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
4599 if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
4600 ast_aoc_destroy_decoded(o->aoc_s_rate_list);
4601 o->aoc_s_rate_list = decoded;
4602 } else {
4603 ast_aoc_destroy_decoded(decoded);
4604 }
4605 }
4606 break;
4607 case AST_CONTROL_REDIRECTING:
4608 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
4609 /*
4610 * Redirecting updates to the caller make sense only on single
4611 * call at a time strategies.
4612 */
4613 break;
4614 }
4615 if (o->block_connected_update) {
4616 ast_verb(3, "Redirecting update to %s prevented\n",
4617 inchan_name);
4618 break;
4619 }
4620 ast_verb(3, "%s redirecting info has changed, passing it to %s\n",
4621 ochan_name, inchan_name);
4622 if (ast_channel_redirecting_sub(o->chan, in, f, 1) &&
4623 ast_channel_redirecting_macro(o->chan, in, f, 1, 1)) {
4624 ast_indicate_data(in, AST_CONTROL_REDIRECTING, f->data.ptr, f->datalen);
4625 }
4626 break;
4627 case AST_CONTROL_PVT_CAUSE_CODE:
4628 ast_indicate_data(in, AST_CONTROL_PVT_CAUSE_CODE, f->data.ptr, f->datalen);
4629 break;
4630 default:
4631 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass.integer);
4632 break;
4633 }
4634 }
4635 ast_frfree(f);
4636 } else { /* ast_read() returned NULL */
4637 endtime = (long) time(NULL) - starttime;
4638 rna(endtime * 1000, qe, on, membername, 1);
4639 do_hang(o);
4640 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
4641 if (qe->parent->timeoutrestart) {
4642 start_time_tv = ast_tvnow();
4643 }
4644 if (ast_remaining_ms(start_time_tv, orig) > 500) {
4645 ring_one(qe, outgoing, &numbusies);
4646 starttime = (long) time(NULL);
4647 }
4648 }
4649 }
4650 }
4651 }
4652
4653 /* If we received an event from the caller, deal with it. */
4654 if (winner == in) {
4655 f = ast_read(in);
4656 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP))) {
4657 /* Got hung up */
4658 *to = -1;
4659 if (f) {
4660 if (f->data.uint32) {
4661 ast_channel_hangupcause_set(in, f->data.uint32);
4662 }
4663 ast_frfree(f);
4664 }
4665 return NULL;
4666 }
4667
4668 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass.integer == '*')) {
4669 ast_verb(3, "User hit %c to disconnect call.\n", f->subclass.integer);
4670 *to = 0;
4671 ast_frfree(f);
4672 return NULL;
4673 }
4674 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass.integer)) {
4675 ast_verb(3, "User pressed digit: %c\n", f->subclass.integer);
4676 *to = 0;
4677 *digit = f->subclass.integer;
4678 ast_frfree(f);
4679 return NULL;
4680 }
4681
4682 /* Send the frame from the in channel to all outgoing channels. */
4683 for (o = start; o; o = o->call_next) {
4684 if (!o->stillgoing || !o->chan) {
4685 /* This outgoing channel has died so don't send the frame to it. */
4686 continue;
4687 }
4688 switch (f->frametype) {
4689 case AST_FRAME_CONTROL:
4690 switch (f->subclass.integer) {
4691 case AST_CONTROL_CONNECTED_LINE:
4692 if (ast_channel_connected_line_sub(in, o->chan, f, 1) &&
4693 ast_channel_connected_line_macro(in, o->chan, f, 0, 1)) {
4694 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
4695 }
4696 break;
4697 case AST_CONTROL_REDIRECTING:
4698 if (ast_channel_redirecting_sub(in, o->chan, f, 1) &&
4699 ast_channel_redirecting_macro(in, o->chan, f, 0, 1)) {
4700 ast_indicate_data(o->chan, f->subclass.integer, f->data.ptr, f->datalen);
4701 }
4702 break;
4703 default:
4704 /* We are not going to do anything with this frame. */
4705 goto skip_frame;
4706 }
4707 break;
4708 default:
4709 /* We are not going to do anything with this frame. */
4710 goto skip_frame;
4711 }
4712 }
4713skip_frame:;
4714
4715 ast_frfree(f);
4716 }
4717 }
4718
4719 /* Make a position announcement, if enabled */
4720 if (qe->parent->announcefrequency && qe->parent->announce_to_first_user) {
4721 say_position(qe, ringing);
4722 }
4723
4724 /* Make a periodic announcement, if enabled */
4725 if (qe->parent->periodicannouncefrequency && qe->parent->announce_to_first_user) {
4726 say_periodic_announcement(qe, ringing);
4727 }
4728
4729 if (!*to) {
4730 for (o = start; o; o = o->call_next) {
4731 rna(orig, qe, o->interface, o->member->membername, 1);
4732 }
4733 }
4734
4735#ifdef HAVE_EPOLL
4736 for (epollo = outgoing; epollo; epollo = epollo->q_next) {
4737 if (epollo->chan) {
4738 ast_poll_channel_del(in, epollo->chan);
4739 }
4740 }
4741#endif
4742
4743 return peer;
4744}
4745
4746/*!
4747 * \brief Check if we should start attempting to call queue members.
4748 *
4749 * A simple process, really. Count the number of members who are available
4750 * to take our call and then see if we are in a position in the queue at
4751 * which a member could accept our call.
4752 *
4753 * \param[in] qe The caller who wants to know if it is his turn
4754 * \retval 0 It is not our turn
4755 * \retval 1 It is our turn
4756 */
4757static int is_our_turn(struct queue_ent *qe)
4758{
4759 struct queue_ent *ch;
4760 int res;
4761 int avl;
4762 int idx = 0;
4763 /* This needs a lock. How many members are available to be served? */
4764 ao2_lock(qe->parent);
4765
4766 avl = num_available_members(qe->parent);
4767
4768 ch = qe->parent->head;
4769
4770 ast_debug(1, "There %s %d available %s.\n", avl != 1 ? "are" : "is", avl, avl != 1 ? "members" : "member");
4771
4772 while ((idx < avl) && (ch) && (ch != qe)) {
4773 if (!ch->pending) {
4774 idx++;
4775 }
4776 ch = ch->next;
4777 }
4778
4779 ao2_unlock(qe->parent);
4780 /* If the queue entry is within avl [the number of available members] calls from the top ...
4781 * Autofill and position check added to support autofill=no (as only calls
4782 * from the front of the queue are valid when autofill is disabled)
4783 */
4784 if (ch && idx < avl && (qe->parent->autofill || qe->pos == 1)) {
4785 ast_debug(1, "It's our turn (%s).\n", ast_channel_name(qe->chan));
4786 res = 1;
4787 } else {
4788 ast_debug(1, "It's not our turn (%s).\n", ast_channel_name(qe->chan));
4789 res = 0;
4790 }
4791
4792 /* Update realtime members if this is the first call and number of avalable members is 0 */
4793 if (avl == 0 && qe->pos == 1) {
4794 update_realtime_members(qe->parent);
4795 }
4796
4797 return res;
4798}
4799
4800/*!
4801 * \brief update rules for queues
4802 *
4803 * Calculate min/max penalties making sure if relative they stay within bounds.
4804 * Update queues penalty and set dialplan vars, goto next list entry.
4805*/
4806static void update_qe_rule(struct queue_ent *qe)
4807{
4808 int max_penalty = INT_MAX;
4809
4810 if (qe->max_penalty != INT_MAX) {
4811 char max_penalty_str[20];
4812
4813 if (qe->pr->max_relative) {
4814 max_penalty = qe->max_penalty + qe->pr->max_value;
4815 } else {
4816 max_penalty = qe->pr->max_value;
4817 }
4818
4819 /* a relative change to the penalty could put it below 0 */
4820 if (max_penalty < 0) {
4821 max_penalty = 0;
4822 }
4823
4824 snprintf(max_penalty_str, sizeof(max_penalty_str), "%d", max_penalty);
4825 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MAX_PENALTY", max_penalty_str);
4826 qe->max_penalty = max_penalty;
4827 ast_debug(3, "Setting max penalty to %d for caller %s since %d seconds have elapsed\n",
4828 qe->max_penalty, ast_channel_name(qe->chan), qe->pr->time);
4829 }
4830
4831 if (qe->min_penalty != INT_MAX) {
4832 char min_penalty_str[20];
4833 int min_penalty;
4834
4835 if (qe->pr->min_relative) {
4836 min_penalty = qe->min_penalty + qe->pr->min_value;
4837 } else {
4838 min_penalty = qe->pr->min_value;
4839 }
4840
4841 /* a relative change to the penalty could put it below 0 */
4842 if (min_penalty < 0) {
4843 min_penalty = 0;
4844 }
4845
4846 if (max_penalty != INT_MAX && min_penalty > max_penalty) {
4847 min_penalty = max_penalty;
4848 }
4849
4850 snprintf(min_penalty_str, sizeof(min_penalty_str), "%d", min_penalty);
4851 pbx_builtin_setvar_helper(qe->chan, "QUEUE_MIN_PENALTY", min_penalty_str);
4852 qe->min_penalty = min_penalty;
4853 ast_debug(3, "Setting min penalty to %d for caller %s since %d seconds have elapsed\n",
4854 qe->min_penalty, ast_channel_name(qe->chan), qe->pr->time);
4855 }
4856
4857 qe->pr = AST_LIST_NEXT(qe->pr, list);
4858}
4859
4860/*! \brief The waiting areas for callers who are not actively calling members
4861 *
4862 * This function is one large loop. This function will return if a caller
4863 * either exits the queue or it becomes that caller's turn to attempt calling
4864 * queue members. Inside the loop, we service the caller with periodic announcements,
4865 * holdtime announcements, etc. as configured in queues.conf
4866 *
4867 * \retval 0 if the caller's turn has arrived
4868 * \retval -1 if the caller should exit the queue.
4869 */
4870static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
4871{
4872 int res = 0;
4873
4874 /* This is the holding pen for callers 2 through maxlen */
4875 for (;;) {
4876
4877 if (is_our_turn(qe)) {
4878 break;
4879 }
4880
4881 /* If we have timed out, break out */
4882 if (qe->expire && (time(NULL) >= qe->expire)) {
4883 *reason = QUEUE_TIMEOUT;
4884 break;
4885 }
4886
4887 if (qe->parent->leavewhenempty) {
4888 int status = 0;
4889
4890 if ((status = get_member_status(qe->parent, qe->max_penalty, qe->min_penalty, qe->parent->leavewhenempty, 0))) {
4891 *reason = QUEUE_LEAVEEMPTY;
4892 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));
4893 leave_queue(qe);
4894 break;
4895 }
4896 }
4897
4898 /* Make a position announcement, if enabled */
4899 if (qe->parent->announcefrequency &&
4900 (res = say_position(qe,ringing))) {
4901 break;
4902 }
4903
4904 /* If we have timed out, break out */
4905 if (qe->expire && (time(NULL) >= qe->expire)) {
4906 *reason = QUEUE_TIMEOUT;
4907 break;
4908 }
4909
4910 /* Make a periodic announcement, if enabled */
4911 if (qe->parent->periodicannouncefrequency &&
4912 (res = say_periodic_announcement(qe,ringing)))
4913 break;
4914
4915 /* see if we need to move to the next penalty level for this queue */
4916 while (qe->pr && ((time(NULL) - qe->start) >= qe->pr->time)) {
4917 update_qe_rule(qe);
4918 }
4919
4920 /* If we have timed out, break out */
4921 if (qe->expire && (time(NULL) >= qe->expire)) {
4922 *reason = QUEUE_TIMEOUT;
4923 break;
4924 }
4925
4926 /* Wait a second before checking again */
4927 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
4928 if (res > 0 && !valid_exit(qe, res)) {
4929 res = 0;
4930 } else {
4931 break;
4932 }
4933 }
4934
4935 /* If we have timed out, break out */
4936 if (qe->expire && (time(NULL) >= qe->expire)) {
4937 *reason = QUEUE_TIMEOUT;
4938 break;
4939 }
4940 }
4941
4942 return res;
4943}
4944
4945/*!
4946 * \brief update the queue status
4947 * \retval Always 0
4948*/
4949static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl, int newtalktime)
4950{
4951 int oldtalktime;
4952
4953 struct member *mem;
4954 struct call_queue *qtmp;
4955 struct ao2_iterator queue_iter;
4956
4957 if (shared_lastcall) {
4958 queue_iter = ao2_iterator_init(queues, 0);
4959 while ((qtmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
4960 ao2_lock(qtmp);
4961 if ((mem = ao2_find(qtmp->members, member, OBJ_POINTER))) {
4962 time(&mem->lastcall);
4963 mem->calls++;
4964 mem->lastqueue = q;
4965 mem->in_call = 0;
4966 ast_debug(4, "Marked member %s as NOT in_call. Lastcall time: %ld \n",
4967 mem->membername, (long)mem->lastcall);
4968 ao2_ref(mem, -1);
4969 }
4970 ao2_unlock(qtmp);
4971 queue_t_unref(qtmp, "Done with iterator");
4972 }
4973 ao2_iterator_destroy(&queue_iter);
4974 } else {
4975 ao2_lock(q);
4976 time(&member->lastcall);
4977 member->calls++;
4978 member->lastqueue = q;
4979 member->in_call = 0;
4980 ast_debug(4, "Marked member %s as NOT in_call. Lastcall time: %ld \n",
4981 member->membername, (long)member->lastcall);
4982 ao2_unlock(q);
4983 }
4984 ao2_lock(q);
4985 q->callscompleted++;
4986 if (callcompletedinsl) {
4987 q->callscompletedinsl++;
4988 }
4989 if (q->callscompletedinsl == 1) {
4990 q->talktime = newtalktime;
4991 } else {
4992 /* Calculate talktime using the same exponential average as holdtime code */
4993 oldtalktime = q->talktime;
4994 q->talktime = (((oldtalktime << 2) - oldtalktime) + newtalktime) >> 2;
4995 }
4996 ao2_unlock(q);
4997 return 0;
4998}
4999
5000/*! \brief Calculate the metric of each member in the outgoing callattempts
5001 *
5002 * A numeric metric is given to each member depending on the ring strategy used
5003 * by the queue. Members with lower metrics will be called before members with
5004 * higher metrics
5005 * \retval -1 if penalties are exceeded
5006 * \retval 0 otherwise
5007 */
5008static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
5009{
5010 /* disregarding penalty on too few members? */
5011 int membercount = ao2_container_count(q->members);
5012 unsigned char usepenalty = (membercount <= q->penaltymemberslimit) ? 0 : 1;
5013
5014 if (usepenalty) {
5015 if ((qe->max_penalty != INT_MAX && mem->penalty > qe->max_penalty) ||
5016 (qe->min_penalty != INT_MAX && mem->penalty < qe->min_penalty)) {
5017 return -1;
5018 }
5019 } else {
5020 ast_debug(1, "Disregarding penalty, %d members and %d in penaltymemberslimit.\n",
5021 membercount, q->penaltymemberslimit);
5022 }
5023
5024 switch (q->strategy) {
5025 case QUEUE_STRATEGY_RINGALL:
5026 /* Everyone equal, except for penalty */
5027 tmp->metric = mem->penalty * 1000000 * usepenalty;
5028 break;
5029 case QUEUE_STRATEGY_LINEAR:
5030 if (pos < qe->linpos) {
5031 tmp->metric = 1000 + pos;
5032 } else {
5033 if (pos > qe->linpos) {
5034 /* Indicate there is another priority */
5035 qe->linwrapped = 1;
5036 }
5037 tmp->metric = pos;
5038 }
5039 tmp->metric += mem->penalty * 1000000 * usepenalty;
5040 break;
5041 case QUEUE_STRATEGY_RRORDERED:
5042 case QUEUE_STRATEGY_RRMEMORY:
5043 pos = mem->queuepos;
5044 if (pos < q->rrpos) {
5045 tmp->metric = 1000 + pos;
5046 } else {
5047 if (pos > q->rrpos) {
5048 /* Indicate there is another priority */
5049 q->wrapped = 1;
5050 }
5051 tmp->metric = pos;
5052 }
5053 tmp->metric += mem->penalty * 1000000 * usepenalty;
5054 break;
5055 case QUEUE_STRATEGY_RANDOM:
5056 tmp->metric = ast_random() % 1000;
5057 tmp->metric += mem->penalty * 1000000 * usepenalty;
5058 break;
5059 case QUEUE_STRATEGY_WRANDOM:
5060 tmp->metric = ast_random() % ((1 + mem->penalty) * 1000);
5061 break;
5062 case QUEUE_STRATEGY_FEWESTCALLS:
5063 tmp->metric = mem->calls;
5064 tmp->metric += mem->penalty * 1000000 * usepenalty;
5065 break;
5066 case QUEUE_STRATEGY_LEASTRECENT:
5067 if (!mem->lastcall) {
5068 tmp->metric = 0;
5069 } else {
5070 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
5071 }
5072 tmp->metric += mem->penalty * 1000000 * usepenalty;
5073 break;
5074 default:
5075 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
5076 break;
5077 }
5078 return 0;
5079}
5080
5081enum agent_complete_reason {
5082 CALLER,
5083 AGENT,
5084 TRANSFER
5085};
5086
5087/*! \brief Send out AMI message with member call completion status information */
5088static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
5089 const struct ast_channel *peer, const struct member *member, time_t callstart,
5090 char *vars, size_t vars_len, enum agent_complete_reason rsn)
5091{
5092 const char *reason = NULL; /* silence dumb compilers */
5093
5094 if (!qe->parent->eventwhencalled) {
5095 return;
5096 }
5097
5098 switch (rsn) {
5099 case CALLER:
5100 reason = "caller";
5101 break;
5102 case AGENT:
5103 reason = "agent";
5104 break;
5105 case TRANSFER:
5106 reason = "transfer";
5107 break;
5108 }
5109
5110 /*** DOCUMENTATION
5111 <managerEventInstance>
5112 <synopsis>Raised when an agent has finished servicing a member in the queue.</synopsis>
5113 <syntax>
5114 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
5115 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='Member'])" />
5116 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
5117 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
5118 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
5119 <parameter name="TalkTime">
5120 <para>The time the agent talked with the member in the queue, expressed in seconds since 00:00, Jan 1, 1970 UTC.</para>
5121 </parameter>
5122 <parameter name="Reason">
5123 <enumlist>
5124 <enum name="caller"/>
5125 <enum name="agent"/>
5126 <enum name="transfer"/>
5127 </enumlist>
5128 </parameter>
5129 </syntax>
5130 <see-also>
5131 <ref type="managerEvent">AgentCalled</ref>
5132 <ref type="managerEvent">AgentConnect</ref>
5133 </see-also>
5134 </managerEventInstance>
5135 ***/
5136 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
5137 "Queue: %s\r\n"
5138 "Uniqueid: %s\r\n"
5139 "Channel: %s\r\n"
5140 "Member: %s\r\n"
5141 "MemberName: %s\r\n"
5142 "HoldTime: %ld\r\n"
5143 "TalkTime: %ld\r\n"
5144 "Reason: %s\r\n"
5145 "%s",
5146 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
5147 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
5148 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
5149}
5150
5151struct queue_transfer_ds {
5152 struct queue_ent *qe;
5153 struct member *member;
5154 time_t starttime;
5155 int callcompletedinsl;
5156};
5157
5158static void queue_transfer_destroy(void *data)
5159{
5160 struct queue_transfer_ds *qtds = data;
5161 ast_free(qtds);
5162}
5163
5164/*! \brief a datastore used to help correctly log attended transfers of queue callers
5165 */
5166static const struct ast_datastore_info queue_transfer_info = {
5167 .type = "queue_transfer",
5168 .chan_fixup = queue_transfer_fixup,
5169 .destroy = queue_transfer_destroy,
5170};
5171
5172/*! \brief Log an attended transfer when a queue caller channel is masqueraded
5173 *
5174 * When a caller is masqueraded, we want to log a transfer. Fixup time is the closest we can come to when
5175 * the actual transfer occurs. This happens during the masquerade after datastores are moved from old_chan
5176 * to new_chan. This is why new_chan is referenced for exten, context, and datastore information.
5177 *
5178 * At the end of this, we want to remove the datastore so that this fixup function is not called on any
5179 * future masquerades of the caller during the current call.
5180 */
5181static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
5182{
5183 struct queue_transfer_ds *qtds = data;
5184 struct queue_ent *qe = qtds->qe;
5185 struct member *member = qtds->member;
5186 time_t callstart = qtds->starttime;
5187 int callcompletedinsl = qtds->callcompletedinsl;
5188 struct ast_datastore *datastore;
5189
5190 ast_queue_log(qe->parent->name, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
5191 ast_channel_exten(new_chan), ast_channel_context(new_chan), (long) (callstart - qe->start),
5192 (long) (time(NULL) - callstart), qe->opos);
5193
5194 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
5195
5196 /* No need to lock the channels because they are already locked in ast_do_masquerade */
5197 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
5198 ast_channel_datastore_remove(old_chan, datastore);
5199 /* Datastore is freed in try_calling() */
5200 } else {
5201 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
5202 }
5203}
5204
5205/*! \brief mechanism to tell if a queue caller was atxferred by a queue member.
5206 *
5207 * When a caller is atxferred, then the queue_transfer_info datastore
5208 * is removed from the channel. If it's still there after the bridge is
5209 * broken, then the caller was not atxferred.
5210 *
5211 * \note Only call this with chan locked
5212 */
5213static int attended_transfer_occurred(struct ast_channel *chan)
5214{
5215 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
5216}
5217
5218/*! \brief create a datastore for storing relevant info to log attended transfers in the queue_log
5219 */
5220static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
5221{
5222 struct ast_datastore *ds;
5223 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
5224
5225 if (!qtds) {
5226 ast_log(LOG_WARNING, "Memory allocation error!\n");
5227 return NULL;
5228 }
5229
5230 ast_channel_lock(qe->chan);
5231 if (!(ds = ast_datastore_alloc(&queue_transfer_info, NULL))) {
5232 ast_channel_unlock(qe->chan);
5233 ast_free(qtds);
5234 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
5235 return NULL;
5236 }
5237
5238 qtds->qe = qe;
5239 /* This member is refcounted in try_calling, so no need to add it here, too */
5240 qtds->member = member;
5241 qtds->starttime = starttime;
5242 qtds->callcompletedinsl = callcompletedinsl;
5243 ds->data = qtds;
5244 ast_channel_datastore_add(qe->chan, ds);
5245 ast_channel_unlock(qe->chan);
5246 return ds;
5247}
5248
5249struct queue_end_bridge {
5250 struct call_queue *q;
5251 struct ast_channel *chan;
5252};
5253
5254static void end_bridge_callback_data_fixup(struct ast_bridge_config *bconfig, struct ast_channel *originator, struct ast_channel *terminator)
5255{
5256 struct queue_end_bridge *qeb = bconfig->end_bridge_callback_data;
5257 ao2_ref(qeb, +1);
5258 qeb->chan = originator;
5259}
5260
5261static void end_bridge_callback(void *data)
5262{
5263 struct queue_end_bridge *qeb = data;
5264 struct call_queue *q = qeb->q;
5265 struct ast_channel *chan = qeb->chan;
5266
5267 if (ao2_ref(qeb, -1) == 1) {
5268 set_queue_variables(q, chan);
5269 /* This unrefs the reference we made in try_calling when we allocated qeb */
5270 queue_t_unref(q, "Expire bridge_config reference");
5271 }
5272}
5273
5274/*!
5275 * \internal
5276 * \brief A large function which calls members, updates statistics, and bridges the caller and a member
5277 *
5278 * Here is the process of this function
5279 * 1. Process any options passed to the Queue() application. Options here mean the third argument to Queue()
5280 * 2. Iterate trough the members of the queue, creating a callattempt corresponding to each member. During this
5281 * iteration, we also check the dialed_interfaces datastore to see if we have already attempted calling this
5282 * member. If we have, we do not create a callattempt. This is in place to prevent call forwarding loops. Also
5283 * during each iteration, we call calc_metric to determine which members should be rung when.
5284 * 3. Call ring_one to place a call to the appropriate member(s)
5285 * 4. Call wait_for_answer to wait for an answer. If no one answers, return.
5286 * 5. Take care of any holdtime announcements, member delays, or other options which occur after a call has been answered.
5287 * 6. Start the monitor or mixmonitor if the option is set
5288 * 7. Remove the caller from the queue to allow other callers to advance
5289 * 8. Bridge the call.
5290 * 9. Do any post processing after the call has disconnected.
5291 *
5292 * \param[in] qe the queue_ent structure which corresponds to the caller attempting to reach members
5293 * \param[in] opts the options passed as the third parameter to the Queue() application
5294 * \param[in] opt_args the options passed as the third parameter to the Queue() application
5295 * \param[in] announceoverride filename to play to user when waiting
5296 * \param[in] url the url passed as the fourth parameter to the Queue() application
5297 * \param[in,out] tries the number of times we have tried calling queue members
5298 * \param[out] noption set if the call to Queue() has the 'n' option set.
5299 * \param[in] agi the agi passed as the fifth parameter to the Queue() application
5300 * \param[in] macro the macro passed as the sixth parameter to the Queue() application
5301 * \param[in] gosub the gosub passed as the seventh parameter to the Queue() application
5302 * \param[in] ringing 1 if the 'r' option is set, otherwise 0
5303 */
5304static int try_calling(struct queue_ent *qe, const struct ast_flags opts, char **opt_args, char *announceoverride, const char *url, int *tries, int *noption, const char *agi, const char *macro, const char *gosub, int ringing)
5305{
5306 struct member *cur;
5307 struct callattempt *outgoing = NULL; /* the list of calls we are building */
5308 int to, orig;
5309 char oldexten[AST_MAX_EXTENSION]="";
5310 char oldcontext[AST_MAX_CONTEXT]="";
5311 char queuename[256]="";
5312 char interfacevar[256]="";
5313 struct ast_channel *peer;
5314 struct ast_channel *which;
5315 struct callattempt *lpeer;
5316 struct member *member;
5317 struct ast_app *application;
5318 int res = 0, bridge = 0;
5319 int numbusies = 0;
5320 int x=0;
5321 char *announce = NULL;
5322 char digit = 0;
5323 time_t callstart;
5324 time_t now = time(NULL);
5325 struct ast_bridge_config bridge_config;
5326 char nondataquality = 1;
5327 char *agiexec = NULL;
5328 char *macroexec = NULL;
5329 char *gosubexec = NULL;
5330 const char *monitorfilename;
5331 const char *monitor_exec;
5332 const char *monitor_options;
5333 char tmpid[256], tmpid2[256];
5334 char meid[1024], meid2[1024];
5335 char mixmonargs[1512];
5336 struct ast_app *mixmonapp = NULL;
5337 char *p;
5338 char vars[2048];
5339 int forwardsallowed = 1;
5340 int block_connected_line = 0;
5341 int callcompletedinsl;
5342 struct ao2_iterator memi;
5343 struct ast_datastore *datastore, *transfer_ds;
5344 struct queue_end_bridge *queue_end_bridge = NULL;
5345 struct ao2_iterator queue_iter; /* to iterate through all queues (for shared_lastcall)*/
5346 struct member *mem;
5347 struct call_queue *queuetmp;
5348
5349 ast_channel_lock(qe->chan);
5350 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
5351 ast_channel_unlock(qe->chan);
5352
5353 memset(&bridge_config, 0, sizeof(bridge_config));
5354 tmpid[0] = 0;
5355 meid[0] = 0;
5356 time(&now);
5357
5358 /* If we've already exceeded our timeout, then just stop
5359 * This should be extremely rare. queue_exec will take care
5360 * of removing the caller and reporting the timeout as the reason.
5361 */
5362 if (qe->expire && now >= qe->expire) {
5363 res = 0;
5364 goto out;
5365 }
5366
5367 if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER)) {
5368 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
5369 }
5370 if (ast_test_flag(&opts, OPT_CALLER_TRANSFER)) {
5371 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
5372 }
5373 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMON)) {
5374 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
5375 }
5376 if (ast_test_flag(&opts, OPT_CALLER_AUTOMON)) {
5377 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
5378 }
5379 if (ast_test_flag(&opts, OPT_GO_ON)) {
5380 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_NO_H_EXTEN);
5381 }
5382 if (ast_test_flag(&opts, OPT_DATA_QUALITY)) {
5383 nondataquality = 0;
5384 }
5385 if (ast_test_flag(&opts, OPT_CALLEE_HANGUP)) {
5386 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
5387 }
5388 if (ast_test_flag(&opts, OPT_CALLER_HANGUP)) {
5389 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
5390 }
5391 if (ast_test_flag(&opts, OPT_CALLEE_PARK)) {
5392 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_PARKCALL);
5393 }
5394 if (ast_test_flag(&opts, OPT_CALLER_PARK)) {
5395 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_PARKCALL);
5396 }
5397 if (ast_test_flag(&opts, OPT_NO_RETRY)) {
5398 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_LINEAR
5399 || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
5400 (*tries)++;
5401 } else {
5402 *tries = ao2_container_count(qe->parent->members);
5403 }
5404 *noption = 1;
5405 }
5406 if (ast_test_flag(&opts, OPT_IGNORE_CALL_FW)) {
5407 forwardsallowed = 0;
5408 }
5409 if (ast_test_flag(&opts, OPT_IGNORE_CONNECTEDLINE)) {
5410 block_connected_line = 1;
5411 }
5412 if (ast_test_flag(&opts, OPT_CALLEE_AUTOMIXMON)) {
5413 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMIXMON);
5414 }
5415 if (ast_test_flag(&opts, OPT_CALLER_AUTOMIXMON)) {
5416 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMIXMON);
5417 }
5418 if (ast_test_flag(&opts, OPT_MARK_AS_ANSWERED)) {
5419 qe->cancel_answered_elsewhere = 1;
5420 }
5421
5422 /* if the calling channel has AST_CAUSE_ANSWERED_ELSEWHERE set, make sure this is inherited.
5423 (this is mainly to support chan_local)
5424 */
5425 if (ast_channel_hangupcause(qe->chan) == AST_CAUSE_ANSWERED_ELSEWHERE) {
5426 qe->cancel_answered_elsewhere = 1;
5427 }
5428
5429 ao2_lock(qe->parent);
5430 ast_debug(1, "%s is trying to call a queue member.\n",
5431 ast_channel_name(qe->chan));
5432 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
5433 if (!ast_strlen_zero(qe->announce)) {
5434 announce = qe->announce;
5435 }
5436 if (!ast_strlen_zero(announceoverride)) {
5437 announce = announceoverride;
5438 }
5439
5440 memi = ao2_iterator_init(qe->parent->members, 0);
5441 while ((cur = ao2_iterator_next(&memi))) {
5442 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
5443 struct ast_dialed_interface *di;
5444 AST_LIST_HEAD(,ast_dialed_interface) *dialed_interfaces;
5445 if (!tmp) {
5446 ao2_ref(cur, -1);
5447 ao2_iterator_destroy(&memi);
5448 ao2_unlock(qe->parent);
5449 goto out;
5450 }
5451 if (!datastore) {
5452 if (!(datastore = ast_datastore_alloc(&dialed_interface_info, NULL))) {
5453 callattempt_free(tmp);
5454 ao2_ref(cur, -1);
5455 ao2_iterator_destroy(&memi);
5456 ao2_unlock(qe->parent);
5457 goto out;
5458 }
5459 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
5460 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
5461 callattempt_free(tmp);
5462 ao2_ref(cur, -1);
5463 ao2_iterator_destroy(&memi);
5464 ao2_unlock(qe->parent);
5465 goto out;
5466 }
5467 datastore->data = dialed_interfaces;
5468 AST_LIST_HEAD_INIT(dialed_interfaces);
5469
5470 ast_channel_lock(qe->chan);
5471 ast_channel_datastore_add(qe->chan, datastore);
5472 ast_channel_unlock(qe->chan);
5473 } else
5474 dialed_interfaces = datastore->data;
5475
5476 AST_LIST_LOCK(dialed_interfaces);
5477 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
5478 if (!strcasecmp(cur->interface, di->interface)) {
5479 ast_debug(1, "Skipping dialing interface '%s' since it has already been dialed\n",
5480 di->interface);
5481 break;
5482 }
5483 }
5484 AST_LIST_UNLOCK(dialed_interfaces);
5485
5486 if (di) {
5487 callattempt_free(tmp);
5488 ao2_ref(cur, -1);
5489 continue;
5490 }
5491
5492 /* It is always ok to dial a Local interface. We only keep track of
5493 * which "real" interfaces have been dialed. The Local channel will
5494 * inherit this list so that if it ends up dialing a real interface,
5495 * it won't call one that has already been called. */
5496 if (strncasecmp(cur->interface, "Local/", 6)) {
5497 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
5498 callattempt_free(tmp);
5499 ao2_ref(cur, -1);
5500 ao2_iterator_destroy(&memi);
5501 ao2_unlock(qe->parent);
5502 goto out;
5503 }
5504 strcpy(di->interface, cur->interface);
5505
5506 AST_LIST_LOCK(dialed_interfaces);
5507 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
5508 AST_LIST_UNLOCK(dialed_interfaces);
5509 }
5510
5511 /*
5512 * Seed the callattempt's connected line information with previously
5513 * acquired connected line info from the queued channel. The
5514 * previously acquired connected line info could have been set
5515 * through the CONNECTED_LINE dialplan function.
5516 */
5517 ast_channel_lock(qe->chan);
5518 ast_party_connected_line_copy(&tmp->connected, ast_channel_connected(qe->chan));
5519 ast_channel_unlock(qe->chan);
5520
5521 tmp->block_connected_update = block_connected_line;
5522 tmp->stillgoing = 1;
5523 tmp->member = cur;/* Place the reference for cur into callattempt. */
5524 tmp->lastcall = cur->lastcall;
5525 tmp->lastqueue = cur->lastqueue;
5526 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
5527 /* Special case: If we ring everyone, go ahead and ring them, otherwise
5528 just calculate their metric for the appropriate strategy */
5529 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
5530 /* Put them in the list of outgoing thingies... We're ready now.
5531 XXX If we're forcibly removed, these outgoing calls won't get
5532 hung up XXX */
5533 tmp->q_next = outgoing;
5534 outgoing = tmp;
5535 /* If this line is up, don't try anybody else */
5536 if (outgoing->chan && (ast_channel_state(outgoing->chan) == AST_STATE_UP))
5537 break;
5538 } else {
5539 callattempt_free(tmp);
5540 }
5541 }
5542 ao2_iterator_destroy(&memi);
5543
5544 if (qe->parent->timeoutpriority == TIMEOUT_PRIORITY_APP) {
5545 /* Application arguments have higher timeout priority (behaviour for <=1.6) */
5546 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout)) {
5547 to = (qe->expire - now) * 1000;
5548 } else {
5549 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
5550 }
5551 } else {
5552 /* Config timeout is higher priority thatn application timeout */
5553 if (qe->expire && qe->expire<=now) {
5554 to = 0;
5555 } else if (qe->parent->timeout) {
5556 to = qe->parent->timeout * 1000;
5557 } else {
5558 to = -1;
5559 }
5560 }
5561 orig = to;
5562 ++qe->pending;
5563 ao2_unlock(qe->parent);
5564 ring_one(qe, outgoing, &numbusies);
5565 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies,
5566 ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT),
5567 forwardsallowed, ringing);
5568 /* The ast_channel_datastore_remove() function could fail here if the
5569 * datastore was moved to another channel during a masquerade. If this is
5570 * the case, don't free the datastore here because later, when the channel
5571 * to which the datastore was moved hangs up, it will attempt to free this
5572 * datastore again, causing a crash
5573 */
5574 ast_channel_lock(qe->chan);
5575 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
5576 ast_datastore_free(datastore);
5577 }
5578 ast_channel_unlock(qe->chan);
5579 ao2_lock(qe->parent);
5580 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY || qe->parent->strategy == QUEUE_STRATEGY_RRORDERED) {
5581 store_next_rr(qe, outgoing);
5582
5583 }
5584 if (qe->parent->strategy == QUEUE_STRATEGY_LINEAR) {
5585 store_next_lin(qe, outgoing);
5586 }
5587 ao2_unlock(qe->parent);
5588 peer = lpeer ? lpeer->chan : NULL;
5589 if (!peer) {
5590 qe->pending = 0;
5591 if (to) {
5592 /* Must gotten hung up */
5593 res = -1;
5594 } else {
5595 /* User exited by pressing a digit */
5596 res = digit;
5597 }
5598 if (res == -1) {
5599 ast_debug(1, "%s: Nobody answered.\n", ast_channel_name(qe->chan));
5600 }
5601 if (ast_cdr_isset_unanswered()) {
5602 /* channel contains the name of one of the outgoing channels
5603 in its CDR; zero out this CDR to avoid a dual-posting */
5604 struct callattempt *o;
5605 for (o = outgoing; o; o = o->q_next) {
5606 if (!o->chan) {
5607 continue;
5608 }
5609 if (strcmp(ast_channel_cdr(o->chan)->dstchannel, ast_channel_cdr(qe->chan)->dstchannel) == 0) {
5610 ast_set_flag(ast_channel_cdr(o->chan), AST_CDR_FLAG_POST_DISABLED);
5611 break;
5612 }
5613 }
5614 }
5615 } else { /* peer is valid */
5616 /* These variables are used with the F option without arguments (callee jumps to next priority after queue) */
5617 char *caller_context;
5618 char *caller_extension;
5619 int caller_priority;
5620
5621 /* Ah ha! Someone answered within the desired timeframe. Of course after this
5622 we will always return with -1 so that it is hung up properly after the
5623 conversation. */
5624 if (!strcmp(ast_channel_tech(qe->chan)->type, "DAHDI")) {
5625 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
5626 }
5627 if (!strcmp(ast_channel_tech(peer)->type, "DAHDI")) {
5628 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
5629 }
5630 /* Update parameters for the queue */
5631 time(&now);
5632 recalc_holdtime(qe, (now - qe->start));
5633 ao2_lock(qe->parent);
5634 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
5635 ao2_unlock(qe->parent);
5636 member = lpeer->member;
5637 /* Increment the refcount for this member, since we're going to be using it for awhile in here. */
5638 ao2_ref(member, 1);
5639 hangupcalls(outgoing, peer, qe->cancel_answered_elsewhere);
5640 outgoing = NULL;
5641 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
5642 int res2;
5643
5644 res2 = ast_autoservice_start(qe->chan);
5645 if (!res2) {
5646 if (qe->parent->memberdelay) {
5647 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
5648 res2 = ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
5649 }
5650 if (!res2 && announce) {
5651 if (play_file(peer, announce) < 0) {
5652 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, ast_channel_name(peer));
5653 }
5654 }
5655 if (!res2 && qe->parent->reportholdtime) {
5656 if (!play_file(peer, qe->parent->sound_reporthold)) {
5657 long holdtime, holdtimesecs;
5658
5659 time(&now);
5660 holdtime = labs((now - qe->start) / 60);
5661 holdtimesecs = labs((now - qe->start) % 60);
5662 if (holdtime > 0) {
5663 ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
5664 if (play_file(peer, qe->parent->sound_minutes) < 0) {
5665 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, ast_channel_name(peer));
5666 }
5667 }
5668 if (holdtimesecs > 1) {
5669 ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
5670 if (play_file(peer, qe->parent->sound_seconds) < 0) {
5671 ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, ast_channel_name(peer));
5672 }
5673 }
5674 }
5675 }
5676 ast_autoservice_stop(qe->chan);
5677 }
5678 if (ast_check_hangup(peer)) {
5679 /* Agent must have hung up */
5680 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", ast_channel_name(peer));
5681 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "AGENTDUMP", "%s", "");
5682 if (qe->parent->eventwhencalled)
5683 /*** DOCUMENTATION
5684 <managerEventInstance>
5685 <synopsis>Raised when an agent hangs up on a member in the queue.</synopsis>
5686 <syntax>
5687 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
5688 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='Member'])" />
5689 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
5690 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
5691 </syntax>
5692 <see-also>
5693 <ref type="managerEvent">AgentCalled</ref>
5694 <ref type="managerEvent">AgentConnect</ref>
5695 </see-also>
5696 </managerEventInstance>
5697 ***/
5698 manager_event(EVENT_FLAG_AGENT, "AgentDump",
5699 "Queue: %s\r\n"
5700 "Uniqueid: %s\r\n"
5701 "Channel: %s\r\n"
5702 "Member: %s\r\n"
5703 "MemberName: %s\r\n"
5704 "%s",
5705 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
5706 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
5707 ast_autoservice_chan_hangup_peer(qe->chan, peer);
5708 ao2_ref(member, -1);
5709 goto out;
5710 } else if (ast_check_hangup(qe->chan)) {
5711 /* Caller must have hung up just before being connected */
5712 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", ast_channel_name(peer));
5713 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) (time(NULL) - qe->start));
5714 record_abandoned(qe);
5715 ast_autoservice_chan_hangup_peer(qe->chan, peer);
5716 ao2_ref(member, -1);
5717 return -1;
5718 }
5719 }
5720 /* Stop music on hold */
5721 if (ringing) {
5722 ast_indicate(qe->chan,-1);
5723 } else {
5724 ast_moh_stop(qe->chan);
5725 }
5726 /* If appropriate, log that we have a destination channel */
5727 if (ast_channel_cdr(qe->chan)) {
5728 ast_cdr_setdestchan(ast_channel_cdr(qe->chan), ast_channel_name(peer));
5729 }
5730 /* Make sure channels are compatible */
5731 res = ast_channel_make_compatible(qe->chan, peer);
5732 if (res < 0) {
5733 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "SYSCOMPAT", "%s", "");
5734 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));
5735 record_abandoned(qe);
5736 ast_cdr_failed(ast_channel_cdr(qe->chan));
5737 ast_autoservice_chan_hangup_peer(qe->chan, peer);
5738 ao2_ref(member, -1);
5739 return -1;
5740 }
5741
5742 /* Play announcement to the caller telling it's his turn if defined */
5743 if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
5744 if (play_file(qe->chan, qe->parent->sound_callerannounce)) {
5745 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
5746 }
5747 }
5748
5749 ao2_lock(qe->parent);
5750 /* if setinterfacevar is defined, make member variables available to the channel */
5751 /* use pbx_builtin_setvar to set a load of variables with one call */
5752 if (qe->parent->setinterfacevar) {
5753 snprintf(interfacevar, sizeof(interfacevar), "MEMBERINTERFACE=%s,MEMBERNAME=%s,MEMBERCALLS=%d,MEMBERLASTCALL=%ld,MEMBERPENALTY=%d,MEMBERDYNAMIC=%d,MEMBERREALTIME=%d",
5754 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic, member->realtime);
5755 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
5756 pbx_builtin_setvar_multiple(peer, interfacevar);
5757 }
5758
5759 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
5760 /* use pbx_builtin_setvar to set a load of variables with one call */
5761 if (qe->parent->setqueueentryvar) {
5762 snprintf(interfacevar, sizeof(interfacevar), "QEHOLDTIME=%ld,QEORIGINALPOS=%d",
5763 (long) (time(NULL) - qe->start), qe->opos);
5764 pbx_builtin_setvar_multiple(qe->chan, interfacevar);
5765 pbx_builtin_setvar_multiple(peer, interfacevar);
5766 }
5767
5768 ao2_unlock(qe->parent);
5769
5770 /* try to set queue variables if configured to do so*/
5771 set_queue_variables(qe->parent, qe->chan);
5772 set_queue_variables(qe->parent, peer);
5773
5774 ast_channel_lock(qe->chan);
5775 /* Copy next destination data for 'F' option (no args) */
5776 caller_context = ast_strdupa(ast_channel_context(qe->chan));
5777 caller_extension = ast_strdupa(ast_channel_exten(qe->chan));
5778 caller_priority = ast_channel_priority(qe->chan);
5779 if ((monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"))) {
5780 monitorfilename = ast_strdupa(monitorfilename);
5781 }
5782 ast_channel_unlock(qe->chan);
5783
5784 /* Begin Monitoring */
5785 if (*qe->parent->monfmt) {
5786 if (!qe->parent->montype) {
5787 const char *monexec;
5788 ast_debug(1, "Starting Monitor as requested.\n");
5789 ast_channel_lock(qe->chan);
5790 if ((monexec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC")) || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) {
5791 which = qe->chan;
5792 monexec = monexec ? ast_strdupa(monexec) : NULL;
5793 } else {
5794 which = peer;
5795 }
5796 ast_channel_unlock(qe->chan);
5797 if (monitorfilename) {
5798 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1, X_REC_IN | X_REC_OUT);
5799 } else if (ast_channel_cdr(qe->chan)) {
5800 ast_monitor_start(which, qe->parent->monfmt, ast_channel_cdr(qe->chan)->uniqueid, 1, X_REC_IN | X_REC_OUT);
5801 } else {
5802 /* Last ditch effort -- no CDR, make up something */
5803 snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
5804 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1, X_REC_IN | X_REC_OUT);
5805 }
5806 if (!ast_strlen_zero(monexec)) {
5807 ast_monitor_setjoinfiles(which, 1);
5808 }
5809 } else {
5810 mixmonapp = pbx_findapp("MixMonitor");
5811
5812 if (mixmonapp) {
5813 ast_debug(1, "Starting MixMonitor as requested.\n");
5814 if (!monitorfilename) {
5815 if (ast_channel_cdr(qe->chan)) {
5816 ast_copy_string(tmpid, ast_channel_cdr(qe->chan)->uniqueid, sizeof(tmpid));
5817 } else {
5818 snprintf(tmpid, sizeof(tmpid), "chan-%lx", (unsigned long)ast_random());
5819 }
5820 } else {
5821 const char *m = monitorfilename;
5822 for (p = tmpid2; p < tmpid2 + sizeof(tmpid2) - 1; p++, m++) {
5823 switch (*m) {
5824 case '^':
5825 if (*(m + 1) == '{')
5826 *p = '$';
5827 break;
5828 case ',':
5829 *p++ = '\\';
5830 /* Fall through */
5831 default:
5832 *p = *m;
5833 }
5834 if (*m == '\0')
5835 break;
5836 }
5837 if (p == tmpid2 + sizeof(tmpid2))
5838 tmpid2[sizeof(tmpid2) - 1] = '\0';
5839
5840 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
5841 }
5842
5843 ast_channel_lock(qe->chan);
5844 if ((monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC"))) {
5845 monitor_exec = ast_strdupa(monitor_exec);
5846 }
5847 if ((monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS"))) {
5848 monitor_options = ast_strdupa(monitor_options);
5849 } else {
5850 monitor_options = "";
5851 }
5852 ast_channel_unlock(qe->chan);
5853
5854 if (monitor_exec) {
5855 const char *m = monitor_exec;
5856 for (p = meid2; p < meid2 + sizeof(meid2) - 1; p++, m++) {
5857 switch (*m) {
5858 case '^':
5859 if (*(m + 1) == '{')
5860 *p = '$';
5861 break;
5862 case ',':
5863 *p++ = '\\';
5864 /* Fall through */
5865 default:
5866 *p = *m;
5867 }
5868 if (*m == '\0') {
5869 break;
5870 }
5871 }
5872 if (p == meid2 + sizeof(meid2)) {
5873 meid2[sizeof(meid2) - 1] = '\0';
5874 }
5875
5876 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
5877 }
5878
5879 snprintf(tmpid2, sizeof(tmpid2), "%s.%s", tmpid, qe->parent->monfmt);
5880
5881 if (!ast_strlen_zero(monitor_exec)) {
5882 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s,%s", tmpid2, monitor_options, monitor_exec);
5883 } else {
5884 snprintf(mixmonargs, sizeof(mixmonargs), "%s,b%s", tmpid2, monitor_options);
5885 }
5886
5887 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
5888 /* We purposely lock the CDR so that pbx_exec does not update the application data */
5889 if (ast_channel_cdr(qe->chan)) {
5890 ast_set_flag(ast_channel_cdr(qe->chan), AST_CDR_FLAG_LOCKED);
5891 }
5892 pbx_exec(qe->chan, mixmonapp, mixmonargs);
5893 if (ast_channel_cdr(qe->chan)) {
5894 ast_clear_flag(ast_channel_cdr(qe->chan), AST_CDR_FLAG_LOCKED);
5895 }
5896 } else {
5897 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
5898 }
5899 }
5900 }
5901 /* Drop out of the queue at this point, to prepare for next caller */
5902 leave_queue(qe);
5903 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
5904 ast_debug(1, "app_queue: sendurl=%s.\n", url);
5905 ast_channel_sendurl(peer, url);
5906 }
5907
5908 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
5909 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
5910 if (!ast_strlen_zero(macro)) {
5911 macroexec = ast_strdupa(macro);
5912 } else {
5913 if (qe->parent->membermacro) {
5914 macroexec = ast_strdupa(qe->parent->membermacro);
5915 }
5916 }
5917
5918 if (!ast_strlen_zero(macroexec)) {
5919 ast_debug(1, "app_queue: macro=%s.\n", macroexec);
5920 ast_app_exec_macro(qe->chan, peer, macroexec);
5921 }
5922
5923 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
5924 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
5925 if (!ast_strlen_zero(gosub)) {
5926 gosubexec = ast_strdupa(gosub);
5927 } else {
5928 if (qe->parent->membergosub) {
5929 gosubexec = ast_strdupa(qe->parent->membergosub);
5930 }
5931 }
5932
5933 if (!ast_strlen_zero(gosubexec)) {
5934 char *gosub_args = NULL;
5935 char *gosub_argstart;
5936
5937 ast_debug(1, "app_queue: gosub=%s.\n", gosubexec);
5938
5939 gosub_argstart = strchr(gosubexec, ',');
5940 if (gosub_argstart) {
5941 const char *what_is_s = "s";
5942 *gosub_argstart = 0;
5943 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)) &&
5944 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
5945 what_is_s = "~~s~~";
5946 }
5947 if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", gosubexec, what_is_s, gosub_argstart + 1) < 0) {
5948 gosub_args = NULL;
5949 }
5950 *gosub_argstart = ',';
5951 } else {
5952 const char *what_is_s = "s";
5953 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)) &&
5954 ast_exists_extension(peer, gosubexec, "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
5955 what_is_s = "~~s~~";
5956 }
5957 if (ast_asprintf(&gosub_args, "%s,%s,1", gosubexec, what_is_s) < 0) {
5958 gosub_args = NULL;
5959 }
5960 }
5961 if (gosub_args) {
5962 ast_app_exec_sub(qe->chan, peer, gosub_args, 0);
5963 ast_free(gosub_args);
5964 } else {
5965 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
5966 }
5967 }
5968
5969 if (!ast_strlen_zero(agi)) {
5970 ast_debug(1, "app_queue: agi=%s.\n", agi);
5971 application = pbx_findapp("agi");
5972 if (application) {
5973 agiexec = ast_strdupa(agi);
5974 pbx_exec(qe->chan, application, agiexec);
5975 } else {
5976 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
5977 }
5978 }
5979 qe->handled++;
5980
5981 /** mark member as "in_call" in all queues */
5982 if (shared_lastcall) {
5983 queue_iter = ao2_iterator_init(queues, 0);
5984 while ((queuetmp = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
5985 ao2_lock(queuetmp);
5986 if ((mem = ao2_find(queuetmp->members, member, OBJ_POINTER))) {
5987 mem->in_call = 1;
5988 ast_debug(4, "Marked member %s as in_call \n", mem->membername);
5989 ao2_ref(mem, -1);
5990 }
5991 ao2_unlock(queuetmp);
5992 queue_t_unref(queuetmp, "Done with iterator");
5993 }
5994 ao2_iterator_destroy(&queue_iter);
5995 } else {
5996 ao2_lock(qe->parent);
5997 member->in_call = 1;
5998 ast_debug(4, "Marked member %s as in_call \n", member->membername);
5999 ao2_unlock(qe->parent);
6000 }
6001
6002 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "CONNECT", "%ld|%s|%ld", (long) (time(NULL) - qe->start), ast_channel_uniqueid(peer),
6003 (long)(orig - to > 0 ? (orig - to) / 1000 : 0));
6004
6005 if (ast_channel_cdr(qe->chan)) {
6006 struct ast_cdr *cdr;
6007 struct ast_cdr *newcdr;
6008
6009 /* Only work with the last CDR in the stack*/
6010 cdr = ast_channel_cdr(qe->chan);
6011 while (cdr->next) {
6012 cdr = cdr->next;
6013 }
6014
6015 /* If this CDR is not related to us add new one*/
6016 if ((strcasecmp(cdr->uniqueid, ast_channel_uniqueid(qe->chan))) &&
6017 (strcasecmp(cdr->linkedid, ast_channel_uniqueid(qe->chan))) &&
6018 (newcdr = ast_cdr_dup(cdr))) {
6019 ast_channel_lock(qe->chan);
6020 ast_cdr_init(newcdr, qe->chan);
6021 ast_cdr_reset(newcdr, 0);
6022 cdr = ast_cdr_append(cdr, newcdr);
6023 cdr = cdr->next;
6024 ast_channel_unlock(qe->chan);
6025 }
6026
6027 if (update_cdr) {
6028 ast_copy_string(cdr->dstchannel, member->membername, sizeof(cdr->dstchannel));
6029 }
6030 }
6031
6032 if (qe->parent->eventwhencalled)
6033 /*** DOCUMENTATION
6034 <managerEventInstance>
6035 <synopsis>Raised when an agent answers and is bridged to a member in the queue.</synopsis>
6036 <syntax>
6037 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
6038 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='Member'])" />
6039 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
6040 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentRingNoAnswer']/managerEventInstance/syntax/parameter[@name='RingTime'])" />
6041 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueCallerAbandon']/managerEventInstance/syntax/parameter[@name='HoldTime'])" />
6042 <xi:include xpointer="xpointer(/docs/managerEvent[@name='AgentCalled']/managerEventInstance/syntax/parameter[@name='Variable'])" />
6043 </syntax>
6044 <see-also>
6045 <ref type="managerEvent">AgentCalled</ref>
6046 <ref type="managerEvent">AgentComplete</ref>
6047 <ref type="managerEvent">AgentDump</ref>
6048 </see-also>
6049 </managerEventInstance>
6050 ***/
6051 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
6052 "Queue: %s\r\n"
6053 "Uniqueid: %s\r\n"
6054 "Channel: %s\r\n"
6055 "Member: %s\r\n"
6056 "MemberName: %s\r\n"
6057 "HoldTime: %ld\r\n"
6058 "BridgedChannel: %s\r\n"
6059 "RingTime: %ld\r\n"
6060 "%s",
6061 queuename, ast_channel_uniqueid(qe->chan), ast_channel_name(peer), member->interface, member->membername,
6062 (long) time(NULL) - qe->start, ast_channel_uniqueid(peer), (long)(orig - to > 0 ? (orig - to) / 1000 : 0),
6063 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
6064 ast_copy_string(oldcontext, ast_channel_context(qe->chan), sizeof(oldcontext));
6065 ast_copy_string(oldexten, ast_channel_exten(qe->chan), sizeof(oldexten));
6066
6067 if ((queue_end_bridge = ao2_alloc(sizeof(*queue_end_bridge), NULL))) {
6068 queue_end_bridge->q = qe->parent;
6069 queue_end_bridge->chan = qe->chan;
6070 bridge_config.end_bridge_callback = end_bridge_callback;
6071 bridge_config.end_bridge_callback_data = queue_end_bridge;
6072 bridge_config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
6073 /* Since queue_end_bridge can survive beyond the life of this call to Queue, we need
6074 * to make sure to increase the refcount of this queue so it cannot be freed until we
6075 * are done with it. We remove this reference in end_bridge_callback.
6076 */
6077 queue_t_ref(qe->parent, "For bridge_config reference");
6078 }
6079
6080 time(&callstart);
6081 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
6082 bridge = ast_bridge_call(qe->chan, peer, &bridge_config);
6083
6084 /* If the queue member did an attended transfer, then the TRANSFER already was logged in the queue_log
6085 * when the masquerade occurred. These other "ending" queue_log messages are unnecessary, except for
6086 * the AgentComplete manager event
6087 */
6088 ast_channel_lock(qe->chan);
6089 if (!attended_transfer_occurred(qe->chan)) {
6090 struct ast_datastore *tds;
6091
6092 /* detect a blind transfer */
6093 if (!(ast_channel_softhangup_internal_flag(qe->chan) | ast_channel_softhangup_internal_flag(peer)) && (strcasecmp(oldcontext, ast_channel_context(qe->chan)) || strcasecmp(oldexten, ast_channel_exten(qe->chan)))) {
6094 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "TRANSFER", "%s|%s|%ld|%ld|%d",
6095 ast_channel_exten(qe->chan), ast_channel_context(qe->chan), (long) (callstart - qe->start),
6096 (long) (time(NULL) - callstart), qe->opos);
6097 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
6098 } else if (ast_check_hangup(qe->chan) && !ast_check_hangup(peer)) {
6099 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETECALLER", "%ld|%ld|%d",
6100 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
6101 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
6102 } else {
6103 ast_queue_log(queuename, ast_channel_uniqueid(qe->chan), member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
6104 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
6105 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
6106 }
6107 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {
6108 ast_channel_datastore_remove(qe->chan, tds);
6109 /* tds was added by setup_transfer_datastore() and is freed below. */
6110 }
6111 ast_channel_unlock(qe->chan);
6112 update_queue(qe->parent, member, callcompletedinsl, (time(NULL) - callstart));
6113 } else {
6114 ast_channel_unlock(qe->chan);
6115
6116 /* We already logged the TRANSFER on the queue_log, but we still need to send the AgentComplete event */
6117 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
6118 }
6119
6120 if (transfer_ds) {
6121 ast_datastore_free(transfer_ds);
6122 }
6123
6124 if (!ast_check_hangup(peer) && ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
6125 int goto_res;
6126
6127 if (!ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GO_ON])) {
6128 ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GO_ON]);
6129 goto_res = ast_parseable_goto(peer, opt_args[OPT_ARG_CALLEE_GO_ON]);
6130 } else { /* F() */
6131 goto_res = ast_goto_if_exists(peer, caller_context, caller_extension,
6132 caller_priority + 1);
6133 }
6134 if (goto_res || ast_pbx_start(peer)) {
6135 ast_autoservice_chan_hangup_peer(qe->chan, peer);
6136 }
6137 } else {
6138 ast_autoservice_chan_hangup_peer(qe->chan, peer);
6139 }
6140
6141 res = bridge ? bridge : 1;
6142 ao2_ref(member, -1);
6143 }
6144out:
6145 hangupcalls(outgoing, NULL, qe->cancel_answered_elsewhere);
6146
6147 return res;
6148}
6149
6150static int wait_a_bit(struct queue_ent *qe)
6151{
6152 /* Don't need to hold the lock while we setup the outgoing calls */
6153 int retrywait = qe->parent->retry * 1000;
6154
6155 int res = ast_waitfordigit(qe->chan, retrywait);
6156 if (res > 0 && !valid_exit(qe, res)) {
6157 res = 0;
6158 }
6159
6160 return res;
6161}
6162
6163static struct member *interface_exists(struct call_queue *q, const char *interface)
6164{
6165 struct member *mem;
6166 struct ao2_iterator mem_iter;
6167
6168 if (!q) {
6169 return NULL;
6170 }
6171 mem_iter = ao2_iterator_init(q->members, 0);
6172 while ((mem = ao2_iterator_next(&mem_iter))) {
6173 if (!strcasecmp(interface, mem->interface)) {
6174 ao2_iterator_destroy(&mem_iter);
6175 return mem;
6176 }
6177 ao2_ref(mem, -1);
6178 }
6179 ao2_iterator_destroy(&mem_iter);
6180
6181 return NULL;
6182}
6183
6184
6185/*! \brief Dump all members in a specific queue to the database
6186 *
6187 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
6188 */
6189static void dump_queue_members(struct call_queue *pm_queue)
6190{
6191 struct member *cur_member;
6192 struct ast_str *value;
6193 struct ao2_iterator mem_iter;
6194
6195 if (!pm_queue) {
6196 return;
6197 }
6198
6199 /* 4K is a reasonable default for most applications, but we grow to
6200 * accommodate more if necessary. */
6201 if (!(value = ast_str_create(4096))) {
6202 return;
6203 }
6204
6205 mem_iter = ao2_iterator_init(pm_queue->members, 0);
6206 while ((cur_member = ao2_iterator_next(&mem_iter))) {
6207 if (!cur_member->dynamic) {
6208 ao2_ref(cur_member, -1);
6209 continue;
6210 }
6211
6212 ast_str_append(&value, 0, "%s%s;%d;%d;%s;%s",
6213 ast_str_strlen(value) ? "|" : "",
6214 cur_member->interface,
6215 cur_member->penalty,
6216 cur_member->paused,
6217 cur_member->membername,
6218 cur_member->state_interface);
6219
6220 ao2_ref(cur_member, -1);
6221 }
6222 ao2_iterator_destroy(&mem_iter);
6223
6224 if (ast_str_strlen(value) && !cur_member) {
6225 if (ast_db_put(pm_family, pm_queue->name, ast_str_buffer(value))) {
6226 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
6227 }
6228 } else {
6229 /* Delete the entry if the queue is empty or there is an error */
6230 ast_db_del(pm_family, pm_queue->name);
6231 }
6232
6233 ast_free(value);
6234}
6235
6236/*! \brief Remove member from queue
6237 * \retval RES_NOT_DYNAMIC when they aren't a RT member
6238 * \retval RES_NOSUCHQUEUE queue does not exist
6239 * \retval RES_OKAY removed member from queue
6240 * \retval RES_EXISTS queue exists but no members
6241*/
6242static int remove_from_queue(const char *queuename, const char *interface)
6243{
6244 struct call_queue *q, tmpq = {
6245 .name = queuename,
6246 };
6247 struct member *mem, tmpmem;
6248 int res = RES_NOSUCHQUEUE;
6249
6250 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
6251 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Temporary reference for interface removal"))) {
6252 ao2_lock(q);
6253 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
6254 /* XXX future changes should beware of this assumption!! */
6255 /*Change Penalty on realtime users*/
6256 if (mem->realtime && !ast_strlen_zero(mem->rt_uniqueid) && negative_penalty_invalid) {
6257 update_realtime_member_field(mem, q->name, "penalty", "-1");
6258 } else if (!mem->dynamic) {
6259 ao2_ref(mem, -1);
6260 ao2_unlock(q);
6261 queue_t_unref(q, "Interface wasn't dynamic, expiring temporary reference");
6262 return RES_NOT_DYNAMIC;
6263 }
6264 /*** DOCUMENTATION
6265 <managerEventInstance>
6266 <synopsis>Raised when a member is removed from the queue.</synopsis>
6267 <syntax>
6268 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
6269 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
6270 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
6271 </syntax>
6272 <see-also>
6273 <ref type="managerEvent">QueueMemberAdded</ref>
6274 <ref type="application">RemoveQueueMember</ref>
6275 </see-also>
6276 </managerEventInstance>
6277 ***/
6278 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
6279 "Queue: %s\r\n"
6280 "Location: %s\r\n"
6281 "MemberName: %s\r\n",
6282 q->name, mem->interface, mem->membername);
6283 member_remove_from_queue(q, mem);
6284 ao2_ref(mem, -1);
6285
6286 if (queue_persistent_members) {
6287 dump_queue_members(q);
6288 }
6289
6290 if (!num_available_members(q)) {
6291 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
6292 }
6293
6294 res = RES_OKAY;
6295 } else {
6296 res = RES_EXISTS;
6297 }
6298 ao2_unlock(q);
6299 queue_t_unref(q, "Expiring temporary reference");
6300 }
6301
6302 return res;
6303}
6304
6305/*! \brief Add member to queue
6306 * \retval RES_NOT_DYNAMIC when they aren't a RT member
6307 * \retval RES_NOSUCHQUEUE queue does not exist
6308 * \retval RES_OKAY added member from queue
6309 * \retval RES_EXISTS queue exists but no members
6310 * \retval RES_OUT_OF_MEMORY queue exists but not enough memory to create member
6311*/
6312static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
6313{
6314 struct call_queue *q;
6315 struct member *new_member, *old_member;
6316 int res = RES_NOSUCHQUEUE;
6317
6318 /*! \note Ensure the appropriate realtime queue is loaded. Note that this
6319 * short-circuits if the queue is already in memory. */
6320 if (!(q = find_load_queue_rt_friendly(queuename))) {
6321 return res;
6322 }
6323
6324 ao2_lock(q);
6325 if ((old_member = interface_exists(q, interface)) == NULL) {
6326 if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface, q->ringinuse))) {
6327 new_member->ringinuse = q->ringinuse;
6328 new_member->dynamic = 1;
6329 member_add_to_queue(q, new_member);
6330 /*** DOCUMENTATION
6331 <managerEventInstance>
6332 <synopsis>Raised when a member is added to the queue.</synopsis>
6333 <syntax>
6334 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
6335 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
6336 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
6337 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='StateInterface'])" />
6338 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Membership'])" />
6339 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Penalty'])" />
6340 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='CallsTaken'])" />
6341 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='LastCall'])" />
6342 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Status'])" />
6343 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Paused'])" />
6344 </syntax>
6345 <see-also>
6346 <ref type="managerEvent">QueueMemberRemoved</ref>
6347 <ref type="application">AddQueueMember</ref>
6348 </see-also>
6349 </managerEventInstance>
6350 ***/
6351 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
6352 "Queue: %s\r\n"
6353 "Location: %s\r\n"
6354 "MemberName: %s\r\n"
6355 "StateInterface: %s\r\n"
6356 "Membership: %s\r\n"
6357 "Penalty: %d\r\n"
6358 "CallsTaken: %d\r\n"
6359 "LastCall: %d\r\n"
6360 "Status: %d\r\n"
6361 "Paused: %d\r\n",
6362 q->name, new_member->interface, new_member->membername, state_interface,
6363 "dynamic",
6364 new_member->penalty, new_member->calls, (int) new_member->lastcall,
6365 new_member->status, new_member->paused);
6366
6367 if (is_member_available(q, new_member)) {
6368 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Queue:%s_avail", q->name);
6369 }
6370
6371 ao2_ref(new_member, -1);
6372 new_member = NULL;
6373
6374 if (dump) {
6375 dump_queue_members(q);
6376 }
6377
6378 res = RES_OKAY;
6379 } else {
6380 res = RES_OUTOFMEMORY;
6381 }
6382 } else {
6383 ao2_ref(old_member, -1);
6384 res = RES_EXISTS;
6385 }
6386 ao2_unlock(q);
6387 queue_t_unref(q, "Expiring temporary reference");
6388
6389 return res;
6390}
6391
6392/*!
6393 * \internal
6394 * \brief Set the pause status of the specific queue member.
6395 *
6396 * \param q Which queue the member belongs.
6397 * \param mem Queue member being paused/unpaused.
6398 * \param reason Why is this happening (Can be NULL/empty for no reason given.)
6399 * \param paused Set to 1 if the member is being paused or 0 to unpause.
6400 *
6401 * \pre The q is locked on entry.
6402 *
6403 * \return Nothing
6404 */
6405static void set_queue_member_pause(struct call_queue *q, struct member *mem, const char *reason, int paused)
6406{
6407 if (mem->paused == paused) {
6408 ast_debug(1, "%spausing already-%spaused queue member %s:%s\n",
6409 (paused ? "" : "un"), (paused ? "" : "un"), q->name, mem->interface);
6410 }
6411
6412 if (mem->realtime) {
6413 if (update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0")) {
6414 ast_log(LOG_WARNING, "Failed %spause update of realtime queue member %s:%s\n",
6415 (paused ? "" : "un"), q->name, mem->interface);
6416 }
6417 }
6418
6419 mem->paused = paused;
6420
6421 if (queue_persistent_members) {
6422 dump_queue_members(q);
6423 }
6424
6425 if (is_member_available(q, mem)) {
6426 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE,
6427 "Queue:%s_avail", q->name);
6428 } else if (!num_available_members(q)) {
6429 ast_devstate_changed(AST_DEVICE_INUSE, AST_DEVSTATE_CACHABLE,
6430 "Queue:%s_avail", q->name);
6431 }
6432
6433 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"),
6434 "%s", S_OR(reason, ""));
6435
6436 if (!ast_strlen_zero(reason)) {
6437 /*** DOCUMENTATION
6438 <managerEventInstance>
6439 <synopsis>Raised when a member is paused/unpaused in the queue with a reason.</synopsis>
6440 <syntax>
6441 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
6442 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
6443 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
6444 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Paused'])" />
6445 <parameter name="Reason">
6446 <para>The reason given for pausing or unpausing a queue member.</para>
6447 </parameter>
6448 </syntax>
6449 <see-also>
6450 <ref type="application">PauseQueueMember</ref>
6451 <ref type="application">UnPauseQueueMember</ref>
6452 </see-also>
6453 </managerEventInstance>
6454 ***/
6455 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
6456 "Queue: %s\r\n"
6457 "Location: %s\r\n"
6458 "MemberName: %s\r\n"
6459 "Paused: %d\r\n"
6460 "Reason: %s\r\n",
6461 q->name, mem->interface, mem->membername, paused, reason);
6462 } else {
6463 /*** DOCUMENTATION
6464 <managerEventInstance>
6465 <synopsis>Raised when a member is paused/unpaused in the queue without a reason.</synopsis>
6466 <syntax>
6467 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
6468 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
6469 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='MemberName'])" />
6470 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Paused'])" />
6471 </syntax>
6472 <see-also>
6473 <ref type="application">PauseQueueMember</ref>
6474 <ref type="application">UnPauseQueueMember</ref>
6475 </see-also>
6476 </managerEventInstance>
6477 ***/
6478 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
6479 "Queue: %s\r\n"
6480 "Location: %s\r\n"
6481 "MemberName: %s\r\n"
6482 "Paused: %d\r\n",
6483 q->name, mem->interface, mem->membername, paused);
6484 }
6485}
6486
6487static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused)
6488{
6489 int found = 0;
6490 struct call_queue *q;
6491 struct ao2_iterator queue_iter;
6492
6493 /* Special event for when all queues are paused - individual events still generated */
6494 /* XXX In all other cases, we use the membername, but since this affects all queues, we cannot */
6495 if (ast_strlen_zero(queuename))
6496 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
6497
6498 queue_iter = ao2_iterator_init(queues, 0);
6499 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate over queues"))) {
6500 ao2_lock(q);
6501 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
6502 struct member *mem;
6503
6504 if ((mem = interface_exists(q, interface))) {
6505 ++found;
6506
6507 set_queue_member_pause(q, mem, reason, paused);
6508 ao2_ref(mem, -1);
6509 }
6510
6511 if (!ast_strlen_zero(queuename)) {
6512 ao2_unlock(q);
6513 queue_t_unref(q, "Done with iterator");
6514 break;
6515 }
6516 }
6517
6518 ao2_unlock(q);
6519 queue_t_unref(q, "Done with iterator");
6520 }
6521 ao2_iterator_destroy(&queue_iter);
6522
6523 return found ? RESULT_SUCCESS : RESULT_FAILURE;
6524}
6525
6526/*!
6527 * \internal
6528 * \brief helper function for set_member_penalty - given a queue, sets all member penalties with the interface
6529 * \param[in] q queue which is having its member's penalty changed - must be unlocked prior to calling
6530 * \param[in] interface String of interface used to search for queue members being changed
6531 * \param[in] penalty Value penalty is being changed to for the member.
6532 * \retval 0 if the there is no member with interface belonging to q and no change is made
6533 * \retval 1 if the there is a member with interface belonging to q and changes are made
6534 */
6535static int set_member_penalty_help_members(struct call_queue *q, const char *interface, int penalty)
6536{
6537 struct member *mem;
6538 int foundinterface = 0;
6539 char rtpenalty[80];
6540
6541 ao2_lock(q);
6542 if ((mem = interface_exists(q, interface))) {
6543 foundinterface++;
6544 if (!mem->realtime) {
6545 mem->penalty = penalty;
6546 } else {
6547 sprintf(rtpenalty, "%i", penalty);
6548 update_realtime_member_field(mem, q->name, "penalty", rtpenalty);
6549 }
6550 ast_queue_log(q->name, "NONE", interface, "PENALTY", "%d", penalty);
6551 /*** DOCUMENTATION
6552 <managerEventInstance>
6553 <synopsis>Raised when a member's penalty is changed.</synopsis>
6554 <syntax>
6555 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
6556 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
6557 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Penalty'])" />
6558 </syntax>
6559 <see-also>
6560 <ref type="function">QUEUE_MEMBER</ref>
6561 </see-also>
6562 </managerEventInstance>
6563 ***/
6564 manager_event(EVENT_FLAG_AGENT, "QueueMemberPenalty",
6565 "Queue: %s\r\n"
6566 "Location: %s\r\n"
6567 "Penalty: %d\r\n",
6568 q->name, mem->interface, penalty);
6569 ao2_ref(mem, -1);
6570 }
6571 ao2_unlock(q);
6572
6573 return foundinterface;
6574}
6575
6576/*!
6577 * \internal
6578 * \brief Set the ringinuse value of the specific queue member.
6579 *
6580 * \param q Which queue the member belongs.
6581 * \param mem Queue member being set.
6582 * \param ringinuse Set to 1 if the member is called when inuse.
6583 *
6584 * \pre The q is locked on entry.
6585 *
6586 * \return Nothing
6587 */
6588static void set_queue_member_ringinuse(struct call_queue *q, struct member *mem, int ringinuse)
6589{
6590 if (mem->realtime) {
6591 update_realtime_member_field(mem, q->name, realtime_ringinuse_field,
6592 ringinuse ? "1" : "0");
6593 }
6594
6595 mem->ringinuse = ringinuse;
6596
6597 ast_queue_log(q->name, "NONE", mem->interface, "RINGINUSE", "%d", ringinuse);
6598
6599 /*** DOCUMENTATION
6600 <managerEventInstance>
6601 <synopsis>Raised when a member's ringinuse setting is changed.</synopsis>
6602 <syntax>
6603 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Queue'])" />
6604 <xi:include xpointer="xpointer(/docs/managerEvent[@name='QueueMemberStatus']/managerEventInstance/syntax/parameter[@name='Location'])" />
6605 <parameter name="Ringinuse">
6606 <enumlist>
6607 <enum name="0"/>
6608 <enum name="1"/>
6609 </enumlist>
6610 </parameter>
6611 </syntax>
6612 <see-also>
6613 <ref type="function">QUEUE_MEMBER</ref>
6614 </see-also>
6615 </managerEventInstance>
6616 ***/
6617 manager_event(EVENT_FLAG_AGENT, "QueueMemberRinginuse",
6618 "Queue: %s\r\n"
6619 "Location: %s\r\n"
6620 "Ringinuse: %d\r\n",
6621 q->name, mem->interface, ringinuse);
6622}
6623
6624static int set_member_ringinuse_help_members(struct call_queue *q, const char *interface, int ringinuse)
6625{
6626 struct member *mem;
6627 int foundinterface = 0;
6628
6629 ao2_lock(q);
6630 if ((mem = interface_exists(q, interface))) {
6631 foundinterface++;
6632 set_queue_member_ringinuse(q, mem, ringinuse);
6633 ao2_ref(mem, -1);
6634 }
6635 ao2_unlock(q);
6636
6637 return foundinterface;
6638}
6639
6640static int set_member_value_help_members(struct call_queue *q, const char *interface, int property, int value)
6641{
6642 switch(property) {
6643 case MEMBER_PENALTY:
6644 return set_member_penalty_help_members(q, interface, value);
6645
6646 case MEMBER_RINGINUSE:
6647 return set_member_ringinuse_help_members(q, interface, value);
6648
6649 default:
6650 ast_log(LOG_ERROR, "Attempted to set invalid property\n");
6651 return 0;
6652 }
6653}
6654
6655/*!
6656 * \internal
6657 * \brief Sets members penalty, if queuename=NULL we set member penalty in all the queues.
6658 * \param[in] queuename If specified, only act on a member if it belongs to this queue
6659 * \param[in] interface Interface of queue member(s) having priority set.
6660 * \param[in] property Which queue property is being set
6661 * \param[in] penalty Value penalty is being changed to for each member
6662 */
6663static int set_member_value(const char *queuename, const char *interface, int property, int value)
6664{
6665 int foundinterface = 0, foundqueue = 0;
6666 struct call_queue *q;
6667 struct ast_config *queue_config = NULL;
6668 struct ao2_iterator queue_iter;
6669
6670 /* property dependent restrictions on values should be checked in this switch */
6671 switch (property) {
6672 case MEMBER_PENALTY:
6673 if (value < 0 && !negative_penalty_invalid) {
6674 ast_log(LOG_ERROR, "Invalid penalty (%d)\n", value);
6675 return RESULT_FAILURE;
6676 }
6677 }
6678
6679 if (ast_strlen_zero(queuename)) { /* This means we need to iterate through all the queues. */
6680 if (ast_check_realtime("queues")) {
6681 char *name;
6682 queue_config = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
6683 if (queue_config) {
6684 for (name = ast_category_browse(queue_config, NULL);
6685 !ast_strlen_zero(name);
6686 name = ast_category_browse(queue_config, name)) {
6687 if ((q = find_load_queue_rt_friendly(name))) {
6688 foundqueue++;
6689 foundinterface += set_member_value_help_members(q, interface, property, value);
6690 queue_unref(q);
6691 }
6692 }
6693 }
6694 }
6695
6696 /* After hitting realtime queues, go back and get the regular ones. */
6697 queue_iter = ao2_iterator_init(queues, 0);
6698 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
6699 foundqueue++;
6700 foundinterface += set_member_value_help_members(q, interface, property, value);
6701 queue_unref(q);
6702 }
6703 ao2_iterator_destroy(&queue_iter);
6704 } else { /* We actually have a queuename, so we can just act on the single queue. */
6705 if ((q = find_load_queue_rt_friendly(queuename))) {
6706 foundqueue++;
6707 foundinterface += set_member_value_help_members(q, interface, property, value);
6708 queue_unref(q);
6709 }
6710 }
6711
6712 if (foundinterface) {
6713 return RESULT_SUCCESS;
6714 } else if (!foundqueue) {
6715 ast_log (LOG_ERROR, "Invalid queuename\n");
6716 } else {
6717 ast_log (LOG_ERROR, "Invalid interface\n");
6718 }
6719
6720 return RESULT_FAILURE;
6721}
6722
6723/* \brief Gets members penalty.
6724 * \return Return the members penalty or RESULT_FAILURE on error.
6725*/
6726static int get_member_penalty(char *queuename, char *interface)
6727{
6728 int foundqueue = 0, penalty;
6729 struct call_queue *q, tmpq = {
6730 .name = queuename,
6731 };
6732 struct member *mem;
6733
6734 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Search for queue"))) {
6735 foundqueue = 1;
6736 ao2_lock(q);
6737 if ((mem = interface_exists(q, interface))) {
6738 penalty = mem->penalty;
6739 ao2_ref(mem, -1);
6740 ao2_unlock(q);
6741 queue_t_unref(q, "Search complete");
6742 return penalty;
6743 }
6744 ao2_unlock(q);
6745 queue_t_unref(q, "Search complete");
6746 }
6747
6748 /* some useful debuging */
6749 if (foundqueue) {
6750 ast_log (LOG_ERROR, "Invalid queuename\n");
6751 } else {
6752 ast_log (LOG_ERROR, "Invalid interface\n");
6753 }
6754
6755 return RESULT_FAILURE;
6756}
6757
6758/*! \brief Reload dynamic queue members persisted into the astdb */
6759static void reload_queue_members(void)
6760{
6761 char *cur_ptr;
6762 const char *queue_name;
6763 char *member;
6764 char *interface;
6765 char *membername = NULL;
6766 char *state_interface;
6767 char *penalty_tok;
6768 int penalty = 0;
6769 char *paused_tok;
6770 int paused = 0;
6771 struct ast_db_entry *db_tree;
6772 struct ast_db_entry *entry;
6773 struct call_queue *cur_queue;
6774 char *queue_data;
6775
6776 /* Each key in 'pm_family' is the name of a queue */
6777 db_tree = ast_db_gettree(pm_family, NULL);
6778 for (entry = db_tree; entry; entry = entry->next) {
6779
6780 queue_name = entry->key + strlen(pm_family) + 2;
6781
6782 {
6783 struct call_queue tmpq = {
6784 .name = queue_name,
6785 };
6786 cur_queue = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Reload queue members");
6787 }
6788
6789 if (!cur_queue) {
6790 cur_queue = find_load_queue_rt_friendly(queue_name);
6791 }
6792
6793 if (!cur_queue) {
6794 /* If the queue no longer exists, remove it from the
6795 * database */
6796 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
6797 ast_db_del(pm_family, queue_name);
6798 continue;
6799 }
6800
6801 if (ast_db_get_allocated(pm_family, queue_name, &queue_data)) {
6802 queue_t_unref(cur_queue, "Expire reload reference");
6803 continue;
6804 }
6805
6806 cur_ptr = queue_data;
6807 while ((member = strsep(&cur_ptr, ",|"))) {
6808 if (ast_strlen_zero(member)) {
6809 continue;
6810 }
6811
6812 interface = strsep(&member, ";");
6813 penalty_tok = strsep(&member, ";");
6814 paused_tok = strsep(&member, ";");
6815 membername = strsep(&member, ";");
6816 state_interface = strsep(&member, ";");
6817
6818 if (!penalty_tok) {
6819 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
6820 break;
6821 }
6822 penalty = strtol(penalty_tok, NULL, 10);
6823 if (errno == ERANGE) {
6824 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
6825 break;
6826 }
6827
6828 if (!paused_tok) {
6829 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
6830 break;
6831 }
6832 paused = strtol(paused_tok, NULL, 10);
6833 if ((errno == ERANGE) || paused < 0 || paused > 1) {
6834 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
6835 break;
6836 }
6837
6838 ast_debug(1, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
6839
6840 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
6841 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
6842 break;
6843 }
6844 }
6845 queue_t_unref(cur_queue, "Expire reload reference");
6846 ast_free(queue_data);
6847 }
6848
6849 if (db_tree) {
6850 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
6851 ast_db_freetree(db_tree);
6852 }
6853}
6854
6855/*! \brief PauseQueueMember application */
6856static int pqm_exec(struct ast_channel *chan, const char *data)
6857{
6858 char *parse;
6859 AST_DECLARE_APP_ARGS(args,
6860 AST_APP_ARG(queuename);
6861 AST_APP_ARG(interface);
6862 AST_APP_ARG(options);
6863 AST_APP_ARG(reason);
6864 );
6865
6866 if (ast_strlen_zero(data)) {
6867 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename],interface[,options][,reason])\n");
6868 return -1;
6869 }
6870
6871 parse = ast_strdupa(data);
6872
6873 AST_STANDARD_APP_ARGS(args, parse);
6874
6875 if (ast_strlen_zero(args.interface)) {
6876 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
6877 return -1;
6878 }
6879
6880 if (set_member_paused(args.queuename, args.interface, args.reason, 1)) {
6881 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
6882 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
6883 return 0;
6884 }
6885
6886 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
6887
6888 return 0;
6889}
6890
6891/*! \brief UnPauseQueueMember application */
6892static int upqm_exec(struct ast_channel *chan, const char *data)
6893{
6894 char *parse;
6895 AST_DECLARE_APP_ARGS(args,
6896 AST_APP_ARG(queuename);
6897 AST_APP_ARG(interface);
6898 AST_APP_ARG(options);
6899 AST_APP_ARG(reason);
6900 );
6901
6902 if (ast_strlen_zero(data)) {
6903 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename],interface[,options[,reason]])\n");
6904 return -1;
6905 }
6906
6907 parse = ast_strdupa(data);
6908
6909 AST_STANDARD_APP_ARGS(args, parse);
6910
6911 if (ast_strlen_zero(args.interface)) {
6912 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename],interface[,options[,reason]])\n");
6913 return -1;
6914 }
6915
6916 if (set_member_paused(args.queuename, args.interface, args.reason, 0)) {
6917 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
6918 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
6919 return 0;
6920 }
6921
6922 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
6923
6924 return 0;
6925}
6926
6927/*! \brief RemoveQueueMember application */
6928static int rqm_exec(struct ast_channel *chan, const char *data)
6929{
6930 int res=-1;
6931 char *parse, *temppos = NULL;
6932 struct member *mem = NULL;
6933
6934 AST_DECLARE_APP_ARGS(args,
6935 AST_APP_ARG(queuename);
6936 AST_APP_ARG(interface);
6937 );
6938
6939
6940 if (ast_strlen_zero(data)) {
6941 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[,interface])\n");
6942 return -1;
6943 }
6944
6945 parse = ast_strdupa(data);
6946
6947 AST_STANDARD_APP_ARGS(args, parse);
6948
6949 if (ast_strlen_zero(args.interface)) {
6950 args.interface = ast_strdupa(ast_channel_name(chan));
6951 temppos = strrchr(args.interface, '-');
6952 if (temppos) {
6953 *temppos = '\0';
6954 }
6955 }
6956
6957 ast_debug(1, "queue: %s, member: %s\n", args.queuename, args.interface);
6958
6959 if (log_membername_as_agent) {
6960 mem = find_member_by_queuename_and_interface(args.queuename, args.interface);
6961 }
6962
6963 switch (remove_from_queue(args.queuename, args.interface)) {
6964 case RES_OKAY:
6965 if (!mem || ast_strlen_zero(mem->membername)) {
6966 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "REMOVEMEMBER", "%s", "");
6967 } else {
6968 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), mem->membername, "REMOVEMEMBER", "%s", "");
6969 }
6970 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
6971 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
6972 res = 0;
6973 break;
6974 case RES_EXISTS:
6975 ast_debug(1, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
6976 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
6977 res = 0;
6978 break;
6979 case RES_NOSUCHQUEUE:
6980 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
6981 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
6982 res = 0;
6983 break;
6984 case RES_NOT_DYNAMIC:
6985 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
6986 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
6987 res = 0;
6988 break;
6989 }
6990
6991 if (mem) {
6992 ao2_ref(mem, -1);
6993 }
6994
6995 return res;
6996}
6997
6998/*! \brief AddQueueMember application */
6999static int aqm_exec(struct ast_channel *chan, const char *data)
7000{
7001 int res=-1;
7002 char *parse, *temppos = NULL;
7003 AST_DECLARE_APP_ARGS(args,
7004 AST_APP_ARG(queuename);
7005 AST_APP_ARG(interface);
7006 AST_APP_ARG(penalty);
7007 AST_APP_ARG(options);
7008 AST_APP_ARG(membername);
7009 AST_APP_ARG(state_interface);
7010 );
7011 int penalty = 0;
7012
7013 if (ast_strlen_zero(data)) {
7014 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[,interface[,penalty[,options[,membername[,stateinterface]]]]])\n");
7015 return -1;
7016 }
7017
7018 parse = ast_strdupa(data);
7019
7020 AST_STANDARD_APP_ARGS(args, parse);
7021
7022 if (ast_strlen_zero(args.interface)) {
7023 args.interface = ast_strdupa(ast_channel_name(chan));
7024 temppos = strrchr(args.interface, '-');
7025 if (temppos) {
7026 *temppos = '\0';
7027 }
7028 }
7029
7030 if (!ast_strlen_zero(args.penalty)) {
7031 if ((sscanf(args.penalty, "%30d", &penalty) != 1) || penalty < 0) {
7032 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
7033 penalty = 0;
7034 }
7035 }
7036
7037 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
7038 case RES_OKAY:
7039 if (ast_strlen_zero(args.membername) || !log_membername_as_agent) {
7040 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.interface, "ADDMEMBER", "%s", "");
7041 } else {
7042 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), args.membername, "ADDMEMBER", "%s", "");
7043 }
7044 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
7045 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
7046 res = 0;
7047 break;
7048 case RES_EXISTS:
7049 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
7050 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
7051 res = 0;
7052 break;
7053 case RES_NOSUCHQUEUE:
7054 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
7055 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
7056 res = 0;
7057 break;
7058 case RES_OUTOFMEMORY:
7059 ast_log(LOG_ERROR, "Out of memory adding interface %s to queue %s\n", args.interface, args.queuename);
7060 break;
7061 }
7062
7063 return res;
7064}
7065
7066/*! \brief QueueLog application */
7067static int ql_exec(struct ast_channel *chan, const char *data)
7068{
7069 char *parse;
7070
7071 AST_DECLARE_APP_ARGS(args,
7072 AST_APP_ARG(queuename);
7073 AST_APP_ARG(uniqueid);
7074 AST_APP_ARG(membername);
7075 AST_APP_ARG(event);
7076 AST_APP_ARG(params);
7077 );
7078
7079 if (ast_strlen_zero(data)) {
7080 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo]\n");
7081 return -1;
7082 }
7083
7084 parse = ast_strdupa(data);
7085
7086 AST_STANDARD_APP_ARGS(args, parse);
7087
7088 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
7089 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
7090 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename,uniqueid,membername,event[,additionalinfo])\n");
7091 return -1;
7092 }
7093
7094 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
7095 "%s", args.params ? args.params : "");
7096
7097 return 0;
7098}
7099
7100/*! \brief Copy rule from global list into specified queue */
7101static void copy_rules(struct queue_ent *qe, const char *rulename)
7102{
7103 struct penalty_rule *pr_iter;
7104 struct rule_list *rl_iter;
7105 const char *tmp = ast_strlen_zero(rulename) ? qe->parent->defaultrule : rulename;
7106 AST_LIST_LOCK(&rule_lists);
7107 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
7108 if (!strcasecmp(rl_iter->name, tmp)) {
7109 break;
7110 }
7111 }
7112 if (rl_iter) {
7113 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
7114 struct penalty_rule *new_pr = ast_calloc(1, sizeof(*new_pr));
7115 if (!new_pr) {
7116 ast_log(LOG_ERROR, "Memory allocation error when copying penalty rules! Aborting!\n");
7117 break;
7118 }
7119 new_pr->time = pr_iter->time;
7120 new_pr->max_value = pr_iter->max_value;
7121 new_pr->min_value = pr_iter->min_value;
7122 new_pr->max_relative = pr_iter->max_relative;
7123 new_pr->min_relative = pr_iter->min_relative;
7124 AST_LIST_INSERT_TAIL(&qe->qe_rules, new_pr, list);
7125 }
7126 }
7127 AST_LIST_UNLOCK(&rule_lists);
7128}
7129
7130/*!\brief The starting point for all queue calls
7131 *
7132 * The process involved here is to
7133 * 1. Parse the options specified in the call to Queue()
7134 * 2. Join the queue
7135 * 3. Wait in a loop until it is our turn to try calling a queue member
7136 * 4. Attempt to call a queue member
7137 * 5. If 4. did not result in a bridged call, then check for between
7138 * call options such as periodic announcements etc.
7139 * 6. Try 4 again unless some condition (such as an expiration time) causes us to
7140 * exit the queue.
7141 */
7142static int queue_exec(struct ast_channel *chan, const char *data)
7143{
7144 int res=-1;
7145 int ringing=0;
7146 const char *user_priority;
7147 const char *max_penalty_str;
7148 const char *min_penalty_str;
7149 int prio;
7150 int qcontinue = 0;
7151 int max_penalty, min_penalty;
7152 enum queue_result reason = QUEUE_UNKNOWN;
7153 /* whether to exit Queue application after the timeout hits */
7154 int tries = 0;
7155 int noption = 0;
7156 char *parse;
7157 int makeannouncement = 0;
7158 int position = 0;
7159 AST_DECLARE_APP_ARGS(args,
7160 AST_APP_ARG(queuename);
7161 AST_APP_ARG(options);
7162 AST_APP_ARG(url);
7163 AST_APP_ARG(announceoverride);
7164 AST_APP_ARG(queuetimeoutstr);
7165 AST_APP_ARG(agi);
7166 AST_APP_ARG(macro);
7167 AST_APP_ARG(gosub);
7168 AST_APP_ARG(rule);
7169 AST_APP_ARG(position);
7170 );
7171 /* Our queue entry */
7172 struct queue_ent qe = { 0 };
7173 struct ast_flags opts = { 0, };
7174 char *opt_args[OPT_ARG_ARRAY_SIZE];
7175
7176 if (ast_strlen_zero(data)) {
7177 ast_log(LOG_WARNING, "Queue requires an argument: queuename[,options[,URL[,announceoverride[,timeout[,agi[,macro[,gosub[,rule[,position]]]]]]]]]\n");
7178 return -1;
7179 }
7180
7181 parse = ast_strdupa(data);
7182 AST_STANDARD_APP_ARGS(args, parse);
7183
7184 ast_debug(1, "queue: %s, options: %s, url: %s, announce: %s, timeout: %s, agi: %s, macro: %s, gosub: %s, rule: %s, position: %s\n",
7185 args.queuename,
7186 S_OR(args.options, ""),
7187 S_OR(args.url, ""),
7188 S_OR(args.announceoverride, ""),
7189 S_OR(args.queuetimeoutstr, ""),
7190 S_OR(args.agi, ""),
7191 S_OR(args.macro, ""),
7192 S_OR(args.gosub, ""),
7193 S_OR(args.rule, ""),
7194 S_OR(args.position, ""));
7195
7196 if (!ast_strlen_zero(args.options)) {
7197 ast_app_parse_options(queue_exec_options, &opts, opt_args, args.options);
7198 }
7199
7200 /* Setup our queue entry */
7201 qe.start = time(NULL);
7202
7203 /* set the expire time based on the supplied timeout; */
7204 if (!ast_strlen_zero(args.queuetimeoutstr)) {
7205 qe.expire = qe.start + atoi(args.queuetimeoutstr);
7206 } else {
7207 qe.expire = 0;
7208 }
7209
7210 /* Get the priority from the variable ${QUEUE_PRIO} */
7211 ast_channel_lock(chan);
7212 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
7213 if (user_priority) {
7214 if (sscanf(user_priority, "%30d", &prio) == 1) {
7215 ast_debug(1, "%s: Got priority %d from ${QUEUE_PRIO}.\n", ast_channel_name(chan), prio);
7216 } else {
7217 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
7218 user_priority, ast_channel_name(chan));
7219 prio = 0;
7220 }
7221 } else {
7222 ast_debug(3, "NO QUEUE_PRIO variable found. Using default.\n");
7223 prio = 0;
7224 }
7225
7226 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
7227
7228 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
7229 if (sscanf(max_penalty_str, "%30d", &max_penalty) == 1) {
7230 ast_debug(1, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n", ast_channel_name(chan), max_penalty);
7231 } else {
7232 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
7233 max_penalty_str, ast_channel_name(chan));
7234 max_penalty = INT_MAX;
7235 }
7236 } else {
7237 max_penalty = INT_MAX;
7238 }
7239
7240 if ((min_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MIN_PENALTY"))) {
7241 if (sscanf(min_penalty_str, "%30d", &min_penalty) == 1) {
7242 ast_debug(1, "%s: Got min penalty %d from ${QUEUE_MIN_PENALTY}.\n", ast_channel_name(chan), min_penalty);
7243 } else {
7244 ast_log(LOG_WARNING, "${QUEUE_MIN_PENALTY}: Invalid value (%s), channel %s.\n",
7245 min_penalty_str, ast_channel_name(chan));
7246 min_penalty = INT_MAX;
7247 }
7248 } else {
7249 min_penalty = INT_MAX;
7250 }
7251 ast_channel_unlock(chan);
7252
7253 if (ast_test_flag(&opts, OPT_RINGING)) {
7254 ringing = 1;
7255 }
7256
7257 if (ringing != 1 && ast_test_flag(&opts, OPT_RING_WHEN_RINGING)) {
7258 qe.ring_when_ringing = 1;
7259 }
7260
7261 if (ast_test_flag(&opts, OPT_GO_ON)) {
7262 qcontinue = 1;
7263 }
7264
7265 if (args.position) {
7266 position = atoi(args.position);
7267 if (position < 0) {
7268 ast_log(LOG_WARNING, "Invalid position '%s' given for call to queue '%s'. Assuming no preference for position\n", args.position, args.queuename);
7269 position = 0;
7270 }
7271 }
7272
7273 ast_debug(1, "queue: %s, expires: %ld, priority: %d\n",
7274 args.queuename, (long)qe.expire, prio);
7275
7276 qe.chan = chan;
7277 qe.prio = prio;
7278 qe.max_penalty = max_penalty;
7279 qe.min_penalty = min_penalty;
7280 qe.last_pos_said = 0;
7281 qe.last_pos = 0;
7282 qe.last_periodic_announce_time = time(NULL);
7283 qe.last_periodic_announce_sound = 0;
7284 qe.valid_digits = 0;
7285 if (join_queue(args.queuename, &qe, &reason, position)) {
7286 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
7287 set_queue_result(chan, reason);
7288 return 0;
7289 }
7290 ast_assert(qe.parent != NULL);
7291
7292 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ENTERQUEUE", "%s|%s|%d",
7293 S_OR(args.url, ""),
7294 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
7295 qe.opos);
7296 copy_rules(&qe, args.rule);
7297 qe.pr = AST_LIST_FIRST(&qe.qe_rules);
7298check_turns:
7299 if (ringing) {
7300 ast_indicate(chan, AST_CONTROL_RINGING);
7301 } else {
7302 ast_moh_start(chan, qe.moh, NULL);
7303 }
7304
7305 /* This is the wait loop for callers 2 through maxlen */
7306 res = wait_our_turn(&qe, ringing, &reason);
7307 if (res) {
7308 goto stop;
7309 }
7310
7311 makeannouncement = 0;
7312
7313 for (;;) {
7314 /* This is the wait loop for the head caller*/
7315 /* To exit, they may get their call answered; */
7316 /* they may dial a digit from the queue context; */
7317 /* or, they may timeout. */
7318
7319 /* Leave if we have exceeded our queuetimeout */
7320 if (qe.expire && (time(NULL) >= qe.expire)) {
7321 record_abandoned(&qe);
7322 reason = QUEUE_TIMEOUT;
7323 res = 0;
7324 ast_queue_log(args.queuename, ast_channel_uniqueid(chan),"NONE", "EXITWITHTIMEOUT", "%d|%d|%ld",
7325 qe.pos, qe.opos, (long) (time(NULL) - qe.start));
7326 break;
7327 }
7328
7329 if (makeannouncement) {
7330 /* Make a position announcement, if enabled */
7331 if (qe.parent->announcefrequency)
7332 if ((res = say_position(&qe,ringing)))
7333 goto stop;
7334 }
7335 makeannouncement = 1;
7336
7337 /* Make a periodic announcement, if enabled */
7338 if (qe.parent->periodicannouncefrequency) {
7339 if ((res = say_periodic_announcement(&qe,ringing))) {
7340 goto stop;
7341 }
7342 }
7343
7344 /* Leave if we have exceeded our queuetimeout */
7345 if (qe.expire && (time(NULL) >= qe.expire)) {
7346 record_abandoned(&qe);
7347 reason = QUEUE_TIMEOUT;
7348 res = 0;
7349 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
7350 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
7351 break;
7352 }
7353
7354 /* see if we need to move to the next penalty level for this queue */
7355 while (qe.pr && ((time(NULL) - qe.start) > qe.pr->time)) {
7356 update_qe_rule(&qe);
7357 }
7358
7359 /* Try calling all queue members for 'timeout' seconds */
7360 res = try_calling(&qe, opts, opt_args, args.announceoverride, args.url, &tries, &noption, args.agi, args.macro, args.gosub, ringing);
7361 if (res) {
7362 goto stop;
7363 }
7364
7365 if (qe.parent->leavewhenempty) {
7366 int status = 0;
7367 if ((status = get_member_status(qe.parent, qe.max_penalty, qe.min_penalty, qe.parent->leavewhenempty, 0))) {
7368 record_abandoned(&qe);
7369 reason = QUEUE_LEAVEEMPTY;
7370 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
7371 res = 0;
7372 break;
7373 }
7374 }
7375
7376 /* exit after 'timeout' cycle if 'n' option enabled */
7377 if (noption && tries >= ao2_container_count(qe.parent->members)) {
7378 ast_verb(3, "Exiting on time-out cycle\n");
7379 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHTIMEOUT",
7380 "%d|%d|%ld", qe.pos, qe.opos, (long) (time(NULL) - qe.start));
7381 record_abandoned(&qe);
7382 reason = QUEUE_TIMEOUT;
7383 res = 0;
7384 break;
7385 }
7386
7387
7388 /* Leave if we have exceeded our queuetimeout */
7389 if (qe.expire && (time(NULL) >= qe.expire)) {
7390 record_abandoned(&qe);
7391 reason = QUEUE_TIMEOUT;
7392 res = 0;
7393 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));
7394 break;
7395 }
7396
7397 /* If using dynamic realtime members, we should regenerate the member list for this queue */
7398 update_realtime_members(qe.parent);
7399 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
7400 res = wait_a_bit(&qe);
7401 if (res) {
7402 goto stop;
7403 }
7404
7405 /* Since this is a priority queue and
7406 * it is not sure that we are still at the head
7407 * of the queue, go and check for our turn again.
7408 */
7409 if (!is_our_turn(&qe)) {
7410 ast_debug(1, "Darn priorities, going back in queue (%s)!\n", ast_channel_name(qe.chan));
7411 goto check_turns;
7412 }
7413 }
7414
7415stop:
7416 if (res) {
7417 if (res < 0) {
7418 if (!qe.handled) {
7419 record_abandoned(&qe);
7420 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "ABANDON",
7421 "%d|%d|%ld", qe.pos, qe.opos,
7422 (long) (time(NULL) - qe.start));
7423 res = -1;
7424 } else if (qcontinue) {
7425 reason = QUEUE_CONTINUE;
7426 res = 0;
7427 }
7428 } else if (qe.valid_digits) {
7429 ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "NONE", "EXITWITHKEY",
7430 "%s|%d|%d|%ld", qe.digits, qe.pos, qe.opos, (long) (time(NULL) - qe.start));
7431 }
7432 }
7433
7434 /* Don't allow return code > 0 */
7435 if (res >= 0) {
7436 res = 0;
7437 if (ringing) {
7438 ast_indicate(chan, -1);
7439 } else {
7440 ast_moh_stop(chan);
7441 }
7442 ast_stopstream(chan);
7443 }
7444
7445 set_queue_variables(qe.parent, qe.chan);
7446
7447 leave_queue(&qe);
7448 if (reason != QUEUE_UNKNOWN)
7449 set_queue_result(chan, reason);
7450
7451 /*
7452 * every queue_ent is given a reference to it's parent
7453 * call_queue when it joins the queue. This ref must be taken
7454 * away right before the queue_ent is destroyed. In this case
7455 * the queue_ent is about to be returned on the stack
7456 */
7457 qe.parent = queue_unref(qe.parent);
7458
7459 return res;
7460}
7461
7462/*!
7463 * \brief create interface var with all queue details.
7464 * \retval 0 on success
7465 * \retval -1 on error
7466*/
7467static int queue_function_var(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7468{
7469 int res = -1;
7470 struct call_queue *q, tmpq = {
7471 .name = data,
7472 };
7473
7474 char interfacevar[256] = "";
7475 float sl = 0;
7476
7477 if (ast_strlen_zero(data)) {
7478 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
7479 return -1;
7480 }
7481
7482 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE() function"))) {
7483 ao2_lock(q);
7484 if (q->setqueuevar) {
7485 sl = 0;
7486 res = 0;
7487
7488 if (q->callscompleted > 0) {
7489 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
7490 }
7491
7492 snprintf(interfacevar, sizeof(interfacevar),
7493 "QUEUEMAX=%d,QUEUESTRATEGY=%s,QUEUECALLS=%d,QUEUEHOLDTIME=%d,QUEUETALKTIME=%d,QUEUECOMPLETED=%d,QUEUEABANDONED=%d,QUEUESRVLEVEL=%d,QUEUESRVLEVELPERF=%2.1f",
7494 q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted, q->callsabandoned, q->servicelevel, sl);
7495
7496 pbx_builtin_setvar_multiple(chan, interfacevar);
7497 }
7498
7499 ao2_unlock(q);
7500 queue_t_unref(q, "Done with QUEUE() function");
7501 } else {
7502 ast_log(LOG_WARNING, "queue %s was not found\n", data);
7503 }
7504
7505 snprintf(buf, len, "%d", res);
7506
7507 return 0;
7508}
7509
7510/*!
7511 * \brief Check if a given queue exists
7512 *
7513 */
7514static int queue_function_exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7515{
7516 struct call_queue *q;
7517
7518 buf[0] = '\0';
7519
7520 if (ast_strlen_zero(data)) {
7521 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
7522 return -1;
7523 }
7524 q = find_load_queue_rt_friendly(data);
7525 snprintf(buf, len, "%d", q != NULL? 1 : 0);
7526 if (q) {
7527 queue_t_unref(q, "Done with temporary reference in QUEUE_EXISTS()");
7528 }
7529
7530 return 0;
7531}
7532
7533static struct member *get_interface_helper(struct call_queue *q, const char *interface)
7534{
7535 struct member *m;
7536
7537 if (ast_strlen_zero(interface)) {
7538 ast_log(LOG_ERROR, "QUEUE_MEMBER: Missing required interface argument.\n");
7539 return NULL;
7540 }
7541
7542 m = interface_exists(q, interface);
7543 if (!m) {
7544 ast_log(LOG_ERROR, "Queue member interface '%s' not in queue '%s'.\n",
7545 interface, q->name);
7546 }
7547 return m;
7548}
7549
7550/*!
7551 * \brief Get number either busy / free / ready or total members of a specific queue
7552 * \brief Get or set member properties penalty / paused / ringinuse
7553 * \retval number of members (busy / free / ready / total) or member info (penalty / paused / ringinuse)
7554 * \retval -1 on error
7555 */
7556static int queue_function_mem_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7557{
7558 int count = 0;
7559 struct member *m;
7560 struct ao2_iterator mem_iter;
7561 struct call_queue *q;
7562
7563 AST_DECLARE_APP_ARGS(args,
7564 AST_APP_ARG(queuename);
7565 AST_APP_ARG(option);
7566 AST_APP_ARG(interface);
7567 );
7568 /* Make sure the returned value on error is zero length string. */
7569 buf[0] = '\0';
7570
7571 if (ast_strlen_zero(data)) {
7572 ast_log(LOG_ERROR,
7573 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
7574 cmd);
7575 return -1;
7576 }
7577
7578 AST_STANDARD_APP_ARGS(args, data);
7579
7580 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.option)) {
7581 ast_log(LOG_ERROR,
7582 "Missing required argument. %s(<queuename>,<option>[,<interface>])\n",
7583 cmd);
7584 return -1;
7585 }
7586
7587 if ((q = find_load_queue_rt_friendly(args.queuename))) {
7588 ao2_lock(q);
7589 if (!strcasecmp(args.option, "logged")) {
7590 mem_iter = ao2_iterator_init(q->members, 0);
7591 while ((m = ao2_iterator_next(&mem_iter))) {
7592 /* Count the agents who are logged in and presently answering calls */
7593 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
7594 count++;
7595 }
7596 ao2_ref(m, -1);
7597 }
7598 ao2_iterator_destroy(&mem_iter);
7599 } else if (!strcasecmp(args.option, "free")) {
7600 mem_iter = ao2_iterator_init(q->members, 0);
7601 while ((m = ao2_iterator_next(&mem_iter))) {
7602 /* Count the agents who are logged in and presently answering calls */
7603 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused)) {
7604 count++;
7605 }
7606 ao2_ref(m, -1);
7607 }
7608 ao2_iterator_destroy(&mem_iter);
7609 } else if (!strcasecmp(args.option, "ready")) {
7610 time_t now;
7611 time(&now);
7612 mem_iter = ao2_iterator_init(q->members, 0);
7613 while ((m = ao2_iterator_next(&mem_iter))) {
7614 /* Count the agents who are logged in, not paused and not wrapping up */
7615 if ((m->status == AST_DEVICE_NOT_INUSE) && (!m->paused) &&
7616 !(m->lastcall && q->wrapuptime && ((now - q->wrapuptime) < m->lastcall))) {
7617 count++;
7618 }
7619 ao2_ref(m, -1);
7620 }
7621 ao2_iterator_destroy(&mem_iter);
7622 } else if (!strcasecmp(args.option, "count")) {
7623 count = ao2_container_count(q->members);
7624 } else if (!strcasecmp(args.option, "penalty")) {
7625 m = get_interface_helper(q, args.interface);
7626 if (m) {
7627 count = m->penalty;
7628 ao2_ref(m, -1);
7629 }
7630 } else if (!strcasecmp(args.option, "paused")) {
7631 m = get_interface_helper(q, args.interface);
7632 if (m) {
7633 count = m->paused;
7634 ao2_ref(m, -1);
7635 }
7636 } else if ((!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
7637 || !strcasecmp(args.option, "ringinuse"))) {
7638 m = get_interface_helper(q, args.interface);
7639 if (m) {
7640 count = m->ringinuse;
7641 ao2_ref(m, -1);
7642 }
7643 } else {
7644 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
7645 }
7646 ao2_unlock(q);
7647 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER()");
7648 } else {
7649 ast_log(LOG_WARNING, "queue %s was not found\n", args.queuename);
7650 }
7651
7652 snprintf(buf, len, "%d", count);
7653
7654 return 0;
7655}
7656
7657/*! \brief Dialplan function QUEUE_MEMBER() Sets the members penalty / paused / ringinuse. */
7658static int queue_function_mem_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
7659{
7660 int memvalue;
7661
7662 AST_DECLARE_APP_ARGS(args,
7663 AST_APP_ARG(queuename);
7664 AST_APP_ARG(option);
7665 AST_APP_ARG(interface);
7666 );
7667
7668 if (ast_strlen_zero(data)) {
7669 ast_log(LOG_ERROR,
7670 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
7671 cmd);
7672 return -1;
7673 }
7674
7675 AST_STANDARD_APP_ARGS(args, data);
7676
7677 if (ast_strlen_zero(args.option)
7678 || ast_strlen_zero(args.interface)) {
7679 ast_log(LOG_ERROR,
7680 "Missing required argument. %s([<queuename>],<option>,<interface>)\n",
7681 cmd);
7682 return -1;
7683 }
7684
7685 /*
7686 * If queuename is empty then the option will be
7687 * set for the interface in all queues.
7688 */
7689
7690 memvalue = atoi(value);
7691 if (!strcasecmp(args.option, "penalty")) {
7692 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, memvalue)) {
7693 ast_log(LOG_ERROR, "Invalid interface, queue, or penalty\n");
7694 return -1;
7695 }
7696 } else if (!strcasecmp(args.option, "paused")) {
7697 memvalue = (memvalue <= 0) ? 0 : 1;
7698 if (set_member_paused(args.queuename, args.interface, NULL, memvalue)) {
7699 ast_log(LOG_ERROR, "Invalid interface or queue\n");
7700 return -1;
7701 }
7702 } else if (!strcasecmp(args.option, "ignorebusy") /* ignorebusy is legacy */
7703 || !strcasecmp(args.option, "ringinuse")) {
7704 memvalue = (memvalue <= 0) ? 0 : 1;
7705 if (set_member_value(args.queuename, args.interface, MEMBER_RINGINUSE, memvalue)) {
7706 ast_log(LOG_ERROR, "Invalid interface or queue\n");
7707 return -1;
7708 }
7709 } else {
7710 ast_log(LOG_ERROR, "%s: Invalid option '%s' provided.\n", cmd, args.option);
7711 return -1;
7712 }
7713 return 0;
7714}
7715
7716/*!
7717 * \brief Get the total number of members in a specific queue (Deprecated)
7718 * \retval number of members
7719 * \retval -1 on error
7720*/
7721static int queue_function_qac_dep(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7722{
7723 int count = 0;
7724 struct member *m;
7725 struct call_queue *q;
7726 struct ao2_iterator mem_iter;
7727 static int depflag = 1;
7728
7729 if (depflag) {
7730 depflag = 0;
7731 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");
7732 }
7733
7734 if (ast_strlen_zero(data)) {
7735 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
7736 return -1;
7737 }
7738
7739 if ((q = find_load_queue_rt_friendly(data))) {
7740 ao2_lock(q);
7741 mem_iter = ao2_iterator_init(q->members, 0);
7742 while ((m = ao2_iterator_next(&mem_iter))) {
7743 /* Count the agents who are logged in and presently answering calls */
7744 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
7745 count++;
7746 }
7747 ao2_ref(m, -1);
7748 }
7749 ao2_iterator_destroy(&mem_iter);
7750 ao2_unlock(q);
7751 queue_t_unref(q, "Done with temporary reference in QUEUE_MEMBER_COUNT");
7752 } else {
7753 ast_log(LOG_WARNING, "queue %s was not found\n", data);
7754 }
7755
7756 snprintf(buf, len, "%d", count);
7757
7758 return 0;
7759}
7760
7761/*! \brief Dialplan function QUEUE_WAITING_COUNT() Get number callers waiting in a specific queue */
7762static int queue_function_queuewaitingcount(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7763{
7764 int count = 0;
7765 struct call_queue *q, tmpq = {
7766 .name = data,
7767 };
7768 struct ast_variable *var = NULL;
7769
7770 buf[0] = '\0';
7771
7772 if (ast_strlen_zero(data)) {
7773 ast_log(LOG_ERROR, "QUEUE_WAITING_COUNT requires an argument: queuename\n");
7774 return -1;
7775 }
7776
7777 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_WAITING_COUNT()"))) {
7778 ao2_lock(q);
7779 count = q->count;
7780 ao2_unlock(q);
7781 queue_t_unref(q, "Done with reference in QUEUE_WAITING_COUNT()");
7782 } else if ((var = ast_load_realtime("queues", "name", data, SENTINEL))) {
7783 /* if the queue is realtime but was not found in memory, this
7784 * means that the queue had been deleted from memory since it was
7785 * "dead." This means it has a 0 waiting count
7786 */
7787 count = 0;
7788 ast_variables_destroy(var);
7789 } else {
7790 ast_log(LOG_WARNING, "queue %s was not found\n", data);
7791 }
7792
7793 snprintf(buf, len, "%d", count);
7794
7795 return 0;
7796}
7797
7798/*! \brief Dialplan function QUEUE_MEMBER_LIST() Get list of members in a specific queue */
7799static int queue_function_queuememberlist(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7800{
7801 struct call_queue *q, tmpq = {
7802 .name = data,
7803 };
7804 struct member *m;
7805
7806 /* Ensure an otherwise empty list doesn't return garbage */
7807 buf[0] = '\0';
7808
7809 if (ast_strlen_zero(data)) {
7810 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
7811 return -1;
7812 }
7813
7814 if ((q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find for QUEUE_MEMBER_LIST()"))) {
7815 int buflen = 0, count = 0;
7816 struct ao2_iterator mem_iter;
7817
7818 ao2_lock(q);
7819 mem_iter = ao2_iterator_init(q->members, 0);
7820 while ((m = ao2_iterator_next(&mem_iter))) {
7821 /* strcat() is always faster than printf() */
7822 if (count++) {
7823 strncat(buf + buflen, ",", len - buflen - 1);
7824 buflen++;
7825 }
7826 strncat(buf + buflen, m->interface, len - buflen - 1);
7827 buflen += strlen(m->interface);
7828 /* Safeguard against overflow (negative length) */
7829 if (buflen >= len - 2) {
7830 ao2_ref(m, -1);
7831 ast_log(LOG_WARNING, "Truncating list\n");
7832 break;
7833 }
7834 ao2_ref(m, -1);
7835 }
7836 ao2_iterator_destroy(&mem_iter);
7837 ao2_unlock(q);
7838 queue_t_unref(q, "Done with QUEUE_MEMBER_LIST()");
7839 } else
7840 ast_log(LOG_WARNING, "queue %s was not found\n", data);
7841
7842 /* We should already be terminated, but let's make sure. */
7843 buf[len - 1] = '\0';
7844
7845 return 0;
7846}
7847
7848/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Gets the members penalty. */
7849static int queue_function_memberpenalty_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
7850{
7851 int penalty;
7852 AST_DECLARE_APP_ARGS(args,
7853 AST_APP_ARG(queuename);
7854 AST_APP_ARG(interface);
7855 );
7856 /* Make sure the returned value on error is NULL. */
7857 buf[0] = '\0';
7858
7859 if (ast_strlen_zero(data)) {
7860 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
7861 return -1;
7862 }
7863
7864 AST_STANDARD_APP_ARGS(args, data);
7865
7866 if (args.argc < 2) {
7867 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
7868 return -1;
7869 }
7870
7871 penalty = get_member_penalty (args.queuename, args.interface);
7872
7873 if (penalty >= 0) { /* remember that buf is already '\0' */
7874 snprintf (buf, len, "%d", penalty);
7875 }
7876
7877 return 0;
7878}
7879
7880/*! \brief Dialplan function QUEUE_MEMBER_PENALTY() Sets the members penalty. */
7881static int queue_function_memberpenalty_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
7882{
7883 int penalty;
7884 AST_DECLARE_APP_ARGS(args,
7885 AST_APP_ARG(queuename);
7886 AST_APP_ARG(interface);
7887 );
7888
7889 if (ast_strlen_zero(data)) {
7890 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
7891 return -1;
7892 }
7893
7894 AST_STANDARD_APP_ARGS(args, data);
7895
7896 if (args.argc < 2) {
7897 ast_log(LOG_ERROR, "Missing argument. QUEUE_MEMBER_PENALTY(<queuename>,<interface>)\n");
7898 return -1;
7899 }
7900
7901 penalty = atoi(value);
7902
7903 if (ast_strlen_zero(args.interface)) {
7904 ast_log (LOG_ERROR, "<interface> parameter can't be null\n");
7905 return -1;
7906 }
7907
7908 /* if queuename = NULL then penalty will be set for interface in all the queues. */
7909 if (set_member_value(args.queuename, args.interface, MEMBER_PENALTY, penalty)) {
7910 ast_log(LOG_ERROR, "Invalid interface, queue or penalty\n");
7911 return -1;
7912 }
7913
7914 return 0;
7915}
7916
7917static struct ast_custom_function queueexists_function = {
7918 .name = "QUEUE_EXISTS",
7919 .read = queue_function_exists,
7920};
7921
7922static struct ast_custom_function queuevar_function = {
7923 .name = "QUEUE_VARIABLES",
7924 .read = queue_function_var,
7925};
7926
7927static struct ast_custom_function queuemembercount_function = {
7928 .name = "QUEUE_MEMBER",
7929 .read = queue_function_mem_read,
7930 .write = queue_function_mem_write,
7931};
7932
7933static struct ast_custom_function queuemembercount_dep = {
7934 .name = "QUEUE_MEMBER_COUNT",
7935 .read = queue_function_qac_dep,
7936};
7937
7938static struct ast_custom_function queuewaitingcount_function = {
7939 .name = "QUEUE_WAITING_COUNT",
7940 .read = queue_function_queuewaitingcount,
7941};
7942
7943static struct ast_custom_function queuememberlist_function = {
7944 .name = "QUEUE_MEMBER_LIST",
7945 .read = queue_function_queuememberlist,
7946};
7947
7948static struct ast_custom_function queuememberpenalty_function = {
7949 .name = "QUEUE_MEMBER_PENALTY",
7950 .read = queue_function_memberpenalty_read,
7951 .write = queue_function_memberpenalty_write,
7952};
7953
7954/*! \brief Reload the rules defined in queuerules.conf
7955 *
7956 * \param reload If 1, then only process queuerules.conf if the file
7957 * has changed since the last time we inspected it.
7958 * \return Always returns AST_MODULE_LOAD_SUCCESS
7959 */
7960static int reload_queue_rules(int reload)
7961{
7962 struct ast_config *cfg;
7963 struct rule_list *rl_iter, *new_rl;
7964 struct penalty_rule *pr_iter;
7965 char *rulecat = NULL;
7966 struct ast_variable *rulevar = NULL;
7967 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
7968
7969 if (!(cfg = ast_config_load("queuerules.conf", config_flags))) {
7970 ast_log(LOG_NOTICE, "No queuerules.conf file found, queues will not follow penalty rules\n");
7971 return AST_MODULE_LOAD_SUCCESS;
7972 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
7973 ast_log(LOG_NOTICE, "queuerules.conf has not changed since it was last loaded. Not taking any action.\n");
7974 return AST_MODULE_LOAD_SUCCESS;
7975 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
7976 ast_log(LOG_ERROR, "Config file queuerules.conf is in an invalid format. Aborting.\n");
7977 return AST_MODULE_LOAD_SUCCESS;
7978 }
7979
7980 AST_LIST_LOCK(&rule_lists);
7981 while ((rl_iter = AST_LIST_REMOVE_HEAD(&rule_lists, list))) {
7982 while ((pr_iter = AST_LIST_REMOVE_HEAD(&rl_iter->rules, list)))
7983 ast_free(pr_iter);
7984 ast_free(rl_iter);
7985 }
7986 while ((rulecat = ast_category_browse(cfg, rulecat))) {
7987 if (!(new_rl = ast_calloc(1, sizeof(*new_rl)))) {
7988 AST_LIST_UNLOCK(&rule_lists);
7989 ast_config_destroy(cfg);
7990 return AST_MODULE_LOAD_FAILURE;
7991 } else {
7992 ast_copy_string(new_rl->name, rulecat, sizeof(new_rl->name));
7993 AST_LIST_INSERT_TAIL(&rule_lists, new_rl, list);
7994 for (rulevar = ast_variable_browse(cfg, rulecat); rulevar; rulevar = rulevar->next)
7995 if(!strcasecmp(rulevar->name, "penaltychange"))
7996 insert_penaltychange(new_rl->name, rulevar->value, rulevar->lineno);
7997 else
7998 ast_log(LOG_WARNING, "Don't know how to handle rule type '%s' on line %d\n", rulevar->name, rulevar->lineno);
7999 }
8000 }
8001 AST_LIST_UNLOCK(&rule_lists);
8002
8003 ast_config_destroy(cfg);
8004
8005 return AST_MODULE_LOAD_SUCCESS;
8006}
8007
8008/*! Set the global queue parameters as defined in the "general" section of queues.conf */
8009static void queue_set_global_params(struct ast_config *cfg)
8010{
8011 const char *general_val = NULL;
8012 queue_persistent_members = 0;
8013 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers"))) {
8014 queue_persistent_members = ast_true(general_val);
8015 }
8016 autofill_default = 0;
8017 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill"))) {
8018 autofill_default = ast_true(general_val);
8019 }
8020 montype_default = 0;
8021 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type"))) {
8022 if (!strcasecmp(general_val, "mixmonitor"))
8023 montype_default = 1;
8024 }
8025 update_cdr = 0;
8026 if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr"))) {
8027 update_cdr = ast_true(general_val);
8028 }
8029 shared_lastcall = 0;
8030 if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall"))) {
8031 shared_lastcall = ast_true(general_val);
8032 }
8033 negative_penalty_invalid = 0;
8034 if ((general_val = ast_variable_retrieve(cfg, "general", "negative_penalty_invalid"))) {
8035 negative_penalty_invalid = ast_true(general_val);
8036 }
8037 log_membername_as_agent = 0;
8038 if ((general_val = ast_variable_retrieve(cfg, "general", "log_membername_as_agent"))) {
8039 log_membername_as_agent = ast_true(general_val);
8040 }
8041}
8042
8043/*! \brief reload information pertaining to a single member
8044 *
8045 * This function is called when a member = line is encountered in
8046 * queues.conf.
8047 *
8048 * \param memberdata The part after member = in the config file
8049 * \param q The queue to which this member belongs
8050 */
8051static void reload_single_member(const char *memberdata, struct call_queue *q)
8052{
8053 char *membername, *interface, *state_interface, *tmp;
8054 char *parse;
8055 struct member *cur, *newm;
8056 struct member tmpmem;
8057 int penalty;
8058 int ringinuse;
8059 AST_DECLARE_APP_ARGS(args,
8060 AST_APP_ARG(interface);
8061 AST_APP_ARG(penalty);
8062 AST_APP_ARG(membername);
8063 AST_APP_ARG(state_interface);
8064 AST_APP_ARG(ringinuse);
8065 );
8066
8067 if (ast_strlen_zero(memberdata)) {
8068 ast_log(LOG_WARNING, "Empty queue member definition. Moving on!\n");
8069 return;
8070 }
8071
8072 /* Add a new member */
8073 parse = ast_strdupa(memberdata);
8074
8075 AST_STANDARD_APP_ARGS(args, parse);
8076
8077 interface = args.interface;
8078 if (!ast_strlen_zero(args.penalty)) {
8079 tmp = args.penalty;
8080 ast_strip(tmp);
8081 penalty = atoi(tmp);
8082 if (penalty < 0) {
8083 penalty = 0;
8084 }
8085 } else {
8086 penalty = 0;
8087 }
8088
8089 if (!ast_strlen_zero(args.membername)) {
8090 membername = args.membername;
8091 ast_strip(membername);
8092 } else {
8093 membername = interface;
8094 }
8095
8096 if (!ast_strlen_zero(args.state_interface)) {
8097 state_interface = args.state_interface;
8098 ast_strip(state_interface);
8099 } else {
8100 state_interface = interface;
8101 }
8102
8103 if (!ast_strlen_zero(args.ringinuse)) {
8104 tmp = args.ringinuse;
8105 ast_strip(tmp);
8106 if (ast_true(tmp)) {
8107 ringinuse = 1;
8108 } else if (ast_false(tmp)) {
8109 ringinuse = 0;
8110 } else {
8111 ast_log(LOG_ERROR, "Member %s has an invalid ringinuse value. Using %s ringinuse value.\n",
8112 membername, q->name);
8113 ringinuse = q->ringinuse;
8114 }
8115 } else {
8116 ringinuse = q->ringinuse;
8117 }
8118
8119 /* Find the old position in the list */
8120 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
8121 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER);
8122
8123 if ((newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface, ringinuse))) {
8124 if (cur) {
8125 /* Round Robin Queue Position must be copied if this is replacing an existing member */
8126 ao2_lock(q->members);
8127 newm->queuepos = cur->queuepos;
8128 ao2_link(q->members, newm);
8129 ao2_unlink(q->members, cur);
8130 ao2_unlock(q->members);
8131 } else {
8132 /* Otherwise we need to add using the function that will apply a round robin queue position manually. */
8133 member_add_to_queue(q, newm);
8134 }
8135 ao2_ref(newm, -1);
8136 }
8137 newm = NULL;
8138
8139 if (cur) {
8140 ao2_ref(cur, -1);
8141 }
8142}
8143
8144static int mark_member_dead(void *obj, void *arg, int flags)
8145{
8146 struct member *member = obj;
8147 if (!member->dynamic && !member->realtime) {
8148 member->delme = 1;
8149 }
8150 return 0;
8151}
8152
8153static int kill_dead_members(void *obj, void *arg, int flags)
8154{
8155 struct member *member = obj;
8156
8157 if (!member->delme) {
8158 member->status = get_queue_member_status(member);
8159 return 0;
8160 } else {
8161 return CMP_MATCH;
8162 }
8163}
8164
8165/*! \brief Reload information pertaining to a particular queue
8166 *
8167 * Once we have isolated a queue within reload_queues, we call this. This will either
8168 * reload information for the queue or if we're just reloading member information, we'll just
8169 * reload that without touching other settings within the queue
8170 *
8171 * \param cfg The configuration which we are reading
8172 * \param mask Tells us what information we need to reload
8173 * \param queuename The name of the queue we are reloading information from
8174 * \retval void
8175 */
8176static void reload_single_queue(struct ast_config *cfg, struct ast_flags *mask, const char *queuename)
8177{
8178 int new;
8179 struct call_queue *q = NULL;
8180 /*We're defining a queue*/
8181 struct call_queue tmpq = {
8182 .name = queuename,
8183 };
8184 const char *tmpvar;
8185 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
8186 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
8187 int prev_weight = 0;
8188 struct ast_variable *var;
8189 if (!(q = ao2_t_find(queues, &tmpq, OBJ_POINTER, "Find queue for reload"))) {
8190 if (queue_reload) {
8191 /* Make one then */
8192 if (!(q = alloc_queue(queuename))) {
8193 return;
8194 }
8195 } else {
8196 /* Since we're not reloading queues, this means that we found a queue
8197 * in the configuration file which we don't know about yet. Just return.
8198 */
8199 return;
8200 }
8201 new = 1;
8202 } else {
8203 new = 0;
8204 }
8205
8206 if (!new) {
8207 ao2_lock(q);
8208 prev_weight = q->weight ? 1 : 0;
8209 }
8210 /* Check if we already found a queue with this name in the config file */
8211 if (q->found) {
8212 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", queuename);
8213 if (!new) {
8214 /* It should be impossible to *not* hit this case*/
8215 ao2_unlock(q);
8216 }
8217 queue_t_unref(q, "We exist! Expiring temporary pointer");
8218 return;
8219 }
8220 /* Due to the fact that the "linear" strategy will have a different allocation
8221 * scheme for queue members, we must devise the queue's strategy before other initializations.
8222 * To be specific, the linear strategy needs to function like a linked list, meaning the ao2
8223 * container used will have only a single bucket instead of the typical number.
8224 */
8225 if (queue_reload) {
8226 if ((tmpvar = ast_variable_retrieve(cfg, queuename, "strategy"))) {
8227 q->strategy = strat2int(tmpvar);
8228 if (q->strategy < 0) {
8229 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
8230 tmpvar, q->name);
8231 q->strategy = QUEUE_STRATEGY_RINGALL;
8232 }
8233 } else {
8234 q->strategy = QUEUE_STRATEGY_RINGALL;
8235 }
8236 init_queue(q);
8237 }
8238 if (member_reload) {
8239 ao2_callback(q->members, OBJ_NODATA, mark_member_dead, NULL);
8240 q->found = 1;
8241 }
8242
8243 /* On the first pass we just read the parameters of the queue */
8244 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
8245 if (queue_reload && strcasecmp(var->name, "member")) {
8246 queue_set_param(q, var->name, var->value, var->lineno, 1);
8247 }
8248 }
8249
8250 /* On the second pass, we read members */
8251 for (var = ast_variable_browse(cfg, queuename); var; var = var->next) {
8252 if (member_reload && !strcasecmp(var->name, "member")) {
8253 reload_single_member(var->value, q);
8254 }
8255 }
8256
8257 /* At this point, we've determined if the queue has a weight, so update use_weight
8258 * as appropriate
8259 */
8260 if (!q->weight && prev_weight) {
8261 ast_atomic_fetchadd_int(&use_weight, -1);
8262 } else if (q->weight && !prev_weight) {
8263 ast_atomic_fetchadd_int(&use_weight, +1);
8264 }
8265
8266 /* Free remaining members marked as delme */
8267 if (member_reload) {
8268 ao2_lock(q->members);
8269 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE, queue_delme_members_decrement_followers, q);
8270 ao2_callback(q->members, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, kill_dead_members, q);
8271 ao2_unlock(q->members);
8272 }
8273
8274 if (new) {
8275 queues_t_link(queues, q, "Add queue to container");
8276 } else {
8277 ao2_unlock(q);
8278 }
8279 queue_t_unref(q, "Expiring creation reference");
8280}
8281
8282static int remove_members_and_mark_unfound(void *obj, void *arg, int flags)
8283{
8284 struct call_queue *q = obj;
8285 char *queuename = arg;
8286 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
8287 q->found = 0;
8288
8289 }
8290 return 0;
8291}
8292
8293static int mark_dead_and_unfound(void *obj, void *arg, int flags)
8294{
8295 struct call_queue *q = obj;
8296 char *queuename = arg;
8297 if (!q->realtime && (ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name))) {
8298 q->dead = 1;
8299 q->found = 0;
8300 }
8301 return 0;
8302}
8303
8304static int kill_dead_queues(void *obj, void *arg, int flags)
8305{
8306 struct call_queue *q = obj;
8307 char *queuename = arg;
8308 if ((ast_strlen_zero(queuename) || !strcasecmp(queuename, q->name)) && q->dead) {
8309 return CMP_MATCH;
8310 } else {
8311 return 0;
8312 }
8313}
8314
8315/*! \brief reload the queues.conf file
8316 *
8317 * This function reloads the information in the general section of the queues.conf
8318 * file and potentially more, depending on the value of mask.
8319 *
8320 * \param reload 0 if we are calling this the first time, 1 every other time
8321 * \param mask Gives flags telling us what information to actually reload
8322 * \param queuename If set to a non-zero string, then only reload information from
8323 * that particular queue. Otherwise inspect all queues
8324 * \retval -1 Failure occurred
8325 * \retval 0 All clear!
8326 */
8327static int reload_queues(int reload, struct ast_flags *mask, const char *queuename)
8328{
8329 struct ast_config *cfg;
8330 char *cat;
8331 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
8332 const int queue_reload = ast_test_flag(mask, QUEUE_RELOAD_PARAMETERS);
8333 const int member_reload = ast_test_flag(mask, QUEUE_RELOAD_MEMBER);
8334
8335 if (!(cfg = ast_config_load("queues.conf", config_flags))) {
8336 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
8337 return -1;
8338 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
8339 return 0;
8340 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
8341 ast_log(LOG_ERROR, "Config file queues.conf is in an invalid format. Aborting.\n");
8342 return -1;
8343 }
8344
8345 /* We've made it here, so it looks like we're doing operations on all queues. */
8346 ao2_lock(queues);
8347
8348 /* Mark all queues as dead for the moment if we're reloading queues.
8349 * For clarity, we could just be reloading members, in which case we don't want to mess
8350 * with the other queue parameters at all*/
8351 if (queue_reload) {
8352 ao2_callback(queues, OBJ_NODATA | OBJ_NOLOCK, mark_dead_and_unfound, (char *) queuename);
8353 }
8354
8355 if (member_reload) {
8356 ao2_callback(queues, OBJ_NODATA, remove_members_and_mark_unfound, (char *) queuename);
8357 }
8358
8359 /* Chug through config file */
8360 cat = NULL;
8361 while ((cat = ast_category_browse(cfg, cat)) ) {
8362 if (!strcasecmp(cat, "general") && queue_reload) {
8363 queue_set_global_params(cfg);
8364 continue;
8365 }
8366 if (ast_strlen_zero(queuename) || !strcasecmp(cat, queuename))
8367 reload_single_queue(cfg, mask, cat);
8368 }
8369
8370 ast_config_destroy(cfg);
8371 /* Unref all the dead queues if we were reloading queues */
8372 if (queue_reload) {
8373 ao2_callback(queues, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK | OBJ_NOLOCK, kill_dead_queues, (char *) queuename);
8374 }
8375 ao2_unlock(queues);
8376 return 0;
8377}
8378
8379/*! \brief Facilitates resetting statistics for a queue
8380 *
8381 * This function actually does not reset any statistics, but
8382 * rather finds a call_queue struct which corresponds to the
8383 * passed-in queue name and passes that structure to the
8384 * clear_queue function. If no queuename is passed in, then
8385 * all queues will have their statistics reset.
8386 *
8387 * \param queuename The name of the queue to reset the statistics
8388 * for. If this is NULL or zero-length, then this means to reset
8389 * the statistics for all queues
8390 * \retval void
8391 */
8392static int clear_stats(const char *queuename)
8393{
8394 struct call_queue *q;
8395 struct ao2_iterator queue_iter;
8396
8397 queue_iter = ao2_iterator_init(queues, 0);
8398 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8399 ao2_lock(q);
8400 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename))
8401 clear_queue(q);
8402 ao2_unlock(q);
8403 queue_t_unref(q, "Done with iterator");
8404 }
8405 ao2_iterator_destroy(&queue_iter);
8406 return 0;
8407}
8408
8409/*! \brief The command center for all reload operations
8410 *
8411 * Whenever any piece of queue information is to be reloaded, this function
8412 * is called. It interprets the flags set in the mask parameter and acts
8413 * based on how they are set.
8414 *
8415 * \param reload True if we are reloading information, false if we are loading
8416 * information for the first time.
8417 * \param mask A bitmask which tells the handler what actions to take
8418 * \param queuename The name of the queue on which we wish to take action
8419 * \retval 0 All reloads were successful
8420 * \retval non-zero There was a failure
8421 */
8422static int reload_handler(int reload, struct ast_flags *mask, const char *queuename)
8423{
8424 int res = 0;
8425
8426 if (ast_test_flag(mask, QUEUE_RELOAD_RULES)) {
8427 res |= reload_queue_rules(reload);
8428 }
8429 if (ast_test_flag(mask, QUEUE_RESET_STATS)) {
8430 res |= clear_stats(queuename);
8431 }
8432 if (ast_test_flag(mask, (QUEUE_RELOAD_PARAMETERS | QUEUE_RELOAD_MEMBER))) {
8433 res |= reload_queues(reload, mask, queuename);
8434 }
8435 return res;
8436}
8437
8438/*! \brief direct ouput to manager or cli with proper terminator */
8439static void do_print(struct mansession *s, int fd, const char *str)
8440{
8441 if (s) {
8442 astman_append(s, "%s\r\n", str);
8443 } else {
8444 ast_cli(fd, "%s\n", str);
8445 }
8446}
8447
8448/*!
8449 * \brief Show queue(s) status and statistics
8450 *
8451 * List the queues strategy, calls processed, members logged in,
8452 * other queue statistics such as avg hold time.
8453*/
8454static char *__queues_show(struct mansession *s, int fd, int argc, const char * const *argv)
8455{
8456 struct call_queue *q;
8457 struct ast_str *out = ast_str_alloca(512);
8458 int found = 0;
8459 time_t now = time(NULL);
8460 struct ao2_iterator queue_iter;
8461 struct ao2_iterator mem_iter;
8462
8463 if (argc != 2 && argc != 3) {
8464 return CLI_SHOWUSAGE;
8465 }
8466
8467 if (argc == 3) { /* specific queue */
8468 if ((q = find_load_queue_rt_friendly(argv[2]))) {
8469 queue_t_unref(q, "Done with temporary pointer");
8470 }
8471 } else if (ast_check_realtime("queues")) {
8472 /* This block is to find any queues which are defined in realtime but
8473 * which have not yet been added to the in-core container
8474 */
8475 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
8476 char *queuename;
8477 if (cfg) {
8478 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
8479 if ((q = find_load_queue_rt_friendly(queuename))) {
8480 queue_t_unref(q, "Done with temporary pointer");
8481 }
8482 }
8483 ast_config_destroy(cfg);
8484 }
8485 }
8486
8487 ao2_lock(queues);
8488 queue_iter = ao2_iterator_init(queues, AO2_ITERATOR_DONTLOCK);
8489 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8490 float sl;
8491 struct call_queue *realtime_queue = NULL;
8492
8493 ao2_lock(q);
8494 /* This check is to make sure we don't print information for realtime
8495 * queues which have been deleted from realtime but which have not yet
8496 * been deleted from the in-core container. Only do this if we're not
8497 * looking for a specific queue.
8498 */
8499 if (argc < 3 && q->realtime) {
8500 realtime_queue = find_load_queue_rt_friendly(q->name);
8501 if (!realtime_queue) {
8502 ao2_unlock(q);
8503 queue_t_unref(q, "Done with iterator");
8504 continue;
8505 }
8506 queue_t_unref(realtime_queue, "Queue is already in memory");
8507 }
8508
8509 if (argc == 3 && strcasecmp(q->name, argv[2])) {
8510 ao2_unlock(q);
8511 queue_t_unref(q, "Done with iterator");
8512 continue;
8513 }
8514 found = 1;
8515
8516 ast_str_set(&out, 0, "%s has %d calls (max ", q->name, q->count);
8517 if (q->maxlen) {
8518 ast_str_append(&out, 0, "%d", q->maxlen);
8519 } else {
8520 ast_str_append(&out, 0, "unlimited");
8521 }
8522 sl = 0;
8523 if (q->callscompleted > 0) {
8524 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
8525 }
8526 ast_str_append(&out, 0, ") in '%s' strategy (%ds holdtime, %ds talktime), W:%d, C:%d, A:%d, SL:%2.1f%% within %ds",
8527 int2strat(q->strategy), q->holdtime, q->talktime, q->weight,
8528 q->callscompleted, q->callsabandoned,sl,q->servicelevel);
8529 do_print(s, fd, ast_str_buffer(out));
8530 if (!ao2_container_count(q->members)) {
8531 do_print(s, fd, " No Members");
8532 } else {
8533 struct member *mem;
8534
8535 do_print(s, fd, " Members: ");
8536 mem_iter = ao2_iterator_init(q->members, 0);
8537 while ((mem = ao2_iterator_next(&mem_iter))) {
8538 ast_str_set(&out, 0, " %s", mem->membername);
8539 if (strcasecmp(mem->membername, mem->interface)) {
8540 ast_str_append(&out, 0, " (%s", mem->interface);
8541 if (!ast_strlen_zero(mem->state_interface)) {
8542 ast_str_append(&out, 0, " from %s", mem->state_interface);
8543 }
8544 ast_str_append(&out, 0, ")");
8545 }
8546 if (mem->penalty) {
8547 ast_str_append(&out, 0, " with penalty %d", mem->penalty);
8548 }
8549
8550 ast_str_append(&out, 0, " (ringinuse %s)", mem->ringinuse ? "enabled" : "disabled");
8551
8552 ast_str_append(&out, 0, "%s%s%s%s (%s)",
8553 mem->dynamic ? " (dynamic)" : "",
8554 mem->realtime ? " (realtime)" : "",
8555 mem->paused ? " (paused)" : "",
8556 mem->in_call ? " (in call)" : "",
8557 ast_devstate2str(mem->status));
8558 if (mem->calls) {
8559 ast_str_append(&out, 0, " has taken %d calls (last was %ld secs ago)",
8560 mem->calls, (long) (time(NULL) - mem->lastcall));
8561 } else {
8562 ast_str_append(&out, 0, " has taken no calls yet");
8563 }
8564 do_print(s, fd, ast_str_buffer(out));
8565 ao2_ref(mem, -1);
8566 }
8567 ao2_iterator_destroy(&mem_iter);
8568 }
8569 if (!q->head) {
8570 do_print(s, fd, " No Callers");
8571 } else {
8572 struct queue_ent *qe;
8573 int pos = 1;
8574
8575 do_print(s, fd, " Callers: ");
8576 for (qe = q->head; qe; qe = qe->next) {
8577 ast_str_set(&out, 0, " %d. %s (wait: %ld:%2.2ld, prio: %d)",
8578 pos++, ast_channel_name(qe->chan), (long) (now - qe->start) / 60,
8579 (long) (now - qe->start) % 60, qe->prio);
8580 do_print(s, fd, ast_str_buffer(out));
8581 }
8582 }
8583 do_print(s, fd, ""); /* blank line between entries */
8584 ao2_unlock(q);
8585 queue_t_unref(q, "Done with iterator"); /* Unref the iterator's reference */
8586 }
8587 ao2_iterator_destroy(&queue_iter);
8588 ao2_unlock(queues);
8589 if (!found) {
8590 if (argc == 3) {
8591 ast_str_set(&out, 0, "No such queue: %s.", argv[2]);
8592 } else {
8593 ast_str_set(&out, 0, "No queues.");
8594 }
8595 do_print(s, fd, ast_str_buffer(out));
8596 }
8597 return CLI_SUCCESS;
8598}
8599
8600/*!
8601 * \brief Check if a given word is in a space-delimited list
8602 *
8603 * \param list Space delimited list of words
8604 * \param word The word used to search the list
8605 *
8606 * \note This function will not return 1 if the word is at the very end of the
8607 * list (followed immediately by a \0, not a space) since it is used for
8608 * checking tab-completion and a word at the end is still being tab-completed.
8609 *
8610 * \return Returns 1 if the word is found
8611 * \return Returns 0 if the word is not found
8612*/
8613static int word_in_list(const char *list, const char *word) {
8614 int list_len, word_len = strlen(word);
8615 const char *find, *end_find, *end_list;
8616
8617 /* strip whitespace from front */
8618 while(isspace(*list)) {
8619 list++;
8620 }
8621
8622 while((find = strstr(list, word))) {
8623 /* beginning of find starts inside another word? */
8624 if (find != list && *(find - 1) != ' ') {
8625 list = find;
8626 /* strip word from front */
8627 while(!isspace(*list) && *list != '\0') {
8628 list++;
8629 }
8630 /* strip whitespace from front */
8631 while(isspace(*list)) {
8632 list++;
8633 }
8634 continue;
8635 }
8636
8637 /* end of find ends inside another word or at very end of list? */
8638 list_len = strlen(list);
8639 end_find = find + word_len;
8640 end_list = list + list_len;
8641 if (end_find == end_list || *end_find != ' ') {
8642 list = find;
8643 /* strip word from front */
8644 while(!isspace(*list) && *list != '\0') {
8645 list++;
8646 }
8647 /* strip whitespace from front */
8648 while(isspace(*list)) {
8649 list++;
8650 }
8651 continue;
8652 }
8653
8654 /* terminating conditions satisfied, word at beginning or separated by ' ' */
8655 return 1;
8656 }
8657
8658 return 0;
8659}
8660
8661/*!
8662 * \brief Check if a given word is in a space-delimited list
8663 *
8664 * \param line The line as typed not including the current word being completed
8665 * \param word The word currently being completed
8666 * \param pos The number of completed words in line
8667 * \param state The nth desired completion option
8668 * \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.
8669 *
8670 * \return Returns the queue tab-completion for the given word and state
8671*/
8672static char *complete_queue(const char *line, const char *word, int pos, int state, ptrdiff_t word_list_offset)
8673{
8674 struct call_queue *q;
8675 char *ret = NULL;
8676 int which = 0;
8677 int wordlen = strlen(word);
8678 struct ao2_iterator queue_iter;
8679 const char *word_list = NULL;
8680
8681 /* for certain commands, already completed items should be left out of
8682 * the list */
8683 if (word_list_offset && strlen(line) >= word_list_offset) {
8684 word_list = line + word_list_offset;
8685 }
8686
8687 queue_iter = ao2_iterator_init(queues, 0);
8688 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8689 if (!strncasecmp(word, q->name, wordlen) && ++which > state
8690 && (!word_list_offset || !word_in_list(word_list, q->name))) {
8691 ret = ast_strdup(q->name);
8692 queue_t_unref(q, "Done with iterator");
8693 break;
8694 }
8695 queue_t_unref(q, "Done with iterator");
8696 }
8697 ao2_iterator_destroy(&queue_iter);
8698
8699 /* Pretend "rules" is at the end of the queues list in certain
8700 * circumstances since it is an alternate command that should be
8701 * tab-completable for "queue show" */
8702 if (!ret && which == state && !wordlen && !strncmp("queue show", line, 10)) {
8703 ret = ast_strdup("rules");
8704 }
8705
8706 return ret;
8707}
8708
8709static char *complete_queue_show(const char *line, const char *word, int pos, int state)
8710{
8711 if (pos == 2) {
8712 return complete_queue(line, word, pos, state, 0);
8713 }
8714 return NULL;
8715}
8716
8717static char *queue_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
8718{
8719 switch ( cmd ) {
8720 case CLI_INIT:
8721 e->command = "queue show";
8722 e->usage =
8723 "Usage: queue show\n"
8724 " Provides summary information on a specified queue.\n";
8725 return NULL;
8726 case CLI_GENERATE:
8727 return complete_queue_show(a->line, a->word, a->pos, a->n);
8728 }
8729
8730 return __queues_show(NULL, a->fd, a->argc, a->argv);
8731}
8732
8733/*!\brief callback to display queues status in manager
8734 \addtogroup Group_AMI
8735 */
8736static int manager_queues_show(struct mansession *s, const struct message *m)
8737{
8738 static const char * const a[] = { "queue", "show" };
8739
8740 __queues_show(s, -1, 2, a);
8741 astman_append(s, "\r\n\r\n"); /* Properly terminate Manager output */
8742
8743 return RESULT_SUCCESS;
8744}
8745
8746static int manager_queue_rule_show(struct mansession *s, const struct message *m)
8747{
8748 const char *rule = astman_get_header(m, "Rule");
8749 const char *id = astman_get_header(m, "ActionID");
8750 struct rule_list *rl_iter;
8751 struct penalty_rule *pr_iter;
8752
8753 astman_append(s, "Response: Success\r\n");
8754 if (!ast_strlen_zero(id)) {
8755 astman_append(s, "ActionID: %s\r\n", id);
8756 }
8757
8758 AST_LIST_LOCK(&rule_lists);
8759 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
8760 if (ast_strlen_zero(rule) || !strcasecmp(rule, rl_iter->name)) {
8761 astman_append(s, "RuleList: %s\r\n", rl_iter->name);
8762 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
8763 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 );
8764 }
8765 if (!ast_strlen_zero(rule)) {
8766 break;
8767 }
8768 }
8769 }
8770 AST_LIST_UNLOCK(&rule_lists);
8771
8772 /*
8773 * Two blank lines instead of one because the Response and
8774 * ActionID headers used to not be present.
8775 */
8776 astman_append(s, "\r\n\r\n");
8777
8778 return RESULT_SUCCESS;
8779}
8780
8781/*! \brief Summary of queue info via the AMI */
8782static int manager_queues_summary(struct mansession *s, const struct message *m)
8783{
8784 time_t now;
8785 int qmemcount = 0;
8786 int qmemavail = 0;
8787 int qchancount = 0;
8788 int qlongestholdtime = 0;
8789 const char *id = astman_get_header(m, "ActionID");
8790 const char *queuefilter = astman_get_header(m, "Queue");
8791 char idText[256] = "";
8792 struct call_queue *q;
8793 struct queue_ent *qe;
8794 struct member *mem;
8795 struct ao2_iterator queue_iter;
8796 struct ao2_iterator mem_iter;
8797
8798 astman_send_ack(s, m, "Queue summary will follow");
8799 time(&now);
8800 if (!ast_strlen_zero(id)) {
8801 snprintf(idText, 256, "ActionID: %s\r\n", id);
8802 }
8803 queue_iter = ao2_iterator_init(queues, 0);
8804 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8805 ao2_lock(q);
8806
8807 /* List queue properties */
8808 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
8809 /* Reset the necessary local variables if no queuefilter is set*/
8810 qmemcount = 0;
8811 qmemavail = 0;
8812 qchancount = 0;
8813 qlongestholdtime = 0;
8814
8815 /* List Queue Members */
8816 mem_iter = ao2_iterator_init(q->members, 0);
8817 while ((mem = ao2_iterator_next(&mem_iter))) {
8818 if ((mem->status != AST_DEVICE_UNAVAILABLE) && (mem->status != AST_DEVICE_INVALID)) {
8819 ++qmemcount;
8820 if (member_status_available(mem->status) && !mem->paused) {
8821 ++qmemavail;
8822 }
8823 }
8824 ao2_ref(mem, -1);
8825 }
8826 ao2_iterator_destroy(&mem_iter);
8827 for (qe = q->head; qe; qe = qe->next) {
8828 if ((now - qe->start) > qlongestholdtime) {
8829 qlongestholdtime = now - qe->start;
8830 }
8831 ++qchancount;
8832 }
8833 astman_append(s, "Event: QueueSummary\r\n"
8834 "Queue: %s\r\n"
8835 "LoggedIn: %d\r\n"
8836 "Available: %d\r\n"
8837 "Callers: %d\r\n"
8838 "HoldTime: %d\r\n"
8839 "TalkTime: %d\r\n"
8840 "LongestHoldTime: %d\r\n"
8841 "%s"
8842 "\r\n",
8843 q->name, qmemcount, qmemavail, qchancount, q->holdtime, q->talktime, qlongestholdtime, idText);
8844 }
8845 ao2_unlock(q);
8846 queue_t_unref(q, "Done with iterator");
8847 }
8848 ao2_iterator_destroy(&queue_iter);
8849 astman_append(s,
8850 "Event: QueueSummaryComplete\r\n"
8851 "%s"
8852 "\r\n", idText);
8853
8854 return RESULT_SUCCESS;
8855}
8856
8857/*! \brief Queue status info via AMI */
8858static int manager_queues_status(struct mansession *s, const struct message *m)
8859{
8860 time_t now;
8861 int pos;
8862 const char *id = astman_get_header(m,"ActionID");
8863 const char *queuefilter = astman_get_header(m,"Queue");
8864 const char *memberfilter = astman_get_header(m,"Member");
8865 char idText[256] = "";
8866 struct call_queue *q;
8867 struct queue_ent *qe;
8868 float sl = 0;
8869 struct member *mem;
8870 struct ao2_iterator queue_iter;
8871 struct ao2_iterator mem_iter;
8872
8873 astman_send_ack(s, m, "Queue status will follow");
8874 time(&now);
8875 if (!ast_strlen_zero(id)) {
8876 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
8877 }
8878
8879 queue_iter = ao2_iterator_init(queues, 0);
8880 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
8881 ao2_lock(q);
8882
8883 /* List queue properties */
8884 if (ast_strlen_zero(queuefilter) || !strcasecmp(q->name, queuefilter)) {
8885 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
8886 astman_append(s, "Event: QueueParams\r\n"
8887 "Queue: %s\r\n"
8888 "Max: %d\r\n"
8889 "Strategy: %s\r\n"
8890 "Calls: %d\r\n"
8891 "Holdtime: %d\r\n"
8892 "TalkTime: %d\r\n"
8893 "Completed: %d\r\n"
8894 "Abandoned: %d\r\n"
8895 "ServiceLevel: %d\r\n"
8896 "ServicelevelPerf: %2.1f\r\n"
8897 "Weight: %d\r\n"
8898 "%s"
8899 "\r\n",
8900 q->name, q->maxlen, int2strat(q->strategy), q->count, q->holdtime, q->talktime, q->callscompleted,
8901 q->callsabandoned, q->servicelevel, sl, q->weight, idText);
8902 /* List Queue Members */
8903 mem_iter = ao2_iterator_init(q->members, 0);
8904 while ((mem = ao2_iterator_next(&mem_iter))) {
8905 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter) || !strcmp(mem->membername, memberfilter)) {
8906 astman_append(s, "Event: QueueMember\r\n"
8907 "Queue: %s\r\n"
8908 "Name: %s\r\n"
8909 "Location: %s\r\n"
8910 "StateInterface: %s\r\n"
8911 "Membership: %s\r\n"
8912 "Penalty: %d\r\n"
8913 "CallsTaken: %d\r\n"
8914 "LastCall: %d\r\n"
8915 "IsInCall: %d\r\n"
8916 "Status: %d\r\n"
8917 "Paused: %d\r\n"
8918 "%s"
8919 "\r\n",
8920 q->name, mem->membername, mem->interface, mem->state_interface, mem->dynamic ? "dynamic" : "static",
8921 mem->penalty, mem->calls, (int)mem->lastcall, mem->in_call, mem->status,
8922 mem->paused, idText);
8923 }
8924 ao2_ref(mem, -1);
8925 }
8926 ao2_iterator_destroy(&mem_iter);
8927 /* List Queue Entries */
8928 pos = 1;
8929 for (qe = q->head; qe; qe = qe->next) {
8930 astman_append(s, "Event: QueueEntry\r\n"
8931 "Queue: %s\r\n"
8932 "Position: %d\r\n"
8933 "Channel: %s\r\n"
8934 "Uniqueid: %s\r\n"
8935 "CallerIDNum: %s\r\n"
8936 "CallerIDName: %s\r\n"
8937 "ConnectedLineNum: %s\r\n"
8938 "ConnectedLineName: %s\r\n"
8939 "Wait: %ld\r\n"
8940 "%s"
8941 "\r\n",
8942 q->name, pos++, ast_channel_name(qe->chan), ast_channel_uniqueid(qe->chan),
8943 S_COR(ast_channel_caller(qe->chan)->id.number.valid, ast_channel_caller(qe->chan)->id.number.str, "unknown"),
8944 S_COR(ast_channel_caller(qe->chan)->id.name.valid, ast_channel_caller(qe->chan)->id.name.str, "unknown"),
8945 S_COR(ast_channel_connected(qe->chan)->id.number.valid, ast_channel_connected(qe->chan)->id.number.str, "unknown"),
8946 S_COR(ast_channel_connected(qe->chan)->id.name.valid, ast_channel_connected(qe->chan)->id.name.str, "unknown"),
8947 (long) (now - qe->start), idText);
8948 }
8949 }
8950 ao2_unlock(q);
8951 queue_t_unref(q, "Done with iterator");
8952 }
8953 ao2_iterator_destroy(&queue_iter);
8954
8955 astman_append(s,
8956 "Event: QueueStatusComplete\r\n"
8957 "%s"
8958 "\r\n",idText);
8959
8960 return RESULT_SUCCESS;
8961}
8962
8963static int manager_add_queue_member(struct mansession *s, const struct message *m)
8964{
8965 const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
8966 int paused, penalty = 0;
8967
8968 queuename = astman_get_header(m, "Queue");
8969 interface = astman_get_header(m, "Interface");
8970 penalty_s = astman_get_header(m, "Penalty");
8971 paused_s = astman_get_header(m, "Paused");
8972 membername = astman_get_header(m, "MemberName");
8973 state_interface = astman_get_header(m, "StateInterface");
8974
8975 if (ast_strlen_zero(queuename)) {
8976 astman_send_error(s, m, "'Queue' not specified.");
8977 return 0;
8978 }
8979
8980 if (ast_strlen_zero(interface)) {
8981 astman_send_error(s, m, "'Interface' not specified.");
8982 return 0;
8983 }
8984
8985 if (ast_strlen_zero(penalty_s)) {
8986 penalty = 0;
8987 } else if (sscanf(penalty_s, "%30d", &penalty) != 1 || penalty < 0) {
8988 penalty = 0;
8989 }
8990
8991 if (ast_strlen_zero(paused_s)) {
8992 paused = 0;
8993 } else {
8994 paused = abs(ast_true(paused_s));
8995 }
8996
8997 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
8998 case RES_OKAY:
8999 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
9000 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
9001 } else {
9002 ast_queue_log(queuename, "MANAGER", membername, "ADDMEMBER", "%s", paused ? "PAUSED" : "");
9003 }
9004 astman_send_ack(s, m, "Added interface to queue");
9005 break;
9006 case RES_EXISTS:
9007 astman_send_error(s, m, "Unable to add interface: Already there");
9008 break;
9009 case RES_NOSUCHQUEUE:
9010 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
9011 break;
9012 case RES_OUTOFMEMORY:
9013 astman_send_error(s, m, "Out of memory");
9014 break;
9015 }
9016
9017 return 0;
9018}
9019
9020static int manager_remove_queue_member(struct mansession *s, const struct message *m)
9021{
9022 const char *queuename, *interface;
9023 struct member *mem = NULL;
9024
9025 queuename = astman_get_header(m, "Queue");
9026 interface = astman_get_header(m, "Interface");
9027
9028 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
9029 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
9030 return 0;
9031 }
9032
9033 if (log_membername_as_agent) {
9034 mem = find_member_by_queuename_and_interface(queuename, interface);
9035 }
9036
9037 switch (remove_from_queue(queuename, interface)) {
9038 case RES_OKAY:
9039 if (!mem || ast_strlen_zero(mem->membername)) {
9040 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
9041 } else {
9042 ast_queue_log(queuename, "MANAGER", mem->membername, "REMOVEMEMBER", "%s", "");
9043 }
9044 astman_send_ack(s, m, "Removed interface from queue");
9045 break;
9046 case RES_EXISTS:
9047 astman_send_error(s, m, "Unable to remove interface: Not there");
9048 break;
9049 case RES_NOSUCHQUEUE:
9050 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
9051 break;
9052 case RES_OUTOFMEMORY:
9053 astman_send_error(s, m, "Out of memory");
9054 break;
9055 case RES_NOT_DYNAMIC:
9056 astman_send_error(s, m, "Member not dynamic");
9057 break;
9058 }
9059
9060 if (mem) {
9061 ao2_ref(mem, -1);
9062 }
9063
9064 return 0;
9065}
9066
9067static int manager_pause_queue_member(struct mansession *s, const struct message *m)
9068{
9069 const char *queuename, *interface, *paused_s, *reason;
9070 int paused;
9071
9072 interface = astman_get_header(m, "Interface");
9073 paused_s = astman_get_header(m, "Paused");
9074 queuename = astman_get_header(m, "Queue"); /* Optional - if not supplied, pause the given Interface in all queues */
9075 reason = astman_get_header(m, "Reason"); /* Optional - Only used for logging purposes */
9076
9077 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
9078 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
9079 return 0;
9080 }
9081
9082 paused = abs(ast_true(paused_s));
9083
9084 if (set_member_paused(queuename, interface, reason, paused)) {
9085 astman_send_error(s, m, "Interface not found");
9086 } else {
9087 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
9088 }
9089 return 0;
9090}
9091
9092static int manager_queue_log_custom(struct mansession *s, const struct message *m)
9093{
9094 const char *queuename, *event, *message, *interface, *uniqueid;
9095
9096 queuename = astman_get_header(m, "Queue");
9097 uniqueid = astman_get_header(m, "UniqueId");
9098 interface = astman_get_header(m, "Interface");
9099 event = astman_get_header(m, "Event");
9100 message = astman_get_header(m, "Message");
9101
9102 if (ast_strlen_zero(queuename) || ast_strlen_zero(event)) {
9103 astman_send_error(s, m, "Need 'Queue' and 'Event' parameters.");
9104 return 0;
9105 }
9106
9107 ast_queue_log(queuename, S_OR(uniqueid, "NONE"), interface, event, "%s", message);
9108 astman_send_ack(s, m, "Event added successfully");
9109
9110 return 0;
9111}
9112
9113static int manager_queue_reload(struct mansession *s, const struct message *m)
9114{
9115 struct ast_flags mask = {0,};
9116 const char *queuename = NULL;
9117 int header_found = 0;
9118
9119 queuename = astman_get_header(m, "Queue");
9120 if (!strcasecmp(S_OR(astman_get_header(m, "Members"), ""), "yes")) {
9121 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
9122 header_found = 1;
9123 }
9124 if (!strcasecmp(S_OR(astman_get_header(m, "Rules"), ""), "yes")) {
9125 ast_set_flag(&mask, QUEUE_RELOAD_RULES);
9126 header_found = 1;
9127 }
9128 if (!strcasecmp(S_OR(astman_get_header(m, "Parameters"), ""), "yes")) {
9129 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
9130 header_found = 1;
9131 }
9132
9133 if (!header_found) {
9134 ast_set_flag(&mask, AST_FLAGS_ALL);
9135 }
9136
9137 if (!reload_handler(1, &mask, queuename)) {
9138 astman_send_ack(s, m, "Queue reloaded successfully");
9139 } else {
9140 astman_send_error(s, m, "Error encountered while reloading queue");
9141 }
9142 return 0;
9143}
9144
9145static int manager_queue_reset(struct mansession *s, const struct message *m)
9146{
9147 const char *queuename = NULL;
9148 struct ast_flags mask = {QUEUE_RESET_STATS,};
9149
9150 queuename = astman_get_header(m, "Queue");
9151
9152 if (!reload_handler(1, &mask, queuename)) {
9153 astman_send_ack(s, m, "Queue stats reset successfully");
9154 } else {
9155 astman_send_error(s, m, "Error encountered while resetting queue stats");
9156 }
9157 return 0;
9158}
9159
9160static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
9161{
9162 /* 0 - queue; 1 - add; 2 - member; 3 - <interface>; 4 - to; 5 - <queue>; 6 - penalty; 7 - <penalty>; 8 - as; 9 - <membername> */
9163 switch (pos) {
9164 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
9165 return NULL;
9166 case 4: /* only one possible match, "to" */
9167 return state == 0 ? ast_strdup("to") : NULL;
9168 case 5: /* <queue> */
9169 return complete_queue(line, word, pos, state, 0);
9170 case 6: /* only one possible match, "penalty" */
9171 return state == 0 ? ast_strdup("penalty") : NULL;
9172 case 7:
9173 if (state < 100) { /* 0-99 */
9174 char *num;
9175 if ((num = ast_malloc(3))) {
9176 sprintf(num, "%d", state);
9177 }
9178 return num;
9179 } else {
9180 return NULL;
9181 }
9182 case 8: /* only one possible match, "as" */
9183 return state == 0 ? ast_strdup("as") : NULL;
9184 case 9: /* Don't attempt to complete name of member (infinite possibilities) */
9185 return NULL;
9186 default:
9187 return NULL;
9188 }
9189}
9190
9191static int manager_queue_member_ringinuse(struct mansession *s, const struct message *m)
9192{
9193 const char *queuename, *interface, *ringinuse_s;
9194 int ringinuse;
9195
9196 interface = astman_get_header(m, "Interface");
9197 ringinuse_s = astman_get_header(m, "RingInUse");
9198
9199 /* Optional - if not supplied, set the ringinuse value for the given Interface in all queues */
9200 queuename = astman_get_header(m, "Queue");
9201
9202 if (ast_strlen_zero(interface) || ast_strlen_zero(ringinuse_s)) {
9203 astman_send_error(s, m, "Need 'Interface' and 'RingInUse' parameters.");
9204 return 0;
9205 }
9206
9207 if (ast_true(ringinuse_s)) {
9208 ringinuse = 1;
9209 } else if (ast_false(ringinuse_s)) {
9210 ringinuse = 0;
9211 } else {
9212 astman_send_error(s, m, "'RingInUse' parameter must be a truth value (yes/no, on/off, 0/1, etc)");
9213 return 0;
9214 }
9215
9216 if (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
9217 astman_send_error(s, m, "Invalid interface, queuename, or ringinuse value\n");
9218 } else {
9219 astman_send_ack(s, m, "Interface ringinuse set successfully");
9220 }
9221
9222 return 0;
9223}
9224
9225static int manager_queue_member_penalty(struct mansession *s, const struct message *m)
9226{
9227 const char *queuename, *interface, *penalty_s;
9228 int penalty;
9229
9230 interface = astman_get_header(m, "Interface");
9231 penalty_s = astman_get_header(m, "Penalty");
9232 /* Optional - if not supplied, set the penalty value for the given Interface in all queues */
9233 queuename = astman_get_header(m, "Queue");
9234
9235 if (ast_strlen_zero(interface) || ast_strlen_zero(penalty_s)) {
9236 astman_send_error(s, m, "Need 'Interface' and 'Penalty' parameters.");
9237 return 0;
9238 }
9239
9240 penalty = atoi(penalty_s);
9241
9242 if (set_member_value((char *)queuename, (char *)interface, MEMBER_PENALTY, penalty)) {
9243 astman_send_error(s, m, "Invalid interface, queuename or penalty");
9244 } else {
9245 astman_send_ack(s, m, "Interface penalty set successfully");
9246 }
9247
9248 return 0;
9249}
9250
9251static char *handle_queue_add_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9252{
9253 const char *queuename, *interface, *membername = NULL, *state_interface = NULL;
9254 int penalty;
9255
9256 switch ( cmd ) {
9257 case CLI_INIT:
9258 e->command = "queue add member";
9259 e->usage =
9260 "Usage: queue add member <dial string> to <queue> [[[penalty <penalty>] as <membername>] state_interface <interface>]\n"
9261 " 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";
9262 return NULL;
9263 case CLI_GENERATE:
9264 return complete_queue_add_member(a->line, a->word, a->pos, a->n);
9265 }
9266
9267 if ((a->argc != 6) && (a->argc != 8) && (a->argc != 10) && (a->argc != 12)) {
9268 return CLI_SHOWUSAGE;
9269 } else if (strcmp(a->argv[4], "to")) {
9270 return CLI_SHOWUSAGE;
9271 } else if ((a->argc >= 8) && strcmp(a->argv[6], "penalty")) {
9272 return CLI_SHOWUSAGE;
9273 } else if ((a->argc >= 10) && strcmp(a->argv[8], "as")) {
9274 return CLI_SHOWUSAGE;
9275 } else if ((a->argc == 12) && strcmp(a->argv[10], "state_interface")) {
9276 return CLI_SHOWUSAGE;
9277 }
9278
9279 queuename = a->argv[5];
9280 interface = a->argv[3];
9281 if (a->argc >= 8) {
9282 if (sscanf(a->argv[7], "%30d", &penalty) == 1) {
9283 if (penalty < 0) {
9284 ast_cli(a->fd, "Penalty must be >= 0\n");
9285 penalty = 0;
9286 }
9287 } else {
9288 ast_cli(a->fd, "Penalty must be an integer >= 0\n");
9289 penalty = 0;
9290 }
9291 } else {
9292 penalty = 0;
9293 }
9294
9295 if (a->argc >= 10) {
9296 membername = a->argv[9];
9297 }
9298
9299 if (a->argc >= 12) {
9300 state_interface = a->argv[11];
9301 }
9302
9303 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
9304 case RES_OKAY:
9305 if (ast_strlen_zero(membername) || !log_membername_as_agent) {
9306 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
9307 } else {
9308 ast_queue_log(queuename, "CLI", membername, "ADDMEMBER", "%s", "");
9309 }
9310 ast_cli(a->fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
9311 return CLI_SUCCESS;
9312 case RES_EXISTS:
9313 ast_cli(a->fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
9314 return CLI_FAILURE;
9315 case RES_NOSUCHQUEUE:
9316 ast_cli(a->fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
9317 return CLI_FAILURE;
9318 case RES_OUTOFMEMORY:
9319 ast_cli(a->fd, "Out of memory\n");
9320 return CLI_FAILURE;
9321 case RES_NOT_DYNAMIC:
9322 ast_cli(a->fd, "Member not dynamic\n");
9323 return CLI_FAILURE;
9324 default:
9325 return CLI_FAILURE;
9326 }
9327}
9328
9329static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
9330{
9331 int which = 0;
9332 struct call_queue *q;
9333 struct member *m;
9334 struct ao2_iterator queue_iter;
9335 struct ao2_iterator mem_iter;
9336 int wordlen = strlen(word);
9337
9338 /* 0 - queue; 1 - remove; 2 - member; 3 - <member>; 4 - from; 5 - <queue> */
9339 if (pos > 5 || pos < 3) {
9340 return NULL;
9341 }
9342 if (pos == 4) { /* only one possible match, 'from' */
9343 return (state == 0 ? ast_strdup("from") : NULL);
9344 }
9345
9346 if (pos == 5) { /* No need to duplicate code */
9347 return complete_queue(line, word, pos, state, 0);
9348 }
9349
9350 /* here is the case for 3, <member> */
9351 queue_iter = ao2_iterator_init(queues, 0);
9352 while ((q = ao2_t_iterator_next(&queue_iter, "Iterate through queues"))) {
9353 ao2_lock(q);
9354 mem_iter = ao2_iterator_init(q->members, 0);
9355 while ((m = ao2_iterator_next(&mem_iter))) {
9356 if (!strncasecmp(word, m->membername, wordlen) && ++which > state) {
9357 char *tmp;
9358 tmp = ast_strdup(m->interface);
9359 ao2_ref(m, -1);
9360 ao2_iterator_destroy(&mem_iter);
9361 ao2_unlock(q);
9362 queue_t_unref(q, "Done with iterator, returning interface name");
9363 ao2_iterator_destroy(&queue_iter);
9364 return tmp;
9365 }
9366 ao2_ref(m, -1);
9367 }
9368 ao2_iterator_destroy(&mem_iter);
9369 ao2_unlock(q);
9370 queue_t_unref(q, "Done with iterator");
9371 }
9372 ao2_iterator_destroy(&queue_iter);
9373
9374 return NULL;
9375}
9376
9377static char *handle_queue_remove_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9378{
9379 const char *queuename, *interface;
9380 struct member *mem = NULL;
9381 char *res = CLI_FAILURE;
9382
9383 switch (cmd) {
9384 case CLI_INIT:
9385 e->command = "queue remove member";
9386 e->usage =
9387 "Usage: queue remove member <channel> from <queue>\n"
9388 " Remove a specific channel from a queue.\n";
9389 return NULL;
9390 case CLI_GENERATE:
9391 return complete_queue_remove_member(a->line, a->word, a->pos, a->n);
9392 }
9393
9394 if (a->argc != 6) {
9395 return CLI_SHOWUSAGE;
9396 } else if (strcmp(a->argv[4], "from")) {
9397 return CLI_SHOWUSAGE;
9398 }
9399
9400 queuename = a->argv[5];
9401 interface = a->argv[3];
9402
9403 if (log_membername_as_agent) {
9404 mem = find_member_by_queuename_and_interface(queuename, interface);
9405 }
9406
9407 switch (remove_from_queue(queuename, interface)) {
9408 case RES_OKAY:
9409 if (!mem || ast_strlen_zero(mem->membername)) {
9410 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
9411 } else {
9412 ast_queue_log(queuename, "CLI", mem->membername, "REMOVEMEMBER", "%s", "");
9413 }
9414 ast_cli(a->fd, "Removed interface %s from queue '%s'\n", interface, queuename);
9415 res = CLI_SUCCESS;
9416 break;
9417 case RES_EXISTS:
9418 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
9419 break;
9420 case RES_NOSUCHQUEUE:
9421 ast_cli(a->fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
9422 break;
9423 case RES_OUTOFMEMORY:
9424 ast_cli(a->fd, "Out of memory\n");
9425 break;
9426 case RES_NOT_DYNAMIC:
9427 ast_cli(a->fd, "Unable to remove interface '%s' from queue '%s': Member is not dynamic\n", interface, queuename);
9428 break;
9429 }
9430
9431 if (mem) {
9432 ao2_ref(mem, -1);
9433 }
9434
9435 return res;
9436}
9437
9438static char *complete_queue_pause_member(const char *line, const char *word, int pos, int state)
9439{
9440 /* 0 - queue; 1 - pause; 2 - member; 3 - <interface>; 4 - queue; 5 - <queue>; 6 - reason; 7 - <reason> */
9441 switch (pos) {
9442 case 3: /* Don't attempt to complete name of interface (infinite possibilities) */
9443 return NULL;
9444 case 4: /* only one possible match, "queue" */
9445 return state == 0 ? ast_strdup("queue") : NULL;
9446 case 5: /* <queue> */
9447 return complete_queue(line, word, pos, state, 0);
9448 case 6: /* "reason" */
9449 return state == 0 ? ast_strdup("reason") : NULL;
9450 case 7: /* Can't autocomplete a reason, since it's 100% customizeable */
9451 return NULL;
9452 default:
9453 return NULL;
9454 }
9455}
9456
9457static char *handle_queue_pause_member(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9458{
9459 const char *queuename, *interface, *reason;
9460 int paused;
9461
9462 switch (cmd) {
9463 case CLI_INIT:
9464 e->command = "queue {pause|unpause} member";
9465 e->usage =
9466 "Usage: queue {pause|unpause} member <member> [queue <queue> [reason <reason>]]\n"
9467 " Pause or unpause a queue member. Not specifying a particular queue\n"
9468 " will pause or unpause a member across all queues to which the member\n"
9469 " belongs.\n";
9470 return NULL;
9471 case CLI_GENERATE:
9472 return complete_queue_pause_member(a->line, a-> word, a->pos, a->n);
9473 }
9474
9475 if (a->argc < 4 || a->argc == 5 || a->argc == 7 || a->argc > 8) {
9476 return CLI_SHOWUSAGE;
9477 } else if (a->argc >= 5 && strcmp(a->argv[4], "queue")) {
9478 return CLI_SHOWUSAGE;
9479 } else if (a->argc == 8 && strcmp(a->argv[6], "reason")) {
9480 return CLI_SHOWUSAGE;
9481 }
9482
9483
9484 interface = a->argv[3];
9485 queuename = a->argc >= 6 ? a->argv[5] : NULL;
9486 reason = a->argc == 8 ? a->argv[7] : NULL;
9487 paused = !strcasecmp(a->argv[1], "pause");
9488
9489 if (set_member_paused(queuename, interface, reason, paused) == RESULT_SUCCESS) {
9490 ast_cli(a->fd, "%spaused interface '%s'", paused ? "" : "un", interface);
9491 if (!ast_strlen_zero(queuename)) {
9492 ast_cli(a->fd, " in queue '%s'", queuename);
9493 }
9494 if (!ast_strlen_zero(reason)) {
9495 ast_cli(a->fd, " for reason '%s'", reason);
9496 }
9497 ast_cli(a->fd, "\n");
9498 return CLI_SUCCESS;
9499 } else {
9500 ast_cli(a->fd, "Unable to %spause interface '%s'", paused ? "" : "un", interface);
9501 if (!ast_strlen_zero(queuename)) {
9502 ast_cli(a->fd, " in queue '%s'", queuename);
9503 }
9504 if (!ast_strlen_zero(reason)) {
9505 ast_cli(a->fd, " for reason '%s'", reason);
9506 }
9507 ast_cli(a->fd, "\n");
9508 return CLI_FAILURE;
9509 }
9510}
9511
9512static char *complete_queue_set_member_value(const char *line, const char *word, int pos, int state)
9513{
9514 /* 0 - queue; 1 - set; 2 - penalty/ringinuse; 3 - <value>; 4 - on; 5 - <member>; 6 - in; 7 - <queue>;*/
9515 switch (pos) {
9516 case 4:
9517 if (state == 0) {
9518 return ast_strdup("on");
9519 } else {
9520 return NULL;
9521 }
9522 case 6:
9523 if (state == 0) {
9524 return ast_strdup("in");
9525 } else {
9526 return NULL;
9527 }
9528 case 7:
9529 return complete_queue(line, word, pos, state, 0);
9530 default:
9531 return NULL;
9532 }
9533}
9534
9535static char *handle_queue_set_member_ringinuse(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9536{
9537 const char *queuename = NULL, *interface;
9538 int ringinuse;
9539
9540 switch (cmd) {
9541 case CLI_INIT:
9542 e->command = "queue set ringinuse";
9543 e->usage =
9544 "Usage: queue set ringinuse <yes/no> on <interface> [in <queue>]\n"
9545 " Set a member's ringinuse in the queue specified. If no queue is specified\n"
9546 " then that interface's penalty is set in all queues to which that interface is a member.\n";
9547 break;
9548 return NULL;
9549 case CLI_GENERATE:
9550 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
9551 }
9552
9553 /* Sensible argument counts */
9554 if (a->argc != 6 && a->argc != 8) {
9555 return CLI_SHOWUSAGE;
9556 }
9557
9558 /* Uses proper indicational words */
9559 if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
9560 return CLI_SHOWUSAGE;
9561 }
9562
9563 /* Set the queue name if applicale */
9564 if (a->argc == 8) {
9565 queuename = a->argv[7];
9566 }
9567
9568 /* Interface being set */
9569 interface = a->argv[5];
9570
9571 /* Check and set the ringinuse value */
9572 if (ast_true(a->argv[3])) {
9573 ringinuse = 1;
9574 } else if (ast_false(a->argv[3])) {
9575 ringinuse = 0;
9576 } else {
9577 return CLI_SHOWUSAGE;
9578 }
9579
9580 switch (set_member_value(queuename, interface, MEMBER_RINGINUSE, ringinuse)) {
9581 case RESULT_SUCCESS:
9582 ast_cli(a->fd, "Set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
9583 return CLI_SUCCESS;
9584 case RESULT_FAILURE:
9585 ast_cli(a->fd, "Failed to set ringinuse on interface '%s' from queue '%s'\n", interface, queuename);
9586 return CLI_FAILURE;
9587 default:
9588 return CLI_FAILURE;
9589 }
9590}
9591
9592static char *handle_queue_set_member_penalty(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9593{
9594 const char *queuename = NULL, *interface;
9595 int penalty = 0;
9596
9597 switch (cmd) {
9598 case CLI_INIT:
9599 e->command = "queue set penalty";
9600 e->usage =
9601 "Usage: queue set penalty <penalty> on <interface> [in <queue>]\n"
9602 " Set a member's penalty in the queue specified. If no queue is specified\n"
9603 " then that interface's penalty is set in all queues to which that interface is a member\n";
9604 return NULL;
9605 case CLI_GENERATE:
9606 return complete_queue_set_member_value(a->line, a->word, a->pos, a->n);
9607 }
9608
9609 if (a->argc != 6 && a->argc != 8) {
9610 return CLI_SHOWUSAGE;
9611 } else if (strcmp(a->argv[4], "on") || (a->argc > 6 && strcmp(a->argv[6], "in"))) {
9612 return CLI_SHOWUSAGE;
9613 }
9614
9615 if (a->argc == 8) {
9616 queuename = a->argv[7];
9617 }
9618 interface = a->argv[5];
9619 penalty = atoi(a->argv[3]);
9620
9621 switch (set_member_value(queuename, interface, MEMBER_PENALTY, penalty)) {
9622 case RESULT_SUCCESS:
9623 ast_cli(a->fd, "Set penalty on interface '%s' from queue '%s'\n", interface, queuename);
9624 return CLI_SUCCESS;
9625 case RESULT_FAILURE:
9626 ast_cli(a->fd, "Failed to set penalty on interface '%s' from queue '%s'\n", interface, queuename);
9627 return CLI_FAILURE;
9628 default:
9629 return CLI_FAILURE;
9630 }
9631}
9632
9633static char *complete_queue_rule_show(const char *line, const char *word, int pos, int state)
9634{
9635 int which = 0;
9636 struct rule_list *rl_iter;
9637 int wordlen = strlen(word);
9638 char *ret = NULL;
9639 if (pos != 3) /* Wha? */ {
9640 return NULL;
9641 }
9642
9643 AST_LIST_LOCK(&rule_lists);
9644 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
9645 if (!strncasecmp(word, rl_iter->name, wordlen) && ++which > state) {
9646 ret = ast_strdup(rl_iter->name);
9647 break;
9648 }
9649 }
9650 AST_LIST_UNLOCK(&rule_lists);
9651
9652 return ret;
9653}
9654
9655static char *handle_queue_rule_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9656{
9657 const char *rule;
9658 struct rule_list *rl_iter;
9659 struct penalty_rule *pr_iter;
9660 switch (cmd) {
9661 case CLI_INIT:
9662 e->command = "queue show rules";
9663 e->usage =
9664 "Usage: queue show rules [rulename]\n"
9665 " Show the list of rules associated with rulename. If no\n"
9666 " rulename is specified, list all rules defined in queuerules.conf\n";
9667 return NULL;
9668 case CLI_GENERATE:
9669 return complete_queue_rule_show(a->line, a->word, a->pos, a->n);
9670 }
9671
9672 if (a->argc != 3 && a->argc != 4) {
9673 return CLI_SHOWUSAGE;
9674 }
9675
9676 rule = a->argc == 4 ? a->argv[3] : "";
9677 AST_LIST_LOCK(&rule_lists);
9678 AST_LIST_TRAVERSE(&rule_lists, rl_iter, list) {
9679 if (ast_strlen_zero(rule) || !strcasecmp(rl_iter->name, rule)) {
9680 ast_cli(a->fd, "Rule: %s\n", rl_iter->name);
9681 AST_LIST_TRAVERSE(&rl_iter->rules, pr_iter, list) {
9682 ast_cli(a->fd, "\tAfter %d seconds, adjust QUEUE_MAX_PENALTY %s %d and adjust QUEUE_MIN_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);
9683 }
9684 }
9685 }
9686 AST_LIST_UNLOCK(&rule_lists);
9687 return CLI_SUCCESS;
9688}
9689
9690static char *handle_queue_reset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9691{
9692 struct ast_flags mask = {QUEUE_RESET_STATS,};
9693 int i;
9694
9695 switch (cmd) {
9696 case CLI_INIT:
9697 e->command = "queue reset stats";
9698 e->usage =
9699 "Usage: queue reset stats [<queuenames>]\n"
9700 "\n"
9701 "Issuing this command will reset statistics for\n"
9702 "<queuenames>, or for all queues if no queue is\n"
9703 "specified.\n";
9704 return NULL;
9705 case CLI_GENERATE:
9706 if (a->pos >= 3) {
9707 return complete_queue(a->line, a->word, a->pos, a->n, 17);
9708 } else {
9709 return NULL;
9710 }
9711 }
9712
9713 if (a->argc < 3) {
9714 return CLI_SHOWUSAGE;
9715 }
9716
9717 if (a->argc == 3) {
9718 reload_handler(1, &mask, NULL);
9719 return CLI_SUCCESS;
9720 }
9721
9722 for (i = 3; i < a->argc; ++i) {
9723 reload_handler(1, &mask, a->argv[i]);
9724 }
9725
9726 return CLI_SUCCESS;
9727}
9728
9729static char *handle_queue_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
9730{
9731 struct ast_flags mask = {0,};
9732 int i;
9733
9734 switch (cmd) {
9735 case CLI_INIT:
9736 e->command = "queue reload {parameters|members|rules|all}";
9737 e->usage =
9738 "Usage: queue reload {parameters|members|rules|all} [<queuenames>]\n"
9739 "Reload queues. If <queuenames> are specified, only reload information pertaining\n"
9740 "to <queuenames>. One of 'parameters,' 'members,' 'rules,' or 'all' must be\n"
9741 "specified in order to know what information to reload. Below is an explanation\n"
9742 "of each of these qualifiers.\n"
9743 "\n"
9744 "\t'members' - reload queue members from queues.conf\n"
9745 "\t'parameters' - reload all queue options except for queue members\n"
9746 "\t'rules' - reload the queuerules.conf file\n"
9747 "\t'all' - reload queue rules, parameters, and members\n"
9748 "\n"
9749 "Note: the 'rules' qualifier here cannot actually be applied to a specific queue.\n"
9750 "Use of the 'rules' qualifier causes queuerules.conf to be reloaded. Even if only\n"
9751 "one queue is specified when using this command, reloading queue rules may cause\n"
9752 "other queues to be affected\n";
9753 return NULL;
9754 case CLI_GENERATE:
9755 if (a->pos >= 3) {
9756 /* find the point at which the list of queue names starts */
9757 const char *command_end = a->line + strlen("queue reload ");
9758 command_end = strchr(command_end, ' ');
9759 if (!command_end) {
9760 command_end = a->line + strlen(a->line);
9761 }
9762 return complete_queue(a->line, a->word, a->pos, a->n, command_end - a->line);
9763 } else {
9764 return NULL;
9765 }
9766 }
9767
9768 if (a->argc < 3)
9769 return CLI_SHOWUSAGE;
9770
9771 if (!strcasecmp(a->argv[2], "rules")) {
9772 ast_set_flag(&mask, QUEUE_RELOAD_RULES);
9773 } else if (!strcasecmp(a->argv[2], "members")) {
9774 ast_set_flag(&mask, QUEUE_RELOAD_MEMBER);
9775 } else if (!strcasecmp(a->argv[2], "parameters")) {
9776 ast_set_flag(&mask, QUEUE_RELOAD_PARAMETERS);
9777 } else if (!strcasecmp(a->argv[2], "all")) {
9778 ast_set_flag(&mask, AST_FLAGS_ALL);
9779 }
9780
9781 if (a->argc == 3) {
9782 reload_handler(1, &mask, NULL);
9783 return CLI_SUCCESS;
9784 }
9785
9786 for (i = 3; i < a->argc; ++i) {
9787 reload_handler(1, &mask, a->argv[i]);
9788 }
9789
9790 return CLI_SUCCESS;
9791}
9792
9793static struct ast_cli_entry cli_queue[] = {
9794 AST_CLI_DEFINE(queue_show, "Show status of a specified queue"),
9795 AST_CLI_DEFINE(handle_queue_rule_show, "Show the rules defined in queuerules.conf"),
9796 AST_CLI_DEFINE(handle_queue_add_member, "Add a channel to a specified queue"),
9797 AST_CLI_DEFINE(handle_queue_remove_member, "Removes a channel from a specified queue"),
9798 AST_CLI_DEFINE(handle_queue_pause_member, "Pause or unpause a queue member"),
9799 AST_CLI_DEFINE(handle_queue_set_member_penalty, "Set penalty for a channel of a specified queue"),
9800 AST_CLI_DEFINE(handle_queue_set_member_ringinuse, "Set ringinuse for a channel of a specified queue"),
9801 AST_CLI_DEFINE(handle_queue_reload, "Reload queues, members, queue rules, or parameters"),
9802 AST_CLI_DEFINE(handle_queue_reset, "Reset statistics for a queue"),
9803};
9804
9805/* struct call_queue astdata mapping. */
9806#define DATA_EXPORT_CALL_QUEUE(MEMBER) \
9807 MEMBER(call_queue, name, AST_DATA_STRING) \
9808 MEMBER(call_queue, moh, AST_DATA_STRING) \
9809 MEMBER(call_queue, announce, AST_DATA_STRING) \
9810 MEMBER(call_queue, context, AST_DATA_STRING) \
9811 MEMBER(call_queue, membermacro, AST_DATA_STRING) \
9812 MEMBER(call_queue, membergosub, AST_DATA_STRING) \
9813 MEMBER(call_queue, defaultrule, AST_DATA_STRING) \
9814 MEMBER(call_queue, sound_next, AST_DATA_STRING) \
9815 MEMBER(call_queue, sound_thereare, AST_DATA_STRING) \
9816 MEMBER(call_queue, sound_calls, AST_DATA_STRING) \
9817 MEMBER(call_queue, queue_quantity1, AST_DATA_STRING) \
9818 MEMBER(call_queue, queue_quantity2, AST_DATA_STRING) \
9819 MEMBER(call_queue, sound_holdtime, AST_DATA_STRING) \
9820 MEMBER(call_queue, sound_minutes, AST_DATA_STRING) \
9821 MEMBER(call_queue, sound_minute, AST_DATA_STRING) \
9822 MEMBER(call_queue, sound_seconds, AST_DATA_STRING) \
9823 MEMBER(call_queue, sound_thanks, AST_DATA_STRING) \
9824 MEMBER(call_queue, sound_callerannounce, AST_DATA_STRING) \
9825 MEMBER(call_queue, sound_reporthold, AST_DATA_STRING) \
9826 MEMBER(call_queue, dead, AST_DATA_BOOLEAN) \
9827 MEMBER(call_queue, eventwhencalled, AST_DATA_BOOLEAN) \
9828 MEMBER(call_queue, ringinuse, AST_DATA_BOOLEAN) \
9829 MEMBER(call_queue, announce_to_first_user, AST_DATA_BOOLEAN) \
9830 MEMBER(call_queue, setinterfacevar, AST_DATA_BOOLEAN) \
9831 MEMBER(call_queue, setqueuevar, AST_DATA_BOOLEAN) \
9832 MEMBER(call_queue, setqueueentryvar, AST_DATA_BOOLEAN) \
9833 MEMBER(call_queue, reportholdtime, AST_DATA_BOOLEAN) \
9834 MEMBER(call_queue, wrapped, AST_DATA_BOOLEAN) \
9835 MEMBER(call_queue, timeoutrestart, AST_DATA_BOOLEAN) \
9836 MEMBER(call_queue, announceholdtime, AST_DATA_INTEGER) \
9837 MEMBER(call_queue, maskmemberstatus, AST_DATA_BOOLEAN) \
9838 MEMBER(call_queue, realtime, AST_DATA_BOOLEAN) \
9839 MEMBER(call_queue, found, AST_DATA_BOOLEAN) \
9840 MEMBER(call_queue, announcepositionlimit, AST_DATA_INTEGER) \
9841 MEMBER(call_queue, announcefrequency, AST_DATA_SECONDS) \
9842 MEMBER(call_queue, minannouncefrequency, AST_DATA_SECONDS) \
9843 MEMBER(call_queue, periodicannouncefrequency, AST_DATA_SECONDS) \
9844 MEMBER(call_queue, numperiodicannounce, AST_DATA_INTEGER) \
9845 MEMBER(call_queue, randomperiodicannounce, AST_DATA_INTEGER) \
9846 MEMBER(call_queue, roundingseconds, AST_DATA_SECONDS) \
9847 MEMBER(call_queue, holdtime, AST_DATA_SECONDS) \
9848 MEMBER(call_queue, talktime, AST_DATA_SECONDS) \
9849 MEMBER(call_queue, callscompleted, AST_DATA_INTEGER) \
9850 MEMBER(call_queue, callsabandoned, AST_DATA_INTEGER) \
9851 MEMBER(call_queue, servicelevel, AST_DATA_INTEGER) \
9852 MEMBER(call_queue, callscompletedinsl, AST_DATA_INTEGER) \
9853 MEMBER(call_queue, monfmt, AST_DATA_STRING) \
9854 MEMBER(call_queue, montype, AST_DATA_INTEGER) \
9855 MEMBER(call_queue, count, AST_DATA_INTEGER) \
9856 MEMBER(call_queue, maxlen, AST_DATA_INTEGER) \
9857 MEMBER(call_queue, wrapuptime, AST_DATA_SECONDS) \
9858 MEMBER(call_queue, retry, AST_DATA_SECONDS) \
9859 MEMBER(call_queue, timeout, AST_DATA_SECONDS) \
9860 MEMBER(call_queue, weight, AST_DATA_INTEGER) \
9861 MEMBER(call_queue, autopause, AST_DATA_INTEGER) \
9862 MEMBER(call_queue, timeoutpriority, AST_DATA_INTEGER) \
9863 MEMBER(call_queue, rrpos, AST_DATA_INTEGER) \
9864 MEMBER(call_queue, memberdelay, AST_DATA_INTEGER) \
9865 MEMBER(call_queue, autofill, AST_DATA_INTEGER) \
9866 MEMBER(call_queue, members, AST_DATA_CONTAINER)
9867
9868AST_DATA_STRUCTURE(call_queue, DATA_EXPORT_CALL_QUEUE);
9869
9870/* struct member astdata mapping. */
9871#define DATA_EXPORT_MEMBER(MEMBER) \
9872 MEMBER(member, interface, AST_DATA_STRING) \
9873 MEMBER(member, state_interface, AST_DATA_STRING) \
9874 MEMBER(member, membername, AST_DATA_STRING) \
9875 MEMBER(member, penalty, AST_DATA_INTEGER) \
9876 MEMBER(member, calls, AST_DATA_INTEGER) \
9877 MEMBER(member, dynamic, AST_DATA_INTEGER) \
9878 MEMBER(member, realtime, AST_DATA_INTEGER) \
9879 MEMBER(member, status, AST_DATA_INTEGER) \
9880 MEMBER(member, paused, AST_DATA_BOOLEAN) \
9881 MEMBER(member, rt_uniqueid, AST_DATA_STRING)
9882
9883AST_DATA_STRUCTURE(member, DATA_EXPORT_MEMBER);
9884
9885#define DATA_EXPORT_QUEUE_ENT(MEMBER) \
9886 MEMBER(queue_ent, moh, AST_DATA_STRING) \
9887 MEMBER(queue_ent, announce, AST_DATA_STRING) \
9888 MEMBER(queue_ent, context, AST_DATA_STRING) \
9889 MEMBER(queue_ent, digits, AST_DATA_STRING) \
9890 MEMBER(queue_ent, valid_digits, AST_DATA_INTEGER) \
9891 MEMBER(queue_ent, pos, AST_DATA_INTEGER) \
9892 MEMBER(queue_ent, prio, AST_DATA_INTEGER) \
9893 MEMBER(queue_ent, last_pos_said, AST_DATA_INTEGER) \
9894 MEMBER(queue_ent, last_periodic_announce_time, AST_DATA_INTEGER) \
9895 MEMBER(queue_ent, last_periodic_announce_sound, AST_DATA_INTEGER) \
9896 MEMBER(queue_ent, last_pos, AST_DATA_INTEGER) \
9897 MEMBER(queue_ent, opos, AST_DATA_INTEGER) \
9898 MEMBER(queue_ent, handled, AST_DATA_INTEGER) \
9899 MEMBER(queue_ent, pending, AST_DATA_INTEGER) \
9900 MEMBER(queue_ent, max_penalty, AST_DATA_INTEGER) \
9901 MEMBER(queue_ent, min_penalty, AST_DATA_INTEGER) \
9902 MEMBER(queue_ent, linpos, AST_DATA_INTEGER) \
9903 MEMBER(queue_ent, linwrapped, AST_DATA_INTEGER) \
9904 MEMBER(queue_ent, start, AST_DATA_INTEGER) \
9905 MEMBER(queue_ent, expire, AST_DATA_INTEGER) \
9906 MEMBER(queue_ent, cancel_answered_elsewhere, AST_DATA_INTEGER)
9907
9908AST_DATA_STRUCTURE(queue_ent, DATA_EXPORT_QUEUE_ENT);
9909
9910/*!
9911 * \internal
9912 * \brief Add a queue to the data_root node.
9913 * \param[in] search The search tree.
9914 * \param[in] data_root The main result node.
9915 * \param[in] queue The queue to add.
9916 */
9917static void queues_data_provider_get_helper(const struct ast_data_search *search,
9918 struct ast_data *data_root, struct call_queue *queue)
9919{
9920 struct ao2_iterator im;
9921 struct member *member;
9922 struct queue_ent *qe;
9923 struct ast_data *data_queue, *data_members = NULL, *enum_node;
9924 struct ast_data *data_member, *data_callers = NULL, *data_caller, *data_caller_channel;
9925
9926 data_queue = ast_data_add_node(data_root, "queue");
9927 if (!data_queue) {
9928 return;
9929 }
9930
9931 ast_data_add_structure(call_queue, data_queue, queue);
9932
9933 ast_data_add_str(data_queue, "strategy", int2strat(queue->strategy));
9934 ast_data_add_int(data_queue, "membercount", ao2_container_count(queue->members));
9935
9936 /* announce position */
9937 enum_node = ast_data_add_node(data_queue, "announceposition");
9938 if (!enum_node) {
9939 return;
9940 }
9941 switch (queue->announceposition) {
9942 case ANNOUNCEPOSITION_LIMIT:
9943 ast_data_add_str(enum_node, "text", "limit");
9944 break;
9945 case ANNOUNCEPOSITION_MORE_THAN:
9946 ast_data_add_str(enum_node, "text", "more");
9947 break;
9948 case ANNOUNCEPOSITION_YES:
9949 ast_data_add_str(enum_node, "text", "yes");
9950 break;
9951 case ANNOUNCEPOSITION_NO:
9952 ast_data_add_str(enum_node, "text", "no");
9953 break;
9954 default:
9955 ast_data_add_str(enum_node, "text", "unknown");
9956 break;
9957 }
9958 ast_data_add_int(enum_node, "value", queue->announceposition);
9959
9960 /* add queue members */
9961 im = ao2_iterator_init(queue->members, 0);
9962 while ((member = ao2_iterator_next(&im))) {
9963 if (!data_members) {
9964 data_members = ast_data_add_node(data_queue, "members");
9965 if (!data_members) {
9966 ao2_ref(member, -1);
9967 continue;
9968 }
9969 }
9970
9971 data_member = ast_data_add_node(data_members, "member");
9972 if (!data_member) {
9973 ao2_ref(member, -1);
9974 continue;
9975 }
9976
9977 ast_data_add_structure(member, data_member, member);
9978
9979 ao2_ref(member, -1);
9980 }
9981 ao2_iterator_destroy(&im);
9982
9983 /* include the callers inside the result. */
9984 if (queue->head) {
9985 for (qe = queue->head; qe; qe = qe->next) {
9986 if (!data_callers) {
9987 data_callers = ast_data_add_node(data_queue, "callers");
9988 if (!data_callers) {
9989 continue;
9990 }
9991 }
9992
9993 data_caller = ast_data_add_node(data_callers, "caller");
9994 if (!data_caller) {
9995 continue;
9996 }
9997
9998 ast_data_add_structure(queue_ent, data_caller, qe);
9999
10000 /* add the caller channel. */
10001 data_caller_channel = ast_data_add_node(data_caller, "channel");
10002 if (!data_caller_channel) {
10003 continue;
10004 }
10005
10006 ast_channel_data_add_structure(data_caller_channel, qe->chan, 1);
10007 }
10008 }
10009
10010 /* if this queue doesn't match remove the added queue. */
10011 if (!ast_data_search_match(search, data_queue)) {
10012 ast_data_remove_node(data_root, data_queue);
10013 }
10014}
10015
10016/*!
10017 * \internal
10018 * \brief Callback used to generate the queues tree.
10019 * \param[in] search The search pattern tree.
10020 * \retval NULL on error.
10021 * \retval non-NULL The generated tree.
10022 */
10023static int queues_data_provider_get(const struct ast_data_search *search,
10024 struct ast_data *data_root)
10025{
10026 struct ao2_iterator i;
10027 struct call_queue *queue, *queue_realtime = NULL;
10028 struct ast_config *cfg;
10029 char *queuename;
10030
10031 /* load realtime queues. */
10032 cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", SENTINEL);
10033 if (cfg) {
10034 for (queuename = ast_category_browse(cfg, NULL);
10035 !ast_strlen_zero(queuename);
10036 queuename = ast_category_browse(cfg, queuename)) {
10037 if ((queue = find_load_queue_rt_friendly(queuename))) {
10038 queue_unref(queue);
10039 }
10040 }
10041 ast_config_destroy(cfg);
10042 }
10043
10044 /* static queues. */
10045 i = ao2_iterator_init(queues, 0);
10046 while ((queue = ao2_iterator_next(&i))) {
10047 ao2_lock(queue);
10048 if (queue->realtime) {
10049 queue_realtime = find_load_queue_rt_friendly(queue->name);
10050 if (!queue_realtime) {
10051 ao2_unlock(queue);
10052 queue_unref(queue);
10053 continue;
10054 }
10055 queue_unref(queue_realtime);
10056 }
10057
10058 queues_data_provider_get_helper(search, data_root, queue);
10059 ao2_unlock(queue);
10060 queue_unref(queue);
10061 }
10062 ao2_iterator_destroy(&i);
10063
10064 return 0;
10065}
10066
10067static const struct ast_data_handler queues_data_provider = {
10068 .version = AST_DATA_HANDLER_VERSION,
10069 .get = queues_data_provider_get
10070};
10071
10072static const struct ast_data_entry queue_data_providers[] = {
10073 AST_DATA_ENTRY("asterisk/application/queue/list", &queues_data_provider),
10074};
10075
10076static int unload_module(void)
10077{
10078 int res;
10079 struct ao2_iterator q_iter;
10080 struct call_queue *q = NULL;
10081
10082 ast_cli_unregister_multiple(cli_queue, ARRAY_LEN(cli_queue));
10083 res = ast_manager_unregister("QueueStatus");
10084 res |= ast_manager_unregister("Queues");
10085 res |= ast_manager_unregister("QueueRule");
10086 res |= ast_manager_unregister("QueueSummary");
10087 res |= ast_manager_unregister("QueueAdd");
10088 res |= ast_manager_unregister("QueueRemove");
10089 res |= ast_manager_unregister("QueuePause");
10090 res |= ast_manager_unregister("QueueLog");
10091 res |= ast_manager_unregister("QueuePenalty");
10092 res |= ast_manager_unregister("QueueReload");
10093 res |= ast_manager_unregister("QueueReset");
10094 res |= ast_manager_unregister("QueueMemberRingInUse");
10095 res |= ast_unregister_application(app_aqm);
10096 res |= ast_unregister_application(app_rqm);
10097 res |= ast_unregister_application(app_pqm);
10098 res |= ast_unregister_application(app_upqm);
10099 res |= ast_unregister_application(app_ql);
10100 res |= ast_unregister_application(app);
10101 res |= ast_custom_function_unregister(&queueexists_function);
10102 res |= ast_custom_function_unregister(&queuevar_function);
10103 res |= ast_custom_function_unregister(&queuemembercount_function);
10104 res |= ast_custom_function_unregister(&queuemembercount_dep);
10105 res |= ast_custom_function_unregister(&queuememberlist_function);
10106 res |= ast_custom_function_unregister(&queuewaitingcount_function);
10107 res |= ast_custom_function_unregister(&queuememberpenalty_function);
10108
10109 res |= ast_data_unregister(NULL);
10110
10111 if (device_state_sub)
10112 ast_event_unsubscribe(device_state_sub);
10113
10114 ast_extension_state_del(0, extension_state_cb);
10115
10116 q_iter = ao2_iterator_init(queues, 0);
10117 while ((q = ao2_t_iterator_next(&q_iter, "Iterate through queues"))) {
10118 queues_t_unlink(queues, q, "Remove queue from container due to unload");
10119 queue_t_unref(q, "Done with iterator");
10120 }
10121 ao2_iterator_destroy(&q_iter);
10122 devicestate_tps = ast_taskprocessor_unreference(devicestate_tps);
10123 ao2_cleanup(pending_members);
10124 ao2_ref(queues, -1);
10125 ast_unload_realtime("queue_members");
10126 return res;
10127}
10128
10129static int load_module(void)
10130{
10131 int res;
10132 struct ast_flags mask = {AST_FLAGS_ALL, };
10133 struct ast_config *member_config;
10134
10135 queues = ao2_container_alloc(MAX_QUEUE_BUCKETS, queue_hash_cb, queue_cmp_cb);
10136 if (!queues) {
10137 return AST_MODULE_LOAD_DECLINE;
10138 }
10139
10140 pending_members = ao2_container_alloc(
10141 MAX_CALL_ATTEMPT_BUCKETS, pending_members_hash, pending_members_cmp);
10142 if (!pending_members) {
10143 unload_module();
10144 return AST_MODULE_LOAD_DECLINE;
10145 }
10146
10147 use_weight = 0;
10148
10149 if (reload_handler(0, &mask, NULL))
10150 return AST_MODULE_LOAD_DECLINE;
10151
10152 ast_realtime_require_field("queue_members", "paused", RQ_INTEGER1, 1, "uniqueid", RQ_UINTEGER2, 5, SENTINEL);
10153
10154 /*
10155 * This section is used to determine which name for 'ringinuse' to use in realtime members
10156 * Necessary for supporting older setups.
10157 */
10158 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name LIKE", "%", SENTINEL);
10159 if (!member_config) {
10160 realtime_ringinuse_field = "ringinuse";
10161 } else {
10162 const char *config_val;
10163 if ((config_val = ast_variable_retrieve(member_config, NULL, "ringinuse"))) {
10164 ast_log(LOG_NOTICE, "ringinuse field entries found in queue_members table. Using 'ringinuse'\n");
10165 realtime_ringinuse_field = "ringinuse";
10166 } else if ((config_val = ast_variable_retrieve(member_config, NULL, "ignorebusy"))) {
10167 ast_log(LOG_NOTICE, "ignorebusy field found in queue_members table with no ringinuse field. Using 'ignorebusy'\n");
10168 realtime_ringinuse_field = "ignorebusy";
10169 } else {
10170 ast_log(LOG_NOTICE, "No entries were found for ringinuse/ignorebusy in queue_members table. Using 'ringinuse'\n");
10171 realtime_ringinuse_field = "ringinuse";
10172 }
10173 }
10174
10175 ast_config_destroy(member_config);
10176
10177 if (queue_persistent_members)
10178 reload_queue_members();
10179
10180 ast_data_register_multiple(queue_data_providers, ARRAY_LEN(queue_data_providers));
10181
10182 ast_cli_register_multiple(cli_queue, ARRAY_LEN(cli_queue));
10183 res = ast_register_application_xml(app, queue_exec);
10184 res |= ast_register_application_xml(app_aqm, aqm_exec);
10185 res |= ast_register_application_xml(app_rqm, rqm_exec);
10186 res |= ast_register_application_xml(app_pqm, pqm_exec);
10187 res |= ast_register_application_xml(app_upqm, upqm_exec);
10188 res |= ast_register_application_xml(app_ql, ql_exec);
10189 res |= ast_manager_register_xml("Queues", 0, manager_queues_show);
10190 res |= ast_manager_register_xml("QueueStatus", 0, manager_queues_status);
10191 res |= ast_manager_register_xml("QueueSummary", 0, manager_queues_summary);
10192 res |= ast_manager_register_xml("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member);
10193 res |= ast_manager_register_xml("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member);
10194 res |= ast_manager_register_xml("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member);
10195 res |= ast_manager_register_xml("QueueLog", EVENT_FLAG_AGENT, manager_queue_log_custom);
10196 res |= ast_manager_register_xml("QueuePenalty", EVENT_FLAG_AGENT, manager_queue_member_penalty);
10197 res |= ast_manager_register_xml("QueueMemberRingInUse", EVENT_FLAG_AGENT, manager_queue_member_ringinuse);
10198 res |= ast_manager_register_xml("QueueRule", 0, manager_queue_rule_show);
10199 res |= ast_manager_register_xml("QueueReload", 0, manager_queue_reload);
10200 res |= ast_manager_register_xml("QueueReset", 0, manager_queue_reset);
10201 res |= ast_custom_function_register(&queuevar_function);
10202 res |= ast_custom_function_register(&queueexists_function);
10203 res |= ast_custom_function_register(&queuemembercount_function);
10204 res |= ast_custom_function_register(&queuemembercount_dep);
10205 res |= ast_custom_function_register(&queuememberlist_function);
10206 res |= ast_custom_function_register(&queuewaitingcount_function);
10207 res |= ast_custom_function_register(&queuememberpenalty_function);
10208
10209 if (!(devicestate_tps = ast_taskprocessor_get("app_queue", 0))) {
10210 ast_log(LOG_WARNING, "devicestate taskprocessor reference failed - devicestate notifications will not occur\n");
10211 }
10212
10213 /* in the following subscribe call, do I use DEVICE_STATE, or DEVICE_STATE_CHANGE? */
10214 if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, "AppQueue Device state", NULL, AST_EVENT_IE_END))) {
10215 res = -1;
10216 }
10217
10218 ast_extension_state_add(NULL, NULL, extension_state_cb, NULL);
10219
10220 return res ? AST_MODULE_LOAD_DECLINE : 0;
10221}
10222
10223static int reload(void)
10224{
10225 struct ast_flags mask = {AST_FLAGS_ALL & ~QUEUE_RESET_STATS,};
10226 ast_unload_realtime("queue_members");
10227 reload_handler(1, &mask, NULL);
10228 return 0;
10229}
10230
10231/* \brief Find a member by looking up queuename and interface.
10232 * \return Returns a member or NULL if member not found.
10233*/
10234static struct member *find_member_by_queuename_and_interface(const char *queuename, const char *interface)
10235{
10236 struct member *mem = NULL;
10237 struct call_queue *q;
10238
10239 if ((q = find_load_queue_rt_friendly(queuename))) {
10240 ao2_lock(q);
10241 mem = ao2_find(q->members, interface, OBJ_KEY);
10242 ao2_unlock(q);
10243 queue_t_unref(q, "Expiring temporary reference.");
10244 }
10245 return mem;
10246}
10247
10248AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "True Call Queueing",
10249 .load = load_module,
10250 .unload = unload_module,
10251 .reload = reload,
10252 .load_pri = AST_MODPRI_DEVSTATE_CONSUMER,
10253 .nonoptreq = "res_monitor",
10254 );