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