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