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