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