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