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: 180006 $")
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 if (ast_strlen_zero(filename)) {
01503 return 0;
01504 }
01505
01506 ast_stopstream(chan);
01507
01508 res = ast_streamfile(chan, filename, chan->language);
01509 if (!res)
01510 res = ast_waitstream(chan, AST_DIGIT_ANY);
01511
01512 ast_stopstream(chan);
01513
01514 return res;
01515 }
01516
01517 static int valid_exit(struct queue_ent *qe, char digit)
01518 {
01519 int digitlen = strlen(qe->digits);
01520
01521
01522 if (digitlen < sizeof(qe->digits) - 2) {
01523 qe->digits[digitlen] = digit;
01524 qe->digits[digitlen + 1] = '\0';
01525 } else {
01526 qe->digits[0] = '\0';
01527 return 0;
01528 }
01529
01530
01531 if (ast_strlen_zero(qe->context))
01532 return 0;
01533
01534
01535 if (!ast_canmatch_extension(qe->chan, qe->context, qe->digits, 1, qe->chan->cid.cid_num)) {
01536 qe->digits[0] = '\0';
01537 return 0;
01538 }
01539
01540
01541 if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
01542 qe->valid_digits = 1;
01543
01544 return 1;
01545 }
01546
01547 return 0;
01548 }
01549
01550 static int say_position(struct queue_ent *qe)
01551 {
01552 int res = 0, avgholdmins, avgholdsecs;
01553 time_t now;
01554
01555
01556 time(&now);
01557 if ((now - qe->last_pos) < 15)
01558 return 0;
01559
01560
01561 if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
01562 return 0;
01563
01564 ast_moh_stop(qe->chan);
01565
01566 if (qe->pos == 1) {
01567 res = play_file(qe->chan, qe->parent->sound_next);
01568 if (res)
01569 goto playout;
01570 else
01571 goto posout;
01572 } else {
01573 res = play_file(qe->chan, qe->parent->sound_thereare);
01574 if (res)
01575 goto playout;
01576 res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL);
01577 if (res)
01578 goto playout;
01579 res = play_file(qe->chan, qe->parent->sound_calls);
01580 if (res)
01581 goto playout;
01582 }
01583
01584 avgholdmins = abs(((qe->parent->holdtime + 30) - (now - qe->start)) / 60);
01585
01586
01587 if (qe->parent->roundingseconds) {
01588 avgholdsecs = (abs(((qe->parent->holdtime + 30) - (now - qe->start))) - 60 * avgholdmins) / qe->parent->roundingseconds;
01589 avgholdsecs *= qe->parent->roundingseconds;
01590 } else {
01591 avgholdsecs = 0;
01592 }
01593
01594 if (option_verbose > 2)
01595 ast_verbose(VERBOSE_PREFIX_3 "Hold time for %s is %d minutes %d seconds\n", qe->parent->name, avgholdmins, avgholdsecs);
01596
01597
01598
01599 if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
01600 ((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
01601 !(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
01602 res = play_file(qe->chan, qe->parent->sound_holdtime);
01603 if (res)
01604 goto playout;
01605
01606 if (avgholdmins > 0) {
01607 if (avgholdmins < 2) {
01608 res = play_file(qe->chan, qe->parent->sound_lessthan);
01609 if (res)
01610 goto playout;
01611
01612 res = ast_say_number(qe->chan, 2, AST_DIGIT_ANY, qe->chan->language, NULL);
01613 if (res)
01614 goto playout;
01615 } else {
01616 res = ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, NULL);
01617 if (res)
01618 goto playout;
01619 }
01620
01621 res = play_file(qe->chan, qe->parent->sound_minutes);
01622 if (res)
01623 goto playout;
01624 }
01625 if (avgholdsecs>0) {
01626 res = ast_say_number(qe->chan, avgholdsecs, AST_DIGIT_ANY, qe->chan->language, NULL);
01627 if (res)
01628 goto playout;
01629
01630 res = play_file(qe->chan, qe->parent->sound_seconds);
01631 if (res)
01632 goto playout;
01633 }
01634
01635 }
01636
01637 posout:
01638 if (option_verbose > 2)
01639 ast_verbose(VERBOSE_PREFIX_3 "Told %s in %s their queue position (which was %d)\n",
01640 qe->chan->name, qe->parent->name, qe->pos);
01641 res = play_file(qe->chan, qe->parent->sound_thanks);
01642
01643 playout:
01644 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
01645 res = 0;
01646
01647
01648 qe->last_pos = now;
01649 qe->last_pos_said = qe->pos;
01650
01651
01652 if (!res)
01653 ast_moh_start(qe->chan, qe->moh, NULL);
01654
01655 return res;
01656 }
01657
01658 static void recalc_holdtime(struct queue_ent *qe, int newholdtime)
01659 {
01660 int oldvalue;
01661
01662
01663
01664
01665
01666 ast_mutex_lock(&qe->parent->lock);
01667 oldvalue = qe->parent->holdtime;
01668 qe->parent->holdtime = (((oldvalue << 2) - oldvalue) + newholdtime) >> 2;
01669 ast_mutex_unlock(&qe->parent->lock);
01670 }
01671
01672
01673 static void leave_queue(struct queue_ent *qe)
01674 {
01675 struct call_queue *q;
01676 struct queue_ent *cur, *prev = NULL;
01677 int pos = 0;
01678
01679 if (!(q = qe->parent))
01680 return;
01681 ast_mutex_lock(&q->lock);
01682
01683 prev = NULL;
01684 for (cur = q->head; cur; cur = cur->next) {
01685 if (cur == qe) {
01686 q->count--;
01687
01688
01689 manager_event(EVENT_FLAG_CALL, "Leave",
01690 "Channel: %s\r\nQueue: %s\r\nCount: %d\r\nUniqueid: %s\r\n",
01691 qe->chan->name, q->name, q->count, qe->chan->uniqueid);
01692 if (option_debug)
01693 ast_log(LOG_DEBUG, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name );
01694
01695 if (prev)
01696 prev->next = cur->next;
01697 else
01698 q->head = cur->next;
01699 } else {
01700
01701 cur->pos = ++pos;
01702 prev = cur;
01703 }
01704 }
01705 ast_mutex_unlock(&q->lock);
01706
01707 if (q->dead && !q->count) {
01708
01709 AST_LIST_LOCK(&queues);
01710 AST_LIST_REMOVE(&queues, q, list);
01711 AST_LIST_UNLOCK(&queues);
01712 destroy_queue(q);
01713 }
01714 }
01715
01716
01717 static void hangupcalls(struct callattempt *outgoing, struct ast_channel *exception)
01718 {
01719 struct callattempt *oo;
01720
01721 while (outgoing) {
01722
01723 if (outgoing->chan && (outgoing->chan != exception))
01724 ast_hangup(outgoing->chan);
01725 oo = outgoing;
01726 outgoing = outgoing->q_next;
01727 if (oo->member)
01728 ao2_ref(oo->member, -1);
01729 free(oo);
01730 }
01731 }
01732
01733
01734
01735
01736 static int compare_weight(struct call_queue *rq, struct member *member)
01737 {
01738 struct call_queue *q;
01739 struct member *mem;
01740 int found = 0;
01741
01742
01743
01744 AST_LIST_TRAVERSE(&queues, q, list) {
01745 if (q == rq)
01746 continue;
01747 ast_mutex_lock(&q->lock);
01748 if (q->count && q->members) {
01749 if ((mem = ao2_find(q->members, member, OBJ_POINTER))) {
01750 ast_log(LOG_DEBUG, "Found matching member %s in queue '%s'\n", mem->interface, q->name);
01751 if (q->weight > rq->weight) {
01752 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);
01753 found = 1;
01754 }
01755 ao2_ref(mem, -1);
01756 }
01757 }
01758 ast_mutex_unlock(&q->lock);
01759 if (found)
01760 break;
01761 }
01762 return found;
01763 }
01764
01765
01766 static void do_hang(struct callattempt *o)
01767 {
01768 o->stillgoing = 0;
01769 ast_hangup(o->chan);
01770 o->chan = NULL;
01771 }
01772
01773 static char *vars2manager(struct ast_channel *chan, char *vars, size_t len)
01774 {
01775 char *tmp = alloca(len);
01776
01777 if (pbx_builtin_serialize_variables(chan, tmp, len)) {
01778 int i, j;
01779
01780
01781 strcpy(vars, "Variable: ");
01782
01783 for (i = 0, j = 10; (i < len - 1) && (j < len - 1); i++, j++) {
01784 vars[j] = tmp[i];
01785
01786 if (tmp[i + 1] == '\0')
01787 break;
01788 if (tmp[i] == '\n') {
01789 vars[j++] = '\r';
01790 vars[j++] = '\n';
01791
01792 ast_copy_string(&(vars[j]), "Variable: ", len - j);
01793 j += 9;
01794 }
01795 }
01796 if (j > len - 3)
01797 j = len - 3;
01798 vars[j++] = '\r';
01799 vars[j++] = '\n';
01800 vars[j] = '\0';
01801 } else {
01802
01803 *vars = '\0';
01804 }
01805 return vars;
01806 }
01807
01808
01809
01810
01811
01812
01813 static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
01814 {
01815 int res;
01816 int status;
01817 char tech[256];
01818 char *location;
01819 const char *macrocontext, *macroexten;
01820
01821
01822 if (qe->parent->wrapuptime && (time(NULL) - tmp->lastcall < qe->parent->wrapuptime)) {
01823 if (queue_debug)
01824 ast_log(LOG_NOTICE, "Wrapuptime not yet expired for %s\n", tmp->interface);
01825 if (qe->chan->cdr)
01826 ast_cdr_busy(qe->chan->cdr);
01827 tmp->stillgoing = 0;
01828 (*busies)++;
01829 return 0;
01830 }
01831
01832 if (!qe->parent->ringinuse && (tmp->member->status != AST_DEVICE_NOT_INUSE) && (tmp->member->status != AST_DEVICE_UNKNOWN)) {
01833 if (queue_debug)
01834 ast_log(LOG_NOTICE, "%s in use, can't receive call\n", tmp->interface);
01835 if (qe->chan->cdr)
01836 ast_cdr_busy(qe->chan->cdr);
01837 tmp->stillgoing = 0;
01838 return 0;
01839 }
01840
01841 if (tmp->member->paused) {
01842 if (queue_debug)
01843 ast_log(LOG_NOTICE, "%s paused, can't receive call\n", tmp->interface);
01844 if (qe->chan->cdr)
01845 ast_cdr_busy(qe->chan->cdr);
01846 tmp->stillgoing = 0;
01847 return 0;
01848 }
01849 if (use_weight && compare_weight(qe->parent,tmp->member)) {
01850 if (queue_debug)
01851 ast_log(LOG_NOTICE, "Priority queue delaying call to %s:%s\n", qe->parent->name, tmp->interface);
01852 if (qe->chan->cdr)
01853 ast_cdr_busy(qe->chan->cdr);
01854 tmp->stillgoing = 0;
01855 (*busies)++;
01856 return 0;
01857 }
01858
01859 ast_copy_string(tech, tmp->interface, sizeof(tech));
01860 if ((location = strchr(tech, '/')))
01861 *location++ = '\0';
01862 else
01863 location = "";
01864
01865
01866 tmp->chan = ast_request(tech, qe->chan->nativeformats, location, &status);
01867 if (!tmp->chan) {
01868 if (queue_debug)
01869 ast_log(LOG_NOTICE, "Unable to create channel of type '%s' for Queue\n", tech);
01870 if (qe->chan->cdr)
01871 ast_cdr_busy(qe->chan->cdr);
01872 tmp->stillgoing = 0;
01873
01874 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
01875
01876 ast_mutex_lock(&qe->parent->lock);
01877 qe->parent->rrpos++;
01878 ast_mutex_unlock(&qe->parent->lock);
01879
01880 (*busies)++;
01881 return 0;
01882 }
01883
01884
01885 tmp->member->ringcount++;
01886 tmp->chan->appl = "AppQueue";
01887 tmp->chan->data = "(Outgoing Line)";
01888 tmp->chan->whentohangup = 0;
01889 if (tmp->chan->cid.cid_num)
01890 free(tmp->chan->cid.cid_num);
01891 tmp->chan->cid.cid_num = ast_strdup(qe->chan->cid.cid_num);
01892 if (tmp->chan->cid.cid_name)
01893 free(tmp->chan->cid.cid_name);
01894 tmp->chan->cid.cid_name = ast_strdup(qe->chan->cid.cid_name);
01895 if (tmp->chan->cid.cid_ani)
01896 free(tmp->chan->cid.cid_ani);
01897 tmp->chan->cid.cid_ani = ast_strdup(qe->chan->cid.cid_ani);
01898
01899
01900 ast_channel_inherit_variables(qe->chan, tmp->chan);
01901
01902
01903 tmp->chan->adsicpe = qe->chan->adsicpe;
01904
01905
01906 ast_channel_lock(qe->chan);
01907 macrocontext = pbx_builtin_getvar_helper(qe->chan, "MACRO_CONTEXT");
01908 if (!ast_strlen_zero(macrocontext))
01909 ast_copy_string(tmp->chan->dialcontext, macrocontext, sizeof(tmp->chan->dialcontext));
01910 else
01911 ast_copy_string(tmp->chan->dialcontext, qe->chan->context, sizeof(tmp->chan->dialcontext));
01912 macroexten = pbx_builtin_getvar_helper(qe->chan, "MACRO_EXTEN");
01913 if (!ast_strlen_zero(macroexten))
01914 ast_copy_string(tmp->chan->exten, macroexten, sizeof(tmp->chan->exten));
01915 else
01916 ast_copy_string(tmp->chan->exten, qe->chan->exten, sizeof(tmp->chan->exten));
01917 ast_channel_unlock(qe->chan);
01918
01919
01920 if ((res = ast_call(tmp->chan, location, 0))) {
01921
01922 if (option_debug)
01923 ast_log(LOG_DEBUG, "ast call on peer returned %d\n", res);
01924 if (option_verbose > 2)
01925 ast_verbose(VERBOSE_PREFIX_3 "Couldn't call %s\n", tmp->interface);
01926 do_hang(tmp);
01927 (*busies)++;
01928 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
01929 return 0;
01930 } else if (qe->parent->eventwhencalled) {
01931 char vars[2048];
01932
01933 manager_event(EVENT_FLAG_AGENT, "AgentCalled",
01934 "AgentCalled: %s\r\n"
01935 "AgentName: %s\r\n"
01936 "ChannelCalling: %s\r\n"
01937 "CallerID: %s\r\n"
01938 "CallerIDName: %s\r\n"
01939 "Context: %s\r\n"
01940 "Extension: %s\r\n"
01941 "Priority: %d\r\n"
01942 "%s",
01943 tmp->interface, tmp->member->membername, qe->chan->name,
01944 tmp->chan->cid.cid_num ? tmp->chan->cid.cid_num : "unknown",
01945 tmp->chan->cid.cid_name ? tmp->chan->cid.cid_name : "unknown",
01946 qe->chan->context, qe->chan->exten, qe->chan->priority,
01947 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
01948 if (option_verbose > 2)
01949 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", tmp->interface);
01950 }
01951
01952 update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
01953 return 1;
01954 }
01955
01956
01957 static struct callattempt *find_best(struct callattempt *outgoing)
01958 {
01959 struct callattempt *best = NULL, *cur;
01960
01961 for (cur = outgoing; cur; cur = cur->q_next) {
01962 if (cur->stillgoing &&
01963 !cur->chan &&
01964 (!best || cur->metric < best->metric)) {
01965 best = cur;
01966 }
01967 }
01968
01969 return best;
01970 }
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980 static int ring_one(struct queue_ent *qe, struct callattempt *outgoing, int *busies)
01981 {
01982 int ret = 0;
01983
01984 while (ret == 0) {
01985 struct callattempt *best = find_best(outgoing);
01986 if (!best) {
01987 if (option_debug)
01988 ast_log(LOG_DEBUG, "Nobody left to try ringing in queue\n");
01989 break;
01990 }
01991 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
01992 struct callattempt *cur;
01993
01994 for (cur = outgoing; cur; cur = cur->q_next) {
01995 if (cur->stillgoing && !cur->chan && cur->metric <= best->metric) {
01996 if (option_debug)
01997 ast_log(LOG_DEBUG, "(Parallel) Trying '%s' with metric %d\n", cur->interface, cur->metric);
01998 ret |= ring_entry(qe, cur, busies);
01999 }
02000 }
02001 } else {
02002
02003 if (option_debug)
02004 ast_log(LOG_DEBUG, "Trying '%s' with metric %d\n", best->interface, best->metric);
02005 ret = ring_entry(qe, best, busies);
02006 }
02007 }
02008
02009 return ret;
02010 }
02011
02012 static int store_next(struct queue_ent *qe, struct callattempt *outgoing)
02013 {
02014 struct callattempt *best = find_best(outgoing);
02015
02016 if (best) {
02017
02018 if (option_debug)
02019 ast_log(LOG_DEBUG, "Next is '%s' with metric %d\n", best->interface, best->metric);
02020 qe->parent->rrpos = best->metric % 1000;
02021 } else {
02022
02023 if (qe->parent->wrapped) {
02024
02025 qe->parent->rrpos = 0;
02026 } else {
02027
02028 qe->parent->rrpos++;
02029 }
02030 }
02031 qe->parent->wrapped = 0;
02032
02033 return 0;
02034 }
02035
02036 static int say_periodic_announcement(struct queue_ent *qe)
02037 {
02038 int res = 0;
02039 time_t now;
02040
02041
02042 time(&now);
02043
02044
02045 if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
02046 return 0;
02047
02048
02049 ast_moh_stop(qe->chan);
02050
02051 if (option_verbose > 2)
02052 ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n");
02053
02054
02055 if (qe->last_periodic_announce_sound >= MAX_PERIODIC_ANNOUNCEMENTS || !strlen(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound])) {
02056 qe->last_periodic_announce_sound = 0;
02057 }
02058
02059
02060 res = play_file(qe->chan, qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]);
02061
02062 if ((res > 0 && !valid_exit(qe, res)) || res < 0)
02063 res = 0;
02064
02065
02066 if (!res)
02067 ast_moh_start(qe->chan, qe->moh, NULL);
02068
02069
02070 qe->last_periodic_announce_time = now;
02071
02072
02073 qe->last_periodic_announce_sound++;
02074
02075 return res;
02076 }
02077
02078 static void record_abandoned(struct queue_ent *qe)
02079 {
02080 ast_mutex_lock(&qe->parent->lock);
02081 manager_event(EVENT_FLAG_AGENT, "QueueCallerAbandon",
02082 "Queue: %s\r\n"
02083 "Uniqueid: %s\r\n"
02084 "Position: %d\r\n"
02085 "OriginalPosition: %d\r\n"
02086 "HoldTime: %d\r\n",
02087 qe->parent->name, qe->chan->uniqueid, qe->pos, qe->opos, (int)(time(NULL) - qe->start));
02088
02089 qe->parent->callsabandoned++;
02090 ast_mutex_unlock(&qe->parent->lock);
02091 }
02092
02093
02094 static void rna(int rnatime, struct queue_ent *qe, char *interface, char *membername, int pause)
02095 {
02096 if (option_verbose > 2)
02097 ast_verbose( VERBOSE_PREFIX_3 "Nobody picked up in %d ms\n", rnatime);
02098 ast_queue_log(qe->parent->name, qe->chan->uniqueid, membername, "RINGNOANSWER", "%d", rnatime);
02099 if (qe->parent->autopause && pause) {
02100 if (!set_member_paused(qe->parent->name, interface, 1)) {
02101 if (option_verbose > 2)
02102 ast_verbose( VERBOSE_PREFIX_3 "Auto-Pausing Queue Member %s in queue %s since they failed to answer.\n", interface, qe->parent->name);
02103 } else {
02104 if (option_verbose > 2)
02105 ast_verbose( VERBOSE_PREFIX_3 "Failed to pause Queue Member %s in queue %s!\n", interface, qe->parent->name);
02106 }
02107 }
02108 return;
02109 }
02110
02111 #define AST_MAX_WATCHERS 256
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122 static struct callattempt *wait_for_answer(struct queue_ent *qe, struct callattempt *outgoing, int *to, char *digit, int prebusies, int caller_disconnect, int forwardsallowed)
02123 {
02124 char *queue = qe->parent->name;
02125 struct callattempt *o, *start = NULL, *prev = NULL;
02126 int status;
02127 int numbusies = prebusies;
02128 int numnochan = 0;
02129 int stillgoing = 0;
02130 int orig = *to;
02131 struct ast_frame *f;
02132 struct callattempt *peer = NULL;
02133 struct ast_channel *winner;
02134 struct ast_channel *in = qe->chan;
02135 char on[80] = "";
02136 char membername[80] = "";
02137 long starttime = 0;
02138 long endtime = 0;
02139
02140 starttime = (long) time(NULL);
02141
02142 while (*to && !peer) {
02143 int numlines, retry, pos = 1;
02144 struct ast_channel *watchers[AST_MAX_WATCHERS];
02145 watchers[0] = in;
02146 start = NULL;
02147
02148 for (retry = 0; retry < 2; retry++) {
02149 numlines = 0;
02150 for (o = outgoing; o; o = o->q_next) {
02151 if (o->stillgoing) {
02152 stillgoing = 1;
02153 if (o->chan) {
02154 watchers[pos++] = o->chan;
02155 if (!start)
02156 start = o;
02157 else
02158 prev->call_next = o;
02159 prev = o;
02160 }
02161 }
02162 numlines++;
02163 }
02164 if (pos > 1 || !stillgoing ||
02165 (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) )
02166 break;
02167
02168
02169 ring_one(qe, outgoing, &numbusies);
02170
02171 }
02172 if (pos == 1 ) {
02173 if (numlines == (numbusies + numnochan)) {
02174 ast_log(LOG_DEBUG, "Everyone is busy at this time\n");
02175 } else {
02176 ast_log(LOG_NOTICE, "No one is answering queue '%s' (%d/%d/%d)\n", queue, numlines, numbusies, numnochan);
02177 }
02178 *to = 0;
02179 return NULL;
02180 }
02181 winner = ast_waitfor_n(watchers, pos, to);
02182 for (o = start; o; o = o->call_next) {
02183 if (o->stillgoing && (o->chan) && (o->chan->_state == AST_STATE_UP)) {
02184 if (!peer) {
02185 if (option_verbose > 2)
02186 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02187 peer = o;
02188 }
02189 } else if (o->chan && (o->chan == winner)) {
02190
02191 ast_copy_string(on, o->member->interface, sizeof(on));
02192 ast_copy_string(membername, o->member->membername, sizeof(membername));
02193
02194 if (!ast_strlen_zero(o->chan->call_forward) && !forwardsallowed) {
02195 if (option_verbose > 2)
02196 ast_verbose(VERBOSE_PREFIX_3 "Forwarding %s to '%s' prevented.\n", in->name, o->chan->call_forward);
02197 numnochan++;
02198 do_hang(o);
02199 winner = NULL;
02200 continue;
02201 } else if (!ast_strlen_zero(o->chan->call_forward)) {
02202 char tmpchan[256];
02203 char *stuff;
02204 char *tech;
02205
02206 ast_copy_string(tmpchan, o->chan->call_forward, sizeof(tmpchan));
02207 if ((stuff = strchr(tmpchan, '/'))) {
02208 *stuff++ = '\0';
02209 tech = tmpchan;
02210 } else {
02211 snprintf(tmpchan, sizeof(tmpchan), "%s@%s", o->chan->call_forward, o->chan->context);
02212 stuff = tmpchan;
02213 tech = "Local";
02214 }
02215
02216 if (option_verbose > 2)
02217 ast_verbose(VERBOSE_PREFIX_3 "Now forwarding %s to '%s/%s' (thanks to %s)\n", in->name, tech, stuff, o->chan->name);
02218
02219 o->chan = ast_request(tech, in->nativeformats, stuff, &status);
02220 if (!o->chan) {
02221 ast_log(LOG_NOTICE, "Unable to create local channel for call forward to '%s/%s'\n", tech, stuff);
02222 o->stillgoing = 0;
02223 numnochan++;
02224 } else {
02225 ast_channel_inherit_variables(in, o->chan);
02226 ast_channel_datastore_inherit(in, o->chan);
02227 if (o->chan->cid.cid_num)
02228 free(o->chan->cid.cid_num);
02229 o->chan->cid.cid_num = ast_strdup(in->cid.cid_num);
02230
02231 if (o->chan->cid.cid_name)
02232 free(o->chan->cid.cid_name);
02233 o->chan->cid.cid_name = ast_strdup(in->cid.cid_name);
02234
02235 ast_string_field_set(o->chan, accountcode, in->accountcode);
02236 o->chan->cdrflags = in->cdrflags;
02237
02238 if (in->cid.cid_ani) {
02239 if (o->chan->cid.cid_ani)
02240 free(o->chan->cid.cid_ani);
02241 o->chan->cid.cid_ani = ast_strdup(in->cid.cid_ani);
02242 }
02243 if (o->chan->cid.cid_rdnis)
02244 free(o->chan->cid.cid_rdnis);
02245 o->chan->cid.cid_rdnis = ast_strdup(S_OR(in->macroexten, in->exten));
02246 if (ast_call(o->chan, tmpchan, 0)) {
02247 ast_log(LOG_NOTICE, "Failed to dial on local channel for call forward to '%s'\n", tmpchan);
02248 do_hang(o);
02249 numnochan++;
02250 }
02251 }
02252
02253 ast_hangup(winner);
02254 continue;
02255 }
02256 f = ast_read(winner);
02257 if (f) {
02258 if (f->frametype == AST_FRAME_CONTROL) {
02259 switch (f->subclass) {
02260 case AST_CONTROL_ANSWER:
02261
02262 if (!peer) {
02263 if (option_verbose > 2)
02264 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name);
02265 peer = o;
02266 }
02267 break;
02268 case AST_CONTROL_BUSY:
02269 if (option_verbose > 2)
02270 ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", o->chan->name);
02271 if (in->cdr)
02272 ast_cdr_busy(in->cdr);
02273 do_hang(o);
02274 endtime = (long)time(NULL);
02275 endtime -= starttime;
02276 rna(endtime * 1000, qe, on, membername, 0);
02277 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02278 if (qe->parent->timeoutrestart)
02279 *to = orig;
02280 ring_one(qe, outgoing, &numbusies);
02281 }
02282 numbusies++;
02283 break;
02284 case AST_CONTROL_CONGESTION:
02285 if (option_verbose > 2)
02286 ast_verbose( VERBOSE_PREFIX_3 "%s is circuit-busy\n", o->chan->name);
02287 if (in->cdr)
02288 ast_cdr_busy(in->cdr);
02289 endtime = (long)time(NULL);
02290 endtime -= starttime;
02291 rna(endtime * 1000, qe, on, membername, 0);
02292 do_hang(o);
02293 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02294 if (qe->parent->timeoutrestart)
02295 *to = orig;
02296 ring_one(qe, outgoing, &numbusies);
02297 }
02298 numbusies++;
02299 break;
02300 case AST_CONTROL_RINGING:
02301 if (option_verbose > 2)
02302 ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", o->chan->name);
02303 break;
02304 case AST_CONTROL_OFFHOOK:
02305
02306 break;
02307 default:
02308 ast_log(LOG_DEBUG, "Dunno what to do with control type %d\n", f->subclass);
02309 }
02310 }
02311 ast_frfree(f);
02312 } else {
02313 endtime = (long) time(NULL) - starttime;
02314 rna(endtime * 1000, qe, on, membername, 1);
02315 do_hang(o);
02316 if (qe->parent->strategy != QUEUE_STRATEGY_RINGALL) {
02317 if (qe->parent->timeoutrestart)
02318 *to = orig;
02319 ring_one(qe, outgoing, &numbusies);
02320 }
02321 }
02322 }
02323 }
02324 if (winner == in) {
02325 f = ast_read(in);
02326 if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
02327
02328 *to = -1;
02329 if (f)
02330 ast_frfree(f);
02331 return NULL;
02332 }
02333
02334 if ((f->frametype == AST_FRAME_DTMF) && valid_exit(qe, f->subclass)) {
02335 if (option_verbose > 3)
02336 ast_verbose(VERBOSE_PREFIX_3 "User pressed digit: %c\n", f->subclass);
02337 *to = 0;
02338 *digit = f->subclass;
02339 ast_frfree(f);
02340 return NULL;
02341 }
02342
02343 if ((f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) {
02344 if (option_verbose > 3)
02345 ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass);
02346 *to = 0;
02347 ast_frfree(f);
02348 return NULL;
02349 }
02350 ast_frfree(f);
02351 }
02352 if (!*to) {
02353 for (o = start; o; o = o->call_next)
02354 rna(orig, qe, o->interface, o->member->membername, 1);
02355 }
02356 }
02357
02358 return peer;
02359 }
02360
02361
02362
02363
02364
02365
02366
02367
02368
02369 static int is_our_turn(struct queue_ent *qe)
02370 {
02371 struct queue_ent *ch;
02372 struct member *cur;
02373 int avl = 0;
02374 int idx = 0;
02375 int res;
02376
02377 if (!qe->parent->autofill) {
02378
02379 ch = qe->parent->head;
02380
02381 if (ch == qe) {
02382 if (option_debug)
02383 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02384 res = 1;
02385 } else {
02386 if (option_debug)
02387 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02388 res = 0;
02389 }
02390
02391 } else {
02392
02393 ast_mutex_lock(&qe->parent->lock);
02394
02395 ch = qe->parent->head;
02396
02397 if (qe->parent->strategy == QUEUE_STRATEGY_RINGALL) {
02398 if (option_debug)
02399 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");
02400 avl = 1;
02401 } else {
02402 struct ao2_iterator mem_iter = ao2_iterator_init(qe->parent->members, 0);
02403 while ((cur = ao2_iterator_next(&mem_iter))) {
02404 switch (cur->status) {
02405 case AST_DEVICE_INUSE:
02406 if (!qe->parent->ringinuse)
02407 break;
02408
02409 case AST_DEVICE_NOT_INUSE:
02410 case AST_DEVICE_UNKNOWN:
02411 if (!cur->paused)
02412 avl++;
02413 break;
02414 }
02415 ao2_ref(cur, -1);
02416 }
02417 }
02418
02419 if (option_debug)
02420 ast_log(LOG_DEBUG, "There are %d available members.\n", avl);
02421
02422 while ((idx < avl) && (ch) && (ch != qe)) {
02423 if (!ch->pending)
02424 idx++;
02425 ch = ch->next;
02426 }
02427
02428
02429 if (ch && idx < avl) {
02430 if (option_debug)
02431 ast_log(LOG_DEBUG, "It's our turn (%s).\n", qe->chan->name);
02432 res = 1;
02433 } else {
02434 if (option_debug)
02435 ast_log(LOG_DEBUG, "It's not our turn (%s).\n", qe->chan->name);
02436 res = 0;
02437 }
02438
02439 ast_mutex_unlock(&qe->parent->lock);
02440 }
02441
02442 return res;
02443 }
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454 static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason)
02455 {
02456 int res = 0;
02457
02458
02459 for (;;) {
02460 enum queue_member_status stat;
02461
02462 if (is_our_turn(qe))
02463 break;
02464
02465
02466 if (qe->expire && (time(NULL) >= qe->expire)) {
02467 *reason = QUEUE_TIMEOUT;
02468 break;
02469 }
02470
02471 stat = get_member_status(qe->parent, qe->max_penalty);
02472
02473
02474 if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
02475 *reason = QUEUE_LEAVEEMPTY;
02476 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02477 leave_queue(qe);
02478 break;
02479 }
02480
02481
02482 if ((qe->parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
02483 *reason = QUEUE_LEAVEUNAVAIL;
02484 ast_queue_log(qe->parent->name, qe->chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
02485 leave_queue(qe);
02486 break;
02487 }
02488
02489
02490 if (qe->parent->announcefrequency && !ringing &&
02491 (res = say_position(qe)))
02492 break;
02493
02494
02495 if (qe->expire && (time(NULL) >= qe->expire)) {
02496 *reason = QUEUE_TIMEOUT;
02497 break;
02498 }
02499
02500
02501 if (qe->parent->periodicannouncefrequency && !ringing &&
02502 (res = say_periodic_announcement(qe)))
02503 break;
02504
02505
02506 if (qe->expire && (time(NULL) >= qe->expire)) {
02507 *reason = QUEUE_TIMEOUT;
02508 break;
02509 }
02510
02511
02512 if ((res = ast_waitfordigit(qe->chan, RECHECK * 1000))) {
02513 if (res > 0 && !valid_exit(qe, res))
02514 res = 0;
02515 else
02516 break;
02517 }
02518
02519
02520 if (qe->expire && (time(NULL) >= qe->expire)) {
02521 *reason = QUEUE_TIMEOUT;
02522 break;
02523 }
02524 }
02525
02526 return res;
02527 }
02528
02529 static int update_queue(struct call_queue *q, struct member *member, int callcompletedinsl)
02530 {
02531 ast_mutex_lock(&q->lock);
02532 time(&member->lastcall);
02533 member->calls++;
02534 q->callscompleted++;
02535 if (callcompletedinsl)
02536 q->callscompletedinsl++;
02537 ast_mutex_unlock(&q->lock);
02538 return 0;
02539 }
02540
02541
02542
02543
02544
02545
02546
02547 static int calc_metric(struct call_queue *q, struct member *mem, int pos, struct queue_ent *qe, struct callattempt *tmp)
02548 {
02549 if (qe->max_penalty && (mem->penalty > qe->max_penalty))
02550 return -1;
02551
02552 switch (q->strategy) {
02553 case QUEUE_STRATEGY_RINGALL:
02554
02555 tmp->metric = mem->penalty * 1000000;
02556 break;
02557 case QUEUE_STRATEGY_ROUNDROBIN:
02558 if (!pos) {
02559 if (!q->wrapped) {
02560
02561 q->rrpos = 0;
02562 } else {
02563
02564 q->rrpos++;
02565 }
02566 q->wrapped = 0;
02567 }
02568
02569 case QUEUE_STRATEGY_RRMEMORY:
02570 if (pos < q->rrpos) {
02571 tmp->metric = 1000 + pos;
02572 } else {
02573 if (pos > q->rrpos)
02574
02575 q->wrapped = 1;
02576 tmp->metric = pos;
02577 }
02578 tmp->metric += mem->penalty * 1000000;
02579 break;
02580 case QUEUE_STRATEGY_RANDOM:
02581 tmp->metric = ast_random() % 1000;
02582 tmp->metric += mem->penalty * 1000000;
02583 break;
02584 case QUEUE_STRATEGY_FEWESTCALLS:
02585 tmp->metric = mem->calls;
02586 tmp->metric += mem->penalty * 1000000;
02587 break;
02588 case QUEUE_STRATEGY_LEASTRECENT:
02589 if (!mem->lastcall)
02590 tmp->metric = 0;
02591 else
02592 tmp->metric = 1000000 - (time(NULL) - mem->lastcall);
02593 tmp->metric += mem->penalty * 1000000;
02594 break;
02595 default:
02596 ast_log(LOG_WARNING, "Can't calculate metric for unknown strategy %d\n", q->strategy);
02597 break;
02598 }
02599 if (q->ringlimit && (mem->ringcount >= q->ringlimit)) {
02600 tmp->metric += (mem->ringcount / q->ringlimit) * 10000000;
02601 }
02602 if (option_debug)
02603 ast_log(LOG_DEBUG, "New metric %d for member %s with %d rings (limit %d)\n",
02604 tmp->metric, mem->interface, mem->ringcount, q->ringlimit);
02605 return 0;
02606 }
02607
02608 struct queue_transfer_ds {
02609 struct queue_ent *qe;
02610 struct member *member;
02611 time_t starttime;
02612 int callcompletedinsl;
02613 };
02614
02615 static void queue_transfer_destroy(void *data)
02616 {
02617 struct queue_transfer_ds *qtds = data;
02618 ast_free(qtds);
02619 }
02620
02621
02622
02623 static const struct ast_datastore_info queue_transfer_info = {
02624 .type = "queue_transfer",
02625 .chan_fixup = queue_transfer_fixup,
02626 .destroy = queue_transfer_destroy,
02627 };
02628
02629
02630
02631
02632
02633
02634
02635
02636
02637
02638 static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
02639 {
02640 struct queue_transfer_ds *qtds = data;
02641 struct queue_ent *qe = qtds->qe;
02642 struct member *member = qtds->member;
02643 time_t callstart = qtds->starttime;
02644 int callcompletedinsl = qtds->callcompletedinsl;
02645 struct ast_datastore *datastore;
02646
02647 ast_queue_log(qe->parent->name, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
02648 new_chan->exten, new_chan->context, (long) (callstart - qe->start),
02649 (long) (time(NULL) - callstart));
02650
02651 update_queue(qe->parent, member, callcompletedinsl);
02652
02653
02654 if ((datastore = ast_channel_datastore_find(old_chan, &queue_transfer_info, NULL))) {
02655 ast_channel_datastore_remove(old_chan, datastore);
02656 } else {
02657 ast_log(LOG_WARNING, "Can't find the queue_transfer datastore.\n");
02658 }
02659 }
02660
02661
02662
02663
02664
02665
02666
02667
02668
02669 static int attended_transfer_occurred(struct ast_channel *chan)
02670 {
02671 return ast_channel_datastore_find(chan, &queue_transfer_info, NULL) ? 0 : 1;
02672 }
02673
02674
02675
02676 static struct ast_datastore *setup_transfer_datastore(struct queue_ent *qe, struct member *member, time_t starttime, int callcompletedinsl)
02677 {
02678 struct ast_datastore *ds;
02679 struct queue_transfer_ds *qtds = ast_calloc(1, sizeof(*qtds));
02680
02681 if (!qtds) {
02682 ast_log(LOG_WARNING, "Memory allocation error!\n");
02683 return NULL;
02684 }
02685
02686 ast_channel_lock(qe->chan);
02687 if (!(ds = ast_channel_datastore_alloc(&queue_transfer_info, NULL))) {
02688 ast_channel_unlock(qe->chan);
02689 ast_log(LOG_WARNING, "Unable to create transfer datastore. queue_log will not show attended transfer\n");
02690 return NULL;
02691 }
02692
02693 qtds->qe = qe;
02694
02695 qtds->member = member;
02696 qtds->starttime = starttime;
02697 qtds->callcompletedinsl = callcompletedinsl;
02698 ds->data = qtds;
02699 ast_channel_datastore_add(qe->chan, ds);
02700 ast_channel_unlock(qe->chan);
02701 return ds;
02702 }
02703
02704
02705
02706
02707
02708
02709
02710
02711
02712
02713
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729 static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *tries, int *noption, const char *agi)
02730 {
02731 struct member *cur;
02732 struct callattempt *outgoing = NULL;
02733 int to;
02734 char oldexten[AST_MAX_EXTENSION]="";
02735 char oldcontext[AST_MAX_CONTEXT]="";
02736 char queuename[256]="";
02737 struct ast_channel *peer;
02738 struct ast_channel *which;
02739 struct callattempt *lpeer;
02740 struct member *member;
02741 struct ast_app *app;
02742 int res = 0, bridge = 0;
02743 int numbusies = 0;
02744 int x=0;
02745 char *announce = NULL;
02746 char digit = 0;
02747 time_t callstart;
02748 time_t now = time(NULL);
02749 struct ast_bridge_config bridge_config;
02750 char nondataquality = 1;
02751 char *agiexec = NULL;
02752 int ret = 0;
02753 const char *monitorfilename;
02754 const char *monitor_exec;
02755 const char *monitor_options;
02756 char tmpid[256], tmpid2[256];
02757 char meid[1024], meid2[1024];
02758 char mixmonargs[1512];
02759 struct ast_app *mixmonapp = NULL;
02760 char *p;
02761 char vars[2048];
02762 int forwardsallowed = 1;
02763 int callcompletedinsl;
02764 struct ao2_iterator memi;
02765 struct ast_datastore *datastore, *transfer_ds;
02766
02767 ast_channel_lock(qe->chan);
02768 datastore = ast_channel_datastore_find(qe->chan, &dialed_interface_info, NULL);
02769 ast_channel_unlock(qe->chan);
02770
02771 memset(&bridge_config, 0, sizeof(bridge_config));
02772 time(&now);
02773
02774
02775
02776
02777
02778 if (qe->expire && now >= qe->expire) {
02779 res = 0;
02780 goto out;
02781 }
02782
02783 for (; options && *options; options++)
02784 switch (*options) {
02785 case 't':
02786 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT);
02787 break;
02788 case 'T':
02789 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT);
02790 break;
02791 case 'w':
02792 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_AUTOMON);
02793 break;
02794 case 'W':
02795 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_AUTOMON);
02796 break;
02797 case 'd':
02798 nondataquality = 0;
02799 break;
02800 case 'h':
02801 ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT);
02802 break;
02803 case 'H':
02804 ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT);
02805 break;
02806 case 'n':
02807 if (qe->parent->strategy == QUEUE_STRATEGY_ROUNDROBIN || qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY)
02808 (*tries)++;
02809 else
02810 *tries = qe->parent->membercount;
02811 *noption = 1;
02812 break;
02813 case 'i':
02814 forwardsallowed = 0;
02815 break;
02816 }
02817
02818
02819 if (use_weight)
02820 AST_LIST_LOCK(&queues);
02821 ast_mutex_lock(&qe->parent->lock);
02822 if (option_debug)
02823 ast_log(LOG_DEBUG, "%s is trying to call a queue member.\n",
02824 qe->chan->name);
02825 ast_copy_string(queuename, qe->parent->name, sizeof(queuename));
02826 if (!ast_strlen_zero(qe->announce))
02827 announce = qe->announce;
02828 if (!ast_strlen_zero(announceoverride))
02829 announce = announceoverride;
02830
02831 memi = ao2_iterator_init(qe->parent->members, 0);
02832 while ((cur = ao2_iterator_next(&memi))) {
02833 struct callattempt *tmp = ast_calloc(1, sizeof(*tmp));
02834 struct ast_dialed_interface *di;
02835 AST_LIST_HEAD(, ast_dialed_interface) *dialed_interfaces;
02836 if (!tmp) {
02837 ao2_ref(cur, -1);
02838 ast_mutex_unlock(&qe->parent->lock);
02839 if (use_weight)
02840 AST_LIST_UNLOCK(&queues);
02841 goto out;
02842 }
02843 if (!datastore) {
02844 if (!(datastore = ast_channel_datastore_alloc(&dialed_interface_info, NULL))) {
02845 ao2_ref(cur, -1);
02846 ast_mutex_unlock(&qe->parent->lock);
02847 if (use_weight)
02848 AST_LIST_UNLOCK(&queues);
02849 free(tmp);
02850 goto out;
02851 }
02852 datastore->inheritance = DATASTORE_INHERIT_FOREVER;
02853 if (!(dialed_interfaces = ast_calloc(1, sizeof(*dialed_interfaces)))) {
02854 ao2_ref(cur, -1);
02855 ast_mutex_unlock(&qe->parent->lock);
02856 if (use_weight)
02857 AST_LIST_UNLOCK(&queues);
02858 free(tmp);
02859 goto out;
02860 }
02861 datastore->data = dialed_interfaces;
02862 AST_LIST_HEAD_INIT(dialed_interfaces);
02863
02864 ast_channel_lock(qe->chan);
02865 ast_channel_datastore_add(qe->chan, datastore);
02866 ast_channel_unlock(qe->chan);
02867 } else
02868 dialed_interfaces = datastore->data;
02869
02870 AST_LIST_LOCK(dialed_interfaces);
02871 AST_LIST_TRAVERSE(dialed_interfaces, di, list) {
02872 if (!strcasecmp(cur->interface, di->interface)) {
02873 ast_log(LOG_DEBUG, "Skipping dialing interface '%s' since it has already been dialed\n",
02874 di->interface);
02875 break;
02876 }
02877 }
02878 AST_LIST_UNLOCK(dialed_interfaces);
02879
02880 if (di) {
02881 free(tmp);
02882 continue;
02883 }
02884
02885
02886
02887
02888
02889 if (strncasecmp(cur->interface, "Local/", 6)) {
02890 if (!(di = ast_calloc(1, sizeof(*di) + strlen(cur->interface)))) {
02891 ao2_ref(cur, -1);
02892 ast_mutex_unlock(&qe->parent->lock);
02893 if (use_weight)
02894 AST_LIST_UNLOCK(&queues);
02895 free(tmp);
02896 goto out;
02897 }
02898 strcpy(di->interface, cur->interface);
02899
02900 AST_LIST_LOCK(dialed_interfaces);
02901 AST_LIST_INSERT_TAIL(dialed_interfaces, di, list);
02902 AST_LIST_UNLOCK(dialed_interfaces);
02903 }
02904
02905 tmp->stillgoing = -1;
02906 tmp->member = cur;
02907 tmp->oldstatus = cur->status;
02908 tmp->lastcall = cur->lastcall;
02909 ast_copy_string(tmp->interface, cur->interface, sizeof(tmp->interface));
02910 if (qe->tries == 0 && (cur->ringcount >= qe->parent->ringlimit)) {
02911 cur->ringcount = 0;
02912 }
02913
02914
02915 if (!calc_metric(qe->parent, cur, x++, qe, tmp)) {
02916
02917
02918
02919 tmp->q_next = outgoing;
02920 outgoing = tmp;
02921
02922 if (outgoing->chan && (outgoing->chan->_state == AST_STATE_UP))
02923 break;
02924 } else {
02925 ao2_ref(cur, -1);
02926 free(tmp);
02927 }
02928 }
02929 if (qe->expire && (!qe->parent->timeout || (qe->expire - now) <= qe->parent->timeout))
02930 to = (qe->expire - now) * 1000;
02931 else
02932 to = (qe->parent->timeout) ? qe->parent->timeout * 1000 : -1;
02933 ++qe->pending;
02934 ++qe->tries;
02935 if (option_debug)
02936 ast_log(LOG_DEBUG, "%s is trying to ring one member from %s. This is try number %d\n",
02937 qe->chan->name, queuename, qe->tries);
02938 ast_mutex_unlock(&qe->parent->lock);
02939 ring_one(qe, outgoing, &numbusies);
02940 if (use_weight)
02941 AST_LIST_UNLOCK(&queues);
02942 lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT), forwardsallowed);
02943
02944
02945
02946
02947
02948
02949 ast_channel_lock(qe->chan);
02950 if (datastore && !ast_channel_datastore_remove(qe->chan, datastore)) {
02951 ast_channel_datastore_free(datastore);
02952 }
02953 ast_channel_unlock(qe->chan);
02954 ast_mutex_lock(&qe->parent->lock);
02955 if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) {
02956 store_next(qe, outgoing);
02957 }
02958 ast_mutex_unlock(&qe->parent->lock);
02959 peer = lpeer ? lpeer->chan : NULL;
02960 if (!peer) {
02961 qe->pending = 0;
02962 if (to) {
02963
02964 res = -1;
02965 } else {
02966
02967 res = digit;
02968 }
02969 if (res == -1) {
02970
02971 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_DONT_TOUCH);
02972 ast_cdr_noanswer(qe->chan->cdr);
02973 if (queue_debug)
02974 ast_log(LOG_NOTICE, "%s: Nobody answered.\n", qe->chan->name);
02975 }
02976 if (qe->parent->eventwhencalled) {
02977 manager_event(EVENT_FLAG_AGENT, "AgentTimeout",
02978 "Queue: %s\r\n"
02979 "ChannelCalling: %s\r\n"
02980 "Uniqueid: %s\r\n"
02981 "Tries: %d\r\n"
02982 "Holdtime: %ld\r\n",
02983 queuename, qe->chan->name, qe->chan->uniqueid, qe->tries,
02984 (long)time(NULL) - qe->start);
02985 }
02986 } else {
02987
02988
02989
02990 if (!strcmp(qe->chan->tech->type, "Zap"))
02991 ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02992 if (!strcmp(peer->tech->type, "Zap"))
02993 ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0);
02994
02995 time(&now);
02996 recalc_holdtime(qe, (now - qe->start));
02997 ast_mutex_lock(&qe->parent->lock);
02998 callcompletedinsl = ((now - qe->start) <= qe->parent->servicelevel);
02999 ast_mutex_unlock(&qe->parent->lock);
03000 member = lpeer->member;
03001
03002 ao2_ref(member, 1);
03003 hangupcalls(outgoing, peer);
03004 outgoing = NULL;
03005 if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) {
03006 int res2;
03007
03008 res2 = ast_autoservice_start(qe->chan);
03009 if (!res2) {
03010 if (qe->parent->memberdelay) {
03011 ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
03012 res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
03013 }
03014 if (!res2 && announce) {
03015 play_file(peer, announce);
03016 }
03017 if (!res2 && qe->parent->reportholdtime) {
03018 if (!play_file(peer, qe->parent->sound_reporthold)) {
03019 int holdtime;
03020
03021 time(&now);
03022 holdtime = abs((now - qe->start) / 60);
03023 if (holdtime < 2) {
03024 play_file(peer, qe->parent->sound_lessthan);
03025 ast_say_number(peer, 2, AST_DIGIT_ANY, peer->language, NULL);
03026 } else
03027 ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
03028 play_file(peer, qe->parent->sound_minutes);
03029 }
03030 }
03031 }
03032 res2 |= ast_autoservice_stop(qe->chan);
03033 if (peer->_softhangup) {
03034
03035 ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
03036 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "AGENTDUMP", "%s", "");
03037 if (qe->parent->eventwhencalled)
03038 manager_event(EVENT_FLAG_AGENT, "AgentDump",
03039 "Queue: %s\r\n"
03040 "Uniqueid: %s\r\n"
03041 "Channel: %s\r\n"
03042 "Member: %s\r\n"
03043 "MemberName: %s\r\n"
03044 "%s",
03045 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03046 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03047 ast_hangup(peer);
03048 ao2_ref(member, -1);
03049 goto out;
03050 } else if (res2) {
03051
03052 ast_log(LOG_NOTICE, "Caller was about to talk to agent on %s but the caller hungup.\n", peer->name);
03053 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "ABANDON", "%d|%d|%ld", qe->pos, qe->opos, (long)time(NULL) - qe->start);
03054 record_abandoned(qe);
03055 ast_hangup(peer);
03056 ao2_ref(member, -1);
03057 return -1;
03058 }
03059 }
03060
03061 ast_moh_stop(qe->chan);
03062
03063 if (qe->chan->cdr)
03064 ast_cdr_setdestchan(qe->chan->cdr, peer->name);
03065
03066 res = ast_channel_make_compatible(qe->chan, peer);
03067 if (res < 0) {
03068 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "SYSCOMPAT", "%s", "");
03069 ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", qe->chan->name, peer->name);
03070 record_abandoned(qe);
03071 ast_hangup(peer);
03072 ao2_ref(member, -1);
03073 return -1;
03074 }
03075
03076 if (qe->parent->setinterfacevar)
03077 pbx_builtin_setvar_helper(qe->chan, "MEMBERINTERFACE", member->interface);
03078
03079
03080 if (qe->parent->monfmt && *qe->parent->monfmt) {
03081 if (!qe->parent->montype) {
03082 if (option_debug)
03083 ast_log(LOG_DEBUG, "Starting Monitor as requested.\n");
03084 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
03085 if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS"))
03086 which = qe->chan;
03087 else
03088 which = peer;
03089 if (monitorfilename)
03090 ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
03091 else if (qe->chan->cdr)
03092 ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
03093 else {
03094
03095 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
03096 ast_monitor_start(which, qe->parent->monfmt, tmpid, 1 );
03097 }
03098 if (qe->parent->monjoin)
03099 ast_monitor_setjoinfiles(which, 1);
03100 } else {
03101 if (option_debug)
03102 ast_log(LOG_DEBUG, "Starting MixMonitor as requested.\n");
03103 monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME");
03104 if (!monitorfilename) {
03105 if (qe->chan->cdr)
03106 ast_copy_string(tmpid, qe->chan->cdr->uniqueid, sizeof(tmpid)-1);
03107 else
03108 snprintf(tmpid, sizeof(tmpid), "chan-%lx", ast_random());
03109 } else {
03110 ast_copy_string(tmpid2, monitorfilename, sizeof(tmpid2)-1);
03111 for (p = tmpid2; *p ; p++) {
03112 if (*p == '^' && *(p+1) == '{') {
03113 *p = '$';
03114 }
03115 }
03116
03117 memset(tmpid, 0, sizeof(tmpid));
03118 pbx_substitute_variables_helper(qe->chan, tmpid2, tmpid, sizeof(tmpid) - 1);
03119 }
03120
03121 monitor_exec = pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC");
03122 monitor_options = pbx_builtin_getvar_helper(qe->chan, "MONITOR_OPTIONS");
03123
03124 if (monitor_exec) {
03125 ast_copy_string(meid2, monitor_exec, sizeof(meid2)-1);
03126 for (p = meid2; *p ; p++) {
03127 if (*p == '^' && *(p+1) == '{') {
03128 *p = '$';
03129 }
03130 }
03131
03132 memset(meid, 0, sizeof(meid));
03133 pbx_substitute_variables_helper(qe->chan, meid2, meid, sizeof(meid) - 1);
03134 }
03135
03136 snprintf(tmpid2, sizeof(tmpid2)-1, "%s.%s", tmpid, qe->parent->monfmt);
03137
03138 mixmonapp = pbx_findapp("MixMonitor");
03139
03140 if (strchr(tmpid2, '|')) {
03141 ast_log(LOG_WARNING, "monitor-format (in queues.conf) and MONITOR_FILENAME cannot contain a '|'! Not recording.\n");
03142 mixmonapp = NULL;
03143 }
03144
03145 if (!monitor_options)
03146 monitor_options = "";
03147
03148 if (strchr(monitor_options, '|')) {
03149 ast_log(LOG_WARNING, "MONITOR_OPTIONS cannot contain a '|'! Not recording.\n");
03150 mixmonapp = NULL;
03151 }
03152
03153 if (mixmonapp) {
03154 if (!ast_strlen_zero(monitor_exec))
03155 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s|%s", tmpid2, monitor_options, monitor_exec);
03156 else
03157 snprintf(mixmonargs, sizeof(mixmonargs)-1, "%s|b%s", tmpid2, monitor_options);
03158
03159 if (option_debug)
03160 ast_log(LOG_DEBUG, "Arguments being passed to MixMonitor: %s\n", mixmonargs);
03161
03162 if (qe->chan->cdr)
03163 ast_set_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
03164 ret = pbx_exec(qe->chan, mixmonapp, mixmonargs);
03165 if (qe->chan->cdr)
03166 ast_clear_flag(qe->chan->cdr, AST_CDR_FLAG_LOCKED);
03167
03168 } else
03169 ast_log(LOG_WARNING, "Asked to run MixMonitor on this call, but cannot find the MixMonitor app!\n");
03170
03171 }
03172 }
03173
03174 leave_queue(qe);
03175 if (!ast_strlen_zero(url) && ast_channel_supports_html(peer)) {
03176 if (option_debug)
03177 ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url);
03178 ast_channel_sendurl(peer, url);
03179 }
03180 if (!ast_strlen_zero(agi)) {
03181 if (option_debug)
03182 ast_log(LOG_DEBUG, "app_queue: agi=%s.\n", agi);
03183 app = pbx_findapp("agi");
03184 if (app) {
03185 agiexec = ast_strdupa(agi);
03186 ret = pbx_exec(qe->chan, app, agiexec);
03187 } else
03188 ast_log(LOG_WARNING, "Asked to execute an AGI on this channel, but could not find application (agi)!\n");
03189 }
03190 qe->handled++;
03191 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "CONNECT", "%ld|%s", (long)time(NULL) - qe->start, peer->uniqueid);
03192 if (qe->parent->eventwhencalled)
03193 manager_event(EVENT_FLAG_AGENT, "AgentConnect",
03194 "Queue: %s\r\n"
03195 "Uniqueid: %s\r\n"
03196 "Channel: %s\r\n"
03197 "Member: %s\r\n"
03198 "MemberName: %s\r\n"
03199 "Holdtime: %ld\r\n"
03200 "BridgedChannel: %s\r\n"
03201 "%s",
03202 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03203 (long)time(NULL) - qe->start, peer->uniqueid,
03204 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03205 ast_copy_string(oldcontext, qe->chan->context, sizeof(oldcontext));
03206 ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
03207 time(&callstart);
03208
03209 if (member->status == AST_DEVICE_NOT_INUSE)
03210 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);
03211
03212 transfer_ds = setup_transfer_datastore(qe, member, callstart, callcompletedinsl);
03213 bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
03214
03215 ast_channel_lock(qe->chan);
03216 if (!attended_transfer_occurred(qe->chan)) {
03217 struct ast_datastore *tds;
03218 if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
03219 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "TRANSFER", "%s|%s|%ld|%ld",
03220 qe->chan->exten, qe->chan->context, (long) (callstart - qe->start),
03221 (long) (time(NULL) - callstart));
03222 } else if (qe->chan->_softhangup) {
03223 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETECALLER", "%ld|%ld|%d",
03224 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
03225 if (qe->parent->eventwhencalled)
03226 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03227 "Queue: %s\r\n"
03228 "Uniqueid: %s\r\n"
03229 "Channel: %s\r\n"
03230 "Member: %s\r\n"
03231 "MemberName: %s\r\n"
03232 "HoldTime: %ld\r\n"
03233 "TalkTime: %ld\r\n"
03234 "Reason: caller\r\n"
03235 "%s",
03236 queuename, qe->chan->uniqueid, peer->name, member->interface, member->membername,
03237 (long)(callstart - qe->start), (long)(time(NULL) - callstart),
03238 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03239 } else {
03240 ast_queue_log(queuename, qe->chan->uniqueid, member->membername, "COMPLETEAGENT", "%ld|%ld|%d",
03241 (long) (callstart - qe->start), (long) (time(NULL) - callstart), qe->opos);
03242 if (qe->parent->eventwhencalled)
03243 manager_event(EVENT_FLAG_AGENT, "AgentComplete",
03244 "Queue: %s\r\n"
03245 "Uniqueid: %s\r\n"
03246 "Channel: %s\r\n"
03247 "MemberName: %s\r\n"
03248 "HoldTime: %ld\r\n"
03249 "TalkTime: %ld\r\n"
03250 "Reason: agent\r\n"
03251 "%s",
03252 queuename, qe->chan->uniqueid, peer->name, member->membername, (long)(callstart - qe->start),
03253 (long)(time(NULL) - callstart),
03254 qe->parent->eventwhencalled == QUEUE_EVENT_VARIABLES ? vars2manager(qe->chan, vars, sizeof(vars)) : "");
03255 }
03256 if ((tds = ast_channel_datastore_find(qe->chan, &queue_transfer_info, NULL))) {
03257 ast_channel_datastore_remove(qe->chan, tds);
03258 }
03259 update_queue(qe->parent, member, callcompletedinsl);
03260 }
03261
03262 if (transfer_ds) {
03263 ast_channel_datastore_free(transfer_ds);
03264 }
03265 ast_channel_unlock(qe->chan);
03266 ast_hangup(peer);
03267 res = bridge ? bridge : 1;
03268 ao2_ref(member, -1);
03269 }
03270 out:
03271 hangupcalls(outgoing, NULL);
03272
03273 return res;
03274 }
03275
03276 static int wait_a_bit(struct queue_ent *qe)
03277 {
03278
03279 int retrywait = qe->parent->retry * 1000;
03280
03281 int res = ast_waitfordigit(qe->chan, retrywait);
03282 if (res > 0 && !valid_exit(qe, res))
03283 res = 0;
03284
03285 return res;
03286 }
03287
03288 static struct member *interface_exists(struct call_queue *q, const char *interface)
03289 {
03290 struct member *mem;
03291 struct ao2_iterator mem_iter;
03292
03293 if (!q)
03294 return NULL;
03295
03296 mem_iter = ao2_iterator_init(q->members, 0);
03297 while ((mem = ao2_iterator_next(&mem_iter))) {
03298 if (!strcasecmp(interface, mem->interface))
03299 return mem;
03300 ao2_ref(mem, -1);
03301 }
03302
03303 return NULL;
03304 }
03305
03306
03307
03308
03309
03310
03311
03312 static void dump_queue_members(struct call_queue *pm_queue)
03313 {
03314 struct member *cur_member;
03315 char value[PM_MAX_LEN];
03316 int value_len = 0;
03317 int res;
03318 struct ao2_iterator mem_iter;
03319
03320 memset(value, 0, sizeof(value));
03321
03322 if (!pm_queue)
03323 return;
03324
03325 mem_iter = ao2_iterator_init(pm_queue->members, 0);
03326 while ((cur_member = ao2_iterator_next(&mem_iter))) {
03327 if (!cur_member->dynamic) {
03328 ao2_ref(cur_member, -1);
03329 continue;
03330 }
03331
03332 res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
03333 value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
03334
03335 ao2_ref(cur_member, -1);
03336
03337 if (res != strlen(value + value_len)) {
03338 ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
03339 break;
03340 }
03341 value_len += res;
03342 }
03343
03344 if (value_len && !cur_member) {
03345 if (ast_db_put(pm_family, pm_queue->name, value))
03346 ast_log(LOG_WARNING, "failed to create persistent dynamic entry!\n");
03347 } else
03348
03349 ast_db_del(pm_family, pm_queue->name);
03350 }
03351
03352 static int remove_from_queue(const char *queuename, const char *interface)
03353 {
03354 struct call_queue *q;
03355 struct member *mem, tmpmem;
03356 int res = RES_NOSUCHQUEUE;
03357
03358 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
03359
03360 AST_LIST_LOCK(&queues);
03361 AST_LIST_TRAVERSE(&queues, q, list) {
03362 ast_mutex_lock(&q->lock);
03363 if (strcmp(q->name, queuename)) {
03364 ast_mutex_unlock(&q->lock);
03365 continue;
03366 }
03367
03368 if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
03369
03370 if (!mem->dynamic) {
03371 res = RES_NOT_DYNAMIC;
03372 ao2_ref(mem, -1);
03373 ast_mutex_unlock(&q->lock);
03374 break;
03375 }
03376 q->membercount--;
03377 manager_event(EVENT_FLAG_AGENT, "QueueMemberRemoved",
03378 "Queue: %s\r\n"
03379 "Location: %s\r\n"
03380 "MemberName: %s\r\n",
03381 q->name, mem->interface, mem->membername);
03382 ao2_unlink(q->members, mem);
03383 ao2_ref(mem, -1);
03384
03385 if (queue_persistent_members)
03386 dump_queue_members(q);
03387
03388 res = RES_OKAY;
03389 } else {
03390 res = RES_EXISTS;
03391 }
03392 ast_mutex_unlock(&q->lock);
03393 break;
03394 }
03395
03396 if (res == RES_OKAY)
03397 remove_from_interfaces(interface);
03398
03399 AST_LIST_UNLOCK(&queues);
03400
03401 return res;
03402 }
03403
03404
03405 static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
03406 {
03407 struct call_queue *q;
03408 struct member *new_member, *old_member;
03409 int res = RES_NOSUCHQUEUE;
03410
03411
03412
03413 if (!(q = load_realtime_queue(queuename)))
03414 return res;
03415
03416 AST_LIST_LOCK(&queues);
03417
03418 ast_mutex_lock(&q->lock);
03419 if ((old_member = interface_exists(q, interface)) == NULL) {
03420 add_to_interfaces(interface);
03421 if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
03422 new_member->dynamic = 1;
03423 ao2_link(q->members, new_member);
03424 q->membercount++;
03425 manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
03426 "Queue: %s\r\n"
03427 "Location: %s\r\n"
03428 "MemberName: %s\r\n"
03429 "Membership: %s\r\n"
03430 "Penalty: %d\r\n"
03431 "CallsTaken: %d\r\n"
03432 "LastCall: %d\r\n"
03433 "Status: %d\r\n"
03434 "Paused: %d\r\n",
03435 q->name, new_member->interface, new_member->membername,
03436 "dynamic",
03437 new_member->penalty, new_member->calls, (int) new_member->lastcall,
03438 new_member->status, new_member->paused);
03439
03440 ao2_ref(new_member, -1);
03441 new_member = NULL;
03442
03443 if (dump)
03444 dump_queue_members(q);
03445
03446 res = RES_OKAY;
03447 } else {
03448 res = RES_OUTOFMEMORY;
03449 }
03450 } else {
03451 ao2_ref(old_member, -1);
03452 res = RES_EXISTS;
03453 }
03454 ast_mutex_unlock(&q->lock);
03455 AST_LIST_UNLOCK(&queues);
03456
03457 return res;
03458 }
03459
03460 static int set_member_paused(const char *queuename, const char *interface, int paused)
03461 {
03462 int found = 0;
03463 struct call_queue *q;
03464 struct member *mem;
03465
03466
03467
03468 if (ast_strlen_zero(queuename))
03469 ast_queue_log("NONE", "NONE", interface, (paused ? "PAUSEALL" : "UNPAUSEALL"), "%s", "");
03470
03471 AST_LIST_LOCK(&queues);
03472 AST_LIST_TRAVERSE(&queues, q, list) {
03473 ast_mutex_lock(&q->lock);
03474 if (ast_strlen_zero(queuename) || !strcasecmp(q->name, queuename)) {
03475 if ((mem = interface_exists(q, interface))) {
03476 found++;
03477 if (mem->paused == paused)
03478 ast_log(LOG_DEBUG, "%spausing already-%spaused queue member %s:%s\n", (paused ? "" : "un"), (paused ? "" : "un"), q->name, interface);
03479 mem->paused = paused;
03480
03481 if (queue_persistent_members)
03482 dump_queue_members(q);
03483
03484 if (mem->realtime)
03485 update_realtime_member_field(mem, q->name, "paused", paused ? "1" : "0");
03486
03487 ast_queue_log(q->name, "NONE", mem->membername, (paused ? "PAUSE" : "UNPAUSE"), "%s", "");
03488
03489 manager_event(EVENT_FLAG_AGENT, "QueueMemberPaused",
03490 "Queue: %s\r\n"
03491 "Location: %s\r\n"
03492 "MemberName: %s\r\n"
03493 "Paused: %d\r\n",
03494 q->name, mem->interface, mem->membername, paused);
03495 ao2_ref(mem, -1);
03496 }
03497 }
03498 ast_mutex_unlock(&q->lock);
03499 }
03500 AST_LIST_UNLOCK(&queues);
03501
03502 return found ? RESULT_SUCCESS : RESULT_FAILURE;
03503 }
03504
03505
03506 static void reload_queue_members(void)
03507 {
03508 char *cur_ptr;
03509 char *queue_name;
03510 char *member;
03511 char *interface;
03512 char *membername = NULL;
03513 char *penalty_tok;
03514 int penalty = 0;
03515 char *paused_tok;
03516 int paused = 0;
03517 struct ast_db_entry *db_tree;
03518 struct ast_db_entry *entry;
03519 struct call_queue *cur_queue;
03520 char queue_data[PM_MAX_LEN];
03521
03522 AST_LIST_LOCK(&queues);
03523
03524
03525 db_tree = ast_db_gettree(pm_family, NULL);
03526 for (entry = db_tree; entry; entry = entry->next) {
03527
03528 queue_name = entry->key + strlen(pm_family) + 2;
03529
03530 AST_LIST_TRAVERSE(&queues, cur_queue, list) {
03531 ast_mutex_lock(&cur_queue->lock);
03532 if (!strcmp(queue_name, cur_queue->name))
03533 break;
03534 ast_mutex_unlock(&cur_queue->lock);
03535 }
03536
03537 if (!cur_queue)
03538 cur_queue = load_realtime_queue(queue_name);
03539
03540 if (!cur_queue) {
03541
03542
03543 ast_log(LOG_WARNING, "Error loading persistent queue: '%s': it does not exist\n", queue_name);
03544 ast_db_del(pm_family, queue_name);
03545 continue;
03546 } else
03547 ast_mutex_unlock(&cur_queue->lock);
03548
03549 if (ast_db_get(pm_family, queue_name, queue_data, PM_MAX_LEN))
03550 continue;
03551
03552 cur_ptr = queue_data;
03553 while ((member = strsep(&cur_ptr, "|"))) {
03554 if (ast_strlen_zero(member))
03555 continue;
03556
03557 interface = strsep(&member, ";");
03558 penalty_tok = strsep(&member, ";");
03559 paused_tok = strsep(&member, ";");
03560 membername = strsep(&member, ";");
03561
03562 if (!penalty_tok) {
03563 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
03564 break;
03565 }
03566 penalty = strtol(penalty_tok, NULL, 10);
03567 if (errno == ERANGE) {
03568 ast_log(LOG_WARNING, "Error converting penalty: %s: Out of range.\n", penalty_tok);
03569 break;
03570 }
03571
03572 if (!paused_tok) {
03573 ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (paused)\n", queue_name);
03574 break;
03575 }
03576 paused = strtol(paused_tok, NULL, 10);
03577 if ((errno == ERANGE) || paused < 0 || paused > 1) {
03578 ast_log(LOG_WARNING, "Error converting paused: %s: Expected 0 or 1.\n", paused_tok);
03579 break;
03580 }
03581 if (ast_strlen_zero(membername))
03582 membername = interface;
03583
03584 if (option_debug)
03585 ast_log(LOG_DEBUG, "Reload Members: Queue: %s Member: %s Name: %s Penalty: %d Paused: %d\n", queue_name, interface, membername, penalty, paused);
03586
03587 if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
03588 ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
03589 break;
03590 }
03591 }
03592 }
03593
03594 AST_LIST_UNLOCK(&queues);
03595 if (db_tree) {
03596 ast_log(LOG_NOTICE, "Queue members successfully reloaded from database.\n");
03597 ast_db_freetree(db_tree);
03598 }
03599 }
03600
03601 static int pqm_exec(struct ast_channel *chan, void *data)
03602 {
03603 struct ast_module_user *lu;
03604 char *parse;
03605 int priority_jump = 0;
03606 int ignore_fail = 0;
03607 AST_DECLARE_APP_ARGS(args,
03608 AST_APP_ARG(queuename);
03609 AST_APP_ARG(interface);
03610 AST_APP_ARG(options);
03611 );
03612
03613 if (ast_strlen_zero(data)) {
03614 ast_log(LOG_WARNING, "PauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03615 return -1;
03616 }
03617
03618 parse = ast_strdupa(data);
03619
03620 AST_STANDARD_APP_ARGS(args, parse);
03621
03622 lu = ast_module_user_add(chan);
03623
03624 if (args.options) {
03625 if (strchr(args.options, 'j'))
03626 priority_jump = 1;
03627 if (strchr(args.options, 'i'))
03628 ignore_fail = 1;
03629 }
03630
03631 if (ast_strlen_zero(args.interface)) {
03632 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03633 ast_module_user_remove(lu);
03634 return -1;
03635 }
03636
03637 if (set_member_paused(args.queuename, args.interface, 1)) {
03638 ast_log(LOG_WARNING, "Attempt to pause interface %s, not found\n", args.interface);
03639 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "NOTFOUND");
03640 if (priority_jump || ast_opt_priority_jumping) {
03641 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03642 ast_module_user_remove(lu);
03643 return 0;
03644 }
03645 }
03646 ast_module_user_remove(lu);
03647 if (ignore_fail) {
03648 return 0;
03649 } else {
03650 return -1;
03651 }
03652 }
03653
03654 ast_module_user_remove(lu);
03655 pbx_builtin_setvar_helper(chan, "PQMSTATUS", "PAUSED");
03656 return 0;
03657 }
03658
03659 static int upqm_exec(struct ast_channel *chan, void *data)
03660 {
03661 struct ast_module_user *lu;
03662 char *parse;
03663 int priority_jump = 0;
03664 int ignore_fail = 0;
03665 AST_DECLARE_APP_ARGS(args,
03666 AST_APP_ARG(queuename);
03667 AST_APP_ARG(interface);
03668 AST_APP_ARG(options);
03669 );
03670
03671 if (ast_strlen_zero(data)) {
03672 ast_log(LOG_WARNING, "UnpauseQueueMember requires an argument ([queuename]|interface[|options])\n");
03673 return -1;
03674 }
03675
03676 parse = ast_strdupa(data);
03677
03678 AST_STANDARD_APP_ARGS(args, parse);
03679
03680 lu = ast_module_user_add(chan);
03681
03682 if (args.options) {
03683 if (strchr(args.options, 'j'))
03684 priority_jump = 1;
03685 if (strchr(args.options, 'i'))
03686 ignore_fail = 1;
03687 }
03688
03689 if (ast_strlen_zero(args.interface)) {
03690 ast_log(LOG_WARNING, "Missing interface argument to PauseQueueMember ([queuename]|interface[|options])\n");
03691 ast_module_user_remove(lu);
03692 return -1;
03693 }
03694
03695 if (set_member_paused(args.queuename, args.interface, 0)) {
03696 ast_log(LOG_WARNING, "Attempt to unpause interface %s, not found\n", args.interface);
03697 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "NOTFOUND");
03698 if (priority_jump || ast_opt_priority_jumping) {
03699 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
03700 ast_module_user_remove(lu);
03701 return 0;
03702 }
03703 }
03704 ast_module_user_remove(lu);
03705 if (ignore_fail) {
03706 return 0;
03707 } else {
03708 return -1;
03709 }
03710 }
03711
03712 ast_module_user_remove(lu);
03713 pbx_builtin_setvar_helper(chan, "UPQMSTATUS", "UNPAUSED");
03714 return 0;
03715 }
03716
03717 static int rqm_exec(struct ast_channel *chan, void *data)
03718 {
03719 int res=-1;
03720 struct ast_module_user *lu;
03721 char *parse, *temppos = NULL;
03722 int priority_jump = 0;
03723 AST_DECLARE_APP_ARGS(args,
03724 AST_APP_ARG(queuename);
03725 AST_APP_ARG(interface);
03726 AST_APP_ARG(options);
03727 );
03728
03729
03730 if (ast_strlen_zero(data)) {
03731 ast_log(LOG_WARNING, "RemoveQueueMember requires an argument (queuename[|interface[|options]])\n");
03732 return -1;
03733 }
03734
03735 parse = ast_strdupa(data);
03736
03737 AST_STANDARD_APP_ARGS(args, parse);
03738
03739 lu = ast_module_user_add(chan);
03740
03741 if (ast_strlen_zero(args.interface)) {
03742 args.interface = ast_strdupa(chan->name);
03743 temppos = strrchr(args.interface, '-');
03744 if (temppos)
03745 *temppos = '\0';
03746 }
03747
03748 if (args.options) {
03749 if (strchr(args.options, 'j'))
03750 priority_jump = 1;
03751 }
03752
03753 switch (remove_from_queue(args.queuename, args.interface)) {
03754 case RES_OKAY:
03755 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "REMOVEMEMBER", "%s", "");
03756 ast_log(LOG_NOTICE, "Removed interface '%s' from queue '%s'\n", args.interface, args.queuename);
03757 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "REMOVED");
03758 res = 0;
03759 break;
03760 case RES_EXISTS:
03761 ast_log(LOG_DEBUG, "Unable to remove interface '%s' from queue '%s': Not there\n", args.interface, args.queuename);
03762 if (priority_jump || ast_opt_priority_jumping)
03763 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03764 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTINQUEUE");
03765 res = 0;
03766 break;
03767 case RES_NOSUCHQUEUE:
03768 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': No such queue\n", args.queuename);
03769 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOSUCHQUEUE");
03770 res = 0;
03771 break;
03772 case RES_NOT_DYNAMIC:
03773 ast_log(LOG_WARNING, "Unable to remove interface from queue '%s': '%s' is not a dynamic member\n", args.queuename, args.interface);
03774 pbx_builtin_setvar_helper(chan, "RQMSTATUS", "NOTDYNAMIC");
03775 res = 0;
03776 break;
03777 }
03778
03779 ast_module_user_remove(lu);
03780
03781 return res;
03782 }
03783
03784 static int aqm_exec(struct ast_channel *chan, void *data)
03785 {
03786 int res=-1;
03787 struct ast_module_user *lu;
03788 char *parse, *temppos = NULL;
03789 int priority_jump = 0;
03790 AST_DECLARE_APP_ARGS(args,
03791 AST_APP_ARG(queuename);
03792 AST_APP_ARG(interface);
03793 AST_APP_ARG(penalty);
03794 AST_APP_ARG(options);
03795 AST_APP_ARG(membername);
03796 );
03797 int penalty = 0;
03798
03799 if (ast_strlen_zero(data)) {
03800 ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
03801 return -1;
03802 }
03803
03804 parse = ast_strdupa(data);
03805
03806 AST_STANDARD_APP_ARGS(args, parse);
03807
03808 lu = ast_module_user_add(chan);
03809
03810 if (ast_strlen_zero(args.interface)) {
03811 args.interface = ast_strdupa(chan->name);
03812 temppos = strrchr(args.interface, '-');
03813 if (temppos)
03814 *temppos = '\0';
03815 }
03816
03817 if (!ast_strlen_zero(args.penalty)) {
03818 if ((sscanf(args.penalty, "%d", &penalty) != 1) || penalty < 0) {
03819 ast_log(LOG_WARNING, "Penalty '%s' is invalid, must be an integer >= 0\n", args.penalty);
03820 penalty = 0;
03821 }
03822 }
03823
03824 if (args.options) {
03825 if (strchr(args.options, 'j'))
03826 priority_jump = 1;
03827 }
03828
03829 switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
03830 case RES_OKAY:
03831 ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
03832 ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
03833 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
03834 res = 0;
03835 break;
03836 case RES_EXISTS:
03837 ast_log(LOG_WARNING, "Unable to add interface '%s' to queue '%s': Already there\n", args.interface, args.queuename);
03838 if (priority_jump || ast_opt_priority_jumping)
03839 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
03840 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "MEMBERALREADY");
03841 res = 0;
03842 break;
03843 case RES_NOSUCHQUEUE:
03844 ast_log(LOG_WARNING, "Unable to add interface to queue '%s': No such queue\n", args.queuename);
03845 pbx_builtin_setvar_helper(chan, "AQMSTATUS", "NOSUCHQUEUE");
03846 res = 0;
03847 break;
03848 case RES_OUTOFMEMORY:
03849 ast_log(LOG_ERROR, "Out of memory adding member %s to queue %s\n", args.interface, args.queuename);
03850 break;
03851 }
03852
03853 ast_module_user_remove(lu);
03854
03855 return res;
03856 }
03857
03858 static int ql_exec(struct ast_channel *chan, void *data)
03859 {
03860 struct ast_module_user *u;
03861 char *parse;
03862
03863 AST_DECLARE_APP_ARGS(args,
03864 AST_APP_ARG(queuename);
03865 AST_APP_ARG(uniqueid);
03866 AST_APP_ARG(membername);
03867 AST_APP_ARG(event);
03868 AST_APP_ARG(params);
03869 );
03870
03871 if (ast_strlen_zero(data)) {
03872 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo]\n");
03873 return -1;
03874 }
03875
03876 u = ast_module_user_add(chan);
03877
03878 parse = ast_strdupa(data);
03879
03880 AST_STANDARD_APP_ARGS(args, parse);
03881
03882 if (ast_strlen_zero(args.queuename) || ast_strlen_zero(args.uniqueid)
03883 || ast_strlen_zero(args.membername) || ast_strlen_zero(args.event)) {
03884 ast_log(LOG_WARNING, "QueueLog requires arguments (queuename|uniqueid|membername|event[|additionalinfo])\n");
03885 ast_module_user_remove(u);
03886 return -1;
03887 }
03888
03889 ast_queue_log(args.queuename, args.uniqueid, args.membername, args.event,
03890 "%s", args.params ? args.params : "");
03891
03892 ast_module_user_remove(u);
03893
03894 return 0;
03895 }
03896
03897
03898
03899
03900
03901
03902
03903
03904
03905
03906
03907
03908
03909 static int queue_exec(struct ast_channel *chan, void *data)
03910 {
03911 int res=-1;
03912 int ringing=0;
03913 struct ast_module_user *lu;
03914 const char *user_priority;
03915 const char *max_penalty_str;
03916 int prio;
03917 int max_penalty;
03918 enum queue_result reason = QUEUE_UNKNOWN;
03919
03920 int tries = 0;
03921 int noption = 0;
03922 char *parse;
03923 AST_DECLARE_APP_ARGS(args,
03924 AST_APP_ARG(queuename);
03925 AST_APP_ARG(options);
03926 AST_APP_ARG(url);
03927 AST_APP_ARG(announceoverride);
03928 AST_APP_ARG(queuetimeoutstr);
03929 AST_APP_ARG(agi);
03930 );
03931
03932 struct queue_ent qe;
03933
03934 if (ast_strlen_zero(data)) {
03935 ast_log(LOG_WARNING, "Queue requires an argument: queuename[|options[|URL[|announceoverride[|timeout[|agi]]]]]\n");
03936 return -1;
03937 }
03938
03939 parse = ast_strdupa(data);
03940 AST_STANDARD_APP_ARGS(args, parse);
03941
03942 lu = ast_module_user_add(chan);
03943
03944
03945 memset(&qe, 0, sizeof(qe));
03946 qe.start = time(NULL);
03947
03948
03949 if (!ast_strlen_zero(args.queuetimeoutstr))
03950 qe.expire = qe.start + atoi(args.queuetimeoutstr);
03951 else
03952 qe.expire = 0;
03953
03954
03955 user_priority = pbx_builtin_getvar_helper(chan, "QUEUE_PRIO");
03956 if (user_priority) {
03957 if (sscanf(user_priority, "%d", &prio) == 1) {
03958 if (option_debug)
03959 ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n",
03960 chan->name, prio);
03961 } else {
03962 ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n",
03963 user_priority, chan->name);
03964 prio = 0;
03965 }
03966 } else {
03967 if (option_debug > 2)
03968 ast_log(LOG_DEBUG, "NO QUEUE_PRIO variable found. Using default.\n");
03969 prio = 0;
03970 }
03971
03972
03973 if ((max_penalty_str = pbx_builtin_getvar_helper(chan, "QUEUE_MAX_PENALTY"))) {
03974 if (sscanf(max_penalty_str, "%d", &max_penalty) == 1) {
03975 if (option_debug)
03976 ast_log(LOG_DEBUG, "%s: Got max penalty %d from ${QUEUE_MAX_PENALTY}.\n",
03977 chan->name, max_penalty);
03978 } else {
03979 ast_log(LOG_WARNING, "${QUEUE_MAX_PENALTY}: Invalid value (%s), channel %s.\n",
03980 max_penalty_str, chan->name);
03981 max_penalty = 0;
03982 }
03983 } else {
03984 max_penalty = 0;
03985 }
03986
03987 if (args.options && (strchr(args.options, 'r')))
03988 ringing = 1;
03989
03990 if (option_debug)
03991 ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n",
03992 args.queuename, args.options, args.url, args.announceoverride, (long)qe.expire, prio);
03993
03994 qe.chan = chan;
03995 qe.prio = prio;
03996 qe.max_penalty = max_penalty;
03997 qe.last_pos_said = 0;
03998 qe.last_pos = 0;
03999 qe.last_periodic_announce_time = time(NULL);
04000 qe.last_periodic_announce_sound = 0;
04001 qe.valid_digits = 0;
04002 if (!join_queue(args.queuename, &qe, &reason)) {
04003 int makeannouncement = 0;
04004
04005 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", S_OR(args.url, ""),
04006 S_OR(chan->cid.cid_num, ""));
04007 check_turns:
04008 if (ringing) {
04009 ast_indicate(chan, AST_CONTROL_RINGING);
04010 } else {
04011 ast_moh_start(chan, qe.moh, NULL);
04012 }
04013
04014
04015 res = wait_our_turn(&qe, ringing, &reason);
04016 if (res)
04017 goto stop;
04018
04019 for (;;) {
04020
04021
04022
04023
04024
04025 enum queue_member_status stat;
04026
04027
04028 if (qe.expire && (time(NULL) >= qe.expire)) {
04029 record_abandoned(&qe);
04030 reason = QUEUE_TIMEOUT;
04031 res = 0;
04032 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04033 break;
04034 }
04035
04036 if (makeannouncement) {
04037
04038 if (qe.parent->announcefrequency && !ringing)
04039 if ((res = say_position(&qe)))
04040 goto stop;
04041
04042 }
04043 makeannouncement = 1;
04044
04045
04046 if (qe.expire && (time(NULL) >= qe.expire)) {
04047 record_abandoned(&qe);
04048 reason = QUEUE_TIMEOUT;
04049 res = 0;
04050 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04051 break;
04052 }
04053
04054 if (qe.parent->periodicannouncefrequency && !ringing)
04055 if ((res = say_periodic_announcement(&qe)))
04056 goto stop;
04057
04058
04059 if (qe.expire && (time(NULL) >= qe.expire)) {
04060 record_abandoned(&qe);
04061 reason = QUEUE_TIMEOUT;
04062 res = 0;
04063 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04064 break;
04065 }
04066
04067 res = try_calling(&qe, args.options, args.announceoverride, args.url, &tries, &noption, args.agi);
04068 if (res)
04069 goto stop;
04070
04071 stat = get_member_status(qe.parent, qe.max_penalty);
04072
04073
04074 if (noption && tries >= qe.parent->membercount) {
04075 if (option_verbose > 2)
04076 ast_verbose(VERBOSE_PREFIX_3 "Exiting on time-out cycle\n");
04077 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04078 record_abandoned(&qe);
04079 reason = QUEUE_TIMEOUT;
04080 res = 0;
04081 break;
04082 }
04083
04084
04085 if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) {
04086 record_abandoned(&qe);
04087 reason = QUEUE_LEAVEEMPTY;
04088 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04089 res = 0;
04090 break;
04091 }
04092
04093
04094 if ((qe.parent->leavewhenempty == QUEUE_EMPTY_STRICT) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) {
04095 record_abandoned(&qe);
04096 reason = QUEUE_LEAVEUNAVAIL;
04097 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITEMPTY", "%d|%d|%ld", qe.pos, qe.opos, (long)(time(NULL) - qe.start));
04098 res = 0;
04099 break;
04100 }
04101
04102
04103 if (qe.expire && (time(NULL) >= qe.expire)) {
04104 record_abandoned(&qe);
04105 reason = QUEUE_TIMEOUT;
04106 res = 0;
04107 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos);
04108 break;
04109 }
04110
04111
04112 update_realtime_members(qe.parent);
04113
04114
04115 res = wait_a_bit(&qe);
04116 if (res)
04117 goto stop;
04118
04119
04120
04121
04122
04123 if (!is_our_turn(&qe)) {
04124 if (option_debug)
04125 ast_log(LOG_DEBUG, "Darn priorities, going back in queue (%s)!\n",
04126 qe.chan->name);
04127 goto check_turns;
04128 }
04129 }
04130
04131 stop:
04132 if (res) {
04133 if (res < 0) {
04134 if (!qe.handled) {
04135 record_abandoned(&qe);
04136 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "ABANDON",
04137 "%d|%d|%ld", qe.pos, qe.opos,
04138 (long) time(NULL) - qe.start);
04139 }
04140 res = -1;
04141 } else if (qe.valid_digits) {
04142 ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
04143 "%s|%d", qe.digits, qe.pos);
04144 }
04145 }
04146
04147
04148 if (res >= 0) {
04149 res = 0;
04150 if (ringing) {
04151 ast_indicate(chan, -1);
04152 } else {
04153 ast_moh_stop(chan);
04154 }
04155 ast_stopstream(chan);
04156 }
04157 leave_queue(&qe);
04158 if (reason != QUEUE_UNKNOWN)
04159 set_queue_result(chan, reason);
04160 } else {
04161 ast_log(LOG_WARNING, "Unable to join queue '%s'\n", args.queuename);
04162 set_queue_result(chan, reason);
04163 res = 0;
04164 }
04165 ast_module_user_remove(lu);
04166
04167 return res;
04168 }
04169
04170 enum qmc_status {
04171 QMC_VALID = 0,
04172 QMC_PAUSED,
04173 QMC_ACTIVE,
04174 QMC_FREE,
04175 QMC_ALL
04176 };
04177
04178 static int queue_function_queuemembercount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
04179 {
04180 int count = 0;
04181 struct call_queue *q;
04182 struct ast_module_user *lu;
04183 struct member *m;
04184 struct ao2_iterator mem_iter;
04185 char *name, *item;
04186 enum qmc_status mode = QMC_VALID;
04187
04188 buf[0] = '\0';
04189
04190 if (ast_strlen_zero(data)) {
04191 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04192 return -1;
04193 }
04194
04195 name = ast_strdupa(data);
04196
04197 lu = ast_module_user_add(chan);
04198
04199 if ((item = strchr(name, ':'))) {
04200 *item = '\0';
04201 item++;
04202 } else {
04203 item = "";
04204 }
04205
04206 if (!strcasecmp(item, "valid")) {
04207 mode = QMC_VALID;
04208 } else if (!strcasecmp(item, "paused")) {
04209 mode = QMC_PAUSED;
04210 } else if (!strcasecmp(item, "active")) {
04211 mode = QMC_ACTIVE;
04212 } else if (!strcasecmp(item, "free")) {
04213 mode = QMC_FREE;
04214 } else if (!strcasecmp(item, "all")) {
04215 mode = QMC_ALL;
04216 }
04217
04218 if ((q = load_realtime_queue(name))) {
04219 ast_mutex_lock(&q->lock);
04220 mem_iter = ao2_iterator_init(q->members, 0);
04221 while ((m = ao2_iterator_next(&mem_iter))) {
04222 switch (mode) {
04223 case QMC_VALID:
04224
04225 if ((m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04226 count++;
04227 }
04228 break;
04229 case QMC_PAUSED:
04230
04231 if (m->paused) {
04232 count++;
04233 }
04234 break;
04235 case QMC_ACTIVE:
04236
04237 if (!m->paused && (m->status != AST_DEVICE_UNAVAILABLE) && (m->status != AST_DEVICE_INVALID)) {
04238 count++;
04239 }
04240 break;
04241 case QMC_FREE:
04242
04243 if (!m->paused && ((m->status == AST_DEVICE_UNKNOWN) || (m->status == AST_DEVICE_NOT_INUSE))) {
04244 count++;
04245 }
04246 break;
04247 default:
04248 count++;
04249 break;
04250 }
04251 ao2_ref(m, -1);
04252 }
04253 ast_mutex_unlock(&q->lock);
04254 } else
04255 ast_log(LOG_WARNING, "queue %s was not found\n", name);
04256
04257 snprintf(buf, len, "%d", count);
04258 ast_module_user_remove(lu);
04259
04260 return 0;
04261 }
04262
04263 static int queue_function_queuewaitingcount(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
04264 {
04265 int count = 0;
04266 struct call_queue *q;
04267 struct ast_module_user *lu;
04268 struct ast_variable *var = NULL;
04269
04270 buf[0] = '\0';
04271
04272 if (ast_strlen_zero(data)) {
04273 ast_log(LOG_ERROR, "%s requires an argument: queuename\n", cmd);
04274 return -1;
04275 }
04276
04277 lu = ast_module_user_add(chan);
04278
04279 AST_LIST_LOCK(&queues);
04280 AST_LIST_TRAVERSE(&queues, q, list) {
04281 if (!strcasecmp(q->name, data)) {
04282 ast_mutex_lock(&q->lock);
04283 break;
04284 }
04285 }
04286 AST_LIST_UNLOCK(&queues);
04287
04288 if (q) {
04289 count = q->count;
04290 ast_mutex_unlock(&q->lock);
04291 } else if ((var = ast_load_realtime("queues", "name", data, NULL))) {
04292
04293
04294
04295
04296 count = 0;
04297 ast_variables_destroy(var);
04298 } else
04299 ast_log(LOG_WARNING, "queue %s was not found\n", data);
04300
04301 snprintf(buf, len, "%d", count);
04302 ast_module_user_remove(lu);
04303 return 0;
04304 }
04305
04306 static int queue_function_queuememberlist(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
04307 {
04308 struct ast_module_user *u;
04309 struct call_queue *q;
04310 struct member *m;
04311
04312
04313 buf[0] = '\0';
04314
04315 if (ast_strlen_zero(data)) {
04316 ast_log(LOG_ERROR, "QUEUE_MEMBER_LIST requires an argument: queuename\n");
04317 return -1;
04318 }
04319
04320 u = ast_module_user_add(chan);
04321
04322 AST_LIST_LOCK(&queues);
04323 AST_LIST_TRAVERSE(&queues, q, list) {
04324 if (!strcasecmp(q->name, data)) {
04325 ast_mutex_lock(&q->lock);
04326 break;
04327 }
04328 }
04329 AST_LIST_UNLOCK(&queues);
04330
04331 if (q) {
04332 int buflen = 0, count = 0;
04333 struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
04334
04335 while ((m = ao2_iterator_next(&mem_iter))) {
04336
04337 if (count++) {
04338 strncat(buf + buflen, ",", len - buflen - 1);
04339 buflen++;
04340 }
04341 strncat(buf + buflen, m->membername, len - buflen - 1);
04342 buflen += strlen(m->membername);
04343
04344 if (buflen >= len - 2) {
04345 ao2_ref(m, -1);
04346 ast_log(LOG_WARNING, "Truncating list\n");
04347 break;
04348 }
04349 ao2_ref(m, -1);
04350 }
04351 ast_mutex_unlock(&q->lock);
04352 } else
04353 ast_log(LOG_WARNING, "queue %s was not found\n", data);
04354
04355
04356 buf[len - 1] = '\0';
04357 ast_module_user_remove(u);
04358
04359 return 0;
04360 }
04361
04362 static struct ast_custom_function queueagentcount_function = {
04363 .name = "QUEUEAGENTCOUNT",
04364 .synopsis = "Count number of agents answering a queue",
04365 .syntax = "QUEUEAGENTCOUNT(<queuename>)",
04366 .desc =
04367 "Returns the number of members currently associated with the specified queue.\n"
04368 "This function is deprecated. You should use QUEUE_MEMBER_COUNT() instead.\n",
04369 .read = queue_function_queuemembercount,
04370 };
04371
04372 static struct ast_custom_function queuemembercount_function = {
04373 .name = "QUEUE_MEMBER_COUNT",
04374 .synopsis = "Count number of members answering a queue",
04375 .syntax = "QUEUE_MEMBER_COUNT(<queuename>[:mode])",
04376 .desc =
04377 "Returns the number of members currently associated with the specified queue.\n"
04378 "Valid mode values are:\n"
04379 "- valid (default) Members anwering the queue.\n"
04380 "- paused Paused members.\n"
04381 "- active Active members(ie. valid and not paused).\n"
04382 "- free Active members not in use.\n"
04383 "- all All members defined in queue.\n",
04384 .read = queue_function_queuemembercount,
04385 };
04386
04387 static struct ast_custom_function queuewaitingcount_function = {
04388 .name = "QUEUE_WAITING_COUNT",
04389 .synopsis = "Count number of calls currently waiting in a queue",
04390 .syntax = "QUEUE_WAITING_COUNT(<queuename>)",
04391 .desc =
04392 "Returns the number of callers currently waiting in the specified queue.\n",
04393 .read = queue_function_queuewaitingcount,
04394 };
04395
04396 static struct ast_custom_function queuememberlist_function = {
04397 .name = "QUEUE_MEMBER_LIST",
04398 .synopsis = "Returns a list of interfaces on a queue",
04399 .syntax = "QUEUE_MEMBER_LIST(<queuename>)",
04400 .desc =
04401 "Returns a comma-separated list of members associated with the specified queue.\n",
04402 .read = queue_function_queuememberlist,
04403 };
04404
04405 static int reload_queues(void)
04406 {
04407 struct call_queue *q;
04408 struct ast_config *cfg;
04409 char *cat, *tmp;
04410 struct ast_variable *var;
04411 struct member *cur, *newm;
04412 struct ao2_iterator mem_iter;
04413 int new;
04414 const char *general_val = NULL;
04415 char parse[80];
04416 char *interface;
04417 char *membername = NULL;
04418 int penalty;
04419 AST_DECLARE_APP_ARGS(args,
04420 AST_APP_ARG(interface);
04421 AST_APP_ARG(penalty);
04422 AST_APP_ARG(membername);
04423 );
04424
04425 if (!(cfg = ast_config_load("queues.conf"))) {
04426 ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
04427 return 0;
04428 }
04429 AST_LIST_LOCK(&queues);
04430 use_weight=0;
04431
04432 AST_LIST_TRAVERSE(&queues, q, list) {
04433 if (!q->realtime) {
04434 q->dead = 1;
04435 q->found = 0;
04436 }
04437 }
04438
04439
04440 cat = NULL;
04441 while ((cat = ast_category_browse(cfg, cat)) ) {
04442 if (!strcasecmp(cat, "general")) {
04443
04444 queue_debug = 0;
04445 if ((general_val = ast_variable_retrieve(cfg, "general", "debug")))
04446 queue_debug = ast_true(general_val);
04447 queue_persistent_members = 0;
04448 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentmembers")))
04449 queue_persistent_members = ast_true(general_val);
04450 autofill_default = 0;
04451 if ((general_val = ast_variable_retrieve(cfg, "general", "autofill")))
04452 autofill_default = ast_true(general_val);
04453 montype_default = 0;
04454 if ((general_val = ast_variable_retrieve(cfg, "general", "monitor-type")))
04455 if (!strcasecmp(general_val, "mixmonitor"))
04456 montype_default = 1;
04457 } else {
04458
04459 AST_LIST_TRAVERSE(&queues, q, list) {
04460 if (!strcmp(q->name, cat))
04461 break;
04462 }
04463 if (!q) {
04464
04465 if (!(q = alloc_queue(cat))) {
04466
04467 }
04468 new = 1;
04469 } else
04470 new = 0;
04471 if (q) {
04472 if (!new)
04473 ast_mutex_lock(&q->lock);
04474
04475 if (q->found) {
04476 ast_log(LOG_WARNING, "Queue '%s' already defined! Skipping!\n", cat);
04477 if (!new)
04478 ast_mutex_unlock(&q->lock);
04479 continue;
04480 }
04481
04482 init_queue(q);
04483 clear_queue(q);
04484 mem_iter = ao2_iterator_init(q->members, 0);
04485 while ((cur = ao2_iterator_next(&mem_iter))) {
04486 if (!cur->dynamic) {
04487 cur->delme = 1;
04488 }
04489 ao2_ref(cur, -1);
04490 }
04491 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
04492 if (!strcasecmp(var->name, "member")) {
04493 struct member tmpmem;
04494 membername = NULL;
04495
04496
04497 ast_copy_string(parse, var->value, sizeof(parse));
04498
04499 AST_NONSTANDARD_APP_ARGS(args, parse, ',');
04500
04501 interface = args.interface;
04502 if (!ast_strlen_zero(args.penalty)) {
04503 tmp = args.penalty;
04504 while (*tmp && *tmp < 33) tmp++;
04505 penalty = atoi(tmp);
04506 if (penalty < 0) {
04507 penalty = 0;
04508 }
04509 } else
04510 penalty = 0;
04511
04512 if (!ast_strlen_zero(args.membername)) {
04513 membername = args.membername;
04514 while (*membername && *membername < 33) membername++;
04515 }
04516
04517
04518 ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
04519 cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
04520
04521 newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
04522 ao2_link(q->members, newm);
04523 ao2_ref(newm, -1);
04524 newm = NULL;
04525
04526 if (cur)
04527 ao2_ref(cur, -1);
04528 else {
04529
04530 add_to_interfaces(interface);
04531 q->membercount++;
04532 }
04533 } else {
04534 queue_set_param(q, var->name, var->value, var->lineno, 1);
04535 }
04536 }
04537
04538
04539 mem_iter = ao2_iterator_init(q->members, 0);
04540 while ((cur = ao2_iterator_next(&mem_iter))) {
04541 if (! cur->delme) {
04542 ao2_ref(cur, -1);
04543 continue;
04544 }
04545
04546 q->membercount--;
04547 ao2_unlink(q->members, cur);
04548 remove_from_interfaces(cur->interface);
04549 ao2_ref(cur, -1);
04550 }
04551
04552 if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
04553 rr_dep_warning();
04554
04555 if (new) {
04556 AST_LIST_INSERT_HEAD(&queues, q, list);
04557 } else
04558 ast_mutex_unlock(&q->lock);
04559 }
04560 }
04561 }
04562 ast_config_destroy(cfg);
04563 AST_LIST_TRAVERSE_SAFE_BEGIN(&queues, q, list) {
04564 if (q->dead) {
04565 AST_LIST_REMOVE_CURRENT(&queues, list);
04566 if (!q->count)
04567 destroy_queue(q);
04568 else
04569 ast_log(LOG_DEBUG, "XXX Leaking a little memory :( XXX\n");
04570 } else {
04571 ast_mutex_lock(&q->lock);
04572 mem_iter = ao2_iterator_init(q->members, 0);
04573 while ((cur = ao2_iterator_next(&mem_iter))) {
04574 if (cur->dynamic)
04575 q->membercount++;
04576 cur->status = ast_device_state(cur->interface);
04577 ao2_ref(cur, -1);
04578 }
04579 ast_mutex_unlock(&q->lock);
04580 }
04581 }
04582 AST_LIST_TRAVERSE_SAFE_END;
04583 AST_LIST_UNLOCK(&queues);
04584 return 1;
04585 }
04586
04587 static int __queues_show(struct mansession *s, int manager, int fd, int argc, char **argv)
04588 {
04589 struct call_queue *q;
04590 struct queue_ent *qe;
04591 struct member *mem;
04592 int pos, queue_show;
04593 time_t now;
04594 char max_buf[150];
04595 char *max;
04596 size_t max_left;
04597 float sl = 0;
04598 char *term = manager ? "\r\n" : "\n";
04599 struct ao2_iterator mem_iter;
04600
04601 time(&now);
04602 if (argc == 2)
04603 queue_show = 0;
04604 else if (argc == 3)
04605 queue_show = 1;
04606 else
04607 return RESULT_SHOWUSAGE;
04608
04609
04610 if (queue_show) {
04611 load_realtime_queue(argv[2]);
04612 } else if (ast_check_realtime("queues")) {
04613 struct ast_config *cfg = ast_load_realtime_multientry("queues", "name LIKE", "%", (char *) NULL);
04614 char *queuename;
04615 if (cfg) {
04616 for (queuename = ast_category_browse(cfg, NULL); !ast_strlen_zero(queuename); queuename = ast_category_browse(cfg, queuename)) {
04617 load_realtime_queue(queuename);
04618 }
04619 ast_config_destroy(cfg);
04620 }
04621 }
04622
04623 AST_LIST_LOCK(&queues);
04624 if (AST_LIST_EMPTY(&queues)) {
04625 AST_LIST_UNLOCK(&queues);
04626 if (queue_show) {
04627 if (s)
04628 astman_append(s, "No such queue: %s.%s",argv[2], term);
04629 else
04630 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04631 } else {
04632 if (s)
04633 astman_append(s, "No queues.%s", term);
04634 else
04635 ast_cli(fd, "No queues.%s", term);
04636 }
04637 return RESULT_SUCCESS;
04638 }
04639 AST_LIST_TRAVERSE(&queues, q, list) {
04640 ast_mutex_lock(&q->lock);
04641 if (queue_show) {
04642 if (strcasecmp(q->name, argv[2]) != 0) {
04643 ast_mutex_unlock(&q->lock);
04644 if (!AST_LIST_NEXT(q, list)) {
04645 ast_cli(fd, "No such queue: %s.%s",argv[2], term);
04646 break;
04647 }
04648 continue;
04649 }
04650 }
04651 max_buf[0] = '\0';
04652 max = max_buf;
04653 max_left = sizeof(max_buf);
04654 if (q->maxlen)
04655 ast_build_string(&max, &max_left, "%d", q->maxlen);
04656 else
04657 ast_build_string(&max, &max_left, "unlimited");
04658 sl = 0;
04659 if (q->callscompleted > 0)
04660 sl = 100 * ((float) q->callscompletedinsl / (float) q->callscompleted);
04661 if (s)
04662 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",
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 else
04666 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",
04667 q->name, q->count, max_buf, int2strat(q->strategy), q->holdtime, q->ringlimit,
04668 q->weight, q->callscompleted, q->callsabandoned, sl, q->servicelevel, term);
04669 if (ao2_container_count(q->members)) {
04670 if (s)
04671 astman_append(s, " Members: %s", term);
04672 else
04673 ast_cli(fd, " Members: %s", term);
04674 mem_iter = ao2_iterator_init(q->members, 0);
04675 while ((mem = ao2_iterator_next(&mem_iter))) {
04676 max_buf[0] = '\0';
04677 max = max_buf;
04678 max_left = sizeof(max_buf);
04679 if (strcasecmp(mem->membername, mem->interface)) {
04680 ast_build_string(&max, &max_left, " (%s)", mem->interface);
04681 }
04682 if (mem->penalty)
04683 ast_build_string(&max, &max_left, " with penalty %d", mem->penalty);
04684 if (mem->dynamic)
04685 ast_build_string(&max, &max_left, " (dynamic)");
04686 if (mem->realtime)
04687 ast_build_string(&max, &max_left, " (realtime)");
04688 if (mem->paused)
04689 ast_build_string(&max, &max_left, " (paused)");
04690 ast_build_string(&max, &max_left, " (%s)", devstate2str(mem->status));
04691 if (mem->calls) {
04692 ast_build_string(&max, &max_left, " has taken %d calls (last was %ld secs ago)",
04693 mem->calls, (long) (time(NULL) - mem->lastcall));
04694 } else
04695 ast_build_string(&max, &max_left, " has taken no calls yet");
04696 if (s)
04697 astman_append(s, " %s%s%s", mem->membername, max_buf, term);
04698 else
04699 ast_cli(fd, " %s%s%s", mem->membername, max_buf, term);
04700 ao2_ref(mem, -1);
04701 }
04702 } else if (s)
04703 astman_append(s, " No Members%s", term);
04704 else
04705 ast_cli(fd, " No Members%s", term);
04706 if (q->head) {
04707 pos = 1;
04708 if (s)
04709 astman_append(s, " Callers: %s", term);
04710 else
04711 ast_cli(fd, " Callers: %s", term);
04712 for (qe = q->head; qe; qe = qe->next) {
04713 if (s)
04714 astman_append(s, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s",
04715 pos++, qe->chan->name, (long) (now - qe->start) / 60,
04716 (long) (now - qe->start) % 60, qe->prio, term);
04717 else
04718 ast_cli(fd, " %d. %s (wait: %ld:%2.2ld, prio: %d)%s", pos++,
04719 qe->chan->name, (long) (now - qe->start) / 60,
04720 (long) (now - qe->start) % 60, qe->prio, term);
04721 }
04722 } else if (s)
04723 astman_append(s, " No Callers%s", term);
04724 else
04725 ast_cli(fd, " No Callers%s", term);
04726 if (s)
04727 astman_append(s, "%s", term);
04728 else
04729 ast_cli(fd, "%s", term);
04730 ast_mutex_unlock(&q->lock);
04731 if (queue_show)
04732 break;
04733 }
04734 AST_LIST_UNLOCK(&queues);
04735 return RESULT_SUCCESS;
04736 }
04737
04738 static int queue_show(int fd, int argc, char **argv)
04739 {
04740 return __queues_show(NULL, 0, fd, argc, argv);
04741 }
04742
04743 static char *complete_queue(const char *line, const char *word, int pos, int state)
04744 {
04745 struct call_queue *q;
04746 char *ret = NULL;
04747 int which = 0;
04748 int wordlen = strlen(word);
04749
04750 AST_LIST_LOCK(&queues);
04751 AST_LIST_TRAVERSE(&queues, q, list) {
04752 if (!strncasecmp(word, q->name, wordlen) && ++which > state) {
04753 ret = ast_strdup(q->name);
04754 break;
04755 }
04756 }
04757 AST_LIST_UNLOCK(&queues);
04758
04759 return ret;
04760 }
04761
04762 static char *complete_queue_show(const char *line, const char *word, int pos, int state)
04763 {
04764 if (pos == 2)
04765 return complete_queue(line, word, pos, state);
04766 return NULL;
04767 }
04768
04769
04770
04771
04772 static int manager_queues_show(struct mansession *s, const struct message *m)
04773 {
04774 char *a[] = { "queue", "show" };
04775
04776 __queues_show(s, 1, -1, 2, a);
04777 astman_append(s, "\r\n\r\n");
04778
04779 return RESULT_SUCCESS;
04780 }
04781
04782
04783 static int manager_queues_status(struct mansession *s, const struct message *m)
04784 {
04785 time_t now;
04786 int pos;
04787 const char *id = astman_get_header(m,"ActionID");
04788 const char *queuefilter = astman_get_header(m,"Queue");
04789 const char *memberfilter = astman_get_header(m,"Member");
04790 char idText[256] = "";
04791 struct call_queue *q;
04792 struct queue_ent *qe;
04793 float sl = 0;
04794 struct member *mem;
04795 struct ao2_iterator mem_iter;
04796
04797 astman_send_ack(s, m, "Queue status will follow");
04798 time(&now);
04799 AST_LIST_LOCK(&queues);
04800 if (!ast_strlen_zero(id))
04801 snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04802
04803 AST_LIST_TRAVERSE(&queues, q, list) {
04804 ast_mutex_lock(&q->lock);
04805
04806
04807 if (ast_strlen_zero(queuefilter) || !strcmp(q->name, queuefilter)) {
04808 sl = ((q->callscompleted > 0) ? 100 * ((float)q->callscompletedinsl / (float)q->callscompleted) : 0);
04809 astman_append(s, "Event: QueueParams\r\n"
04810 "Queue: %s\r\n"
04811 "Max: %d\r\n"
04812 "Calls: %d\r\n"
04813 "Holdtime: %d\r\n"
04814 "Completed: %d\r\n"
04815 "Abandoned: %d\r\n"
04816 "ServiceLevel: %d\r\n"
04817 "ServicelevelPerf: %2.1f\r\n"
04818 "RingLimit: %d\r\n"
04819 "Weight: %d\r\n"
04820 "%s"
04821 "\r\n",
04822 q->name, q->maxlen, q->count, q->holdtime, q->callscompleted,
04823 q->callsabandoned, q->servicelevel, sl, q->ringlimit, q->weight, idText);
04824
04825 mem_iter = ao2_iterator_init(q->members, 0);
04826 while ((mem = ao2_iterator_next(&mem_iter))) {
04827 if (ast_strlen_zero(memberfilter) || !strcmp(mem->interface, memberfilter)) {
04828 astman_append(s, "Event: QueueMember\r\n"
04829 "Queue: %s\r\n"
04830 "Name: %s\r\n"
04831 "Location: %s\r\n"
04832 "Membership: %s\r\n"
04833 "Penalty: %d\r\n"
04834 "CallsTaken: %d\r\n"
04835 "LastCall: %d\r\n"
04836 "Status: %d\r\n"
04837 "Paused: %d\r\n"
04838 "%s"
04839 "\r\n",
04840 q->name, mem->membername, mem->interface, mem->dynamic ? "dynamic" : "static",
04841 mem->penalty, mem->calls, (int)mem->lastcall, mem->status, mem->paused, idText);
04842 }
04843 ao2_ref(mem, -1);
04844 }
04845
04846 pos = 1;
04847 for (qe = q->head; qe; qe = qe->next) {
04848 astman_append(s, "Event: QueueEntry\r\n"
04849 "Queue: %s\r\n"
04850 "Position: %d\r\n"
04851 "Channel: %s\r\n"
04852 "CallerID: %s\r\n"
04853 "CallerIDName: %s\r\n"
04854 "Wait: %ld\r\n"
04855 "%s"
04856 "\r\n",
04857 q->name, pos++, qe->chan->name,
04858 S_OR(qe->chan->cid.cid_num, "unknown"),
04859 S_OR(qe->chan->cid.cid_name, "unknown"),
04860 (long) (now - qe->start), idText);
04861 }
04862 }
04863 ast_mutex_unlock(&q->lock);
04864 }
04865
04866 astman_append(s,
04867 "Event: QueueStatusComplete\r\n"
04868 "%s"
04869 "\r\n",idText);
04870
04871 AST_LIST_UNLOCK(&queues);
04872
04873
04874 return RESULT_SUCCESS;
04875 }
04876
04877 static int manager_add_queue_member(struct mansession *s, const struct message *m)
04878 {
04879 const char *queuename, *interface, *penalty_s, *paused_s, *membername;
04880 int paused, penalty = 0;
04881
04882 queuename = astman_get_header(m, "Queue");
04883 interface = astman_get_header(m, "Interface");
04884 penalty_s = astman_get_header(m, "Penalty");
04885 paused_s = astman_get_header(m, "Paused");
04886 membername = astman_get_header(m, "MemberName");
04887
04888 if (ast_strlen_zero(queuename)) {
04889 astman_send_error(s, m, "'Queue' not specified.");
04890 return 0;
04891 }
04892
04893 if (ast_strlen_zero(interface)) {
04894 astman_send_error(s, m, "'Interface' not specified.");
04895 return 0;
04896 }
04897
04898 if (ast_strlen_zero(penalty_s))
04899 penalty = 0;
04900 else if (sscanf(penalty_s, "%d", &penalty) != 1 || penalty < 0)
04901 penalty = 0;
04902
04903 if (ast_strlen_zero(paused_s))
04904 paused = 0;
04905 else
04906 paused = abs(ast_true(paused_s));
04907
04908 switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
04909 case RES_OKAY:
04910 ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
04911 astman_send_ack(s, m, "Added interface to queue");
04912 break;
04913 case RES_EXISTS:
04914 astman_send_error(s, m, "Unable to add interface: Already there");
04915 break;
04916 case RES_NOSUCHQUEUE:
04917 astman_send_error(s, m, "Unable to add interface to queue: No such queue");
04918 break;
04919 case RES_OUTOFMEMORY:
04920 astman_send_error(s, m, "Out of memory");
04921 break;
04922 }
04923
04924 return 0;
04925 }
04926
04927 static int manager_remove_queue_member(struct mansession *s, const struct message *m)
04928 {
04929 const char *queuename, *interface;
04930
04931 queuename = astman_get_header(m, "Queue");
04932 interface = astman_get_header(m, "Interface");
04933
04934 if (ast_strlen_zero(queuename) || ast_strlen_zero(interface)) {
04935 astman_send_error(s, m, "Need 'Queue' and 'Interface' parameters.");
04936 return 0;
04937 }
04938
04939 switch (remove_from_queue(queuename, interface)) {
04940 case RES_OKAY:
04941 ast_queue_log(queuename, "MANAGER", interface, "REMOVEMEMBER", "%s", "");
04942 astman_send_ack(s, m, "Removed interface from queue");
04943 break;
04944 case RES_EXISTS:
04945 astman_send_error(s, m, "Unable to remove interface: Not there");
04946 break;
04947 case RES_NOSUCHQUEUE:
04948 astman_send_error(s, m, "Unable to remove interface from queue: No such queue");
04949 break;
04950 case RES_OUTOFMEMORY:
04951 astman_send_error(s, m, "Out of memory");
04952 break;
04953 case RES_NOT_DYNAMIC:
04954 astman_send_error(s, m, "Member not dynamic");
04955 break;
04956 }
04957
04958 return 0;
04959 }
04960
04961 static int manager_pause_queue_member(struct mansession *s, const struct message *m)
04962 {
04963 const char *queuename, *interface, *paused_s;
04964 int paused;
04965
04966 interface = astman_get_header(m, "Interface");
04967 paused_s = astman_get_header(m, "Paused");
04968 queuename = astman_get_header(m, "Queue");
04969
04970 if (ast_strlen_zero(interface) || ast_strlen_zero(paused_s)) {
04971 astman_send_error(s, m, "Need 'Interface' and 'Paused' parameters.");
04972 return 0;
04973 }
04974
04975 paused = abs(ast_true(paused_s));
04976
04977 if (set_member_paused(queuename, interface, paused))
04978 astman_send_error(s, m, "Interface not found");
04979 else
04980 astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
04981 return 0;
04982 }
04983
04984 static int handle_queue_add_member(int fd, int argc, char *argv[])
04985 {
04986 char *queuename, *interface, *membername = NULL;
04987 int penalty;
04988
04989 if ((argc != 6) && (argc != 8) && (argc != 10)) {
04990 return RESULT_SHOWUSAGE;
04991 } else if (strcmp(argv[4], "to")) {
04992 return RESULT_SHOWUSAGE;
04993 } else if ((argc == 8) && strcmp(argv[6], "penalty")) {
04994 return RESULT_SHOWUSAGE;
04995 } else if ((argc == 10) && strcmp(argv[8], "as")) {
04996 return RESULT_SHOWUSAGE;
04997 }
04998
04999 queuename = argv[5];
05000 interface = argv[3];
05001 if (argc >= 8) {
05002 if (sscanf(argv[7], "%d", &penalty) == 1) {
05003 if (penalty < 0) {
05004 ast_cli(fd, "Penalty must be >= 0\n");
05005 penalty = 0;
05006 }
05007 } else {
05008 ast_cli(fd, "Penalty must be an integer >= 0\n");
05009 penalty = 0;
05010 }
05011 } else {
05012 penalty = 0;
05013 }
05014
05015 if (argc >= 10) {
05016 membername = argv[9];
05017 }
05018
05019 switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
05020 case RES_OKAY:
05021 ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
05022 ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
05023 return RESULT_SUCCESS;
05024 case RES_EXISTS:
05025 ast_cli(fd, "Unable to add interface '%s' to queue '%s': Already there\n", interface, queuename);
05026 return RESULT_FAILURE;
05027 case RES_NOSUCHQUEUE:
05028 ast_cli(fd, "Unable to add interface to queue '%s': No such queue\n", queuename);
05029 return RESULT_FAILURE;
05030 case RES_OUTOFMEMORY:
05031 ast_cli(fd, "Out of memory\n");
05032 return RESULT_FAILURE;
05033 default:
05034 return RESULT_FAILURE;
05035 }
05036 }
05037
05038 static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
05039 {
05040
05041 switch (pos) {
05042 case 3:
05043 return NULL;
05044 case 4:
05045 return state == 0 ? ast_strdup("to") : NULL;
05046 case 5:
05047 return complete_queue(line, word, pos, state);
05048 case 6:
05049 return state == 0 ? ast_strdup("penalty") : NULL;
05050 case 7:
05051 if (state < 100) {
05052 char *num;
05053 if ((num = ast_malloc(3))) {
05054 sprintf(num, "%d", state);
05055 }
05056 return num;
05057 } else {
05058 return NULL;
05059 }
05060 case 8:
05061 return state == 0 ? ast_strdup("as") : NULL;
05062 case 9:
05063 return NULL;
05064 default:
05065 return NULL;
05066 }
05067 }
05068
05069 static int handle_queue_remove_member(int fd, int argc, char *argv[])
05070 {
05071 char *queuename, *interface;
05072
05073 if (argc != 6) {
05074 return RESULT_SHOWUSAGE;
05075 } else if (strcmp(argv[4], "from")) {
05076 return RESULT_SHOWUSAGE;
05077 }
05078
05079 queuename = argv[5];
05080 interface = argv[3];
05081
05082 switch (remove_from_queue(queuename, interface)) {
05083 case RES_OKAY:
05084 ast_queue_log(queuename, "CLI", interface, "REMOVEMEMBER", "%s", "");
05085 ast_cli(fd, "Removed interface '%s' from queue '%s'\n", interface, queuename);
05086 return RESULT_SUCCESS;
05087 case RES_EXISTS:
05088 ast_cli(fd, "Unable to remove interface '%s' from queue '%s': Not there\n", interface, queuename);
05089 return RESULT_FAILURE;
05090 case RES_NOSUCHQUEUE:
05091 ast_cli(fd, "Unable to remove interface from queue '%s': No such queue\n", queuename);
05092 return RESULT_FAILURE;
05093 case RES_OUTOFMEMORY:
05094 ast_cli(fd, "Out of memory\n");
05095 return RESULT_FAILURE;
05096 case RES_NOT_DYNAMIC:
05097 ast_cli(fd, "Member not dynamic\n");
05098 return RESULT_FAILURE;
05099 default:
05100 return RESULT_FAILURE;
05101 }
05102 }
05103
05104 static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
05105 {
05106 int which = 0;
05107 struct call_queue *q;
05108 struct member *m;
05109 struct ao2_iterator mem_iter;
05110
05111
05112 if (pos > 5 || pos < 3)
05113 return NULL;
05114 if (pos == 4)
05115 return state == 0 ? ast_strdup("from") : NULL;
05116
05117 if (pos == 5)
05118 return complete_queue(line, word, pos, state);
05119
05120
05121 if (!AST_LIST_EMPTY(&queues)) {
05122 AST_LIST_TRAVERSE(&queues, q, list) {
05123 ast_mutex_lock(&q->lock);
05124 mem_iter = ao2_iterator_init(q->members, 0);
05125 while ((m = ao2_iterator_next(&mem_iter))) {
05126 if (++which > state) {
05127 char *tmp;
05128 ast_mutex_unlock(&q->lock);
05129 tmp = ast_strdup(m->interface);
05130 ao2_ref(m, -1);
05131 return tmp;
05132 }
05133 ao2_ref(m, -1);
05134 }
05135 ast_mutex_unlock(&q->lock);
05136 }
05137 }
05138
05139 return NULL;
05140 }
05141
05142 static char queue_show_usage[] =
05143 "Usage: queue show\n"
05144 " Provides summary information on a specified queue.\n";
05145
05146 static char qam_cmd_usage[] =
05147 "Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
05148
05149 static char qrm_cmd_usage[] =
05150 "Usage: queue remove member <channel> from <queue>\n";
05151
05152 static struct ast_cli_entry cli_show_queue_deprecated = {
05153 { "show", "queue", NULL },
05154 queue_show, NULL,
05155 NULL, complete_queue_show };
05156
05157 static struct ast_cli_entry cli_add_queue_member_deprecated = {
05158 { "add", "queue", "member", NULL },
05159 handle_queue_add_member, NULL,
05160 NULL, complete_queue_add_member };
05161
05162 static struct ast_cli_entry cli_remove_queue_member_deprecated = {
05163 { "remove", "queue", "member", NULL },
05164 handle_queue_remove_member, NULL,
05165 NULL, complete_queue_remove_member };
05166
05167 static struct ast_cli_entry cli_queue[] = {
05168
05169 { { "show", "queues", NULL },
05170 queue_show, NULL,
05171 NULL, NULL },
05172
05173 { { "queue", "show", NULL },
05174 queue_show, "Show status of a specified queue",
05175 queue_show_usage, complete_queue_show, &cli_show_queue_deprecated },
05176
05177 { { "queue", "add", "member", NULL },
05178 handle_queue_add_member, "Add a channel to a specified queue",
05179 qam_cmd_usage, complete_queue_add_member, &cli_add_queue_member_deprecated },
05180
05181 { { "queue", "remove", "member", NULL },
05182 handle_queue_remove_member, "Removes a channel from a specified queue",
05183 qrm_cmd_usage, complete_queue_remove_member, &cli_remove_queue_member_deprecated },
05184 };
05185
05186 static int unload_module(void)
05187 {
05188 int res;
05189
05190 if (device_state.thread != AST_PTHREADT_NULL) {
05191 device_state.stop = 1;
05192 ast_mutex_lock(&device_state.lock);
05193 ast_cond_signal(&device_state.cond);
05194 ast_mutex_unlock(&device_state.lock);
05195 pthread_join(device_state.thread, NULL);
05196 }
05197
05198 ast_cli_unregister_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05199 res = ast_manager_unregister("QueueStatus");
05200 res |= ast_manager_unregister("Queues");
05201 res |= ast_manager_unregister("QueueAdd");
05202 res |= ast_manager_unregister("QueueRemove");
05203 res |= ast_manager_unregister("QueuePause");
05204 res |= ast_unregister_application(app_aqm);
05205 res |= ast_unregister_application(app_rqm);
05206 res |= ast_unregister_application(app_pqm);
05207 res |= ast_unregister_application(app_upqm);
05208 res |= ast_unregister_application(app_ql);
05209 res |= ast_unregister_application(app);
05210 res |= ast_custom_function_unregister(&queueagentcount_function);
05211 res |= ast_custom_function_unregister(&queuemembercount_function);
05212 res |= ast_custom_function_unregister(&queuememberlist_function);
05213 res |= ast_custom_function_unregister(&queuewaitingcount_function);
05214 ast_devstate_del(statechange_queue, NULL);
05215
05216 ast_module_user_hangup_all();
05217
05218 clear_and_free_interfaces();
05219
05220 return res;
05221 }
05222
05223 static int load_module(void)
05224 {
05225 int res;
05226
05227 if (!reload_queues())
05228 return AST_MODULE_LOAD_DECLINE;
05229
05230 if (queue_persistent_members)
05231 reload_queue_members();
05232
05233 ast_mutex_init(&device_state.lock);
05234 ast_cond_init(&device_state.cond, NULL);
05235 ast_pthread_create(&device_state.thread, NULL, device_state_thread, NULL);
05236
05237 ast_cli_register_multiple(cli_queue, sizeof(cli_queue) / sizeof(struct ast_cli_entry));
05238 res = ast_register_application(app, queue_exec, synopsis, descrip);
05239 res |= ast_register_application(app_aqm, aqm_exec, app_aqm_synopsis, app_aqm_descrip);
05240 res |= ast_register_application(app_rqm, rqm_exec, app_rqm_synopsis, app_rqm_descrip);
05241 res |= ast_register_application(app_pqm, pqm_exec, app_pqm_synopsis, app_pqm_descrip);
05242 res |= ast_register_application(app_upqm, upqm_exec, app_upqm_synopsis, app_upqm_descrip);
05243 res |= ast_register_application(app_ql, ql_exec, app_ql_synopsis, app_ql_descrip);
05244 res |= ast_manager_register("Queues", 0, manager_queues_show, "Queues");
05245 res |= ast_manager_register("QueueStatus", 0, manager_queues_status, "Queue Status");
05246 res |= ast_manager_register("QueueAdd", EVENT_FLAG_AGENT, manager_add_queue_member, "Add interface to queue.");
05247 res |= ast_manager_register("QueueRemove", EVENT_FLAG_AGENT, manager_remove_queue_member, "Remove interface from queue.");
05248 res |= ast_manager_register("QueuePause", EVENT_FLAG_AGENT, manager_pause_queue_member, "Makes a queue member temporarily unavailable");
05249 res |= ast_custom_function_register(&queueagentcount_function);
05250 res |= ast_custom_function_register(&queuemembercount_function);
05251 res |= ast_custom_function_register(&queuememberlist_function);
05252 res |= ast_custom_function_register(&queuewaitingcount_function);
05253 res |= ast_devstate_add(statechange_queue, NULL);
05254
05255 return res;
05256 }
05257
05258 static int reload(void)
05259 {
05260 reload_queues();
05261 return 0;
05262 }
05263
05264 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "True Call Queueing",
05265 .load = load_module,
05266 .unload = unload_module,
05267 .reload = reload,
05268 );
05269