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