convert the final clients of ast_build_string to use ast_str_*()
[asterisk/asterisk.git] / apps / app_queue.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief True call queues with optional send URL on answer
22  *
23  * \author Mark Spencer <markster@digium.com>
24  *
25  * \arg Config in \ref Config_qu queues.conf
26  *
27  * \par Development notes
28  * \note 2004-11-25: Persistent Dynamic Members added by:
29  *             NetNation Communications (www.netnation.com)
30  *             Kevin Lindsay <kevinl@netnation.com>
31  *
32  *             Each dynamic agent in each queue is now stored in the astdb.
33  *             When asterisk is restarted, each agent will be automatically
34  *             readded into their recorded queues. This feature can be
35  *             configured with the 'persistent_members=<1|0>' setting in the
36  *             '[general]' category in queues.conf. The default is on.
37  *
38  * \note 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr).
39  *
40  * \note These features added by David C. Troy <dave@toad.net>:
41  *    - Per-queue holdtime calculation
42  *    - Estimated holdtime announcement
43  *    - Position announcement
44  *    - Abandoned/completed call counters
45  *    - Failout timer passed as optional app parameter
46  *    - Optional monitoring of calls, started when call is answered
47  *
48  * Patch Version 1.07 2003-12-24 01
49  *
50  * Added servicelevel statistic by Michiel Betel <michiel@betel.nl>
51  * Added Priority jumping code for adding and removing queue members by Jonathan Stanton <asterisk@doilooklikeicare.com>
52  *
53  * Fixed to work with CVS as of 2004-02-25 and released as 1.07a
54  * by Matthew Enger <m.enger@xi.com.au>
55  *
56  * \ingroup applications
57  */
58
59 #include "asterisk.h"
60
61 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
62
63 #include <stdlib.h>
64 #include <errno.h>
65 #include <unistd.h>
66 #include <string.h>
67 #include <stdlib.h>
68 #include <stdio.h>
69 #include <sys/time.h>
70 #include <sys/signal.h>
71 #include <netinet/in.h>
72
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
96 enum {
97         QUEUE_STRATEGY_RINGALL = 0,
98         QUEUE_STRATEGY_LEASTRECENT,
99         QUEUE_STRATEGY_FEWESTCALLS,
100         QUEUE_STRATEGY_RANDOM,
101         QUEUE_STRATEGY_RRMEMORY
102 };
103
104 static struct strategy {
105         int strategy;
106         char *name;
107 } strategies[] = {
108         { QUEUE_STRATEGY_RINGALL, "ringall" },
109         { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
110         { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
111         { QUEUE_STRATEGY_RANDOM, "random" },
112         { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
113 };
114
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 */
119
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 */
124
125 static char *app = "Queue";
126
127 static char *synopsis = "Queue a call for a call queue";
128
129 static char *descrip =
130 "  Queue(queuename[|options[|URL][|announceoverride][|timeout][|AGI][|macro]):\n"
131 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
132 "This application will return to the dialplan if the queue does not exist, or\n"
133 "any of the join options cause the caller to not enter the queue.\n"
134 "The option string may contain zero or more of the following characters:\n"
135 "      'd' -- data-quality (modem) call (minimum delay).\n"
136 "      'h' -- allow callee to hang up by hitting *.\n"
137 "      'H' -- allow caller to hang up by hitting *.\n"
138 "      'n' -- no retries on the timeout; will exit this application and \n"
139 "             go to the next step.\n"
140 "      'i' -- ignore call forward requests from queue members and do nothing\n"
141 "             when they are requested.\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"
150 "it.\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 optional macro parameter will run a macro on the \n"
154 "calling party's channel once they are connected to a queue member.\n"
155 "  The timeout will cause the queue to fail out after a specified number of\n"
156 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
157 "  This application sets the following channel variable upon completion:\n"
158 "      QUEUESTATUS    The status of the call as a text string, one of\n"
159 "             TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
160
161 static char *app_aqm = "AddQueueMember" ;
162 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
163 static char *app_aqm_descrip =
164 "   AddQueueMember(queuename[|interface[|penalty[|options]]]):\n"
165 "Dynamically adds interface to an existing queue.\n"
166 "If the interface is already in the queue and there exists an n+101 priority\n"
167 "then it will then jump to this priority.  Otherwise it will return an error\n"
168 "The option string may contain zero or more of the following characters:\n"
169 "       'j' -- jump to +101 priority when appropriate.\n"
170 "  This application sets the following channel variable upon completion:\n"
171 "     AQMSTATUS    The status of the attempt to add a queue member as a \n"
172 "                     text string, one of\n"
173 "           ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
174 "Example: AddQueueMember(techsupport|SIP/3000)\n"
175 "";
176
177 static char *app_rqm = "RemoveQueueMember" ;
178 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
179 static char *app_rqm_descrip =
180 "   RemoveQueueMember(queuename[|interface[|options]]):\n"
181 "Dynamically removes interface to an existing queue\n"
182 "If the interface is NOT in the queue and there exists an n+101 priority\n"
183 "then it will then jump to this priority.  Otherwise it will return an error\n"
184 "The option string may contain zero or more of the following characters:\n"
185 "       'j' -- jump to +101 priority when appropriate.\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"
191 "";
192
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.  If the interface is not in the named queue, or if no queue\n"
203 "is given and the interface is not in any queue, it will jump to\n"
204 "priority n+101, if it exists and the appropriate options are set.\n"
205 "The application will fail if the interface is not found and no extension\n"
206 "to jump to exists.\n"
207 "The option string may contain zero or more of the following characters:\n"
208 "       'j' -- jump to +101 priority when appropriate.\n"
209 "  This application sets the following channel variable upon completion:\n"
210 "     PQMSTATUS      The status of the attempt to pause a queue member as a\n"
211 "                     text string, one of\n"
212 "           PAUSED | NOTFOUND\n"
213 "Example: PauseQueueMember(|SIP/3000)\n";
214
215 static char *app_upqm = "UnpauseQueueMember" ;
216 static char *app_upqm_synopsis = "Unpauses a queue member" ;
217 static char *app_upqm_descrip =
218 "   UnpauseQueueMember([queuename]|interface[|options]):\n"
219 "Unpauses (resumes calls to) a queue member.\n"
220 "This is the counterpart to PauseQueueMember and operates exactly the\n"
221 "same way, except it unpauses instead of pausing the given interface.\n"
222 "The option string may contain zero or more of the following characters:\n"
223 "       'j' -- jump to +101 priority when appropriate.\n"
224 "  This application sets the following channel variable upon completion:\n"
225 "     UPQMSTATUS       The status of the attempt to unpause a queue \n"
226 "                      member as a text string, one of\n"
227 "            UNPAUSED | NOTFOUND\n"
228 "Example: UnpauseQueueMember(|SIP/3000)\n";
229
230 static char *app_ql = "QueueLog" ;
231 static char *app_ql_synopsis = "Writes to the queue_log" ;
232 static char *app_ql_descrip =
233 "   QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n"
234 "Allows you to write your own events into the queue log\n"
235 "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n";
236
237 /*! \brief Persistent Members astdb family */
238 static const char *pm_family = "/Queue/PersistentMembers";
239 /* The maximum length of each persistent member queue database entry */
240 #define PM_MAX_LEN 8192
241
242 /*! \brief queues.conf [general] option */
243 static int queue_keep_stats = 0;
244
245 /*! \brief queues.conf [general] option */
246 static int queue_persistent_members = 0;
247
248 /*! \brief queues.conf per-queue weight option */
249 static int use_weight = 0;
250
251 /*! \brief queues.conf [general] option */
252 static int autofill_default = 0;
253
254 /*! \brief queues.conf [general] option */
255 static int montype_default = 0;
256
257 enum queue_result {
258         QUEUE_UNKNOWN = 0,
259         QUEUE_TIMEOUT = 1,
260         QUEUE_JOINEMPTY = 2,
261         QUEUE_LEAVEEMPTY = 3,
262         QUEUE_JOINUNAVAIL = 4,
263         QUEUE_LEAVEUNAVAIL = 5,
264         QUEUE_FULL = 6,
265 };
266
267 const struct {
268         enum queue_result id;
269         char *text;
270 } queue_results[] = {
271         { QUEUE_UNKNOWN, "UNKNOWN" },
272         { QUEUE_TIMEOUT, "TIMEOUT" },
273         { QUEUE_JOINEMPTY,"JOINEMPTY" },
274         { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
275         { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
276         { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
277         { QUEUE_FULL, "FULL" },
278 };
279
280 /*! \brief We define a custom "local user" structure because we
281    use it not only for keeping track of what is in use but
282    also for keeping track of who we're dialing. */
283
284 struct callattempt {
285         struct callattempt *q_next;
286         struct ast_channel *chan;
287         char interface[256];
288         int stillgoing;
289         int metric;
290         int oldstatus;
291         time_t lastcall;
292         struct member *member;
293 };
294
295
296 struct queue_ent {
297         struct call_queue *parent;          /*!< What queue is our parent */
298         char moh[80];                       /*!< Name of musiconhold to be used */
299         char announce[80];                  /*!< Announcement to play for member when call is answered */
300         char context[AST_MAX_CONTEXT];      /*!< Context when user exits queue */
301         char digits[AST_MAX_EXTENSION];     /*!< Digits entered while in queue */
302         int pos;                            /*!< Where we are in the queue */
303         int prio;                           /*!< Our priority */
304         int last_pos_said;                  /*!< Last position we told the user */
305         time_t last_periodic_announce_time; /*!< The last time we played a periodic announcement */
306         int last_periodic_announce_sound;   /*!< The last periodic announcement we made */
307         time_t last_pos;                    /*!< Last time we told the user their position */
308         int opos;                           /*!< Where we started in the queue */
309         int handled;                        /*!< Whether our call was handled */
310         int max_penalty;                    /*!< Limit the members that can take this call to this penalty or lower */
311         time_t start;                       /*!< When we started holding */
312         time_t expire;                      /*!< When this entry should expire (time out of queue) */
313         struct ast_channel *chan;           /*!< Our channel */
314         struct queue_ent *next;             /*!< The next queue entry */
315 };
316
317 struct member {
318         char interface[80];                 /*!< Technology/Location */
319         char membername[80];                /*!< Member name to use in queue logs */
320         int penalty;                        /*!< Are we a last resort? */
321         int calls;                          /*!< Number of calls serviced by this member */
322         int dynamic;                        /*!< Are we dynamically added? */
323         int status;                         /*!< Status of queue member */
324         int paused;                         /*!< Are we paused (not accepting calls)? */
325         time_t lastcall;                    /*!< When last successful call was hungup */
326         unsigned int dead:1;                /*!< Used to detect members deleted in realtime */
327         unsigned int delme:1;               /*!< Flag to delete entry on reload */
328         struct member *next;                /*!< Next member */
329 };
330
331 struct member_interface {
332         char interface[80];
333         AST_LIST_ENTRY(member_interface) list;    /*!< Next call queue */
334 };
335
336 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
337
338 /* values used in multi-bit flags in call_queue */
339 #define QUEUE_EMPTY_NORMAL 1
340 #define QUEUE_EMPTY_STRICT 2
341 #define QUEUE_EMPTY_LOOSE 3
342 #define ANNOUNCEHOLDTIME_ALWAYS 1
343 #define ANNOUNCEHOLDTIME_ONCE 2
344 #define QUEUE_EVENT_VARIABLES 3
345
346 struct call_queue {
347         ast_mutex_t lock;       
348         char name[80];                      /*!< Name */
349         char moh[80];                       /*!< Music On Hold class to be used */
350         char announce[80];                  /*!< Announcement to play when call is answered */
351         char context[AST_MAX_CONTEXT];      /*!< Exit context */
352         unsigned int monjoin:1;
353         unsigned int dead:1;
354         unsigned int joinempty:2;
355         unsigned int eventwhencalled:2;
356         unsigned int leavewhenempty:2;
357         unsigned int ringinuse:1;
358         unsigned int setinterfacevar:1;
359         unsigned int setqueuevar:1;
360         unsigned int setqueueentryvar:1;
361         unsigned int reportholdtime:1;
362         unsigned int wrapped:1;
363         unsigned int timeoutrestart:1;
364         unsigned int announceholdtime:2;
365         unsigned int strategy:3;
366         unsigned int maskmemberstatus:1;
367         unsigned int realtime:1;
368         int announcefrequency;              /*!< How often to announce their position */
369         int periodicannouncefrequency;      /*!< How often to play periodic announcement */
370         int roundingseconds;                /*!< How many seconds do we round to? */
371         int holdtime;                       /*!< Current avg holdtime, based on recursive boxcar filter */
372         int callscompleted;                 /*!< Number of queue calls completed */
373         int callsabandoned;                 /*!< Number of queue calls abandoned */
374         int servicelevel;                   /*!< seconds setting for servicelevel*/
375         int callscompletedinsl;             /*!< Number of calls answered with servicelevel*/
376         char monfmt[8];                     /*!< Format to use when recording calls */
377         int montype;                        /*!< Monitor type  Monitor vs. MixMonitor */
378         char membermacro[32];               /*!< Macro to run upon member connection */
379         char sound_next[80];                /*!< Sound file: "Your call is now first in line" (def. queue-youarenext) */
380         char sound_thereare[80];            /*!< Sound file: "There are currently" (def. queue-thereare) */
381         char sound_calls[80];               /*!< Sound file: "calls waiting to speak to a representative." (def. queue-callswaiting)*/
382         char sound_holdtime[80];            /*!< Sound file: "The current estimated total holdtime is" (def. queue-holdtime) */
383         char sound_minutes[80];             /*!< Sound file: "minutes." (def. queue-minutes) */
384         char sound_lessthan[80];            /*!< Sound file: "less-than" (def. queue-lessthan) */
385         char sound_seconds[80];             /*!< Sound file: "seconds." (def. queue-seconds) */
386         char sound_thanks[80];              /*!< Sound file: "Thank you for your patience." (def. queue-thankyou) */
387         char sound_reporthold[80];          /*!< Sound file: "Hold time" (def. queue-reporthold) */
388         char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];/*!< Sound files: Custom announce, no default */
389
390         int count;                          /*!< How many entries */
391         int maxlen;                         /*!< Max number of entries */
392         int wrapuptime;                     /*!< Wrapup Time */
393
394         int retry;                          /*!< Retry calling everyone after this amount of time */
395         int timeout;                        /*!< How long to wait for an answer */
396         int weight;                         /*!< Respective weight */
397         int autopause;                      /*!< Auto pause queue members if they fail to answer */
398
399         /* Queue strategy things */
400         int rrpos;                          /*!< Round Robin - position */
401         int memberdelay;                    /*!< Seconds to delay connecting member to caller */
402         int autofill;                       /*!< Ignore the head call status and ring an available agent */
403         
404         struct member *members;             /*!< Head of the list of members */
405         struct queue_ent *head;             /*!< Head of the list of callers */
406         AST_LIST_ENTRY(call_queue) list;    /*!< Next call queue */
407 };
408
409 static AST_LIST_HEAD_STATIC(queues, call_queue);
410
411 static int set_member_paused(char *queuename, char *interface, int paused);
412
413 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
414 {
415         int i;
416
417         for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
418                 if (queue_results[i].id == res) {
419                         pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
420                         return;
421                 }
422         }
423 }
424
425 static char *int2strat(int strategy)
426 {
427         int x;
428
429         for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
430                 if (strategy == strategies[x].strategy)
431                         return strategies[x].name;
432         }
433
434         return "<unknown>";
435 }
436
437 static int strat2int(const char *strategy)
438 {
439         int x;
440
441         for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
442                 if (!strcasecmp(strategy, strategies[x].name))
443                         return strategies[x].strategy;
444         }
445
446         return -1;
447 }
448
449 static void set_queue_variables(struct queue_ent *qe)
450 {
451
452         char interfacevar[256]="";
453         float sl = 0;
454         
455         if (qe->parent->setqueuevar) {
456         sl = 0;
457         if (qe->parent->callscompleted > 0) 
458                 sl = 100 * ((float) qe->parent->callscompletedinsl / (float) qe->parent->callscompleted);
459
460         snprintf(interfacevar,sizeof(interfacevar),
461                 "QUEUEMAX=%d|QUEUESTRATEGY=%s|QUEUECALLS=%d|QUEUEHOLDTIME=%d|QUEUECOMPLETED=%d|QUEUEABANDONED=%d|QUEUESRVLEVEL=%d|QUEUESRVLEVELPERF=%2.1f",
462                 qe->parent->maxlen, int2strat(qe->parent->strategy), qe->parent->count, qe->parent->holdtime, qe->parent->callscompleted,
463                 qe->parent->callsabandoned,  qe->parent->servicelevel, sl);
464         
465         pbx_builtin_setvar(qe->chan, interfacevar); 
466         }
467 }
468
469 /*! \brief Insert the 'new' entry after the 'prev' entry of queue 'q' */
470 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
471 {
472         struct queue_ent *cur;
473
474         if (!q || !new)
475                 return;
476         if (prev) {
477                 cur = prev->next;
478                 prev->next = new;
479         } else {
480                 cur = q->head;
481                 q->head = new;
482         }
483         new->next = cur;
484         new->parent = q;
485         new->pos = ++(*pos);
486         new->opos = *pos;
487 }
488
489 enum queue_member_status {
490         QUEUE_NO_MEMBERS,
491         QUEUE_NO_REACHABLE_MEMBERS,
492         QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS,
493         QUEUE_NORMAL
494 };
495
496 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
497 {
498         struct member *member;
499         enum queue_member_status result = QUEUE_NO_MEMBERS;
500
501         ast_mutex_lock(&q->lock);
502         for (member = q->members; member; member = member->next) {
503                 if (max_penalty && (member->penalty > max_penalty))
504                         continue;
505
506                 switch (member->status) {
507                 case AST_DEVICE_INVALID:
508                         /* nothing to do */
509                         break;
510                 case AST_DEVICE_UNAVAILABLE:
511                         if (result != QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS) 
512                                 result = QUEUE_NO_REACHABLE_MEMBERS;
513                         break;
514                 default:
515                         if (member->paused) {
516                                 result = QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS;
517                         } else {
518                                 ast_mutex_unlock(&q->lock);
519                                 return QUEUE_NORMAL;
520                         }
521                         break;
522                 }
523         }
524         
525         ast_mutex_unlock(&q->lock);
526         return result;
527 }
528
529 struct statechange {
530         int state;
531         char dev[0];
532 };
533
534 static void *changethread(void *data)
535 {
536         struct call_queue *q;
537         struct statechange *sc = data;
538         struct member *cur;
539         struct member_interface *curint;
540         char *loc;
541         char *technology;
542
543         technology = ast_strdupa(sc->dev);
544         loc = strchr(technology, '/');
545         if (loc) {
546                 *loc++ = '\0';
547         } else {
548                 free(sc);
549                 return NULL;
550         }
551
552         AST_LIST_LOCK(&interfaces);
553         AST_LIST_TRAVERSE(&interfaces, curint, list) {
554                 char *interface;
555                 char *slash_pos;
556                 interface = ast_strdupa(curint->interface);
557                 if ((slash_pos = strchr(interface, '/')))
558                         if ((slash_pos = strchr(slash_pos + 1, '/')))
559                                 *slash_pos = '\0';
560
561                 if (!strcasecmp(interface, sc->dev))
562                         break;
563         }
564         AST_LIST_UNLOCK(&interfaces);
565
566         if (!curint) {
567                 if (option_debug)
568                         ast_log(LOG_DEBUG, "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                 free(sc);
570                 return NULL;
571         }
572
573         if (option_debug)
574                 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
575         AST_LIST_LOCK(&queues);
576         AST_LIST_TRAVERSE(&queues, q, list) {
577                 ast_mutex_lock(&q->lock);
578                 for (cur = q->members; cur; cur = cur->next) {
579                         char *interface;
580                         char *slash_pos;
581                         interface = ast_strdupa(cur->interface);
582                         if ((slash_pos = strchr(interface, '/')))
583                                 if ((slash_pos = strchr(slash_pos + 1, '/')))
584                                         *slash_pos = '\0';
585
586                         if (strcasecmp(sc->dev, interface))
587                                 continue;
588
589                         if (cur->status != sc->state) {
590                                 cur->status = sc->state;
591                                 if (q->maskmemberstatus)
592                                         continue;
593
594                                 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
595                                         "Queue: %s\r\n"
596                                         "Location: %s\r\n"
597                                         "MemberName: %s\r\n"
598                                         "Membership: %s\r\n"
599                                         "Penalty: %d\r\n"
600                                         "CallsTaken: %d\r\n"
601                                         "LastCall: %d\r\n"
602                                         "Status: %d\r\n"
603                                         "Paused: %d\r\n",
604                                         q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
605                                         cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
606                         }
607                 }
608                 ast_mutex_unlock(&q->lock);
609         }
610         AST_LIST_UNLOCK(&queues);
611
612         return NULL;
613 }
614
615 static int statechange_queue(const char *dev, int state, void *ign)
616 {
617         /* Avoid potential for deadlocks by spawning a new thread to handle
618            the event */
619         struct statechange *sc;
620         pthread_t t;
621         pthread_attr_t attr;
622
623         if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
624                 return 0;
625
626         sc->state = state;
627         strcpy(sc->dev, dev);
628         pthread_attr_init(&attr);
629         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
630         if (ast_pthread_create_background(&t, &attr, changethread, sc)) {
631                 ast_log(LOG_WARNING, "Failed to create update thread!\n");
632                 free(sc);
633         }
634
635         return 0;
636 }
637
638 static struct member *create_queue_member(char *interface, const char *membername, int penalty, int paused)
639 {
640         struct member *cur;
641         
642         if ((cur = ast_calloc(1, sizeof(*cur)))) {
643                 cur->penalty = penalty;
644                 cur->paused = paused;
645                 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
646                 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
647                 if (!strchr(cur->interface, '/'))
648                         ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
649                 cur->status = ast_device_state(interface);
650         }
651
652         return cur;
653 }
654
655 static struct call_queue *alloc_queue(const char *queuename)
656 {
657         struct call_queue *q;
658
659         if ((q = ast_calloc(1, sizeof(*q)))) {
660                 ast_mutex_init(&q->lock);
661                 ast_copy_string(q->name, queuename, sizeof(q->name));
662         }
663         return q;
664 }
665
666 static void init_queue(struct call_queue *q)
667 {
668         int i;
669
670         q->dead = 0;
671         q->retry = DEFAULT_RETRY;
672         q->timeout = -1;
673         q->maxlen = 0;
674         q->announcefrequency = 0;
675         q->announceholdtime = 0;
676         q->roundingseconds = 0; /* Default - don't announce seconds */
677         q->servicelevel = 0;
678         q->ringinuse = 1;
679         q->setinterfacevar = 0;
680         q->setqueuevar = 0;
681         q->setqueueentryvar = 0;
682         q->autofill = autofill_default;
683         q->montype = montype_default;
684         q->membermacro[0] = '\0';
685         q->moh[0] = '\0';
686         q->announce[0] = '\0';
687         q->context[0] = '\0';
688         q->monfmt[0] = '\0';
689         q->periodicannouncefrequency = 0;
690         ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
691         ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
692         ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
693         ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
694         ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
695         ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
696         ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
697         ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
698         ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
699         ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
700         for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
701                 q->sound_periodicannounce[i][0]='\0';
702         }
703 }
704
705 static void clear_queue(struct call_queue *q)
706 {
707         q->holdtime = 0;
708         q->callscompleted = 0;
709         q->callsabandoned = 0;
710         q->callscompletedinsl = 0;
711         q->wrapuptime = 0;
712 }
713
714 static int add_to_interfaces(char *interface)
715 {
716         struct member_interface *curint;
717
718         AST_LIST_LOCK(&interfaces);
719         AST_LIST_TRAVERSE(&interfaces, curint, list) {
720                 if (!strcasecmp(curint->interface, interface))
721                         break;
722         }
723
724         if (curint) {
725                 AST_LIST_UNLOCK(&interfaces);
726                 return 0;
727         }
728
729         if (option_debug)
730                 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
731         
732         if ((curint = ast_calloc(1, sizeof(*curint)))) {
733                 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
734                 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
735         }
736         AST_LIST_UNLOCK(&interfaces);
737
738         return 0;
739 }
740
741 static int interface_exists_global(char *interface)
742 {
743         struct call_queue *q;
744         struct member *mem;
745         int ret = 0;
746
747         AST_LIST_LOCK(&queues);
748         AST_LIST_TRAVERSE(&queues, q, list) {
749                 ast_mutex_lock(&q->lock);
750                 for (mem = q->members; mem && !ret; mem = mem->next) {
751                         if (!strcasecmp(interface, mem->interface))
752                                 ret = 1;
753                 }
754                 ast_mutex_unlock(&q->lock);
755                 if (ret)
756                         break;
757         }
758         AST_LIST_UNLOCK(&queues);
759
760         return ret;
761 }
762
763 static int remove_from_interfaces(char *interface)
764 {
765         struct member_interface *curint;
766
767         AST_LIST_LOCK(&interfaces);
768         AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
769                 if (!strcasecmp(curint->interface, interface)) {
770                         if (!interface_exists_global(interface)) {
771                                 if (option_debug)
772                                         ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
773                                 AST_LIST_REMOVE_CURRENT(&interfaces, list);
774                                 free(curint);
775                         }
776                         break;
777                 }
778         }
779         AST_LIST_TRAVERSE_SAFE_END;
780         AST_LIST_UNLOCK(&interfaces);
781
782         return 0;
783 }
784
785 static void clear_and_free_interfaces(void)
786 {
787         struct member_interface *curint;
788
789         AST_LIST_LOCK(&interfaces);
790         while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
791                 free(curint);
792         AST_LIST_UNLOCK(&interfaces);
793 }
794
795 /*! \brief Configure a queue parameter.
796 \par
797    For error reporting, line number is passed for .conf static configuration.
798    For Realtime queues, linenum is -1.
799    The failunknown flag is set for config files (and static realtime) to show
800    errors for unknown parameters. It is cleared for dynamic realtime to allow
801    extra fields in the tables. */
802 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
803 {
804         if (!strcasecmp(param, "musicclass") || 
805                 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
806                 ast_copy_string(q->moh, val, sizeof(q->moh));
807         } else if (!strcasecmp(param, "announce")) {
808                 ast_copy_string(q->announce, val, sizeof(q->announce));
809         } else if (!strcasecmp(param, "context")) {
810                 ast_copy_string(q->context, val, sizeof(q->context));
811         } else if (!strcasecmp(param, "timeout")) {
812                 q->timeout = atoi(val);
813                 if (q->timeout < 0)
814                         q->timeout = DEFAULT_TIMEOUT;
815         } else if (!strcasecmp(param, "ringinuse")) {
816                 q->ringinuse = ast_true(val);
817         } else if (!strcasecmp(param, "setinterfacevar")) {
818                 q->setinterfacevar = ast_true(val);
819         } else if (!strcasecmp(param, "setqueuevar")) {
820                 q->setqueuevar = ast_true(val);
821         } else if (!strcasecmp(param, "setqueueentryvar")) {
822                 q->setqueueentryvar = ast_true(val);
823         } else if (!strcasecmp(param, "monitor-join")) {
824                 q->monjoin = ast_true(val);
825         } else if (!strcasecmp(param, "monitor-format")) {
826                 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
827         } else if (!strcasecmp(param, "membermacro")) {
828                 ast_copy_string(q->membermacro, val, sizeof(q->membermacro));
829         } else if (!strcasecmp(param, "queue-youarenext")) {
830                 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
831         } else if (!strcasecmp(param, "queue-thereare")) {
832                 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
833         } else if (!strcasecmp(param, "queue-callswaiting")) {
834                 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
835         } else if (!strcasecmp(param, "queue-holdtime")) {
836                 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
837         } else if (!strcasecmp(param, "queue-minutes")) {
838                 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
839         } else if (!strcasecmp(param, "queue-seconds")) {
840                 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
841         } else if (!strcasecmp(param, "queue-lessthan")) {
842                 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
843         } else if (!strcasecmp(param, "queue-thankyou")) {
844                 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
845         } else if (!strcasecmp(param, "queue-reporthold")) {
846                 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
847         } else if (!strcasecmp(param, "announce-frequency")) {
848                 q->announcefrequency = atoi(val);
849         } else if (!strcasecmp(param, "announce-round-seconds")) {
850                 q->roundingseconds = atoi(val);
851                 if (q->roundingseconds>60 || q->roundingseconds<0) {
852                         if (linenum >= 0) {
853                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
854                                         "using 0 instead for queue '%s' at line %d of queues.conf\n",
855                                         val, param, q->name, linenum);
856                         } else {
857                                 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
858                                         "using 0 instead for queue '%s'\n", val, param, q->name);
859                         }
860                         q->roundingseconds=0;
861                 }
862         } else if (!strcasecmp(param, "announce-holdtime")) {
863                 if (!strcasecmp(val, "once"))
864                         q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
865                 else if (ast_true(val))
866                         q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
867                 else
868                         q->announceholdtime = 0;
869         } else if (!strcasecmp(param, "periodic-announce")) {
870                 if (strchr(val, '|')) {
871                         char *s, *buf = ast_strdupa(val);
872                         unsigned int i = 0;
873
874                         while ((s = strsep(&buf, "|"))) {
875                                 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
876                                 i++;
877                                 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
878                                         break;
879                         }
880                 } else {
881                         ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
882                 }
883         } else if (!strcasecmp(param, "periodic-announce-frequency")) {
884                 q->periodicannouncefrequency = atoi(val);
885         } else if (!strcasecmp(param, "retry")) {
886                 q->retry = atoi(val);
887                 if (q->retry <= 0)
888                         q->retry = DEFAULT_RETRY;
889         } else if (!strcasecmp(param, "wrapuptime")) {
890                 q->wrapuptime = atoi(val);
891         } else if (!strcasecmp(param, "autofill")) {
892                 q->autofill = ast_true(val);
893         } else if (!strcasecmp(param, "monitor-type")) {
894                 if (!strcasecmp(val, "mixmonitor"))
895                         q->montype = 1;
896         } else if (!strcasecmp(param, "autopause")) {
897                 q->autopause = ast_true(val);
898         } else if (!strcasecmp(param, "maxlen")) {
899                 q->maxlen = atoi(val);
900                 if (q->maxlen < 0)
901                         q->maxlen = 0;
902         } else if (!strcasecmp(param, "servicelevel")) {
903                 q->servicelevel= atoi(val);
904         } else if (!strcasecmp(param, "strategy")) {
905                 q->strategy = strat2int(val);
906                 if (q->strategy < 0) {
907                         ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
908                                 val, q->name);
909                         q->strategy = QUEUE_STRATEGY_RINGALL;
910                 }
911         } else if (!strcasecmp(param, "joinempty")) {
912                 if (!strcasecmp(val, "loose"))
913                         q->joinempty = QUEUE_EMPTY_LOOSE;
914                 else if (!strcasecmp(val, "strict"))
915                         q->joinempty = QUEUE_EMPTY_STRICT;
916                 else if (ast_true(val))
917                         q->joinempty = QUEUE_EMPTY_NORMAL;
918                 else
919                         q->joinempty = 0;
920         } else if (!strcasecmp(param, "leavewhenempty")) {
921                 if (!strcasecmp(val, "loose"))
922                         q->leavewhenempty = QUEUE_EMPTY_LOOSE;
923                 else if (!strcasecmp(val, "strict"))
924                         q->leavewhenempty = QUEUE_EMPTY_STRICT;
925                 else if (ast_true(val))
926                         q->leavewhenempty = QUEUE_EMPTY_NORMAL;
927                 else
928                         q->leavewhenempty = 0;
929         } else if (!strcasecmp(param, "eventmemberstatus")) {
930                 q->maskmemberstatus = !ast_true(val);
931         } else if (!strcasecmp(param, "eventwhencalled")) {
932                 if (!strcasecmp(val, "vars")) {
933                         q->eventwhencalled = QUEUE_EVENT_VARIABLES;
934                 } else {
935                         q->eventwhencalled = ast_true(val);
936                 }
937         } else if (!strcasecmp(param, "reportholdtime")) {
938                 q->reportholdtime = ast_true(val);
939         } else if (!strcasecmp(param, "memberdelay")) {
940                 q->memberdelay = atoi(val);
941         } else if (!strcasecmp(param, "weight")) {
942                 q->weight = atoi(val);
943                 if (q->weight)
944                         use_weight++;
945                 /* With Realtime queues, if the last queue using weights is deleted in realtime,
946                    we will not see any effect on use_weight until next reload. */
947         } else if (!strcasecmp(param, "timeoutrestart")) {
948                 q->timeoutrestart = ast_true(val);
949         } else if (failunknown) {
950                 if (linenum >= 0) {
951                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
952                                 q->name, param, linenum);
953                 } else {
954                         ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
955                 }
956         }
957 }
958
959 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str)
960 {
961         struct member *m, *prev_m;
962         int penalty = 0;
963
964         if (penalty_str) {
965                 penalty = atoi(penalty_str);
966                 if (penalty < 0)
967                         penalty = 0;
968         }
969
970         /* Find the member, or the place to put a new one. */
971         for (m = q->members, prev_m = NULL;
972                 m && strcmp(m->interface, interface);
973                 prev_m = m, m = m->next);
974
975         /* Create a new one if not found, else update penalty */
976         if (!m) {
977                 if ((m = create_queue_member(interface, membername, penalty, 0))) {
978                         m->dead = 0;
979                         add_to_interfaces(interface);
980                         if (prev_m) {
981                                 prev_m->next = m;
982                         } else {
983                                 q->members = m;
984                         }
985                 }
986         } else {
987                 m->dead = 0;    /* Do not delete this one. */
988                 m->penalty = penalty;
989         }
990 }
991
992 static void free_members(struct call_queue *q, int all)
993 {
994         /* Free non-dynamic members */
995         struct member *curm, *next, *prev = NULL;
996
997         for (curm = q->members; curm; curm = next) {
998                 next = curm->next;
999                 if (all || !curm->dynamic) {
1000                         if (prev)
1001                                 prev->next = next;
1002                         else
1003                                 q->members = next;
1004                         remove_from_interfaces(curm->interface);
1005                         free(curm);
1006                 } else
1007                         prev = curm;
1008         }
1009 }
1010
1011 static void destroy_queue(struct call_queue *q)
1012 {
1013         free_members(q, 1);
1014         ast_mutex_destroy(&q->lock);
1015         free(q);
1016 }
1017
1018 /*!\brief Reload a single queue via realtime.
1019    \return Return the queue, or NULL if it doesn't exist.
1020    \note Should be called with the global qlock locked. */
1021 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1022 {
1023         struct ast_variable *v;
1024         struct call_queue *q;
1025         struct member *m, *prev_m, *next_m;
1026         char *interface = NULL;
1027         char *tmp, *tmp_name;
1028         char tmpbuf[64];        /* Must be longer than the longest queue param name. */
1029
1030         /* Find the queue in the in-core list (we will create a new one if not found). */
1031         AST_LIST_TRAVERSE(&queues, q, list) {
1032                 if (!strcasecmp(q->name, queuename))
1033                         break;
1034         }
1035
1036         /* Static queues override realtime. */
1037         if (q) {
1038                 ast_mutex_lock(&q->lock);
1039                 if (!q->realtime) {
1040                         if (q->dead) {
1041                                 ast_mutex_unlock(&q->lock);
1042                                 return NULL;
1043                         } else {
1044                                 ast_mutex_unlock(&q->lock);
1045                                 return q;
1046                         }
1047                 }
1048         } else if (!member_config)
1049                 /* Not found in the list, and it's not realtime ... */
1050                 return NULL;
1051
1052         /* Check if queue is defined in realtime. */
1053         if (!queue_vars) {
1054                 /* Delete queue from in-core list if it has been deleted in realtime. */
1055                 if (q) {
1056                         /*! \note Hmm, can't seem to distinguish a DB failure from a not
1057                            found condition... So we might delete an in-core queue
1058                            in case of DB failure. */
1059                         if (option_debug)
1060                                 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
1061
1062                         q->dead = 1;
1063                         /* Delete if unused (else will be deleted when last caller leaves). */
1064                         if (!q->count) {
1065                                 /* Delete. */
1066                                 AST_LIST_REMOVE(&queues, q, list);
1067                                 ast_mutex_unlock(&q->lock);
1068                                 destroy_queue(q);
1069                         } else
1070                                 ast_mutex_unlock(&q->lock);
1071                 }
1072                 return NULL;
1073         }
1074
1075         /* Create a new queue if an in-core entry does not exist yet. */
1076         if (!q) {
1077                 if (!(q = alloc_queue(queuename)))
1078                         return NULL;
1079                 ast_mutex_lock(&q->lock);
1080                 clear_queue(q);
1081                 q->realtime = 1;
1082                 AST_LIST_INSERT_HEAD(&queues, q, list);
1083         }
1084         init_queue(q);          /* Ensure defaults for all parameters not set explicitly. */
1085
1086         memset(tmpbuf, 0, sizeof(tmpbuf));
1087         for (v = queue_vars; v; v = v->next) {
1088                 /* Convert to dashes `-' from underscores `_' as the latter are more SQL friendly. */
1089                 if ((tmp = strchr(v->name, '_'))) {
1090                         ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
1091                         tmp_name = tmpbuf;
1092                         tmp = tmp_name;
1093                         while ((tmp = strchr(tmp, '_')))
1094                                 *tmp++ = '-';
1095                 } else
1096                         tmp_name = v->name;
1097                 queue_set_param(q, tmp_name, v->value, -1, 0);
1098         }
1099
1100         /* Temporarily set non-dynamic members dead so we can detect deleted ones. */
1101         for (m = q->members; m; m = m->next) {
1102                 if (!m->dynamic)
1103                         m->dead = 1;
1104         }
1105
1106         while ((interface = ast_category_browse(member_config, interface))) {
1107                 rt_handle_member_record(q, interface,
1108                         S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1109                         ast_variable_retrieve(member_config, interface, "penalty"));
1110         }
1111
1112         /* Delete all realtime members that have been deleted in DB. */
1113         m = q->members;
1114         prev_m = NULL;
1115         while (m) {
1116                 next_m = m->next;
1117                 if (m->dead) {
1118                         if (prev_m) {
1119                                 prev_m->next = next_m;
1120                         } else {
1121                                 q->members = next_m;
1122                         }
1123                         remove_from_interfaces(m->interface);
1124                         free(m);
1125                 } else {
1126                         prev_m = m;
1127                 }
1128                 m = next_m;
1129         }
1130
1131         ast_mutex_unlock(&q->lock);
1132
1133         return q;
1134 }
1135
1136 static struct call_queue *load_realtime_queue(char *queuename)
1137 {
1138         struct ast_variable *queue_vars;
1139         struct ast_config *member_config = NULL;
1140         struct call_queue *q;
1141
1142         /* Find the queue in the in-core list first. */
1143         AST_LIST_LOCK(&queues);
1144         AST_LIST_TRAVERSE(&queues, q, list) {
1145                 if (!strcasecmp(q->name, queuename)) {
1146                         break;
1147                 }
1148         }
1149         AST_LIST_UNLOCK(&queues);
1150
1151         if (!q || q->realtime) {
1152                 /*! \note Load from realtime before taking the global qlock, to avoid blocking all
1153                    queue operations while waiting for the DB.
1154
1155                    This will be two separate database transactions, so we might
1156                    see queue parameters as they were before another process
1157                    changed the queue and member list as it was after the change.
1158                    Thus we might see an empty member list when a queue is
1159                    deleted. In practise, this is unlikely to cause a problem. */
1160
1161                 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
1162                 if (queue_vars) {
1163                         member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
1164                         if (!member_config) {
1165                                 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
1166                                 return NULL;
1167                         }
1168                 }
1169
1170                 AST_LIST_LOCK(&queues);
1171
1172                 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
1173                 if (member_config)
1174                         ast_config_destroy(member_config);
1175                 if (queue_vars)
1176                         ast_variables_destroy(queue_vars);
1177
1178                 AST_LIST_UNLOCK(&queues);
1179         }
1180         return q;
1181 }
1182
1183 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
1184 {
1185         struct call_queue *q;
1186         struct queue_ent *cur, *prev = NULL;
1187         int res = -1;
1188         int pos = 0;
1189         int inserted = 0;
1190         enum queue_member_status stat;
1191
1192         if (!(q = load_realtime_queue(queuename)))
1193                 return res;
1194
1195         AST_LIST_LOCK(&queues);
1196         ast_mutex_lock(&q->lock);
1197
1198         /* This is our one */
1199         stat = get_member_status(q, qe->max_penalty);
1200         if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
1201                 *reason = QUEUE_JOINEMPTY;
1202         else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS))
1203                 *reason = QUEUE_JOINUNAVAIL;
1204         else if ((q->joinempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS))
1205                 *reason = QUEUE_JOINUNAVAIL;
1206         else if (q->maxlen && (q->count >= q->maxlen))
1207                 *reason = QUEUE_FULL;
1208         else {
1209                 /* There's space for us, put us at the right position inside
1210                  * the queue.
1211                  * Take into account the priority of the calling user */
1212                 inserted = 0;
1213                 prev = NULL;
1214                 cur = q->head;
1215                 while (cur) {
1216                         /* We have higher priority than the current user, enter
1217                          * before him, after all the other users with priority
1218                          * higher or equal to our priority. */
1219                         if ((!inserted) && (qe->prio > cur->prio)) {
1220                                 insert_entry(q, prev, qe, &pos);
1221                                 inserted = 1;
1222                         }
1223                         cur->pos = ++pos;
1224                         prev = cur;
1225                         cur = cur->next;
1226                 }
1227                 /* No luck, join at the end of the queue */
1228                 if (!inserted)
1229                         insert_entry(q, prev, qe, &pos);
1230                 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
1231                 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
1232                 ast_copy_string(qe->context, q->context, sizeof(qe->context));
1233                 q->count++;
1234                 res = 0;
1235                 manager_event(EVENT_FLAG_CALL, "Join",
1236                         "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
1237                         qe->chan->name,
1238                         S_OR(qe->chan->cid.cid_num, "unknown"), /* XXX somewhere else it is <unknown> */
1239                         S_OR(qe->chan->cid.cid_name, "unknown"),
1240                         q->name, qe->pos, q->count, qe->chan->uniqueid );
1241                 if (option_debug)
1242                         ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
1243         }
1244         ast_mutex_unlock(&q->lock);
1245         AST_LIST_UNLOCK(&queues);
1246
1247         return res;
1248 }
1249
1250 static int play_file(struct ast_channel *chan, char *filename)
1251 {
1252         int res;
1253
1254         ast_stopstream(chan);
1255         res = ast_streamfile(chan, filename, chan->language);
1256         if (!res)
1257                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1258         ast_stopstream(chan);
1259
1260         return res;
1261 }
1262
1263 static int valid_exit(struct queue_ent *qe, char digit)
1264 {
1265         int digitlen = strlen(qe->digits);
1266
1267         /* Prevent possible buffer overflow */
1268         if (digitlen < sizeof(qe->digits) - 2) {
1269                 qe->digits[digitlen] = digit;
1270                 qe->digits[digitlen + 1] = '\0';
1271         } else {
1272                 qe->digits[0] = '\0';
1273                 return 0;
1274         }
1275
1276         /* If there's no context to goto, short-circuit */
1277         if (ast_strlen_zero(qe->context))
1278                 return 0;
1279
1280         /* If the extension is bad, then reset the digits to blank */
1281         if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
1282                 qe->digits[0] = '\0';
1283                 return 0;
1284         }
1285
1286         /* We have an exact match */
1287         if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
1288                 /* Return 1 on a successful goto */
1289                 return 1;
1290         }
1291
1292         return 0;
1293 }
1294
1295 static int say_position(struct queue_ent *qe)
1296 {
1297         int res = 0, avgholdmins, avgholdsecs;
1298         time_t now;
1299
1300         /* Check to see if this is ludicrous -- if we just announced position, don't do it again*/
1301         time(&now);
1302         if ((now - qe->last_pos) < 15)
1303                 return 0;
1304
1305         /* If either our position has changed, or we are over the freq timer, say position */
1306         if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
1307                 return 0;
1308
1309         ast_moh_stop(qe->chan);
1310         /* Say we're next, if we are */
1311         if (qe->pos == 1) {
1312                 res = play_file(qe->chan, qe->parent->sound_next);
1313                 if (res && valid_exit(qe, res))
1314                         goto playout;
1315                 else
1316                         goto posout;
1317         } else {
1318                 res = play_file(qe->chan, qe->parent->sound_thereare);
1319                 if (res && valid_exit(qe, res))
1320                         goto playout;
1321                 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */
1322                 if (res && valid_exit(qe, res))
1323                         goto playout;
1324                 res = play_file(qe->chan, qe->parent->sound_calls);
1325                 if (res && valid_exit(qe, res))
1326                         goto playout;
1327         }
1328         /* Round hold time to nearest minute */
1329         avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
1330
1331         /* If they have specified a rounding then round the seconds as well */
1332         if (qe->parent->roundingseconds) {
1333                 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
1334                 avgholdsecs *= qe->parent->roundingseconds;
1335         } else {
1336                 avgholdsecs = 0;
1337         }
1338
1339         if (option_verbose > 2)
1340                 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
1341
1342         /* If the hold time is >1 min, if it's enabled, and if it's not
1343            supposed to be only once and we have already said it, say it */
1344         if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
1345                 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
1346                 res = play_file(qe->chan, qe->parent->sound_holdtime);
1347                 if (res && valid_exit(qe, res))
1348                         goto playout;
1349
1350                 if (avgholdmins > 0) {
1351                         if (avgholdmins < 2) {
1352                                 res = play_file(qe->chan, qe->parent->sound_lessthan);
1353                                 if (res && valid_exit(qe, res))
1354                                         goto playout;
1355
1356                                 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
1357                                 if (res && valid_exit(qe, res))
1358                                         goto playout;
1359                         } else {
1360                                 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
1361                                 if (res && valid_exit(qe, res))
1362                                         goto playout;
1363                         }
1364                         
1365                         res = play_file(qe->chan, qe->parent->sound_minutes);
1366                         if (res && valid_exit(qe, res))
1367                                 goto playout;
1368                 }
1369                 if (avgholdsecs>0) {
1370                         res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
1371                         if (res && valid_exit(qe, res))
1372                                 goto playout;
1373
1374                         res = play_file(qe->chan, qe->parent->sound_seconds);
1375                         if (res && valid_exit(qe, res))
1376                                 goto playout;
1377                 }
1378
1379         }
1380
1381 posout:
1382         if (option_verbose > 2)
1383                 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
1384                         qe->chan->name, qe->parent->name, qe->pos);
1385         res = play_file(qe->chan, qe->parent->sound_thanks);
1386         if (res && !valid_exit(qe, res))
1387                 res = 0;
1388
1389 playout:
1390         /* Set our last_pos indicators */
1391         qe->last_pos = now;
1392         qe->last_pos_said = qe->pos;
1393
1394         /* Don't restart music on hold if we're about to exit the caller from the queue */
1395         if (!res)
1396                 ast_moh_start(qe->chan, qe->moh, NULL);
1397
1398         return res;
1399 }
1400
1401 static void recalc_holdtime(struct queue_ent *qe)
1402 {
1403         int oldvalue, newvalue;
1404
1405         /* Calculate holdtime using a recursive boxcar filter */
1406         /* Thanks to SRT for this contribution */
1407         /* 2^2 (4) is the filter coefficient; a higher exponent would give old entries more weight */
1408
1409         newvalue = time(NULL) - qe->start;
1410
1411         ast_mutex_lock(&qe->parent->lock);
1412         if (newvalue <= qe->parent->servicelevel)
1413                 qe->parent->callscompletedinsl++;
1414         oldvalue = qe->parent->holdtime;
1415         qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newvalue) >> 2;
1416         ast_mutex_unlock(&qe->parent->lock);
1417 }
1418
1419
1420 static void leave_queue(struct queue_ent *qe)
1421 {
1422         struct call_queue *q;
1423         struct queue_ent *cur, *prev = NULL;
1424         int pos = 0;
1425
1426         if (!(q = qe->parent))
1427                 return;
1428         ast_mutex_lock(&q->lock);
1429
1430         prev = NULL;
1431         for (cur = q->head; cur; cur = cur->next) {
1432                 if (cur == qe) {
1433                         q->count--;
1434
1435                         /* Take us out of the queue */
1436                         manager_event(EVENT_FLAG_CALL, "Leave",
1437                                 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
1438                                 qe->chan->name, q->name,  q->count, qe->chan->uniqueid);
1439                         if (option_debug)
1440                                 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
1441                         /* Take us out of the queue */
1442                         if (prev)
1443                                 prev->next = cur->next;
1444                         else
1445                                 q->head = cur->next;
1446                 } else {
1447                         /* Renumber the people after us in the queue based on a new count */
1448                         cur->pos = ++pos;
1449                         prev = cur;
1450                 }
1451         }
1452         ast_mutex_unlock(&q->lock);
1453
1454         if (q->dead && !q->count) {     
1455                 /* It's dead and nobody is in it, so kill it */
1456                 AST_LIST_LOCK(&queues);
1457                 AST_LIST_REMOVE(&queues, q, list);
1458                 AST_LIST_UNLOCK(&queues);
1459                 destroy_queue(q);
1460         }
1461 }
1462
1463 /* Hang up a list of outgoing calls */
1464 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
1465 {
1466         struct callattempt *oo;
1467
1468         while (outgoing) {
1469                 /* Hangup any existing lines we have open */
1470                 if (outgoing->chan && (outgoing->chan != exception))
1471                         ast_hangup(outgoing->chan);
1472                 oo = outgoing;
1473                 outgoing = outgoing->q_next;
1474                 free(oo);
1475         }
1476 }
1477
1478 static int update_status(struct call_queue *q, struct member *member, int status)
1479 {
1480         struct member *cur;
1481
1482         /* Since a reload could have taken place, we have to traverse the list to
1483                 be sure it's still valid */
1484         ast_mutex_lock(&q->lock);
1485         for (cur = q->members; cur; cur = cur->next) {
1486                 if (member != cur)
1487                         continue;
1488
1489                 cur->status = status;
1490                 if (!q->maskmemberstatus) {
1491                         manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
1492                                 "Queue: %s\r\n"
1493                                 "Location: %s\r\n"
1494                                 "MemberName: %s\r\n"
1495                                 "Membership: %s\r\n"
1496                                 "Penalty: %d\r\n"
1497                                 "CallsTaken: %d\r\n"
1498                                 "LastCall: %d\r\n"
1499                                 "Status: %d\r\n"
1500                                 "Paused: %d\r\n",
1501                                 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : "static",
1502                                 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
1503                 }
1504         }
1505         ast_mutex_unlock(&q->lock);
1506         return 0;
1507 }
1508
1509 static int update_dial_status(struct call_queue *q, struct member *member, int status)
1510 {
1511         if (status == AST_CAUSE_BUSY)
1512                 status = AST_DEVICE_BUSY;
1513         else if (status == AST_CAUSE_UNREGISTERED)
1514                 status = AST_DEVICE_UNAVAILABLE;
1515         else if (status == AST_CAUSE_NOSUCHDRIVER)
1516                 status = AST_DEVICE_INVALID;
1517         else
1518                 status = AST_DEVICE_UNKNOWN;
1519         return update_status(q, member, status);
1520 }
1521
1522 /* traverse all defined queues which have calls waiting and contain this member
1523    return 0 if no other queue has precedence (higher weight) or 1 if found  */
1524 static int compare_weight(struct call_queue *rq, struct member *member)
1525 {
1526         struct call_queue *q;
1527         struct member *mem;
1528         int found = 0;
1529         
1530         /* &qlock and &rq->lock already set by try_calling()
1531          * to solve deadlock */
1532         AST_LIST_TRAVERSE(&queues, q, list) {
1533                 if (q == rq) /* don't check myself, could deadlock */
1534                         continue;
1535                 ast_mutex_lock(&q->lock);
1536                 if (q->count && q->members) {
1537                         for (mem = q->members; mem; mem = mem->next) {
1538                                 if (strcmp(mem->interface, member->interface))
1539                                         continue;
1540
1541                                 if (option_debug)
1542                                         ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
1543                                 if (q->weight > rq->weight) {
1544                                         if (option_debug)
1545                                                 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);
1546                                         found = 1;
1547                                         break;
1548                                 }
1549                         }
1550                 }
1551                 ast_mutex_unlock(&q->lock);
1552                 if (found)
1553                         break;
1554         }
1555         return found;
1556 }
1557
1558 /*! \brief common hangup actions */
1559 static void do_hang(struct callattempt *o)
1560 {
1561         o->stillgoing = 0;
1562         ast_hangup(o->chan);
1563         o->chan = NULL;
1564 }
1565
1566 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
1567 {
1568         struct ast_str *buf = ast_str_alloca(len + 1);
1569         char *tmp;
1570
1571         if (pbx_builtin_serialize_variables(chan, &buf)) {
1572                 int i, j;
1573
1574                 /* convert "\n" to "\nVariable: " */
1575                 strcpy(vars, "Variable: ");
1576                 tmp = buf->str;
1577
1578                 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
1579                         vars[j] = tmp[i];
1580
1581                         if (tmp[i + 1] == '\0')
1582                                 break;
1583                         if (tmp[i] == '\n') {
1584                                 vars[j] = '\r';
1585                                 vars[++j] = '\n';
1586
1587                                 ast_copy_string(&(vars[j]), "Variable: ", len - j);
1588                                 j += 9;
1589                         }
1590                 }
1591                 if (j > len - 1)
1592                         j = len - 1;
1593                 vars[j - 2] = '\r';
1594                 vars[j - 1] = '\n';
1595                 vars[j] = '\0';
1596         } else {
1597                 /* there are no channel variables; leave it blank */
1598                 *vars = '\0';
1599         }
1600         return vars;
1601 }
1602
1603 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1604 {
1605         int res;
1606         int status;
1607         char tech[256];
1608         char *location;
1609
1610         /* on entry here, we know that tmp->chan == NULL */
1611         if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
1612                 if (option_debug)
1613                         ast_log(LOG_DEBUG, "Wrapuptime not yet expired for %s\n", tmp->interface);
1614                 if (qe->chan->cdr)
1615                         ast_cdr_busy(qe->chan->cdr);
1616                 tmp->stillgoing = 0;
1617                 (*busies)++;
1618                 return 0;
1619         }
1620
1621         if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
1622                 if (option_debug)
1623                         ast_log(LOG_DEBUG, "%s in use, can't receive call\n", tmp->interface);
1624                 if (qe->chan->cdr)
1625                         ast_cdr_busy(qe->chan->cdr);
1626                 tmp->stillgoing = 0;
1627                 return 0;
1628         }
1629
1630         if (tmp->member->paused) {
1631                 if (option_debug)
1632                         ast_log(LOG_DEBUG, "%s paused, can't receive call\n", tmp->interface);
1633                 if (qe->chan->cdr)
1634                         ast_cdr_busy(qe->chan->cdr);
1635                 tmp->stillgoing = 0;
1636                 return 0;
1637         }
1638         if (use_weight && compare_weight(qe->parent,tmp->member)) {
1639                 if (option_debug)
1640                         ast_log(LOG_DEBUG, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
1641                 if (qe->chan->cdr)
1642                         ast_cdr_busy(qe->chan->cdr);
1643                 tmp->stillgoing = 0;
1644                 (*busies)++;
1645                 return 0;
1646         }
1647
1648         ast_copy_string(tech, tmp->interface, sizeof(tech));
1649         if ((location = strchr(tech, '/')))
1650                 *location++ = '\0';
1651         else
1652                 location = "";
1653
1654         /* Request the peer */
1655         tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
1656         if (!tmp->chan) {                       /* If we can't, just go on to the next call */
1657                 if (qe->chan->cdr)
1658                         ast_cdr_busy(qe->chan->cdr);
1659                 tmp->stillgoing = 0;
1660                 update_dial_status(qe->parent, tmp->member, status);
1661
1662                 ast_mutex_lock(&qe->parent->lock);
1663                 qe->parent->rrpos++;
1664                 ast_mutex_unlock(&qe->parent->lock);
1665
1666                 (*busies)++;
1667                 return 0;
1668         } else if (status != tmp->oldstatus)
1669                 update_dial_status(qe->parent, tmp->member, status);
1670         
1671         tmp->chan->appl = "AppQueue";
1672         tmp->chan->data = "(Outgoing Line)";
1673         tmp->chan->whentohangup = 0;
1674         if (tmp->chan->cid.cid_num)
1675                 free(tmp->chan->cid.cid_num);
1676         tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
1677         if (tmp->chan->cid.cid_name)
1678                 free(tmp->chan->cid.cid_name);
1679         tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
1680         if (tmp->chan->cid.cid_ani)
1681                 free(tmp->chan->cid.cid_ani);
1682         tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
1683
1684         /* Inherit specially named variables from parent channel */
1685         ast_channel_inherit_variables(qe->chan, tmp->chan);
1686
1687         /* Presense of ADSI CPE on outgoing channel follows ours */
1688         tmp->chan->adsicpe = qe->chan->adsicpe;
1689
1690         /* Place the call, but don't wait on the answer */
1691         if ((res = ast_call(tmp->chan, location, 0))) {
1692                 /* Again, keep going even if there's an error */
1693                 if (option_debug)
1694                         ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
1695                 if (option_verbose > 2)
1696                         ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
1697                 do_hang(tmp);
1698                 (*busies)++;
1699                 return 0;
1700         } else if (qe->parent->eventwhencalled) {
1701                 char vars[2048];
1702
1703                 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
1704                                         "AgentCalled: %s\r\n"
1705                                         "ChannelCalling: %s\r\n"
1706                                         "CallerIDNum: %s\r\n"
1707                                         "CallerIDName: %s\r\n"
1708                                         "Context: %s\r\n"
1709                                         "Extension: %s\r\n"
1710                                         "Priority: %d\r\n"
1711                                         "%s",
1712                                         tmp->interface, qe->chan->name,
1713                                         tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
1714                                         tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
1715                                         qe->chan->context, qe->chan->exten, qe->chan->priority,
1716                                         qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
1717                 if (option_verbose > 2)
1718                         ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
1719         }
1720
1721         return 1;
1722 }
1723
1724 /*! \brief find the entry with the best metric, or NULL */
1725 static struct callattempt *find_best(struct callattempt *outgoing)
1726 {
1727         struct callattempt *best = NULL, *cur;
1728
1729         for (cur = outgoing; cur; cur = cur->q_next) {
1730                 if (cur->stillgoing &&                                  /* Not already done */
1731                         !cur->chan &&                                   /* Isn't already going */
1732                         (!best || cur->metric < best->metric)) {                /* We haven't found one yet, or it's better */
1733                         best = cur;
1734                 }
1735         }
1736
1737         return best;
1738 }
1739
1740 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
1741 {
1742         int ret = 0;
1743
1744         while (ret == 0) {
1745                 struct callattempt *best = find_best(outgoing);
1746                 if (!best) {
1747                         if (option_debug)
1748                                 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
1749                         break;
1750                 }
1751                 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
1752                         struct callattempt *cur;
1753                         /* Ring everyone who shares this best metric (for ringall) */
1754                         for (cur = outgoing; cur; cur = cur->q_next) {
1755                                 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
1756                                         if (option_debug)
1757                                                 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
1758                                         ring_entry(qe, cur, busies);
1759                                 }
1760                         }
1761                 } else {
1762                         /* Ring just the best channel */
1763                         if (option_debug)
1764                                 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
1765                         ring_entry(qe, best, busies);
1766                 }
1767                 if (best->chan) /* break out with result = 1 */
1768                         ret = 1;
1769         }
1770
1771         return ret;
1772 }
1773
1774 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
1775 {
1776         struct callattempt *best = find_best(outgoing);
1777
1778         if (best) {
1779                 /* Ring just the best channel */
1780                 if (option_debug)
1781                         ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
1782                 qe->parent->rrpos = best->metric % 1000;
1783         } else {
1784                 /* Just increment rrpos */
1785                 if (qe->parent->wrapped) {
1786                         /* No more channels, start over */
1787                         qe->parent->rrpos = 0;
1788                 } else {
1789                         /* Prioritize next entry */
1790                         qe->parent->rrpos++;
1791                 }
1792         }
1793         qe->parent->wrapped = 0;
1794
1795         return 0;
1796 }
1797
1798 static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename)
1799 {
1800         int res;
1801
1802         ast_stopstream(chan);
1803         res = ast_streamfile(chan, filename, chan->language);
1804
1805         if (!res) {
1806                 /* Wait for a keypress */
1807                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1808                 if (res < 0 || !valid_exit(qe, res))
1809                         res = 0;
1810
1811                 /* Stop playback */
1812                 ast_stopstream(chan);
1813         }
1814         
1815         return res;
1816 }
1817
1818 static int say_periodic_announcement(struct queue_ent *qe)
1819 {
1820         int res = 0;
1821         time_t now;
1822
1823         /* Get the current time */
1824         time(&now);
1825
1826         /* Check to see if it is time to announce */
1827         if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
1828                 return 0;
1829
1830         /* Stop the music on hold so we can play our own file */
1831         ast_moh_stop(qe->chan);
1832
1833         if (option_verbose > 2)
1834                 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
1835
1836         /* Check to make sure we have a sound file. If not, reset to the first sound file */
1837         if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
1838                 qe->last_periodic_announce_sound = 0;
1839         }
1840         
1841         /* play the announcement */
1842         res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
1843
1844         /* Resume Music on Hold if the caller is going to stay in the queue */
1845         if (!res)
1846                 ast_moh_start(qe->chan, qe->moh, NULL);
1847
1848         /* update last_periodic_announce_time */
1849         qe->last_periodic_announce_time = now;
1850
1851         /* Update the current periodic announcement to the next announcement */
1852         qe->last_periodic_announce_sound++;
1853         
1854         return res;
1855 }
1856
1857 static void record_abandoned(struct queue_ent *qe)
1858 {
1859         ast_mutex_lock(&qe->parent->lock);
1860         set_queue_variables(qe);
1861         manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
1862                 "Queue: %s\r\n"
1863                 "Uniqueid: %s\r\n"
1864                 "Position: %d\r\n"
1865                 "OriginalPosition: %d\r\n"
1866                 "HoldTime: %d\r\n",
1867                 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
1868
1869         qe->parent->callsabandoned++;
1870         ast_mutex_unlock(&qe->parent->lock);
1871 }
1872
1873 /*! \brief RNA == Ring No Answer. Common code that is executed when we try a queue member and they don't answer. */
1874 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
1875 {
1876         if (option_verbose > 2)
1877                 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
1878         ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
1879         if (qe->parent->autopause) {
1880                 if (!set_member_paused(qe->parent->name, interface, 1)) {
1881                         if (option_verbose > 2)
1882                                 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
1883                 } else {
1884                         if (option_verbose > 2)
1885                                 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
1886                 }
1887         }
1888         return;
1889 }
1890
1891 #define AST_MAX_WATCHERS 256
1892
1893 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
1894 {
1895         char *queue = qe->parent->name;
1896         struct callattempt *o;
1897         int status;
1898         int sentringing = 0;
1899         int numbusies = prebusies;
1900         int numnochan = 0;
1901         int stillgoing = 0;
1902         int orig = *to;
1903         struct ast_frame *f;
1904         struct callattempt *peer = NULL;
1905         struct ast_channel *winner;
1906         struct ast_channel *in = qe->chan;
1907         char on[80] = "";
1908         char membername[80] = "";
1909         long starttime = 0;
1910         long endtime = 0;       
1911
1912         starttime = (long) time(NULL);
1913         
1914         while (*to && !peer) {
1915                 int numlines, retry, pos = 1;
1916                 struct ast_channel *watchers[AST_MAX_WATCHERS];
1917                 watchers[0] = in;
1918
1919                 for (retry = 0; retry < 2; retry++) {
1920                         numlines = 0;
1921                         for (o = outgoing; o; o = o->q_next) { /* Keep track of important channels */
1922                                 if (o->stillgoing) {    /* Keep track of important channels */
1923                                         stillgoing = 1;
1924                                         if (o->chan)
1925                                                 watchers[pos++] = o->chan;
1926                                 }
1927                                 numlines++;
1928                         }
1929                         if (pos > 1 /* found */ || !stillgoing /* nobody listening */ ||
1930                                 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) /* ring would not be delivered */)
1931                                 break;
1932                         /* On "ringall" strategy we only move to the next penalty level
1933                            when *all* ringing phones are done in the current penalty level */
1934                         ring_one(qe, outgoing, &numbusies);
1935                         /* and retry... */
1936                 }
1937                 if (pos == 1 /* not found */) {
1938                         if (numlines == (numbusies + numnochan)) {
1939                                 if (option_debug)
1940                                         ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
1941                         } else {
1942                                 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
1943                         }
1944                         *to = 0;
1945                         return NULL;
1946                 }
1947                 winner = ast_waitfor_n(watchers, pos, to);
1948                 for (o = outgoing; o; o = o->q_next) {
1949                         if (o->stillgoing && (o->chan) &&  (o->chan->_state == AST_STATE_UP)) {
1950                                 if (!peer) {
1951                                         if (option_verbose > 2)
1952                                                 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
1953                                         peer = o;
1954                                 }
1955                         } else if (o->chan && (o->chan == winner)) {
1956
1957                                 ast_copy_string(on, o->member->interface, sizeof(on));
1958                                 ast_copy_string(membername, o->member->membername, sizeof(membername));
1959
1960                                 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
1961                                         if (option_verbose > 2)
1962                                                 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
1963                                         winner = o->chan = NULL;
1964                                 } else if (!ast_strlen_zero(o->chan->call_forward)) {
1965                                         char tmpchan[256];
1966                                         char *stuff;
1967                                         char *tech;
1968
1969                                         ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
1970                                         if ((stuff = strchr(tmpchan, '/'))) {
1971                                                 *stuff++ = '\0';
1972                                                 tech = tmpchan;
1973                                         } else {
1974                                                 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
1975                                                 stuff = tmpchan;
1976                                                 tech = "Local";
1977                                         }
1978                                         /* Before processing channel, go ahead and check for forwarding */
1979                                         if (option_verbose > 2)
1980                                                 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
1981                                         /* Setup parameters */
1982                                         o->chan = ast_request(tech, in->nativeformats, stuff, &status);
1983                                         if (status != o->oldstatus)
1984                                                 update_dial_status(qe->parent, o->member, status);                                              
1985                                         if (!o->chan) {
1986                                                 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
1987                                                 o->stillgoing = 0;
1988                                                 numnochan++;
1989                                         } else {
1990                                                 ast_channel_inherit_variables(in, o->chan);
1991                                                 if (o->chan->cid.cid_num)
1992                                                         free(o->chan->cid.cid_num);
1993                                                 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
1994
1995                                                 if (o->chan->cid.cid_name)
1996                                                         free(o->chan->cid.cid_name);
1997                                                 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
1998
1999                                                 ast_string_field_set(o->chan, accountcode, in->accountcode);
2000                                                 o->chan->cdrflags = in->cdrflags;
2001
2002                                                 if (in->cid.cid_ani) {
2003                                                         if (o->chan->cid.cid_ani)
2004                                                                 free(o->chan->cid.cid_ani);
2005                                                         o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
2006                                                 }
2007                                                 if (o->chan->cid.cid_rdnis)
2008                                                         free(o->chan->cid.cid_rdnis);
2009                                                 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
2010                                                 if (ast_call(o->chan, tmpchan, 0)) {
2011                                                         ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
2012                                                         do_hang(o);
2013                                                         numnochan++;
2014                                                 }
2015                                         }
2016                                         /* Hangup the original channel now, in case we needed it */
2017                                         ast_hangup(winner);
2018                                         continue;
2019                                 }
2020                                 f = ast_read(winner);
2021                                 if (f) {
2022                                         if (f->frametype == AST_FRAME_CONTROL) {
2023                                                 switch (f->subclass) {
2024                                                 case AST_CONTROL_ANSWER:
2025                                                         /* This is our guy if someone answered. */
2026                                                         if (!peer) {
2027                                                                 if (option_verbose > 2)
2028                                                                         ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
2029                                                                 peer = o;
2030                                                         }
2031                                                         break;
2032                                                 case AST_CONTROL_BUSY:
2033                                                         if (option_verbose > 2)
2034                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
2035                                                         if (in->cdr)
2036                                                                 ast_cdr_busy(in->cdr);
2037                                                         do_hang(o);
2038                                                         endtime = (long)time(NULL);
2039                                                         endtime -= starttime;
2040                                                         rna(endtime*1000, qe, on, membername);
2041                                                         if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2042                                                                 if (qe->parent->timeoutrestart)
2043                                                                         *to = orig;
2044                                                                 ring_one(qe, outgoing, &numbusies);
2045                                                         }
2046                                                         numbusies++;
2047                                                         break;
2048                                                 case AST_CONTROL_CONGESTION:
2049                                                         if (option_verbose > 2)
2050                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
2051                                                         if (in->cdr)
2052                                                                 ast_cdr_busy(in->cdr);
2053                                                         endtime = (long)time(NULL);
2054                                                         endtime -= starttime;
2055                                                         rna(endtime*1000, qe, on, membername);
2056                                                         do_hang(o);
2057                                                         if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2058                                                                 if (qe->parent->timeoutrestart)
2059                                                                         *to = orig;
2060                                                                 ring_one(qe, outgoing, &numbusies);
2061                                                         }
2062                                                         numbusies++;
2063                                                         break;
2064                                                 case AST_CONTROL_RINGING:
2065                                                         if (option_verbose > 2)
2066                                                                 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
2067                                                         if (!sentringing) {
2068 #if 0
2069                                                                 ast_indicate(in, AST_CONTROL_RINGING);
2070 #endif                                                          
2071                                                                 sentringing++;
2072                                                         }
2073                                                         break;
2074                                                 case AST_CONTROL_OFFHOOK:
2075                                                         /* Ignore going off hook */
2076                                                         break;
2077                                                 default:
2078                                                         if (option_debug)
2079                                                                 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
2080                                                 }
2081                                         }
2082                                         ast_frfree(f);
2083                                 } else {
2084                                         endtime = (long) time(NULL) - starttime;
2085                                         rna(endtime * 1000, qe, on, membername);
2086                                         do_hang(o);
2087                                         if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
2088                                                 if (qe->parent->timeoutrestart)
2089                                                         *to = orig;
2090                                                 ring_one(qe, outgoing, &numbusies);
2091                                         }
2092                                 }
2093                         }
2094                 }
2095                 if (winner == in) {
2096                         f = ast_read(in);
2097                         if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
2098                                 /* Got hung up */
2099                                 *to = -1;
2100                                 if (f)
2101                                         ast_frfree(f);
2102                                 return NULL;
2103                         }
2104                         if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
2105                                 if (option_verbose > 3)
2106                                         ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
2107                                 *to = 0;
2108                                 ast_frfree(f);
2109                                 return NULL;
2110                         }
2111                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass != '*') && valid_exit(qe, f->subclass)) {
2112                                 if (option_verbose > 3)
2113                                         ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
2114                                 *to = 0;
2115                                 *digit = f->subclass;
2116                                 ast_frfree(f);
2117                                 return NULL;
2118                         }
2119                         ast_frfree(f);
2120                 }
2121                 if (!*to)
2122                         rna(orig, qe, on, membername);
2123         }
2124
2125         return peer;
2126 }
2127
2128 static int is_our_turn(struct queue_ent *qe)
2129 {
2130         struct queue_ent *ch;
2131         struct member *cur;
2132         int avl = 0;
2133         int idx = 0;
2134         int res;
2135
2136         if (!qe->parent->autofill) {
2137                 /* Atomically read the parent head -- does not need a lock */
2138                 ch = qe->parent->head;
2139                 /* If we are now at the top of the head, break out */
2140                 if (ch == qe) {
2141                         if (option_debug)
2142                                 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2143                         res = 1;
2144                 } else {
2145                         if (option_debug)
2146                                 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2147                         res = 0;
2148                 }       
2149
2150         } else {
2151                 /* This needs a lock. How many members are available to be served? */
2152                 ast_mutex_lock(&qe->parent->lock);
2153                         
2154                 ch = qe->parent->head;
2155         
2156                 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
2157                         if (option_debug)
2158                                 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);
2159                         avl = 1;
2160                 } else {
2161                         for (cur = qe->parent->members; cur; cur = cur->next) {
2162                                 switch (cur->status) {
2163                                 case AST_DEVICE_NOT_INUSE:
2164                                 case AST_DEVICE_UNKNOWN:
2165                                         avl++;
2166                                         break;
2167                                 }
2168                         }
2169                 }
2170
2171                 if (option_debug)
2172                         ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
2173         
2174                 while ((idx < avl) && (ch) && (ch != qe)) {
2175                         idx++;
2176                         ch = ch->next;                  
2177                 }
2178         
2179                 /* If the queue entry is within avl [the number of available members] calls from the top ... */
2180                 if (ch && idx < avl) {
2181                         if (option_debug)
2182                                 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
2183                         res = 1;
2184                 } else {
2185                         if (option_debug)
2186                                 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
2187                         res = 0;
2188                 }
2189                 
2190                 ast_mutex_unlock(&qe->parent->lock);
2191         }
2192
2193         return res;
2194 }
2195
2196 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
2197 {
2198         int res = 0;
2199
2200         /* This is the holding pen for callers 2 through maxlen */
2201         for (;;) {
2202                 enum queue_member_status stat;
2203
2204                 if (is_our_turn(qe))
2205                         break;
2206
2207                 /* If we have timed out, break out */
2208                 if (qe->expire && (time(NULL) > qe->expire)) {
2209                         *reason = QUEUE_TIMEOUT;
2210                         break;
2211                 }
2212
2213                 stat = get_member_status(qe->parent, qe->max_penalty);
2214
2215                 /* leave the queue if no agents, if enabled */
2216                 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
2217                         *reason = QUEUE_LEAVEEMPTY;
2218                         ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2219                         leave_queue(qe);
2220                         break;
2221                 }
2222
2223                 /* leave the queue if no reachable agents, if enabled */
2224                 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_UNPAUSED_REACHABLE_MEMBERS)) {
2225                         *reason = QUEUE_LEAVEUNAVAIL;
2226                         ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2227                         leave_queue(qe);
2228                         break;
2229                 }
2230                 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_LOOSE) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
2231                         *reason = QUEUE_LEAVEUNAVAIL;
2232                         ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2233                         leave_queue(qe);
2234                         break;
2235                 }
2236
2237                 /* Make a position announcement, if enabled */
2238                 if (qe->parent->announcefrequency && !ringing &&
2239                         (res = say_position(qe)))
2240                         break;
2241
2242                 /* Make a periodic announcement, if enabled */
2243                 if (qe->parent->periodicannouncefrequency && !ringing &&
2244                         (res = say_periodic_announcement(qe)))
2245                         break;
2246
2247                 /* Wait a second before checking again */
2248                 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000)))
2249                         break;
2250         }
2251
2252         return res;
2253 }
2254
2255 static int update_queue(struct call_queue *q, struct member *member)
2256 {
2257         struct member *cur;
2258
2259         /* Since a reload could have taken place, we have to traverse the list to
2260                 be sure it's still valid */
2261         ast_mutex_lock(&q->lock);
2262         cur = q->members;
2263         while (cur) {
2264                 if (member == cur) {
2265                         time(&cur->lastcall);
2266                         cur->calls++;
2267                         break;
2268                 }
2269                 cur = cur->next;
2270         }
2271         q->callscompleted++;
2272         ast_mutex_unlock(&q->lock);
2273         return 0;
2274 }
2275
2276 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
2277 {
2278         if (qe->max_penalty && (mem->penalty > qe->max_penalty))
2279                 return -1;
2280
2281         switch (q->strategy) {
2282         case QUEUE_STRATEGY_RINGALL:
2283                 /* Everyone equal, except for penalty */
2284                 tmp->metric = mem->penalty * 1000000;
2285                 break;
2286         case QUEUE_STRATEGY_RRMEMORY:
2287                 if (pos < q->rrpos) {
2288                         tmp->metric = 1000 + pos;
2289                 } else {
2290                         if (pos > q->rrpos)
2291                                 /* Indicate there is another priority */
2292                                 q->wrapped = 1;
2293                         tmp->metric = pos;
2294                 }
2295                 tmp->metric += mem->penalty * 1000000;
2296                 break;
2297         case QUEUE_STRATEGY_RANDOM:
2298                 tmp->metric = ast_random() % 1000;
2299                 tmp->metric += mem->penalty * 1000000;
2300                 break;
2301         case QUEUE_STRATEGY_FEWESTCALLS:
2302                 tmp->metric = mem->calls;
2303                 tmp->metric += mem->penalty * 1000000;
2304                 break;
2305         case QUEUE_STRATEGY_LEASTRECENT:
2306                 if (!mem->lastcall)
2307                         tmp->metric = 0;
2308                 else
2309                         tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
2310                 tmp->metric += mem->penalty * 1000000;
2311                 break;
2312         default:
2313                 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
2314                 break;
2315         }
2316         return 0;
2317 }
2318
2319 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)
2320 {
2321         struct member *cur;
2322         struct callattempt *outgoing = NULL; /* the list of calls we are building */
2323         int to;
2324         char oldexten[AST_MAX_EXTENSION]="";
2325         char oldcontext[AST_MAX_CONTEXT]="";
2326         char queuename[256]="";
2327         char interfacevar[256]="";
2328         struct ast_channel *peer;
2329         struct ast_channel *which;
2330         struct callattempt *lpeer;
2331         struct member *member;
2332         struct ast_app *app;
2333         int res = 0, bridge = 0;
2334         int numbusies = 0;
2335         int x=0;
2336         char *announce = NULL;
2337         char digit = 0;
2338         time_t callstart;
2339         time_t now = time(NULL);
2340         struct ast_bridge_config bridge_config;
2341         char nondataquality = 1;
2342         char *agiexec = NULL;
2343         char *macroexec = NULL;
2344         int ret = 0;
2345         const char *monitorfilename;
2346         const char *monitor_exec;
2347         const char *monitor_options;
2348         char tmpid[256], tmpid2[256];
2349         char meid[1024], meid2[1024];
2350         char mixmonargs[1512];
2351         struct ast_app *mixmonapp = NULL;
2352         char *p;
2353         char vars[2048];
2354         int forwardsallowed = 1;
2355         memset(&bridge_config, 0, sizeof(bridge_config));
2356         time(&now);
2357                 
2358         for (; options && *options; options++)
2359                 switch (*options) {
2360                 case 't':
2361                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
2362                         break;
2363                 case 'T':
2364                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
2365                         break;
2366                 case 'w':
2367                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
2368                         break;
2369                 case 'W':
2370                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
2371                         break;
2372                 case 'd':
2373                         nondataquality = 0;
2374                         break;
2375                 case 'h':
2376                         ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
2377                         break;
2378                 case 'H':
2379                         ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
2380                         break;
2381                 case 'n':
2382                         if ((now - qe->start >= qe->parent->timeout))
2383                                 *go_on = 1;
2384                         break;
2385                 case 'i':
2386                         forwardsallowed = 0;
2387                         break;
2388                 }
2389
2390         /* Hold the lock while we setup the outgoing calls */
2391         if (use_weight)
2392                 AST_LIST_LOCK(&queues);
2393         ast_mutex_lock(&qe->parent->lock);
2394         if (option_debug)
2395                 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
2396                                                         qe->chan->name);
2397         ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
2398         cur = qe->parent->members;
2399         if (!ast_strlen_zero(qe->announce))
2400                 announce = qe->announce;
2401         if (!ast_strlen_zero(announceoverride))
2402                 announce = announceoverride;
2403
2404         for (; cur; cur = cur->next) {
2405                 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
2406
2407                 if (!tmp) {
2408                         ast_mutex_unlock(&qe->parent->lock);
2409                         if (use_weight)
2410                                 AST_LIST_UNLOCK(&queues);
2411                         goto out;
2412                 }
2413                 tmp->stillgoing = -1;
2414                 tmp->member = cur;              /* Never directly dereference!  Could change on reload */
2415                 tmp->oldstatus = cur->status;
2416                 tmp->lastcall = cur->lastcall;
2417                 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
2418                 /* Special case: If we ring everyone, go ahead and ring them, otherwise
2419                    just calculate their metric for the appropriate strategy */
2420                 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
2421                         /* Put them in the list of outgoing thingies...  We're ready now.
2422                            XXX If we're forcibly removed, these outgoing calls won't get
2423                            hung up XXX */
2424                         tmp->q_next = outgoing;
2425                         outgoing = tmp;         
2426                         /* If this line is up, don't try anybody else */
2427                         if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
2428                                 break;
2429                 } else {
2430                         free(tmp);
2431                 }
2432         }
2433         if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
2434                 to = (qe->expire - now) * 1000;
2435         else
2436                 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
2437         ring_one(qe, outgoing, &numbusies);
2438         ast_mutex_unlock(&qe->parent->lock);
2439         if (use_weight)
2440                 AST_LIST_UNLOCK(&queues);
2441         lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
2442         ast_mutex_lock(&qe->parent->lock);
2443         if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
2444                 store_next(qe, outgoing);
2445         }
2446         ast_mutex_unlock(&qe->parent->lock);
2447         peer = lpeer ? lpeer->chan : NULL;
2448         if (!peer) {
2449                 if (to) {
2450                         /* Must gotten hung up */
2451                         res = -1;
2452                 } else {
2453                         res = digit;
2454                 }
2455                 if (option_debug)
2456                         ast_log(LOG_DEBUG, "%s: Nobody answered.\n", qe->chan->name);
2457         } else { /* peer is valid */
2458                 /* Ah ha!  Someone answered within the desired timeframe.  Of course after this
2459                    we will always return with -1 so that it is hung up properly after the
2460                    conversation.  */
2461                 qe->handled++;
2462                 if (!strcmp(qe->chan->tech->type, "Zap"))
2463                         ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2464                 if (!strcmp(peer->tech->type, "Zap"))
2465                         ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
2466                 /* Update parameters for the queue */
2467                 recalc_holdtime(qe);
2468                 member = lpeer->member;
2469                 hangupcalls(outgoing, peer);
2470                 outgoing = NULL;
2471                 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
2472                         int res2;
2473
2474                         res2 = ast_autoservice_start(qe->chan);
2475                         if (!res2) {
2476                                 if (qe->parent->memberdelay) {
2477                                         ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
2478                                         res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
2479                                 }
2480                                 if (!res2 && announce) {
2481                                         if (play_file(peer, announce))
2482                                                 ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce);
2483                                 }
2484                                 if (!res2 && qe->parent->reportholdtime) {
2485                                         if (!play_file(peer, qe->parent->sound_reporthold)) {
2486                                                 int holdtime;
2487
2488                                                 time(&now);
2489                                                 holdtime = abs((now - qe->start) / 60);
2490                                                 if (holdtime < 2) {
2491                                                         play_file(peer, qe->parent->sound_lessthan);
2492                                                         ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
2493                                                 } else
2494                                                         ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
2495                                                 play_file(peer, qe->parent->sound_minutes);
2496                                         }
2497                                 }
2498                         }
2499                         res2 |= ast_autoservice_stop(qe->chan);
2500                         if (peer->_softhangup) {
2501                                 /* Agent must have hung up */
2502                                 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.  They're going to be pissed.\n", peer->name);
2503                                 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
2504                                 record_abandoned(qe);
2505                                 if (qe->parent->eventwhencalled)
2506                                         manager_event(EVENT_FLAG_AGENT, "AgentDump",
2507                                                         "Queue: %s\r\n"
2508                                                         "Uniqueid: %s\r\n"
2509                                                         "Channel: %s\r\n"
2510                                                         "Member: %s\r\n"
2511                                                         "MemberName: %s\r\n"
2512                                                         "%s",
2513                                                         queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2514                                                         qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2515                                 ast_hangup(peer);
2516                                 goto out;
2517                         } else if (res2) {
2518                                 /* Caller must have hung up just before being connected*/
2519                                 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
2520                                 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
2521                                 record_abandoned(qe);
2522                                 ast_hangup(peer);
2523                                 return -1;
2524                         }
2525                 }
2526                 /* Stop music on hold */
2527                 ast_moh_stop(qe->chan);
2528                 /* If appropriate, log that we have a destination channel */
2529                 if (qe->chan->cdr)
2530                         ast_cdr_setdestchan(qe->chan->cdr, peer->name);
2531                 /* Make sure channels are compatible */
2532                 res = ast_channel_make_compatible(qe->chan, peer);
2533                 if (res < 0) {
2534                         ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
2535                         ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
2536                         record_abandoned(qe);
2537                         ast_hangup(peer);
2538                         return -1;
2539                 }
2540                 /* Begin Monitoring */
2541                 if (qe->parent->monfmt && *qe->parent->monfmt) {
2542                         if (!qe->parent->montype) {
2543                                 if (option_debug)
2544                                         ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
2545                                 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2546                                 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
2547                                         which = qe->chan;
2548                                 else
2549                                         which = peer;
2550                                 if (monitorfilename)
2551                                         ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
2552                                 else if (qe->chan->cdr)
2553                                         ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
2554                                 else {
2555                                         /* Last ditch effort -- no CDR, make up something */
2556                                         snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2557                                         ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
2558                                 }
2559                                 if (qe->parent->monjoin)
2560                                         ast_monitor_setjoinfiles(which, 1);
2561                         } else {
2562                                 if (option_debug)
2563                                         ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
2564                                 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
2565                                 if (!monitorfilename) {
2566                                         if (qe->chan->cdr)
2567                                                 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
2568                                         else
2569                                                 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
2570                                 } else {
2571                                         ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
2572                                         for (p = tmpid2; *p ; p++) {
2573                                                 if (*p == '^' && *(p+1) == '{') {
2574                                                         *p = '$';
2575                                                 }
2576                                         }
2577
2578                                         memset(tmpid, 0, sizeof(tmpid));
2579                                         pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
2580                                 }
2581
2582                                 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
2583                                 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
2584
2585                                 if (monitor_exec) {
2586                                         ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
2587                                         for (p = meid2; *p ; p++) {
2588                                                 if (*p == '^' && *(p+1) == '{') {
2589                                                         *p = '$';
2590                                                 }
2591                                         }
2592
2593                                         memset(meid, 0, sizeof(meid));
2594                                         pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
2595                                 }
2596         
2597                                 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
2598
2599                                 mixmonapp = pbx_findapp("MixMonitor");
2600
2601                                 if (strchr(tmpid2, '|')) {
2602                                         ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
2603                                         mixmonapp = NULL;
2604                                 }
2605
2606                                 if (!monitor_options)
2607                                         monitor_options = "";
2608                                 
2609                                 if (strchr(monitor_options, '|')) {
2610                                         ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
2611                                         mixmonapp = NULL;
2612                                 }
2613
2614                                 if (mixmonapp) {
2615                                         if (!ast_strlen_zero(monitor_exec) && !ast_strlen_zero(monitor_options))
2616                                                 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
2617                                         else
2618                                                 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
2619                                                 
2620                                         if (option_debug)
2621                                                 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
2622
2623                                         ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
2624
2625                                 } else
2626                                         ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
2627
2628                         }
2629                 }
2630                 /* Drop out of the queue at this point, to prepare for next caller */
2631                 leave_queue(qe);                        
2632                 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
2633                         if (option_debug)
2634                                 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
2635                         ast_channel_sendurl(peer, url);
2636                 }
2637                 
2638                 ast_mutex_lock(&qe->parent->lock);
2639                 /* if setinterfacevar is defined, make member variables available to the channel */
2640                 /* use  pbx_builtin_setvar to set a load of variables with one call */
2641                 if (qe->parent->setinterfacevar) {
2642                         snprintf(interfacevar,sizeof(interfacevar), "MEMBERINTERFACE=%s|MEMBERNAME=%s|MEMBERCALLS=%d|MEMBERLASTCALL=%ld|MEMBERPENALTY=%d|MEMBERDYNAMIC=%d",
2643                                 member->interface, member->membername, member->calls, (long)member->lastcall, member->penalty, member->dynamic);
2644                         pbx_builtin_setvar(qe->chan, interfacevar);
2645                 }
2646                 
2647                 /* if setqueueentryvar is defined, make queue entry (i.e. the caller) variables available to the channel */
2648                 /* use  pbx_builtin_setvar to set a load of variables with one call */
2649                 if (qe->parent->setqueueentryvar) {
2650                         snprintf(interfacevar,sizeof(interfacevar), "QEHOLDTIME=%ld|QEORIGINALPOS=%d",
2651                                 (long)time(NULL) - qe->start, qe->opos);
2652                         pbx_builtin_setvar(qe->chan, interfacevar);
2653                 }
2654         
2655                 /* try to set queue variables if configured to do so*/
2656                 set_queue_variables(qe);
2657                 ast_mutex_unlock(&qe->parent->lock);
2658                 
2659                 /* run a macro for this connection if defined. The macro simply returns, no action is taken on the result */
2660                 /* use macro from dialplan if passed as a option, otherwise use the default queue macro */
2661                 if (!ast_strlen_zero(macro)) {
2662                                 macroexec = ast_strdupa(macro);
2663                 } else {
2664                         if (qe->parent->membermacro)
2665                                 macroexec = ast_strdupa(qe->parent->membermacro);
2666                 }
2667
2668                 if (!ast_strlen_zero(macroexec)) {
2669                         if (option_debug)
2670                                 ast_log(LOG_DEBUG, "app_queue: macro=%s.\n", macroexec);
2671                         
2672                         res = ast_autoservice_start(qe->chan);
2673                         if (res) {
2674                                 ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
2675                                 res = -1;
2676                         }
2677                         
2678                         app = pbx_findapp("Macro");
2679                         
2680                         if (app) {
2681                                 res = pbx_exec(qe->chan, app, macroexec);
2682                                 if (option_debug)
2683                                         ast_log(LOG_DEBUG, "Macro exited with status %d\n", res);
2684                                 res = 0;
2685                         } else {
2686                                 ast_log(LOG_ERROR, "Could not find application Macro\n");
2687                                 res = -1;
2688                         }
2689                 
2690                         if (ast_autoservice_stop(qe->chan) < 0) {
2691                                 ast_log(LOG_ERROR, "Could not stop autoservice on calling channel\n");
2692                                 res = -1;
2693                         }
2694                 }
2695
2696                 if (!ast_strlen_zero(agi)) {
2697                         if (option_debug)
2698                                 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
2699                         app = pbx_findapp("agi");
2700                         if (app) {
2701                                 agiexec = ast_strdupa(agi);
2702                                 ret = pbx_exec(qe->chan, app, agiexec);
2703                         } else
2704                                 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
2705                 }
2706                 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
2707                 if (qe->parent->eventwhencalled)
2708                         manager_event(EVENT_FLAG_AGENT, "AgentConnect",
2709                                         "Queue: %s\r\n"
2710                                         "Uniqueid: %s\r\n"
2711                                         "Channel: %s\r\n"
2712                                         "Member: %s\r\n"
2713                                         "MemberName: %s\r\n"
2714                                         "Holdtime: %ld\r\n"
2715                                         "BridgedChannel: %s\r\n"
2716                                         "%s",
2717                                         queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2718                                         (long)time(NULL) - qe->start, peer->uniqueid,
2719                                         qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2720                 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
2721                 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
2722                 time(&callstart);
2723
2724                 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
2725
2726                 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
2727                         ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
2728                                 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
2729                                 (long) (time(NULL) - callstart));
2730                 } else if (qe->chan->_softhangup) {
2731                         ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld",
2732                                 (long) (callstart - qe->start), (long) (time(NULL) - callstart));
2733                         if (qe->parent->eventwhencalled)
2734                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2735                                                 "Queue: %s\r\n"
2736                                                 "Uniqueid: %s\r\n"
2737                                                 "Channel: %s\r\n"
2738                                                 "Member: %s\r\n"
2739                                                 "MemberName: %s\r\n"
2740                                                 "HoldTime: %ld\r\n"
2741                                                 "TalkTime: %ld\r\n"
2742                                                 "Reason: caller\r\n"
2743                                                 "%s",
2744                                                 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
2745                                                 (long)(callstart - qe->start), (long)(time(NULL) - callstart),
2746                                                 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2747                 } else {
2748                         ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld",
2749                                 (long) (callstart - qe->start), (long) (time(NULL) - callstart));
2750                         if (qe->parent->eventwhencalled)
2751                                 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
2752                                                 "Queue: %s\r\n"
2753                                                 "Uniqueid: %s\r\n"
2754                                                 "Channel: %s\r\n"
2755                                                 "MemberName: %s\r\n"
2756                                                 "HoldTime: %ld\r\n"
2757                                                 "TalkTime: %ld\r\n"
2758                                                 "Reason: agent\r\n"
2759                                                 "%s",
2760                                                 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
2761                                                 (long)(time(NULL) - callstart),
2762                                                 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
2763                 }
2764
2765                 if (bridge != AST_PBX_NO_HANGUP_PEER)
2766                         ast_hangup(peer);
2767                 update_queue(qe->parent, member);
2768                 res = bridge ? bridge : 1;
2769         }
2770 out:
2771         hangupcalls(outgoing, NULL);
2772
2773         return res;
2774 }
2775
2776 static int wait_a_bit(struct queue_ent *qe)
2777 {
2778         /* Don't need to hold the lock while we setup the outgoing calls */
2779         int retrywait = qe->parent->retry * 1000;
2780
2781         return ast_waitfordigit(qe->chan, retrywait);
2782 }
2783
2784 static struct member *interface_exists(struct call_queue *q, char *interface)
2785 {
2786         struct member *mem;
2787
2788         if (!q)
2789                 return NULL;
2790
2791         for (mem = q->members; mem; mem = mem->next) {
2792                 if (!strcasecmp(interface, mem->interface))
2793                         return mem;
2794         }
2795
2796         return NULL;
2797 }
2798
2799
2800 /* Dump all members in a specific queue to the database
2801  *
2802  * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
2803  *
2804  */
2805 static void dump_queue_members(struct call_queue *pm_queue)
2806 {
2807         struct member *cur_member;
2808         char value[PM_MAX_LEN];
2809         int value_len = 0;
2810         int res;
2811
2812         memset(value, 0, sizeof(value));
2813
2814         if (!pm_queue)
2815                 return;
2816
2817         for (cur_member = pm_queue->members; cur_member; cur_member = cur_member->next) {
2818                 if (!cur_member->dynamic)
2819                         continue;
2820
2821                 res = snprintf(value + value_len, sizeof(value) - value_len, "%s;%d;%d;%s%s",
2822                         cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername,
2823                         cur_member->next ? "|" : "");
2824                 if (res != strlen(value + value_len)) {
2825                         ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
2826                         break;
2827                 }
2828                 value_len += res;
2829         }
2830         
2831         if (value_len && !cur_member) {
2832                 if (ast_db_put(pm_family, pm_queue->name, value))
2833                         ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
2834         } else
2835                 /* Delete the entry if the queue is empty or there is an error */
2836                 ast_db_del(pm_family, pm_queue->name);
2837 }
2838
2839 static int remove_from_queue(char *queuename, char *interface)
2840 {
2841         struct call_queue *q;
2842         struct member *last_member, *look;
2843         int res = RES_NOSUCHQUEUE;
2844
2845         AST_LIST_LOCK(&queues);
2846         AST_LIST_TRAVERSE(&queues, q, list) {
2847                 ast_mutex_lock(&q->lock);
2848                 if (strcmp(q->name, queuename)) {
2849                         ast_mutex_unlock(&q->lock);
2850                         continue;
2851                 }
2852
2853                 if ((last_member = interface_exists(q, interface))) {
2854                         if ((look = q->members) == last_member) {
2855                                 q->members = last_member->next;
2856                         } else {
2857                                 while (look != NULL) {
2858                                         if (look->next == last_member) {
2859                                                 look->next = last_member->next;
2860                                                 break;
2861                                         } else {
2862                                                 look = look->next;
2863                                         }
2864                                 }
2865                         }
2866                         manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
2867                                 "Queue: %s\r\n"
2868                                 "Location: %s\r\n"
2869                                 "MemberName: %s\r\n",
2870                                 q->name, last_member->interface, last_member->membername);
2871                         free(last_member);
2872                         
2873                         if (queue_persistent_members)
2874                                 dump_queue_members(q);
2875                         
2876                         res = RES_OKAY;
2877                 } else {
2878                         res = RES_EXISTS;
2879                 }
2880                 ast_mutex_unlock(&q->lock);
2881                 break;
2882         }
2883
2884         if (res == RES_OKAY)
2885                 remove_from_interfaces(interface);