2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief True call queues with optional send URL on answer
23 * \author Mark Spencer <markster@digium.com>
25 * \arg Config in \ref Config_qu queues.conf
27 * \par Development notes
28 * \note 2004-11-25: Persistent Dynamic Members added by:
29 * NetNation Communications (www.netnation.com)
30 * Kevin Lindsay <kevinl@netnation.com>
32 * Each dynamic agent in each queue is now stored in the astdb.
33 * When asterisk is restarted, each agent will be automatically
34 * readded into their recorded queues. This feature can be
35 * configured with the 'persistent_members=<1|0>' setting in the
36 * '[general]' category in queues.conf. The default is on.
38 * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
40 * \note These features added by David C. Troy <dave@toad.net>:
41 * - Per-queue holdtime calculation
42 * - Estimated holdtime announcement
43 * - Position announcement
44 * - Abandoned/completed call counters
45 * - Failout timer passed as optional app parameter
46 * - Optional monitoring of calls, started when call is answered
48 * Patch Version 1.07 2003-12-24 01
50 * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51 * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
53 * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54 * by Matthew Enger <m.enger@xi.com.au>
56 * \ingroup applications
61 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
70 #include <sys/signal.h>
71 #include <netinet/in.h>
73 #include "asterisk/lock.h"
74 #include "asterisk/file.h"
75 #include "asterisk/logger.h"
76 #include "asterisk/channel.h"
77 #include "asterisk/pbx.h"
78 #include "asterisk/options.h"
79 #include "asterisk/app.h"
80 #include "asterisk/linkedlists.h"
81 #include "asterisk/module.h"
82 #include "asterisk/translate.h"
83 #include "asterisk/say.h"
84 #include "asterisk/features.h"
85 #include "asterisk/musiconhold.h"
86 #include "asterisk/cli.h"
87 #include "asterisk/manager.h"
88 #include "asterisk/config.h"
89 #include "asterisk/monitor.h"
90 #include "asterisk/utils.h"
91 #include "asterisk/causes.h"
92 #include "asterisk/astdb.h"
93 #include "asterisk/devicestate.h"
94 #include "asterisk/stringfields.h"
95 #include "asterisk/event.h"
98 QUEUE_STRATEGY_RINGALL = 0,
99 QUEUE_STRATEGY_LEASTRECENT,
100 QUEUE_STRATEGY_FEWESTCALLS,
101 QUEUE_STRATEGY_RANDOM,
102 QUEUE_STRATEGY_RRMEMORY
105 static struct strategy {
109 { QUEUE_STRATEGY_RINGALL, "ringall" },
110 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
111 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
112 { QUEUE_STRATEGY_RANDOM, "random" },
113 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
116 #define DEFAULT_RETRY 5
117 #define DEFAULT_TIMEOUT 15
118 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
119 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
120 #define DEFAULT_MIN_ANNOUNCE_FREQUENCY 15 /* The minimum number of seconds between position announcements
121 The default value of 15 provides backwards compatibility */
123 #define RES_OKAY 0 /* Action completed */
124 #define RES_EXISTS (-1) /* Entry already exists */
125 #define RES_OUTOFMEMORY (-2) /* Out of memory */
126 #define RES_NOSUCHQUEUE (-3) /* No such queue */
128 static char *app = "Queue";
130 static char *synopsis = "Queue a call for a call queue";
132 static char *descrip =
133 " Queue(queuename[|options[|URL][|announceoverride][|timeout][|AGI][|macro][|gosub]):\n"
134 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
135 "This application will return to the dialplan if the queue does not exist, or\n"
136 "any of the join options cause the caller to not enter the queue.\n"
137 "The option string may contain zero or more of the following characters:\n"
138 " 'c' -- continue in the dialplan if the callee hangs up.\n"
139 " 'd' -- data-quality (modem) call (minimum delay).\n"
140 " 'h' -- allow callee to hang up by pressing *.\n"
141 " 'H' -- allow caller to hang up by pressing *.\n"
142 " 'n' -- no retries on the timeout; will exit this application and \n"
143 " go to the next step.\n"
144 " 'i' -- ignore call forward requests from queue members and do nothing\n"
145 " when they are requested.\n"
146 " 'r' -- ring instead of playing MOH.\n"
147 " 't' -- allow the called user to transfer the calling user.\n"
148 " 'T' -- allow the calling user to transfer the call.\n"
149 " 'w' -- allow the called user to write the conversation to disk via Monitor.\n"
150 " 'W' -- allow the calling user to write the conversation to disk via Monitor.\n"
151 " In addition to transferring the call, a call may be parked and then picked\n"
152 "up by another user.\n"
153 " The optional URL will be sent to the called party if the channel supports\n"
155 " The optional AGI parameter will setup an AGI script to be executed on the \n"
156 "calling party's channel once they are connected to a queue member.\n"
157 " The optional macro parameter will run a macro on the \n"
158 "calling party's channel once they are connected to a queue member.\n"
159 " The optional gosub parameter will run a gosub on the \n"
160 "calling party's channel once they are connected to a queue member.\n"
161 " The timeout will cause the queue to fail out after a specified number of\n"
162 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
163 " This application sets the following channel variable upon completion:\n"
164 " QUEUESTATUS The status of the call as a text string, one of\n"
165 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL | CONTINUE\n";
167 static char *app_aqm = "AddQueueMember" ;
168 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
169 static char *app_aqm_descrip =
170 " AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]]):\n"
171 "Dynamically adds interface to an existing queue.\n"
172 "If the interface is already in the queue it will return an error.\n"
173 " This application sets the following channel variable upon completion:\n"
174 " AQMSTATUS The status of the attempt to add a queue member as a \n"
175 " text string, one of\n"
176 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
177 "Example: AddQueueMember(techsupport|SIP/3000)\n"
180 static char *app_rqm = "RemoveQueueMember" ;
181 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
182 static char *app_rqm_descrip =
183 " RemoveQueueMember(queuename[|interface[|options]]):\n"
184 "Dynamically removes interface to an existing queue\n"
185 "If the interface is NOT in the queue it will return an error.\n"
186 " This application sets the following channel variable upon completion:\n"
187 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
188 " text string, one of\n"
189 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
190 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
193 static char *app_pqm = "PauseQueueMember" ;
194 static char *app_pqm_synopsis = "Pauses a queue member" ;
195 static char *app_pqm_descrip =
196 " PauseQueueMember([queuename]|interface[|options]):\n"
197 "Pauses (blocks calls for) a queue member.\n"
198 "The given interface will be paused in the given queue. This prevents\n"
199 "any calls from being sent from the queue to the interface until it is\n"
200 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
201 "queuename is given, the interface is paused in every queue it is a\n"
202 "member of. The application will fail if the interface is not found.\n"
203 " This application sets the following channel variable upon completion:\n"
204 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
205 " text string, one of\n"
206 " PAUSED | NOTFOUND\n"
207 "Example: PauseQueueMember(|SIP/3000)\n";
209 static char *app_upqm = "UnpauseQueueMember" ;
210 static char *app_upqm_synopsis = "Unpauses a queue member" ;
211 static char *app_upqm_descrip =
212 " UnpauseQueueMember([queuename]|interface[|options]):\n"
213 "Unpauses (resumes calls to) a queue member.\n"
214 "This is the counterpart to PauseQueueMember and operates exactly the\n"
215 "same way, except it unpauses instead of pausing the given interface.\n"
216 " This application sets the following channel variable upon completion:\n"
217 " UPQMSTATUS The status of the attempt to unpause a queue \n"
218 " member as a text string, one of\n"
219 " UNPAUSED | NOTFOUND\n"
220 "Example: UnpauseQueueMember(|SIP/3000)\n";
222 static char *app_ql = "QueueLog" ;
223 static char *app_ql_synopsis = "Writes to the queue_log" ;
224 static char *app_ql_descrip =
225 " QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n"
226 "Allows you to write your own events into the queue log\n"
227 "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n";
229 /*! \brief Persistent Members astdb family */
230 static const char *pm_family = "Queue/PersistentMembers";
231 /* The maximum length of each persistent member queue database entry */
232 #define PM_MAX_LEN 8192
234 /*! \brief queues.conf [general] option */
235 static int queue_keep_stats = 0;
237 /*! \brief queues.conf [general] option */
238 static int queue_persistent_members = 0;
240 /*! \brief queues.conf per-queue weight option */
241 static int use_weight = 0;
243 /*! \brief queues.conf [general] option */
244 static int autofill_default = 0;
246 /*! \brief queues.conf [general] option */
247 static int montype_default = 0;
249 /*! \brief Subscription to device state change events */
250 static struct ast_event_sub *device_state_sub;
256 QUEUE_LEAVEEMPTY = 3,
257 QUEUE_JOINUNAVAIL = 4,
258 QUEUE_LEAVEUNAVAIL = 5,
264 enum queue_result id;
266 } queue_results[] = {
267 { QUEUE_UNKNOWN, "UNKNOWN" },
268 { QUEUE_TIMEOUT, "TIMEOUT" },
269 { QUEUE_JOINEMPTY,"JOINEMPTY" },
270 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
271 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
272 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
273 { QUEUE_FULL, "FULL" },
274 { QUEUE_CONTINUE, "CONTINUE" },
277 /*! \brief We define a custom "local user" structure because we
278 use it not only for keeping track of what is in use but
279 also for keeping track of who we're dialing. */
282 struct callattempt *q_next;
283 struct ast_channel *chan;
289 struct member *member;
294 struct call_queue *parent; /*!< What queue is our parent */
295 char moh[80]; /*!< Name of musiconhold to be used */
296 char announce[80]; /*!< Announcement to play for member when call is answered */
297 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
298 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
299 int pos; /*!< Where we are in the queue */
300 int prio; /*!< Our priority */
301 int last_pos_said; /*!< Last position we told the user */
302 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
303 int last_periodic_announce_sound; /*!< The last periodic announcement we made */
304 time_t last_pos; /*!< Last time we told the user their position */
305 int opos; /*!< Where we started in the queue */
306 int handled; /*!< Whether our call was handled */
307 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
308 time_t start; /*!< When we started holding */
309 time_t expire; /*!< When this entry should expire (time out of queue) */
310 struct ast_channel *chan; /*!< Our channel */
311 struct queue_ent *next; /*!< The next queue entry */
315 char interface[80]; /*!< Technology/Location */
316 char membername[80]; /*!< Member name to use in queue logs */
317 int penalty; /*!< Are we a last resort? */
318 int calls; /*!< Number of calls serviced by this member */
319 int dynamic; /*!< Are we dynamically added? */
320 int status; /*!< Status of queue member */
321 int paused; /*!< Are we paused (not accepting calls)? */
322 time_t lastcall; /*!< When last successful call was hungup */
323 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
324 unsigned int delme:1; /*!< Flag to delete entry on reload */
325 struct member *next; /*!< Next member */
328 struct member_interface {
330 AST_LIST_ENTRY(member_interface) list; /*!< Next call queue */
333 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
335 /* values used in multi-bit flags in call_queue */
336 #define QUEUE_EMPTY_NORMAL 1
337 #define QUEUE_EMPTY_STRICT 2
338 #define QUEUE_EMPTY_LOOSE 3
339 #define ANNOUNCEHOLDTIME_ALWAYS 1
340 #define ANNOUNCEHOLDTIME_ONCE 2
341 #define QUEUE_EVENT_VARIABLES 3
345 char name[80]; /*!< Name */
346 char moh[80]; /*!< Music On Hold class to be used */
347 char announce[80]; /*!< Announcement to play when call is answered */
348 char context[AST_MAX_CONTEXT]; /*!< Exit context */
349 unsigned int monjoin:1;
351 unsigned int joinempty:2;
352 unsigned int eventwhencalled:2;
353 unsigned int leavewhenempty:2;
354 unsigned int ringinuse:1;
355 unsigned int setinterfacevar:1;
356 unsigned int setqueuevar:1;
357 unsigned int setqueueentryvar:1;
358 unsigned int reportholdtime:1;
359 unsigned int wrapped:1;
360 unsigned int timeoutrestart:1;
361 unsigned int announceholdtime:2;
362 unsigned int strategy:3;
363 unsigned int maskmemberstatus:1;
364 unsigned int realtime:1;
365 int announcefrequency; /*!< How often to announce their position */
366 int minannouncefrequency; /*!< The minimum number of seconds between position announcements (def. 15) */
367 int periodicannouncefrequency; /*!< How often to play periodic announcement */
368 int roundingseconds; /*!< How many seconds do we round to? */
369 int holdtime; /*!< Current avg holdtime, based on recursive boxcar filter */
370 int callscompleted; /*!< Number of queue calls completed */
371 int callsabandoned; /*!< Number of queue calls abandoned */
372 int servicelevel; /*!< seconds setting for servicelevel*/
373 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
374 char monfmt[8]; /*!< Format to use when recording calls */
375 int montype; /*!< Monitor type Monitor vs. MixMonitor */
376 char membermacro[32]; /*!< Macro to run upon member connection */
377 char membergosub[32]; /*!< Gosub to run upon member connection */
378 char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
379 char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
380 char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
381 char sound_holdtime[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
382 char sound_minutes[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
383 char sound_lessthan[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
384 char sound_seconds[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
385 char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
386 char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
387 char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/*!< Sound files: Custom announce, no default */
389 int count; /*!< How many entries */
390 int maxlen; /*!< Max number of entries */
391 int wrapuptime; /*!< Wrapup Time */
393 int retry; /*!< Retry calling everyone after this amount of time */
394 int timeout; /*!< How long to wait for an answer */
395 int weight; /*!< Respective weight */
396 int autopause; /*!< Auto pause queue members if they fail to answer */
398 /* Queue strategy things */
399 int rrpos; /*!< Round Robin - position */
400 int memberdelay; /*!< Seconds to delay connecting member to caller */
401 int autofill; /*!< Ignore the head call status and ring an available agent */
403 struct member *members; /*!< Head of the list of members */
404 struct queue_ent *head; /*!< Head of the list of callers */
405 AST_LIST_ENTRY(call_queue) list; /*!< Next call queue */
408 static AST_LIST_HEAD_STATIC(queues, call_queue);
410 static int set_member_paused(const char *queuename, const char *interface, int paused);
412 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
416 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
417 if (queue_results[i].id == res) {
418 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
424 static char *int2strat(int strategy)
428 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
429 if (strategy == strategies[x].strategy)
430 return strategies[x].name;
436 static int strat2int(const char *strategy)
440 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
441 if (!strcasecmp(strategy, strategies[x].name))
442 return strategies[x].strategy;
448 static void set_queue_variables(struct queue_ent *qe)
451 char interfacevar[256]="";
454 if (qe->parent->setqueuevar) {
456 if (qe->parent->callscompleted > 0)
457 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
459 snprintf(interfacevar,sizeof(interfacevar),
460 "QUEUEMAX=%d|QUEUESTRATEGY=%s|QUEUECALLS=%d|QUEUEHOLDTIME=%d|QUEUECOMPLETED=%d|QUEUEABANDONED=%d|QUEUESRVLEVEL=%d|QUEUESRVLEVELPERF=%2.1f",
461 qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
462 qe->parent->callsabandoned, qe->parent->servicelevel, sl);
464 pbx_builtin_setvar(qe->chan, interfacevar);
468 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
469 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
471 struct queue_ent *cur;
488 enum queue_member_status {
490 QUEUE_NO_REACHABLE_MEMBERS,
491 QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
495 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
497 struct member *member;
498 enum queue_member_status result = QUEUE_NO_MEMBERS;
500 ast_mutex_lock(&q->lock);
501 for (member = q->members; member; member = member->next) {
502 if (max_penalty && (member->penalty > max_penalty))
505 switch (member->status) {
506 case AST_DEVICE_INVALID:
509 case AST_DEVICE_UNAVAILABLE:
510 if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)
511 result = QUEUE_NO_REACHABLE_MEMBERS;
514 if (member->paused) {
515 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
517 ast_mutex_unlock(&q->lock);
524 ast_mutex_unlock(&q->lock);
529 AST_LIST_ENTRY(statechange) entry;
534 static void *handle_statechange(struct statechange *sc)
536 struct call_queue *q;
538 struct member_interface *curint;
542 technology = ast_strdupa(sc->dev);
543 loc = strchr(technology, '/');
550 AST_LIST_LOCK(&interfaces);
551 AST_LIST_TRAVERSE(&interfaces, curint, list) {
554 interface = ast_strdupa(curint->interface);
555 if ((slash_pos = strchr(interface, '/')))
556 if ((slash_pos = strchr(slash_pos + 1, '/')))
559 if (!strcasecmp(interface, sc->dev))
562 AST_LIST_UNLOCK(&interfaces);
565 ast_debug(3, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
569 ast_debug(1, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
570 AST_LIST_LOCK(&queues);
571 AST_LIST_TRAVERSE(&queues, q, list) {
572 ast_mutex_lock(&q->lock);
573 for (cur = q->members; cur; cur = cur->next) {
576 interface = ast_strdupa(cur->interface);
577 if ((slash_pos = strchr(interface, '/')))
578 if ((slash_pos = strchr(slash_pos + 1, '/')))
581 if (strcasecmp(sc->dev, interface))
584 if (cur->status != sc->state) {
585 cur->status = sc->state;
586 if (q->maskmemberstatus)
589 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
599 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
600 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
603 ast_mutex_unlock(&q->lock);
605 AST_LIST_UNLOCK(&queues);
611 * \brief Data used by the device state thread
614 /*! Set to 1 to stop the thread */
616 /*! The device state monitoring thread */
618 /*! Lock for the state change queue */
620 /*! Condition for the state change queue */
622 /*! Queue of state changes */
623 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
625 .thread = AST_PTHREADT_NULL,
628 static void *device_state_thread(void *data)
630 struct statechange *sc;
632 while (!device_state.stop) {
633 ast_mutex_lock(&device_state.lock);
634 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
635 ast_cond_wait(&device_state.cond, &device_state.lock);
636 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
638 ast_mutex_unlock(&device_state.lock);
640 /* Check to see if we were woken up to see the request to stop */
641 if (device_state.stop)
647 handle_statechange(sc);
655 static int statechange_queue(const char *dev, enum ast_device_state state)
657 struct statechange *sc;
659 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
663 strcpy(sc->dev, dev);
665 ast_mutex_lock(&device_state.lock);
666 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
667 ast_cond_signal(&device_state.cond);
668 ast_mutex_unlock(&device_state.lock);
673 static void device_state_cb(const struct ast_event *event, void *unused)
675 enum ast_device_state state;
678 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
679 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
681 if (ast_strlen_zero(device)) {
682 ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
686 statechange_queue(device, state);
689 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
693 if ((cur = ast_calloc(1, sizeof(*cur)))) {
694 cur->penalty = penalty;
695 cur->paused = paused;
696 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
697 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
698 if (!strchr(cur->interface, '/'))
699 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
700 cur->status = ast_device_state(interface);
706 static struct call_queue *alloc_queue(const char *queuename)
708 struct call_queue *q;
710 if ((q = ast_calloc(1, sizeof(*q)))) {
711 ast_mutex_init(&q->lock);
712 ast_copy_string(q->name, queuename, sizeof(q->name));
717 static void init_queue(struct call_queue *q)
722 q->retry = DEFAULT_RETRY;
725 q->announcefrequency = 0;
726 q->minannouncefrequency = DEFAULT_MIN_ANNOUNCE_FREQUENCY;
727 q->announceholdtime = 0;
728 q->roundingseconds = 0; /* Default - don't announce seconds */
731 q->setinterfacevar = 0;
733 q->setqueueentryvar = 0;
734 q->autofill = autofill_default;
735 q->montype = montype_default;
736 q->membermacro[0] = '\0';
737 q->membergosub[0] = '\0';
739 q->announce[0] = '\0';
740 q->context[0] = '\0';
742 q->periodicannouncefrequency = 0;
743 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
744 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
745 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
746 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
747 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
748 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
749 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
750 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
751 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
752 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
753 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
754 q->sound_periodicannounce[i][0]='\0';
758 static void clear_queue(struct call_queue *q)
761 q->callscompleted = 0;
762 q->callsabandoned = 0;
763 q->callscompletedinsl = 0;
767 static int add_to_interfaces(const char *interface)
769 struct member_interface *curint;
771 AST_LIST_LOCK(&interfaces);
772 AST_LIST_TRAVERSE(&interfaces, curint, list) {
773 if (!strcasecmp(curint->interface, interface))
778 AST_LIST_UNLOCK(&interfaces);
782 ast_debug(1, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
784 if ((curint = ast_calloc(1, sizeof(*curint)))) {
785 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
786 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
788 AST_LIST_UNLOCK(&interfaces);
793 static int interface_exists_global(const char *interface)
795 struct call_queue *q;
799 AST_LIST_LOCK(&queues);
800 AST_LIST_TRAVERSE(&queues, q, list) {
801 ast_mutex_lock(&q->lock);
802 for (mem = q->members; mem && !ret; mem = mem->next) {
803 if (!strcasecmp(interface, mem->interface))
806 ast_mutex_unlock(&q->lock);
810 AST_LIST_UNLOCK(&queues);
815 static int remove_from_interfaces(const char *interface)
817 struct member_interface *curint;
819 AST_LIST_LOCK(&interfaces);
820 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
821 if (!strcasecmp(curint->interface, interface)) {
822 if (!interface_exists_global(interface)) {
823 ast_debug(1, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
824 AST_LIST_REMOVE_CURRENT(&interfaces, list);
830 AST_LIST_TRAVERSE_SAFE_END;
831 AST_LIST_UNLOCK(&interfaces);
836 static void clear_and_free_interfaces(void)
838 struct member_interface *curint;
840 AST_LIST_LOCK(&interfaces);
841 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
843 AST_LIST_UNLOCK(&interfaces);
846 /*! \brief Configure a queue parameter.
848 For error reporting, line number is passed for .conf static configuration.
849 For Realtime queues, linenum is -1.
850 The failunknown flag is set for config files (and static realtime) to show
851 errors for unknown parameters. It is cleared for dynamic realtime to allow
852 extra fields in the tables. */
853 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
855 if (!strcasecmp(param, "musicclass") ||
856 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
857 ast_copy_string(q->moh, val, sizeof(q->moh));
858 } else if (!strcasecmp(param, "announce")) {
859 ast_copy_string(q->announce, val, sizeof(q->announce));
860 } else if (!strcasecmp(param, "context")) {
861 ast_copy_string(q->context, val, sizeof(q->context));
862 } else if (!strcasecmp(param, "timeout")) {
863 q->timeout = atoi(val);
865 q->timeout = DEFAULT_TIMEOUT;
866 } else if (!strcasecmp(param, "ringinuse")) {
867 q->ringinuse = ast_true(val);
868 } else if (!strcasecmp(param, "setinterfacevar")) {
869 q->setinterfacevar = ast_true(val);
870 } else if (!strcasecmp(param, "setqueuevar")) {
871 q->setqueuevar = ast_true(val);
872 } else if (!strcasecmp(param, "setqueueentryvar")) {
873 q->setqueueentryvar = ast_true(val);
874 } else if (!strcasecmp(param, "monitor-join")) {
875 q->monjoin = ast_true(val);
876 } else if (!strcasecmp(param, "monitor-format")) {
877 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
878 } else if (!strcasecmp(param, "membermacro")) {
879 ast_copy_string(q->membermacro, val, sizeof(q->membermacro));
880 } else if (!strcasecmp(param, "membergosub")) {
881 ast_copy_string(q->membergosub, val, sizeof(q->membergosub));
882 } else if (!strcasecmp(param, "queue-youarenext")) {
883 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
884 } else if (!strcasecmp(param, "queue-thereare")) {
885 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
886 } else if (!strcasecmp(param, "queue-callswaiting")) {
887 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
888 } else if (!strcasecmp(param, "queue-holdtime")) {
889 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
890 } else if (!strcasecmp(param, "queue-minutes")) {
891 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
892 } else if (!strcasecmp(param, "queue-seconds")) {
893 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
894 } else if (!strcasecmp(param, "queue-lessthan")) {
895 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
896 } else if (!strcasecmp(param, "queue-thankyou")) {
897 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
898 } else if (!strcasecmp(param, "queue-reporthold")) {
899 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
900 } else if (!strcasecmp(param, "announce-frequency")) {
901 q->announcefrequency = atoi(val);
902 } else if (!strcasecmp(param, "min-announce-frequency")) {
903 q->minannouncefrequency = atoi(val);
904 ast_debug(1, "%s=%s for queue '%s'\n", param, val, q->name);
905 } else if (!strcasecmp(param, "announce-round-seconds")) {
906 q->roundingseconds = atoi(val);
907 /* Rounding to any other values just doesn't make sense... */
908 if (!(q->roundingseconds == 0 || q->roundingseconds == 1 || q->roundingseconds == 5 || q->roundingseconds == 10
909 || q->roundingseconds == 15 || q->roundingseconds == 20 || q->roundingseconds == 30)) {
911 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
912 "using 0 instead for queue '%s' at line %d of queues.conf\n",
913 val, param, q->name, linenum);
915 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
916 "using 0 instead for queue '%s'\n", val, param, q->name);
918 q->roundingseconds=0;
920 } else if (!strcasecmp(param, "announce-holdtime")) {
921 if (!strcasecmp(val, "once"))
922 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
923 else if (ast_true(val))
924 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
926 q->announceholdtime = 0;
927 } else if (!strcasecmp(param, "periodic-announce")) {
928 if (strchr(val, '|')) {
929 char *s, *buf = ast_strdupa(val);
932 while ((s = strsep(&buf, "|"))) {
933 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
935 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
939 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
941 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
942 q->periodicannouncefrequency = atoi(val);
943 } else if (!strcasecmp(param, "retry")) {
944 q->retry = atoi(val);
946 q->retry = DEFAULT_RETRY;
947 } else if (!strcasecmp(param, "wrapuptime")) {
948 q->wrapuptime = atoi(val);
949 } else if (!strcasecmp(param, "autofill")) {
950 q->autofill = ast_true(val);
951 } else if (!strcasecmp(param, "monitor-type")) {
952 if (!strcasecmp(val, "mixmonitor"))
954 } else if (!strcasecmp(param, "autopause")) {
955 q->autopause = ast_true(val);
956 } else if (!strcasecmp(param, "maxlen")) {
957 q->maxlen = atoi(val);
960 } else if (!strcasecmp(param, "servicelevel")) {
961 q->servicelevel= atoi(val);
962 } else if (!strcasecmp(param, "strategy")) {
963 q->strategy = strat2int(val);
964 if (q->strategy < 0) {
965 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
967 q->strategy = QUEUE_STRATEGY_RINGALL;
969 } else if (!strcasecmp(param, "joinempty")) {
970 if (!strcasecmp(val, "loose"))
971 q->joinempty = QUEUE_EMPTY_LOOSE;
972 else if (!strcasecmp(val, "strict"))
973 q->joinempty = QUEUE_EMPTY_STRICT;
974 else if (ast_true(val))
975 q->joinempty = QUEUE_EMPTY_NORMAL;
978 } else if (!strcasecmp(param, "leavewhenempty")) {
979 if (!strcasecmp(val, "loose"))
980 q->leavewhenempty = QUEUE_EMPTY_LOOSE;
981 else if (!strcasecmp(val, "strict"))
982 q->leavewhenempty = QUEUE_EMPTY_STRICT;
983 else if (ast_true(val))
984 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
986 q->leavewhenempty = 0;
987 } else if (!strcasecmp(param, "eventmemberstatus")) {
988 q->maskmemberstatus = !ast_true(val);
989 } else if (!strcasecmp(param, "eventwhencalled")) {
990 if (!strcasecmp(val, "vars")) {
991 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
993 q->eventwhencalled = ast_true(val);
995 } else if (!strcasecmp(param, "reportholdtime")) {
996 q->reportholdtime = ast_true(val);
997 } else if (!strcasecmp(param, "memberdelay")) {
998 q->memberdelay = atoi(val);
999 } else if (!strcasecmp(param, "weight")) {
1000 q->weight = atoi(val);
1003 /* With Realtime queues, if the last queue using weights is deleted in realtime,
1004 we will not see any effect on use_weight until next reload. */
1005 } else if (!strcasecmp(param, "timeoutrestart")) {
1006 q->timeoutrestart = ast_true(val);
1007 } else if (failunknown) {
1009 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
1010 q->name, param, linenum);
1012 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1017 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1019 struct member *m, *prev_m;
1024 penalty = atoi(penalty_str);
1030 paused = atoi(paused_str);
1035 /* Find the member, or the place to put a new one. */
1036 for (m = q->members, prev_m = NULL;
1037 m && strcmp(m->interface, interface);
1038 prev_m = m, m = m->next);
1040 /* Create a new one if not found, else update penalty */
1042 if ((m = create_queue_member(interface, membername, penalty, paused))) {
1044 add_to_interfaces(interface);
1052 m->dead = 0; /* Do not delete this one. */
1055 m->penalty = penalty;
1059 static void free_members(struct call_queue *q, int all)
1061 /* Free non-dynamic members */
1062 struct member *curm, *next, *prev = NULL;
1064 for (curm = q->members; curm; curm = next) {
1066 if (all || !curm->dynamic) {
1071 remove_from_interfaces(curm->interface);
1078 static void destroy_queue(struct call_queue *q)
1081 ast_mutex_destroy(&q->lock);
1085 /*!\brief Reload a single queue via realtime.
1086 \return Return the queue, or NULL if it doesn't exist.
1087 \note Should be called with the global qlock locked. */
1088 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1090 struct ast_variable *v;
1091 struct call_queue *q;
1092 struct member *m, *prev_m, *next_m;
1093 char *interface = NULL;
1094 char *tmp, *tmp_name;
1095 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
1097 /* Find the queue in the in-core list (we will create a new one if not found). */
1098 AST_LIST_TRAVERSE(&queues, q, list) {
1099 if (!strcasecmp(q->name, queuename))
1103 /* Static queues override realtime. */
1105 ast_mutex_lock(&q->lock);
1108 ast_mutex_unlock(&q->lock);
1111 ast_mutex_unlock(&q->lock);
1115 } else if (!member_config)
1116 /* Not found in the list, and it's not realtime ... */
1119 /* Check if queue is defined in realtime. */
1121 /* Delete queue from in-core list if it has been deleted in realtime. */
1123 /*! \note Hmm, can't seem to distinguish a DB failure from a not
1124 found condition... So we might delete an in-core queue
1125 in case of DB failure. */
1126 ast_debug(1, "Queue %s not found in realtime.\n", queuename);
1129 /* Delete if unused (else will be deleted when last caller leaves). */
1132 AST_LIST_REMOVE(&queues, q, list);
1133 ast_mutex_unlock(&q->lock);
1136 ast_mutex_unlock(&q->lock);
1141 /* Create a new queue if an in-core entry does not exist yet. */
1143 if (!(q = alloc_queue(queuename)))
1145 ast_mutex_lock(&q->lock);
1148 AST_LIST_INSERT_HEAD(&queues, q, list);
1150 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
1152 memset(tmpbuf, 0, sizeof(tmpbuf));
1153 for (v = queue_vars; v; v = v->next) {
1154 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1155 if ((tmp = strchr(v->name, '_'))) {
1156 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1159 while ((tmp = strchr(tmp, '_')))
1163 queue_set_param(q, tmp_name, v->value, -1, 0);
1166 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
1167 for (m = q->members; m; m = m->next) {
1172 while ((interface = ast_category_browse(member_config, interface))) {
1173 rt_handle_member_record(q, interface,
1174 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1175 ast_variable_retrieve(member_config, interface, "penalty"),
1176 ast_variable_retrieve(member_config, interface, "paused"));
1179 /* Delete all realtime members that have been deleted in DB. */
1186 prev_m->next = next_m;
1188 q->members = next_m;
1190 remove_from_interfaces(m->interface);
1198 ast_mutex_unlock(&q->lock);
1203 static struct call_queue *load_realtime_queue(const char *queuename)
1205 struct ast_variable *queue_vars;
1206 struct ast_config *member_config = NULL;
1207 struct call_queue *q;
1209 /* Find the queue in the in-core list first. */
1210 AST_LIST_LOCK(&queues);
1211 AST_LIST_TRAVERSE(&queues, q, list) {
1212 if (!strcasecmp(q->name, queuename)) {
1216 AST_LIST_UNLOCK(&queues);
1218 if (!q || q->realtime) {
1219 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1220 queue operations while waiting for the DB.
1222 This will be two separate database transactions, so we might
1223 see queue parameters as they were before another process
1224 changed the queue and member list as it was after the change.
1225 Thus we might see an empty member list when a queue is
1226 deleted. In practise, this is unlikely to cause a problem. */
1228 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1230 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1231 if (!member_config) {
1232 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1237 AST_LIST_LOCK(&queues);
1239 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1241 ast_config_destroy(member_config);
1243 ast_variables_destroy(queue_vars);
1245 AST_LIST_UNLOCK(&queues);
1250 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1252 struct call_queue *q;
1253 struct queue_ent *cur, *prev = NULL;
1257 enum queue_member_status stat;
1259 if (!(q = load_realtime_queue(queuename)))
1262 AST_LIST_LOCK(&queues);
1263 ast_mutex_lock(&q->lock);
1265 /* This is our one */
1266 stat = get_member_status(q, qe->max_penalty);
1267 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1268 *reason = QUEUE_JOINEMPTY;
1269 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS))
1270 *reason = QUEUE_JOINUNAVAIL;
1271 else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1272 *reason = QUEUE_JOINUNAVAIL;
1273 else if (q->maxlen && (q->count >= q->maxlen))
1274 *reason = QUEUE_FULL;
1276 /* There's space for us, put us at the right position inside
1278 * Take into account the priority of the calling user */
1283 /* We have higher priority than the current user, enter
1284 * before him, after all the other users with priority
1285 * higher or equal to our priority. */
1286 if ((!inserted) && (qe->prio > cur->prio)) {
1287 insert_entry(q, prev, qe, &pos);
1294 /* No luck, join at the end of the queue */
1296 insert_entry(q, prev, qe, &pos);
1297 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1298 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1299 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1302 manager_event(EVENT_FLAG_CALL, "Join",
1303 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1305 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1306 S_OR(qe->chan->cid.cid_name, "unknown"),
1307 q->name, qe->pos, q->count, qe->chan->uniqueid );
1308 ast_debug(1, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1310 ast_mutex_unlock(&q->lock);
1311 AST_LIST_UNLOCK(&queues);
1316 static int play_file(struct ast_channel *chan, char *filename)
1320 ast_stopstream(chan);
1321 res = ast_streamfile(chan, filename, chan->language);
1323 res = ast_waitstream(chan, AST_DIGIT_ANY);
1324 ast_stopstream(chan);
1329 static int valid_exit(struct queue_ent *qe, char digit)
1331 int digitlen = strlen(qe->digits);
1333 /* Prevent possible buffer overflow */
1334 if (digitlen < sizeof(qe->digits) - 2) {
1335 qe->digits[digitlen] = digit;
1336 qe->digits[digitlen + 1] = '\0';
1338 qe->digits[0] = '\0';
1342 /* If there's no context to goto, short-circuit */
1343 if (ast_strlen_zero(qe->context))
1346 /* If the extension is bad, then reset the digits to blank */
1347 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1348 qe->digits[0] = '\0';
1352 /* We have an exact match */
1353 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1354 /* Return 1 on a successful goto */
1361 static int say_position(struct queue_ent *qe)
1363 int res = 0, avgholdmins, avgholdsecs;
1366 /* Let minannouncefrequency seconds pass between the start of each position announcement */
1368 if ((now - qe->last_pos) < qe->parent->minannouncefrequency)
1371 /* If either our position has changed, or we are over the freq timer, say position */
1372 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1375 ast_moh_stop(qe->chan);
1376 /* Say we're next, if we are */
1378 res = play_file(qe->chan, qe->parent->sound_next);
1379 if (res && valid_exit(qe, res))
1384 res = play_file(qe->chan, qe->parent->sound_thereare);
1385 if (res && valid_exit(qe, res))
1387 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1388 if (res && valid_exit(qe, res))
1390 res = play_file(qe->chan, qe->parent->sound_calls);
1391 if (res && valid_exit(qe, res))
1394 /* Round hold time to nearest minute */
1395 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1397 /* If they have specified a rounding then round the seconds as well */
1398 if (qe->parent->roundingseconds) {
1399 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1400 avgholdsecs *= qe->parent->roundingseconds;
1405 if (option_verbose > 2)
1406 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1408 /* If the hold time is >1 min, if it's enabled, and if it's not
1409 supposed to be only once and we have already said it, say it */
1410 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1411 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1412 res = play_file(qe->chan, qe->parent->sound_holdtime);
1413 if (res && valid_exit(qe, res))
1416 if (avgholdmins > 0) {
1417 if (avgholdmins < 2) {
1418 res = play_file(qe->chan, qe->parent->sound_lessthan);
1419 if (res && valid_exit(qe, res))
1422 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1423 if (res && valid_exit(qe, res))
1426 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1427 if (res && valid_exit(qe, res))
1431 res = play_file(qe->chan, qe->parent->sound_minutes);
1432 if (res && valid_exit(qe, res))
1435 if (avgholdsecs>0) {
1436 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1437 if (res && valid_exit(qe, res))
1440 res = play_file(qe->chan, qe->parent->sound_seconds);
1441 if (res && valid_exit(qe, res))
1448 if (option_verbose > 2)
1449 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1450 qe->chan->name, qe->parent->name, qe->pos);
1451 res = play_file(qe->chan, qe->parent->sound_thanks);
1452 if (res && !valid_exit(qe, res))
1456 /* Set our last_pos indicators */
1458 qe->last_pos_said = qe->pos;
1460 /* Don't restart music on hold if we're about to exit the caller from the queue */
1462 ast_moh_start(qe->chan, qe->moh, NULL);
1467 static void recalc_holdtime(struct queue_ent *qe)
1469 int oldvalue, newvalue;
1471 /* Calculate holdtime using a recursive boxcar filter */
1472 /* Thanks to SRT for this contribution */
1473 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1475 newvalue = time(NULL) - qe->start;
1477 ast_mutex_lock(&qe->parent->lock);
1478 if (newvalue <= qe->parent->servicelevel)
1479 qe->parent->callscompletedinsl++;
1480 oldvalue = qe->parent->holdtime;
1481 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1482 ast_mutex_unlock(&qe->parent->lock);
1486 static void leave_queue(struct queue_ent *qe)
1488 struct call_queue *q;
1489 struct queue_ent *cur, *prev = NULL;
1492 if (!(q = qe->parent))
1494 ast_mutex_lock(&q->lock);
1497 for (cur = q->head; cur; cur = cur->next) {
1501 /* Take us out of the queue */
1502 manager_event(EVENT_FLAG_CALL, "Leave",
1503 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1504 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
1505 ast_debug(1, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1506 /* Take us out of the queue */
1508 prev->next = cur->next;
1510 q->head = cur->next;
1512 /* Renumber the people after us in the queue based on a new count */
1517 ast_mutex_unlock(&q->lock);
1519 if (q->dead && !q->count) {
1520 /* It's dead and nobody is in it, so kill it */
1521 AST_LIST_LOCK(&queues);
1522 AST_LIST_REMOVE(&queues, q, list);
1523 AST_LIST_UNLOCK(&queues);
1528 /* Hang up a list of outgoing calls */
1529 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1531 struct callattempt *oo;
1534 /* Hangup any existing lines we have open */
1535 if (outgoing->chan && (outgoing->chan != exception))
1536 ast_hangup(outgoing->chan);
1538 outgoing = outgoing->q_next;
1543 static int update_status(struct call_queue *q, struct member *member, int status)
1547 /* Since a reload could have taken place, we have to traverse the list to
1548 be sure it's still valid */
1549 ast_mutex_lock(&q->lock);
1550 for (cur = q->members; cur; cur = cur->next) {
1554 cur->status = status;
1555 if (!q->maskmemberstatus) {
1556 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1559 "MemberName: %s\r\n"
1560 "Membership: %s\r\n"
1562 "CallsTaken: %d\r\n"
1566 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
1567 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1570 ast_mutex_unlock(&q->lock);
1574 static int update_dial_status(struct call_queue *q, struct member *member, int status)
1576 if (status == AST_CAUSE_BUSY)
1577 status = AST_DEVICE_BUSY;
1578 else if (status == AST_CAUSE_UNREGISTERED)
1579 status = AST_DEVICE_UNAVAILABLE;
1580 else if (status == AST_CAUSE_NOSUCHDRIVER)
1581 status = AST_DEVICE_INVALID;
1583 status = AST_DEVICE_UNKNOWN;
1584 return update_status(q, member, status);
1587 /* traverse all defined queues which have calls waiting and contain this member
1588 return 0 if no other queue has precedence (higher weight) or 1 if found */
1589 static int compare_weight(struct call_queue *rq, struct member *member)
1591 struct call_queue *q;
1595 /* &qlock and &rq->lock already set by try_calling()
1596 * to solve deadlock */
1597 AST_LIST_TRAVERSE(&queues, q, list) {
1598 if (q == rq) /* don't check myself, could deadlock */
1600 ast_mutex_lock(&q->lock);
1601 if (q->count && q->members) {
1602 for (mem = q->members; mem; mem = mem->next) {
1603 if (strcmp(mem->interface, member->interface))
1606 ast_debug(1, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1607 if (q->weight > rq->weight) {
1608 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);
1614 ast_mutex_unlock(&q->lock);
1621 /*! \brief common hangup actions */
1622 static void do_hang(struct callattempt *o)
1625 ast_hangup(o->chan);
1629 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1631 struct ast_str *buf = ast_str_alloca(len + 1);
1634 if (pbx_builtin_serialize_variables(chan, &buf)) {
1637 /* convert "\n" to "\nVariable: " */
1638 strcpy(vars, "Variable: ");
1641 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1644 if (tmp[i + 1] == '\0')
1646 if (tmp[i] == '\n') {
1650 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1660 /* there are no channel variables; leave it blank */
1666 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1673 /* on entry here, we know that tmp->chan == NULL */
1674 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1675 ast_debug(1, "Wrapuptime not yet expired for %s\n", tmp->interface);
1677 ast_cdr_busy(qe->chan->cdr);
1678 tmp->stillgoing = 0;
1683 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1684 ast_debug(1, "%s in use, can't receive call\n", tmp->interface);
1686 ast_cdr_busy(qe->chan->cdr);
1687 tmp->stillgoing = 0;
1691 if (tmp->member->paused) {
1692 ast_debug(1, "%s paused, can't receive call\n", tmp->interface);
1694 ast_cdr_busy(qe->chan->cdr);
1695 tmp->stillgoing = 0;
1698 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1699 ast_debug(1, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1701 ast_cdr_busy(qe->chan->cdr);
1702 tmp->stillgoing = 0;
1707 ast_copy_string(tech, tmp->interface, sizeof(tech));
1708 if ((location = strchr(tech, '/')))
1713 /* Request the peer */
1714 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1715 if (!tmp->chan) { /* If we can't, just go on to the next call */
1717 ast_cdr_busy(qe->chan->cdr);
1718 tmp->stillgoing = 0;
1719 update_dial_status(qe->parent, tmp->member, status);
1721 ast_mutex_lock(&qe->parent->lock);
1722 qe->parent->rrpos++;
1723 ast_mutex_unlock(&qe->parent->lock);
1727 } else if (status != tmp->oldstatus)
1728 update_dial_status(qe->parent, tmp->member, status);
1730 tmp->chan->appl = "AppQueue";
1731 tmp->chan->data = "(Outgoing Line)";
1732 tmp->chan->whentohangup = 0;
1733 if (tmp->chan->cid.cid_num)
1734 ast_free(tmp->chan->cid.cid_num);
1735 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1736 if (tmp->chan->cid.cid_name)
1737 ast_free(tmp->chan->cid.cid_name);
1738 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1739 if (tmp->chan->cid.cid_ani)
1740 ast_free(tmp->chan->cid.cid_ani);
1741 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1743 /* Inherit specially named variables from parent channel */
1744 ast_channel_inherit_variables(qe->chan, tmp->chan);
1746 /* Presense of ADSI CPE on outgoing channel follows ours */
1747 tmp->chan->adsicpe = qe->chan->adsicpe;
1749 /* Place the call, but don't wait on the answer */
1750 if ((res = ast_call(tmp->chan, location, 0))) {
1751 /* Again, keep going even if there's an error */
1752 ast_debug(1, "ast call on peer returned %d\n", res);
1753 if (option_verbose > 2)
1754 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1758 } else if (qe->parent->eventwhencalled) {
1761 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1762 "AgentCalled: %s\r\n"
1763 "ChannelCalling: %s\r\n"
1764 "CallerIDNum: %s\r\n"
1765 "CallerIDName: %s\r\n"
1770 tmp->interface, qe->chan->name,
1771 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1772 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1773 qe->chan->context, qe->chan->exten, qe->chan->priority,
1774 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1775 if (option_verbose > 2)
1776 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1782 /*! \brief find the entry with the best metric, or NULL */
1783 static struct callattempt *find_best(struct callattempt *outgoing)
1785 struct callattempt *best = NULL, *cur;
1787 for (cur = outgoing; cur; cur = cur->q_next) {
1788 if (cur->stillgoing && /* Not already done */
1789 !cur->chan && /* Isn't already going */
1790 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1798 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1803 struct callattempt *best = find_best(outgoing);
1805 ast_debug(1, "Nobody left to try ringing in queue\n");
1808 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1809 struct callattempt *cur;
1810 /* Ring everyone who shares this best metric (for ringall) */
1811 for (cur = outgoing; cur; cur = cur->q_next) {
1812 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1813 ast_debug(1, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1814 ring_entry(qe, cur, busies);
1818 /* Ring just the best channel */
1819 ast_debug(1, "Trying '%s' with metric %d\n", best->interface, best->metric);
1820 ring_entry(qe, best, busies);
1822 if (best->chan) /* break out with result = 1 */
1829 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1831 struct callattempt *best = find_best(outgoing);
1834 /* Ring just the best channel */
1835 ast_debug(1, "Next is '%s' with metric %d\n", best->interface, best->metric);
1836 qe->parent->rrpos = best->metric % 1000;
1838 /* Just increment rrpos */
1839 if (qe->parent->wrapped) {
1840 /* No more channels, start over */
1841 qe->parent->rrpos = 0;
1843 /* Prioritize next entry */
1844 qe->parent->rrpos++;
1847 qe->parent->wrapped = 0;
1852 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1856 ast_stopstream(chan);
1857 res = ast_streamfile(chan, filename, chan->language);
1860 /* Wait for a keypress */
1861 res = ast_waitstream(chan, AST_DIGIT_ANY);
1862 if (res < 0 || !valid_exit(qe, res))
1866 ast_stopstream(chan);
1872 static int say_periodic_announcement(struct queue_ent *qe)
1877 /* Get the current time */
1880 /* Check to see if it is time to announce */
1881 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1884 /* Stop the music on hold so we can play our own file */
1885 ast_moh_stop(qe->chan);
1887 if (option_verbose > 2)
1888 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1890 /* Check to make sure we have a sound file. If not, reset to the first sound file */
1891 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
1892 qe->last_periodic_announce_sound = 0;
1895 /* play the announcement */
1896 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
1898 /* Resume Music on Hold if the caller is going to stay in the queue */
1900 ast_moh_start(qe->chan, qe->moh, NULL);
1902 /* update last_periodic_announce_time */
1903 qe->last_periodic_announce_time = now;
1905 /* Update the current periodic announcement to the next announcement */
1906 qe->last_periodic_announce_sound++;
1911 static void record_abandoned(struct queue_ent *qe)
1913 ast_mutex_lock(&qe->parent->lock);
1914 set_queue_variables(qe);
1915 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
1919 "OriginalPosition: %d\r\n"
1921 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
1923 qe->parent->callsabandoned++;
1924 ast_mutex_unlock(&qe->parent->lock);
1927 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
1928 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
1930 if (option_verbose > 2)
1931 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
1932 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
1933 if (qe->parent->autopause) {
1934 if (!set_member_paused(qe->parent->name, interface, 1)) {
1935 if (option_verbose > 2)
1936 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
1938 if (option_verbose > 2)
1939 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
1945 #define AST_MAX_WATCHERS 256
1947 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
1949 char *queue = qe->parent->name;
1950 struct callattempt *o;
1952 int sentringing = 0;
1953 int numbusies = prebusies;
1957 struct ast_frame *f;
1958 struct callattempt *peer = NULL;
1959 struct ast_channel *winner;
1960 struct ast_channel *in = qe->chan;
1962 char membername[80] = "";
1966 starttime = (long) time(NULL);
1968 while (*to && !peer) {
1969 int numlines, retry, pos = 1;
1970 struct ast_channel *watchers[AST_MAX_WATCHERS];
1973 for (retry = 0; retry < 2; retry++) {
1975 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
1976 if (o->stillgoing) { /* Keep track of important channels */
1979 watchers[pos++] = o->chan;
1983 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
1984 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
1986 /* On "ringall" strategy we only move to the next penalty level
1987 when *all* ringing phones are done in the current penalty level */
1988 ring_one(qe, outgoing, &numbusies);
1991 if (pos == 1 /* not found */) {
1992 if (numlines == (numbusies + numnochan)) {
1993 ast_debug(1, "Everyone is busy at this time\n");
1995 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
2000 winner = ast_waitfor_n(watchers, pos, to);
2001 for (o = outgoing; o; o = o->q_next) {
2002 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
2004 if (option_verbose > 2)
2005 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2008 } else if (o->chan && (o->chan == winner)) {
2010 ast_copy_string(on, o->member->interface, sizeof(on));
2011 ast_copy_string(membername, o->member->membername, sizeof(membername));
2013 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
2014 if (option_verbose > 2)
2015 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
2020 } else if (!ast_strlen_zero(o->chan->call_forward)) {
2025 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
2026 if ((stuff = strchr(tmpchan, '/'))) {
2030 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
2034 /* Before processing channel, go ahead and check for forwarding */
2035 if (option_verbose > 2)
2036 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
2037 /* Setup parameters */
2038 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
2039 if (status != o->oldstatus)
2040 update_dial_status(qe->parent, o->member, status);
2042 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
2046 ast_channel_inherit_variables(in, o->chan);
2047 if (o->chan->cid.cid_num)
2048 ast_free(o->chan->cid.cid_num);
2049 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
2051 if (o->chan->cid.cid_name)
2052 ast_free(o->chan->cid.cid_name);
2053 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
2055 ast_string_field_set(o->chan, accountcode, in->accountcode);
2056 o->chan->cdrflags = in->cdrflags;
2058 if (in->cid.cid_ani) {
2059 if (o->chan->cid.cid_ani)
2060 ast_free(o->chan->cid.cid_ani);
2061 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2063 if (o->chan->cid.cid_rdnis)
2064 ast_free(o->chan->cid.cid_rdnis);
2065 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2066 if (ast_call(o->chan, tmpchan, 0)) {
2067 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2072 /* Hangup the original channel now, in case we needed it */
2076 f = ast_read(winner);
2078 if (f->frametype == AST_FRAME_CONTROL) {
2079 switch (f->subclass) {
2080 case AST_CONTROL_ANSWER:
2081 /* This is our guy if someone answered. */
2083 if (option_verbose > 2)
2084 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2088 case AST_CONTROL_BUSY:
2089 if (option_verbose > 2)
2090 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
2092 ast_cdr_busy(in->cdr);
2094 endtime = (long) time(NULL);
2095 endtime -= starttime;
2096 rna(endtime*1000, qe, on, membername);
2097 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2098 if (qe->parent->timeoutrestart)
2100 ring_one(qe, outgoing, &numbusies);
2104 case AST_CONTROL_CONGESTION:
2105 if (option_verbose > 2)
2106 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
2108 ast_cdr_busy(in->cdr);
2109 endtime = (long) time(NULL);
2110 endtime -= starttime;
2111 rna(endtime*1000, qe, on, membername);
2113 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2114 if (qe->parent->timeoutrestart)
2116 ring_one(qe, outgoing, &numbusies);
2120 case AST_CONTROL_RINGING:
2121 if (option_verbose > 2)
2122 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
2125 ast_indicate(in, AST_CONTROL_RINGING);
2130 case AST_CONTROL_OFFHOOK:
2131 /* Ignore going off hook */
2134 ast_debug(1, "Dunno what to do with control type %d\n", f->subclass);
2139 endtime = (long) time(NULL) - starttime;
2140 rna(endtime * 1000, qe, on, membername);
2142 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2143 if (qe->parent->timeoutrestart)
2145 ring_one(qe, outgoing, &numbusies);
2152 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2159 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2160 if (option_verbose > 3)
2161 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
2166 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
2167 if (option_verbose > 3)
2168 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
2170 *digit = f->subclass;
2177 rna(orig, qe, on, membername);
2183 static int is_our_turn(struct queue_ent *qe)
2185 struct queue_ent *ch;
2191 if (!qe->parent->autofill) {
2192 /* Atomically read the parent head -- does not need a lock */
2193 ch = qe->parent->head;
2194 /* If we are now at the top of the head, break out */
2196 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2199 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2204 /* This needs a lock. How many members are available to be served? */
2205 ast_mutex_lock(&qe->parent->lock);
2207 ch = qe->parent->head;
2209 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2210 ast_debug(1, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in\n", avl);
2213 for (cur = qe->parent->members; cur; cur = cur->next) {
2214 switch (cur->status) {
2215 case AST_DEVICE_NOT_INUSE:
2216 case AST_DEVICE_UNKNOWN:
2223 ast_debug(1, "There are %d available members.\n", avl);
2225 while ((idx < avl) && (ch) && (ch != qe)) {
2230 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2231 if (ch && idx < avl) {
2232 ast_debug(1, "It's our turn (%s).\n", qe->chan->name);
2235 ast_debug(1, "It's not our turn (%s).\n", qe->chan->name);
2239 ast_mutex_unlock(&qe->parent->lock);
2245 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2249 /* This is the holding pen for callers 2 through maxlen */
2251 enum queue_member_status stat;
2253 if (is_our_turn(qe))
2256 /* If we have timed out, break out */
2257 if (qe->expire && (time(NULL) > qe->expire)) {
2258 *reason = QUEUE_TIMEOUT;
2262 stat = get_member_status(qe->parent, qe->max_penalty);
2264 /* leave the queue if no agents, if enabled */
2265 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2266 *reason = QUEUE_LEAVEEMPTY;
2267 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2272 /* leave the queue if no reachable agents, if enabled */
2273 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2274 *reason = QUEUE_LEAVEUNAVAIL;
2275 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2279 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2280 *reason = QUEUE_LEAVEUNAVAIL;
2281 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2286 /* Make a position announcement, if enabled */
2287 if (qe->parent->announcefrequency && !ringing &&
2288 (res = say_position(qe)))
2291 /* Make a periodic announcement, if enabled */
2292 if (qe->parent->periodicannouncefrequency && !ringing &&
2293 (res = say_periodic_announcement(qe)))
2296 /* Wait a second before checking again */
2297 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000)))
2304 static int update_queue(struct call_queue *q, struct member *member)
2308 /* Since a reload could have taken place, we have to traverse the list to
2309 be sure it's still valid */
2310 ast_mutex_lock(&q->lock);
2313 if (member == cur) {
2314 time(&cur->lastcall);
2320 q->callscompleted++;
2321 ast_mutex_unlock(&q->lock);
2325 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2327 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2330 switch (q->strategy) {
2331 case QUEUE_STRATEGY_RINGALL:
2332 /* Everyone equal, except for penalty */
2333 tmp->metric = mem->penalty * 1000000;
2335 case QUEUE_STRATEGY_RRMEMORY:
2336 if (pos < q->rrpos) {
2337 tmp->metric = 1000 + pos;
2340 /* Indicate there is another priority */
2344 tmp->metric += mem->penalty * 1000000;
2346 case QUEUE_STRATEGY_RANDOM:
2347 tmp->metric = ast_random() % 1000;
2348 tmp->metric += mem->penalty * 1000000;
2350 case QUEUE_STRATEGY_FEWESTCALLS:
2351 tmp->metric = mem->calls;
2352 tmp->metric += mem->penalty * 1000000;
2354 case QUEUE_STRATEGY_LEASTRECENT:
2358 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2359 tmp->metric += mem->penalty * 1000000;
2362 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2368 enum agent_complete_reason {
2374 static void send_agent_complete(const struct queue_ent *qe, const char *queuename,
2375 const struct ast_channel *peer, const struct member *member, time_t callstart,
2376 char *vars, size_t vars_len, enum agent_complete_reason rsn)
2380 if (!qe->parent->eventwhencalled)
2391 reason = "transfer";
2395 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2400 "MemberName: %s\r\n"
2405 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2406 (long)(callstart - qe->start), (long)(time(NULL) - callstart), reason,
2407 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, vars_len) : "");
2410 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on, const char *agi, const char *macro, const char *gosub)
2413 struct callattempt *outgoing = NULL; /* the list of calls we are building */
2415 char oldexten[AST_MAX_EXTENSION]="";
2416 char oldcontext[AST_MAX_CONTEXT]="";
2417 char queuename[256]="";
2418 char interfacevar[256]="";
2419 struct ast_channel *peer;
2420 struct ast_channel *which;
2421 struct callattempt *lpeer;
2422 struct member *member;
2423 struct ast_app *app;
2424 int res = 0, bridge = 0;
2427 char *announce = NULL;
2430 time_t now = time(NULL);
2431 struct ast_bridge_config bridge_config;
2432 char nondataquality = 1;
2433 char *agiexec = NULL;
2434 char *macroexec = NULL;
2435 char *gosubexec = NULL;
2437 const char *monitorfilename;
2438 const char *monitor_exec;
2439 const char *monitor_options;
2440 char tmpid[256], tmpid2[256];
2441 char meid[1024], meid2[1024];
2442 char mixmonargs[1512];
2443 struct ast_app *mixmonapp = NULL;
2446 int forwardsallowed = 1;
2447 memset(&bridge_config, 0, sizeof(bridge_config));
2450 for (; options && *options; options++)
2453 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2456 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2459 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2462 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2468 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2471 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2474 if ((now - qe->start >= qe->parent->timeout))
2478 forwardsallowed = 0;
2482 /* Hold the lock while we setup the outgoing calls */
2484 AST_LIST_LOCK(&queues);
2485 ast_mutex_lock(&qe->parent->lock);
2486 ast_debug(1, "%s is trying to call a queue member.\n",
2488 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2489 cur = qe->parent->members;
2490 if (!ast_strlen_zero(qe->announce))
2491 announce = qe->announce;
2492 if (!ast_strlen_zero(announceoverride))
2493 announce = announceoverride;
2495 for (; cur; cur = cur->next) {
2496 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2499 ast_mutex_unlock(&qe->parent->lock);
2501 AST_LIST_UNLOCK(&queues);
2504 tmp->stillgoing = -1;
2505 tmp->member = cur; /* Never directly dereference! Could change on reload */
2506 tmp->oldstatus = cur->status;
2507 tmp->lastcall = cur->lastcall;
2508 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2509 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2510 just calculate their metric for the appropriate strategy */
2511 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2512 /* Put them in the list of outgoing thingies... We're ready now.
2513 XXX If we're forcibly removed, these outgoing calls won't get
2515 tmp->q_next = outgoing;
2517 /* If this line is up, don't try anybody else */
2518 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2524 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2525 to = (qe->expire - now) * 1000;
2527 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2528 ring_one(qe, outgoing, &numbusies);
2529 ast_mutex_unlock(&qe->parent->lock);
2531 AST_LIST_UNLOCK(&queues);
2532 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2533 ast_mutex_lock(&qe->parent->lock);
2534 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2535 store_next(qe, outgoing);
2537 ast_mutex_unlock(&qe->parent->lock);
2538 peer = lpeer ? lpeer->chan : NULL;
2541 /* Must gotten hung up */
2546 ast_debug(1, "%s: Nobody answered.\n", qe->chan->name);
2547 } else { /* peer is valid */
2548 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2549 we will always return with -1 so that it is hung up properly after the
2552 if (!strcmp(qe->chan->tech->type, "Zap"))
2553 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2554 if (!strcmp(peer->tech->type, "Zap"))
2555 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2556 /* Update parameters for the queue */
2557 recalc_holdtime(qe);
2558 member = lpeer->member;
2559 hangupcalls(outgoing, peer);
2561 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2564 res2 = ast_autoservice_start(qe->chan);
2566 if (qe->parent->memberdelay) {
2567 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2568 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2570 if (!res2 && announce) {
2571 if (play_file(peer, announce))
2572 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2574 if (!res2 && qe->parent->reportholdtime) {
2575 if (!play_file(peer, qe->parent->sound_reporthold)) {
2579 holdtime = abs((now - qe->start) / 60);
2581 play_file(peer, qe->parent->sound_lessthan);
2582 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2584 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2585 play_file(peer, qe->parent->sound_minutes);
2589 res2 |= ast_autoservice_stop(qe->chan);
2590 if (peer->_softhangup) {
2591 /* Agent must have hung up */
2592 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
2593 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2594 record_abandoned(qe);
2595 if (qe->parent->eventwhencalled)
2596 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2601 "MemberName: %s\r\n"
2603 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2604 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2608 /* Caller must have hung up just before being connected*/
2609 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2610 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long) time(NULL) - qe->start);
2611 record_abandoned(qe);
2616 /* Stop music on hold */
2617 ast_moh_stop(qe->chan);
2618 /* If appropriate, log that we have a destination channel */
2620 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2621 /* Make sure channels are compatible */
2622 res = ast_channel_make_compatible(qe->chan, peer);
2624 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2625 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2626 record_abandoned(qe);
2630 /* Begin Monitoring */
2631 if (qe->parent->monfmt && *qe->parent->monfmt) {
2632 if (!qe->parent->montype) {
2633 ast_debug(1, "Starting Monitor as requested.\n");
2634 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2635 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2639 if (monitorfilename)
2640 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2641 else if (qe->chan->cdr)
2642 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2644 /* Last ditch effort -- no CDR, make up something */
2645 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2646 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2648 if (qe->parent->monjoin)
2649 ast_monitor_setjoinfiles(which, 1);
2651 ast_debug(1, "Starting MixMonitor as requested.\n");
2652 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2653 if (!monitorfilename) {
2655 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
2657 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2659 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
2660 for (p = tmpid2; *p ; p++) {
2661 if (*p == '^' && *(p+1) == '{') {
2666 memset(tmpid, 0, sizeof(tmpid));
2667 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2670 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2671 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2674 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
2675 for (p = meid2; *p ; p++) {
2676 if (*p == '^' && *(p+1) == '{') {
2681 memset(meid, 0, sizeof(meid));
2682 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2685 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
2687 mixmonapp = pbx_findapp("MixMonitor");
2689 if (strchr(tmpid2, '|')) {
2690 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
2694 if (!monitor_options)
2695 monitor_options = "";
2697 if (strchr(monitor_options, '|')) {
2698 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
2703 if (!ast_strlen_zero(monitor_exec))
2704 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
2706 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
2708 ast_debug(1, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2710 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2713 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2717 /* Drop out of the queue at this point, to prepare for next caller */
2719 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2720 ast_debug(1, "app_queue: sendurl=%s.\n", url);
2721 ast_channel_sendurl(peer, url);
2724 ast_mutex_lock(&qe->parent->lock);
2725 /* if setinterfacevar is defined, make member variables available to the channel */
2726 /* use pbx_builtin_setvar to set a load of variables with one call */
2727 if (qe->parent->setinterfacevar) {
2728 snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d",
2729 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic);
2730 pbx_builtin_setvar(qe->chan, interfacevar);
2733 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
2734 /* use pbx_builtin_setvar to set a load of variables with one call */
2735 if (qe->parent->setqueueentryvar) {
2736 snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
2737 (long) time(NULL) - qe->start, qe->opos);
2738 pbx_builtin_setvar(qe->chan, interfacevar);
2741 /* try to set queue variables if configured to do so*/
2742 set_queue_variables(qe);
2743 ast_mutex_unlock(&qe->parent->lock);
2745 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
2746 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
2747 if (!ast_strlen_zero(macro)) {
2748 macroexec = ast_strdupa(macro);
2750 if (qe->parent->membermacro)
2751 macroexec = ast_strdupa(qe->parent->membermacro);
2754 if (!ast_strlen_zero(macroexec)) {
2755 ast_debug(1, "app_queue: macro=%s.\n", macroexec);
2757 res = ast_autoservice_start(qe->chan);
2759 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
2763 app = pbx_findapp("Macro");
2766 res = pbx_exec(qe->chan, app, macroexec);
2767 ast_debug(1, "Macro exited with status %d\n", res);
2770 ast_log(LOG_ERROR, "Could not find application Macro\n");
2774 if (ast_autoservice_stop(qe->chan) < 0) {
2775 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
2780 /* run a gosub for this connection if defined. The gosub simply returns, no action is taken on the result */
2781 /* use gosub from dialplan if passed as a option, otherwise use the default queue gosub */
2782 if (!ast_strlen_zero(gosub)) {
2783 gosubexec = ast_strdupa(gosub);
2785 if (qe->parent->membergosub)
2786 gosubexec = ast_strdupa(qe->parent->membergosub);
2789 if (!ast_strlen_zero(gosubexec)) {
2791 ast_log(LOG_DEBUG, "app_queue: gosub=%s.\n", gosubexec);
2793 res = ast_autoservice_start(qe->chan);
2795 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
2799 app = pbx_findapp("Gosub");
2802 char *gosub_args, *gosub_argstart;
2804 /* Set where we came from */
2805 ast_copy_string(qe->chan->context, "app_dial_gosub_virtual_context", sizeof(qe->chan->context));
2806 ast_copy_string(qe->chan->exten, "s", sizeof(qe->chan->exten));
2807 qe->chan->priority = 0;
2809 gosub_argstart = strchr(gosubexec, '|');
2810 if (gosub_argstart) {
2811 *gosub_argstart = 0;
2812 asprintf(&gosub_args, "%s|s|1(%s)", gosubexec, gosub_argstart + 1);
2813 *gosub_argstart = '|';
2815 asprintf(&gosub_args, "%s|s|1", gosubexec);
2818 res = pbx_exec(qe->chan, app, gosub_args);
2819 ast_pbx_run(qe->chan);
2822 ast_log(LOG_DEBUG, "Gosub exited with status %d\n", res);
2824 ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
2828 ast_log(LOG_ERROR, "Could not find application Gosub\n");
2832 if (ast_autoservice_stop(qe->chan) < 0) {
2833 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
2838 if (!ast_strlen_zero(agi)) {
2839 ast_debug(1, "app_queue: agi=%s.\n", agi);
2840 app = pbx_findapp("agi");
2842 agiexec = ast_strdupa(agi);
2843 ret = pbx_exec(qe->chan, app, agiexec);
2845 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
2847 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long) time(NULL) - qe->start, peer->uniqueid);
2848 if (qe->parent->eventwhencalled)
2849 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2854 "MemberName: %s\r\n"
2856 "BridgedChannel: %s\r\n"
2858 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2859 (long) time(NULL) - qe->start, peer->uniqueid,
2860 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2861 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2862 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2865 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2867 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2868 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
2869 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
2870 (long) (time(NULL) - callstart));
2871 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), TRANSFER);
2872 } else if (qe->chan->_softhangup) {
2873 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
2874 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
2875 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), CALLER);
2877 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
2878 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
2879 send_agent_complete(qe, queuename, peer, member, callstart, vars, sizeof(vars), AGENT);
2882 if (bridge != AST_PBX_NO_HANGUP_PEER)
2884 update_queue(qe->parent, member);
2885 res = bridge ? bridge : 1;
2888 hangupcalls(outgoing, NULL);
2893 static int wait_a_bit(struct queue_ent *qe)
2895 /* Don't need to hold the lock while we setup the outgoing calls */
2896 int retrywait = qe->parent->retry * 1000;
2898 return ast_waitfordigit(qe->chan, retrywait);
2901 static struct member *interface_exists(struct call_queue *q, const char *interface)