00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063 #include "asterisk.h"
00064
00065 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 140488 $")
00066
00067 #include <stdlib.h>
00068 #include <errno.h>
00069 #include <unistd.h>
00070 #include <string.h>
00071 #include <stdlib.h>
00072 #include <stdio.h>
00073 #include <sys/time.h>
00074 #include <sys/signal.h>
00075 #include <netinet/in.h>
00076
00077 #include "asterisk/lock.h"
00078 #include "asterisk/file.h"
00079 #include "asterisk/logger.h"
00080 #include "asterisk/channel.h"
00081 #include "asterisk/pbx.h"
00082 #include "asterisk/options.h"
00083 #include "asterisk/app.h"
00084 #include "asterisk/linkedlists.h"
00085 #include "asterisk/module.h"
00086 #include "asterisk/translate.h"
00087 #include "asterisk/say.h"
00088 #include "asterisk/features.h"
00089 #include "asterisk/musiconhold.h"
00090 #include "asterisk/cli.h"
00091 #include "asterisk/manager.h"
00092 #include "asterisk/config.h"
00093 #include "asterisk/monitor.h"
00094 #include "asterisk/utils.h"
00095 #include "asterisk/causes.h"
00096 #include "asterisk/astdb.h"
00097 #include "asterisk/devicestate.h"
00098 #include "asterisk/stringfields.h"
00099 #include "asterisk/astobj2.h"
00100 #include "asterisk/global_datastores.h"
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 enum {
00117 QUEUE_STRATEGY_RINGALL = 0,
00118 QUEUE_STRATEGY_ROUNDROBIN,
00119 QUEUE_STRATEGY_LEASTRECENT,
00120 QUEUE_STRATEGY_FEWESTCALLS,
00121 QUEUE_STRATEGY_RANDOM,
00122 QUEUE_STRATEGY_RRMEMORY
00123 };
00124
00125 static struct strategy {
00126 int strategy;
00127 char *name;
00128 } strategies[] = {
00129 { QUEUE_STRATEGY_RINGALL, "ringall" },
00130 { QUEUE_STRATEGY_ROUNDROBIN, "roundrobin" },
00131 { QUEUE_STRATEGY_LEASTRECENT, "leastrecent" },
00132 { QUEUE_STRATEGY_FEWESTCALLS, "fewestcalls" },
00133 { QUEUE_STRATEGY_RANDOM, "random" },
00134 { QUEUE_STRATEGY_RRMEMORY, "rrmemory" },
00135 };
00136
00137 #define DEFAULT_RETRY 5
00138 #define DEFAULT_TIMEOUT 15
00139 #define RECHECK 1
00140 #define MAX_PERIODIC_ANNOUNCEMENTS 10
00141
00142 #define RES_OKAY 0
00143 #define RES_EXISTS (-1)
00144 #define RES_OUTOFMEMORY (-2)
00145 #define RES_NOSUCHQUEUE (-3)
00146 #define RES_NOT_DYNAMIC (-4)
00147
00148 static char *app = "Queue";
00149
00150 static char *synopsis = "Queue a call for a call queue";
00151
00152 static char *descrip =
00153 " Queue(queuename[|options[|URL][|announceoverride][|timeout][|AGI]):\n"
00154 "Queues an incoming call in a particular call queue as defined in queues.conf.\n"
00155 "This application will return to the dialplan if the queue does not exist, or\n"
00156 "any of the join options cause the caller to not enter the queue.\n"
00157 "The option string may contain zero or more of the following characters:\n"
00158 " 'd' -- data-quality (modem) call (minimum delay).\n"
00159 " 'h' -- allow callee to hang up by hitting *.\n"
00160 " 'H' -- allow caller to hang up by hitting *.\n"
00161 " 'n' -- no retries on the timeout; will exit this application and \n"
00162 " go to the next step.\n"
00163 " 'i' -- ignore call forward requests from queue members and do nothing\n"
00164 " when they are requested.\n"
00165 " 'r' -- ring instead of playing MOH\n"
00166 " 't' -- allow the called user transfer the calling user\n"
00167 " 'T' -- to allow the calling user to transfer the call.\n"
00168 " 'w' -- allow the called user to write the conversation to disk via Monitor\n"
00169 " 'W' -- allow the calling user to write the conversation to disk via Monitor\n"
00170 " In addition to transferring the call, a call may be parked and then picked\n"
00171 "up by another user.\n"
00172 " The optional URL will be sent to the called party if the channel supports\n"
00173 "it.\n"
00174 " The optional AGI parameter will setup an AGI script to be executed on the \n"
00175 "calling party's channel once they are connected to a queue member.\n"
00176 " The timeout will cause the queue to fail out after a specified number of\n"
00177 "seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"
00178 " This application sets the following channel variable upon completion:\n"
00179 " QUEUESTATUS The status of the call as a text string, one of\n"
00180 " TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
00181
00182 static char *app_aqm = "AddQueueMember" ;
00183 static char *app_aqm_synopsis = "Dynamically adds queue members" ;
00184 static char *app_aqm_descrip =
00185 " AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]]):\n"
00186 "Dynamically adds interface to an existing queue.\n"
00187 "If the interface is already in the queue and there exists an n+101 priority\n"
00188 "then it will then jump to this priority. Otherwise it will return an error\n"
00189 "The option string may contain zero or more of the following characters:\n"
00190 " 'j' -- jump to +101 priority when appropriate.\n"
00191 " This application sets the following channel variable upon completion:\n"
00192 " AQMSTATUS The status of the attempt to add a queue member as a \n"
00193 " text string, one of\n"
00194 " ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
00195 "Example: AddQueueMember(techsupport|SIP/3000)\n"
00196 "";
00197
00198 static char *app_rqm = "RemoveQueueMember" ;
00199 static char *app_rqm_synopsis = "Dynamically removes queue members" ;
00200 static char *app_rqm_descrip =
00201 " RemoveQueueMember(queuename[|interface[|options]]):\n"
00202 "Dynamically removes interface to an existing queue\n"
00203 "If the interface is NOT in the queue and there exists an n+101 priority\n"
00204 "then it will then jump to this priority. Otherwise it will return an error\n"
00205 "The option string may contain zero or more of the following characters:\n"
00206 " 'j' -- jump to +101 priority when appropriate.\n"
00207 " This application sets the following channel variable upon completion:\n"
00208 " RQMSTATUS The status of the attempt to remove a queue member as a\n"
00209 " text string, one of\n"
00210 " REMOVED | NOTINQUEUE | NOSUCHQUEUE \n"
00211 "Example: RemoveQueueMember(techsupport|SIP/3000)\n"
00212 "";
00213
00214 static char *app_pqm = "PauseQueueMember" ;
00215 static char *app_pqm_synopsis = "Pauses a queue member" ;
00216 static char *app_pqm_descrip =
00217 " PauseQueueMember([queuename]|interface[|options]):\n"
00218 "Pauses (blocks calls for) a queue member.\n"
00219 "The given interface will be paused in the given queue. This prevents\n"
00220 "any calls from being sent from the queue to the interface until it is\n"
00221 "unpaused with UnpauseQueueMember or the manager interface. If no\n"
00222 "queuename is given, the interface is paused in every queue it is a\n"
00223 "member of. If the interface is not in the named queue, or if no queue\n"
00224 "is given and the interface is not in any queue, it will jump to\n"
00225 "priority n+101, if it exists and the appropriate options are set.\n"
00226 "The application will fail if the interface is not found and no extension\n"
00227 "to jump to exists.\n"
00228 "The option string may contain zero or more of the following characters:\n"
00229 " 'j' -- jump to +101 priority when appropriate.\n"
00230 " 'i' -- ignore failure if member not found.\n"
00231 " This application sets the following channel variable upon completion:\n"
00232 " PQMSTATUS The status of the attempt to pause a queue member as a\n"
00233 " text string, one of\n"
00234 " PAUSED | NOTFOUND\n"
00235 "Example: PauseQueueMember(|SIP/3000)\n";
00236
00237 static char *app_upqm = "UnpauseQueueMember" ;
00238 static char *app_upqm_synopsis = "Unpauses a queue member" ;
00239 static char *app_upqm_descrip =
00240 " UnpauseQueueMember([queuename]|interface[|options]):\n"
00241 "Unpauses (resumes calls to) a queue member.\n"
00242 "This is the counterpart to PauseQueueMember and operates exactly the\n"
00243 "same way, except it unpauses instead of pausing the given interface.\n"
00244 "The option string may contain zero or more of the following characters:\n"
00245 " 'j' -- jump to +101 priority when appropriate.\n"
00246 " 'i' -- ignore failure if member not found.\n"
00247 " This application sets the following channel variable upon completion:\n"
00248 " UPQMSTATUS The status of the attempt to unpause a queue \n"
00249 " member as a text string, one of\n"
00250 " UNPAUSED | NOTFOUND\n"
00251 "Example: UnpauseQueueMember(|SIP/3000)\n";
00252
00253 static char *app_ql = "QueueLog" ;
00254 static char *app_ql_synopsis = "Writes to the queue_log" ;
00255 static char *app_ql_descrip =
00256 " QueueLog(queuename|uniqueid|agent|event[|additionalinfo]):\n"
00257 "Allows you to write your own events into the queue log\n"
00258 "Example: QueueLog(101|${UNIQUEID}|${AGENT}|WENTONBREAK|600)\n";
00259
00260
00261 static const char *pm_family = "Queue/PersistentMembers";
00262
00263 #define PM_MAX_LEN 8192
00264
00265
00266 static int queue_debug = 0;
00267
00268
00269 static int queue_persistent_members = 0;
00270
00271
00272 static int use_weight = 0;
00273
00274
00275 static int autofill_default = 0;
00276
00277
00278 static int montype_default = 0;
00279
00280 enum queue_result {
00281 QUEUE_UNKNOWN = 0,
00282 QUEUE_TIMEOUT = 1,
00283 QUEUE_JOINEMPTY = 2,
00284 QUEUE_LEAVEEMPTY = 3,
00285 QUEUE_JOINUNAVAIL = 4,
00286 QUEUE_LEAVEUNAVAIL = 5,
00287 QUEUE_FULL = 6,
00288 };
00289
00290 const struct {
00291 enum queue_result id;
00292 char *text;
00293 } queue_results[] = {
00294 { QUEUE_UNKNOWN, "UNKNOWN" },
00295 { QUEUE_TIMEOUT, "TIMEOUT" },
00296 { QUEUE_JOINEMPTY,"JOINEMPTY" },
00297 { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" },
00298 { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" },
00299 { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" },
00300 { QUEUE_FULL, "FULL" },
00301 };
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 struct callattempt {
00315 struct callattempt *q_next;
00316 struct callattempt *call_next;
00317 struct ast_channel *chan;
00318 char interface[256];
00319 int stillgoing;
00320 int metric;
00321 int oldstatus;
00322 time_t lastcall;
00323 struct member *member;
00324 };
00325
00326
00327 struct queue_ent {
00328 struct call_queue *parent;
00329 char moh[80];
00330 char announce[80];
00331 char context[AST_MAX_CONTEXT];
00332 char digits[AST_MAX_EXTENSION];
00333 int valid_digits;
00334 int pos;
00335 int prio;
00336 int last_pos_said;
00337 time_t last_periodic_announce_time;
00338 int last_periodic_announce_sound;
00339 time_t last_pos;
00340 int opos;
00341 int handled;
00342 int tries;
00343 int pending;
00344 int max_penalty;
00345 time_t start;
00346 time_t expire;
00347 struct ast_channel *chan;
00348 struct queue_ent *next;
00349 };
00350
00351 struct member {
00352 char interface[80];
00353 char membername[80];
00354 int penalty;
00355 int calls;
00356 int dynamic;
00357 int realtime;
00358 int status;
00359 int paused;
00360 time_t lastcall;
00361 unsigned int dead:1;
00362 int ringcount;
00363 unsigned int delme:1;
00364 };
00365
00366 struct member_interface {
00367 char interface[80];
00368 AST_LIST_ENTRY(member_interface) list;
00369 };
00370
00371 static AST_LIST_HEAD_STATIC(interfaces, member_interface);
00372
00373
00374 #define QUEUE_EMPTY_NORMAL 1
00375 #define QUEUE_EMPTY_STRICT 2
00376 #define ANNOUNCEHOLDTIME_ALWAYS 1
00377 #define ANNOUNCEHOLDTIME_ONCE 2
00378 #define QUEUE_EVENT_VARIABLES 3
00379
00380 struct call_queue {
00381 ast_mutex_t lock;
00382 char name[80];
00383 char moh[80];
00384 char announce[80];
00385 char context[AST_MAX_CONTEXT];
00386 unsigned int monjoin:1;
00387 unsigned int dead:1;
00388 unsigned int joinempty:2;
00389 unsigned int eventwhencalled:2;
00390 unsigned int leavewhenempty:2;
00391 unsigned int ringinuse:1;
00392 unsigned int setinterfacevar:1;
00393 unsigned int reportholdtime:1;
00394 unsigned int wrapped:1;
00395 unsigned int timeoutrestart:1;
00396 unsigned int announceholdtime:2;
00397 int strategy:4;
00398 unsigned int maskmemberstatus:1;
00399 unsigned int realtime:1;
00400 unsigned int found:1;
00401 int announcefrequency;
00402 int periodicannouncefrequency;
00403 int roundingseconds;
00404 int holdtime;
00405 int callscompleted;
00406 int callsabandoned;
00407 int servicelevel;
00408 int callscompletedinsl;
00409 char monfmt[8];
00410 int montype;
00411 char sound_next[80];
00412 char sound_thereare[80];
00413 char sound_calls[80];
00414 char sound_holdtime[80];
00415 char sound_minutes[80];
00416 char sound_lessthan[80];
00417 char sound_seconds[80];
00418 char sound_thanks[80];
00419 char sound_reporthold[80];
00420 char sound_periodicannounce[MAX_PERIODIC_ANNOUNCEMENTS][80];
00421
00422 int count;
00423 int maxlen;
00424 int wrapuptime;
00425 int ringlimit;
00426
00427 int retry;
00428 int timeout;
00429 int weight;
00430 int autopause;
00431
00432
00433 int rrpos;
00434 int memberdelay;
00435 int autofill;
00436
00437 struct ao2_container *members;
00438
00439
00440
00441
00442
00443 int membercount;
00444 struct queue_ent *head;
00445 AST_LIST_ENTRY(call_queue) list;
00446 };
00447
00448 static AST_LIST_HEAD_STATIC(queues, call_queue);
00449
00450 static int set_member_paused(const char *queuename, const char *interface, int paused);
00451
00452 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
00453
00454 static void rr_dep_warning(void)
00455 {
00456 static unsigned int warned = 0;
00457
00458 if (!warned) {
00459 ast_log(LOG_NOTICE, "The 'roundrobin' queue strategy is deprecated. Please use the 'rrmemory' strategy instead.\n");
00460 warned = 1;
00461 }
00462 }
00463
00464 static void monjoin_dep_warning(void)
00465 {
00466 static unsigned int warned = 0;
00467 if (!warned) {
00468 ast_log(LOG_NOTICE, "The 'monitor-join' queue option is deprecated. Please use monitor-type=mixmonitor instead.\n");
00469 warned = 1;
00470 }
00471 }
00472
00473 static void set_queue_result(struct ast_channel *chan, enum queue_result res)
00474 {
00475 int i;
00476
00477 for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) {
00478 if (queue_results[i].id == res) {
00479 pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text);
00480 return;
00481 }
00482 }
00483 }
00484
00485 static char *int2strat(int strategy)
00486 {
00487 int x;
00488
00489 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
00490 if (strategy == strategies[x].strategy)
00491 return strategies[x].name;
00492 }
00493
00494 return "<unknown>";
00495 }
00496
00497 static int strat2int(const char *strategy)
00498 {
00499 int x;
00500
00501 for (x = 0; x < sizeof(strategies) / sizeof(strategies[0]); x++) {
00502 if (!strcasecmp(strategy, strategies[x].name))
00503 return strategies[x].strategy;
00504 }
00505
00506 return -1;
00507 }
00508
00509
00510 static inline void insert_entry(struct call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos)
00511 {
00512 struct queue_ent *cur;
00513
00514 if (!q || !new)
00515 return;
00516 if (prev) {
00517 cur = prev->next;
00518 prev->next = new;
00519 } else {
00520 cur = q->head;
00521 q->head = new;
00522 }
00523 new->next = cur;
00524 new->parent = q;
00525 new->pos = ++(*pos);
00526 new->opos = *pos;
00527 }
00528
00529 enum queue_member_status {
00530 QUEUE_NO_MEMBERS,
00531 QUEUE_NO_REACHABLE_MEMBERS,
00532 QUEUE_NORMAL
00533 };
00534
00535
00536
00537
00538
00539
00540
00541 static enum queue_member_status get_member_status(struct call_queue *q, int max_penalty)
00542 {
00543 struct member *member;
00544 struct ao2_iterator mem_iter;
00545 enum queue_member_status result = QUEUE_NO_MEMBERS;
00546
00547 ast_mutex_lock(&q->lock);
00548 mem_iter = ao2_iterator_init(q->members, 0);
00549 while ((member = ao2_iterator_next(&mem_iter))) {
00550 if (max_penalty && (member->penalty > max_penalty)) {
00551 ao2_ref(member, -1);
00552 continue;
00553 }
00554
00555 if (member->paused) {
00556 ao2_ref(member, -1);
00557 continue;
00558 }
00559
00560 switch (member->status) {
00561 case AST_DEVICE_INVALID:
00562
00563 ao2_ref(member, -1);
00564 break;
00565 case AST_DEVICE_UNAVAILABLE:
00566 result = QUEUE_NO_REACHABLE_MEMBERS;
00567 ao2_ref(member, -1);
00568 break;
00569 default:
00570 ast_mutex_unlock(&q->lock);
00571 ao2_ref(member, -1);
00572 return QUEUE_NORMAL;
00573 }
00574 }
00575
00576 ast_mutex_unlock(&q->lock);
00577 return result;
00578 }
00579
00580 struct statechange {
00581 AST_LIST_ENTRY(statechange) entry;
00582 int state;
00583 char dev[0];
00584 };
00585
00586 static int update_status(const char *interface, const int status)
00587 {
00588 struct member *cur;
00589 struct ao2_iterator mem_iter;
00590 struct call_queue *q;
00591
00592 AST_LIST_LOCK(&queues);
00593 AST_LIST_TRAVERSE(&queues, q, list) {
00594 ast_mutex_lock(&q->lock);
00595 mem_iter = ao2_iterator_init(q->members, 0);
00596 while ((cur = ao2_iterator_next(&mem_iter))) {
00597 char *tmp_interface;
00598 char *slash_pos;
00599 tmp_interface = ast_strdupa(cur->interface);
00600 if ((slash_pos = strchr(tmp_interface, '/')))
00601 if ((slash_pos = strchr(slash_pos + 1, '/')))
00602 *slash_pos = '\0';
00603
00604 if (strcasecmp(interface, tmp_interface)) {
00605 ao2_ref(cur, -1);
00606 continue;
00607 }
00608
00609 if (cur->status != status) {
00610 cur->status = status;
00611 if (q->maskmemberstatus) {
00612 ao2_ref(cur, -1);
00613 continue;
00614 }
00615
00616 manager_event(EVENT_FLAG_AGENT, "QueueMemberStatus",
00617 "Queue: %s\r\n"
00618 "Location: %s\r\n"
00619 "MemberName: %s\r\n"
00620 "Membership: %s\r\n"
00621 "Penalty: %d\r\n"
00622 "CallsTaken: %d\r\n"
00623 "LastCall: %d\r\n"
00624 "Status: %d\r\n"
00625 "Paused: %d\r\n",
00626 q->name, cur->interface, cur->membername, cur->dynamic ? "dynamic" : cur->realtime ? "realtime" : "static",
00627 cur->penalty, cur->calls, (int)cur->lastcall, cur->status, cur->paused);
00628 }
00629 ao2_ref(cur, -1);
00630 }
00631 ast_mutex_unlock(&q->lock);
00632 }
00633 AST_LIST_UNLOCK(&queues);
00634
00635 return 0;
00636 }
00637
00638
00639 static void *handle_statechange(struct statechange *sc)
00640 {
00641 struct member_interface *curint;
00642 char *loc;
00643 char *technology;
00644
00645 technology = ast_strdupa(sc->dev);
00646 loc = strchr(technology, '/');
00647 if (loc) {
00648 *loc++ = '\0';
00649 } else {
00650 return NULL;
00651 }
00652
00653 AST_LIST_LOCK(&interfaces);
00654 AST_LIST_TRAVERSE(&interfaces, curint, list) {
00655 char *interface;
00656 char *slash_pos;
00657 interface = ast_strdupa(curint->interface);
00658 if ((slash_pos = strchr(interface, '/')))
00659 if ((slash_pos = strchr(slash_pos + 1, '/')))
00660 *slash_pos = '\0';
00661
00662 if (!strcasecmp(interface, sc->dev))
00663 break;
00664 }
00665 AST_LIST_UNLOCK(&interfaces);
00666
00667 if (!curint) {
00668 if (option_debug > 2)
00669 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s) but we don't care because they're not a member of any queue.\n", technology, loc, sc->state, devstate2str(sc->state));
00670 return NULL;
00671 }
00672
00673 if (option_debug)
00674 ast_log(LOG_DEBUG, "Device '%s/%s' changed to state '%d' (%s)\n", technology, loc, sc->state, devstate2str(sc->state));
00675
00676 update_status(sc->dev, sc->state);
00677
00678 return NULL;
00679 }
00680
00681
00682
00683
00684 static struct {
00685
00686 unsigned int stop:1;
00687
00688 pthread_t thread;
00689
00690 ast_mutex_t lock;
00691
00692 ast_cond_t cond;
00693
00694 AST_LIST_HEAD_NOLOCK(, statechange) state_change_q;
00695 } device_state = {
00696 .thread = AST_PTHREADT_NULL,
00697 };
00698
00699
00700 static void *device_state_thread(void *data)
00701 {
00702 struct statechange *sc = NULL;
00703
00704 while (!device_state.stop) {
00705 ast_mutex_lock(&device_state.lock);
00706 if (!(sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry))) {
00707 ast_cond_wait(&device_state.cond, &device_state.lock);
00708 sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry);
00709 }
00710 ast_mutex_unlock(&device_state.lock);
00711
00712
00713 if (device_state.stop)
00714 break;
00715
00716 if (!sc)
00717 continue;
00718
00719 handle_statechange(sc);
00720
00721 free(sc);
00722 sc = NULL;
00723 }
00724
00725 if (sc)
00726 free(sc);
00727
00728 while ((sc = AST_LIST_REMOVE_HEAD(&device_state.state_change_q, entry)))
00729 free(sc);
00730
00731 return NULL;
00732 }
00733
00734 static int statechange_queue(const char *dev, int state, void *ign)
00735 {
00736 struct statechange *sc;
00737
00738 if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(dev) + 1)))
00739 return 0;
00740
00741 sc->state = state;
00742 strcpy(sc->dev, dev);
00743
00744 ast_mutex_lock(&device_state.lock);
00745 AST_LIST_INSERT_TAIL(&device_state.state_change_q, sc, entry);
00746 ast_cond_signal(&device_state.cond);
00747 ast_mutex_unlock(&device_state.lock);
00748
00749 return 0;
00750 }
00751
00752 static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
00753 {
00754 struct member *cur;
00755
00756 if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
00757 cur->penalty = penalty;
00758 cur->paused = paused;
00759 ast_copy_string(cur->interface, interface, sizeof(cur->interface));
00760 if (!ast_strlen_zero(membername))
00761 ast_copy_string(cur->membername, membername, sizeof(cur->membername));
00762 else
00763 ast_copy_string(cur->membername, interface, sizeof(cur->membername));
00764 if (!strchr(cur->interface, '/'))
00765 ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
00766 cur->status = ast_device_state(interface);
00767 }
00768
00769 return cur;
00770 }
00771
00772 static struct call_queue *alloc_queue(const char *queuename)
00773 {
00774 struct call_queue *q;
00775
00776 if ((q = ast_calloc(1, sizeof(*q)))) {
00777 ast_mutex_init(&q->lock);
00778 ast_copy_string(q->name, queuename, sizeof(q->name));
00779 }
00780 return q;
00781 }
00782
00783 static int compress_char(const char c)
00784 {
00785 if (c < 32)
00786 return 0;
00787 else if (c > 96)
00788 return c - 64;
00789 else
00790 return c - 32;
00791 }
00792
00793 static int member_hash_fn(const void *obj, const int flags)
00794 {
00795 const struct member *mem = obj;
00796 const char *chname = strchr(mem->interface, '/');
00797 int ret = 0, i;
00798 if (!chname)
00799 chname = mem->interface;
00800 for (i = 0; i < 5 && chname[i]; i++)
00801 ret += compress_char(chname[i]) << (i * 6);
00802 return ret;
00803 }
00804
00805 static int member_cmp_fn(void *obj1, void *obj2, int flags)
00806 {
00807 struct member *mem1 = obj1, *mem2 = obj2;
00808 return strcmp(mem1->interface, mem2->interface) ? 0 : CMP_MATCH | CMP_STOP;
00809 }
00810
00811 static void init_queue(struct call_queue *q)
00812 {
00813 int i;
00814
00815 q->dead = 0;
00816 q->retry = DEFAULT_RETRY;
00817 q->timeout = -1;
00818 q->maxlen = 0;
00819 q->ringlimit = 0;
00820 q->announcefrequency = 0;
00821 q->announceholdtime = 0;
00822 q->roundingseconds = 0;
00823 q->servicelevel = 0;
00824 q->ringinuse = 1;
00825 q->setinterfacevar = 0;
00826 q->autofill = autofill_default;
00827 q->montype = montype_default;
00828 q->moh[0] = '\0';
00829 q->announce[0] = '\0';
00830 q->context[0] = '\0';
00831 q->monfmt[0] = '\0';
00832 q->periodicannouncefrequency = 0;
00833 q->reportholdtime = 0;
00834 q->monjoin = 0;
00835 q->wrapuptime = 0;
00836 q->joinempty = 0;
00837 q->leavewhenempty = 0;
00838 q->memberdelay = 0;
00839 q->maskmemberstatus = 0;
00840 q->eventwhencalled = 0;
00841 q->weight = 0;
00842 q->timeoutrestart = 0;
00843 if (!q->members)
00844 q->members = ao2_container_alloc(37, member_hash_fn, member_cmp_fn);
00845 q->membercount = 0;
00846 q->found = 1;
00847 ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next));
00848 ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare));
00849 ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls));
00850 ast_copy_string(q->sound_holdtime, "queue-holdtime", sizeof(q->sound_holdtime));
00851 ast_copy_string(q->sound_minutes, "queue-minutes", sizeof(q->sound_minutes));
00852 ast_copy_string(q->sound_seconds, "queue-seconds", sizeof(q->sound_seconds));
00853 ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks));
00854 ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan));
00855 ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold));
00856 ast_copy_string(q->sound_periodicannounce[0], "queue-periodic-announce", sizeof(q->sound_periodicannounce[0]));
00857 for (i = 1; i < MAX_PERIODIC_ANNOUNCEMENTS; i++) {
00858 q->sound_periodicannounce[i][0]='\0';
00859 }
00860 }
00861
00862 static void clear_queue(struct call_queue *q)
00863 {
00864 q->holdtime = 0;
00865 q->callscompleted = 0;
00866 q->callsabandoned = 0;
00867 q->callscompletedinsl = 0;
00868 q->wrapuptime = 0;
00869 }
00870
00871 static int add_to_interfaces(const char *interface)
00872 {
00873 struct member_interface *curint;
00874
00875 AST_LIST_LOCK(&interfaces);
00876 AST_LIST_TRAVERSE(&interfaces, curint, list) {
00877 if (!strcasecmp(curint->interface, interface))
00878 break;
00879 }
00880
00881 if (curint) {
00882 AST_LIST_UNLOCK(&interfaces);
00883 return 0;
00884 }
00885
00886 if (option_debug)
00887 ast_log(LOG_DEBUG, "Adding %s to the list of interfaces that make up all of our queue members.\n", interface);
00888
00889 if ((curint = ast_calloc(1, sizeof(*curint)))) {
00890 ast_copy_string(curint->interface, interface, sizeof(curint->interface));
00891 AST_LIST_INSERT_HEAD(&interfaces, curint, list);
00892 }
00893 AST_LIST_UNLOCK(&interfaces);
00894
00895 return 0;
00896 }
00897
00898 static int interface_exists_global(const char *interface)
00899 {
00900 struct call_queue *q;
00901 struct member *mem, tmpmem;
00902 int ret = 0;
00903
00904 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
00905
00906 AST_LIST_LOCK(&queues);
00907 AST_LIST_TRAVERSE(&queues, q, list) {
00908 ast_mutex_lock(&q->lock);
00909 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
00910 ao2_ref(mem, -1);
00911 ret = 1;
00912 }
00913 ast_mutex_unlock(&q->lock);
00914 if (ret)
00915 break;
00916 }
00917 AST_LIST_UNLOCK(&queues);
00918
00919 return ret;
00920 }
00921
00922 static int remove_from_interfaces(const char *interface)
00923 {
00924 struct member_interface *curint;
00925
00926 if (interface_exists_global(interface))
00927 return 0;
00928
00929 AST_LIST_LOCK(&interfaces);
00930 AST_LIST_TRAVERSE_SAFE_BEGIN(&interfaces, curint, list) {
00931 if (!strcasecmp(curint->interface, interface)) {
00932 if (option_debug)
00933 ast_log(LOG_DEBUG, "Removing %s from the list of interfaces that make up all of our queue members.\n", interface);
00934 AST_LIST_REMOVE_CURRENT(&interfaces, list);
00935 free(curint);
00936 break;
00937 }
00938 }
00939 AST_LIST_TRAVERSE_SAFE_END;
00940 AST_LIST_UNLOCK(&interfaces);
00941
00942 return 0;
00943 }
00944
00945 static void clear_and_free_interfaces(void)
00946 {
00947 struct member_interface *curint;
00948
00949 AST_LIST_LOCK(&interfaces);
00950 while ((curint = AST_LIST_REMOVE_HEAD(&interfaces, list)))
00951 free(curint);
00952 AST_LIST_UNLOCK(&interfaces);
00953 }
00954
00955
00956
00957
00958
00959
00960
00961
00962 static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
00963 {
00964 if (!strcasecmp(param, "musicclass") ||
00965 !strcasecmp(param, "music") || !strcasecmp(param, "musiconhold")) {
00966 ast_copy_string(q->moh, val, sizeof(q->moh));
00967 } else if (!strcasecmp(param, "announce")) {
00968 ast_copy_string(q->announce, val, sizeof(q->announce));
00969 } else if (!strcasecmp(param, "context")) {
00970 ast_copy_string(q->context, val, sizeof(q->context));
00971 } else if (!strcasecmp(param, "timeout")) {
00972 q->timeout = atoi(val);
00973 if (q->timeout < 0)
00974 q->timeout = DEFAULT_TIMEOUT;
00975 } else if (!strcasecmp(param, "ringinuse")) {
00976 q->ringinuse = ast_true(val);
00977 } else if (!strcasecmp(param, "setinterfacevar")) {
00978 q->setinterfacevar = ast_true(val);
00979 } else if (!strcasecmp(param, "monitor-join")) {
00980 monjoin_dep_warning();
00981 q->monjoin = ast_true(val);
00982 } else if (!strcasecmp(param, "monitor-format")) {
00983 ast_copy_string(q->monfmt, val, sizeof(q->monfmt));
00984 } else if (!strcasecmp(param, "queue-youarenext")) {
00985 ast_copy_string(q->sound_next, val, sizeof(q->sound_next));
00986 } else if (!strcasecmp(param, "queue-thereare")) {
00987 ast_copy_string(q->sound_thereare, val, sizeof(q->sound_thereare));
00988 } else if (!strcasecmp(param, "queue-callswaiting")) {
00989 ast_copy_string(q->sound_calls, val, sizeof(q->sound_calls));
00990 } else if (!strcasecmp(param, "queue-holdtime")) {
00991 ast_copy_string(q->sound_holdtime, val, sizeof(q->sound_holdtime));
00992 } else if (!strcasecmp(param, "queue-minutes")) {
00993 ast_copy_string(q->sound_minutes, val, sizeof(q->sound_minutes));
00994 } else if (!strcasecmp(param, "queue-seconds")) {
00995 ast_copy_string(q->sound_seconds, val, sizeof(q->sound_seconds));
00996 } else if (!strcasecmp(param, "queue-lessthan")) {
00997 ast_copy_string(q->sound_lessthan, val, sizeof(q->sound_lessthan));
00998 } else if (!strcasecmp(param, "queue-thankyou")) {
00999 ast_copy_string(q->sound_thanks, val, sizeof(q->sound_thanks));
01000 } else if (!strcasecmp(param, "queue-reporthold")) {
01001 ast_copy_string(q->sound_reporthold, val, sizeof(q->sound_reporthold));
01002 } else if (!strcasecmp(param, "announce-frequency")) {
01003 q->announcefrequency = atoi(val);
01004 } else if (!strcasecmp(param, "announce-round-seconds")) {
01005 q->roundingseconds = atoi(val);
01006 if (q->roundingseconds>60 || q->roundingseconds<0) {
01007 if (linenum >= 0) {
01008 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01009 "using 0 instead for queue '%s' at line %d of queues.conf\n",
01010 val, param, q->name, linenum);
01011 } else {
01012 ast_log(LOG_WARNING, "'%s' isn't a valid value for %s "
01013 "using 0 instead for queue '%s'\n", val, param, q->name);
01014 }
01015 q->roundingseconds=0;
01016 }
01017 } else if (!strcasecmp(param, "announce-holdtime")) {
01018 if (!strcasecmp(val, "once"))
01019 q->announceholdtime = ANNOUNCEHOLDTIME_ONCE;
01020 else if (ast_true(val))
01021 q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS;
01022 else
01023 q->announceholdtime = 0;
01024 } else if (!strcasecmp(param, "periodic-announce")) {
01025 if (strchr(val, '|')) {
01026 char *s, *buf = ast_strdupa(val);
01027 unsigned int i = 0;
01028
01029 while ((s = strsep(&buf, "|"))) {
01030 ast_copy_string(q->sound_periodicannounce[i], s, sizeof(q->sound_periodicannounce[i]));
01031 i++;
01032 if (i == MAX_PERIODIC_ANNOUNCEMENTS)
01033 break;
01034 }
01035 } else {
01036 ast_copy_string(q->sound_periodicannounce[0], val, sizeof(q->sound_periodicannounce[0]));
01037 }
01038 } else if (!strcasecmp(param, "periodic-announce-frequency")) {
01039 q->periodicannouncefrequency = atoi(val);
01040 } else if (!strcasecmp(param, "retry")) {
01041 q->retry = atoi(val);
01042 if (q->retry <= 0)
01043 q->retry = DEFAULT_RETRY;
01044 } else if (!strcasecmp(param, "wrapuptime")) {
01045 q->wrapuptime = atoi(val);
01046 } else if (!strcasecmp(param, "autofill")) {
01047 q->autofill = ast_true(val);
01048 } else if (!strcasecmp(param, "monitor-type")) {
01049 if (!strcasecmp(val, "mixmonitor"))
01050 q->montype = 1;
01051 } else if (!strcasecmp(param, "autopause")) {
01052 q->autopause = ast_true(val);
01053 } else if (!strcasecmp(param, "maxlen")) {
01054 q->maxlen = atoi(val);
01055 if (q->maxlen < 0)
01056 q->maxlen = 0;
01057 } else if (!strcasecmp(param, "ringlimit")) {
01058 q->ringlimit = atoi(val);
01059 if (q->ringlimit < 0)
01060 q->ringlimit = 0;
01061 } else if (!strcasecmp(param, "servicelevel")) {
01062 q->servicelevel= atoi(val);
01063 } else if (!strcasecmp(param, "strategy")) {
01064 q->strategy = strat2int(val);
01065 if (q->strategy < 0) {
01066 ast_log(LOG_WARNING, "'%s' isn't a valid strategy for queue '%s', using ringall instead\n",
01067 val, q->name);
01068 q->strategy = QUEUE_STRATEGY_RINGALL;
01069 }
01070 } else if (!strcasecmp(param, "joinempty")) {
01071 if (!strcasecmp(val, "strict"))
01072 q->joinempty = QUEUE_EMPTY_STRICT;
01073 else if (ast_true(val))
01074 q->joinempty = QUEUE_EMPTY_NORMAL;
01075 else
01076 q->joinempty = 0;
01077 } else if (!strcasecmp(param, "leavewhenempty")) {
01078 if (!strcasecmp(val, "strict"))
01079 q->leavewhenempty = QUEUE_EMPTY_STRICT;
01080 else if (ast_true(val))
01081 q->leavewhenempty = QUEUE_EMPTY_NORMAL;
01082 else
01083 q->leavewhenempty = 0;
01084 } else if (!strcasecmp(param, "eventmemberstatus")) {
01085 q->maskmemberstatus = !ast_true(val);
01086 } else if (!strcasecmp(param, "eventwhencalled")) {
01087 if (!strcasecmp(val, "vars")) {
01088 q->eventwhencalled = QUEUE_EVENT_VARIABLES;
01089 } else {
01090 q->eventwhencalled = ast_true(val) ? 1 : 0;
01091 }
01092 } else if (!strcasecmp(param, "reportholdtime")) {
01093 q->reportholdtime = ast_true(val);
01094 } else if (!strcasecmp(param, "memberdelay")) {
01095 q->memberdelay = atoi(val);
01096 } else if (!strcasecmp(param, "weight")) {
01097 q->weight = atoi(val);
01098 if (q->weight)
01099 use_weight++;
01100
01101
01102 } else if (!strcasecmp(param, "timeoutrestart")) {
01103 q->timeoutrestart = ast_true(val);
01104 } else if (failunknown) {
01105 if (linenum >= 0) {
01106 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queues.conf\n",
01107 q->name, param, linenum);
01108 } else {
01109 ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
01110 }
01111 }
01112 }
01113
01114 static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
01115 {
01116 struct member *m, tmpmem;
01117 int penalty = 0;
01118 int paused = 0;
01119
01120 if (penalty_str) {
01121 penalty = atoi(penalty_str);
01122 if (penalty < 0)
01123 penalty = 0;
01124 }
01125
01126 if (paused_str) {
01127 paused = atoi(paused_str);
01128 if (paused < 0)
01129 paused = 0;
01130 }
01131
01132
01133 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
01134 m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
01135
01136
01137 if (!m) {
01138 if ((m = create_queue_member(interface, membername, penalty, paused))) {
01139 m->dead = 0;
01140 m->realtime = 1;
01141 add_to_interfaces(interface);
01142 ao2_link(q->members, m);
01143 ao2_ref(m, -1);
01144 m = NULL;
01145 q->membercount++;
01146 }
01147 } else {
01148 m->dead = 0;
01149 if (paused_str)
01150 m->paused = paused;
01151 m->penalty = penalty;
01152 ao2_ref(m, -1);
01153 }
01154 }
01155
01156 static void free_members(struct call_queue *q, int all)
01157 {
01158
01159 struct member *cur;
01160 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
01161
01162 while ((cur = ao2_iterator_next(&mem_iter))) {
01163 if (all || !cur->dynamic) {
01164 ao2_unlink(q->members, cur);
01165 remove_from_interfaces(cur->interface);
01166 q->membercount--;
01167 }
01168 ao2_ref(cur, -1);
01169 }
01170 }
01171
01172 static void destroy_queue(struct call_queue *q)
01173 {
01174 free_members(q, 1);
01175 ast_mutex_destroy(&q->lock);
01176 ao2_ref(q->members, -1);
01177 free(q);
01178 }
01179
01180
01181
01182
01183 static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
01184 {
01185 struct ast_variable *v;
01186 struct call_queue *q;
01187 struct member *m;
01188 struct ao2_iterator mem_iter;
01189 char *interface = NULL;
01190 char *tmp, *tmp_name;
01191 char tmpbuf[64];
01192
01193
01194 AST_LIST_TRAVERSE(&queues, q, list) {
01195 if (!strcasecmp(q->name, queuename))
01196 break;
01197 }
01198
01199
01200 if (q) {
01201 ast_mutex_lock(&q->lock);
01202 if (!q->realtime) {
01203 if (q->dead) {
01204 ast_mutex_unlock(&q->lock);
01205 return NULL;
01206 } else {
01207 ast_log(LOG_WARNING, "Static queue '%s' already exists. Not loading from realtime\n", q->name);
01208 ast_mutex_unlock(&q->lock);
01209 return q;
01210 }
01211 }
01212 } else if (!member_config)
01213
01214 return NULL;
01215
01216
01217 if (!queue_vars) {
01218
01219 if (q) {
01220
01221
01222
01223 ast_log(LOG_DEBUG, "Queue %s not found in realtime.\n", queuename);
01224
01225 q->dead = 1;
01226
01227 if (!q->count) {
01228
01229 AST_LIST_REMOVE(&queues, q, list);
01230 ast_mutex_unlock(&q->lock);
01231 destroy_queue(q);
01232 } else
01233 ast_mutex_unlock(&q->lock);
01234 }
01235 return NULL;
01236 }
01237
01238
01239 if (!q) {
01240 if (!(q = alloc_queue(queuename)))
01241 return NULL;
01242 ast_mutex_lock(&q->lock);
01243 clear_queue(q);
01244 q->realtime = 1;
01245 AST_LIST_INSERT_HEAD(&queues, q, list);
01246 }
01247 init_queue(q);
01248
01249 memset(tmpbuf, 0, sizeof(tmpbuf));
01250 for (v = queue_vars; v; v = v->next) {
01251
01252 if ((tmp = strchr(v->name, '_'))) {
01253 ast_copy_string(tmpbuf, v->name, sizeof(tmpbuf));
01254 tmp_name = tmpbuf;
01255 tmp = tmp_name;
01256 while ((tmp = strchr(tmp, '_')))
01257 *tmp++ = '-';
01258 } else
01259 tmp_name = v->name;
01260
01261 if (!ast_strlen_zero(v->value)) {
01262
01263 queue_set_param(q, tmp_name, v->value, -1, 0);
01264 }
01265 }
01266
01267 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
01268 rr_dep_warning();
01269
01270
01271
01272 mem_iter = ao2_iterator_init(q->members, 0);
01273 while ((m = ao2_iterator_next(&mem_iter))) {
01274 q->membercount++;
01275 if (m->realtime)
01276 m->dead = 1;
01277 ao2_ref(m, -1);
01278 }
01279
01280 while ((interface = ast_category_browse(member_config, interface))) {
01281 rt_handle_member_record(q, interface,
01282 ast_variable_retrieve(member_config, interface, "membername"),
01283 ast_variable_retrieve(member_config, interface, "penalty"),
01284 ast_variable_retrieve(member_config, interface, "paused"));
01285 }
01286
01287
01288 mem_iter = ao2_iterator_init(q->members, 0);
01289 while ((m = ao2_iterator_next(&mem_iter))) {
01290 if (m->dead) {
01291 ao2_unlink(q->members, m);
01292 ast_mutex_unlock(&q->lock);
01293 remove_from_interfaces(m->interface);
01294 ast_mutex_lock(&q->lock);
01295 q->membercount--;
01296 }
01297 ao2_ref(m, -1);
01298 }
01299
01300 ast_mutex_unlock(&q->lock);
01301
01302 return q;
01303 }
01304
01305 static int update_realtime_member_field(struct member *mem, const char *queue_name, const char *field, const char *value)
01306 {
01307 struct ast_variable *var;
01308 int ret = -1;
01309
01310 if (!(var = ast_load_realtime("queue_members", "interface", mem->interface, "queue_name", queue_name, NULL)))
01311 return ret;
01312 while (var) {
01313 if (!strcmp(var->name, "uniqueid"))
01314 break;
01315 var = var->next;
01316 }
01317 if (var && !ast_strlen_zero(var->value)) {
01318 if ((ast_update_realtime("queue_members", "uniqueid", var->value, field, value, NULL)) > -1)
01319 ret = 0;
01320 }
01321 return ret;
01322 }
01323
01324 static void update_realtime_members(struct call_queue *q)
01325 {
01326 struct ast_config *member_config = NULL;
01327 struct member *m;
01328 char *interface = NULL;
01329 struct ao2_iterator mem_iter;
01330
01331 if (!(member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", q->name , NULL))) {
01332
01333 if (option_debug > 2)
01334 ast_log(LOG_DEBUG, "Queue %s has no realtime members defined. No need for update\n", q->name);
01335 return;
01336 }
01337
01338 ast_mutex_lock(&q->lock);
01339
01340
01341 mem_iter = ao2_iterator_init(q->members, 0);
01342 while ((m = ao2_iterator_next(&mem_iter))) {
01343 if (m->realtime)
01344 m->dead = 1;
01345 ao2_ref(m, -1);
01346 }
01347
01348 while ((interface = ast_category_browse(member_config, interface))) {
01349 rt_handle_member_record(q, interface,
01350 S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
01351 ast_variable_retrieve(member_config, interface, "penalty"),
01352 ast_variable_retrieve(member_config, interface, "paused"));
01353 }
01354
01355
01356 mem_iter = ao2_iterator_init(q->members, 0);
01357 while ((m = ao2_iterator_next(&mem_iter))) {
01358 if (m->dead) {
01359 ao2_unlink(q->members, m);
01360 ast_mutex_unlock(&q->lock);
01361 remove_from_interfaces(m->interface);
01362 ast_mutex_lock(&q->lock);
01363 q->membercount--;
01364 }
01365 ao2_ref(m, -1);
01366 }
01367 ast_mutex_unlock(&q->lock);
01368 ast_config_destroy(member_config);
01369 }
01370
01371 static struct call_queue *load_realtime_queue(const char *queuename)
01372 {
01373 struct ast_variable *queue_vars;
01374 struct ast_config *member_config = NULL;
01375 struct call_queue *q;
01376
01377
01378 AST_LIST_LOCK(&queues);
01379 AST_LIST_TRAVERSE(&queues, q, list) {
01380 if (!strcasecmp(q->name, queuename)) {
01381 break;
01382 }
01383 }
01384 AST_LIST_UNLOCK(&queues);
01385
01386 if (!q || q->realtime) {
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396 queue_vars = ast_load_realtime("queues", "name", queuename, NULL);
01397 if (queue_vars) {
01398 member_config = ast_load_realtime_multientry("queue_members", "interface LIKE", "%", "queue_name", queuename, NULL);
01399 if (!member_config) {
01400 ast_log(LOG_ERROR, "no queue_members defined in your config (extconfig.conf).\n");
01401 ast_variables_destroy(queue_vars);
01402 return NULL;
01403 }
01404 }
01405
01406 AST_LIST_LOCK(&queues);
01407
01408 q = find_queue_by_name_rt(queuename, queue_vars, member_config);
01409 if (member_config)
01410 ast_config_destroy(member_config);
01411 if (queue_vars)
01412 ast_variables_destroy(queue_vars);
01413
01414 AST_LIST_UNLOCK(&queues);
01415 } else {
01416 update_realtime_members(q);
01417 }
01418 return q;
01419 }
01420
01421 static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason)
01422 {
01423 struct call_queue *q;
01424 struct queue_ent *cur, *prev = NULL;
01425 int res = -1;
01426 int pos = 0;
01427 int inserted = 0;
01428 enum queue_member_status stat;
01429
01430 if (!(q = load_realtime_queue(queuename)))
01431 return res;
01432
01433 AST_LIST_LOCK(&queues);
01434 ast_mutex_lock(&q->lock);
01435
01436
01437 stat = get_member_status(q, qe->max_penalty);
01438 if (!q->joinempty && (stat == QUEUE_NO_MEMBERS))
01439 *reason = QUEUE_JOINEMPTY;
01440 else if ((q->joinempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS || stat == QUEUE_NO_MEMBERS))
01441 *reason = QUEUE_JOINUNAVAIL;
01442 else if (q->maxlen && (q->count >= q->maxlen))
01443 *reason = QUEUE_FULL;
01444 else {
01445
01446
01447
01448 inserted = 0;
01449 prev = NULL;
01450 cur = q->head;
01451 while (cur) {
01452
01453
01454
01455 if ((!inserted) && (qe->prio > cur->prio)) {
01456 insert_entry(q, prev, qe, &pos);
01457 inserted = 1;
01458 }
01459 cur->pos = ++pos;
01460 prev = cur;
01461 cur = cur->next;
01462 }
01463
01464 if (!inserted)
01465 insert_entry(q, prev, qe, &pos);
01466 ast_copy_string(qe->moh, q->moh, sizeof(qe->moh));
01467 ast_copy_string(qe->announce, q->announce, sizeof(qe->announce));
01468 ast_copy_string(qe->context, q->context, sizeof(qe->context));
01469 q->count++;
01470 res = 0;
01471 manager_event(EVENT_FLAG_CALL, "Join",
01472 "Channel: %s\r\nCallerID: %s\r\nCallerIDName: %s\r\nQueue: %s\r\nPosition: %d\r\nCount: %d\r\nUniqueid: %s\r\n",
01473 qe->chan->name,
01474 S_OR(qe->chan->cid.cid_num, "unknown"),
01475 S_OR(qe->chan->cid.cid_name, "unknown"),
01476 q->name, qe->pos, q->count, qe->chan->uniqueid );
01477 if (option_debug)
01478 ast_log(LOG_DEBUG, "Queue '%s' Join, Channel '%s', Position '%d'\n", q->name, qe->chan->name, qe->pos );
01479 }
01480 ast_mutex_unlock(&q->lock);
01481 AST_LIST_UNLOCK(&queues);
01482
01483 return res;
01484 }
01485
01486 static int play_file(struct ast_channel *chan, char *filename)
01487 {
01488 int res;
01489
01490 ast_stopstream(chan);
01491
01492 res = ast_streamfile(chan, filename, chan->language);
01493 if (!res)
01494 res = ast_waitstream(chan, AST_DIGIT_ANY);
01495
01496 ast_stopstream(chan);
01497
01498 return res;
01499 }
01500
01501 static int valid_exit(struct queue_ent *qe, char digit)
01502 {
01503 int digitlen = strlen(qe->digits);
01504
01505
01506 if (digitlen < sizeof(qe->digits) - 2) {
01507 qe->digits[digitlen] = digit;
01508 qe->digits[digitlen + 1] = '\0';
01509 } else {
01510 qe->digits[0] = '\0';
01511 return 0;
01512 }
01513
01514
01515 if (ast_strlen_zero(qe->context))
01516 return 0;
01517
01518
01519 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
01520 qe->digits[0] = '\0';
01521 return 0;
01522 }
01523
01524
01525 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
01526 qe->valid_digits = 1;
01527
01528 return 1;
01529 }
01530
01531 return 0;
01532 }
01533
01534 static int say_position(struct queue_ent *qe)
01535 {
01536 int res = 0, avgholdmins, avgholdsecs;
01537 time_t now;
01538
01539
01540 time(&now);
01541 if ((now - qe->last_pos) < 15)
01542 return 0;
01543
01544
01545 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
01546 return 0;
01547
01548 ast_moh_stop(qe->chan);
01549
01550 if (qe->pos == 1) {
01551 res = play_file(qe->chan, qe->parent->sound_next);
01552 if (res)
01553 goto playout;
01554 else
01555 goto posout;
01556 } else {
01557 res = play_file(qe->chan, qe->parent->sound_thereare);
01558 if (res)
01559 goto playout;
01560 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL);
01561 if (res)
01562 goto playout;
01563 res = play_file(qe->chan, qe->parent->sound_calls);
01564 if (res)
01565 goto playout;
01566 }
01567
01568 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
01569
01570
01571 if (qe->parent->roundingseconds) {
01572 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
01573 avgholdsecs *= qe->parent->roundingseconds;
01574 } else {
01575 avgholdsecs = 0;
01576 }
01577
01578 if (option_verbose > 2)
01579 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01580
01581
01582
01583 if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) &&
01584 (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) {
01585 res = play_file(qe->chan, qe->parent->sound_holdtime);
01586 if (res)
01587 goto playout;
01588
01589 if (avgholdmins > 0) {
01590 if (avgholdmins < 2) {
01591 res = play_file(qe->chan, qe->parent->sound_lessthan);
01592 if (res)
01593 goto playout;
01594
01595 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
01596 if (res)
01597 goto playout;
01598 } else {
01599 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
01600 if (res)
01601 goto playout;
01602 }
01603
01604 res = play_file(qe->chan, qe->parent->sound_minutes);
01605 if (res)
01606 goto playout;
01607 }
01608 if (avgholdsecs>0) {
01609 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
01610 if (res)
01611 goto playout;
01612
01613 res = play_file(qe->chan, qe->parent->sound_seconds);
01614 if (res)
01615 goto playout;
01616 }
01617
01618 }
01619
01620 posout:
01621 if (option_verbose > 2)
01622 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
01623 qe->chan->name, qe->parent->name, qe->pos);
01624 res = play_file(qe->chan, qe->parent->sound_thanks);
01625
01626 playout:
01627 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
01628 res = 0;
01629
01630
01631 qe->last_pos = now;
01632 qe->last_pos_said = qe->pos;
01633
01634
01635 if (!res)
01636 ast_moh_start(qe->chan, qe->moh, NULL);
01637
01638 return res;
01639 }
01640
01641 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
01642 {
01643 int oldvalue;
01644
01645
01646
01647
01648
01649 ast_mutex_lock(&qe->parent->lock);
01650 oldvalue = qe->parent->holdtime;
01651 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
01652 ast_mutex_unlock(&qe->parent->lock);
01653 }
01654
01655
01656 static void leave_queue(struct queue_ent *qe)
01657 {
01658 struct call_queue *q;
01659 struct queue_ent *cur, *prev = NULL;
01660 int pos = 0;
01661
01662 if (!(q = qe->parent))
01663 return;
01664 ast_mutex_lock(&q->lock);
01665
01666 prev = NULL;
01667 for (cur = q->head; cur; cur = cur->next) {
01668 if (cur == qe) {
01669 q->count--;
01670
01671
01672 manager_event(EVENT_FLAG_CALL, "Leave",
01673 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
01674 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
01675 if (option_debug)
01676 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
01677
01678 if (prev)
01679 prev->next = cur->next;
01680 else
01681 q->head = cur->next;
01682 } else {
01683
01684 cur->pos = ++pos;
01685 prev = cur;
01686 }
01687 }
01688 ast_mutex_unlock(&q->lock);
01689
01690 if (q->dead && !q->count) {
01691
01692 AST_LIST_LOCK(&queues);
01693 AST_LIST_REMOVE(&queues, q, list);
01694 AST_LIST_UNLOCK(&queues);
01695 destroy_queue(q);
01696 }
01697 }
01698
01699
01700 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
01701 {
01702 struct callattempt *oo;
01703
01704 while (outgoing) {
01705
01706 if (outgoing->chan && (outgoing->chan != exception))
01707 ast_hangup(outgoing->chan);
01708 oo = outgoing;
01709 outgoing = outgoing->q_next;
01710 if (oo->member)
01711 ao2_ref(oo->member, -1);
01712 free(oo);
01713 }
01714 }
01715
01716
01717
01718
01719 static int compare_weight(struct call_queue *rq, struct member *member)
01720 {
01721 struct call_queue *q;
01722 struct member *mem;
01723 int found = 0;
01724
01725
01726
01727 AST_LIST_TRAVERSE(&queues, q, list) {
01728 if (q == rq)
01729 continue;
01730 ast_mutex_lock(&q->lock);
01731 if (q->count && q->members) {
01732 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
01733 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
01734 if (q->weight > rq->weight) {
01735 ast_log(LOG_DEBUG, "Queue '%s' (weight %d, calls %d) is preferred over '%s' (weight %d, calls %d)\n", q->name, q->weight, q->count, rq->name, rq->weight, rq->count);
01736 found = 1;
01737 }
01738 ao2_ref(mem, -1);
01739 }
01740 }
01741 ast_mutex_unlock(&q->lock);
01742 if (found)
01743 break;
01744 }
01745 return found;
01746 }
01747
01748
01749 static void do_hang(struct callattempt *o)
01750 {
01751 o->stillgoing = 0;
01752 ast_hangup(o->chan);
01753 o->chan = NULL;
01754 }
01755
01756 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
01757 {
01758 char *tmp = alloca(len);
01759
01760 if (pbx_builtin_serialize_variables(chan, tmp, len)) {
01761 int i, j;
01762
01763
01764 strcpy(vars, "Variable: ");
01765
01766 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
01767 vars[j] = tmp[i];
01768
01769 if (tmp[i + 1] == '\0')
01770 break;
01771 if (tmp[i] == '\n') {
01772 vars[j++] = '\r';
01773 vars[j++] = '\n';
01774
01775 ast_copy_string(&(vars[j]), "Variable: ", len - j);
01776 j += 9;
01777 }
01778 }
01779 if (j > len - 3)
01780 j = len - 3;
01781 vars[j++] = '\r';
01782 vars[j++] = '\n';
01783 vars[j] = '\0';
01784 } else {
01785
01786 *vars = '\0';
01787 }
01788 return vars;
01789 }
01790
01791
01792
01793
01794
01795
01796 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
01797 {
01798 int res;
01799 int status;
01800 char tech[256];
01801 char *location;
01802 const char *macrocontext, *macroexten;
01803
01804
01805 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
01806 if (queue_debug)
01807 ast_log(LOG_NOTICE, "Wrapuptime not yet expired for %s\n", tmp->interface);
01808 if (qe->chan->cdr)
01809 ast_cdr_busy(qe->chan->cdr);
01810 tmp->stillgoing = 0;
01811 (*busies)++;
01812 return 0;
01813 }
01814
01815 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
01816 if (queue_debug)
01817 ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface);
01818 if (qe->chan->cdr)
01819 ast_cdr_busy(qe->chan->cdr);
01820 tmp->stillgoing = 0;
01821 return 0;
01822 }
01823
01824 if (tmp->member->paused) {
01825 if (queue_debug)
01826 ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface);
01827 if (qe->chan->cdr)
01828 ast_cdr_busy(qe->chan->cdr);
01829 tmp->stillgoing = 0;
01830 return 0;
01831 }
01832 if (use_weight && compare_weight(qe->parent,tmp->member)) {
01833 if (queue_debug)
01834 ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
01835 if (qe->chan->cdr)
01836 ast_cdr_busy(qe->chan->cdr);
01837 tmp->stillgoing = 0;
01838 (*busies)++;
01839 return 0;
01840 }
01841
01842 ast_copy_string(tech, tmp->interface, sizeof(tech));
01843 if ((location = strchr(tech, '/')))
01844 *location++ = '\0';
01845 else
01846 location = "";
01847
01848
01849 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
01850 if (!tmp->chan) {
01851 if (queue_debug)
01852 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech);
01853 if (qe->chan->cdr)
01854 ast_cdr_busy(qe->chan->cdr);
01855 tmp->stillgoing = 0;
01856
01857 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
01858
01859 ast_mutex_lock(&qe->parent->lock);
01860 qe->parent->rrpos++;
01861 ast_mutex_unlock(&qe->parent->lock);
01862
01863 (*busies)++;
01864 return 0;
01865 }
01866
01867
01868 tmp->member->ringcount++;
01869 tmp->chan->appl = "AppQueue";
01870 tmp->chan->data = "(Outgoing Line)";
01871 tmp->chan->whentohangup = 0;
01872 if (tmp->chan->cid.cid_num)
01873 free(tmp->chan->cid.cid_num);
01874 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
01875 if (tmp->chan->cid.cid_name)
01876 free(tmp->chan->cid.cid_name);
01877 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
01878 if (tmp->chan->cid.cid_ani)
01879 free(tmp->chan->cid.cid_ani);
01880 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
01881
01882
01883 ast_channel_inherit_variables(qe->chan, tmp->chan);
01884
01885
01886 tmp->chan->adsicpe = qe->chan->adsicpe;
01887
01888
01889 ast_channel_lock(qe->chan);
01890 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
01891 if (!ast_strlen_zero(macrocontext))
01892 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
01893 else
01894 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
01895 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
01896 if (!ast_strlen_zero(macroexten))
01897 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
01898 else
01899 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
01900 ast_channel_unlock(qe->chan);
01901
01902
01903 if ((res = ast_call(tmp->chan, location, 0))) {
01904
01905 if (option_debug)
01906 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01907 if (option_verbose > 2)
01908 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
01909 do_hang(tmp);
01910 (*busies)++;
01911 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
01912 return 0;
01913 } else if (qe->parent->eventwhencalled) {
01914 char vars[2048];
01915
01916 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
01917 "AgentCalled: %s\r\n"
01918 "AgentName: %s\r\n"
01919 "ChannelCalling: %s\r\n"
01920 "CallerID: %s\r\n"
01921 "CallerIDName: %s\r\n"
01922 "Context: %s\r\n"
01923 "Extension: %s\r\n"
01924 "Priority: %d\r\n"
01925 "%s",
01926 tmp->interface, tmp->member->membername, qe->chan->name,
01927 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
01928 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
01929 qe->chan->context, qe->chan->exten, qe->chan->priority,
01930 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
01931 if (option_verbose > 2)
01932 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
01933 }
01934
01935 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
01936 return 1;
01937 }
01938
01939
01940 static struct callattempt *find_best(struct callattempt *outgoing)
01941 {
01942 struct callattempt *best = NULL, *cur;
01943
01944 for (cur = outgoing; cur; cur = cur->q_next) {
01945 if (cur->stillgoing &&
01946 !cur->chan &&
01947 (!best || cur->metric < best->metric)) {
01948 best = cur;
01949 }
01950 }
01951
01952 return best;
01953 }
01954
01955
01956
01957
01958
01959
01960
01961
01962
01963 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
01964 {
01965 int ret = 0;
01966
01967 while (ret == 0) {
01968 struct callattempt *best = find_best(outgoing);
01969 if (!best) {
01970 if (option_debug)
01971 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
01972 break;
01973 }
01974 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
01975 struct callattempt *cur;
01976
01977 for (cur = outgoing; cur; cur = cur->q_next) {
01978 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
01979 if (option_debug)
01980 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
01981 ret |= ring_entry(qe, cur, busies);
01982 }
01983 }
01984 } else {
01985
01986 if (option_debug)
01987 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
01988 ret = ring_entry(qe, best, busies);
01989 }
01990 }
01991
01992 return ret;
01993 }
01994
01995 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
01996 {
01997 struct callattempt *best = find_best(outgoing);
01998
01999 if (best) {
02000
02001 if (option_debug)
02002 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
02003 qe->parent->rrpos = best->metric % 1000;
02004 } else {
02005
02006 if (qe->parent->wrapped) {
02007
02008 qe->parent->rrpos = 0;
02009 } else {
02010
02011 qe->parent->rrpos++;
02012 }
02013 }
02014 qe->parent->wrapped = 0;
02015
02016 return 0;
02017 }
02018
02019 static int say_periodic_announcement(struct queue_ent *qe)
02020 {
02021 int res = 0;
02022 time_t now;
02023
02024
02025 time(&now);
02026
02027
02028 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
02029 return 0;
02030
02031
02032 ast_moh_stop(qe->chan);
02033
02034 if (option_verbose > 2)
02035 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
02036
02037
02038 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
02039 qe->last_periodic_announce_sound = 0;
02040 }
02041
02042
02043 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
02044
02045 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
02046 res = 0;
02047
02048
02049 if (!res)
02050 ast_moh_start(qe->chan, qe->moh, NULL);
02051
02052
02053 qe->last_periodic_announce_time = now;
02054
02055
02056 qe->last_periodic_announce_sound++;
02057
02058 return res;
02059 }
02060
02061 static void record_abandoned(struct queue_ent *qe)
02062 {
02063 ast_mutex_lock(&qe->parent->lock);
02064 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
02065 "Queue: %s\r\n"
02066 "Uniqueid: %s\r\n"
02067 "Position: %d\r\n"
02068 "OriginalPosition: %d\r\n"
02069 "HoldTime: %d\r\n",
02070 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
02071
02072 qe->parent->callsabandoned++;
02073 ast_mutex_unlock(&qe->parent->lock);
02074 }
02075
02076
02077 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername)
02078 {
02079 if (option_verbose > 2)
02080 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
02081 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
02082 if (qe->parent->autopause) {
02083 if (!set_member_paused(qe->parent->name, interface, 1)) {
02084 if (option_verbose > 2)
02085 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
02086 } else {
02087 if (option_verbose > 2)
02088 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
02089 }
02090 }
02091 return;
02092 }
02093
02094 #define AST_MAX_WATCHERS 256
02095
02096
02097
02098
02099
02100
02101
02102
02103
02104
02105 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
02106 {
02107 char *queue = qe->parent->name;
02108 struct callattempt *o, *start = NULL, *prev = NULL;
02109 int status;
02110 int numbusies = prebusies;
02111 int numnochan = 0;
02112 int stillgoing = 0;
02113 int orig = *to;
02114 struct ast_frame *f;
02115 struct callattempt *peer = NULL;
02116 struct ast_channel *winner;
02117 struct ast_channel *in = qe->chan;
02118 char on[80] = "";
02119 char membername[80] = "";
02120 long starttime = 0;
02121 long endtime = 0;
02122
02123 starttime = (long) time(NULL);
02124
02125 while (*to && !peer) {
02126 int numlines, retry, pos = 1;
02127 struct ast_channel *watchers[AST_MAX_WATCHERS];
02128 watchers[0] = in;
02129 start = NULL;
02130
02131 for (retry = 0; retry < 2; retry++) {
02132 numlines = 0;
02133 for (o = outgoing; o; o = o->q_next) {
02134 if (o->stillgoing) {
02135 stillgoing = 1;
02136 if (o->chan) {
02137 watchers[pos++] = o->chan;
02138 if (!start)
02139 start = o;
02140 else
02141 prev->call_next = o;
02142 prev = o;
02143 }
02144 }
02145 numlines++;
02146 }
02147 if (pos > 1 || !stillgoing ||
02148 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) )
02149 break;
02150
02151
02152 ring_one(qe, outgoing, &numbusies);
02153
02154 }
02155 if (pos == 1 ) {
02156 if (numlines == (numbusies + numnochan)) {
02157 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
02158 } else {
02159 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
02160 }
02161 *to = 0;
02162 return NULL;
02163 }
02164 winner = ast_waitfor_n(watchers, pos, to);
02165 for (o = start; o; o = o->call_next) {
02166 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
02167 if (!peer) {
02168 if (option_verbose > 2)
02169 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02170 peer = o;
02171 }
02172 } else if (o->chan && (o->chan == winner)) {
02173
02174 ast_copy_string(on, o->member->interface, sizeof(on));
02175 ast_copy_string(membername, o->member->membername, sizeof(membername));
02176
02177 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
02178 if (option_verbose > 2)
02179 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
02180 numnochan++;
02181 do_hang(o);
02182 winner = NULL;
02183 continue;
02184 } else if (!ast_strlen_zero(o->chan->call_forward)) {
02185 char tmpchan[256];
02186 char *stuff;
02187 char *tech;
02188
02189 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
02190 if ((stuff = strchr(tmpchan, '/'))) {
02191 *stuff++ = '\0';
02192 tech = tmpchan;
02193 } else {
02194 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
02195 stuff = tmpchan;
02196 tech = "Local";
02197 }
02198
02199 if (option_verbose > 2)
02200 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
02201
02202 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
02203 if (!o->chan) {
02204 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
02205 o->stillgoing = 0;
02206 numnochan++;
02207 } else {
02208 ast_channel_inherit_variables(in, o->chan);
02209 ast_channel_datastore_inherit(in, o->chan);
02210 if (o->chan->cid.cid_num)
02211 free(o->chan->cid.cid_num);
02212 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
02213
02214 if (o->chan->cid.cid_name)
02215 free(o->chan->cid.cid_name);
02216 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
02217
02218 ast_string_field_set(o->chan, accountcode, in->accountcode);
02219 o->chan->cdrflags = in->cdrflags;
02220
02221 if (in->cid.cid_ani) {
02222 if (o->chan->cid.cid_ani)
02223 free(o->chan->cid.cid_ani);
02224 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
02225 }
02226 if (o->chan->cid.cid_rdnis)
02227 free(o->chan->cid.cid_rdnis);
02228 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
02229 if (ast_call(o->chan, tmpchan, 0)) {
02230 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
02231 do_hang(o);
02232 numnochan++;
02233 }
02234 }
02235
02236 ast_hangup(winner);
02237 continue;
02238 }
02239 f = ast_read(winner);
02240 if (f) {
02241 if (f->frametype == AST_FRAME_CONTROL) {
02242 switch (f->subclass) {
02243 case AST_CONTROL_ANSWER:
02244
02245 if (!peer) {
02246 if (option_verbose > 2)
02247 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02248 peer = o;
02249 }
02250 break;
02251 case AST_CONTROL_BUSY:
02252 if (option_verbose > 2)
02253 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
02254 if (in->cdr)
02255 ast_cdr_busy(in->cdr);
02256 do_hang(o);
02257 endtime = (long)time(NULL);
02258 endtime -= starttime;
02259 rna(endtime*1000, qe, on, membername);
02260 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02261 if (qe->parent->timeoutrestart)
02262 *to = orig;
02263 ring_one(qe, outgoing, &numbusies);
02264 }
02265 numbusies++;
02266 break;
02267 case AST_CONTROL_CONGESTION:
02268 if (option_verbose > 2)
02269 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
02270 if (in->cdr)
02271 ast_cdr_busy(in->cdr);
02272 endtime = (long)time(NULL);
02273 endtime -= starttime;
02274 rna(endtime*1000, qe, on, membername);
02275 do_hang(o);
02276 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02277 if (qe->parent->timeoutrestart)
02278 *to = orig;
02279 ring_one(qe, outgoing, &numbusies);
02280 }
02281 numbusies++;
02282 break;
02283 case AST_CONTROL_RINGING:
02284 if (option_verbose > 2)
02285 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
02286 break;
02287 case AST_CONTROL_OFFHOOK:
02288
02289 break;
02290 default:
02291 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
02292 }
02293 }
02294 ast_frfree(f);
02295 } else {
02296 endtime = (long) time(NULL) - starttime;
02297 rna(endtime * 1000, qe, on, membername);
02298 do_hang(o);
02299 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02300 if (qe->parent->timeoutrestart)
02301 *to = orig;
02302 ring_one(qe, outgoing, &numbusies);
02303 }
02304 }
02305 }
02306 }
02307 if (winner == in) {
02308 f = ast_read(in);
02309 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
02310
02311 *to = -1;
02312 if (f)
02313 ast_frfree(f);
02314 return NULL;
02315 }
02316
02317 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
02318 if (option_verbose > 3)
02319 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
02320 *to = 0;
02321 *digit = f->subclass;
02322 ast_frfree(f);
02323 return NULL;
02324 }
02325
02326 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
02327 if (option_verbose > 3)
02328 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
02329 *to = 0;
02330 ast_frfree(f);
02331 return NULL;
02332 }
02333 ast_frfree(f);
02334 }
02335 if (!*to) {
02336 for (o = start; o; o = o->call_next)
02337 rna(orig, qe, o->interface, o->member->membername);
02338 }
02339 }
02340
02341 return peer;
02342 }
02343
02344
02345
02346
02347
02348
02349
02350
02351
02352 static int is_our_turn(struct queue_ent *qe)
02353 {
02354 struct queue_ent *ch;
02355 struct member *cur;
02356 int avl = 0;
02357 int idx = 0;
02358 int res;
02359
02360 if (!qe->parent->autofill) {
02361
02362 ch = qe->parent->head;
02363
02364 if (ch == qe) {
02365 if (option_debug)
02366 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02367 res = 1;
02368 } else {
02369 if (option_debug)
02370 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02371 res = 0;
02372 }
02373
02374 } else {
02375
02376 ast_mutex_lock(&qe->parent->lock);
02377
02378 ch = qe->parent->head;
02379
02380 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
02381 if (option_debug)
02382 ast_log(LOG_DEBUG, "Even though there may be multiple members available, the strategy is ringall so only the head call is allowed in\n");
02383 avl = 1;
02384 } else {
02385 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
02386 while ((cur = ao2_iterator_next(&mem_iter))) {
02387 switch (cur->status) {
02388 case AST_DEVICE_INUSE:
02389 if (!qe->parent->ringinuse)
02390 break;
02391
02392 case AST_DEVICE_NOT_INUSE:
02393 case AST_DEVICE_UNKNOWN:
02394 if (!cur->paused)
02395 avl++;
02396 break;
02397 }
02398 ao2_ref(cur, -1);
02399 }
02400 }
02401
02402 if (option_debug)
02403 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
02404
02405 while ((idx < avl) && (ch) && (ch != qe)) {
02406 if (!ch->pending)
02407 idx++;
02408 ch = ch->next;
02409 }
02410
02411
02412 if (ch && idx < avl) {
02413 if (option_debug)
02414 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02415 res = 1;
02416 } else {
02417 if (option_debug)
02418 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02419 res = 0;
02420 }
02421
02422 ast_mutex_unlock(&qe->parent->lock);
02423 }
02424
02425 return res;
02426 }
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
02438 {
02439 int res = 0;
02440
02441
02442 for (;;) {
02443 enum queue_member_status stat;
02444
02445 if (is_our_turn(qe))
02446 break;
02447
02448
02449 if (qe->expire && (time(NULL) >= qe->expire)) {
02450 *reason = QUEUE_TIMEOUT;
02451 break;
02452 }
02453
02454 stat = get_member_status(qe->parent, qe->max_penalty);
02455
02456
02457 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
02458 *reason = QUEUE_LEAVEEMPTY;
02459 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02460 leave_queue(qe);
02461 break;
02462 }
02463
02464
02465 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
02466 *reason = QUEUE_LEAVEUNAVAIL;
02467 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02468 leave_queue(qe);
02469 break;
02470 }
02471
02472
02473 if (qe->parent->announcefrequency && !ringing &&
02474 (res = say_position(qe)))
02475 break;
02476
02477
02478 if (qe->expire && (time(NULL) >= qe->expire)) {
02479 *reason = QUEUE_TIMEOUT;
02480 break;
02481 }
02482
02483
02484 if (qe->parent->periodicannouncefrequency && !ringing &&
02485 (res = say_periodic_announcement(qe)))
02486 break;
02487
02488
02489 if (qe->expire && (time(NULL) >= qe->expire)) {
02490 *reason = QUEUE_TIMEOUT;
02491 break;
02492 }
02493
02494
02495 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
02496 if (res > 0 && !valid_exit(qe, res))
02497 res = 0;
02498 else
02499 break;
02500 }
02501
02502
02503 if (qe->expire && (time(NULL) >= qe->expire)) {
02504 *reason = QUEUE_TIMEOUT;
02505 break;
02506 }
02507 }
02508
02509 return res;
02510 }
02511
02512 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
02513 {
02514 ast_mutex_lock(&q->lock);
02515 time(&member->lastcall);
02516 member->calls++;
02517 q->callscompleted++;
02518 if (callcompletedinsl)
02519 q->callscompletedinsl++;
02520 ast_mutex_unlock(&q->lock);
02521 return 0;
02522 }
02523
02524
02525
02526
02527
02528
02529
02530 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
02531 {
02532 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
02533 return -1;
02534
02535 switch (q->strategy) {
02536 case QUEUE_STRATEGY_RINGALL:
02537
02538 tmp->metric = mem->penalty * 1000000;
02539 break;
02540 case QUEUE_STRATEGY_ROUNDROBIN:
02541 if (!pos) {
02542 if (!q->wrapped) {
02543
02544 q->rrpos = 0;
02545 } else {
02546
02547 q->rrpos++;
02548 }
02549 q->wrapped = 0;
02550 }
02551
02552 case QUEUE_STRATEGY_RRMEMORY:
02553 if (pos < q->rrpos) {
02554 tmp->metric = 1000 + pos;
02555 } else {
02556 if (pos > q->rrpos)
02557
02558 q->wrapped = 1;
02559 tmp->metric = pos;
02560 }
02561 tmp->metric += mem->penalty * 1000000;
02562 break;
02563 case QUEUE_STRATEGY_RANDOM:
02564 tmp->metric = ast_random() % 1000;
02565 tmp->metric += mem->penalty * 1000000;
02566 break;
02567 case QUEUE_STRATEGY_FEWESTCALLS:
02568 tmp->metric = mem->calls;
02569 tmp->metric += mem->penalty * 1000000;
02570 break;
02571 case QUEUE_STRATEGY_LEASTRECENT:
02572 if (!mem->lastcall)
02573 tmp->metric = 0;
02574 else
02575 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
02576 tmp->metric += mem->penalty * 1000000;
02577 break;
02578 default:
02579 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
02580 break;
02581 }
02582 if (q->ringlimit && (mem->ringcount >= q->ringlimit)) {
02583 tmp->metric += (mem->ringcount / q->ringlimit) * 10000000;
02584 }
02585 if (option_debug)
02586 ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n",
02587 tmp->metric, mem->interface, mem->ringcount, q->ringlimit);
02588 return 0;
02589 }
02590
02591 struct queue_transfer_ds {
02592 struct queue_ent *qe;
02593 struct member *member;
02594 int starttime;
02595 };
02596
02597 static void queue_transfer_destroy(void *data)
02598 {
02599 struct queue_transfer_ds *qtds = data;
02600 ast_free(qtds);
02601 }
02602
02603
02604
02605 static const struct ast_datastore_info queue_transfer_info = {
02606 .type = "queue_transfer",
02607 .chan_fixup = queue_transfer_fixup,
02608 .destroy = queue_transfer_destroy,
02609 };
02610
02611
02612
02613
02614
02615
02616
02617
02618
02619
02620 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
02621 {
02622 struct queue_transfer_ds *qtds = data;
02623 struct queue_ent *qe = qtds->qe;
02624 struct member *member = qtds->member;
02625 int callstart = qtds->starttime;
02626 struct ast_datastore *datastore;
02627
02628 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
02629 new_chan->exten, new_chan->context, (long) (callstart - qe->start),
02630 (long) (time(NULL) - callstart));
02631
02632 if (!(datastore = ast_channel_datastore_find(new_chan, &queue_transfer_info, NULL))) {
02633 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
02634 return;
02635 }
02636
02637 ast_channel_datastore_remove(new_chan, datastore);
02638 ast_channel_datastore_free(datastore);
02639 }
02640
02641
02642
02643
02644
02645
02646
02647 static int attended_transfer_occurred(struct ast_channel *chan)
02648 {
02649 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
02650 }
02651
02652
02653
02654 static void setup_transfer_datastore(struct queue_ent *qe, struct member *member, int starttime)
02655 {
02656 struct ast_datastore *ds;
02657 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
02658
02659 if (!qtds) {
02660 ast_log(LOG_WARNING, "Memory allocation error!\n");
02661 return;
02662 }
02663
02664 ast_channel_lock(qe->chan);
02665 if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) {
02666 ast_channel_unlock(qe->chan);
02667 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
02668 return;
02669 }
02670
02671 qtds->qe = qe;
02672
02673 qtds->member = member;
02674 qtds->starttime = starttime;
02675 ds->data = qtds;
02676 ast_channel_datastore_add(qe->chan, ds);
02677 ast_channel_unlock(qe->chan);
02678 }
02679
02680
02681
02682
02683
02684
02685
02686
02687
02688
02689
02690
02691
02692
02693
02694
02695
02696
02697
02698
02699
02700
02701
02702
02703
02704
02705 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
02706 {
02707 struct member *cur;
02708 struct callattempt *outgoing = NULL;
02709 int to;
02710 char oldexten[AST_MAX_EXTENSION]="";
02711 char oldcontext[AST_MAX_CONTEXT]="";
02712 char queuename[256]="";
02713 struct ast_channel *peer;
02714 struct ast_channel *which;
02715 struct callattempt *lpeer;
02716 struct member *member;
02717 struct ast_app *app;
02718 int res = 0, bridge = 0;
02719 int numbusies = 0;
02720 int x=0;
02721 char *announce = NULL;
02722 char digit = 0;
02723 time_t callstart;
02724 time_t now = time(NULL);
02725 struct ast_bridge_config bridge_config;
02726 char nondataquality = 1;
02727 char *agiexec = NULL;
02728 int ret = 0;
02729 const char *monitorfilename;
02730 const char *monitor_exec;
02731 const char *monitor_options;
02732 char tmpid[256], tmpid2[256];
02733 char meid[1024], meid2[1024];
02734 char mixmonargs[1512];
02735 struct ast_app *mixmonapp = NULL;
02736 char *p;
02737 char vars[2048];
02738 int forwardsallowed = 1;
02739 int callcompletedinsl;
02740 struct ao2_iterator memi;
02741 struct ast_datastore *datastore;
02742
02743 ast_channel_lock(qe->chan);
02744 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
02745 ast_channel_unlock(qe->chan);
02746
02747 memset(&bridge_config, 0, sizeof(bridge_config));
02748 time(&now);
02749
02750
02751
02752
02753
02754 if (qe->expire && now >= qe->expire) {
02755 res = 0;
02756 goto out;
02757 }
02758
02759 for (; options && *options; options++)
02760 switch (*options) {
02761 case 't':
02762 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
02763 break;
02764 case 'T':
02765 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
02766 break;
02767 case 'w':
02768 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
02769 break;
02770 case 'W':
02771 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
02772 break;
02773 case 'd':
02774 nondataquality = 0;
02775 break;
02776 case 'h':
02777 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
02778 break;
02779 case 'H':
02780 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
02781 break;
02782 case 'n':
02783 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
02784 (*tries)++;
02785 else
02786 *tries = qe->parent->membercount;
02787 *noption = 1;
02788 break;
02789 case 'i':
02790 forwardsallowed = 0;
02791 break;
02792 }
02793
02794
02795 if (use_weight)
02796 AST_LIST_LOCK(&queues);
02797 ast_mutex_lock(&qe->parent->lock);
02798 if (option_debug)
02799 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
02800 qe->chan->name);
02801 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
02802 if (!ast_strlen_zero(qe->announce))
02803 announce = qe->announce;
02804 if (!ast_strlen_zero(announceoverride))
02805 announce = announceoverride;
02806
02807 memi = ao2_iterator_init(qe->parent->members, 0);
02808 while ((cur = ao2_iterator_next(&memi))) {
02809 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
02810 struct ast_dialed_interface *di;
02811 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
02812 if (!tmp) {
02813 ao2_ref(cur, -1);
02814 ast_mutex_unlock(&qe->parent->lock);
02815 if (use_weight)
02816 AST_LIST_UNLOCK(&queues);
02817 goto out;
02818 }
02819 if (!datastore) {
02820 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
02821 ao2_ref(cur, -1);
02822 ast_mutex_unlock(&qe->parent->lock);
02823 if (use_weight)
02824 AST_LIST_UNLOCK(&queues);
02825 free(tmp);
02826 goto out;
02827 }
02828 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
02829 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
02830 ao2_ref(cur, -1);
02831 ast_mutex_unlock(&qe->parent->lock);
02832 if (use_weight)
02833 AST_LIST_UNLOCK(&queues);
02834 free(tmp);
02835 goto out;
02836 }
02837 datastore->data = dialed_interfaces;
02838 AST_LIST_HEAD_INIT(dialed_interfaces);
02839
02840 ast_channel_lock(qe->chan);
02841 ast_channel_datastore_add(qe->chan, datastore);
02842 ast_channel_unlock(qe->chan);
02843 } else
02844 dialed_interfaces = datastore->data;
02845
02846 AST_LIST_LOCK(dialed_interfaces);
02847 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
02848 if (!strcasecmp(cur->interface, di->interface)) {
02849 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n",
02850 di->interface);
02851 break;
02852 }
02853 }
02854 AST_LIST_UNLOCK(dialed_interfaces);
02855
02856 if (di) {
02857 free(tmp);
02858 continue;
02859 }
02860
02861
02862
02863
02864
02865 if (strncasecmp(cur->interface, "Local/", 6)) {
02866 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
02867 ao2_ref(cur, -1);
02868 ast_mutex_unlock(&qe->parent->lock);
02869 if (use_weight)
02870 AST_LIST_UNLOCK(&queues);
02871 free(tmp);
02872 goto out;
02873 }
02874 strcpy(di->interface, cur->interface);
02875
02876 AST_LIST_LOCK(dialed_interfaces);
02877 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
02878 AST_LIST_UNLOCK(dialed_interfaces);
02879 }
02880
02881 tmp->stillgoing = -1;
02882 tmp->member = cur;
02883 tmp->oldstatus = cur->status;
02884 tmp->lastcall = cur->lastcall;
02885 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
02886 if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) {
02887 cur->ringcount = 0;
02888 }
02889
02890
02891 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
02892
02893
02894
02895 tmp->q_next = outgoing;
02896 outgoing = tmp;
02897
02898 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
02899 break;
02900 } else {
02901 ao2_ref(cur, -1);
02902 free(tmp);
02903 }
02904 }
02905 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
02906 to = (qe->expire - now) * 1000;
02907 else
02908 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
02909 ++qe->pending;
02910 ++qe->tries;
02911 if (option_debug)
02912 ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n",
02913 qe->chan->name, queuename, qe->tries);
02914 ast_mutex_unlock(&qe->parent->lock);
02915 ring_one(qe, outgoing, &numbusies);
02916 if (use_weight)
02917 AST_LIST_UNLOCK(&queues);
02918 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
02919
02920
02921
02922
02923
02924
02925 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
02926 ast_channel_datastore_free(datastore);
02927 }
02928 ast_mutex_lock(&qe->parent->lock);
02929 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
02930 store_next(qe, outgoing);
02931 }
02932 ast_mutex_unlock(&qe->parent->lock);
02933 peer = lpeer ? lpeer->chan : NULL;
02934 if (!peer) {
02935 qe->pending = 0;
02936 if (to) {
02937
02938 res = -1;
02939 } else {
02940
02941 res = digit;
02942 }
02943 if (res == -1) {
02944
02945 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_DONT_TOUCH);
02946 ast_cdr_noanswer(qe->chan->cdr);
02947 if (queue_debug)
02948 ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name);
02949 }
02950 if (qe->parent->eventwhencalled) {
02951 manager_event(EVENT_FLAG_AGENT, "AgentTimeout",
02952 "Queue: %s\r\n"
02953 "ChannelCalling: %s\r\n"
02954 "Uniqueid: %s\r\n"
02955 "Tries: %d\r\n"
02956 "Holdtime: %ld\r\n",
02957 queuename, qe->chan->name, qe->chan->uniqueid, qe->tries,
02958 (long)time(NULL) - qe->start);
02959 }
02960 } else {
02961
02962
02963
02964 if (!strcmp(qe->chan->tech->type, "Zap"))
02965 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02966 if (!strcmp(peer->tech->type, "Zap"))
02967 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02968
02969 time(&now);
02970 recalc_holdtime(qe, (now - qe->start));
02971 ast_mutex_lock(&qe->parent->lock);
02972 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
02973 ast_mutex_unlock(&qe->parent->lock);
02974 member = lpeer->member;
02975
02976 ao2_ref(member, 1);
02977 hangupcalls(outgoing, peer);
02978 outgoing = NULL;
02979 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
02980 int res2;
02981
02982 res2 = ast_autoservice_start(qe->chan);
02983 if (!res2) {
02984 if (qe->parent->memberdelay) {
02985 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
02986 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
02987 }
02988 if (!res2 && announce) {
02989 play_file(peer, announce);
02990 }
02991 if (!res2 && qe->parent->reportholdtime) {
02992 if (!play_file(peer, qe->parent->sound_reporthold)) {
02993 int holdtime;
02994
02995 time(&now);
02996 holdtime = abs((now - qe->start) / 60);
02997 if (holdtime < 2) {
02998 play_file(peer, qe->parent->sound_lessthan);
02999 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
03000 } else
03001 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
03002 play_file(peer, qe->parent->sound_minutes);
03003 }
03004 }
03005 }
03006 res2 |= ast_autoservice_stop(qe->chan);
03007 if (peer->_softhangup) {
03008
03009 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
03010 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
03011 if (qe->parent->eventwhencalled)
03012 manager_event(EVENT_FLAG_AGENT, "AgentDump",
03013 "Queue: %s\r\n"
03014 "Uniqueid: %s\r\n"
03015 "Channel: %s\r\n"
03016 "Member: %s\r\n"
03017 "MemberName: %s\r\n"
03018 "%s",
03019 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03020 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03021 ast_hangup(peer);
03022 ao2_ref(member, -1);
03023 goto out;
03024 } else if (res2) {
03025
03026 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
03027 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
03028 record_abandoned(qe);
03029 ast_hangup(peer);
03030 ao2_ref(member, -1);
03031 return -1;
03032 }
03033 }
03034
03035 ast_moh_stop(qe->chan);
03036
03037 if (qe->chan->cdr)
03038 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
03039
03040 res = ast_channel_make_compatible(qe->chan, peer);
03041 if (res < 0) {
03042 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
03043 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
03044 record_abandoned(qe);
03045 ast_hangup(peer);
03046 ao2_ref(member, -1);
03047 return -1;
03048 }
03049
03050 if (qe->parent->setinterfacevar)
03051 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
03052
03053
03054 if (qe->parent->monfmt && *qe->parent->monfmt) {
03055 if (!qe->parent->montype) {
03056 if (option_debug)
03057 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
03058 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
03059 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
03060 which = qe->chan;
03061 else
03062 which = peer;
03063 if (monitorfilename)
03064 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
03065 else if (qe->chan->cdr)
03066 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
03067 else {
03068
03069 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
03070 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
03071 }
03072 if (qe->parent->monjoin)
03073 ast_monitor_setjoinfiles(which, 1);
03074 } else {
03075 if (option_debug)
03076 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
03077 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
03078 if (!monitorfilename) {
03079 if (qe->chan->cdr)
03080 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
03081 else
03082 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
03083 } else {
03084 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
03085 for (p = tmpid2; *p ; p++) {
03086 if (*p == '^' && *(p+1) == '{') {
03087 *p = '$';
03088 }
03089 }
03090
03091 memset(tmpid, 0, sizeof(tmpid));
03092 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
03093 }
03094
03095 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
03096 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
03097
03098 if (monitor_exec) {
03099 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
03100 for (p = meid2; *p ; p++) {
03101 if (*p == '^' && *(p+1) == '{') {
03102 *p = '$';
03103 }
03104 }
03105
03106 memset(meid, 0, sizeof(meid));
03107 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
03108 }
03109
03110 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
03111
03112 mixmonapp = pbx_findapp("MixMonitor");
03113
03114 if (strchr(tmpid2, '|')) {
03115 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
03116 mixmonapp = NULL;
03117 }
03118
03119 if (!monitor_options)
03120 monitor_options = "";
03121
03122 if (strchr(monitor_options, '|')) {
03123 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
03124 mixmonapp = NULL;
03125 }
03126
03127 if (mixmonapp) {
03128 if (!ast_strlen_zero(monitor_exec))
03129 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
03130 else
03131 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
03132
03133 if (option_debug)
03134 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
03135
03136 if (qe->chan->cdr)
03137 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
03138 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
03139 if (qe->chan->cdr)
03140 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
03141
03142 } else
03143 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
03144
03145 }
03146 }
03147
03148 leave_queue(qe);
03149 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
03150 if (option_debug)
03151 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
03152 ast_channel_sendurl(peer, url);
03153 }
03154 if (!ast_strlen_zero(agi)) {
03155 if (option_debug)
03156 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
03157 app = pbx_findapp("agi");
03158 if (app) {
03159 agiexec = ast_strdupa(agi);
03160 ret = pbx_exec(qe->chan, app, agiexec);
03161 } else
03162 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
03163 }
03164 qe->handled++;
03165 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
03166 if (qe->parent->eventwhencalled)
03167 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
03168 "Queue: %s\r\n"
03169 "Uniqueid: %s\r\n"
03170 "Channel: %s\r\n"
03171 "Member: %s\r\n"
03172 "MemberName: %s\r\n"
03173 "Holdtime: %ld\r\n"
03174 "BridgedChannel: %s\r\n"
03175 "%s",
03176 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03177 (long)time(NULL) - qe->start, peer->uniqueid,
03178 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03179 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
03180 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
03181 time(&callstart);
03182
03183 if (member->status == AST_DEVICE_NOT_INUSE)
03184 ast_log(LOG_WARNING, "The device state of this queue member, %s, is still 'Not in Use' when it probably should not be! Please check UPGRADE.txt for correct configuration settings.\n", member->membername);
03185
03186 setup_transfer_datastore(qe, member, callstart);
03187 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
03188
03189 if (!attended_transfer_occurred(qe->chan)) {
03190 struct ast_datastore *transfer_ds;
03191 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
03192 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
03193 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
03194 (long) (time(NULL) - callstart));
03195 } else if (qe->chan->_softhangup) {
03196 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
03197 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
03198 if (qe->parent->eventwhencalled)
03199 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03200 "Queue: %s\r\n"
03201 "Uniqueid: %s\r\n"
03202 "Channel: %s\r\n"
03203 "Member: %s\r\n"
03204 "MemberName: %s\r\n"
03205 "HoldTime: %ld\r\n"
03206 "TalkTime: %ld\r\n"
03207 "Reason: caller\r\n"
03208 "%s",
03209 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03210 (long)(callstart - qe->start), (long)(time(NULL) - callstart),
03211 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03212 } else {
03213 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
03214 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
03215 if (qe->parent->eventwhencalled)
03216 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03217 "Queue: %s\r\n"
03218 "Uniqueid: %s\r\n"
03219 "Channel: %s\r\n"
03220 "MemberName: %s\r\n"
03221 "HoldTime: %ld\r\n"
03222 "TalkTime: %ld\r\n"
03223 "Reason: agent\r\n"
03224 "%s",
03225 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
03226 (long)(time(NULL) - callstart),
03227 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03228 }
03229 ast_channel_lock(qe->chan);
03230 transfer_ds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL);
03231 if (transfer_ds) {
03232 ast_channel_datastore_remove(qe->chan, transfer_ds);
03233 ast_channel_datastore_free(transfer_ds);
03234 }
03235 ast_channel_unlock(qe->chan);
03236 }
03237
03238 if (bridge != AST_PBX_NO_HANGUP_PEER)
03239 ast_hangup(peer);
03240 update_queue(qe->parent, member, callcompletedinsl);
03241 res = bridge ? bridge : 1;
03242 ao2_ref(member, -1);
03243 }
03244 out:
03245 hangupcalls(outgoing, NULL);
03246
03247 return res;
03248 }
03249
03250 static int wait_a_bit(struct queue_ent *qe)
03251 {
03252
03253 int retrywait = qe->parent->retry * 1000;
03254
03255 int res = ast_waitfordigit(qe->chan, retrywait);
03256 if (res > 0 && !valid_exit(qe, res))
03257 res = 0;
03258
03259 return res;
03260 }
03261
03262 static struct member *interface_exists(struct call_queue *q, const char *interface)
03263 {
03264 struct member *mem;
03265 struct ao2_iterator mem_iter;
03266
03267 if (!q)
03268 return NULL;
03269
03270 mem_iter = ao2_iterator_init(q->members, 0);
03271 while ((mem = ao2_iterator_next(&mem_iter))) {
03272 if (!strcasecmp(interface, mem->interface))
03273 return mem;
03274 ao2_ref(mem, -1);
03275 }
03276
03277 return NULL;
03278 }
03279
03280
03281
03282
03283
03284
03285
03286 static void dump_queue_members(struct call_queue *pm_queue)
03287 {
03288 struct member *cur_member;
03289 char value[PM_MAX_LEN];
03290 int value_len = 0;
03291 int res;
03292 struct ao2_iterator mem_iter;
03293
03294 memset(value, 0, sizeof(value));
03295
03296 if (!pm_queue)
03297 return;
03298
03299 mem_iter = ao2_iterator_init(pm_queue->members, 0);
03300 while ((cur_member = ao2_iterator_next(&mem_iter))) {
03301 if (!cur_member->dynamic) {
03302 ao2_ref(cur_member, -1);
03303 continue;
03304 }
03305
03306 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
03307 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
03308
03309 ao2_ref(cur_member, -1);
03310
03311 if (res != strlen(value + value_len)) {
03312 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
03313 break;
03314 }
03315 value_len += res;
03316 }
03317
03318 if (value_len && !cur_member) {
03319 if (ast_db_put(pm_family, pm_queue->name, value))
03320 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
03321 } else
03322
03323 ast_db_del(pm_family, pm_queue->name);
03324 }
03325
03326 static int remove_from_queue(const char *queuename, const char *interface)
03327 {
03328 struct call_queue *q;
03329 struct member *mem, tmpmem;
03330 int res = RES_NOSUCHQUEUE;
03331
03332 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
03333
03334 AST_LIST_LOCK(&queues);
03335 AST_LIST_TRAVERSE(&queues, q, list) {
03336 ast_mutex_lock(&q->lock);
03337 if (strcmp(q->name, queuename)) {
03338 ast_mutex_unlock(&q->lock);
03339 continue;
03340 }
03341
03342 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
03343
03344 if (!mem->dynamic) {
03345 res = RES_NOT_DYNAMIC;
03346 ao2_ref(mem, -1);
03347 ast_mutex_unlock(&q->lock);
03348 break;
03349 }
03350 q->membercount--;
03351 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
03352 "Queue: %s\r\n"
03353 "Location: %s\r\n"
03354 "MemberName: %s\r\n",
03355 q->name, mem->interface, mem->membername);
03356 ao2_unlink(q->members, mem);
03357 ao2_ref(mem, -1);
03358
03359 if (queue_persistent_members)
03360 dump_queue_members(q);
03361
03362 res = RES_OKAY;
03363 } else {
03364 res = RES_EXISTS;
03365 }
03366 ast_mutex_unlock(&q->lock);
03367 break;
03368 }
03369
03370 if (res == RES_OKAY)
03371 remove_from_interfaces(interface);
03372
03373 AST_LIST_UNLOCK(&queues);
03374
03375 return res;
03376 }
03377
03378
03379 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
03380 {
03381 struct call_queue *q;
03382 struct member *new_member, *old_member;
03383 int res = RES_NOSUCHQUEUE;
03384
03385
03386
03387 if (!(q = load_realtime_queue(queuename)))
03388 return res;
03389
03390 AST_LIST_LOCK(&queues);
03391
03392 ast_mutex_lock(&q->lock);
03393 if ((old_member = interface_exists(q, interface)) == NULL) {
03394 add_to_interfaces(interface);
03395 if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
03396 new_member->dynamic = 1;
03397 ao2_link(q->members, new_member);
03398 q->membercount++;
03399 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
03400 "Queue: %s\r\n"
03401 "Location: %s\r\n"
03402 "MemberName: %s\r\n"
03403 "Membership: %s\r\n"
03404 "Penalty: %d\r\n"
03405 "CallsTaken: %d\r\n"
03406 "LastCall: %d\r\n"
03407 "Status: %d\r\n"
03408 "Paused: %d\r\n",
03409 q->name, new_member->interface, new_member->membername,
03410 "dynamic",
03411 new_member->penalty, new_member->calls, (int) new_member->lastcall,
03412 new_member->status, new_member->paused);
03413
03414 ao2_ref(new_member, -1);
03415 new_member = NULL;
03416
03417 if (dump)
03418 dump_queue_members(q);
03419
03420 res = RES_OKAY;
03421 } else {
03422 res = RES_OUTOFMEMORY;
03423 }
03424 } else {
03425 ao2_ref(old_member, -1);
03426 res = RES_EXISTS;
03427 }
03428 ast_mutex_unlock(&q->lock);
03429 AST_LIST_UNLOCK(&queues);
03430
03431 return res;
03432 }
03433
03434 static int set_member_paused(const char *queuename, const char *interface, int paused)
03435 {
03436 int found = 0;
03437 struct call_queue *q;
03438 struct member *mem;
03439
03440
03441
03442 if (ast_strlen_zero(queuename))
03443 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
03444
03445 AST_LIST_LOCK(&queues);
03446 AST_LIST_TRAVERSE(&queues, q, list) {
03447 ast_mutex_lock(&q->lock);
03448 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
03449 if ((mem = interface_exists(q, interface))) {
03450 found++;
03451 if (mem->paused == paused)
03452 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
03453 mem->paused = paused;
03454
03455 if (queue_persistent_members)
03456 dump_queue_members(q);
03457
03458 if (mem->realtime)
03459 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
03460
03461 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
03462
03463 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
03464 "Queue: %s\r\n"
03465 "Location: %s\r\n"
03466 "MemberName: %s\r\n"
03467 "Paused: %d\r\n",
03468 q->name, mem->interface, mem->membername, paused);
03469 ao2_ref(mem, -1);
03470 }
03471 }
03472 ast_mutex_unlock(&q->lock);
03473 }
03474 AST_LIST_UNLOCK(&queues);
03475
03476 return found ? RESULT_SUCCESS : RESULT_FAILURE;
03477 }
03478
03479
03480 static void reload_queue_members(void)
03481 {
03482 char *cur_ptr;
03483 char *queue_name;
03484 char *member;
03485 char *interface;
03486 char *membername = NULL;
03487 char *penalty_tok;
03488 int penalty = 0;
03489 char *paused_tok;
03490 int paused = 0;
03491 struct ast_db_entry *db_tree;
03492 struct ast_db_entry *entry;
03493 struct call_queue *cur_queue;
03494 char queue_data[PM_MAX_LEN];
03495
03496 AST_LIST_LOCK(&queues);
03497
03498
03499 db_tree = ast_db_gettree(pm_family, NULL);
03500 for (entry = db_tree; entry; entry = entry->next) {
03501
03502 queue_name = entry->key + strlen(pm_family) + 2;
03503
03504 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
03505 ast_mutex_lock(&cur_queue->lock);
03506 if (!strcmp(queue_name, cur_queue->name))
03507 break;
03508 ast_mutex_unlock(&cur_queue->lock);
03509 }
03510
03511 if (!cur_queue)
03512 cur_queue = load_realtime_queue(queue_name);
03513
03514 if (!cur_queue) {
03515
03516
03517 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
03518 ast_db_del(pm_family, queue_name);
03519 continue;
03520 } else
03521 ast_mutex_unlock(&cur_queue->lock);
03522
03523 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
03524 continue;
03525
03526 cur_ptr = queue_data;
03527 while ((member = strsep(&cur_ptr, "|"))) {
03528 if (ast_strlen_zero(member))
03529 continue;
03530
03531 interface = strsep(&member, ";");
03532 penalty_tok = strsep(&member, ";");
03533 paused_tok = strsep(&member, ";");
03534 membername = strsep(&member, ";");
03535
03536 if (!penalty_tok) {
03537 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
03538 break;
03539 }
03540 penalty = strtol(penalty_tok, NULL, 10);
03541 if (errno == ERANGE) {
03542 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
03543 break;
03544 }
03545
03546 if (!paused_tok) {
03547 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
03548 break;
03549 }
03550 paused = strtol(paused_tok, NULL, 10);
03551 if ((errno == ERANGE) || paused < 0 || paused > 1) {
03552 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
03553 break;
03554 }
03555 if (ast_strlen_zero(membername))
03556 membername = interface;
03557
03558 if (option_debug)
03559 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
03560
03561 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
03562 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
03563 break;
03564 }
03565 }
03566 }
03567
03568 AST_LIST_UNLOCK(&queues);
03569 if (db_tree) {
03570 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
03571 ast_db_freetree(db_tree);
03572 }
03573 }
03574
03575 static int pqm_exec(struct ast_channel *chan, void *data)
03576 {
03577 struct ast_module_user *lu;
03578 char *parse;
03579 int priority_jump = 0;
03580 int ignore_fail = 0;
03581 AST_DECLARE_APP_ARGS(args,
03582 AST_APP_ARG(queuename);
03583 AST_APP_ARG(interface);
03584 AST_APP_ARG(options);
03585 );
03586
03587 if (ast_strlen_zero(data)) {
03588 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03589 return -1;
03590 }
03591
03592 parse = ast_strdupa(data);
03593
03594 AST_STANDARD_APP_ARGS(args, parse);
03595
03596 lu = ast_module_user_add(chan);
03597
03598 if (args.options) {
03599 if (strchr(args.options, 'j'))
03600 priority_jump = 1;
03601 if (strchr(args.options, 'i'))
03602 ignore_fail = 1;
03603 }
03604
03605 if (ast_strlen_zero(args.interface)) {
03606 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03607 ast_module_user_remove(lu);
03608 return -1;
03609 }
03610
03611 if (set_member_paused(args.queuename, args.interface, 1)) {
03612 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
03613 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
03614 if (priority_jump || ast_opt_priority_jumping) {
03615 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03616 ast_module_user_remove(lu);
03617 return 0;
03618 }
03619 }
03620 ast_module_user_remove(lu);
03621 if (ignore_fail) {
03622 return 0;
03623 } else {
03624 return -1;
03625 }
03626 }
03627
03628 ast_module_user_remove(lu);
03629 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
03630 return 0;
03631 }
03632
03633 static int upqm_exec(struct ast_channel *chan, void *data)
03634 {
03635 struct ast_module_user *lu;
03636 char *parse;
03637 int priority_jump = 0;
03638 int ignore_fail = 0;
03639 AST_DECLARE_APP_ARGS(args,
03640 AST_APP_ARG(queuename);
03641 AST_APP_ARG(interface);
03642 AST_APP_ARG(options);
03643 );
03644
03645 if (ast_strlen_zero(data)) {
03646 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03647 return -1;
03648 }
03649
03650 parse = ast_strdupa(data);
03651
03652 AST_STANDARD_APP_ARGS(args, parse);
03653
03654 lu = ast_module_user_add(chan);
03655
03656 if (args.options) {
03657 if (strchr(args.options, 'j'))
03658 priority_jump = 1;
03659 if (strchr(args.options, 'i'))
03660 ignore_fail = 1;
03661 }
03662
03663 if (ast_strlen_zero(args.interface)) {
03664 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03665 ast_module_user_remove(lu);
03666 return -1;
03667 }
03668
03669 if (set_member_paused(args.queuename, args.interface, 0)) {
03670 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
03671 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
03672 if (priority_jump || ast_opt_priority_jumping) {
03673 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03674 ast_module_user_remove(lu);
03675 return 0;
03676 }
03677 }
03678 ast_module_user_remove(lu);
03679 if (ignore_fail) {
03680 return 0;
03681 } else {
03682 return -1;
03683 }
03684 }
03685
03686 ast_module_user_remove(lu);
03687 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
03688 return 0;
03689 }
03690
03691 static int rqm_exec(struct ast_channel *chan, void *data)
03692 {
03693 int res=-1;
03694 struct ast_module_user *lu;
03695 char *parse, *temppos = NULL;
03696 int priority_jump = 0;
03697 AST_DECLARE_APP_ARGS(args,
03698 AST_APP_ARG(queuename);
03699 AST_APP_ARG(interface);
03700 AST_APP_ARG(options);
03701 );
03702
03703
03704 if (ast_strlen_zero(data)) {
03705 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
03706 return -1;
03707 }
03708
03709 parse = ast_strdupa(data);
03710
03711 AST_STANDARD_APP_ARGS(args, parse);
03712
03713 lu = ast_module_user_add(chan);
03714
03715 if (ast_strlen_zero(args.interface)) {
03716 args.interface = ast_strdupa(chan->name);
03717 temppos = strrchr(args.interface, '-');
03718 if (temppos)
03719 *temppos = '\0';
03720 }
03721
03722 if (args.options) {
03723 if (strchr(args.options, 'j'))
03724 priority_jump = 1;
03725 }
03726
03727 switch (remove_from_queue(args.queuename, args.interface)) {
03728 case RES_OKAY:
03729 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
03730 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
03731 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
03732 res = 0;
03733 break;
03734 case RES_EXISTS:
03735 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
03736 if (priority_jump || ast_opt_priority_jumping)
03737 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03738 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
03739 res = 0;
03740 break;
03741 case RES_NOSUCHQUEUE:
03742 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
03743 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
03744 res = 0;
03745 break;
03746 case RES_NOT_DYNAMIC:
03747 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
03748 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
03749 res = 0;
03750 break;
03751 }
03752
03753 ast_module_user_remove(lu);
03754
03755 return res;
03756 }
03757
03758 static int aqm_exec(struct ast_channel *chan, void *data)
03759 {
03760 int res=-1;
03761 struct ast_module_user *lu;
03762 char *parse, *temppos = NULL;
03763 int priority_jump = 0;
03764 AST_DECLARE_APP_ARGS(args,
03765 AST_APP_ARG(queuename);
03766 AST_APP_ARG(interface);
03767 AST_APP_ARG(penalty);
03768 AST_APP_ARG(options);
03769 AST_APP_ARG(membername);
03770 );
03771 int penalty = 0;
03772
03773 if (ast_strlen_zero(data)) {
03774 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
03775 return -1;
03776 }
03777
03778 parse = ast_strdupa(data);
03779
03780 AST_STANDARD_APP_ARGS(args, parse);
03781
03782 lu = ast_module_user_add(chan);
03783
03784 if (ast_strlen_zero(args.interface)) {
03785 args.interface = ast_strdupa(chan->name);
03786 temppos = strrchr(args.interface, '-');
03787 if (temppos)
03788 *temppos = '\0';
03789 }
03790
03791 if (!ast_strlen_zero(args.penalty)) {
03792 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
03793 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
03794 penalty = 0;
03795 }
03796 }
03797
03798 if (args.options) {
03799 if (strchr(args.options, 'j'))
03800 priority_jump = 1;
03801 }
03802
03803 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
03804 case RES_OKAY:
03805 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
03806 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
03807 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
03808 res = 0;
03809 break;
03810 case RES_EXISTS:
03811 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
03812 if (priority_jump || ast_opt_priority_jumping)
03813 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03814 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
03815 res = 0;
03816 break;
03817 case RES_NOSUCHQUEUE:
03818 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
03819 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
03820 res = 0;
03821 break;
03822 case RES_OUTOFMEMORY:
03823 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
03824 break;
03825 }
03826
03827 ast_module_user_remove(lu);
03828
03829 return res;
03830 }
03831
03832 static int ql_exec(struct ast_channel *chan, void *data)
03833 {
03834 struct ast_module_user *u;
03835 char *parse;
03836
03837 AST_DECLARE_APP_ARGS(args,
03838 AST_APP_ARG(queuename);
03839 AST_APP_ARG(uniqueid);
03840 AST_APP_ARG(membername);
03841 AST_APP_ARG(event);
03842 AST_APP_ARG(params);
03843 );
03844
03845 if (ast_strlen_zero(data)) {
03846 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
03847 return -1;
03848 }
03849
03850 u = ast_module_user_add(chan);
03851
03852 parse = ast_strdupa(data);
03853
03854 AST_STANDARD_APP_ARGS(args, parse);
03855
03856 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
03857 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
03858 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
03859 ast_module_user_remove(u);
03860 return -1;
03861 }
03862
03863 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
03864 "%s", args.params ? args.params : "");
03865
03866 ast_module_user_remove(u);
03867
03868 return 0;
03869 }
03870
03871
03872
03873
03874
03875
03876
03877
03878
03879
03880
03881
03882
03883 static int queue_exec(struct ast_channel *chan, void *data)
03884 {
03885 int res=-1;
03886 int ringing=0;
03887 struct ast_module_user *lu;
03888 const char *user_priority;
03889 const char *max_penalty_str;
03890 int prio;
03891 int max_penalty;
03892 enum queue_result reason = QUEUE_UNKNOWN;
03893
03894 int tries = 0;
03895 int noption = 0;
03896 char *parse;
03897 AST_DECLARE_APP_ARGS(args,
03898 AST_APP_ARG(queuename);
03899 AST_APP_ARG(options);
03900 AST_APP_ARG(url);
03901 AST_APP_ARG(announceoverride);
03902 AST_APP_ARG(queuetimeoutstr);
03903 AST_APP_ARG(agi);
03904 );
03905
03906 struct queue_ent qe;
03907
03908 if (ast_strlen_zero(data)) {
03909 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
03910 return -1;
03911 }
03912
03913 parse = ast_strdupa(data);
03914 AST_STANDARD_APP_ARGS(args, parse);
03915
03916 lu = ast_module_user_add(chan);
03917
03918
03919 memset(&qe, 0, sizeof(qe));
03920 qe.start = time(NULL);
03921
03922
03923 if (!ast_strlen_zero(args.queuetimeoutstr))
03924 qe.expire = qe.start + atoi(args.queuetimeoutstr);
03925 else
03926 qe.expire = 0;
03927
03928
03929 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
03930 if (user_priority) {
03931 if (sscanf(user_priority, "%d", &prio) == 1) {
03932 if (option_debug)
03933 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
03934 chan->name, prio);
03935 } else {
03936 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
03937 user_priority, chan->name);
03938 prio = 0;
03939 }
03940 } else {
03941 if (option_debug > 2)
03942 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
03943 prio = 0;
03944 }
03945
03946
03947 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
03948 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
03949 if (option_debug)
03950 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
03951 chan->name, max_penalty);
03952 } else {
03953 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
03954 max_penalty_str, chan->name);
03955 max_penalty = 0;
03956 }
03957 } else {
03958 max_penalty = 0;
03959 }
03960
03961 if (args.options && (strchr(args.options, 'r')))
03962 ringing = 1;
03963
03964 if (option_debug)
03965 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
03966 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
03967
03968 qe.chan = chan;
03969 qe.prio = prio;
03970 qe.max_penalty = max_penalty;
03971 qe.last_pos_said = 0;
03972 qe.last_pos = 0;
03973 qe.last_periodic_announce_time = time(NULL);
03974 qe.last_periodic_announce_sound = 0;
03975 qe.valid_digits = 0;
03976 if (!join_queue(args.queuename, &qe, &reason)) {
03977 int makeannouncement = 0;
03978
03979 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
03980 S_OR(chan->cid.cid_num, ""));
03981 check_turns:
03982 if (ringing) {
03983 ast_indicate(chan, AST_CONTROL_RINGING);
03984 } else {
03985 ast_moh_start(chan, qe.moh, NULL);
03986 }
03987
03988
03989 res = wait_our_turn(&qe, ringing, &reason);
03990 if (res)
03991 goto stop;
03992
03993 for (;;) {
03994
03995
03996
03997
03998
03999 enum queue_member_status stat;
04000
04001
04002 if (qe.expire && (time(NULL) >= qe.expire)) {
04003 record_abandoned(&qe);
04004 reason = QUEUE_TIMEOUT;
04005 res = 0;
04006 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04007 break;
04008 }
04009
04010 if (makeannouncement) {
04011
04012 if (qe.parent->announcefrequency && !ringing)
04013 if ((res = say_position(&qe)))
04014 goto stop;
04015
04016 }
04017 makeannouncement = 1;
04018
04019
04020 if (qe.expire && (time(NULL) >= qe.expire)) {
04021 record_abandoned(&qe);
04022 reason = QUEUE_TIMEOUT;
04023 res = 0;
04024 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04025 break;
04026 }
04027
04028 if (qe.parent->periodicannouncefrequency && !ringing)
04029 if ((res = say_periodic_announcement(&qe)))
04030 goto stop;
04031
04032
04033 if (qe.expire && (time(NULL) >= qe.expire)) {
04034 record_abandoned(&qe);
04035 reason = QUEUE_TIMEOUT;
04036 res = 0;
04037 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04038 break;
04039 }
04040
04041 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi);
04042 if (res)
04043 goto stop;
04044
04045 stat = get_member_status(qe.parent, qe.max_penalty);
04046
04047
04048 if (noption && tries >= qe.parent->membercount) {
04049 if (option_verbose > 2)
04050 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
04051 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04052 record_abandoned(&qe);
04053 reason = QUEUE_TIMEOUT;
04054 res = 0;
04055 break;
04056 }
04057
04058
04059 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
04060 record_abandoned(&qe);
04061 reason = QUEUE_LEAVEEMPTY;
04062 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04063 res = 0;
04064 break;
04065 }
04066
04067
04068 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
04069 record_abandoned(&qe);
04070 reason = QUEUE_LEAVEUNAVAIL;
04071 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04072 res = 0;
04073 break;
04074 }
04075
04076
04077 if (qe.expire && (time(NULL) >= qe.expire)) {
04078 record_abandoned(&qe);
04079 reason = QUEUE_TIMEOUT;
04080 res = 0;
04081 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04082 break;
04083 }
04084
04085
04086 update_realtime_members(qe.parent);
04087
04088
04089 res = wait_a_bit(&qe);
04090 if (res)
04091 goto stop;
04092
04093
04094
04095
04096
04097 if (!is_our_turn(&qe)) {
04098 if (option_debug)
04099 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
04100 qe.chan->name);
04101 goto check_turns;
04102 }
04103 }
04104
04105 stop:
04106 if (res) {
04107 if (res < 0) {
04108 if (!qe.handled) {
04109 record_abandoned(&qe);
04110 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
04111 "%d|%d|%ld", qe.pos, qe.opos,
04112 (long) time(NULL) - qe.start);
04113 }
04114 res = -1;
04115 } else if (qe.valid_digits) {
04116 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
04117 "%s|%d", qe.digits, qe.pos);
04118 }
04119 }
04120
04121
04122 if (res >= 0 && res != AST_PBX_KEEPALIVE) {
04123 res = 0;
04124 if (ringing) {
04125 ast_indicate(chan, -1);
04126 } else {
04127 ast_moh_stop(chan);
04128 }
04129 ast_stopstream(chan);
04130 }
04131 leave_queue(&qe);
04132 if (reason != QUEUE_UNKNOWN)
04133 set_queue_result(chan, reason);
04134 } else {
04135 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
04136 set_queue_result(chan, reason);
04137 res = 0;
04138 }
04139 ast_module_user_remove(lu);
04140
04141 return res;
04142 }
04143
04144 enum qmc_status {
04145 QMC_VALID = 0,
04146 QMC_PAUSED,
04147 QMC_ACTIVE,
04148 QMC_FREE,
04149 QMC_ALL
04150 };
04151
04152 static int queue_function_queuemembercount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
04153 {
04154 int count = 0;
04155 struct call_queue *q;
04156 struct ast_module_user *lu;
04157 struct member *m;
04158 struct ao2_iterator mem_iter;
04159 char *name, *item;
04160 enum qmc_status mode = QMC_VALID;
04161
04162 buf[0] = '\0';
04163
04164 if (ast_strlen_zero(data)) {
04165 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04166 return -1;
04167 }
04168
04169 name = ast_strdupa(data);
04170
04171 lu = ast_module_user_add(chan);
04172
04173 if ((item = strchr(name, ':'))) {
04174 *item = '\0';
04175 item++;
04176 } else {
04177 item = "";
04178 }
04179
04180 if (!strcasecmp(item, "valid")) {
04181 mode = QMC_VALID;
04182 } else if (!strcasecmp(item, "paused")) {
04183 mode = QMC_PAUSED;
04184 } else if (!strcasecmp(item, "active")) {
04185 mode = QMC_ACTIVE;
04186 } else if (!strcasecmp(item, "free")) {
04187 mode = QMC_FREE;
04188 } else if (!strcasecmp(item, "all")) {
04189 mode = QMC_ALL;
04190 }
04191
04192 if ((q = load_realtime_queue(name))) {
04193 ast_mutex_lock(&q->lock);
04194 mem_iter = ao2_iterator_init(q->members, 0);
04195 while ((m = ao2_iterator_next(&mem_iter))) {
04196 switch (mode) {
04197 case QMC_VALID:
04198
04199 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04200 count++;
04201 }
04202 break;
04203 case QMC_PAUSED:
04204
04205 if (m->paused) {
04206 count++;
04207 }
04208 break;
04209 case QMC_ACTIVE:
04210
04211 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04212 count++;
04213 }
04214 break;
04215 case QMC_FREE:
04216
04217 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) {
04218 count++;
04219 }
04220 break;
04221 default:
04222 count++;
04223 break;
04224 }
04225 ao2_ref(m, -1);
04226 }
04227 ast_mutex_unlock(&q->lock);
04228 } else
04229 ast_log(LOG_WARNING, "queue %s was not found\n", name);
04230
04231 snprintf(buf, len, "%d", count);
04232 ast_module_user_remove(lu);
04233
04234 return 0;
04235 }
04236
04237 static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
04238 {
04239 int count = 0;
04240 struct call_queue *q;
04241 struct ast_module_user *lu;
04242 struct ast_variable *var = NULL;
04243
04244 buf[0] = '\0';
04245
04246 if (ast_strlen_zero(data)) {
04247 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04248 return -1;
04249 }
04250
04251 lu = ast_module_user_add(chan);
04252
04253 AST_LIST_LOCK(&queues);
04254 AST_LIST_TRAVERSE(&queues, q, list) {
04255 if (!strcasecmp(q->name, data)) {
04256 ast_mutex_lock(&q->lock);
04257 break;
04258 }
04259 }
04260 AST_LIST_UNLOCK(&queues);
04261
04262 if (q) {
04263 count = q->count;
04264 ast_mutex_unlock(&q->lock);
04265 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
04266
04267
04268
04269
04270 count = 0;
04271 ast_variables_destroy(var);
04272 } else
04273 ast_log(LOG_WARNING, "queue %s was not found\n", data);
04274
04275 snprintf(buf, len, "%d", count);
04276 ast_module_user_remove(lu);
04277 return 0;
04278 }
04279
04280 static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
04281 {
04282 struct ast_module_user *u;
04283 struct call_queue *q;
04284 struct member *m;
04285
04286
04287 buf[0] = '\0';
04288
04289 if (ast_strlen_zero(data)) {
04290 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
04291 return -1;
04292 }
04293
04294 u = ast_module_user_add(chan);
04295
04296 AST_LIST_LOCK(&queues);
04297 AST_LIST_TRAVERSE(&queues, q, list) {
04298 if (!strcasecmp(q->name, data)) {
04299 ast_mutex_lock(&q->lock);
04300 break;
04301 }
04302 }
04303 AST_LIST_UNLOCK(&queues);
04304
04305 if (q) {
04306 int buflen = 0, count = 0;
04307 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
04308
04309 while ((m = ao2_iterator_next(&mem_iter))) {
04310
04311 if (count++) {
04312 strncat(buf + buflen, ",", len - buflen - 1);
04313 buflen++;
04314 }
04315 strncat(buf + buflen, m->membername, len - buflen - 1);
04316 buflen += strlen(m->membername);
04317
04318 if (buflen >= len - 2) {
04319 ao2_ref(m, -1);
04320 ast_log(LOG_WARNING, "Truncating list\n");
04321 break;
04322 }
04323 ao2_ref(m, -1);
04324 }
04325 ast_mutex_unlock(&q->lock);
04326 } else
04327 ast_log(LOG_WARNING, "queue %s was not found\n", data);
04328
04329
04330 buf[len - 1] = '\0';
04331 ast_module_user_remove(u);
04332
04333 return 0;
04334 }
04335
04336 static struct ast_custom_function queueagentcount_function = {
04337 .name = "QUEUEAGENTCOUNT",
04338 .synopsis = "Count number of agents answering a queue",
04339 .syntax = "QUEUEAGENTCOUNT(<queuename>)",
04340 .desc =
04341 "Returns the number of members currently associated with the specified queue.\n"
04342 "This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
04343 .read = queue_function_queuemembercount,
04344 };
04345
04346 static struct ast_custom_function queuemembercount_function = {
04347 .name = "QUEUE_MEMBER_COUNT",
04348 .synopsis = "Count number of members answering a queue",
04349 .syntax = "QUEUE_MEMBER_COUNT(<queuename>[:mode])",
04350 .desc =
04351 "Returns the number of members currently associated with the specified queue.\n"
04352 "Valid mode values are:\n"
04353 "- valid (default) Members anwering the queue.\n"
04354 "- paused Paused members.\n"
04355 "- active Active members(ie. valid and not paused).\n"
04356 "- free Active members not in use.\n"
04357 "- all All members defined in queue.\n",
04358 .read = queue_function_queuemembercount,
04359 };
04360
04361 static struct ast_custom_function queuewaitingcount_function = {
04362 .name = "QUEUE_WAITING_COUNT",
04363 .synopsis = "Count number of calls currently waiting in a queue",
04364 .syntax = "QUEUE_WAITING_COUNT(<queuename>)",
04365 .desc =
04366 "Returns the number of callers currently waiting in the specified queue.\n",
04367 .read = queue_function_queuewaitingcount,
04368 };
04369
04370 static struct ast_custom_function queuememberlist_function = {
04371 .name = "QUEUE_MEMBER_LIST",
04372 .synopsis = "Returns a list of interfaces on a queue",
04373 .syntax = "QUEUE_MEMBER_LIST(<queuename>)",
04374 .desc =
04375 "Returns a comma-separated list of members associated with the specified queue.\n",
04376 .read = queue_function_queuememberlist,
04377 };
04378
04379 static int reload_queues(void)
04380 {
04381 struct call_queue *q;
04382 struct ast_config *cfg;
04383 char *cat, *tmp;
04384 struct ast_variable *var;
04385 struct member *cur, *newm;
04386 struct ao2_iterator mem_iter;
04387 int new;
04388 const char *general_val = NULL;
04389 char parse[80];
04390 char *interface;
04391 char *membername = NULL;
04392 int penalty;
04393 AST_DECLARE_APP_ARGS(args,
04394 AST_APP_ARG(interface);
04395 AST_APP_ARG(penalty);
04396 AST_APP_ARG(membername);
04397 );
04398
04399 if (!(cfg = ast_config_load("queues.conf"))) {
04400 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
04401 return 0;
04402 }
04403 AST_LIST_LOCK(&queues);
04404 use_weight=0;
04405
04406 AST_LIST_TRAVERSE(&queues, q, list) {
04407 if (!q->realtime) {
04408 q->dead = 1;
04409 q->found = 0;
04410 }
04411 }
04412
04413
04414 cat = NULL;
04415 while ((cat = ast_category_browse(cfg, cat)) ) {
04416 if (!strcasecmp(cat, "general")) {
04417
04418 queue_debug = 0;
04419 if ((general_val = ast_variable_retrieve(cfg, "general", "debug")))
04420 queue_debug = ast_true(general_val);
04421 queue_persistent_members = 0;
04422 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
04423 queue_persistent_members = ast_true(general_val);
04424 autofill_default = 0;
04425 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
04426 autofill_default = ast_true(general_val);
04427 montype_default = 0;
04428 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
04429 if (!strcasecmp(general_val, "mixmonitor"))
04430 montype_default = 1;
04431 } else {
04432
04433 AST_LIST_TRAVERSE(&queues, q, list) {
04434 if (!strcmp(q->name, cat))
04435 break;
04436 }
04437 if (!q) {
04438
04439 if (!(q = alloc_queue(cat))) {
04440
04441 }
04442 new = 1;
04443 } else
04444 new = 0;
04445 if (q) {
04446 if (!new)
04447 ast_mutex_lock(&q->lock);
04448
04449 if (q->found) {
04450 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
04451 if (!new)
04452 ast_mutex_unlock(&q->lock);
04453 continue;
04454 }
04455
04456 init_queue(q);
04457 clear_queue(q);
04458 mem_iter = ao2_iterator_init(q->members, 0);
04459 while ((cur = ao2_iterator_next(&mem_iter))) {
04460 if (!cur->dynamic) {
04461 cur->delme = 1;
04462 }
04463 ao2_ref(cur, -1);
04464 }
04465 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04466 if (!strcasecmp(var->name, "member")) {
04467 struct member tmpmem;
04468 membername = NULL;
04469
04470
04471 ast_copy_string(parse, var->value, sizeof(parse));
04472
04473 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
04474
04475 interface = args.interface;
04476 if (!ast_strlen_zero(args.penalty)) {
04477 tmp = args.penalty;
04478 while (*tmp && *tmp < 33) tmp++;
04479 penalty = atoi(tmp);
04480 if (penalty < 0) {
04481 penalty = 0;
04482 }
04483 } else
04484 penalty = 0;
04485
04486 if (!ast_strlen_zero(args.membername)) {
04487 membername = args.membername;
04488 while (*membername && *membername < 33) membername++;
04489 }
04490
04491
04492 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
04493 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
04494
04495 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
04496 ao2_link(q->members, newm);
04497 ao2_ref(newm, -1);
04498 newm = NULL;
04499
04500 if (cur)
04501 ao2_ref(cur, -1);
04502 else {
04503
04504 add_to_interfaces(interface);
04505 q->membercount++;
04506 }
04507 } else {
04508 queue_set_param(q, var->name, var->value, var->lineno, 1);
04509 }
04510 }
04511
04512
04513 mem_iter = ao2_iterator_init(q->members, 0);
04514 while ((cur = ao2_iterator_next(&mem_iter))) {
04515 if (! cur->delme) {
04516 ao2_ref(cur, -1);
04517 continue;
04518 }
04519
04520 q->membercount--;
04521 ao2_unlink(q->members, cur);
04522 remove_from_interfaces(cur->interface);
04523 ao2_ref(cur, -1);
04524 }
04525
04526 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
04527 rr_dep_warning();
04528
04529 if (new) {
04530 AST_LIST_INSERT_HEAD(&queues, q, list);
04531 } else
04532 ast_mutex_unlock(&q->lock);
04533 }
04534 }
04535 }
04536 ast_config_destroy(cfg);
04537 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
04538 if (q->dead) {
04539 AST_LIST_REMOVE_CURRENT(&queues, list);
04540 if (!q->count)
04541 destroy_queue(q);
04542 else
04543 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
04544 } else {
04545 ast_mutex_lock(&q->lock);
04546 mem_iter = ao2_iterator_init(q->members, 0);
04547 while ((cur = ao2_iterator_next(&mem_iter))) {
04548 if (cur->dynamic)
04549 q->membercount++;
04550 cur->status = ast_device_state(cur->interface);
04551 ao2_ref(cur, -1);
04552 }
04553 ast_mutex_unlock(&q->lock);
04554 }
04555 }
04556 AST_LIST_TRAVERSE_SAFE_END;
04557 AST_LIST_UNLOCK(&queues);
04558 return 1;
04559 }
04560
04561 static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
04562 {
04563 struct call_queue *q;
04564 struct queue_ent *qe;
04565 struct member *mem;
04566 int pos, queue_show;
04567 time_t now;
04568 char max_buf[150];
04569 char *max;
04570 size_t max_left;
04571 float sl = 0;
04572 char *term = manager ? "\r\n" : "\n";
04573 struct ao2_iterator mem_iter;
04574
04575 time(&now);
04576 if (argc == 2)
04577 queue_show = 0;
04578 else if (argc == 3)
04579 queue_show = 1;
04580 else
04581 return RESULT_SHOWUSAGE;
04582
04583
04584 if (queue_show) {
04585 load_realtime_queue(argv[2]);
04586 } else if (ast_check_realtime("queues")) {
04587 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL);
04588 char *queuename;
04589 if (cfg) {
04590 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
04591 load_realtime_queue(queuename);
04592 }
04593 ast_config_destroy(cfg);
04594 }
04595 }
04596
04597 AST_LIST_LOCK(&queues);
04598 if (AST_LIST_EMPTY(&queues)) {
04599 AST_LIST_UNLOCK(&queues);
04600 if (queue_show) {
04601 if (s)
04602 astman_append(s, "No such queue: %s.%s",argv[2], term);
04603 else
04604 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04605 } else {
04606 if (s)
04607 astman_append(s, "No queues.%s", term);
04608 else
04609 ast_cli(fd, "No queues.%s", term);
04610 }
04611 return RESULT_SUCCESS;
04612 }
04613 AST_LIST_TRAVERSE(&queues, q, list) {
04614 ast_mutex_lock(&q->lock);
04615 if (queue_show) {
04616 if (strcasecmp(q->name, argv[2]) != 0) {
04617 ast_mutex_unlock(&q->lock);
04618 if (!AST_LIST_NEXT(q, list)) {
04619 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04620 break;
04621 }
04622 continue;
04623 }
04624 }
04625 max_buf[0] = '\0';
04626 max = max_buf;
04627 max_left = sizeof(max_buf);
04628 if (q->maxlen)
04629 ast_build_string(&max, &max_left, "%d", q->maxlen);
04630 else
04631 ast_build_string(&max, &max_left, "unlimited");
04632 sl = 0;
04633 if (q->callscompleted > 0)
04634 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
04635 if (s)
04636 astman_append(s, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
04637 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit,
04638 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term);
04639 else
04640 ast_cli(fd, "%-12.12s has %d calls (max %s) in '%s' strategy (%ds holdtime), R:%d, W:%d, C:%d, A:%d, SL:%2.1f%% within %ds%s",
04641 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit,
04642 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term);
04643 if (ao2_container_count(q->members)) {
04644 if (s)
04645 astman_append(s, " Members: %s", term);
04646 else
04647 ast_cli(fd, " Members: %s", term);
04648 mem_iter = ao2_iterator_init(q->members, 0);
04649 while ((mem = ao2_iterator_next(&mem_iter))) {
04650 max_buf[0] = '\0';
04651 max = max_buf;
04652 max_left = sizeof(max_buf);
04653 if (strcasecmp(mem->membername, mem->interface)) {
04654 ast_build_string(&max, &max_left, " (%s)", mem->interface);
04655 }
04656 if (mem->penalty)
04657 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
04658 if (mem->dynamic)
04659 ast_build_string(&max, &max_left, " (dynamic)");
04660 if (mem->realtime)
04661 ast_build_string(&max, &max_left, " (realtime)");
04662 if (mem->paused)
04663 ast_build_string(&max, &max_left, " (paused)");
04664 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
04665 if (mem->calls) {
04666 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
04667 mem->calls, (long) (time(NULL) - mem->lastcall));
04668 } else
04669 ast_build_string(&max, &max_left, " has taken no calls yet");
04670 if (s)
04671 astman_append(s, " %s%s%s", mem->membername, max_buf, term);
04672 else
04673 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term);
04674 ao2_ref(mem, -1);
04675 }
04676 } else if (s)
04677 astman_append(s, " No Members%s", term);
04678 else
04679 ast_cli(fd, " No Members%s", term);
04680 if (q->head) {
04681 pos = 1;
04682 if (s)
04683 astman_append(s, " Callers: %s", term);
04684 else
04685 ast_cli(fd, " Callers: %s", term);
04686 for (qe = q->head; qe; qe = qe->next) {
04687 if (s)
04688 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
04689 pos++, qe->chan->name, (long) (now - qe->start) / 60,
04690 (long) (now - qe->start) % 60, qe->prio, term);
04691 else
04692 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
04693 qe->chan->name, (long) (now - qe->start) / 60,
04694 (long) (now - qe->start) % 60, qe->prio, term);
04695 }
04696 } else if (s)
04697 astman_append(s, " No Callers%s", term);
04698 else
04699 ast_cli(fd, " No Callers%s", term);
04700 if (s)
04701 astman_append(s, "%s", term);
04702 else
04703 ast_cli(fd, "%s", term);
04704 ast_mutex_unlock(&q->lock);
04705 if (queue_show)
04706 break;
04707 }
04708 AST_LIST_UNLOCK(&queues);
04709 return RESULT_SUCCESS;
04710 }
04711
04712 static int queue_show(int fd, int argc, char **argv)
04713 {
04714 return __queues_show(NULL, 0, fd, argc, argv);
04715 }
04716
04717 static char *complete_queue(const char *line, const char *word, int pos, int state)
04718 {
04719 struct call_queue *q;
04720 char *ret = NULL;
04721 int which = 0;
04722 int wordlen = strlen(word);
04723
04724 AST_LIST_LOCK(&queues);
04725 AST_LIST_TRAVERSE(&queues, q, list) {
04726 if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
04727 ret = ast_strdup(q->name);
04728 break;
04729 }
04730 }
04731 AST_LIST_UNLOCK(&queues);
04732
04733 return ret;
04734 }
04735
04736 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
04737 {
04738 if (pos == 2)
04739 return complete_queue(line, word, pos, state);
04740 return NULL;
04741 }
04742
04743
04744
04745
04746 static int manager_queues_show(struct mansession *s, const struct message *m)
04747 {
04748 char *a[] = { "queue", "show" };
04749
04750 __queues_show(s, 1, -1, 2, a);
04751 astman_append(s, "\r\n\r\n");
04752
04753 return RESULT_SUCCESS;
04754 }
04755
04756
04757 static int manager_queues_status(struct mansession *s, const struct message *m)
04758 {
04759 time_t now;
04760 int pos;
04761 const char *id = astman_get_header(m,"ActionID");
04762 const char *queuefilter = astman_get_header(m,"Queue");
04763 const char *memberfilter = astman_get_header(m,"Member");
04764 char idText[256] = "";
04765 struct call_queue *q;
04766 struct queue_ent *qe;
04767 float sl = 0;
04768 struct member *mem;
04769 struct ao2_iterator mem_iter;
04770
04771 astman_send_ack(s, m, "Queue status will follow");
04772 time(&now);
04773 AST_LIST_LOCK(&queues);
04774 if (!ast_strlen_zero(id))
04775 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04776
04777 AST_LIST_TRAVERSE(&queues, q, list) {
04778 ast_mutex_lock(&q->lock);
04779
04780
04781 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
04782 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
04783 astman_append(s, "Event: QueueParams\r\n"
04784 "Queue: %s\r\n"
04785 "Max: %d\r\n"
04786 "Calls: %d\r\n"
04787 "Holdtime: %d\r\n"
04788 "Completed: %d\r\n"
04789 "Abandoned: %d\r\n"
04790 "ServiceLevel: %d\r\n"
04791 "ServicelevelPerf: %2.1f\r\n"
04792 "RingLimit: %d\r\n"
04793 "Weight: %d\r\n"
04794 "%s"
04795 "\r\n",
04796 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
04797 q->callsabandoned, q->servicelevel, sl, q->ringlimit, q->weight, idText);
04798
04799 mem_iter = ao2_iterator_init(q->members, 0);
04800 while ((mem = ao2_iterator_next(&mem_iter))) {
04801 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
04802 astman_append(s, "Event: QueueMember\r\n"
04803 "Queue: %s\r\n"
04804 "Name: %s\r\n"
04805 "Location: %s\r\n"
04806 "Membership: %s\r\n"
04807 "Penalty: %d\r\n"
04808 "CallsTaken: %d\r\n"
04809 "LastCall: %d\r\n"
04810 "Status: %d\r\n"
04811 "Paused: %d\r\n"
04812 "%s"
04813 "\r\n",
04814 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
04815 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
04816 }
04817 ao2_ref(mem, -1);
04818 }
04819
04820 pos = 1;
04821 for (qe = q->head; qe; qe = qe->next) {
04822 astman_append(s, "Event: QueueEntry\r\n"
04823 "Queue: %s\r\n"
04824 "Position: %d\r\n"
04825 "Channel: %s\r\n"
04826 "CallerID: %s\r\n"
04827 "CallerIDName: %s\r\n"
04828 "Wait: %ld\r\n"
04829 "%s"
04830 "\r\n",
04831 q->name, pos++, qe->chan->name,
04832 S_OR(qe->chan->cid.cid_num, "unknown"),
04833 S_OR(qe->chan->cid.cid_name, "unknown"),
04834 (long) (now - qe->start), idText);
04835 }
04836 }
04837 ast_mutex_unlock(&q->lock);
04838 }
04839
04840 astman_append(s,
04841 "Event: QueueStatusComplete\r\n"
04842 "%s"
04843 "\r\n",idText);
04844
04845 AST_LIST_UNLOCK(&queues);
04846
04847
04848 return RESULT_SUCCESS;
04849 }
04850
04851 static int manager_add_queue_member(struct mansession *s, const struct message *m)
04852 {
04853 const char *queuename, *interface, *penalty_s, *paused_s, *membername;
04854 int paused, penalty = 0;
04855
04856 queuename = astman_get_header(m, "Queue");
04857 interface = astman_get_header(m, "Interface");
04858 penalty_s = astman_get_header(m, "Penalty");
04859 paused_s = astman_get_header(m, "Paused");
04860 membername = astman_get_header(m, "MemberName");
04861
04862 if (ast_strlen_zero(queuename)) {
04863 astman_send_error(s, m, "'Queue' not specified.");
04864 return 0;
04865 }
04866
04867 if (ast_strlen_zero(interface)) {
04868 astman_send_error(s, m, "'Interface' not specified.");
04869 return 0;
04870 }
04871
04872 if (ast_strlen_zero(penalty_s))
04873 penalty = 0;
04874 else if (sscanf(penalty_s, "%d", &penalty) != 1 || penalty < 0)
04875 penalty = 0;
04876
04877 if (ast_strlen_zero(paused_s))
04878 paused = 0;
04879 else
04880 paused = abs(ast_true(paused_s));
04881
04882 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
04883 case RES_OKAY:
04884 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
04885 astman_send_ack(s, m, "Added interface to queue");
04886 break;
04887 case RES_EXISTS:
04888 astman_send_error(s, m, "Unable to add interface: Already there");
04889 break;
04890 case RES_NOSUCHQUEUE:
04891 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
04892 break;
04893 case RES_OUTOFMEMORY:
04894 astman_send_error(s, m, "Out of memory");
04895 break;
04896 }
04897
04898 return 0;
04899 }
04900
04901 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
04902 {
04903 const char *queuename, *interface;
04904
04905 queuename = astman_get_header(m, "Queue");
04906 interface = astman_get_header(m, "Interface");
04907
04908 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
04909 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
04910 return 0;
04911 }
04912
04913 switch (remove_from_queue(queuename, interface)) {
04914 case RES_OKAY:
04915 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
04916 astman_send_ack(s, m, "Removed interface from queue");
04917 break;
04918 case RES_EXISTS:
04919 astman_send_error(s, m, "Unable to remove interface: Not there");
04920 break;
04921 case RES_NOSUCHQUEUE:
04922 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
04923 break;
04924 case RES_OUTOFMEMORY:
04925 astman_send_error(s, m, "Out of memory");
04926 break;
04927 case RES_NOT_DYNAMIC:
04928 astman_send_error(s, m, "Member not dynamic");
04929 break;
04930 }
04931
04932 return 0;
04933 }
04934
04935 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
04936 {
04937 const char *queuename, *interface, *paused_s;
04938 int paused;
04939
04940 interface = astman_get_header(m, "Interface");
04941 paused_s = astman_get_header(m, "Paused");
04942 queuename = astman_get_header(m, "Queue");
04943
04944 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
04945 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
04946 return 0;
04947 }
04948
04949 paused = abs(ast_true(paused_s));
04950
04951 if (set_member_paused(queuename, interface, paused))
04952 astman_send_error(s, m, "Interface not found");
04953 else
04954 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
04955 return 0;
04956 }
04957
04958 static int handle_queue_add_member(int fd, int argc, char *argv[])
04959 {
04960 char *queuename, *interface, *membername = NULL;
04961 int penalty;
04962
04963 if ((argc != 6) && (argc != 8) && (argc != 10)) {
04964 return RESULT_SHOWUSAGE;
04965 } else if (strcmp(argv[4], "to")) {
04966 return RESULT_SHOWUSAGE;
04967 } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
04968 return RESULT_SHOWUSAGE;
04969 } else if ((argc == 10) && strcmp(argv[8], "as")) {
04970 return RESULT_SHOWUSAGE;
04971 }
04972
04973 queuename = argv[5];
04974 interface = argv[3];
04975 if (argc >= 8) {
04976 if (sscanf(argv[7], "%d", &penalty) == 1) {
04977 if (penalty < 0) {
04978 ast_cli(fd, "Penalty must be >= 0\n");
04979 penalty = 0;
04980 }
04981 } else {
04982 ast_cli(fd, "Penalty must be an integer >= 0\n");
04983 penalty = 0;
04984 }
04985 } else {
04986 penalty = 0;
04987 }
04988
04989 if (argc >= 10) {
04990 membername = argv[9];
04991 }
04992
04993 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
04994 case RES_OKAY:
04995 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
04996 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
04997 return RESULT_SUCCESS;
04998 case RES_EXISTS:
04999 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
05000 return RESULT_FAILURE;
05001 case RES_NOSUCHQUEUE:
05002 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
05003 return RESULT_FAILURE;
05004 case RES_OUTOFMEMORY:
05005 ast_cli(fd, "Out of memory\n");
05006 return RESULT_FAILURE;
05007 default:
05008 return RESULT_FAILURE;
05009 }
05010 }
05011
05012 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
05013 {
05014
05015 switch (pos) {
05016 case 3:
05017 return NULL;
05018 case 4:
05019 return state == 0 ? ast_strdup("to") : NULL;
05020 case 5:
05021 return complete_queue(line, word, pos, state);
05022 case 6:
05023 return state == 0 ? ast_strdup("penalty") : NULL;
05024 case 7:
05025 if (state < 100) {
05026 char *num;
05027 if ((num = ast_malloc(3))) {
05028 sprintf(num, "%d", state);
05029 }
05030 return num;
05031 } else {
05032 return NULL;
05033 }
05034 case 8:
05035 return state == 0 ? ast_strdup("as") : NULL;
05036 case 9:
05037 return NULL;
05038 default:
05039 return NULL;
05040 }
05041 }
05042
05043 static int handle_queue_remove_member(int fd, int argc, char *argv[])
05044 {
05045 char *queuename, *interface;
05046
05047 if (argc != 6) {
05048 return RESULT_SHOWUSAGE;
05049 } else if (strcmp(argv[4], "from")) {
05050 return RESULT_SHOWUSAGE;
05051 }
05052
05053 queuename = argv[5];
05054 interface = argv[3];
05055
05056 switch (remove_from_queue(queuename, interface)) {
05057 case RES_OKAY:
05058 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
05059 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
05060 return RESULT_SUCCESS;
05061 case RES_EXISTS:
05062 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
05063 return RESULT_FAILURE;
05064 case RES_NOSUCHQUEUE:
05065 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
05066 return RESULT_FAILURE;
05067 case RES_OUTOFMEMORY:
05068 ast_cli(fd, "Out of memory\n");
05069 return RESULT_FAILURE;
05070 case RES_NOT_DYNAMIC:
05071 ast_cli(fd, "Member not dynamic\n");
05072 return RESULT_FAILURE;
05073 default:
05074 return RESULT_FAILURE;
05075 }
05076 }
05077
05078 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
05079 {
05080 int which = 0;
05081 struct call_queue *q;
05082 struct member *m;
05083 struct ao2_iterator mem_iter;
05084
05085
05086 if (pos > 5 || pos < 3)
05087 return NULL;
05088 if (pos == 4)
05089 return state == 0 ? ast_strdup("from") : NULL;
05090
05091 if (pos == 5)
05092 return complete_queue(line, word, pos, state);
05093
05094
05095 if (!AST_LIST_EMPTY(&queues)) {
05096 AST_LIST_TRAVERSE(&queues, q, list) {
05097 ast_mutex_lock(&q->lock);
05098 mem_iter = ao2_iterator_init(q->members, 0);
05099 while ((m = ao2_iterator_next(&mem_iter))) {
05100 if (++which > state) {
05101 char *tmp;
05102 ast_mutex_unlock(&q->lock);
05103 tmp = ast_strdup(m->interface);
05104 ao2_ref(m, -1);
05105 return tmp;
05106 }
05107 ao2_ref(m, -1);
05108 }
05109 ast_mutex_unlock(&q->lock);
05110 }
05111 }
05112
05113 return NULL;
05114 }
05115
05116 static char queue_show_usage[] =
05117 "Usage: queue show\n"
05118 " Provides summary information on a specified queue.\n";
05119
05120 static char qam_cmd_usage[] =
05121 "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
05122
05123 static char qrm_cmd_usage[] =
05124 "Usage: queue remove member <channel> from <queue>\n";
05125
05126 static struct ast_cli_entry cli_show_queue_deprecated = {
05127 { "show", "queue", NULL },
05128 queue_show, NULL,
05129 NULL, complete_queue_show };
05130
05131 static struct ast_cli_entry cli_add_queue_member_deprecated = {
05132 { "add", "queue", "member", NULL },
05133 handle_queue_add_member, NULL,
05134 NULL, complete_queue_add_member };
05135
05136 static struct ast_cli_entry cli_remove_queue_member_deprecated = {
05137 { "remove", "queue", "member", NULL },
05138 handle_queue_remove_member, NULL,
05139 NULL, complete_queue_remove_member };
05140
05141 static struct ast_cli_entry cli_queue[] = {
05142
05143 { { "show", "queues", NULL },
05144 queue_show, NULL,
05145 NULL, NULL },
05146
05147 { { "queue", "show", NULL },
05148 queue_show, "Show status of a specified queue",
05149 queue_show_usage, complete_queue_show, &cli_show_queue_deprecated },
05150
05151 { { "queue", "add", "member", NULL },
05152 handle_queue_add_member, "Add a channel to a specified queue",
05153 qam_cmd_usage, complete_queue_add_member, &cli_add_queue_member_deprecated },
05154
05155 { { "queue", "remove", "member", NULL },
05156 handle_queue_remove_member, "Removes a channel from a specified queue",
05157 qrm_cmd_usage, complete_queue_remove_member, &cli_remove_queue_member_deprecated },
05158 };
05159
05160 static int unload_module(void)
05161 {
05162 int res;
05163
05164 if (device_state.thread != AST_PTHREADT_NULL) {
05165 device_state.stop = 1;
05166 ast_mutex_lock(&device_state.lock);
05167 ast_cond_signal(&device_state.cond);
05168 ast_mutex_unlock(&device_state.lock);
05169 pthread_join(device_state.thread, NULL);
05170 }
05171
05172 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05173 res = ast_manager_unregister("QueueStatus");
05174 res |= ast_manager_unregister("Queues");
05175 res |= ast_manager_unregister("QueueAdd");
05176 res |= ast_manager_unregister("QueueRemove");
05177 res |= ast_manager_unregister("QueuePause");
05178 res |= ast_unregister_application(app_aqm);
05179 res |= ast_unregister_application(app_rqm);
05180 res |= ast_unregister_application(app_pqm);
05181 res |= ast_unregister_application(app_upqm);
05182 res |= ast_unregister_application(app_ql);
05183 res |= ast_unregister_application(app);
05184 res |= ast_custom_function_unregister(&queueagentcount_function);
05185 res |= ast_custom_function_unregister(&queuemembercount_function);
05186 res |= ast_custom_function_unregister(&queuememberlist_function);
05187 res |= ast_custom_function_unregister(&queuewaitingcount_function);
05188 ast_devstate_del(statechange_queue, NULL);
05189
05190 ast_module_user_hangup_all();
05191
05192 clear_and_free_interfaces();
05193
05194 return res;
05195 }
05196
05197 static int load_module(void)
05198 {
05199 int res;
05200
05201 if (!reload_queues())
05202 return AST_MODULE_LOAD_DECLINE;
05203
05204 if (queue_persistent_members)
05205 reload_queue_members();
05206
05207 ast_mutex_init(&device_state.lock);
05208 ast_cond_init(&device_state.cond, NULL);
05209 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
05210
05211 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05212 res = ast_register_application(app, queue_exec, synopsis, descrip);
05213 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
05214 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
05215 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
05216 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
05217 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
05218 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
05219 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
05220 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
05221 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
05222 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
05223 res |= ast_custom_function_register(&queueagentcount_function);
05224 res |= ast_custom_function_register(&queuemembercount_function);
05225 res |= ast_custom_function_register(&queuememberlist_function);
05226 res |= ast_custom_function_register(&queuewaitingcount_function);
05227 res |= ast_devstate_add(statechange_queue, NULL);
05228
05229 return res;
05230 }
05231
05232 static int reload(void)
05233 {
05234 reload_queues();
05235 return 0;
05236 }
05237
05238 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
05239 .load = load_module,
05240 .unload = unload_module,
05241 .reload = reload,
05242 );
05243