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