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
66 #include <sys/signal.h>
67 #include <netinet/in.h>
71 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
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"
96 #define QUEUE_STRATEGY_RINGALL 0
97 #define QUEUE_STRATEGY_ROUNDROBIN 1
98 #define QUEUE_STRATEGY_LEASTRECENT 2
99 #define QUEUE_STRATEGY_FEWESTCALLS 3
100 #define QUEUE_STRATEGY_RANDOM 4
101 #define QUEUE_STRATEGY_RRMEMORY 5
103 static struct strategy {
107 { QUEUE_STRATEGY_RINGALL, "ringall" },
108 { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
109 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
110 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
111 { QUEUE_STRATEGY_RANDOM, "random" },
112 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
115 #define DEFAULT_RETRY 5
116 #define DEFAULT_TIMEOUT 15
117 #define RECHECK 1 /* Recheck every second to see we we're at the top yet */
118 #define MAX_PERIODIC_ANNOUNCEMENTS 10 /* The maximum periodic announcements we can have */
120 #define RES_OKAY 0 /* Action completed */
121 #define RES_EXISTS (-1) /* Entry already exists */
122 #define RES_OUTOFMEMORY (-2) /* Out of memory */
123 #define RES_NOSUCHQUEUE (-3) /* No such queue */
125 static char *tdesc = "True Call Queueing";
127 static char *app = "Queue";
129 static char *synopsis = "Queue a call for a call queue";
131 static char *descrip =
132 " Queue(queuename[|options[|URL][|announceoverride][|timeout][|AGI]):\n"
133 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
134 "This application will return to the dialplan if the queue does not exist, or\n"
135 "any of the join options cause the caller to not enter the queue.\n"
136 "The option string may contain zero or more of the following characters:\n"
137 " 'd' -- data-quality (modem) call (minimum delay).\n"
138 " 'h' -- allow callee to hang up by hitting *.\n"
139 " 'H' -- allow caller to hang up by hitting *.\n"
140 " 'n' -- no retries on the timeout; will exit this application and \n"
141 " go to the next step.\n"
142 " 'r' -- ring instead of playing MOH\n"
143 " 't' -- allow the called user transfer the calling user\n"
144 " 'T' -- to allow the calling user to transfer the call.\n"
145 " 'w' -- allow the called user to write the conversation to disk via Monitor\n"
146 " 'W' -- allow the calling user to write the conversation to disk via Monitor\n"
147 " In addition to transferring the call, a call may be parked and then picked\n"
148 "up by another user.\n"
149 " The optional URL will be sent to the called party if the channel supports\n"
151 " The optional AGI parameter will setup an AGI script to be executed on the \n"
152 "calling party's channel once they are connected to a queue member.\n"
153 " The timeout will cause the queue to fail out after a specified number of\n"
154 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
155 " This application sets the following channel variable upon completion:\n"
156 " QUEUESTATUS The status of the call as a text string, one of\n"
157 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
159 static char *app_aqm = "AddQueueMember" ;
160 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
161 static char *app_aqm_descrip =
162 " AddQueueMember(queuename[|interface[|penalty[|options]]]):\n"
163 "Dynamically adds interface to an existing queue.\n"
164 "If the interface is already in the queue and there exists an n+101 priority\n"
165 "then it will then jump to this priority. Otherwise it will return an error\n"
166 "The option string may contain zero or more of the following characters:\n"
167 " 'j' -- jump to +101 priority when appropriate.\n"
168 " This application sets the following channel variable upon completion:\n"
169 " AQMSTATUS The status of the attempt to add a queue member as a \n"
170 " text string, one of\n"
171 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
172 "Example: AddQueueMember(techsupport|SIP/3000)\n"
175 static char *app_rqm = "RemoveQueueMember" ;
176 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
177 static char *app_rqm_descrip =
178 " RemoveQueueMember(queuename[|interface[|options]]):\n"
179 "Dynamically removes interface to an existing queue\n"
180 "If the interface is NOT in the queue and there exists an n+101 priority\n"
181 "then it will then jump to this priority. Otherwise it will return an error\n"
182 "The option string may contain zero or more of the following characters:\n"
183 " 'j' -- jump to +101 priority when appropriate.\n"
184 " This application sets the following channel variable upon completion:\n"
185 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
186 " text string, one of\n"
187 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
188 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
191 static char *app_pqm = "PauseQueueMember" ;
192 static char *app_pqm_synopsis = "Pauses a queue member" ;
193 static char *app_pqm_descrip =
194 " PauseQueueMember([queuename]|interface[|options]):\n"
195 "Pauses (blocks calls for) a queue member.\n"
196 "The given interface will be paused in the given queue. This prevents\n"
197 "any calls from being sent from the queue to the interface until it is\n"
198 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
199 "queuename is given, the interface is paused in every queue it is a\n"
200 "member of. If the interface is not in the named queue, or if no queue\n"
201 "is given and the interface is not in any queue, it will jump to\n"
202 "priority n+101, if it exists and the appropriate options are set.\n"
203 "The application will fail if the interface is not found and no extension\n"
204 "to jump to exists.\n"
205 "The option string may contain zero or more of the following characters:\n"
206 " 'j' -- jump to +101 priority when appropriate.\n"
207 " This application sets the following channel variable upon completion:\n"
208 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
209 " text string, one of\n"
210 " PAUSED | NOTFOUND\n"
211 "Example: PauseQueueMember(|SIP/3000)\n";
213 static char *app_upqm = "UnpauseQueueMember" ;
214 static char *app_upqm_synopsis = "Unpauses a queue member" ;
215 static char *app_upqm_descrip =
216 " UnpauseQueueMember([queuename]|interface[|options]):\n"
217 "Unpauses (resumes calls to) a queue member.\n"
218 "This is the counterpart to PauseQueueMember and operates exactly the\n"
219 "same way, except it unpauses instead of pausing the given interface.\n"
220 "The option string may contain zero or more of the following characters:\n"
221 " 'j' -- jump to +101 priority when appropriate.\n"
222 " This application sets the following channel variable upon completion:\n"
223 " UPQMSTATUS The status of the attempt to unpause a queue \n"
224 " member as a text string, one of\n"
225 " UNPAUSED | NOTFOUND\n"
226 "Example: UnpauseQueueMember(|SIP/3000)\n";
228 /*! \brief Persistent Members astdb family */
229 static const char *pm_family = "/Queue/PersistentMembers";
230 /* The maximum length of each persistent member queue database entry */
231 #define PM_MAX_LEN 2048
233 /*! \brief queues.conf [general] option */
234 static int queue_persistent_members = 0;
236 /*! \brief queues.conf per-queue weight option */
237 static int use_weight = 0;
239 /*! \brief queues.conf [general] option */
240 static int autofill_default = 0;
242 /*! \brief queues.conf [general] option */
243 static int montype_default = 0;
249 QUEUE_LEAVEEMPTY = 3,
250 QUEUE_JOINUNAVAIL = 4,
251 QUEUE_LEAVEUNAVAIL = 5,
256 enum queue_result id;
258 } queue_results[] = {
259 { QUEUE_UNKNOWN, "UNKNOWN" },
260 { QUEUE_TIMEOUT, "TIMEOUT" },
261 { QUEUE_JOINEMPTY,"JOINEMPTY" },
262 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
263 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
264 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
265 { QUEUE_FULL, "FULL" },
268 /*! \brief We define a custom "local user" structure because we
269 use it not only for keeping track of what is in use but
270 also for keeping track of who we're dialing. */
273 struct callattempt *q_next;
274 struct ast_channel *chan;
280 struct member *member;
286 struct ast_call_queue *parent; /*!< What queue is our parent */
287 char moh[80]; /*!< Name of musiconhold to be used */
288 char announce[80]; /*!< Announcement to play for member when call is answered */
289 char context[AST_MAX_CONTEXT]; /*!< Context when user exits queue */
290 char digits[AST_MAX_EXTENSION]; /*!< Digits entered while in queue */
291 int pos; /*!< Where we are in the queue */
292 int prio; /*!< Our priority */
293 int last_pos_said; /*!< Last position we told the user */
294 time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
295 int last_periodic_announce_sound; /* The last periodic announcement we made */
296 time_t last_pos; /*!< Last time we told the user their position */
297 int opos; /*!< Where we started in the queue */
298 int handled; /*!< Whether our call was handled */
299 int max_penalty; /*!< Limit the members that can take this call to this penalty or lower */
300 time_t start; /*!< When we started holding */
301 time_t expire; /*!< When this entry should expire (time out of queue) */
302 struct ast_channel *chan; /*!< Our channel */
303 struct queue_ent *next; /*!< The next queue entry */
307 char interface[80]; /*!< Technology/Location */
308 int penalty; /*!< Are we a last resort? */
309 int calls; /*!< Number of calls serviced by this member */
310 int dynamic; /*!< Are we dynamically added? */
311 int status; /*!< Status of queue member */
312 int paused; /*!< Are we paused (not accepting calls)? */
313 time_t lastcall; /*!< When last successful call was hungup */
314 unsigned int dead:1; /*!< Used to detect members deleted in realtime */
315 unsigned int delme:1; /*!< Flag to delete entry on reload */
316 struct member *next; /*!< Next member */
319 /* values used in multi-bit flags in ast_call_queue */
320 #define QUEUE_EMPTY_NORMAL 1
321 #define QUEUE_EMPTY_STRICT 2
322 #define ANNOUNCEHOLDTIME_ALWAYS 1
323 #define ANNOUNCEHOLDTIME_ONCE 2
325 struct ast_call_queue {
327 char name[80]; /*!< Name */
328 char moh[80]; /*!< Music On Hold class to be used */
329 char announce[80]; /*!< Announcement to play when call is answered */
330 char context[AST_MAX_CONTEXT]; /*!< Exit context */
331 unsigned int monjoin:1;
333 unsigned int joinempty:2;
334 unsigned int eventwhencalled:1;
335 unsigned int leavewhenempty:2;
336 unsigned int ringinuse:1;
337 unsigned int setinterfacevar:1;
338 unsigned int reportholdtime:1;
339 unsigned int wrapped:1;
340 unsigned int timeoutrestart:1;
341 unsigned int announceholdtime:2;
342 unsigned int strategy:3;
343 unsigned int maskmemberstatus:1;
344 unsigned int realtime:1;
345 int announcefrequency; /*!< How often to announce their position */
346 int periodicannouncefrequency; /*!< How often to play periodic announcement */
347 int roundingseconds; /*!< How many seconds do we round to? */
348 int holdtime; /*!< Current avg holdtime, based on recursive boxcar filter */
349 int callscompleted; /*!< Number of queue calls completed */
350 int callsabandoned; /*!< Number of queue calls abandoned */
351 int servicelevel; /*!< seconds setting for servicelevel*/
352 int callscompletedinsl; /*!< Number of calls answered with servicelevel*/
353 char monfmt[8]; /*!< Format to use when recording calls */
354 int montype; /*!< Monitor type Monitor vs. MixMonitor */
355 char sound_next[80]; /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
356 char sound_thereare[80]; /*!< Sound file: "There are currently" (def. queue-thereare) */
357 char sound_calls[80]; /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
358 char sound_holdtime[80]; /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
359 char sound_minutes[80]; /*!< Sound file: "minutes." (def. queue-minutes) */
360 char sound_lessthan[80]; /*!< Sound file: "less-than" (def. queue-lessthan) */
361 char sound_seconds[80]; /*!< Sound file: "seconds." (def. queue-seconds) */
362 char sound_thanks[80]; /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
363 char sound_reporthold[80]; /*!< Sound file: "Hold time" (def. queue-reporthold) */
364 char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/* Sound files: Custom announce, no default */
366 int count; /*!< How many entries */
367 int maxlen; /*!< Max number of entries */
368 int wrapuptime; /*!< Wrapup Time */
370 int retry; /*!< Retry calling everyone after this amount of time */
371 int timeout; /*!< How long to wait for an answer */
372 int weight; /*!< Respective weight */
373 int autopause; /*!< Auto pause queue members if they fail to answer */
375 /* Queue strategy things */
376 int rrpos; /*!< Round Robin - position */
377 int memberdelay; /*!< Seconds to delay connecting member to caller */
378 int autofill; /*!< Ignore the head call status and ring an available agent */
380 struct member *members; /*!< Head of the list of members */
381 struct queue_ent *head; /*!< Head of the list of callers */
382 AST_LIST_ENTRY(ast_call_queue) list; /*!< Next call queue */
385 static AST_LIST_HEAD_STATIC(queues, ast_call_queue);
387 static int set_member_paused(char *queuename, char *interface, int paused);
389 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
393 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
394 if (queue_results[i].id == res) {
395 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
401 static char *int2strat(int strategy)
404 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
405 if (strategy == strategies[x].strategy)
406 return strategies[x].name;
411 static int strat2int(const char *strategy)
414 for (x=0;x<sizeof(strategies) / sizeof(strategies[0]);x++) {
415 if (!strcasecmp(strategy, strategies[x].name))
416 return strategies[x].strategy;
421 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
422 static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
424 struct queue_ent *cur;
441 enum queue_member_status {
443 QUEUE_NO_REACHABLE_MEMBERS,
447 static enum queue_member_status get_member_status(const struct ast_call_queue *q, int max_penalty)
449 struct member *member;
450 enum queue_member_status result = QUEUE_NO_MEMBERS;
452 for (member = q->members; member; member = member->next) {
453 if (max_penalty && (member->penalty > max_penalty))
456 switch (member->status) {
457 case AST_DEVICE_INVALID:
460 case AST_DEVICE_UNAVAILABLE:
461 result = QUEUE_NO_REACHABLE_MEMBERS;
476 static void *changethread(void *data)
478 struct ast_call_queue *q;
479 struct statechange *sc = data;
484 technology = ast_strdupa(sc->dev);
485 loc = strchr(technology, '/');
494 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
495 AST_LIST_LOCK(&queues);
496 AST_LIST_TRAVERSE(&queues, q, list) {
497 ast_mutex_lock(&q->lock);
500 if (!strcasecmp(sc->dev, cur->interface)) {
501 if (cur->status != sc->state) {
502 cur->status = sc->state;
503 if (!q->maskmemberstatus) {
504 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
513 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
514 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
520 ast_mutex_unlock(&q->lock);
522 AST_LIST_UNLOCK(&queues);
527 static int statechange_queue(const char *dev, int state, void *ign)
529 /* Avoid potential for deadlocks by spawning a new thread to handle
531 struct statechange *sc;
535 if ((sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1))) {
537 strcpy(sc->dev, dev);
538 pthread_attr_init(&attr);
539 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
540 if (ast_pthread_create(&t, &attr, changethread, sc)) {
541 ast_log(LOG_WARNING, "Failed to create update thread!\n");
548 static struct member *create_queue_member(char *interface, int penalty, int paused)
552 /* Add a new member */
554 if ((cur = ast_calloc(1, sizeof(*cur)))) {
555 cur->penalty = penalty;
556 cur->paused = paused;
557 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
558 if (!strchr(cur->interface, '/'))
559 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
560 cur->status = ast_device_state(interface);
566 static struct ast_call_queue *alloc_queue(const char *queuename)
568 struct ast_call_queue *q;
570 if ((q = ast_calloc(1, sizeof(*q)))) {
571 ast_mutex_init(&q->lock);
572 ast_copy_string(q->name, queuename, sizeof(q->name));
577 static void init_queue(struct ast_call_queue *q)
581 q->retry = DEFAULT_RETRY;
584 q->announcefrequency = 0;
585 q->announceholdtime = 0;
586 q->roundingseconds = 0; /* Default - don't announce seconds */
589 q->setinterfacevar = 0;
590 q->autofill = autofill_default;
591 q->montype = montype_default;
593 q->announce[0] = '\0';
594 q->context[0] = '\0';
596 q->periodicannouncefrequency = 0;
597 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
598 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
599 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
600 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
601 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
602 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
603 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
604 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
605 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
606 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
607 for (i=1;i<MAX_PERIODIC_ANNOUNCEMENTS;i++) {
608 q->sound_periodicannounce[i][0]='\0';
612 static void clear_queue(struct ast_call_queue *q)
615 q->callscompleted = 0;
616 q->callsabandoned = 0;
617 q->callscompletedinsl = 0;
621 /*! \brief Configure a queue parameter.
623 For error reporting, line number is passed for .conf static configuration.
624 For Realtime queues, linenum is -1.
625 The failunknown flag is set for config files (and static realtime) to show
626 errors for unknown parameters. It is cleared for dynamic realtime to allow
627 extra fields in the tables. */
628 static void queue_set_param(struct ast_call_queue *q, const char *param, const char *val, int linenum, int failunknown)
633 if (!strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
634 ast_copy_string(q->moh, val, sizeof(q->moh));
635 } else if (!strcasecmp(param, "announce")) {
636 ast_copy_string(q->announce, val, sizeof(q->announce));
637 } else if (!strcasecmp(param, "context")) {
638 ast_copy_string(q->context, val, sizeof(q->context));
639 } else if (!strcasecmp(param, "timeout")) {
640 q->timeout = atoi(val);
642 q->timeout = DEFAULT_TIMEOUT;
643 } else if (!strcasecmp(param, "ringinuse")) {
644 q->ringinuse = ast_true(val);
645 } else if (!strcasecmp(param, "setinterfacevar")) {
646 q->setinterfacevar = ast_true(val);
647 } else if (!strcasecmp(param, "monitor-join")) {
648 q->monjoin = ast_true(val);
649 } else if (!strcasecmp(param, "monitor-format")) {
650 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
651 } else if (!strcasecmp(param, "queue-youarenext")) {
652 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
653 } else if (!strcasecmp(param, "queue-thereare")) {
654 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
655 } else if (!strcasecmp(param, "queue-callswaiting")) {
656 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
657 } else if (!strcasecmp(param, "queue-holdtime")) {
658 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
659 } else if (!strcasecmp(param, "queue-minutes")) {
660 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
661 } else if (!strcasecmp(param, "queue-seconds")) {
662 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
663 } else if (!strcasecmp(param, "queue-lessthan")) {
664 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
665 } else if (!strcasecmp(param, "queue-thankyou")) {
666 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
667 } else if (!strcasecmp(param, "queue-reporthold")) {
668 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
669 } else if (!strcasecmp(param, "announce-frequency")) {
670 q->announcefrequency = atoi(val);
671 } else if (!strcasecmp(param, "announce-round-seconds")) {
672 q->roundingseconds = atoi(val);
673 if (q->roundingseconds>60 || q->roundingseconds<0) {
675 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
676 "using 0 instead for queue '%s' at line %d of queues.conf\n",
677 val, param, q->name, linenum);
679 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
680 "using 0 instead for queue '%s'\n", val, param, q->name);
682 q->roundingseconds=0;
684 } else if (!strcasecmp(param, "announce-holdtime")) {
685 if (!strcasecmp(val, "once"))
686 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
687 else if (ast_true(val))
688 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
690 q->announceholdtime = 0;
691 } else if (!strcasecmp(param, "periodic-announce")) {
692 if (strchr(val,'|')) {
694 while ((c = strchr(lastc,'|'))) {
695 if (i > MAX_PERIODIC_ANNOUNCEMENTS)
697 strncpy(buff, lastc, abs(lastc - c));
698 buff[abs(lastc - c)] = '\0';
699 ast_copy_string(q->sound_periodicannounce[i], buff, sizeof(q->sound_periodicannounce[i]));
704 ast_copy_string(q->sound_periodicannounce[i], lastc, sizeof(q->sound_periodicannounce[i]));
707 ast_copy_string(q->sound_periodicannounce[i], val, sizeof(q->sound_periodicannounce[i]));
709 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
710 q->periodicannouncefrequency = atoi(val);
711 } else if (!strcasecmp(param, "retry")) {
712 q->retry = atoi(val);
714 q->retry = DEFAULT_RETRY;
715 } else if (!strcasecmp(param, "wrapuptime")) {
716 q->wrapuptime = atoi(val);
717 } else if (!strcasecmp(param, "autofill")) {
718 q->autofill = ast_true(val);
719 } else if (!strcasecmp(param, "monitor-type")) {
720 if (!strcasecmp(val, "mixmonitor"))
722 } else if (!strcasecmp(param, "autopause")) {
723 q->autopause = ast_true(val);
724 } else if (!strcasecmp(param, "maxlen")) {
725 q->maxlen = atoi(val);
728 } else if (!strcasecmp(param, "servicelevel")) {
729 q->servicelevel= atoi(val);
730 } else if (!strcasecmp(param, "strategy")) {
731 q->strategy = strat2int(val);
732 if (q->strategy < 0) {
733 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
737 } else if (!strcasecmp(param, "joinempty")) {
738 if (!strcasecmp(val, "strict"))
739 q->joinempty = QUEUE_EMPTY_STRICT;
740 else if (ast_true(val))
741 q->joinempty = QUEUE_EMPTY_NORMAL;
744 } else if (!strcasecmp(param, "leavewhenempty")) {
745 if (!strcasecmp(val, "strict"))
746 q->leavewhenempty = QUEUE_EMPTY_STRICT;
747 else if (ast_true(val))
748 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
750 q->leavewhenempty = 0;
751 } else if (!strcasecmp(param, "eventmemberstatus")) {
752 q->maskmemberstatus = !ast_true(val);
753 } else if (!strcasecmp(param, "eventwhencalled")) {
754 q->eventwhencalled = ast_true(val);
755 } else if (!strcasecmp(param, "reportholdtime")) {
756 q->reportholdtime = ast_true(val);
757 } else if (!strcasecmp(param, "memberdelay")) {
758 q->memberdelay = atoi(val);
759 } else if (!strcasecmp(param, "weight")) {
760 q->weight = atoi(val);
763 /* With Realtime queues, if the last queue using weights is deleted in realtime,
764 we will not see any effect on use_weight until next reload. */
765 } else if (!strcasecmp(param, "timeoutrestart")) {
766 q->timeoutrestart = ast_true(val);
767 } else if(failunknown) {
769 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
770 q->name, param, linenum);
772 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
777 static void rt_handle_member_record(struct ast_call_queue *q, char *interface, const char *penalty_str)
779 struct member *m, *prev_m;
783 penalty = atoi(penalty_str);
788 /* Find the member, or the place to put a new one. */
791 while (m && strcmp(m->interface, interface)) {
796 /* Create a new one if not found, else update penalty */
798 m = create_queue_member(interface, penalty, 0);
808 m->dead = 0; /* Do not delete this one. */
809 m->penalty = penalty;
813 static void free_members(struct ast_call_queue *q, int all)
815 /* Free non-dynamic members */
816 struct member *curm, *next, *prev = NULL;
818 for (curm = q->members; curm; curm = next) {
820 if (all || !curm->dynamic) {
831 static void destroy_queue(struct ast_call_queue *q)
834 ast_mutex_destroy(&q->lock);
838 /*!\brief Reload a single queue via realtime.
839 \return Return the queue, or NULL if it doesn't exist.
840 \note Should be called with the global qlock locked. */
841 static struct ast_call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
843 struct ast_variable *v;
844 struct ast_call_queue *q;
845 struct member *m, *prev_m, *next_m;
847 char *tmp, *tmp_name;
848 char tmpbuf[64]; /* Must be longer than the longest queue param name. */
850 /* Find the queue in the in-core list (we will create a new one if not found). */
851 AST_LIST_TRAVERSE(&queues, q, list) {
852 if (!strcasecmp(q->name, queuename)) {
857 /* Static queues override realtime. */
859 ast_mutex_lock(&q->lock);
862 ast_mutex_unlock(&q->lock);
865 ast_mutex_unlock(&q->lock);
869 } else if (!member_config)
870 /* Not found in the list, and it's not realtime ... */
873 /* Check if queue is defined in realtime. */
875 /* Delete queue from in-core list if it has been deleted in realtime. */
877 /*! \note Hmm, can't seem to distinguish a DB failure from a not
878 found condition... So we might delete an in-core queue
879 in case of DB failure. */
880 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
883 /* Delete if unused (else will be deleted when last caller leaves). */
886 AST_LIST_REMOVE(&queues, q, list);
887 ast_mutex_unlock(&q->lock);
890 ast_mutex_unlock(&q->lock);
895 /* Create a new queue if an in-core entry does not exist yet. */
897 if (!(q = alloc_queue(queuename)))
899 ast_mutex_lock(&q->lock);
902 AST_LIST_INSERT_HEAD(&queues, q, list);
904 init_queue(q); /* Ensure defaults for all parameters not set explicitly. */
907 memset(tmpbuf, 0, sizeof(tmpbuf));
909 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
910 if((tmp = strchr(v->name, '_')) != NULL) {
911 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
914 while((tmp = strchr(tmp, '_')) != NULL)
918 queue_set_param(q, tmp_name, v->value, -1, 0);
922 /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
930 interface = ast_category_browse(member_config, NULL);
932 rt_handle_member_record(q, interface, ast_variable_retrieve(member_config, interface, "penalty"));
933 interface = ast_category_browse(member_config, interface);
936 /* Delete all realtime members that have been deleted in DB. */
943 prev_m->next = next_m;
954 ast_mutex_unlock(&q->lock);
959 static struct ast_call_queue *load_realtime_queue(char *queuename)
961 struct ast_variable *queue_vars = NULL;
962 struct ast_config *member_config = NULL;
963 struct ast_call_queue *q;
965 /* Find the queue in the in-core list first. */
966 AST_LIST_LOCK(&queues);
967 AST_LIST_TRAVERSE(&queues, q, list) {
968 if (!strcasecmp(q->name, queuename)) {
972 AST_LIST_UNLOCK(&queues);
974 if (!q || q->realtime) {
975 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
976 queue operations while waiting for the DB.
978 This will be two separate database transactions, so we might
979 see queue parameters as they were before another process
980 changed the queue and member list as it was after the change.
981 Thus we might see an empty member list when a queue is
982 deleted. In practise, this is unlikely to cause a problem. */
984 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
986 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
987 if (!member_config) {
988 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
993 AST_LIST_LOCK(&queues);
995 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
997 ast_config_destroy(member_config);
999 ast_variables_destroy(queue_vars);
1001 AST_LIST_UNLOCK(&queues);
1006 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1008 struct ast_call_queue *q;
1009 struct queue_ent *cur, *prev = NULL;
1013 enum queue_member_status stat;
1015 q = load_realtime_queue(queuename);
1019 AST_LIST_LOCK(&queues);
1020 ast_mutex_lock(&q->lock);
1022 /* This is our one */
1023 stat = get_member_status(q, qe->max_penalty);
1024 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1025 *reason = QUEUE_JOINEMPTY;
1026 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1027 *reason = QUEUE_JOINUNAVAIL;
1028 else if (q->maxlen && (q->count >= q->maxlen))
1029 *reason = QUEUE_FULL;
1031 /* There's space for us, put us at the right position inside
1033 * Take into account the priority of the calling user */
1038 /* We have higher priority than the current user, enter
1039 * before him, after all the other users with priority
1040 * higher or equal to our priority. */
1041 if ((!inserted) && (qe->prio > cur->prio)) {
1042 insert_entry(q, prev, qe, &pos);
1049 /* No luck, join at the end of the queue */
1051 insert_entry(q, prev, qe, &pos);
1052 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1053 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1054 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1057 /* XXX missing CalledIDnum ? */
1058 manager_event(EVENT_FLAG_CALL, "Join",
1059 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1061 S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1062 S_OR(qe->chan->cid.cid_name, "unknown"),
1063 q->name, qe->pos, q->count, qe->chan->uniqueid );
1065 ast_log(LOG_NOTICE, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1068 ast_mutex_unlock(&q->lock);
1069 AST_LIST_UNLOCK(&queues);
1073 static int play_file(struct ast_channel *chan, char *filename)
1077 ast_stopstream(chan);
1078 res = ast_streamfile(chan, filename, chan->language);
1081 res = ast_waitstream(chan, AST_DIGIT_ANY);
1085 ast_stopstream(chan);
1090 static int valid_exit(struct queue_ent *qe, char digit)
1092 int digitlen = strlen(qe->digits);
1094 /* Prevent possible buffer overflow */
1095 if (digitlen < sizeof(qe->digits) - 2) {
1096 qe->digits[digitlen] = digit;
1097 qe->digits[digitlen + 1] = '\0';
1099 qe->digits[0] = '\0';
1103 /* If there's no context to goto, short-circuit */
1104 if (ast_strlen_zero(qe->context))
1107 /* If the extension is bad, then reset the digits to blank */
1108 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1109 qe->digits[0] = '\0';
1113 /* We have an exact match */
1114 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1115 /* Return 1 on a successful goto */
1121 static int say_position(struct queue_ent *qe)
1123 int res = 0, avgholdmins, avgholdsecs;
1126 /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1128 if ( (now - qe->last_pos) < 15 )
1131 /* If either our position has changed, or we are over the freq timer, say position */
1132 if ( (qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency) )
1135 ast_moh_stop(qe->chan);
1136 /* Say we're next, if we are */
1138 res = play_file(qe->chan, qe->parent->sound_next);
1139 if (res && valid_exit(qe, res))
1144 res = play_file(qe->chan, qe->parent->sound_thereare);
1145 if (res && valid_exit(qe, res))
1147 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1148 if (res && valid_exit(qe, res))
1150 res = play_file(qe->chan, qe->parent->sound_calls);
1151 if (res && valid_exit(qe, res))
1154 /* Round hold time to nearest minute */
1155 avgholdmins = abs(( (qe->parent->holdtime + 30) - (now - qe->start) ) / 60);
1157 /* If they have specified a rounding then round the seconds as well */
1158 if(qe->parent->roundingseconds) {
1159 avgholdsecs = (abs(( (qe->parent->holdtime + 30) - (now - qe->start) )) - 60 * avgholdmins) / qe->parent->roundingseconds;
1160 avgholdsecs*= qe->parent->roundingseconds;
1165 if (option_verbose > 2)
1166 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1168 /* If the hold time is >1 min, if it's enabled, and if it's not
1169 supposed to be only once and we have already said it, say it */
1170 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1171 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1172 res = play_file(qe->chan, qe->parent->sound_holdtime);
1173 if (res && valid_exit(qe, res))
1176 if (avgholdmins>0) {
1177 if (avgholdmins < 2) {
1178 res = play_file(qe->chan, qe->parent->sound_lessthan);
1179 if (res && valid_exit(qe, res))
1182 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, (char *)NULL);
1183 if (res && valid_exit(qe, res))
1186 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1187 if (res && valid_exit(qe, res))
1191 res = play_file(qe->chan, qe->parent->sound_minutes);
1192 if (res && valid_exit(qe, res))
1195 if (avgholdsecs>0) {
1196 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, (char*) NULL);
1197 if (res && valid_exit(qe, res))
1200 res = play_file(qe->chan, qe->parent->sound_seconds);
1201 if (res && valid_exit(qe, res))
1208 if (option_verbose > 2)
1209 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1210 qe->chan->name, qe->parent->name, qe->pos);
1211 res = play_file(qe->chan, qe->parent->sound_thanks);
1214 /* Set our last_pos indicators */
1216 qe->last_pos_said = qe->pos;
1217 /* Don't restart music on hold if we're about to exit the caller from the queue */
1219 ast_moh_start(qe->chan, qe->moh);
1224 static void recalc_holdtime(struct queue_ent *qe)
1226 int oldvalue, newvalue;
1228 /* Calculate holdtime using a recursive boxcar filter */
1229 /* Thanks to SRT for this contribution */
1230 /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1232 newvalue = time(NULL) - qe->start;
1234 ast_mutex_lock(&qe->parent->lock);
1235 if (newvalue <= qe->parent->servicelevel)
1236 qe->parent->callscompletedinsl++;
1237 oldvalue = qe->parent->holdtime;
1238 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1239 ast_mutex_unlock(&qe->parent->lock);
1243 static void leave_queue(struct queue_ent *qe)
1245 struct ast_call_queue *q;
1246 struct queue_ent *cur, *prev = NULL;
1252 ast_mutex_lock(&q->lock);
1260 /* Take us out of the queue */
1261 manager_event(EVENT_FLAG_CALL, "Leave",
1262 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\n",
1263 qe->chan->name, q->name, q->count);
1265 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1266 /* Take us out of the queue */
1268 prev->next = cur->next;
1270 q->head = cur->next;
1272 /* Renumber the people after us in the queue based on a new count */
1278 ast_mutex_unlock(&q->lock);
1279 if (q->dead && !q->count) {
1280 /* It's dead and nobody is in it, so kill it */
1281 AST_LIST_LOCK(&queues);
1282 AST_LIST_REMOVE(&queues, q, list);
1283 AST_LIST_UNLOCK(&queues);
1288 /* Hang up a list of outgoing calls */
1289 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1291 struct callattempt *oo;
1294 /* Hangup any existing lines we have open */
1295 if (outgoing->chan && (outgoing->chan != exception))
1296 ast_hangup(outgoing->chan);
1298 outgoing=outgoing->q_next;
1303 static int update_status(struct ast_call_queue *q, struct member *member, int status)
1307 /* Since a reload could have taken place, we have to traverse the list to
1308 be sure it's still valid */
1309 ast_mutex_lock(&q->lock);
1310 for (cur = q->members; cur; cur = cur->next) {
1311 if (member == cur) {
1312 cur->status = status;
1313 if (!q->maskmemberstatus) {
1314 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1317 "Membership: %s\r\n"
1319 "CallsTaken: %d\r\n"
1323 q->name, cur->interface, cur->dynamic ? "dynamic" : "static",
1324 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1329 ast_mutex_unlock(&q->lock);
1333 static int update_dial_status(struct ast_call_queue *q, struct member *member, int status)
1335 if (status == AST_CAUSE_BUSY)
1336 status = AST_DEVICE_BUSY;
1337 else if (status == AST_CAUSE_UNREGISTERED)
1338 status = AST_DEVICE_UNAVAILABLE;
1339 else if (status == AST_CAUSE_NOSUCHDRIVER)
1340 status = AST_DEVICE_INVALID;
1342 status = AST_DEVICE_UNKNOWN;
1343 return update_status(q, member, status);
1346 /* traverse all defined queues which have calls waiting and contain this member
1347 return 0 if no other queue has precedence (higher weight) or 1 if found */
1348 static int compare_weight(struct ast_call_queue *rq, struct member *member)
1350 struct ast_call_queue *q;
1354 /* &qlock and &rq->lock already set by try_calling()
1355 * to solve deadlock */
1356 AST_LIST_TRAVERSE(&queues, q, list) {
1357 if (q == rq) /* don't check myself, could deadlock */
1359 ast_mutex_lock(&q->lock);
1360 if (q->count && q->members) {
1361 for (mem = q->members; mem; mem = mem->next) {
1362 if (!strcmp(mem->interface, member->interface)) {
1363 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1364 if (q->weight > rq->weight) {
1365 ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
1372 ast_mutex_unlock(&q->lock);
1379 /*! \brief common hangup actions */
1380 static void do_hang(struct callattempt *o)
1383 ast_hangup(o->chan);
1387 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1394 /* on entry here, we know that tmp->chan == NULL */
1395 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1397 ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1399 ast_cdr_busy(qe->chan->cdr);
1400 tmp->stillgoing = 0;
1405 if (!qe->parent->ringinuse && (tmp->member->status == AST_DEVICE_INUSE)) {
1407 ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1409 ast_cdr_busy(qe->chan->cdr);
1410 tmp->stillgoing = 0;
1414 if (tmp->member->paused) {
1416 ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1418 ast_cdr_busy(qe->chan->cdr);
1419 tmp->stillgoing = 0;
1422 if (use_weight && compare_weight(qe->parent,tmp->member)) {
1423 ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1425 ast_cdr_busy(qe->chan->cdr);
1426 tmp->stillgoing = 0;
1431 ast_copy_string(tech, tmp->interface, sizeof(tech));
1432 if ((location = strchr(tech, '/')))
1437 /* Request the peer */
1438 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1439 if (!tmp->chan) { /* If we can't, just go on to the next call */
1441 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", cur->tech);
1444 ast_cdr_busy(qe->chan->cdr);
1445 tmp->stillgoing = 0;
1446 update_dial_status(qe->parent, tmp->member, status);
1449 } else if (status != tmp->oldstatus)
1450 update_dial_status(qe->parent, tmp->member, status);
1452 tmp->chan->appl = "AppQueue";
1453 tmp->chan->data = "(Outgoing Line)";
1454 tmp->chan->whentohangup = 0;
1455 if (tmp->chan->cid.cid_num)
1456 free(tmp->chan->cid.cid_num);
1457 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1458 if (tmp->chan->cid.cid_name)
1459 free(tmp->chan->cid.cid_name);
1460 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1461 if (tmp->chan->cid.cid_ani)
1462 free(tmp->chan->cid.cid_ani);
1463 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1465 /* Inherit specially named variables from parent channel */
1466 ast_channel_inherit_variables(qe->chan, tmp->chan);
1468 /* Presense of ADSI CPE on outgoing channel follows ours */
1469 tmp->chan->adsicpe = qe->chan->adsicpe;
1471 /* Place the call, but don't wait on the answer */
1472 res = ast_call(tmp->chan, location, 0);
1474 /* Again, keep going even if there's an error */
1476 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1477 else if (option_verbose > 2)
1478 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1483 if (qe->parent->eventwhencalled) {
1484 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1485 "AgentCalled: %s\r\n"
1486 "ChannelCalling: %s\r\n"
1488 "CallerIDName: %s\r\n"
1492 tmp->interface, qe->chan->name,
1493 S_OR(tmp->chan->cid.cid_num, "unknown"),
1494 S_OR(tmp->chan->cid.cid_name, "unknown"),
1495 qe->chan->context, qe->chan->exten, qe->chan->priority);
1497 if (option_verbose > 2)
1498 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1503 /*! \brief find the entry with the best metric, or NULL */
1504 static struct callattempt *find_best(struct callattempt *outgoing)
1506 struct callattempt *best = NULL, *cur;
1508 for (cur = outgoing; cur; cur = cur->q_next) {
1509 if (cur->stillgoing && /* Not already done */
1510 !cur->chan && /* Isn't already going */
1511 (!best || cur->metric < best->metric)) { /* We haven't found one yet, or it's better */
1518 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1523 struct callattempt *best = find_best(outgoing);
1526 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1529 if (!qe->parent->strategy) {
1530 struct callattempt *cur;
1531 /* Ring everyone who shares this best metric (for ringall) */
1532 for (cur = outgoing; cur; cur = cur->q_next) {
1533 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1535 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1536 ring_entry(qe, cur, busies);
1540 /* Ring just the best channel */
1542 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1543 ring_entry(qe, best, busies);
1545 if (best->chan) /* break out with result = 1 */
1551 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1553 struct callattempt *best = find_best(outgoing);
1556 /* Ring just the best channel */
1558 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1559 qe->parent->rrpos = best->metric % 1000;
1561 /* Just increment rrpos */
1562 if (qe->parent->wrapped) {
1563 /* No more channels, start over */
1564 qe->parent->rrpos = 0;
1566 /* Prioritize next entry */
1567 qe->parent->rrpos++;
1570 qe->parent->wrapped = 0;
1574 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1578 ast_stopstream(chan);
1579 res = ast_streamfile(chan, filename, chan->language);
1582 /* Wait for a keypress */
1583 res = ast_waitstream(chan, AST_DIGIT_ANY);
1584 if (res <= 0 || !valid_exit(qe, res))
1588 ast_stopstream(chan);
1594 ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name);
1601 static int say_periodic_announcement(struct queue_ent *qe)
1606 /* Get the current time */
1609 /* Check to see if it is time to announce */
1610 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1613 /* Stop the music on hold so we can play our own file */
1614 ast_moh_stop(qe->chan);
1616 if (option_verbose > 2)
1617 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1619 /* Check to make sure we have a sound file. If not, reset to the first sound file */
1620 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
1621 qe->last_periodic_announce_sound = 0;
1624 /* play the announcement */
1625 res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
1627 /* Resume Music on Hold */
1628 ast_moh_start(qe->chan, qe->moh);
1630 /* update last_periodic_announce_time */
1631 qe->last_periodic_announce_time = now;
1633 /* Update the current periodic announcement to the next announcement */
1634 qe->last_periodic_announce_sound++;
1639 static void record_abandoned(struct queue_ent *qe)
1641 ast_mutex_lock(&qe->parent->lock);
1642 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
1646 "OriginalPosition: %d\r\n"
1648 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
1650 qe->parent->callsabandoned++;
1651 ast_mutex_unlock(&qe->parent->lock);
1655 #define AST_MAX_WATCHERS 256
1657 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect)
1659 char *queue = qe->parent->name;
1660 struct callattempt *o;
1662 int sentringing = 0;
1663 int numbusies = prebusies;
1667 struct ast_frame *f;
1668 struct callattempt *peer = NULL;
1669 struct ast_channel *winner;
1670 struct ast_channel *in = qe->chan;
1673 while(*to && !peer) {
1674 int numlines, retry, pos = 1;
1675 struct ast_channel *watchers[AST_MAX_WATCHERS];
1678 for (retry = 0; retry < 2; retry++) {
1680 for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
1681 if (o->stillgoing) { /* Keep track of important channels */
1684 watchers[pos++] = o->chan;
1688 if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
1689 qe->parent->strategy /* ring would not be delivered */)
1691 /* On "ringall" strategy we only move to the next penalty level
1692 when *all* ringing phones are done in the current penalty level */
1693 ring_one(qe, outgoing, &numbusies);
1696 if (pos == 1 /* not found */) {
1697 if (numlines == (numbusies + numnochan)) {
1698 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1700 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1705 winner = ast_waitfor_n(watchers, pos, to);
1706 for (o = outgoing; o; o = o->q_next) {
1707 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
1709 if (option_verbose > 2)
1710 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1713 } else if (o->chan && (o->chan == winner)) {
1714 ast_copy_string(on, o->member->interface, sizeof(on));
1715 if (!ast_strlen_zero(o->chan->call_forward)) {
1716 char tmpchan[256]="";
1719 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1720 if ((stuff = strchr(tmpchan, '/'))) {
1724 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1728 /* Before processing channel, go ahead and check for forwarding */
1729 if (option_verbose > 2)
1730 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1731 /* Setup parameters */
1732 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1733 if (status != o->oldstatus)
1734 update_dial_status(qe->parent, o->member, status);
1736 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1740 if (o->chan->cid.cid_num)
1741 free(o->chan->cid.cid_num);
1742 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
1744 if (o->chan->cid.cid_name)
1745 free(o->chan->cid.cid_name);
1746 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
1748 ast_string_field_set(o->chan, accountcode, in->accountcode);
1749 o->chan->cdrflags = in->cdrflags;
1751 if (in->cid.cid_ani) {
1752 if (o->chan->cid.cid_ani)
1753 free(o->chan->cid.cid_ani);
1754 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
1756 if (o->chan->cid.cid_rdnis)
1757 free(o->chan->cid.cid_rdnis);
1758 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
1759 if (ast_call(o->chan, tmpchan, 0)) {
1760 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
1765 /* Hangup the original channel now, in case we needed it */
1769 f = ast_read(winner);
1771 if (f->frametype == AST_FRAME_CONTROL) {
1772 switch(f->subclass) {
1773 case AST_CONTROL_ANSWER:
1774 /* This is our guy if someone answered. */
1776 if (option_verbose > 2)
1777 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1781 case AST_CONTROL_BUSY:
1782 if (option_verbose > 2)
1783 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
1785 ast_cdr_busy(in->cdr);
1787 if (qe->parent->strategy) {
1788 if (qe->parent->timeoutrestart)
1790 ring_one(qe, outgoing, &numbusies);
1794 case AST_CONTROL_CONGESTION:
1795 if (option_verbose > 2)
1796 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
1798 ast_cdr_busy(in->cdr);
1800 if (qe->parent->strategy) {
1801 if (qe->parent->timeoutrestart)
1803 ring_one(qe, outgoing, &numbusies);
1807 case AST_CONTROL_RINGING:
1808 if (option_verbose > 2)
1809 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
1812 ast_indicate(in, AST_CONTROL_RINGING);
1817 case AST_CONTROL_OFFHOOK:
1818 /* Ignore going off hook */
1821 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
1827 if (qe->parent->strategy) {
1828 if (qe->parent->timeoutrestart)
1830 ring_one(qe, outgoing, &numbusies);
1838 if (f && (f->frametype != AST_FRAME_VOICE))
1839 printf("Frame type: %d, %d\n", f->frametype, f->subclass);
1840 else if (!f || (f->frametype != AST_FRAME_VOICE))
1841 printf("Hangup received on %s\n", in->name);
1843 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
1850 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
1851 if (option_verbose > 3)
1852 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
1857 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
1858 if (option_verbose > 3)
1859 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
1868 if (option_verbose > 2)
1869 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", orig);
1870 ast_queue_log(qe->parent->name, qe->chan->uniqueid, on, "RINGNOANSWER", "%d", orig);
1871 if (qe->parent->autopause) {
1872 if (!set_member_paused(qe->parent->name, on, 1)) {
1873 if (option_verbose > 2)
1874 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", on, qe->parent->name);
1876 if (option_verbose > 2)
1877 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", on, qe->parent->name);
1887 static int is_our_turn(struct queue_ent *qe)
1889 struct queue_ent *ch;
1895 if (!qe->parent->autofill) {
1897 /* Atomically read the parent head -- does not need a lock */
1898 ch = qe->parent->head;
1899 /* If we are now at the top of the head, break out */
1900 if ((ch == qe) || (qe->parent->autofill)) {
1902 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1906 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1912 /* This needs a lock. How many members are available to be served? */
1914 ast_mutex_lock(&qe->parent->lock);
1916 ch = qe->parent->head;
1917 cur = qe->parent->members;
1920 if (cur->status == 1)
1926 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
1928 if (qe->parent->strategy == 1) {
1930 ast_log(LOG_DEBUG, "Even though there are %d available members, the strategy is ringall so only the head call is allowed in!\n", avl);
1934 while ((idx < avl) && (ch) && (ch != qe)) {
1939 /* If the queue entry is within avl [the number of available members] calls from the top ... */
1940 if (ch && idx < avl) {
1942 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
1946 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
1950 ast_mutex_unlock(&qe->parent->lock);
1956 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
1960 /* This is the holding pen for callers 2 through maxlen */
1962 enum queue_member_status stat;
1964 if (is_our_turn(qe))
1967 /* If we have timed out, break out */
1968 if (qe->expire && (time(NULL) > qe->expire)) {
1969 *reason = QUEUE_TIMEOUT;
1970 ast_queue_log(qe->parent->name, qe->chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe->pos);
1974 stat = get_member_status(qe->parent, qe->max_penalty);
1976 /* leave the queue if no agents, if enabled */
1977 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
1978 *reason = QUEUE_LEAVEEMPTY;
1979 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
1984 /* leave the queue if no reachable agents, if enabled */
1985 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
1986 *reason = QUEUE_LEAVEUNAVAIL;
1987 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
1992 /* Make a position announcement, if enabled */
1993 if (qe->parent->announcefrequency && !ringing)
1994 res = say_position(qe);
1998 /* Make a periodic announcement, if enabled */
1999 if (qe->parent->periodicannouncefrequency && !ringing)
2000 res = say_periodic_announcement(qe);
2002 /* Wait a second before checking again */
2003 if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000);
2010 static int update_queue(struct ast_call_queue *q, struct member *member)
2014 /* Since a reload could have taken place, we have to traverse the list to
2015 be sure it's still valid */
2016 ast_mutex_lock(&q->lock);
2019 if (member == cur) {
2020 time(&cur->lastcall);
2026 q->callscompleted++;
2027 ast_mutex_unlock(&q->lock);
2031 static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2033 if (mem->penalty > qe->max_penalty)
2036 switch (q->strategy) {
2037 case QUEUE_STRATEGY_RINGALL:
2038 /* Everyone equal, except for penalty */
2039 tmp->metric = mem->penalty * 1000000;
2041 case QUEUE_STRATEGY_ROUNDROBIN:
2044 /* No more channels, start over */
2047 /* Prioritize next entry */
2053 case QUEUE_STRATEGY_RRMEMORY:
2054 if (pos < q->rrpos) {
2055 tmp->metric = 1000 + pos;
2058 /* Indicate there is another priority */
2062 tmp->metric += mem->penalty * 1000000;
2064 case QUEUE_STRATEGY_RANDOM:
2065 tmp->metric = ast_random() % 1000;
2066 tmp->metric += mem->penalty * 1000000;
2068 case QUEUE_STRATEGY_FEWESTCALLS:
2069 tmp->metric = mem->calls;
2070 tmp->metric += mem->penalty * 1000000;
2072 case QUEUE_STRATEGY_LEASTRECENT:
2076 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2077 tmp->metric += mem->penalty * 1000000;
2080 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2086 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on, const char *agi)
2089 struct callattempt *outgoing=NULL; /* the queue we are building */
2091 char oldexten[AST_MAX_EXTENSION]="";
2092 char oldcontext[AST_MAX_CONTEXT]="";
2093 char queuename[256]="";
2094 struct ast_channel *peer;
2095 struct ast_channel *which;
2096 struct callattempt *lpeer;
2097 struct member *member;
2098 struct ast_app *app;
2099 int res = 0, bridge = 0;
2102 char *announce = NULL;
2105 time_t now = time(NULL);
2106 struct ast_bridge_config bridge_config;
2107 char nondataquality = 1;
2108 char *agiexec = NULL;
2110 const char *monitorfilename;
2111 const char *monitor_exec;
2112 const char *monitor_options;
2113 char tmpid[256], tmpid2[256];
2114 char meid[1024], meid2[1024];
2115 char mixmonargs[1512];
2116 struct ast_app *mixmonapp = NULL;
2120 memset(&bridge_config, 0, sizeof(bridge_config));
2123 for (; options && *options; options++)
2126 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2129 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2132 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2135 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2141 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2144 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2147 if ((now - qe->start >= qe->parent->timeout))
2152 /* Hold the lock while we setup the outgoing calls */
2154 AST_LIST_LOCK(&queues);
2155 ast_mutex_lock(&qe->parent->lock);
2157 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2159 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2160 cur = qe->parent->members;
2161 if (!ast_strlen_zero(qe->announce))
2162 announce = qe->announce;
2163 if (!ast_strlen_zero(announceoverride))
2164 announce = announceoverride;
2166 for (;cur; cur = cur->next) {
2167 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2169 ast_mutex_unlock(&qe->parent->lock);
2171 AST_LIST_UNLOCK(&queues);
2174 tmp->stillgoing = -1;
2177 ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url);
2179 ast_log(LOG_DEBUG, "Simple queue (no URL)\n");
2182 tmp->member = cur; /* Never directly dereference! Could change on reload */
2183 tmp->oldstatus = cur->status;
2184 tmp->lastcall = cur->lastcall;
2185 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2186 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2187 just calculate their metric for the appropriate strategy */
2188 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2189 /* Put them in the list of outgoing thingies... We're ready now.
2190 XXX If we're forcibly removed, these outgoing calls won't get
2192 tmp->q_next = outgoing;
2194 /* If this line is up, don't try anybody else */
2195 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2201 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2202 ring_one(qe, outgoing, &numbusies);
2203 ast_mutex_unlock(&qe->parent->lock);
2205 AST_LIST_UNLOCK(&queues);
2206 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT));
2207 ast_mutex_lock(&qe->parent->lock);
2208 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2209 store_next(qe, outgoing);
2211 ast_mutex_unlock(&qe->parent->lock);
2212 peer = lpeer ? lpeer->chan : NULL;
2215 /* Must gotten hung up */
2221 ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2222 } else { /* peer is valid */
2223 /* Ah ha! Someone answered within the desired timeframe. Of course after this
2224 we will always return with -1 so that it is hung up properly after the
2227 if (!strcmp(qe->chan->tech->type, "Zap"))
2228 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2229 if (!strcmp(peer->tech->type, "Zap"))
2230 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2231 /* Update parameters for the queue */
2232 recalc_holdtime(qe);
2233 member = lpeer->member;
2234 hangupcalls(outgoing, peer);
2236 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2238 res2 = ast_autoservice_start(qe->chan);
2240 if (qe->parent->memberdelay) {
2241 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2242 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2244 if (!res2 && announce) {
2245 if (play_file(peer, announce))
2246 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2248 if (!res2 && qe->parent->reportholdtime) {
2249 if (!play_file(peer, qe->parent->sound_reporthold)) {
2253 holdtime = abs((now - qe->start) / 60);
2255 play_file(peer, qe->parent->sound_lessthan);
2256 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2258 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2259 play_file(peer, qe->parent->sound_minutes);
2263 res2 |= ast_autoservice_stop(qe->chan);
2264 if (peer->_softhangup) {
2265 /* Agent must have hung up */
2266 ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name);
2267 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", "");
2268 record_abandoned(qe);
2269 if (qe->parent->eventwhencalled) {
2270 manager_event(EVENT_FLAG_AGENT, "AgentDump",
2275 queuename, qe->chan->uniqueid, peer->name, member->interface);
2280 /* Caller must have hung up just before being connected*/
2281 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2282 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2283 record_abandoned(qe);
2288 /* Stop music on hold */
2289 ast_moh_stop(qe->chan);
2290 /* If appropriate, log that we have a destination channel */
2292 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2293 /* Make sure channels are compatible */
2294 res = ast_channel_make_compatible(qe->chan, peer);
2296 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "SYSCOMPAT", "%s", "");
2297 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2298 record_abandoned(qe);
2302 /* Begin Monitoring */
2303 if (qe->parent->monfmt && *qe->parent->monfmt) {
2304 if (!qe->parent->montype) {
2306 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
2307 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2308 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2312 if (monitorfilename)
2313 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2314 else if (qe->chan->cdr)
2315 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2317 /* Last ditch effort -- no CDR, make up something */
2318 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2319 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2321 if (qe->parent->monjoin)
2322 ast_monitor_setjoinfiles(which, 1);
2325 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
2326 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2327 if (!monitorfilename) {
2329 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
2331 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2333 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
2334 for (p = tmpid2; *p ; p++) {
2335 if (*p == '^' && *(p+1) == '{') {
2340 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2343 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2344 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2347 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
2348 for (p = meid2; *p ; p++) {
2349 if (*p == '^' && *(p+1) == '{') {
2353 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2356 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
2358 mixmonapp = pbx_findapp("MixMonitor");
2360 if (strchr(tmpid2, '|')) {
2361 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
2365 if (strchr(monitor_options, '|')) {
2366 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
2370 if (!monitor_options)
2371 monitor_options = ast_strdupa("");
2374 if (!ast_strlen_zero(monitor_exec) && !ast_strlen_zero(monitor_options))
2375 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
2377 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
2380 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2382 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2385 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2389 /* Drop out of the queue at this point, to prepare for next caller */
2391 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2393 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2394 ast_channel_sendurl(peer, url);
2396 if (qe->parent->setinterfacevar)
2397 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
2398 if (!ast_strlen_zero(agi)) {
2400 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
2401 app = pbx_findapp("agi");
2403 agiexec = ast_strdupa(agi);
2404 ret = pbx_exec(qe->chan, app, agiexec);
2406 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
2408 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
2409 if (qe->parent->eventwhencalled)
2410 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2416 "BridgedChannel: %s\r\n",
2417 queuename, qe->chan->uniqueid, peer->name, member->interface,
2418 (long)time(NULL) - qe->start,peer->uniqueid);
2419 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2420 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2423 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2425 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2426 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s|%ld|%ld",
2427 qe->chan->exten, qe->chan->context, (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2428 } else if (qe->chan->_softhangup) {
2429 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2430 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2431 if (qe->parent->eventwhencalled)
2432 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2439 "Reason: caller\r\n",
2440 queuename, qe->chan->uniqueid, peer->name, member->interface,
2441 (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2443 ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart));
2444 if (qe->parent->eventwhencalled)
2445 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2451 "Reason: agent\r\n",
2452 queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start),
2453 (long)(time(NULL) - callstart));
2456 if(bridge != AST_PBX_NO_HANGUP_PEER)
2458 update_queue(qe->parent, member);
2460 res = 1; /* JDG: bridge successfully, leave app_queue */
2462 res = bridge; /* bridge error, stay in the queue */
2465 hangupcalls(outgoing, NULL);
2469 static int wait_a_bit(struct queue_ent *qe)
2471 /* Don't need to hold the lock while we setup the outgoing calls */
2472 int retrywait = qe->parent->retry * 1000;
2474 return ast_waitfordigit(qe->chan, retrywait);
2477 static struct member * interface_exists(struct ast_call_queue *q, char *interface)
2482 for (mem = q->members; mem; mem = mem->next)
2483 if (!strcasecmp(interface, mem->interface))
2490 /* Dump all members in a specific queue to the database
2492 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2495 static void dump_queue_members(struct ast_call_queue *pm_queue)
2497 struct member *cur_member;
2498 char value[PM_MAX_LEN];
2502 memset(value, 0, sizeof(value));
2507 for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2508 if (!cur_member->dynamic)
2511 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d%s",
2512 cur_member->interface, cur_member->penalty, cur_member->paused,
2513 cur_member->next ? "|" : "");
2514 if (res != strlen(value + value_len)) {
2515 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2521 if (value_len && !cur_member) {
2522 if (ast_db_put(pm_family, pm_queue->name, value))
2523 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2525 /* Delete the entry if the queue is empty or there is an error */
2526 ast_db_del(pm_family, pm_queue->name);
2529 static int remove_from_queue(char *queuename, char *interface)
2531 struct ast_call_queue *q;
2532 struct member *last_member, *look;
2533 int res = RES_NOSUCHQUEUE;
2535 AST_LIST_LOCK(&queues);
2536 AST_LIST_TRAVERSE(&queues, q, list) {
2537 ast_mutex_lock(&q->lock);
2538 if (!strcmp(q->name, queuename)) {
2539 if ((last_member = interface_exists(q, interface))) {
2540 if ((look = q->members) == last_member) {
2541 q->members = last_member->next;
2543 while (look != NULL) {
2544 if (look->next == last_member) {
2545 look->next = last_member->next;
2552 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2555 q->name, last_member->interface);
2558 if (queue_persistent_members)
2559 dump_queue_members(q);
2565 ast_mutex_unlock(&q->lock);
2568 ast_mutex_unlock(&q->lock);
2570 AST_LIST_UNLOCK(&queues);
2574 static int add_to_queue(char *queuename, char *interface, int penalty, int paused, int dump)
2576 struct ast_call_queue *q;
2577 struct member *new_member;
2578 int res = RES_NOSUCHQUEUE;
2580 /* \note Ensure the appropriate realtime queue is loaded. Note that this
2581 * short-circuits if the queue is already in memory. */
2582 q = load_realtime_queue(queuename);
2584 AST_LIST_LOCK(&queues);
2587 ast_mutex_lock(&q->lock);
2588 if (interface_exists(q, interface) == NULL) {
2589 new_member = create_queue_member(interface, penalty, paused);
2591 if (new_member != NULL) {
2592 new_member->dynamic = 1;
2593 new_member->next = q->members;
2594 q->members = new_member;
2595 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
2598 "Membership: %s\r\n"
2600 "CallsTaken: %d\r\n"
2604 q->name, new_member->interface, new_member->dynamic ? "dynamic" : "static",
2605 new_member->penalty, new_member->calls, (int)new_member->lastcall, new_member->status, new_member->paused);
2608 dump_queue_members(q);
2612 res = RES_OUTOFMEMORY;
2617 ast_mutex_unlock(&q->lock);
2619 AST_LIST_UNLOCK(&queues);
2623 static int set_member_paused(char *queuename, char *interface, int paused)
2626 struct ast_call_queue *q;
2629 /* Special event for when all queues are paused - individual events still generated */
2631 if (ast_strlen_zero(queuename))
2632 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
2634 AST_LIST_LOCK(&queues);
2635 AST_LIST_TRAVERSE(&queues, q, list) {
2636 ast_mutex_lock(&q->lock);
2637 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
2638 if ((mem = interface_exists(q, interface))) {
2640 if (mem->paused == paused)
2641 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
2642 mem->paused = paused;
2644 if (queue_persistent_members)
2645 dump_queue_members(q);
2647 ast_queue_log(q->name, "NONE", interface, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
2649 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
2653 q->name, mem->interface, paused);
2656 ast_mutex_unlock(&q->lock);
2658 AST_LIST_UNLOCK(&queues);
2661 return RESULT_SUCCESS;
2663 return RESULT_FAILURE;
2666 /* Reload dynamic queue members persisted into the astdb */
2667 static void reload_queue_members(void)
2677 struct ast_db_entry *db_tree;
2678 struct ast_db_entry *entry;
2679 struct ast_call_queue *cur_queue;
2680 char queue_data[PM_MAX_LEN];
2682 AST_LIST_LOCK(&queues);
2684 /* Each key in 'pm_family' is the name of a queue */
2685 db_tree = ast_db_gettree(pm_family, NULL);
2686 for (entry = db_tree; entry; entry = entry->next) {
2688 queue_name = entry->key + strlen(pm_family) + 2;
2690 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
2691 ast_mutex_lock(&cur_queue->lock);
2692 if (!strcmp(queue_name, cur_queue->name))
2694 ast_mutex_unlock(&cur_queue->lock);
2698 /* If the queue no longer exists, remove it from the
2700 ast_db_del(pm_family, queue_name);
2703 ast_mutex_unlock(&cur_queue->lock);
2705 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
2708 cur_ptr = queue_data;
2709 while ((member = strsep(&cur_ptr, "|"))) {
2710 if (ast_strlen_zero(member))
2713 interface = strsep(&member, ";");
2714 penalty_tok = strsep(&member, ";");
2715 paused_tok = strsep(&member, ";");
2718 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
2721 penalty = strtol(penalty_tok, NULL, 10);
2722 if (errno == ERANGE) {
2723 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
2728 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
2731 paused = strtol(paused_tok, NULL, 10);
2732 if ((errno == ERANGE) || paused < 0 || paused > 1) {
2733 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
2738 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Penalty: %d Paused: %d\n", queue_name, interface, penalty, paused);
2740 if (add_to_queue(queue_name, interface, penalty, paused, 0) == RES_OUTOFMEMORY) {
2741 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
2747 AST_LIST_UNLOCK(&queues);
2749 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
2750 ast_db_freetree(db_tree);
2754 static int pqm_exec(struct ast_channel *chan, void *data)
2756 struct localuser *lu;
2758 int priority_jump = 0;
2759 AST_DECLARE_APP_ARGS(args,
2760 AST_APP_ARG(queuename);
2761 AST_APP_ARG(interface);
2762 AST_APP_ARG(options);
2765 if (ast_strlen_zero(data)) {
2766 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2770 if (!(parse = ast_strdupa(data)))
2773 AST_STANDARD_APP_ARGS(args, parse);
2778 if (strchr(args.options, 'j'))
2782 if (ast_strlen_zero(args.interface)) {
2783 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2784 LOCAL_USER_REMOVE(lu);
2788 if (set_member_paused(args.queuename, args.interface, 1)) {
2789 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
2790 if (priority_jump || ast_opt_priority_jumping) {
2791 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2792 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2793 LOCAL_USER_REMOVE(lu);
2797 LOCAL_USER_REMOVE(lu);
2798 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
2802 LOCAL_USER_REMOVE(lu);
2803 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
2807 static int upqm_exec(struct ast_channel *chan, void *data)
2809 struct localuser *lu;
2811 int priority_jump = 0;
2812 AST_DECLARE_APP_ARGS(args,
2813 AST_APP_ARG(queuename);
2814 AST_APP_ARG(interface);
2815 AST_APP_ARG(options);
2818 if (ast_strlen_zero(data)) {
2819 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
2823 if (!(parse = ast_strdupa(data)))
2826 AST_STANDARD_APP_ARGS(args, parse);
2831 if (strchr(args.options, 'j'))
2835 if (ast_strlen_zero(args.interface)) {
2836 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
2837 LOCAL_USER_REMOVE(lu);
2841 if (set_member_paused(args.queuename, args.interface, 0)) {
2842 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
2843 if (priority_jump || ast_opt_priority_jumping) {
2844 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
2845 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2846 LOCAL_USER_REMOVE(lu);
2850 LOCAL_USER_REMOVE(lu);
2851 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
2855 LOCAL_USER_REMOVE(lu);
2856 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
2860 static int rqm_exec(struct ast_channel *chan, void *data)
2863 struct localuser *lu;
2864 char *parse, *temppos = NULL;
2865 int priority_jump = 0;
2866 AST_DECLARE_APP_ARGS(args,
2867 AST_APP_ARG(queuename);
2868 AST_APP_ARG(interface);
2869 AST_APP_ARG(options);
2873 if (ast_strlen_zero(data)) {
2874 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
2878 if (!(parse = ast_strdupa(data)))
2881 AST_STANDARD_APP_ARGS(args, parse);
2885 if (ast_strlen_zero(args.interface)) {
2886 args.interface = ast_strdupa(chan->name);
2887 temppos = strrchr(args.interface, '-');
2893 if (strchr(args.options, 'j'))
2897 switch (remove_from_queue(args.queuename, args.interface)) {
2899 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
2900 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
2904 ast_log(LOG_WARNING, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
2905 if (priority_jump || ast_opt_priority_jumping)
2906 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2907 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
2910 case RES_NOSUCHQUEUE:
2911 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
2912 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
2915 case RES_OUTOFMEMORY:
2916 ast_log(LOG_ERROR, "Out of memory\n");
2920 LOCAL_USER_REMOVE(lu);
2924 static int aqm_exec(struct ast_channel *chan, void *data)
2927 struct localuser *lu;
2928 char *parse, *temppos = NULL;
2929 int priority_jump = 0;
2930 AST_DECLARE_APP_ARGS(args,
2931 AST_APP_ARG(queuename);
2932 AST_APP_ARG(interface);
2933 AST_APP_ARG(penalty);
2934 AST_APP_ARG(options);
2938 if (ast_strlen_zero(data)) {
2939 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options]])\n");
2943 if (!(parse = ast_strdupa(data)))
2946 AST_STANDARD_APP_ARGS(args, parse);
2950 if (ast_strlen_zero(args.interface)) {
2951 args.interface = ast_strdupa(chan->name);
2952 temppos = strrchr(args.interface, '-');
2957 if (!ast_strlen_zero(args.penalty)) {
2958 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
2959 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
2965 if (strchr(args.options, 'j'))
2970 switch (add_to_queue(args.queuename, args.interface, penalty, 0, queue_persistent_members)) {
2972 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
2973 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
2977 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
2978 if (priority_jump || ast_opt_priority_jumping)
2979 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2980 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
2983 case RES_NOSUCHQUEUE:
2984 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
2985 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
2988 case RES_OUTOFMEMORY:
2989 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
2993 LOCAL_USER_REMOVE(lu);
2997 static int queue_exec(struct ast_channel *chan, void *data)
3001 struct localuser *lu;
3002 const char *user_priority;
3003 const char *max_penalty_str;
3006 enum queue_result reason = QUEUE_UNKNOWN;
3008 /* whether to exit Queue application after the timeout hits */
3012 AST_DECLARE_APP_ARGS(args,
3013 AST_APP_ARG(queuename);
3014 AST_APP_ARG(options);
3016 AST_APP_ARG(announceoverride);
3017 AST_APP_ARG(queuetimeoutstr);
3021 /* Our queue entry */
3022 struct queue_ent qe;
3024 if (ast_strlen_zero(data)) {
3025 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL][|announceoverride][|timeout]]\n");
3029 parse = ast_strdupa(data);
3031 ast_log(LOG_ERROR, "Out of memory!\n");
3034 AST_STANDARD_APP_ARGS(args, parse);
3038 /* Setup our queue entry */
3039 memset(&qe, 0, sizeof(qe));
3040 qe.start = time(NULL);
3042 /* set the expire time based on the supplied timeout; */
3043 if (args.queuetimeoutstr)
3044 qe.expire = qe.start + atoi(args.queuetimeoutstr);
3048 /* Get the priority from the variable ${QUEUE_PRIO} */
3049 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
3050 if (user_priority) {
3051 if (sscanf(user_priority, "%d", &prio) == 1) {
3053 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
3056 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
3057 user_priority, chan->name);
3061 if (option_debug > 2)
3062 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
3066 /* Get the maximum penalty from the variable ${QUEUE_MAX_PENALTY} */
3067 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
3068 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
3070 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
3071 chan->name, max_penalty);
3073 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
3074 max_penalty_str, chan->name);
3081 if (args.options && (strchr(args.options, 'r')))
3085 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
3086 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
3090 qe.max_penalty = max_penalty;
3091 qe.last_pos_said = 0;
3093 qe.last_periodic_announce_time = time(NULL);
3094 qe.last_periodic_announce_sound = 0;
3095 if (!join_queue(args.queuename, &qe, &reason)) {
3096 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
3097 S_OR(chan->cid.cid_num, ""));
3100 ast_indicate(chan, AST_CONTROL_RINGING);
3102 ast_moh_start(chan, qe.moh);
3105 /* This is the wait loop for callers 2 through maxlen */
3107 res = wait_our_turn(&qe, ringing, &reason);
3108 /* If they hungup, return immediately */
3110 /* Record this abandoned call */
3111 record_abandoned(&qe);
3112 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3113 if (option_verbose > 2) {
3114 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s while waiting their turn\n", args.queuename);
3121 if (valid_exit(&qe, res)) {
3122 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3127 int makeannouncement = 0;
3129 /* This is the wait loop for the head caller*/
3130 /* To exit, they may get their call answered; */
3131 /* they may dial a digit from the queue context; */
3132 /* or, they may timeout. */
3134 enum queue_member_status stat;
3136 /* Leave if we have exceeded our queuetimeout */
3137 if (qe.expire && (time(NULL) > qe.expire)) {
3138 record_abandoned(&qe);
3139 reason = QUEUE_TIMEOUT;
3141 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3145 if (makeannouncement) {
3146 /* Make a position announcement, if enabled */
3147 if (qe.parent->announcefrequency && !ringing)
3148 res = say_position(&qe);
3150 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3155 makeannouncement = 1;
3157 /* Make a periodic announcement, if enabled */
3158 if (qe.parent->periodicannouncefrequency && !ringing)
3159 res = say_periodic_announcement(&qe);
3161 if (res && valid_exit(&qe, res)) {
3162 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos);
3166 /* Try calling all queue members for 'timeout' seconds */
3167 res = try_calling(&qe, args.options, args.announceoverride, args.url, &go_on, args.agi);
3172 record_abandoned(&qe);
3173 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3176 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3180 stat = get_member_status(qe.parent, qe.max_penalty);
3182 /* leave the queue if no agents, if enabled */
3183 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
3184 record_abandoned(&qe);
3185 reason = QUEUE_LEAVEEMPTY;
3190 /* leave the queue if no reachable agents, if enabled */
3191 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
3192 record_abandoned(&qe);
3193 reason = QUEUE_LEAVEUNAVAIL;
3198 /* Leave if we have exceeded our queuetimeout */
3199 if (qe.expire && (time(NULL) > qe.expire)) {
3200 record_abandoned(&qe);
3201 reason = QUEUE_TIMEOUT;
3203 ast_queue_log(args.queuename, chan->uniqueid,"NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3207 /* OK, we didn't get anybody; wait for 'retry' seconds; may get a digit to exit with */
3208 res = wait_a_bit(&qe);
3210 record_abandoned(&qe);
3211 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON", "%d|%d|%ld", qe.pos, qe.opos, (long)time(NULL) - qe.start);
3212 if (option_verbose > 2) {
3213 ast_verbose(VERBOSE_PREFIX_3 "User disconnected from queue %s when they almost made it\n", args.queuename);
3218 if (res && valid_exit(&qe, res)) {
3219 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%s|%d", qe.digits, qe.pos);
3222 /* exit after 'timeout' cycle if 'n' option enabled */
3224 if (option_verbose > 2)
3225 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
3226 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
3227 record_abandoned(&qe);
3228 reason = QUEUE_TIMEOUT;
3232 /* Since this is a priority queue and
3233 * it is not sure that we are still at the head
3234 * of the queue, go and check for our turn again.
3236 if (!is_our_turn(&qe)) {
3238 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
3244 /* Don't allow return code > 0 */
3245 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
3248 ast_indicate(chan, -1);
3252 ast_stopstream(chan);
3255 if (reason != QUEUE_UNKNOWN)
3256 set_queue_result(chan, reason);
3258 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
3259 set_queue_result(chan, reason);
3262 LOCAL_USER_REMOVE(lu);
3266 static int queue_function_qac(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
3269 struct ast_call_queue *q;
3270 struct localuser *lu;
3275 if (ast_strlen_zero(data)) {
3276 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);