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